+VG_STATIC void mesh_free( glmesh *mesh )
+{
+ if( mesh->loaded )
+ {
+ glDeleteVertexArrays( 1, &mesh->vao );
+ glDeleteBuffers( 1, &mesh->ebo );
+ glDeleteBuffers( 1, &mesh->vbo );
+ mesh->loaded = 0;
+ }
+}
+
+VG_STATIC void mdl_load_fatal_corrupt( mdl_context *mdl )
+{
+ fclose( mdl->file );
+ vg_file_print_invalid( mdl->file );
+ vg_fatal_exit_loop( "Corrupt model" );
+}
+
+/*
+ * Model implementation
+ *
+ * TODO.
+ *
+ * you have two api options for loading a model, first, the easy way:
+ * mdl_load ...
+ * will put the entire model straight into the linear_alloc
+ *
+ * or, to target different allocators:
+ *
+ * mdl_open
+ * mdl_load_metadata
+ * mdl_load_vertex_data
+ * mdl_load_indice_data
+ * mdl_close
+ *
+ * these should ideally be called in quick succession to limit stalls.
+ */
+
+/*
+ * 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 )
+{
+ memset( mdl, 0, sizeof( mdl_context ) );
+ mdl->file = fopen( path, "rb" );
+
+ if( !mdl->file )
+ {
+ vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) );
+ vg_fatal_exit_loop( "see above for details" );
+ }
+
+ u64 l = fread( &mdl->info, sizeof(mdl_file_header), 1, mdl->file );
+ if( l != 1 )
+ mdl_load_fatal_corrupt( mdl );
+}
+
+/*
+ * Load all metadata (everything up until the large buffers). Probs at most 50k
+ */
+VG_STATIC void mdl_load_metadata( mdl_context *mdl, void *lin_alloc )
+{
+ assert( mdl->file );
+
+ u64 lheader = sizeof(mdl_file_header),
+ ldata = mdl->info.keyframe_offset - lheader;
+
+ void *all_data = vg_linear_alloc( lin_alloc, ldata );
+
+ fseek( mdl->file, lheader, SEEK_SET );
+ u64 l = fread( all_data, ldata, 1, mdl->file );
+
+ if( l != 1 )
+ {
+ vg_file_print_invalid( mdl->file );
+ vg_fatal_exit_loop( "Corrupt model" );
+ }
+
+ mdl->node_buffer = all_data + (mdl->info.node_offset - lheader);
+ mdl->submesh_buffer = all_data + (mdl->info.submesh_offset - lheader);
+ mdl->material_buffer = all_data + (mdl->info.material_offset - lheader);
+ mdl->texture_buffer = all_data + (mdl->info.texture_offset - lheader);
+ mdl->anim_buffer = all_data + (mdl->info.anim_offset - lheader);
+ mdl->entdata_buffer = all_data + (mdl->info.entdata_offset - lheader);
+ mdl->string_buffer = all_data + (mdl->info.strings_offset - lheader);
+}
+
+/*
+ * Load just the mesh data
+ */
+VG_STATIC void mdl_load_mesh_data( mdl_context *mdl, void *lin_alloc )
+{
+ assert( mdl->file );
+
+ u64 size_verts = vg_align8( mdl->info.vertex_count * sizeof(mdl_vert) ),
+ size_index = vg_align8( mdl->info.indice_count * sizeof(u32) );
+
+ mdl->vertex_buffer = vg_linear_alloc( lin_alloc, size_verts );
+ mdl->index_buffer = vg_linear_alloc( lin_alloc, size_index );
+
+ {
+ fseek( mdl->file, mdl->info.vertex_offset, SEEK_SET );
+ u64 l = fread( mdl->vertex_buffer, size_verts, 1, mdl->file );
+ if( l != 1 )
+ mdl_load_fatal_corrupt( mdl );
+ }
+ {
+ fseek( mdl->file, mdl->info.indice_offset, SEEK_SET );
+ u64 l = fread( mdl->index_buffer, size_index, 1, mdl->file );
+ if( l != 1 )
+ mdl_load_fatal_corrupt( mdl );
+ }
+}
+
+/*
+ * Load animation data
+ */
+VG_STATIC void mdl_load_anim_data( mdl_context *mdl, void *lin_alloc )
+{
+ assert( mdl->file );
+
+ if( mdl->info.keyframe_count == 0 )
+ return;
+
+ u64 size_kf = vg_align8( mdl->info.keyframe_count * sizeof(mdl_keyframe) );
+ mdl->keyframe_buffer = vg_linear_alloc( lin_alloc, size_kf );
+
+ fseek( mdl->file, mdl->info.keyframe_offset, SEEK_SET );
+ u64 l = fread( mdl->keyframe_buffer, size_kf, 1, mdl->file );
+ if( l != 1 )
+ mdl_load_fatal_corrupt( mdl );
+}
+