2 * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved
10 #include "vg/vg_async.h"
11 #include "vg/vg_tex.h"
16 #define MDL_VERSION_MIN 101
17 #define MDL_VERSION_NR 105
20 k_shader_standard
= 0,
21 k_shader_standard_cutout
= 1,
22 k_shader_terrain_blend
= 2,
23 k_shader_standard_vertex_blend
= 3,
25 k_shader_invisible
= 5,
26 k_shader_boundary
= 6,
30 k_shader_foliage
= 10,
31 k_shader_override
= 30000
34 enum mdl_surface_prop
{
35 k_surface_prop_concrete
= 0,
36 k_surface_prop_wood
= 1,
37 k_surface_prop_grass
= 2,
38 k_surface_prop_tiles
= 3,
39 k_surface_prop_metal
= 4,
40 k_surface_prop_snow
= 5,
41 k_surface_prop_sand
= 6
45 k_material_flag_skate_target
= 0x0001,
46 k_material_flag_collision
= 0x0002,
47 k_material_flag_grow_grass
= 0x0004,
48 k_material_flag_grindable
= 0x0008,
49 k_material_flag_invisible
= 0x0010,
50 k_material_flag_boundary
= 0x0020,
51 k_material_flag_preview_visibile
= 0x0040,
52 k_material_flag_walking
= 0x0080,
54 k_material_flag_ghosts
=
55 k_material_flag_boundary
|
56 k_material_flag_invisible
|
57 k_material_flag_walking
69 u8 colour
[4]; /* 4*8 */
70 u16 weights
[4];/* 4*16 */
71 u8 groups
[4]; /* 4*8 */
76 typedef u32 mdl_indice
;
78 typedef struct mdl_context mdl_context
;
79 typedef struct mdl_array_ptr mdl_array_ptr
;
80 typedef struct mdl_vert mdl_vert
;
81 typedef struct mdl_transform mdl_transform
;
82 typedef struct mdl_submesh mdl_submesh
;
83 typedef struct mdl_material mdl_material
;
84 typedef struct mdl_bone mdl_bone
;
85 typedef struct mdl_armature mdl_armature
;
86 typedef struct mdl_animation mdl_animation
;
87 typedef struct mdl_transform mdl_keyframe
;
88 typedef struct mdl_mesh mdl_mesh
;
89 typedef struct mdl_file mdl_file
;
90 typedef struct mdl_texture mdl_texture
;
91 typedef struct mdl_array mdl_array
;
92 typedef struct mdl_header mdl_header
;
94 typedef struct glmesh glmesh
;
108 static void transform_identity( mdl_transform
*transform
)
110 v3_zero( transform
->co
);
111 q_identity( transform
->q
);
112 v3_fill( transform
->s
, 1.0f
);
115 static void mdl_transform_vector( mdl_transform
*transform
, v3f vec
, v3f dest
)
117 v3_mul( transform
->s
, vec
, dest
);
118 q_mulv( transform
->q
, dest
, dest
);
121 static void mdl_transform_point( mdl_transform
*transform
, v3f co
, v3f dest
)
123 mdl_transform_vector( transform
, co
, dest
);
124 v3_add( transform
->co
, dest
, dest
);
127 static void mdl_transform_mul( mdl_transform
*a
, mdl_transform
*b
,
130 mdl_transform_point( a
, b
->co
, d
->co
);
131 q_mul( a
->q
, b
->q
, d
->q
);
133 v3_mul( a
->s
, b
->s
, d
->s
);
162 v3f conevx
, conevy
, coneva
;
168 k_bone_flag_deform
= 0x00000001,
169 k_bone_flag_ik
= 0x00000002,
170 k_bone_flag_cone_constraint
= 0x00000004
175 k_bone_collider_none
= 0,
176 k_bone_collider_box
= 1,
177 k_bone_collider_capsule
= 2
182 mdl_transform transform
;
205 u16 material_id
, flags
;
210 k_submesh_flag_none
= 0x0000,
211 k_submesh_flag_consumed
= 0x0001
216 mdl_transform transform
;
220 entity_id
, /* upper 16 bits: type, lower 16 bits: index */
256 struct mdl_array_ptr
{
272 /* animation buffers */
278 u32 pack_base_offset
;
285 static void mdl_load_fatal_corrupt( mdl_context
*mdl
)
288 vg_file_print_invalid( mdl
->file
);
289 vg_fatal_error( "Corrupt model" );
293 * Model implementation
296 static const char *mdl_pstr( mdl_context
*mdl
, u32 pstr
);
298 void mdl_fread_pack_file( mdl_context
*mdl
, mdl_file
*info
, void *dst
)
300 if( !info
->pack_size
){
301 vg_warn( "path: %s\n", mdl_pstr( mdl
, info
->pstr_path
) );
302 vg_fatal_error( "Packed file is only a header; it is not packed" );
305 fseek( mdl
->file
, mdl
->pack_base_offset
+info
->pack_offset
, SEEK_SET
);
306 u64 l
= fread( dst
, info
->pack_size
, 1, mdl
->file
);
308 if( l
!= 1 ) mdl_load_fatal_corrupt( mdl
);
311 /* TODO: Rename these */
312 static void mdl_load_array_file_buffer( mdl_context
*mdl
, mdl_array
*arr
,
313 void *buffer
, u32 stride
)
315 if( arr
->item_count
){
316 fseek( mdl
->file
, arr
->file_offset
, SEEK_SET
);
318 if( stride
== arr
->item_size
){
319 u64 l
= fread( buffer
, arr
->item_size
*arr
->item_count
, 1, mdl
->file
);
320 if( l
!= 1 ) mdl_load_fatal_corrupt( mdl
);
323 vg_warn( "Applying alignment fixup to array @%p [%u -> %u] x %u\n",
324 buffer
, arr
->item_size
, stride
, arr
->item_count
);
325 if( stride
< arr
->item_size
)
326 vg_fatal_error( "not safe\n" );
328 for( u32 i
=0; i
<arr
->item_count
; i
++ ){
329 u64 l
= fread( buffer
+i
*stride
, arr
->item_size
, 1, mdl
->file
);
330 if( l
!= 1 ) mdl_load_fatal_corrupt( mdl
);
336 static void mdl_load_array_file( mdl_context
*mdl
, mdl_array_ptr
*ptr
,
337 mdl_array
*arr
, void *lin_alloc
, u32 stride
)
339 if( stride
< arr
->item_size
){
340 vg_error( "Structure max: %u. Got: %u\n", stride
, arr
->item_size
);
341 vg_fatal_error( "not safe\n" );
344 if( arr
->item_count
){
345 u32 size
= stride
*arr
->item_count
;
346 ptr
->data
= vg_linear_alloc( lin_alloc
, vg_align8(size
) );
347 mdl_load_array_file_buffer( mdl
, arr
, ptr
->data
, stride
);
353 ptr
->stride
= stride
;
354 ptr
->count
= arr
->item_count
;
357 static void *mdl_arritm( mdl_array_ptr
*arr
, u32 index
)
359 return ((u8
*)arr
->data
) + index
*arr
->stride
;
362 static u32
mdl_arrcount( mdl_array_ptr
*arr
)
367 static mdl_array
*mdl_find_array( mdl_context
*mdl
, const char *name
)
369 for( u32 i
=0; i
<mdl_arrcount(&mdl
->index
); i
++ ){
370 mdl_array
*arr
= mdl_arritm( &mdl
->index
, i
);
372 if( !strncmp(arr
->name
,name
,16) ){
380 static int _mdl_load_array( mdl_context
*mdl
, mdl_array_ptr
*ptr
,
381 const char *name
, void *lin_alloc
, u32 stride
)
383 mdl_array
*arr
= mdl_find_array( mdl
, name
);
386 mdl_load_array_file( mdl
, ptr
, arr
, lin_alloc
, stride
);
397 #define MDL_LOAD_ARRAY( MDL, PTR, STRUCT, ALLOCATOR ) \
398 _mdl_load_array( MDL, PTR, #STRUCT, ALLOCATOR, sizeof(STRUCT) )
400 static int mdl_load_mesh_block( mdl_context
*mdl
, void *lin_alloc
){
403 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->verts
, mdl_vert
, lin_alloc
);
404 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->indices
, mdl_indice
, lin_alloc
);
409 static int mdl_load_metadata_block( mdl_context
*mdl
, void *lin_alloc
){
412 success
&= _mdl_load_array( mdl
, &mdl
->strings
, "strings", lin_alloc
, 1 );
413 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->meshs
, mdl_mesh
, lin_alloc
);
414 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->submeshs
, mdl_submesh
, lin_alloc
);
415 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->materials
, mdl_material
, lin_alloc
);
416 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->textures
, mdl_texture
, lin_alloc
);
417 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->armatures
, mdl_armature
, lin_alloc
);
418 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->bones
, mdl_bone
, lin_alloc
);
419 success
&= MDL_LOAD_ARRAY( mdl
, &mdl
->animations
,mdl_animation
,lin_alloc
);
424 static int mdl_load_animation_block( mdl_context
*mdl
, void *lin_alloc
){
425 return MDL_LOAD_ARRAY( mdl
, &mdl
->keyframes
, mdl_keyframe
, lin_alloc
);
429 * if calling mdl_open, and the file does not exist, the game will fatal quit
431 static void mdl_open( mdl_context
*mdl
, const char *path
, void *lin_alloc
)
433 memset( mdl
, 0, sizeof( mdl_context
) );
434 mdl
->file
= fopen( path
, "rb" );
437 vg_error( "mdl_open('%s'): %s\n", path
, strerror(errno
) );
438 vg_fatal_error( "see above for details" );
441 u64 l
= fread( &mdl
->info
, sizeof(mdl_header
), 1, mdl
->file
);
443 mdl_load_fatal_corrupt( mdl
);
445 if( mdl
->info
.version
< MDL_VERSION_MIN
){
446 vg_warn( "For model: %s\n", path
);
447 vg_warn( " version: %u (min: %u, current: %u)\n",
448 mdl
->info
.version
, MDL_VERSION_MIN
, MDL_VERSION_NR
);
450 vg_fatal_error( "Legacy model version incompatable" );
453 mdl_load_array_file( mdl
, &mdl
->index
, &mdl
->info
.index
, lin_alloc
,
456 mdl_array
*pack
= mdl_find_array( mdl
, "pack" );
457 if( pack
) mdl
->pack_base_offset
= pack
->file_offset
;
458 else mdl
->pack_base_offset
= 0;
464 static void mdl_close( mdl_context
*mdl
)
470 /* useful things you can do with the model */
472 static void mdl_transform_m4x3( mdl_transform
*transform
, m4x3f mtx
)
474 q_m3x3( transform
->q
, mtx
);
475 v3_muls( mtx
[0], transform
->s
[0], mtx
[0] );
476 v3_muls( mtx
[1], transform
->s
[1], mtx
[1] );
477 v3_muls( mtx
[2], transform
->s
[2], mtx
[2] );
478 v3_copy( transform
->co
, mtx
[3] );
481 static const char *mdl_pstr( mdl_context
*mdl
, u32 pstr
)
483 return ((char *)mdl_arritm( &mdl
->strings
, pstr
)) + 4;
488 mdl_pstreq( mdl_context
*mdl
, u32 pstr
, const char *str
, u32 djb2
)
490 u32 hash
= *((u32
*)mdl_arritm( &mdl
->strings
, pstr
));
492 if( !strcmp( str
, mdl_pstr( mdl
, pstr
))) return 1;
498 #define MDL_CONST_PSTREQ( MDL, Q, CONSTSTR )\
499 mdl_pstreq( MDL, Q, CONSTSTR, vg_strdjb2( CONSTSTR ) )
502 * Simple mesh interface for OpenGL
503 * ----------------------------------------------------------------------------
506 static void mesh_upload( glmesh
*mesh
,
507 mdl_vert
*verts
, u32 vert_count
,
508 u32
*indices
, u32 indice_count
)
510 //assert( mesh->loaded == 0 );
512 glGenVertexArrays( 1, &mesh
->vao
);
513 glGenBuffers( 1, &mesh
->vbo
);
514 glGenBuffers( 1, &mesh
->ebo
);
515 glBindVertexArray( mesh
->vao
);
517 size_t stride
= sizeof(mdl_vert
);
519 glBindBuffer( GL_ARRAY_BUFFER
, mesh
->vbo
);
520 glBufferData( GL_ARRAY_BUFFER
, vert_count
*stride
, verts
, GL_STATIC_DRAW
);
522 glBindVertexArray( mesh
->vao
);
523 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, mesh
->ebo
);
524 glBufferData( GL_ELEMENT_ARRAY_BUFFER
, indice_count
*sizeof(u32
),
525 indices
, GL_STATIC_DRAW
);
528 glVertexAttribPointer( 0, 3, GL_FLOAT
, GL_FALSE
, stride
, (void*)0 );
529 glEnableVertexAttribArray( 0 );
532 glVertexAttribPointer( 1, 3, GL_FLOAT
, GL_FALSE
,
533 stride
, (void *)offsetof(mdl_vert
, norm
) );
534 glEnableVertexAttribArray( 1 );
537 glVertexAttribPointer( 2, 2, GL_FLOAT
, GL_FALSE
,
538 stride
, (void *)offsetof(mdl_vert
, uv
) );
539 glEnableVertexAttribArray( 2 );
542 glVertexAttribPointer( 3, 4, GL_UNSIGNED_BYTE
, GL_TRUE
,
543 stride
, (void *)offsetof(mdl_vert
, colour
) );
544 glEnableVertexAttribArray( 3 );
547 glVertexAttribPointer( 4, 4, GL_UNSIGNED_SHORT
, GL_TRUE
,
548 stride
, (void *)offsetof(mdl_vert
, weights
) );
549 glEnableVertexAttribArray( 4 );
552 glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE
,
553 stride
, (void *)offsetof(mdl_vert
, groups
) );
554 glEnableVertexAttribArray( 5 );
558 mesh
->indice_count
= indice_count
;
562 static void mesh_bind( glmesh
*mesh
)
564 glBindVertexArray( mesh
->vao
);
567 static void mesh_drawn( u32 start
, u32 count
)
569 glDrawElements( GL_TRIANGLES
, count
, GL_UNSIGNED_INT
,
570 (void *)(start
*sizeof(u32
)) );
573 static void mesh_draw( glmesh
*mesh
)
575 mesh_drawn( 0, mesh
->indice_count
);
578 static void mesh_free( glmesh
*mesh
)
581 glDeleteVertexArrays( 1, &mesh
->vao
);
582 glDeleteBuffers( 1, &mesh
->ebo
);
583 glDeleteBuffers( 1, &mesh
->vbo
);
588 static void mdl_draw_submesh( mdl_submesh
*sm
)
590 mesh_drawn( sm
->indice_start
, sm
->indice_count
);
593 static mdl_mesh
*mdl_find_mesh( mdl_context
*mdl
, const char *name
)
595 for( u32 i
=0; i
<mdl_arrcount( &mdl
->meshs
); i
++ ){
596 mdl_mesh
*mesh
= mdl_arritm( &mdl
->meshs
, i
);
597 if( !strcmp( name
, mdl_pstr( mdl
, mesh
->pstr_name
))){
604 struct payload_glmesh_load
{
614 static void async_mdl_load_glmesh( void *payload
, u32 size
)
616 struct payload_glmesh_load
*job
= payload
;
617 mesh_upload( job
->mesh
, job
->verts
, job
->vertex_count
,
618 job
->indices
, job
->indice_count
);
621 static void mdl_async_load_glmesh( mdl_context
*mdl
, glmesh
*mesh
,
623 mdl_array
*arr_vertices
= mdl_find_array( mdl
, "mdl_vert" );
624 mdl_array
*arr_indices
= mdl_find_array( mdl
, "mdl_indice" );
626 if( arr_vertices
&& arr_indices
){
627 u32 size_verts
= vg_align8(sizeof(mdl_vert
)*arr_vertices
->item_count
),
628 size_indices
= vg_align8(sizeof(mdl_indice
)*arr_indices
->item_count
),
629 size_hdr
= vg_align8(sizeof(struct payload_glmesh_load
)),
630 total
= size_hdr
+ size_verts
+ size_indices
;
632 vg_async_item
*call
= vg_async_alloc( total
);
633 struct payload_glmesh_load
*job
= call
->payload
;
635 u8
*payload
= call
->payload
;
638 job
->verts
= (void*)(payload
+ size_hdr
);
639 job
->indices
= (void*)(payload
+ size_hdr
+ size_verts
);
640 job
->vertex_count
= arr_vertices
->item_count
;
641 job
->indice_count
= arr_indices
->item_count
;
643 mdl_load_array_file_buffer( mdl
, arr_vertices
,
644 job
->verts
, sizeof(mdl_vert
) );
645 mdl_load_array_file_buffer( mdl
, arr_indices
, job
->indices
,
646 sizeof(mdl_indice
) );
649 for( u32 i
=0; i
<job
->vertex_count
; i
++ ){
650 mdl_vert
*vert
= &job
->verts
[i
];
652 for( u32 j
=0; j
<4; j
++ ){
653 vert
->groups
[j
] = fixup_table
[vert
->groups
[j
]];
659 * Unpack the indices (if there are meshes)
660 * ---------------------------------------------------------
663 if( mdl_arrcount( &mdl
->submeshs
) ){
664 mdl_submesh
*sm
= mdl_arritm( &mdl
->submeshs
, 0 );
665 u32 offset
= sm
->vertex_count
;
667 for( u32 i
=1; i
<mdl_arrcount( &mdl
->submeshs
); i
++ ){
668 mdl_submesh
*sm
= mdl_arritm( &mdl
->submeshs
, i
);
669 u32
*indices
= job
->indices
+ sm
->indice_start
;
671 for( u32 j
=0; j
<sm
->indice_count
; j
++ )
672 indices
[j
] += offset
;
674 offset
+= sm
->vertex_count
;
680 * -------------------------
683 vg_async_dispatch( call
, async_mdl_load_glmesh
);
686 vg_fatal_error( "no vertex/indice data\n" );
690 /* uploads the glmesh, and textures. everything is saved into the mdl_context */
691 static void mdl_async_full_load_std( mdl_context
*mdl
){
692 mdl_async_load_glmesh( mdl
, &mdl
->mesh
, NULL
);
694 for( u32 i
=0; i
<mdl_arrcount( &mdl
->textures
); i
++ ){
695 vg_linear_clear( vg_mem
.scratch
);
696 mdl_texture
*tex
= mdl_arritm( &mdl
->textures
, i
);
698 void *data
= vg_linear_alloc( vg_mem
.scratch
, tex
->file
.pack_size
);
699 mdl_fread_pack_file( mdl
, &tex
->file
, data
);
701 vg_tex2d_load_qoi_async( data
, tex
->file
.pack_size
,
702 VG_TEX2D_CLAMP
|VG_TEX2D_NEAREST
, &tex
->glname
);