2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
13 k_shader_standard
= 0,
14 k_shader_standard_cutout
= 1,
15 k_shader_terrain_blend
= 2,
16 k_shader_standard_vertex_blend
= 3,
22 k_surface_prop_concrete
= 0,
23 k_surface_prop_wood
= 1,
24 k_surface_prop_grass
= 2,
25 k_surface_prop_tiles
= 3,
26 k_surface_prop_metal
= 4
31 k_material_flag_skate_surface
= 0x1,
32 k_material_flag_collision
= 0x2,
33 k_material_flag_grow_grass
= 0x4,
34 k_material_flag_grind_surface
= 0x8
46 u8 colour
[4]; /* 4*8 */
47 u16 weights
[4];/* 4*16 */
48 u8 groups
[4]; /* 4*8 */
53 typedef struct mdl_context mdl_context
;
54 typedef struct mdl_array_ptr mdl_array_ptr
;
55 typedef struct mdl_vert mdl_vert
;
56 typedef struct mdl_transform mdl_transform
;
57 typedef struct mdl_submesh mdl_submesh
;
58 typedef struct mdl_material mdl_material
;
59 typedef struct mdl_bone mdl_bone
;
60 typedef struct mdl_armature mdl_armature
;
61 typedef struct mdl_animation mdl_animation
;
62 typedef struct mdl_transform mdl_keyframe
;
63 typedef struct mdl_mesh mdl_mesh
;
64 typedef struct mdl_file mdl_file
;
65 typedef struct mdl_texture mdl_texture
;
66 typedef struct mdl_array mdl_array
;
67 typedef struct mdl_header mdl_header
;
112 v3f conevx
, conevy
, coneva
;
118 k_bone_flag_deform
= 0x1,
119 k_bone_flag_ik
= 0x2,
120 k_bone_flag_cone_constraint
= 0x4
125 k_bone_collider_none
= 0,
126 k_bone_collider_box
= 1,
127 k_bone_collider_capsule
= 2
132 mdl_transform transform
;
149 mdl_transform transform
;
207 /* animation buffers */
219 VG_STATIC
void mdl_load_fatal_corrupt( mdl_context
*mdl
)
222 vg_file_print_invalid( mdl
->file
);
223 vg_fatal_exit_loop( "Corrupt model" );
227 * Model implementation
230 VG_STATIC
void mdl_load_array_file( mdl_context
*mdl
, mdl_array_ptr
*ptr
,
231 mdl_array
*arr
, void *lin_alloc
)
233 if( arr
->item_count
){
234 u32 size
= arr
->item_size
*arr
->item_count
;
235 ptr
->data
= vg_linear_alloc( lin_alloc
, vg_align8(size
) );
237 fseek( mdl
->file
, arr
->file_offset
, SEEK_SET
);
238 u64 l
= fread( ptr
->data
, arr
->item_size
*arr
->item_count
, 1, mdl
->file
);
241 mdl_load_fatal_corrupt( mdl
);
246 ptr
->count
= arr
->item_count
;
247 ptr
->stride
= arr
->item_size
;
250 VG_STATIC
void *mdl_arritm( mdl_array_ptr
*arr
, u32 index
)
252 return ((u8
*)arr
->data
) + index
*arr
->stride
;
255 VG_STATIC u32
mdl_arrcount( mdl_array_ptr
*arr
)
260 VG_STATIC
int mdl_load_array( mdl_context
*mdl
, mdl_array_ptr
*ptr
,
261 const char *name
, void *lin_alloc
)
263 for( u32 i
=0; i
<mdl_arrcount(&mdl
->index
); i
++ ){
264 mdl_array
*arr
= mdl_arritm( &mdl
->index
, i
);
266 if( !strncmp(arr
->name
,name
,16) ){
267 mdl_load_array_file( mdl
, ptr
, arr
, lin_alloc
);
278 VG_STATIC
int mdl_load_mesh_block( mdl_context
*mdl
, void *lin_alloc
)
282 success
&= mdl_load_array( mdl
, &mdl
->verts
, "mdl_vert", lin_alloc
);
283 success
&= mdl_load_array( mdl
, &mdl
->indices
, "mdl_indice", lin_alloc
);
288 VG_STATIC
int mdl_load_metadata_block( mdl_context
*mdl
, void *lin_alloc
)
292 success
&= mdl_load_array( mdl
, &mdl
->strings
, "strings", lin_alloc
);
293 success
&= mdl_load_array( mdl
, &mdl
->meshs
, "mdl_mesh", lin_alloc
);
294 success
&= mdl_load_array( mdl
, &mdl
->submeshs
, "mdl_submesh", lin_alloc
);
295 success
&= mdl_load_array( mdl
, &mdl
->materials
, "mdl_material", lin_alloc
);
296 success
&= mdl_load_array( mdl
, &mdl
->textures
, "mdl_texture", lin_alloc
);
297 success
&= mdl_load_array( mdl
, &mdl
->armatures
, "mdl_armature", lin_alloc
);
298 success
&= mdl_load_array( mdl
, &mdl
->bones
, "mdl_bone", lin_alloc
);
299 success
&= mdl_load_array( mdl
, &mdl
->animations
,"mdl_animation",lin_alloc
);
304 VG_STATIC
int mdl_load_animation_block( mdl_context
*mdl
, void *lin_alloc
)
306 return mdl_load_array( mdl
, &mdl
->keyframes
, "mdl_keyframe", lin_alloc
);
309 VG_STATIC
int mdl_load_pack_block( mdl_context
*mdl
, void *lin_alloc
)
311 return mdl_load_array( mdl
, &mdl
->pack
, "pack", lin_alloc
);
315 * if calling mdl_open, and the file does not exist, the game will fatal quit
317 VG_STATIC
void mdl_open( mdl_context
*mdl
, const char *path
, void *lin_alloc
)
319 memset( mdl
, 0, sizeof( mdl_context
) );
320 mdl
->file
= fopen( path
, "rb" );
323 vg_error( "mdl_open('%s'): %s\n", path
, strerror(errno
) );
324 vg_fatal_exit_loop( "see above for details" );
327 u64 l
= fread( &mdl
->info
, sizeof(mdl_header
), 1, mdl
->file
);
329 mdl_load_fatal_corrupt( mdl
);
331 mdl_load_array_file( mdl
, &mdl
->index
, &mdl
->info
.index
, lin_alloc
);
337 VG_STATIC
void mdl_close( mdl_context
*mdl
)
343 /* useful things you can do with the model */
345 VG_STATIC
void mdl_transform_m4x3( mdl_transform
*transform
, m4x3f mtx
)
347 q_m3x3( transform
->q
, mtx
);
348 v3_muls( mtx
[0], transform
->s
[0], mtx
[0] );
349 v3_muls( mtx
[1], transform
->s
[1], mtx
[1] );
350 v3_muls( mtx
[2], transform
->s
[2], mtx
[2] );
351 v3_copy( transform
->co
, mtx
[3] );
354 VG_STATIC
const char *mdl_pstr( mdl_context
*mdl
, u32 pstr
)
356 return mdl_arritm( &mdl
->strings
, pstr
);
360 * Simple mesh interface for OpenGL
361 * ----------------------------------------------------------------------------
364 typedef struct glmesh glmesh
;
367 GLuint vao
, vbo
, ebo
;
372 VG_STATIC
void mesh_upload( glmesh
*mesh
,
373 mdl_vert
*verts
, u32 vert_count
,
374 u32
*indices
, u32 indice_count
)
376 //assert( mesh->loaded == 0 );
378 glGenVertexArrays( 1, &mesh
->vao
);
379 glGenBuffers( 1, &mesh
->vbo
);
380 glGenBuffers( 1, &mesh
->ebo
);
381 glBindVertexArray( mesh
->vao
);
383 size_t stride
= sizeof(mdl_vert
);
385 glBindBuffer( GL_ARRAY_BUFFER
, mesh
->vbo
);
386 glBufferData( GL_ARRAY_BUFFER
, vert_count
*stride
, verts
, GL_STATIC_DRAW
);
388 glBindVertexArray( mesh
->vao
);
389 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, mesh
->ebo
);
390 glBufferData( GL_ELEMENT_ARRAY_BUFFER
, indice_count
*sizeof(u32
),
391 indices
, GL_STATIC_DRAW
);
394 glVertexAttribPointer( 0, 3, GL_FLOAT
, GL_FALSE
, stride
, (void*)0 );
395 glEnableVertexAttribArray( 0 );
398 glVertexAttribPointer( 1, 3, GL_FLOAT
, GL_FALSE
,
399 stride
, (void *)offsetof(mdl_vert
, norm
) );
400 glEnableVertexAttribArray( 1 );
403 glVertexAttribPointer( 2, 2, GL_FLOAT
, GL_FALSE
,
404 stride
, (void *)offsetof(mdl_vert
, uv
) );
405 glEnableVertexAttribArray( 2 );
408 glVertexAttribPointer( 3, 4, GL_UNSIGNED_BYTE
, GL_TRUE
,
409 stride
, (void *)offsetof(mdl_vert
, colour
) );
410 glEnableVertexAttribArray( 3 );
413 glVertexAttribPointer( 4, 4, GL_UNSIGNED_SHORT
, GL_TRUE
,
414 stride
, (void *)offsetof(mdl_vert
, weights
) );
415 glEnableVertexAttribArray( 4 );
418 glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE
,
419 stride
, (void *)offsetof(mdl_vert
, groups
) );
420 glEnableVertexAttribArray( 5 );
424 mesh
->indice_count
= indice_count
;
428 VG_STATIC
void mesh_bind( glmesh
*mesh
)
430 glBindVertexArray( mesh
->vao
);
433 VG_STATIC
void mesh_drawn( u32 start
, u32 count
)
435 glDrawElements( GL_TRIANGLES
, count
, GL_UNSIGNED_INT
,
436 (void *)(start
*sizeof(u32
)) );
439 VG_STATIC
void mesh_draw( glmesh
*mesh
)
441 mesh_drawn( 0, mesh
->indice_count
);
444 VG_STATIC
void mesh_free( glmesh
*mesh
)
447 glDeleteVertexArrays( 1, &mesh
->vao
);
448 glDeleteBuffers( 1, &mesh
->ebo
);
449 glDeleteBuffers( 1, &mesh
->vbo
);
454 VG_STATIC
void mdl_draw_submesh( mdl_submesh
*sm
)
456 mesh_drawn( sm
->indice_start
, sm
->indice_count
);
459 /* WARNING: Destructive! Only use this once and then discard the context. */
460 VG_STATIC
void mdl_unpack_glmesh( mdl_context
*mdl
, glmesh
*mesh
)
462 if( !mdl
->submeshs
.count
)
463 vg_fatal_exit_loop( "Tried to unpack empty model file" );
465 mdl_submesh
*sm
= mdl_arritm( &mdl
->submeshs
, 0 );
466 u32 offset
= sm
->vertex_count
;
468 for( u32 i
=1; i
<mdl_arrcount( &mdl
->submeshs
); i
++ ){
469 mdl_submesh
*sm
= mdl_arritm( &mdl
->submeshs
, i
);
470 u32
*indices
= mdl_arritm( &mdl
->indices
, sm
->indice_start
);
472 for( u32 j
=0; j
<sm
->indice_count
; j
++ )
473 indices
[j
] += offset
;
475 offset
+= sm
->vertex_count
;
478 mesh_upload( mesh
, mdl
->verts
.data
, mdl
->verts
.count
,
479 mdl
->indices
.data
, mdl
->indices
.count
);
482 VG_STATIC mdl_mesh
*mdl_find_mesh( mdl_context
*mdl
, const char *name
)
484 for( u32 i
=0; i
<mdl_arrcount( &mdl
->meshs
); i
++ ){
485 mdl_mesh
*mesh
= mdl_arritm( &mdl
->meshs
, i
);
486 if( !strcmp( name
, mdl_pstr( mdl
, mesh
->pstr_name
))){