2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
10 typedef struct glmesh glmesh
;
12 typedef struct mdl_vert mdl_vert
;
13 typedef struct mdl_submesh mdl_submesh
;
14 typedef struct mdl_material mdl_material
;
15 typedef struct mdl_node mdl_node
;
16 typedef struct mdl_header mdl_header
;
17 typedef struct mdl_animation mdl_animation
;
18 typedef struct mdl_keyframe mdl_keyframe
;
20 #define MDL_SIZE_MAX 0x1000000
21 #define MDL_VERT_MAX 1000000
22 #define MDL_INDICE_MAX 1000000
23 #define MDL_MATERIAL_MAX 32
24 #define MDL_NODE_MAX 4000
25 #define MDL_SUBMESH_MAX 8000
26 #define MDL_STRING_LENGTH_MAX 64
32 k_classtype_block
= 2,
33 k_classtype_spawn
= 3,
34 k_classtype_water
= 4,
35 k_classtype_car_path
= 5,
36 k_classtype_instance
= 6,
37 k_classtype_capsule
= 7,
38 k_classtype_route_node
= 8,
39 k_classtype_route
= 9,
40 k_classtype_bone
= 10,
41 k_classtype_skeleton
= 11,
42 k_classtype_skin
= 12,
43 k_classtype_achievement_box
= 13,
44 k_classtype_audio
= 14
82 union{ u32 submesh_start
, sub_uid
; };
111 u32 identifier
, version
, file_length
;
113 u32 vertex_count
, vertex_offset
,
114 indice_count
, indice_offset
,
115 submesh_count
, submesh_offset
,
116 material_count
, material_offset
,
117 node_count
, node_offset
,
118 anim_count
, anim_offset
,
119 strings_offset
, entdata_offset
, animdata_offset
;
123 * Entity data structures
126 struct classtype_block
131 struct classtype_gate
137 struct classtype_spawn
142 struct classtype_water
147 struct classtype_car_path
152 struct classtype_instance
157 struct classtype_capsule
159 float height
, radius
;
162 struct classtype_route_node
167 struct classtype_route
173 struct classtype_bone
185 struct classtype_skeleton
194 struct classtype_skin
199 struct classtype_achievement_box
205 struct classtype_audio
216 * Simple mesh interface for OpenGL
221 GLuint vao
, vbo
, ebo
;
226 static void mesh_upload( glmesh
*mesh
,
227 mdl_vert
*verts
, u32 vert_count
,
228 u32
*indices
, u32 indice_count
)
230 //assert( mesh->loaded == 0 );
232 glGenVertexArrays( 1, &mesh
->vao
);
233 glGenBuffers( 1, &mesh
->vbo
);
234 glGenBuffers( 1, &mesh
->ebo
);
235 glBindVertexArray( mesh
->vao
);
237 size_t stride
= sizeof(mdl_vert
);
239 glBindBuffer( GL_ARRAY_BUFFER
, mesh
->vbo
);
240 glBufferData( GL_ARRAY_BUFFER
, vert_count
*stride
, verts
, GL_STATIC_DRAW
);
242 glBindVertexArray( mesh
->vao
);
243 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, mesh
->ebo
);
244 glBufferData( GL_ELEMENT_ARRAY_BUFFER
, indice_count
*sizeof(u32
),
245 indices
, GL_STATIC_DRAW
);
248 glVertexAttribPointer( 0, 3, GL_FLOAT
, GL_FALSE
, stride
, (void*)0 );
249 glEnableVertexAttribArray( 0 );
252 glVertexAttribPointer( 1, 3, GL_FLOAT
, GL_FALSE
,
253 stride
, (void *)offsetof(mdl_vert
, norm
) );
254 glEnableVertexAttribArray( 1 );
257 glVertexAttribPointer( 2, 2, GL_FLOAT
, GL_FALSE
,
258 stride
, (void *)offsetof(mdl_vert
, uv
) );
259 glEnableVertexAttribArray( 2 );
262 glVertexAttribPointer( 3, 4, GL_UNSIGNED_BYTE
, GL_TRUE
,
263 stride
, (void *)offsetof(mdl_vert
, colour
) );
264 glEnableVertexAttribArray( 3 );
267 glVertexAttribPointer( 4, 4, GL_UNSIGNED_SHORT
, GL_TRUE
,
268 stride
, (void *)offsetof(mdl_vert
, weights
) );
269 glEnableVertexAttribArray( 4 );
272 glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE
,
273 stride
, (void *)offsetof(mdl_vert
, groups
) );
274 glEnableVertexAttribArray( 5 );
278 mesh
->indice_count
= indice_count
;
282 static void mesh_bind( glmesh
*mesh
)
284 glBindVertexArray( mesh
->vao
);
287 static void mesh_drawn( u32 start
, u32 count
)
289 glDrawElements( GL_TRIANGLES
, count
, GL_UNSIGNED_INT
,
290 (void *)(start
*sizeof(u32
)) );
293 static void mesh_draw( glmesh
*mesh
)
295 mesh_drawn( 0, mesh
->indice_count
);
298 static void mesh_free( glmesh
*mesh
)
302 glDeleteVertexArrays( 1, &mesh
->vao
);
303 glDeleteBuffers( 1, &mesh
->ebo
);
304 glDeleteBuffers( 1, &mesh
->vbo
);
310 * Model implementation
313 static mdl_header
*mdl_load( const char *path
)
316 mdl_header
*header
= vg_asset_read_s( path
, &size
);
319 * Check file is valid
323 vg_error( "Could not open '%s'\n", path
);
327 if( size
< sizeof(mdl_header
) )
330 vg_error( "Invalid file '%s' (too small for header)\n", path
);
334 if( header
->file_length
!= size
)
336 vg_error( "Invalid file '%s'"
337 "(wrong .file_length, %ub != real file size %ub)\n",
338 path
, header
->file_length
, size
);
344 * Validate offsets and memory sections, to ensure all arrays are in-bounds,
345 * and that they do not overlap.
351 u32 count
, max_count
, size
, offset
;
356 header
->vertex_count
, MDL_VERT_MAX
,
357 sizeof(mdl_vert
), header
->vertex_offset
361 header
->indice_count
, MDL_INDICE_MAX
,
362 sizeof(u32
), header
->indice_offset
366 header
->submesh_count
, MDL_SUBMESH_MAX
,
367 sizeof(mdl_submesh
), header
->submesh_offset
371 header
->material_count
, MDL_MATERIAL_MAX
,
372 sizeof(mdl_material
), header
->material_offset
376 header
->node_count
, MDL_NODE_MAX
,
377 sizeof(mdl_node
), header
->node_count
381 for( int i
=0; i
<vg_list_size(regions
); i
++ )
383 struct memregion
*ri
= ®ions
[i
];
388 if( ri
->count
> ri
->max_count
)
391 vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n",
392 path
, ri
->desc
, ri
->count
, ri
->max_count
);
396 if( ri
->offset
>= header
->file_length
)
399 vg_error( "'%s': '%s' buffer offset is out of range\n",
404 if( ri
->offset
+ ri
->size
*ri
->count
> header
->file_length
)
407 vg_error( "'%s': '%s' buffer size is out of range\n",
412 for( int j
=0; j
<vg_list_size(regions
); j
++ )
414 struct memregion
*rj
= ®ions
[j
];
418 if( ri
->offset
>= rj
->offset
&&
419 (ri
->offset
+ri
->size
*ri
->count
< rj
->offset
+rj
->size
*rj
->count
))
422 vg_error( "'%s': '%s' buffer overlaps '%s'\n",
423 path
, ri
->desc
, rj
->desc
);
430 * Pointer validation TODO(workshop)
434 * strings TODO(workshop)
440 static void *mdl_baseptr( mdl_header
*mdl
, u32 offset
)
442 return (void *)mdl
+ offset
;
445 static const char *mdl_pstr( mdl_header
*mdl
, u32 pstr
)
447 return (const char *)(mdl_baseptr( mdl
, mdl
->strings_offset
)) + pstr
;
450 static mdl_node
*mdl_node_from_id( mdl_header
*mdl
, u32 id
)
452 return ((mdl_node
*)mdl_baseptr( mdl
, mdl
->node_offset
)) + id
;
455 static mdl_node
*mdl_node_from_name( mdl_header
*mdl
, const char *name
)
457 for( int i
=0; i
<mdl
->node_count
; i
++ )
459 mdl_node
*pnode
= mdl_node_from_id( mdl
, i
);
461 if( !strcmp( name
, mdl_pstr( mdl
, pnode
->pstr_name
)) )
468 static mdl_submesh
*mdl_submesh_from_id( mdl_header
*mdl
, u32 id
)
470 if( id
>= mdl
->submesh_count
)
473 return ((mdl_submesh
*)mdl_baseptr( mdl
, mdl
->submesh_offset
)) + id
;
476 static mdl_submesh
*mdl_node_submesh( mdl_header
*mdl
, mdl_node
*node
, u32 i
)
478 if( i
>= node
->submesh_count
)
481 return mdl_submesh_from_id( mdl
, node
->submesh_start
+i
);
484 static u32
*mdl_submesh_indices( mdl_header
*mdl
, mdl_submesh
*sm
)
486 return ((u32
*)mdl_baseptr( mdl
, mdl
->indice_offset
)) + sm
->indice_start
;
489 static mdl_vert
*mdl_submesh_vertices( mdl_header
*mdl
, mdl_submesh
*sm
)
491 return ((mdl_vert
*)mdl_baseptr(mdl
,mdl
->vertex_offset
)) + sm
->vertex_start
;
494 static mdl_material
*mdl_material_from_id( mdl_header
*mdl
, u32 id
)
496 return ((mdl_material
*)mdl_baseptr(mdl
,mdl
->material_offset
)) + id
;
499 static mdl_animation
*mdl_animation_from_id( mdl_header
*mdl
, u32 id
)
501 return ((mdl_animation
*)mdl_baseptr(mdl
,mdl
->anim_offset
)) + id
;
504 static void mdl_node_transform( mdl_node
*pnode
, m4x3f transform
)
506 q_m3x3( pnode
->q
, transform
);
507 v3_muls( transform
[0], pnode
->s
[0], transform
[0] );
508 v3_muls( transform
[1], pnode
->s
[1], transform
[1] );
509 v3_muls( transform
[2], pnode
->s
[2], transform
[2] );
510 v3_copy( pnode
->co
, transform
[3] );
513 static void mdl_unpack_submesh( mdl_header
*mdl
, glmesh
*mesh
, mdl_submesh
*sm
)
515 mesh_upload( mesh
, mdl_submesh_vertices( mdl
, sm
), sm
->vertex_count
,
516 mdl_submesh_indices( mdl
, sm
), sm
->indice_count
);
519 static void mdl_unpack_glmesh( mdl_header
*mdl
, glmesh
*mesh
)
521 u32 offset
= mdl_submesh_from_id( mdl
, 0 )->vertex_count
;
523 for( int i
=1; i
< mdl
->submesh_count
; i
++ )
525 mdl_submesh
*sm
= mdl_submesh_from_id( mdl
, i
);
526 u32
*indices
= mdl_submesh_indices( mdl
, sm
);
528 for( u32 j
=0; j
<sm
->indice_count
; j
++ )
529 indices
[j
] += offset
;
531 offset
+= sm
->vertex_count
;
534 mdl_vert
*vertex_base
= mdl_baseptr( mdl
, mdl
->vertex_offset
);
535 u32
*indice_base
= mdl_baseptr( mdl
, mdl
->indice_offset
);
537 mesh_upload( mesh
, vertex_base
, mdl
->vertex_count
,
538 indice_base
, mdl
->indice_count
);
541 static void mdl_draw_submesh( mdl_submesh
*sm
)
543 mesh_drawn( sm
->indice_start
, sm
->indice_count
);
546 static void *mdl_get_entdata( mdl_header
*mdl
, mdl_node
*pnode
)
548 return mdl_baseptr( mdl
, mdl
->entdata_offset
) + pnode
->offset
;
551 static mdl_keyframe
*mdl_get_animdata( mdl_header
*mdl
, mdl_animation
*anim
)
553 return mdl_baseptr( mdl
, mdl
->animdata_offset
) + anim
->offset
;
556 static void mdl_link_materials( mdl_header
*root
, mdl_header
*child
)
558 u32 lookup
[MDL_MATERIAL_MAX
];
560 for( int i
=0; i
<child
->material_count
; i
++ )
562 mdl_material
*mi
= mdl_material_from_id( child
, i
);
563 const char *si
= mdl_pstr( child
, mi
->pstr_name
);
567 for( int j
=0; j
<root
->material_count
; j
++ )
569 mdl_material
*mj
= mdl_material_from_id( root
, j
);
570 const char *sj
= mdl_pstr( root
, mj
->pstr_name
);
572 if( !strcmp( si
, sj
) )
579 if( lookup
[i
] == 0 && i
!= 0 )
581 vg_warn( "Could not link material '%s' (not present in root model)\n",
586 for( int i
=0; i
<child
->submesh_count
; i
++ )
588 mdl_submesh
*sm
= mdl_submesh_from_id( child
, i
);
589 sm
->material_id
= lookup
[sm
->material_id
];