2 * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved
8 #include "vg/vg_async.h"
10 #include "vg/vg_msg.h"
11 #include "vg/vg_string.h"
18 static void mdl_load_fatal_corrupt( mdl_context
*mdl
)
21 vg_file_print_invalid( mdl
->file
);
22 vg_fatal_error( "Corrupt model" );
26 * Model implementation
29 void mdl_fread_pack_file( mdl_context
*mdl
, mdl_file
*info
, void *dst
)
31 if( !info
->pack_size
)
33 vg_warn( "path: %s\n", mdl_pstr( mdl
, info
->pstr_path
) );
34 vg_fatal_error( "Packed file is only a header; it is not packed" );
37 fseek( mdl
->file
, mdl
->pack_base_offset
+info
->pack_offset
, SEEK_SET
);
38 u64 l
= fread( dst
, info
->pack_size
, 1, mdl
->file
);
40 if( l
!= 1 ) mdl_load_fatal_corrupt( mdl
);
43 /* TODO: Rename these */
44 static void mdl_load_array_file_buffer( mdl_context
*mdl
, mdl_array
*arr
,
45 void *buffer
, u32 stride
)
49 fseek( mdl
->file
, arr
->file_offset
, SEEK_SET
);
51 if( stride
== arr
->item_size
)
53 u64 l
= fread( buffer
, arr
->item_size
*arr
->item_count
, 1, mdl
->file
);
54 if( l
!= 1 ) mdl_load_fatal_corrupt( mdl
);
58 vg_warn( "Applying alignment fixup to array @%p [%u -> %u] x %u\n",
59 buffer
, arr
->item_size
, stride
, arr
->item_count
);
61 if( stride
> arr
->item_size
)
62 memset( buffer
, 0, stride
*arr
->item_count
);
64 u32 read_size
= VG_MIN( stride
, arr
->item_size
);
66 for( u32 i
=0; i
<arr
->item_count
; i
++ )
68 u64 l
= fread( buffer
+i
*stride
, read_size
, 1, mdl
->file
);
69 if( stride
< arr
->item_size
)
70 fseek( mdl
->file
, arr
->item_size
-stride
, SEEK_CUR
);
72 if( l
!= 1 ) mdl_load_fatal_corrupt( mdl
);
78 static void mdl_load_array_file( mdl_context
*mdl
, mdl_array_ptr
*ptr
,
79 mdl_array
*arr
, void *lin_alloc
, u32 stride
)
83 u32 size
= stride
*arr
->item_count
;
84 ptr
->data
= vg_linear_alloc( lin_alloc
, vg_align8(size
) );
85 mdl_load_array_file_buffer( mdl
, arr
, ptr
->data
, stride
);
93 ptr
->count
= arr
->item_count
;
96 void *mdl_arritm( mdl_array_ptr
*arr
, u32 index
)
98 return ((u8
*)arr
->data
) + index
*arr
->stride
;
101 u32
mdl_arrcount( mdl_array_ptr
*arr
)
106 static mdl_array
*mdl_find_array( mdl_context
*mdl
, const char *name
)
108 for( u32 i
=0; i
<mdl_arrcount(&mdl
->index
); i
++ )
110 mdl_array
*arr
= mdl_arritm( &mdl
->index
, i
);
112 if( !strncmp(arr
->name
,name
,16) )
119 int _mdl_load_array( mdl_context
*mdl
, mdl_array_ptr
*ptr
,
120 const char *name
, void *lin_alloc
, u32 stride
)
122 mdl_array
*arr
= mdl_find_array( mdl
, name
);
126 mdl_load_array_file( mdl
, ptr
, arr
, lin_alloc
, stride
);
138 int mdl_load_mesh_block( mdl_context
*mdl
, void *lin_alloc
)
142 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->verts
, mdl_vert
, lin_alloc
);
143 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->indices
, mdl_indice
, lin_alloc
);
148 int mdl_load_metadata_block( mdl_context
*mdl
, void *lin_alloc
)
152 success
&= _mdl_load_array( mdl
, &mdl
->strings
, "strings", lin_alloc
, 1 );
153 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->meshs
, mdl_mesh
, lin_alloc
);
154 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->submeshs
, mdl_submesh
, lin_alloc
);
155 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->textures
, mdl_texture
, lin_alloc
);
156 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->armatures
, mdl_armature
, lin_alloc
);
157 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->bones
, mdl_bone
, lin_alloc
);
158 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->animations
,mdl_animation
,lin_alloc
);
160 success
&= mdl_load_materials( mdl
, lin_alloc
);
165 int mdl_load_animation_block( mdl_context
*mdl
, void *lin_alloc
)
167 return MDL_LOAD_ARRAY( mdl
, &mdl
->keyframes
, mdl_keyframe
, lin_alloc
);
170 void *mdl_shader_standard( vg_msg
*msg
, void *alloc
)
172 struct shader_props_standard
*props
=
173 vg_linear_alloc( alloc
, sizeof(struct shader_props_standard
) );
175 vg_msg_getkvintg( msg
, "tex_diffuse", k_vg_msg_u32
, &props
->tex_diffuse
,
181 void *mdl_shader_terrain( vg_msg
*msg
, void *alloc
)
183 struct shader_props_terrain
*props
=
184 vg_linear_alloc( alloc
, sizeof(struct shader_props_terrain
) );
186 vg_msg_getkvintg( msg
, "tex_diffuse", k_vg_msg_u32
, &props
->tex_diffuse
,
188 vg_msg_getkvvecf( msg
, "sand_colour", k_vg_msg_v4f
,
189 props
->sand_colour
, (v4f
){ 0.79, 0.63, 0.48, 1.0 } );
190 vg_msg_getkvvecf( msg
, "blend_offset", k_vg_msg_v2f
,
191 props
->blend_offset
, (v2f
){ 0.5, 0.0 } );
196 void *mdl_shader_vertex_blend( vg_msg
*msg
, void *alloc
)
198 struct shader_props_vertex_blend
*props
=
199 vg_linear_alloc( alloc
, sizeof(struct shader_props_vertex_blend
) );
201 vg_msg_getkvintg( msg
, "tex_diffuse", k_vg_msg_u32
, &props
->tex_diffuse
,
203 vg_msg_getkvvecf( msg
, "blend_offset", k_vg_msg_v2f
,
204 props
->blend_offset
, (v2f
){ 0.5, 0.0 } );
208 void *mdl_shader_water( vg_msg
*msg
, void *alloc
)
210 struct shader_props_water
*props
=
211 vg_linear_alloc( alloc
, sizeof(struct shader_props_water
) );
213 vg_msg_getkvvecf( msg
, "shore_colour", k_vg_msg_v4f
,
214 props
->shore_colour
, (v4f
){0.03,0.32,0.61,1.0} );
215 vg_msg_getkvvecf( msg
, "deep_colour", k_vg_msg_v4f
,
216 props
->deep_colour
, (v4f
){0.0,0.006,0.03,1.0} );
217 vg_msg_getkvintg( msg
, "fog_scale", k_vg_msg_f32
, &props
->fog_scale
,
219 vg_msg_getkvintg( msg
, "fresnel", k_vg_msg_f32
, &props
->fresnel
,
221 vg_msg_getkvintg( msg
, "water_scale", k_vg_msg_f32
, &props
->water_sale
,
223 vg_msg_getkvvecf( msg
, "wave_speed", k_vg_msg_v4f
,
224 props
->wave_speed
, (v4f
){0.008,0.006,0.003,0.03} );
228 void *mdl_shader_cubemapped( vg_msg
*msg
, void *alloc
)
230 struct shader_props_cubemapped
*props
=
231 vg_linear_alloc( alloc
, sizeof(struct shader_props_cubemapped
) );
233 vg_msg_getkvintg( msg
, "tex_diffuse", k_vg_msg_u32
, &props
->tex_diffuse
,
235 vg_msg_getkvintg( msg
, "cubemap_entity", k_vg_msg_u32
,
236 &props
->cubemap_entity
, NULL
);
237 vg_msg_getkvvecf( msg
, "tint", k_vg_msg_v4f
,
238 props
->tint
, (v4f
){1.0,1.0,1.0,1.0} );
242 bool _mdl_legacy_v105_properties( struct mdl_material_v105
*mat
, vg_msg
*dst
)
244 vg_msg_wkvnum( dst
, "tex_diffuse", k_vg_msg_u32
, 1, &mat
->tex_diffuse
);
246 if( mat
->shader
== k_shader_cubemap
)
248 vg_msg_wkvnum( dst
, "cubemap", k_vg_msg_u32
, 1, &mat
->tex_none0
);
249 vg_msg_wkvnum( dst
, "tint", k_vg_msg_f32
, 4, mat
->colour
);
251 else if( mat
->shader
== k_shader_terrain_blend
)
253 vg_msg_wkvnum( dst
, "sand_colour", k_vg_msg_f32
, 4, mat
->colour
);
254 vg_msg_wkvnum( dst
, "blend_offset", k_vg_msg_f32
, 2, mat
->colour1
);
256 else if( mat
->shader
== k_shader_standard_vertex_blend
)
258 vg_msg_wkvnum( dst
, "blend_offset", k_vg_msg_f32
, 2, mat
->colour1
);
260 else if( mat
->shader
== k_shader_water
)
262 vg_msg_wkvnum( dst
, "shore_colour", k_vg_msg_f32
, 4, mat
->colour
);
263 vg_msg_wkvnum( dst
, "deep_colour", k_vg_msg_f32
, 4, mat
->colour1
);
269 int mdl_load_materials( mdl_context
*mdl
, void *lin_alloc
)
271 MDL_LOAD_ARRAY( mdl
, &mdl
->materials
, mdl_material
, lin_alloc
);
273 #if (MDL_VERSION_MIN <= 105)
274 /* load legacy material data into scratch */
275 mdl_array_ptr legacy_materials
;
276 if( mdl
->info
.version
<= 105 )
278 _mdl_load_array( mdl
, &legacy_materials
, "mdl_material", vg_mem
.scratch
,
279 sizeof(struct mdl_material_v105
) );
284 _mdl_load_array( mdl
, &data
, "shader_data", vg_mem
.scratch
, 1 );
286 for( u32 i
=0; i
<mdl_arrcount(&mdl
->materials
); i
++ )
288 mdl_material
*mat
= mdl_arritm( &mdl
->materials
, i
);
291 #if (MDL_VERSION_MIN <= 105)
293 if( mdl
->info
.version
<= 105 )
295 vg_msg_init( &msg
, legacy_buf
, sizeof(legacy_buf
) );
296 _mdl_legacy_v105_properties( mdl_arritm( &legacy_materials
,i
), &msg
);
297 vg_msg_init( &msg
, legacy_buf
, msg
.cur
.co
);
302 vg_msg_init( &msg
, data
.data
+ mat
->props
.kvs
.offset
,
303 mat
->props
.kvs
.size
);
306 if( mat
->shader
== k_shader_standard
||
307 mat
->shader
== k_shader_standard_cutout
||
308 mat
->shader
== k_shader_foliage
||
309 mat
->shader
== k_shader_fxglow
)
311 mat
->props
.compiled
= mdl_shader_standard( &msg
, lin_alloc
);
313 else if( mat
->shader
== k_shader_standard_vertex_blend
)
315 mat
->props
.compiled
= mdl_shader_vertex_blend( &msg
, lin_alloc
);
317 else if( mat
->shader
== k_shader_cubemap
)
319 mat
->props
.compiled
= mdl_shader_cubemapped( &msg
, lin_alloc
);
321 else if( mat
->shader
== k_shader_terrain_blend
)
323 mat
->props
.compiled
= mdl_shader_terrain( &msg
, lin_alloc
);
325 else if( mat
->shader
== k_shader_water
)
327 mat
->props
.compiled
= mdl_shader_water( &msg
, lin_alloc
);
330 mat
->props
.compiled
= NULL
;
337 * if calling mdl_open, and the file does not exist, the game will fatal quit
339 void mdl_open( mdl_context
*mdl
, const char *path
, void *lin_alloc
)
341 memset( mdl
, 0, sizeof( mdl_context
) );
342 mdl
->file
= fopen( path
, "rb" );
346 vg_error( "mdl_open('%s'): %s\n", path
, strerror(errno
) );
347 vg_fatal_error( "see above for details" );
350 u64 l
= fread( &mdl
->info
, sizeof(mdl_header
), 1, mdl
->file
);
352 mdl_load_fatal_corrupt( mdl
);
354 if( mdl
->info
.version
< MDL_VERSION_MIN
)
356 vg_warn( "For model: %s\n", path
);
357 vg_warn( " version: %u (min: %u, current: %u)\n",
358 mdl
->info
.version
, MDL_VERSION_MIN
, MDL_VERSION_NR
);
360 vg_fatal_error( "Legacy model version incompatable" );
363 mdl_load_array_file( mdl
, &mdl
->index
, &mdl
->info
.index
, lin_alloc
,
366 mdl_array
*pack
= mdl_find_array( mdl
, "pack" );
367 if( pack
) mdl
->pack_base_offset
= pack
->file_offset
;
368 else mdl
->pack_base_offset
= 0;
374 void mdl_close( mdl_context
*mdl
)
380 /* useful things you can do with the model */
382 void mdl_transform_m4x3( mdl_transform
*transform
, m4x3f mtx
)
384 q_m3x3( transform
->q
, mtx
);
385 v3_muls( mtx
[0], transform
->s
[0], mtx
[0] );
386 v3_muls( mtx
[1], transform
->s
[1], mtx
[1] );
387 v3_muls( mtx
[2], transform
->s
[2], mtx
[2] );
388 v3_copy( transform
->co
, mtx
[3] );
391 const char *mdl_pstr( mdl_context
*mdl
, u32 pstr
)
393 return ((char *)mdl_arritm( &mdl
->strings
, pstr
)) + 4;
397 int mdl_pstreq( mdl_context
*mdl
, u32 pstr
, const char *str
, u32 djb2
)
399 u32 hash
= *((u32
*)mdl_arritm( &mdl
->strings
, pstr
));
401 if( !strcmp( str
, mdl_pstr( mdl
, pstr
))) return 1;
408 * Simple mesh interface for OpenGL
409 * ----------------------------------------------------------------------------
412 static void mesh_upload( glmesh
*mesh
,
413 mdl_vert
*verts
, u32 vert_count
,
414 u32
*indices
, u32 indice_count
)
416 glGenVertexArrays( 1, &mesh
->vao
);
417 glGenBuffers( 1, &mesh
->vbo
);
418 glGenBuffers( 1, &mesh
->ebo
);
419 glBindVertexArray( mesh
->vao
);
421 size_t stride
= sizeof(mdl_vert
);
423 glBindBuffer( GL_ARRAY_BUFFER
, mesh
->vbo
);
424 glBufferData( GL_ARRAY_BUFFER
, vert_count
*stride
, verts
, GL_STATIC_DRAW
);
426 glBindVertexArray( mesh
->vao
);
427 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, mesh
->ebo
);
428 glBufferData( GL_ELEMENT_ARRAY_BUFFER
, indice_count
*sizeof(u32
),
429 indices
, GL_STATIC_DRAW
);
432 glVertexAttribPointer( 0, 3, GL_FLOAT
, GL_FALSE
, stride
, (void*)0 );
433 glEnableVertexAttribArray( 0 );
436 glVertexAttribPointer( 1, 3, GL_FLOAT
, GL_FALSE
,
437 stride
, (void *)offsetof(mdl_vert
, norm
) );
438 glEnableVertexAttribArray( 1 );
441 glVertexAttribPointer( 2, 2, GL_FLOAT
, GL_FALSE
,
442 stride
, (void *)offsetof(mdl_vert
, uv
) );
443 glEnableVertexAttribArray( 2 );
446 glVertexAttribPointer( 3, 4, GL_UNSIGNED_BYTE
, GL_TRUE
,
447 stride
, (void *)offsetof(mdl_vert
, colour
) );
448 glEnableVertexAttribArray( 3 );
451 glVertexAttribPointer( 4, 4, GL_UNSIGNED_SHORT
, GL_TRUE
,
452 stride
, (void *)offsetof(mdl_vert
, weights
) );
453 glEnableVertexAttribArray( 4 );
456 glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE
,
457 stride
, (void *)offsetof(mdl_vert
, groups
) );
458 glEnableVertexAttribArray( 5 );
462 mesh
->indice_count
= indice_count
;
466 void mesh_bind( glmesh
*mesh
)
468 glBindVertexArray( mesh
->vao
);
471 void mesh_drawn( u32 start
, u32 count
)
473 glDrawElements( GL_TRIANGLES
, count
, GL_UNSIGNED_INT
,
474 (void *)(start
*sizeof(u32
)) );
477 void mesh_draw( glmesh
*mesh
)
479 mesh_drawn( 0, mesh
->indice_count
);
482 void mesh_free( glmesh
*mesh
)
486 glDeleteVertexArrays( 1, &mesh
->vao
);
487 glDeleteBuffers( 1, &mesh
->ebo
);
488 glDeleteBuffers( 1, &mesh
->vbo
);
493 void mdl_draw_submesh( mdl_submesh
*sm
)
495 mesh_drawn( sm
->indice_start
, sm
->indice_count
);
498 mdl_mesh
*mdl_find_mesh( mdl_context
*mdl
, const char *name
)
500 for( u32 i
=0; i
<mdl_arrcount( &mdl
->meshs
); i
++ )
502 mdl_mesh
*mesh
= mdl_arritm( &mdl
->meshs
, i
);
503 if( !strcmp( name
, mdl_pstr( mdl
, mesh
->pstr_name
)))
511 struct payload_glmesh_load
522 static void _sync_mdl_load_glmesh( void *payload
, u32 size
)
524 struct payload_glmesh_load
*job
= payload
;
525 mesh_upload( job
->mesh
, job
->verts
, job
->vertex_count
,
526 job
->indices
, job
->indice_count
);
529 void mdl_async_load_glmesh( mdl_context
*mdl
, glmesh
*mesh
, u32
*fixup_table
)
531 mdl_array
*arr_vertices
= mdl_find_array( mdl
, "mdl_vert" );
532 mdl_array
*arr_indices
= mdl_find_array( mdl
, "mdl_indice" );
534 if( arr_vertices
&& arr_indices
)
536 u32 size_verts
= vg_align8(sizeof(mdl_vert
)*arr_vertices
->item_count
),
537 size_indices
= vg_align8(sizeof(mdl_indice
)*arr_indices
->item_count
),
538 size_hdr
= vg_align8(sizeof(struct payload_glmesh_load
)),
539 total
= size_hdr
+ size_verts
+ size_indices
;
541 vg_async_item
*call
= vg_async_alloc( total
);
542 struct payload_glmesh_load
*job
= call
->payload
;
544 u8
*payload
= call
->payload
;
547 job
->verts
= (void*)(payload
+ size_hdr
);
548 job
->indices
= (void*)(payload
+ size_hdr
+ size_verts
);
549 job
->vertex_count
= arr_vertices
->item_count
;
550 job
->indice_count
= arr_indices
->item_count
;
552 mdl_load_array_file_buffer( mdl
, arr_vertices
,
553 job
->verts
, sizeof(mdl_vert
) );
554 mdl_load_array_file_buffer( mdl
, arr_indices
, job
->indices
,
555 sizeof(mdl_indice
) );
559 for( u32 i
=0; i
<job
->vertex_count
; i
++ )
561 mdl_vert
*vert
= &job
->verts
[i
];
563 for( u32 j
=0; j
<4; j
++ )
565 vert
->groups
[j
] = fixup_table
[vert
->groups
[j
]];
571 * Unpack the indices (if there are meshes)
572 * ---------------------------------------------------------
575 if( mdl_arrcount( &mdl
->submeshs
) )
577 mdl_submesh
*sm
= mdl_arritm( &mdl
->submeshs
, 0 );
578 u32 offset
= sm
->vertex_count
;
580 for( u32 i
=1; i
<mdl_arrcount( &mdl
->submeshs
); i
++ )
582 mdl_submesh
*sm
= mdl_arritm( &mdl
->submeshs
, i
);
583 u32
*indices
= job
->indices
+ sm
->indice_start
;
585 for( u32 j
=0; j
<sm
->indice_count
; j
++ )
586 indices
[j
] += offset
;
588 offset
+= sm
->vertex_count
;
594 * -------------------------
597 vg_async_dispatch( call
, _sync_mdl_load_glmesh
);
601 vg_fatal_error( "no vertex/indice data\n" );
605 /* uploads the glmesh, and textures. everything is saved into the mdl_context */
606 void mdl_async_full_load_std( mdl_context
*mdl
)
608 mdl_async_load_glmesh( mdl
, &mdl
->mesh
, NULL
);
610 for( u32 i
=0; i
<mdl_arrcount( &mdl
->textures
); i
++ )
612 vg_linear_clear( vg_mem
.scratch
);
613 mdl_texture
*tex
= mdl_arritm( &mdl
->textures
, i
);
615 void *data
= vg_linear_alloc( vg_mem
.scratch
, tex
->file
.pack_size
);
616 mdl_fread_pack_file( mdl
, &tex
->file
, data
);
618 vg_tex2d_load_qoi_async( data
, tex
->file
.pack_size
,
619 VG_TEX2D_CLAMP
|VG_TEX2D_NEAREST
, &tex
->glname
);