+struct mdl_header
+{
+ u32 version;
+ mdl_array index;
+};
+
+struct mdl_context{
+ FILE *file;
+ mdl_header info;
+
+ struct mdl_array_ptr{
+ void *data;
+ u32 count, stride;
+ }
+ index,
+
+ /* metadata */
+ strings,
+ meshs,
+ submeshs,
+ materials,
+ textures,
+ armatures,
+ bones,
+ animations,
+
+ /* animation buffers */
+ keyframes,
+
+ /* mesh buffers */
+ verts,
+ indices;
+ u32 pack_base_offset;
+
+ /* runtime */
+ glmesh mesh;
+};
+
+
+VG_STATIC void mdl_load_fatal_corrupt( mdl_context *mdl )
+{
+ fclose( mdl->file );
+ vg_file_print_invalid( mdl->file );
+ vg_fatal_error( "Corrupt model" );
+}
+
+/*
+ * Model implementation
+ */
+
+VG_STATIC u32 mdl_query_array_size( mdl_array *arr )
+{
+ if( arr->item_count ){
+ u32 size = arr->item_size*arr->item_count;
+ return vg_align8(size);
+ }
+ else return 0;
+}
+
+VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr );
+VG_STATIC
+void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst )
+{
+ if( !info->pack_size ){
+ vg_warn( "path: %s\n", mdl_pstr( mdl, info->pstr_path ) );
+ vg_fatal_error( "Packed file is only a header; it is not packed" );
+ }
+
+ fseek( mdl->file, mdl->pack_base_offset+info->pack_offset, SEEK_SET );
+ u64 l = fread( dst, info->pack_size, 1, mdl->file );
+
+ if( l != 1 ) mdl_load_fatal_corrupt( mdl );
+}
+
+/* TODO: Rename these */
+VG_STATIC void mdl_load_array_file_buffer( mdl_context *mdl, mdl_array *arr,
+ void *buffer )
+{
+ if( arr->item_count ){
+ fseek( mdl->file, arr->file_offset, SEEK_SET );
+ u64 l = fread( buffer, arr->item_size*arr->item_count, 1, mdl->file );
+
+ if( l != 1 ) mdl_load_fatal_corrupt( mdl );
+ }
+}
+
+VG_STATIC void mdl_load_array_file( mdl_context *mdl, mdl_array_ptr *ptr,
+ mdl_array *arr, void *lin_alloc )
+{
+ if( arr->item_count ){
+ u32 size = arr->item_size*arr->item_count;
+ ptr->data = vg_linear_alloc( lin_alloc, vg_align8(size) );
+ mdl_load_array_file_buffer( mdl, arr, ptr->data );
+ }
+ else
+ ptr->data = NULL;
+
+ ptr->count = arr->item_count;
+ ptr->stride = arr->item_size;
+}
+
+VG_STATIC void *mdl_arritm( mdl_array_ptr *arr, u32 index )
+{
+ return ((u8 *)arr->data) + index*arr->stride;
+}
+
+VG_STATIC u32 mdl_arrcount( mdl_array_ptr *arr )
+{
+ return arr->count;
+}
+
+VG_STATIC mdl_array *mdl_find_array( mdl_context *mdl, const char *name )
+{
+ for( u32 i=0; i<mdl_arrcount(&mdl->index); i++ ){
+ mdl_array *arr = mdl_arritm( &mdl->index, i );
+
+ if( !strncmp(arr->name,name,16) ){
+ return arr;
+ }
+ }
+
+ return NULL;
+}
+
+VG_STATIC int mdl_load_array( mdl_context *mdl, mdl_array_ptr *ptr,
+ const char *name, void *lin_alloc )
+{
+ mdl_array *arr = mdl_find_array( mdl, name );
+
+ if( arr ){
+ mdl_load_array_file( mdl, ptr, arr, lin_alloc );
+ return 1;
+ }
+ else{
+ ptr->data = NULL;
+ ptr->count = 0;
+ ptr->stride = 0;
+ return 0;
+ }
+}
+
+VG_STATIC int mdl_load_mesh_block( mdl_context *mdl, void *lin_alloc )
+{
+ int success = 1;
+
+ success &= mdl_load_array( mdl, &mdl->verts, "mdl_vert", lin_alloc );
+ success &= mdl_load_array( mdl, &mdl->indices, "mdl_indice", lin_alloc );
+
+ return success;
+}
+
+VG_STATIC int mdl_load_metadata_block( mdl_context *mdl, void *lin_alloc )
+{
+ int success = 1;
+
+ success &= mdl_load_array( mdl, &mdl->strings, "strings", lin_alloc );
+ success &= mdl_load_array( mdl, &mdl->meshs, "mdl_mesh", lin_alloc );
+ success &= mdl_load_array( mdl, &mdl->submeshs, "mdl_submesh", lin_alloc );
+ success &= mdl_load_array( mdl, &mdl->materials, "mdl_material", lin_alloc );
+ success &= mdl_load_array( mdl, &mdl->textures, "mdl_texture", lin_alloc );
+ success &= mdl_load_array( mdl, &mdl->armatures, "mdl_armature", lin_alloc );
+ success &= mdl_load_array( mdl, &mdl->bones, "mdl_bone", lin_alloc );
+ success &= mdl_load_array( mdl, &mdl->animations,"mdl_animation",lin_alloc );
+
+ return success;
+}
+
+VG_STATIC int mdl_load_animation_block( mdl_context *mdl, void *lin_alloc )
+{
+ return mdl_load_array( mdl, &mdl->keyframes, "mdl_keyframe", lin_alloc );
+}
+
+/*
+ * if calling mdl_open, and the file does not exist, the game will fatal quit
+ */
+VG_STATIC void mdl_open( mdl_context *mdl, const char *path, void *lin_alloc )