X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=model.h;h=aade46aa21ddd00c341c552d71669bc20f1fbd00;hb=HEAD;hp=c28455d1faf4689d8cda17b7e7185f9fe24b55fe;hpb=22f62f001f21d1b91fefd9fc495c122d9ddf205a;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/model.h b/model.h index c28455d..aade46a 100644 --- a/model.h +++ b/model.h @@ -1,14 +1,11 @@ /* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved + * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved */ -#ifndef MODEL_H -#define MODEL_H - -#include "skaterift.h" +#pragma once #define MDL_VERSION_MIN 101 -#define MDL_VERSION_NR 102 +#define MDL_VERSION_NR 106 enum mdl_shader{ k_shader_standard = 0, @@ -20,15 +17,19 @@ enum mdl_shader{ k_shader_boundary = 6, k_shader_fxglow = 7, k_shader_cubemap = 8, + k_shader_walking = 9, + k_shader_foliage = 10, k_shader_override = 30000 }; enum mdl_surface_prop{ - k_surface_prop_concrete = 0, - k_surface_prop_wood = 1, - k_surface_prop_grass = 2, - k_surface_prop_tiles = 3, - k_surface_prop_metal = 4 + k_surface_prop_concrete = 0, + k_surface_prop_wood = 1, + k_surface_prop_grass = 2, + k_surface_prop_tiles = 3, + k_surface_prop_metal = 4, + k_surface_prop_snow = 5, + k_surface_prop_sand = 6 }; enum material_flag{ @@ -63,6 +64,8 @@ struct mdl_vert #pragma pack(pop) +typedef u32 mdl_indice; + typedef struct mdl_context mdl_context; typedef struct mdl_array_ptr mdl_array_ptr; typedef struct mdl_vert mdl_vert; @@ -82,7 +85,7 @@ typedef struct mdl_header mdl_header; typedef struct glmesh glmesh; struct glmesh { - GLuint vao, vbo, ebo; + u32 vao, vbo, ebo; u32 indice_count; u32 loaded; }; @@ -121,7 +124,15 @@ static void mdl_transform_mul( mdl_transform *a, mdl_transform *b, v3_mul( a->s, b->s, d->s ); } -struct mdl_material +struct mdl_file +{ + u32 pstr_path, + pack_offset, + pack_size; +}; + +#if (MDL_VERSION_MIN <= 105) +struct mdl_material_v105 { u32 pstr_name, shader, @@ -131,10 +142,31 @@ struct mdl_material v4f colour, colour1; - u32 tex_diffuse, + u32 tex_diffuse, /* Indexes start from 1. 0 if missing. */ tex_none0, tex_none1; }; +#endif + +struct mdl_material +{ + u32 pstr_name, + shader, + flags, + surface_prop; + + union + { + struct + { + u32 offset, size; + /* -> vg_msg containing KV properties */ + } + kvs; + void *compiled; /* -> shader specific structure for render */ + } + props; +}; struct mdl_bone { @@ -209,13 +241,6 @@ struct mdl_mesh armature_id; }; -struct mdl_file -{ - u32 pstr_path, - pack_offset, - pack_size; -}; - struct mdl_texture { mdl_file file; @@ -237,11 +262,13 @@ struct mdl_header mdl_array index; }; -struct mdl_context{ +struct mdl_context +{ FILE *file; mdl_header info; - struct mdl_array_ptr{ + struct mdl_array_ptr + { void *data; u32 count, stride; } @@ -269,404 +296,50 @@ struct mdl_context{ glmesh mesh; }; +void mesh_bind( glmesh *mesh ); +void mesh_drawn( u32 start, u32 count ); +void mesh_draw( glmesh *mesh ); +void mesh_free( glmesh *mesh ); -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 - */ - -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; -} - -static const char *mdl_pstr( mdl_context *mdl, u32 pstr ); -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 */ -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 ); - } -} - -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; -} - -static void *mdl_arritm( mdl_array_ptr *arr, u32 index ) -{ - return ((u8 *)arr->data) + index*arr->stride; -} - -static u32 mdl_arrcount( mdl_array_ptr *arr ) -{ - return arr->count; -} - -static mdl_array *mdl_find_array( mdl_context *mdl, const char *name ) -{ - for( u32 i=0; iindex); i++ ){ - mdl_array *arr = mdl_arritm( &mdl->index, i ); - - if( !strncmp(arr->name,name,16) ){ - return arr; - } - } - - return NULL; -} - -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; - } -} - -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; -} - -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; -} - -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 - */ -static void mdl_open( mdl_context *mdl, const char *path, void *lin_alloc ) -{ - memset( mdl, 0, sizeof( mdl_context ) ); - mdl->file = fopen( path, "rb" ); +/* file context management */ +void mdl_open( mdl_context *mdl, const char *path, void *lin_alloc ); +void mdl_close( mdl_context *mdl ); - if( !mdl->file ){ - vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) ); - vg_fatal_error( "see above for details" ); - } +/* array loading */ +int _mdl_load_array( mdl_context *mdl, mdl_array_ptr *ptr, + const char *name, void *lin_alloc, u32 stride ); +#define MDL_LOAD_ARRAY( MDL, PTR, STRUCT, ALLOCATOR ) \ + _mdl_load_array( MDL, PTR, #STRUCT, ALLOCATOR, sizeof(STRUCT) ) - u64 l = fread( &mdl->info, sizeof(mdl_header), 1, mdl->file ); - if( l != 1 ) - mdl_load_fatal_corrupt( mdl ); +/* array access */ +void *mdl_arritm( mdl_array_ptr *arr, u32 index ); +u32 mdl_arrcount( mdl_array_ptr *arr ); - if( mdl->info.version < MDL_VERSION_MIN ){ - vg_warn( "For model: %s\n", path ); - vg_warn( " version: %u (min: %u, current: %u)\n", - mdl->info.version, MDL_VERSION_MIN, MDL_VERSION_NR ); +/* pack access */ +void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst ); - vg_fatal_error( "Legacy model version incompatable" ); - } +/* standard array groups */ +int mdl_load_animation_block( mdl_context *mdl, void *lin_alloc ); +int mdl_load_metadata_block( mdl_context *mdl, void *lin_alloc ); +int mdl_load_mesh_block( mdl_context *mdl, void *lin_alloc ); +int mdl_load_materials( mdl_context *mdl, void *lin_alloc ); - mdl_load_array_file( mdl, &mdl->index, &mdl->info.index, lin_alloc ); +/* load mesh */ +void mdl_async_load_glmesh( mdl_context *mdl, glmesh *mesh, u32 *fixup_table ); - mdl_array *pack = mdl_find_array( mdl, "pack" ); - if( pack ) mdl->pack_base_offset = pack->file_offset; - else mdl->pack_base_offset = 0; -} - -/* - * close file handle - */ -static void mdl_close( mdl_context *mdl ) -{ - fclose( mdl->file ); - mdl->file = NULL; -} - -/* useful things you can do with the model */ - -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] ); -} - -static const char *mdl_pstr( mdl_context *mdl, u32 pstr ) -{ - return ((char *)mdl_arritm( &mdl->strings, pstr )) + 4; -} +/* load textures and mesh */ +void mdl_async_full_load_std( mdl_context *mdl ); +/* rendering */ +void mdl_draw_submesh( mdl_submesh *sm ); +mdl_mesh *mdl_find_mesh( mdl_context *mdl, const char *name ); +mdl_submesh *mdl_find_submesh( mdl_context *mdl, const char *mesh_name ); -static int -mdl_pstreq( mdl_context *mdl, u32 pstr, const char *str, u32 djb2 ) -{ - u32 hash = *((u32 *)mdl_arritm( &mdl->strings, pstr )); - if( hash == djb2 ){ - if( !strcmp( str, mdl_pstr( mdl, pstr ))) return 1; - else return 0; - } - else return 0; -} - +/* pstrs */ +const char *mdl_pstr( mdl_context *mdl, u32 pstr ); +int mdl_pstreq( mdl_context *mdl, u32 pstr, const char *str, u32 djb2 ); #define MDL_CONST_PSTREQ( MDL, Q, CONSTSTR )\ mdl_pstreq( MDL, Q, CONSTSTR, vg_strdjb2( CONSTSTR ) ) -/* - * Simple mesh interface for OpenGL - * ---------------------------------------------------------------------------- - */ - -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 ); - - /* 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 mesh_bind( glmesh *mesh ) -{ - glBindVertexArray( mesh->vao ); -} - -static void mesh_drawn( u32 start, u32 count ) -{ - glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT, - (void *)(start*sizeof(u32)) ); -} +void mdl_transform_m4x3( mdl_transform *transform, m4x3f mtx ); -static void mesh_draw( glmesh *mesh ) -{ - mesh_drawn( 0, mesh->indice_count ); -} - -static void mesh_free( glmesh *mesh ) -{ - if( mesh->loaded ){ - glDeleteVertexArrays( 1, &mesh->vao ); - glDeleteBuffers( 1, &mesh->ebo ); - glDeleteBuffers( 1, &mesh->vbo ); - mesh->loaded = 0; - } -} - -static void mdl_draw_submesh( mdl_submesh *sm ) -{ - mesh_drawn( sm->indice_start, sm->indice_count ); -} - -static mdl_mesh *mdl_find_mesh( mdl_context *mdl, const char *name ) -{ - 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; -} - -struct payload_glmesh_load{ - mdl_vert *verts; - u32 *indices; - - u32 vertex_count, - indice_count; - - glmesh *mesh; -}; - -static void async_mdl_load_glmesh( void *payload, u32 size ) -{ - struct payload_glmesh_load *job = payload; - mesh_upload( job->mesh, job->verts, job->vertex_count, - job->indices, job->indice_count ); -} - -/* TODO: Find out if this needs deprecating in favour of the new full loader */ -static void mdl_async_load_glmesh( mdl_context *mdl, glmesh *mesh ) -{ - mdl_array *arr_vertices = mdl_find_array( mdl, "mdl_vert" ); - mdl_array *arr_indices = mdl_find_array( mdl, "mdl_indice" ); - - if( arr_vertices && arr_indices ){ - u32 size_verts = vg_align8(mdl_query_array_size( arr_vertices )), - size_indices = vg_align8(mdl_query_array_size( arr_indices )), - size_hdr = vg_align8(sizeof(struct payload_glmesh_load)), - total = size_hdr + size_verts + size_indices; - - vg_async_item *call = vg_async_alloc( total ); - struct payload_glmesh_load *job = call->payload; - - u8 *payload = call->payload; - - job->mesh = mesh; - job->verts = (void*)(payload + size_hdr); - job->indices = (void*)(payload + size_hdr + size_verts); - job->vertex_count = arr_vertices->item_count; - job->indice_count = arr_indices->item_count; - - mdl_load_array_file_buffer( mdl, arr_vertices, job->verts ); - mdl_load_array_file_buffer( mdl, arr_indices, job->indices ); - - /* - * Unpack the indices (if there are meshes) - * --------------------------------------------------------- - */ - - if( mdl_arrcount( &mdl->submeshs ) ){ - 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 = job->indices + sm->indice_start; - - for( u32 j=0; jindice_count; j++ ) - indices[j] += offset; - - offset += sm->vertex_count; - } - } - - /* - * Dispatch - * ------------------------- - */ - - vg_async_dispatch( call, async_mdl_load_glmesh ); - } - else{ - vg_fatal_error( "no vertex/indice data\n" ); - } -} - -/* uploads the glmesh, and textures. everything is saved into the mdl_context */ -static void mdl_async_full_load_std( mdl_context *mdl ){ - mdl_async_load_glmesh( mdl, &mdl->mesh ); - - for( u32 i=0; itextures ); i ++ ){ - vg_linear_clear( vg_mem.scratch ); - mdl_texture *tex = mdl_arritm( &mdl->textures, i ); - - void *data = vg_linear_alloc( vg_mem.scratch, tex->file.pack_size ); - mdl_fread_pack_file( mdl, &tex->file, data ); - - vg_tex2d_load_qoi_async( data, tex->file.pack_size, - VG_TEX2D_CLAMP|VG_TEX2D_NEAREST, &tex->glname ); - } -} - -#endif