X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=model.h;h=b3650f8009c4a854dc383642c0391fea00fec311;hb=47941822dae18a018c985847b052e70214a3ccc6;hp=faa9f5fd8988483bcc774ba4d70667b1a53d4f2e;hpb=4f96bd0040e35ecb21d353ee2b895129682d22c1;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/model.h b/model.h index faa9f5f..b3650f8 100644 --- a/model.h +++ b/model.h @@ -13,9 +13,10 @@ typedef struct mdl_vert mdl_vert; typedef struct mdl_submesh mdl_submesh; typedef struct mdl_material mdl_material; typedef struct mdl_node mdl_node; -typedef struct mdl_header mdl_header; +typedef struct mdl_file_header mdl_file_header; typedef struct mdl_animation mdl_animation; typedef struct mdl_keyframe mdl_keyframe; +typedef struct mdl_context mdl_context; #define MDL_SIZE_MAX 0x1000000 #define MDL_VERT_MAX 1000000 @@ -41,7 +42,8 @@ enum classtype k_classtype_skeleton = 11, k_classtype_skin = 12, k_classtype_achievement_box = 13, - k_classtype_audio = 14 + k_classtype_audio = 14, + k_classtype_trigger = 15 }; @@ -79,9 +81,8 @@ struct mdl_node v4f q; v3f s; - union{ u32 submesh_start, sub_uid; }; - - u32 + u32 sub_uid, /* allocated in-file... too bad. */ + submesh_start, submesh_count, classtype, offset, @@ -106,9 +107,9 @@ struct mdl_animation u32 offset; }; -struct mdl_header +struct mdl_file_header { - u32 identifier, version, file_length; + u32 identifier, version, file_length, pad0; u32 vertex_count, vertex_offset, indice_count, indice_offset, @@ -116,7 +117,9 @@ struct mdl_header material_count, material_offset, node_count, node_offset, anim_count, anim_offset, - strings_offset, entdata_offset, animdata_offset; + strings_length, strings_offset, + entdata_length, entdata_offset, + keyframe_count, keyframe_offset; }; /* @@ -212,6 +215,26 @@ struct classtype_audio #pragma pack(pop) + +struct mdl_context +{ + FILE *file; + mdl_file_header info; + + /* each buffer becomes availible after each _load function is called */ + mdl_node *node_buffer; /* mdl_load_metadata() */ + mdl_submesh *submesh_buffer; + mdl_material *material_buffer; + mdl_animation *anim_buffer; + void *entdata_buffer; + const char *string_buffer; + + mdl_keyframe *keyframe_buffer; /* mdl_load_anim_data() */ + + mdl_vert *vertex_buffer; /* mdl_load_mesh_data() */ + u32 *index_buffer; +}; + /* * Simple mesh interface for OpenGL */ @@ -223,7 +246,7 @@ struct glmesh u32 loaded; }; -static void mesh_upload( glmesh *mesh, +VG_STATIC void mesh_upload( glmesh *mesh, mdl_vert *verts, u32 vert_count, u32 *indices, u32 indice_count ) { @@ -279,23 +302,23 @@ static void mesh_upload( glmesh *mesh, mesh->loaded = 1; } -static void mesh_bind( glmesh *mesh ) +VG_STATIC void mesh_bind( glmesh *mesh ) { glBindVertexArray( mesh->vao ); } -static void mesh_drawn( u32 start, u32 count ) +VG_STATIC void mesh_drawn( u32 start, u32 count ) { glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT, (void *)(start*sizeof(u32)) ); } -static void mesh_draw( glmesh *mesh ) +VG_STATIC void mesh_draw( glmesh *mesh ) { mesh_drawn( 0, mesh->indice_count ); } -static void mesh_free( glmesh *mesh ) +VG_STATIC void mesh_free( glmesh *mesh ) { if( mesh->loaded ) { @@ -305,156 +328,177 @@ static void mesh_free( glmesh *mesh ) } } +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. */ -static mdl_header *mdl_load( const char *path ) +/* + * 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 ) { - i64 size; - mdl_header *header = vg_asset_read_s( path, &size ); + memset( mdl, 0, sizeof( mdl_context ) ); + mdl->file = fopen( path, "rb" ); - /* - * Check file is valid - */ - if( !header ) + if( !mdl->file ) { - vg_error( "Could not open '%s'\n", path ); - return NULL; + vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) ); + vg_fatal_exit_loop( "see above for details" ); } - if( size < sizeof(mdl_header) ) - { - vg_free( header ); - vg_error( "Invalid file '%s' (too small for header)\n", path ); - return NULL; - } + u64 l = fread( &mdl->info, sizeof(mdl_file_header), 1, mdl->file ); + if( l != 1 ) + mdl_load_fatal_corrupt( mdl ); +} - if( header->file_length != size ) - { - vg_error( "Invalid file '%s'" - "(wrong .file_length, %ub != real file size %ub)\n", - path, header->file_length, size ); - vg_free( header ); - return NULL; - } +/* + * 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; - /* - * Validate offsets and memory sections, to ensure all arrays are in-bounds, - * and that they do not overlap. - */ + void *all_data = vg_linear_alloc( lin_alloc, ldata ); - struct memregion + fseek( mdl->file, lheader, SEEK_SET ); + u64 l = fread( all_data, ldata, 1, mdl->file ); + + if( l != 1 ) { - const char *desc; - u32 count, max_count, size, offset; + vg_file_print_invalid( mdl->file ); + vg_fatal_exit_loop( "Corrupt model" ); } - regions[] = { - { - "Vertices", - header->vertex_count, MDL_VERT_MAX, - sizeof(mdl_vert), header->vertex_offset - }, - { - "Indices", - header->indice_count, MDL_INDICE_MAX, - sizeof(u32), header->indice_offset - }, - { - "Submesh", - header->submesh_count, MDL_SUBMESH_MAX, - sizeof(mdl_submesh), header->submesh_offset - }, - { - "Materials", - header->material_count, MDL_MATERIAL_MAX, - sizeof(mdl_material), header->material_offset - }, - { - "Nodes", - header->node_count, MDL_NODE_MAX, - sizeof(mdl_node), header->node_count - } - }; - for( int i=0; inode_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->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); +} - if( ri->count == 0 ) - continue; +/* + * Load just the mesh data + */ +VG_STATIC void mdl_load_mesh_data( mdl_context *mdl, void *lin_alloc ) +{ + assert( mdl->file ); + + u64 size_verts = mdl->info.vertex_count * sizeof(mdl_vert), + size_index = mdl->info.indice_count * sizeof(u32); - if( ri->count > ri->max_count ) - { - vg_free( header ); - vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n", - path, ri->desc, ri->count, ri->max_count ); - return NULL; - } + 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 ); + } +} - if( ri->offset >= header->file_length ) - { - vg_free( header ); - vg_error( "'%s': '%s' buffer offset is out of range\n", - path, ri->desc ); - return NULL; - } +/* + * Load animation data + */ +VG_STATIC void mdl_load_anim_data( mdl_context *mdl, void *lin_alloc ) +{ + assert( mdl->file ); - if( ri->offset + ri->size*ri->count > header->file_length ) - { - vg_free( header ); - vg_error( "'%s': '%s' buffer size is out of range\n", - path, ri->desc ); - return NULL; - } + if( mdl->info.keyframe_count == 0 ) + return; + + u64 size_kf = 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 ); +} - for( int j=0; jcount == 0 ) - continue; +/* + * close file handle + */ +VG_STATIC void mdl_close( mdl_context *mdl ) +{ + fclose( mdl->file ); + mdl->file = NULL; +} - if( ri->offset >= rj->offset && - (ri->offset+ri->size*ri->count < rj->offset+rj->size*rj->count)) - { - vg_free( header ); - vg_error( "'%s': '%s' buffer overlaps '%s'\n", - path, ri->desc, rj->desc ); - return NULL; - } - } - } +/* open a model */ +VG_STATIC mdl_context *mdl_load_full( void *lin_alloc, const char *path ) +{ + /* Inspect the header by opening it, give us the size needed */ + mdl_context temp_ctx; + mdl_open( &temp_ctx, path ); - /* - * Pointer validation TODO(workshop) - */ + /* create allocator */ + u32 tot_size = temp_ctx.info.file_length + sizeof( mdl_context ); + void *data = vg_create_linear_allocator( lin_alloc, tot_size ); - /* - * strings TODO(workshop) - */ + /* copy context and load all other data */ + mdl_context *ctx = vg_linear_alloc( data, sizeof(mdl_context) ); + memcpy( ctx, &temp_ctx, sizeof(mdl_context) ); - return header; -} + mdl_load_metadata( ctx, data ); + mdl_load_anim_data( ctx, data ); + mdl_load_mesh_data( ctx, data ); + mdl_close( ctx ); -static void *mdl_baseptr( mdl_header *mdl, u32 offset ) -{ - return (void *)mdl + offset; + return ctx; } -static const char *mdl_pstr( mdl_header *mdl, u32 pstr ) +/* + * Item getters + * ---------------------------------------------------------------------------- + * TODO: Clamp access and oob errors + */ +VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr ) { - return (const char *)(mdl_baseptr( mdl, mdl->strings_offset )) + pstr; + return mdl->string_buffer + pstr; } -static mdl_node *mdl_node_from_id( mdl_header *mdl, u32 id ) +VG_STATIC mdl_node *mdl_node_from_id( mdl_context *mdl, u32 id ) { - return ((mdl_node *)mdl_baseptr( mdl, mdl->node_offset )) + id; + return &mdl->node_buffer[id]; } -static mdl_node *mdl_node_from_name( mdl_header *mdl, const char *name ) +VG_STATIC mdl_node *mdl_node_from_name( mdl_context *mdl, const char *name ) { - for( int i=0; inode_count; i++ ) + for( int i=0; i < mdl->info.node_count; i++ ) { mdl_node *pnode = mdl_node_from_id( mdl, i ); @@ -465,43 +509,23 @@ static mdl_node *mdl_node_from_name( mdl_header *mdl, const char *name ) return NULL; } -static mdl_submesh *mdl_submesh_from_id( mdl_header *mdl, u32 id ) -{ - if( id >= mdl->submesh_count ) - return NULL; - - return ((mdl_submesh *)mdl_baseptr( mdl, mdl->submesh_offset )) + id; -} - -static mdl_submesh *mdl_node_submesh( mdl_header *mdl, mdl_node *node, u32 i ) -{ - if( i >= node->submesh_count ) - return NULL; - - return mdl_submesh_from_id( mdl, node->submesh_start+i ); -} - -static u32 *mdl_submesh_indices( mdl_header *mdl, mdl_submesh *sm ) +VG_STATIC mdl_submesh *mdl_node_submesh( mdl_context *mdl, + mdl_node *node, u32 i ) { - return ((u32 *)mdl_baseptr( mdl, mdl->indice_offset )) + sm->indice_start; + return &mdl->submesh_buffer[ node->submesh_start+i ]; } -static mdl_vert *mdl_submesh_vertices( mdl_header *mdl, mdl_submesh *sm ) +VG_STATIC u32 *mdl_submesh_indices( mdl_context *mdl, mdl_submesh *sm ) { - return ((mdl_vert *)mdl_baseptr(mdl,mdl->vertex_offset)) + sm->vertex_start; + return &mdl->index_buffer[ sm->indice_start ]; } -static mdl_material *mdl_material_from_id( mdl_header *mdl, u32 id ) +VG_STATIC mdl_vert *mdl_submesh_vertices( mdl_context *mdl, mdl_submesh *sm ) { - return ((mdl_material *)mdl_baseptr(mdl,mdl->material_offset)) + id; + return &mdl->vertex_buffer[ sm->vertex_start ]; } -static mdl_animation *mdl_animation_from_id( mdl_header *mdl, u32 id ) -{ - return ((mdl_animation *)mdl_baseptr(mdl,mdl->anim_offset)) + id; -} - -static void mdl_node_transform( mdl_node *pnode, m4x3f transform ) +VG_STATIC void mdl_node_transform( mdl_node *pnode, m4x3f transform ) { q_m3x3( pnode->q, transform ); v3_muls( transform[0], pnode->s[0], transform[0] ); @@ -510,20 +534,23 @@ static void mdl_node_transform( mdl_node *pnode, m4x3f transform ) v3_copy( pnode->co, transform[3] ); } -static void mdl_unpack_submesh( mdl_header *mdl, glmesh *mesh, mdl_submesh *sm ) +/* upload a mesh based on file submesh */ +VG_STATIC void mdl_unpack_submesh( mdl_context *mdl, glmesh *mesh, + mdl_submesh *sm ) { mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count, mdl_submesh_indices( mdl, sm ), sm->indice_count ); } -static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh ) +/* upload entire mesh from model */ +VG_STATIC void mdl_unpack_glmesh( mdl_context *mdl, glmesh *mesh ) { - u32 offset = mdl_submesh_from_id( mdl, 0 )->vertex_count; + u32 offset = mdl->submesh_buffer[0].vertex_count; - for( int i=1; i< mdl->submesh_count; i++ ) + for( int i=1; i< mdl->info.submesh_count; i++ ) { - mdl_submesh *sm = mdl_submesh_from_id( mdl, i ); - u32 *indices = mdl_submesh_indices( mdl, sm ); + mdl_submesh *sm = &mdl->submesh_buffer[i]; + u32 *indices = mdl_submesh_indices( mdl, sm ); for( u32 j=0; jindice_count; j++ ) indices[j] += offset; @@ -531,42 +558,39 @@ static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh ) offset += sm->vertex_count; } - mdl_vert *vertex_base = mdl_baseptr( mdl, mdl->vertex_offset ); - u32 *indice_base = mdl_baseptr( mdl, mdl->indice_offset ); - - mesh_upload( mesh, vertex_base, mdl->vertex_count, - indice_base, mdl->indice_count ); + mesh_upload( mesh, mdl->vertex_buffer, mdl->info.vertex_count, + mdl->index_buffer, mdl->info.indice_count ); } -static void mdl_draw_submesh( mdl_submesh *sm ) +VG_STATIC void mdl_draw_submesh( mdl_submesh *sm ) { mesh_drawn( sm->indice_start, sm->indice_count ); } -static void *mdl_get_entdata( mdl_header *mdl, mdl_node *pnode ) +VG_STATIC void *mdl_get_entdata( mdl_context *mdl, mdl_node *pnode ) { - return mdl_baseptr( mdl, mdl->entdata_offset ) + pnode->offset; + return mdl->entdata_buffer + pnode->offset; } -static mdl_keyframe *mdl_get_animdata( mdl_header *mdl, mdl_animation *anim ) +VG_STATIC mdl_keyframe *mdl_get_animdata( mdl_context *mdl, mdl_animation *anim ) { - return mdl_baseptr( mdl, mdl->animdata_offset ) + anim->offset; + return mdl->keyframe_buffer + anim->offset; } -static void mdl_link_materials( mdl_header *root, mdl_header *child ) +VG_STATIC void mdl_link_materials( mdl_context *root, mdl_context *child ) { u32 lookup[MDL_MATERIAL_MAX]; - for( int i=0; imaterial_count; i++ ) + for( int i=0; iinfo.material_count; i++ ) { - mdl_material *mi = mdl_material_from_id( child, i ); + mdl_material *mi = &child->material_buffer[i]; const char *si = mdl_pstr( child, mi->pstr_name ); lookup[i] = 0; - for( int j=0; jmaterial_count; j++ ) + for( int j=0; jinfo.material_count; j++ ) { - mdl_material *mj = mdl_material_from_id( root, j ); + mdl_material *mj = &root->material_buffer[j]; const char *sj = mdl_pstr( root, mj->pstr_name ); if( !strcmp( si, sj ) ) @@ -583,10 +607,10 @@ static void mdl_link_materials( mdl_header *root, mdl_header *child ) } } - for( int i=0; isubmesh_count; i++ ) + for( int i=0; iinfo.submesh_count; i++ ) { - mdl_submesh *sm = mdl_submesh_from_id( child, i ); - sm->material_id = lookup[sm->material_id]; + mdl_submesh *sm = &child->submesh_buffer[i]; + sm->material_id = lookup[sm->material_id]; } }