X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=model.h;h=c92960f04569b11ea2b8e5a6b62776c07e8f59dd;hb=a1056ed8198f0f5be0e0f341da8bd49aa6c47198;hp=9558d1e42b22480284e863982c2c770a0c45ce4b;hpb=1f1d636056450dcd23cce55c0795ec6276272531;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/model.h b/model.h index 9558d1e..c92960f 100644 --- a/model.h +++ b/model.h @@ -1,217 +1,472 @@ +/* + * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved + */ + #ifndef MODEL_H #define MODEL_H -#include "vg/vg.h" +#include "common.h" -typedef struct model model; -typedef struct glmesh glmesh; -typedef struct submodel submodel; -typedef struct model_vert model_vert; -typedef struct model_marker model_marker; -typedef struct sdf_primative sdf_primative; -typedef enum esdf_type esdf_type; + +enum mdl_shader +{ + k_shader_standard = 0, + k_shader_standard_cutout = 1, + k_shader_terrain_blend = 2, + k_shader_standard_vertex_blend = 3, + k_shader_water = 4 +}; + +enum mdl_surface_prop +{ + k_surface_prop_concrete = 0, + k_surface_prop_wood = 1, + k_surface_prop_grass = 2, + k_surface_prop_tiles = 3 +}; + +enum material_flag +{ + k_material_flag_skate_surface = 0x1, + k_material_flag_collision = 0x2, + k_material_flag_grow_grass = 0x4, + k_material_flag_grind_surface = 0x8 +}; #pragma pack(push,1) -struct model + +/* 48 byte */ +struct mdl_vert { - u32 identifier; + v3f co, /* 3*32 */ + norm; /* 3*32 */ + v2f uv; /* 2*32 */ - u32 vertex_count, - indice_count, - layer_count, - marker_count; + u8 colour[4]; /* 4*8 */ + u16 weights[4];/* 4*16 */ + u8 groups[4]; /* 4*8 */ }; -struct sdf_primative +#pragma pack(pop) + +typedef struct mdl_context mdl_context; +typedef struct mdl_array_ptr mdl_array_ptr; +typedef struct mdl_vert mdl_vert; +typedef struct mdl_transform mdl_transform; +typedef struct mdl_submesh mdl_submesh; +typedef struct mdl_material mdl_material; +typedef struct mdl_bone mdl_bone; +typedef struct mdl_armature mdl_armature; +typedef struct mdl_animation mdl_animation; +typedef struct mdl_transform mdl_keyframe; +typedef struct mdl_mesh mdl_mesh; +typedef struct mdl_file mdl_file; +typedef struct mdl_texture mdl_texture; +typedef struct mdl_array mdl_array; +typedef struct mdl_header mdl_header; + +struct mdl_transform { - v4f origin; /* xyz, yaw */ - /* Cone: - x base scale - y height - */ - v4f info; + v3f co, s; + v4f q; }; -struct submodel +struct mdl_submesh { u32 indice_start, indice_count, vertex_start, vertex_count; - + boxf bbx; - v3f pivot; - sdf_primative sdf; + u32 material_id; +}; - enum esdf_type - { - k_sdf_none = 0, - k_sdf_cone, - k_sdf_sphere, - k_sdf_box - } - sdf_type; +struct mdl_material +{ + u32 pstr_name, + shader, + flags, + surface_prop; - char name[32]; + v4f colour, + colour1; + + u32 tex_diffuse, + tex_none0, + tex_none1; }; -struct model_marker +struct mdl_bone { - v3f co; - v4f q; - v3f s; - char name[32]; + v3f co, end; + u32 parent, + collider, + ik_target, + ik_pole, + flags, + pstr_name; + + boxf hitbox; + v3f conevx, conevy, coneva; + float conet; }; -struct model_vert +enum bone_flag { - v3f co, - norm; - v4f colour; - v2f uv; + k_bone_flag_deform = 0x1, + k_bone_flag_ik = 0x2, + k_bone_flag_cone_constraint = 0x4 }; -#pragma pack(pop) -struct glmesh +enum bone_collider { - GLuint vao, vbo, ebo; - u32 indice_count; + k_bone_collider_none = 0, + k_bone_collider_box = 1, + k_bone_collider_capsule = 2 +}; + +struct mdl_armature +{ + mdl_transform transform; + u32 bone_start, + bone_count, + anim_start, + anim_count; }; -static void mesh_upload( glmesh *mesh, - model_vert *verts, u32 vert_count, - u32 *indices, u32 indice_count ) +struct mdl_animation { - glGenVertexArrays( 1, &mesh->vao ); - glGenBuffers( 1, &mesh->vbo ); - glGenBuffers( 1, &mesh->ebo ); - glBindVertexArray( mesh->vao ); + u32 pstr_name, + length; + float rate; + u32 offset; +}; - glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo ); - glBufferData( GL_ARRAY_BUFFER, vert_count*sizeof(model_vert), - verts, GL_STATIC_DRAW ); +struct mdl_mesh +{ + mdl_transform transform; + u32 submesh_start, + submesh_count, + pstr_name, + flags, + armature_id; +}; - glBindVertexArray( mesh->vao ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, indice_count*sizeof(u32), - indices, GL_STATIC_DRAW ); - - glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, - sizeof(model_vert), (void*)0 ); - glEnableVertexAttribArray( 0 ); +struct mdl_file +{ + u32 pstr_path, + pack_offset, + pack_size; +}; - glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, - sizeof(model_vert), (void *)offsetof(model_vert, norm) ); - glEnableVertexAttribArray( 1 ); +struct mdl_texture +{ + mdl_file file; + u32 type; +}; - glVertexAttribPointer( 2, 4, GL_FLOAT, GL_FALSE, - sizeof(model_vert), (void *)offsetof(model_vert, colour) ); - glEnableVertexAttribArray( 2 ); +struct mdl_array +{ + u32 file_offset, + item_count, + item_size; - glVertexAttribPointer( 3, 2, GL_FLOAT, GL_FALSE, - sizeof(model_vert), (void *)offsetof(model_vert, uv) ); - glEnableVertexAttribArray( 3 ); + char name[16]; +}; + +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, - VG_CHECK_GL(); - mesh->indice_count = indice_count; -} + /* pack data */ + pack; +}; -static void mesh_bind( glmesh *mesh ) + +VG_STATIC void mdl_load_fatal_corrupt( mdl_context *mdl ) { - glBindVertexArray( mesh->vao ); + fclose( mdl->file ); + vg_file_print_invalid( mdl->file ); + vg_fatal_exit_loop( "Corrupt model" ); } -static void mesh_drawn( u32 start, u32 count ) +/* + * Model implementation + */ + +VG_STATIC void mdl_load_array_file( mdl_context *mdl, mdl_array_ptr *ptr, + mdl_array *arr, void *lin_alloc ) { - glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT, - (void *)(start*sizeof(u32)) ); + if( arr->item_count ){ + u32 size = arr->item_size*arr->item_count; + ptr->data = vg_linear_alloc( lin_alloc, vg_align8(size) ); + + fseek( mdl->file, arr->file_offset, SEEK_SET ); + u64 l = fread( ptr->data, arr->item_size*arr->item_count, 1, mdl->file ); + + if( l != 1 ) + mdl_load_fatal_corrupt( mdl ); + } + else + ptr->data = NULL; + + ptr->count = arr->item_count; + ptr->stride = arr->item_size; } -static void mesh_draw( glmesh *mesh ) +VG_STATIC void *mdl_arritm( mdl_array_ptr *arr, u32 index ) { - mesh_drawn( 0, mesh->indice_count ); + return ((u8 *)arr->data) + index*arr->stride; } -/* - * Helper functions for file offsets - * TODO: Revise this - */ -static submodel *model_get_submodel( model *mdl, int id ) +VG_STATIC u32 mdl_arrcount( mdl_array_ptr *arr ) { - return ((submodel*)(mdl+1)) + id; + return arr->count; } -static model_marker *model_get_marker( model *mdl, int id ) +VG_STATIC int mdl_load_array( mdl_context *mdl, mdl_array_ptr *ptr, + const char *name, void *lin_alloc ) { - return ((model_marker*)model_get_submodel(mdl,mdl->layer_count)) + id; + for( u32 i=0; iindex); i++ ){ + mdl_array *arr = mdl_arritm( &mdl->index, i ); + + if( !strncmp(arr->name,name,16) ){ + mdl_load_array_file( mdl, ptr, arr, lin_alloc ); + return 1; + } + } + + ptr->data = NULL; + ptr->count = 0; + ptr->stride = 0; + return 0; } -static model_vert *model_vertex_base( model *mdl ) +VG_STATIC int mdl_load_mesh_block( mdl_context *mdl, void *lin_alloc ) { - return (model_vert *)model_get_marker( mdl, mdl->marker_count ); + 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; } -static u32 *model_indice_base( model *mdl ) +VG_STATIC int mdl_load_metadata_block( mdl_context *mdl, void *lin_alloc ) { - return (u32 *)(model_vertex_base( mdl ) + mdl->vertex_count); + 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; } -static model_vert *submodel_vert_data( model *mdl, submodel *sub ) +VG_STATIC int mdl_load_animation_block( mdl_context *mdl, void *lin_alloc ) { - return model_vertex_base(mdl) + sub->vertex_start; + return mdl_load_array( mdl, &mdl->keyframes, "mdl_keyframe", lin_alloc ); } -static u32 *submodel_indice_data( model *mdl, submodel *sub ) +VG_STATIC int mdl_load_pack_block( mdl_context *mdl, void *lin_alloc ) { - return model_indice_base(mdl) + sub->indice_start; + return mdl_load_array( mdl, &mdl->pack, "pack", lin_alloc ); } -static submodel *submodel_get( model *mdl, const char *name ) +/* + * 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 ) { - for( int i=0; ilayer_count; i++ ) - { - submodel *pmdl =model_get_submodel(mdl,i); + memset( mdl, 0, sizeof( mdl_context ) ); + mdl->file = fopen( path, "rb" ); - if( !strcmp( pmdl->name, name ) ) - return pmdl; + if( !mdl->file ){ + vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) ); + vg_fatal_exit_loop( "see above for details" ); } - - return NULL; + + u64 l = fread( &mdl->info, sizeof(mdl_header), 1, mdl->file ); + if( l != 1 ) + mdl_load_fatal_corrupt( mdl ); + + mdl_load_array_file( mdl, &mdl->index, &mdl->info.index, lin_alloc ); } -static model_marker *model_marker_get( model *mdl, const char *name ) +/* + * close file handle + */ +VG_STATIC void mdl_close( mdl_context *mdl ) { - for( int i=0; imarker_count; i++ ) - { - model_marker *mk = model_get_marker( mdl,i ); + fclose( mdl->file ); + mdl->file = NULL; +} - if( !strcmp( mk->name, name ) ) - return mk; - } +/* useful things you can do with the model */ + +VG_STATIC void mdl_transform_m4x3( mdl_transform *transform, m4x3f mtx ) +{ + q_m3x3( transform->q, mtx ); + v3_muls( mtx[0], transform->s[0], mtx[0] ); + v3_muls( mtx[1], transform->s[1], mtx[1] ); + v3_muls( mtx[2], transform->s[2], mtx[2] ); + v3_copy( transform->co, mtx[3] ); +} + +VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr ) +{ + return mdl_arritm( &mdl->strings, pstr ); +} + +/* + * Simple mesh interface for OpenGL + * ---------------------------------------------------------------------------- + */ + +typedef struct glmesh glmesh; +struct glmesh +{ + GLuint vao, vbo, ebo; + u32 indice_count; + u32 loaded; +}; + +VG_STATIC void mesh_upload( glmesh *mesh, + mdl_vert *verts, u32 vert_count, + u32 *indices, u32 indice_count ) +{ + //assert( mesh->loaded == 0 ); + + glGenVertexArrays( 1, &mesh->vao ); + glGenBuffers( 1, &mesh->vbo ); + glGenBuffers( 1, &mesh->ebo ); + glBindVertexArray( mesh->vao ); + + size_t stride = sizeof(mdl_vert); + + glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo ); + glBufferData( GL_ARRAY_BUFFER, vert_count*stride, verts, GL_STATIC_DRAW ); + + glBindVertexArray( mesh->vao ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, indice_count*sizeof(u32), + indices, GL_STATIC_DRAW ); - return NULL; + /* 0: coordinates */ + glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 ); + glEnableVertexAttribArray( 0 ); + + /* 1: normal */ + glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, + stride, (void *)offsetof(mdl_vert, norm) ); + glEnableVertexAttribArray( 1 ); + + /* 2: uv */ + glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE, + stride, (void *)offsetof(mdl_vert, uv) ); + glEnableVertexAttribArray( 2 ); + + /* 3: colour */ + glVertexAttribPointer( 3, 4, GL_UNSIGNED_BYTE, GL_TRUE, + stride, (void *)offsetof(mdl_vert, colour) ); + glEnableVertexAttribArray( 3 ); + + /* 4: weights */ + glVertexAttribPointer( 4, 4, GL_UNSIGNED_SHORT, GL_TRUE, + stride, (void *)offsetof(mdl_vert, weights) ); + glEnableVertexAttribArray( 4 ); + + /* 5: groups */ + glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE, + stride, (void *)offsetof(mdl_vert, groups) ); + glEnableVertexAttribArray( 5 ); + + VG_CHECK_GL_ERR(); + + mesh->indice_count = indice_count; + mesh->loaded = 1; } -static void submodel_draw( submodel *sm ) +VG_STATIC void mesh_bind( glmesh *mesh ) { - mesh_drawn( sm->indice_start, sm->indice_count ); + glBindVertexArray( mesh->vao ); +} + +VG_STATIC void mesh_drawn( u32 start, u32 count ) +{ + glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT, + (void *)(start*sizeof(u32)) ); } -static void model_unpack_submodel( model *model, glmesh *mesh, submodel *sm ) +VG_STATIC void mesh_draw( glmesh *mesh ) { - mesh_upload( mesh, - model_vertex_base( model ) + sm->vertex_start, sm->vertex_count, - model_indice_base( model ) + sm->indice_start, sm->indice_count ); + mesh_drawn( 0, mesh->indice_count ); } -static void model_unpack( model *model, glmesh *mesh ) +VG_STATIC void mesh_free( glmesh *mesh ) { - u32 offset = model_get_submodel( model, 0 )->vertex_count; + if( mesh->loaded ){ + glDeleteVertexArrays( 1, &mesh->vao ); + glDeleteBuffers( 1, &mesh->ebo ); + glDeleteBuffers( 1, &mesh->vbo ); + mesh->loaded = 0; + } +} - for( int i=1; ilayer_count; i++ ) - { - submodel *sm = model_get_submodel( model, i ); - u32 *indices = submodel_indice_data( model, sm ); +VG_STATIC void mdl_draw_submesh( mdl_submesh *sm ) +{ + mesh_drawn( sm->indice_start, sm->indice_count ); +} + +/* WARNING: Destructive! Only use this once and then discard the context. */ +VG_STATIC void mdl_unpack_glmesh( mdl_context *mdl, glmesh *mesh ) +{ + if( !mdl->submeshs.count ) + vg_fatal_exit_loop( "Tried to unpack empty model file" ); + + mdl_submesh *sm = mdl_arritm( &mdl->submeshs, 0 ); + u32 offset = sm->vertex_count; + + for( u32 i=1; isubmeshs ); i++ ){ + mdl_submesh *sm = mdl_arritm( &mdl->submeshs, i ); + u32 *indices = mdl_arritm( &mdl->indices, sm->indice_start ); for( u32 j=0; jindice_count; j++ ) indices[j] += offset; @@ -219,15 +474,19 @@ static void model_unpack( model *model, glmesh *mesh ) offset += sm->vertex_count; } - mesh_upload( mesh, model_vertex_base( model ), model->vertex_count, - model_indice_base( model ), model->indice_count ); + mesh_upload( mesh, mdl->verts.data, mdl->verts.count, + mdl->indices.data, mdl->indices.count ); } -static void mesh_free( glmesh *mesh ) +VG_STATIC mdl_mesh *mdl_find_mesh( mdl_context *mdl, const char *name ) { - glDeleteVertexArrays( 1, &mesh->vao ); - glDeleteBuffers( 1, &mesh->ebo ); - glDeleteBuffers( 1, &mesh->vbo ); + for( u32 i=0; imeshs ); i++ ){ + mdl_mesh *mesh = mdl_arritm( &mdl->meshs, i ); + if( !strcmp( name, mdl_pstr( mdl, mesh->pstr_name ))){ + return mesh; + } + } + return NULL; } - + #endif