fffd26d111228c8661989f7291208afec53d5b48
[carveJwlIkooP6JGAAIwe30JlM.git] / model.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #ifndef MODEL_H
6 #define MODEL_H
7
8 #include "common.h"
9
10 enum mdl_shader
11 {
12 k_shader_standard = 0,
13 k_shader_standard_cutout = 1,
14 k_shader_terrain_blend = 2,
15 k_shader_standard_vertex_blend = 3,
16 k_shader_water = 4,
17 k_shader_invisible = 5,
18 k_shader_boundary = 6
19 };
20
21 enum mdl_surface_prop
22 {
23 k_surface_prop_concrete = 0,
24 k_surface_prop_wood = 1,
25 k_surface_prop_grass = 2,
26 k_surface_prop_tiles = 3,
27 k_surface_prop_metal = 4
28 };
29
30 enum material_flag
31 {
32 k_material_flag_skate_target = 0x1,
33 k_material_flag_collision = 0x2,
34 k_material_flag_grow_grass = 0x4,
35 k_material_flag_grindable = 0x8,
36 k_material_flag_invisible = 0x10,
37 k_material_flag_boundary = 0x20
38 };
39
40 #pragma pack(push,1)
41
42 /* 48 byte */
43 struct mdl_vert
44 {
45 v3f co, /* 3*32 */
46 norm; /* 3*32 */
47 v2f uv; /* 2*32 */
48
49 u8 colour[4]; /* 4*8 */
50 u16 weights[4];/* 4*16 */
51 u8 groups[4]; /* 4*8 */
52 };
53
54 #pragma pack(pop)
55
56 typedef struct mdl_context mdl_context;
57 typedef struct mdl_array_ptr mdl_array_ptr;
58 typedef struct mdl_vert mdl_vert;
59 typedef struct mdl_transform mdl_transform;
60 typedef struct mdl_submesh mdl_submesh;
61 typedef struct mdl_material mdl_material;
62 typedef struct mdl_bone mdl_bone;
63 typedef struct mdl_armature mdl_armature;
64 typedef struct mdl_animation mdl_animation;
65 typedef struct mdl_transform mdl_keyframe;
66 typedef struct mdl_mesh mdl_mesh;
67 typedef struct mdl_file mdl_file;
68 typedef struct mdl_texture mdl_texture;
69 typedef struct mdl_array mdl_array;
70 typedef struct mdl_header mdl_header;
71
72 struct mdl_transform
73 {
74 v3f co, s;
75 v4f q;
76 };
77
78 struct mdl_submesh
79 {
80 u32 indice_start,
81 indice_count,
82 vertex_start,
83 vertex_count;
84
85 boxf bbx;
86 u32 material_id;
87 };
88
89 struct mdl_material
90 {
91 u32 pstr_name,
92 shader,
93 flags,
94 surface_prop;
95
96 v4f colour,
97 colour1;
98
99 u32 tex_diffuse,
100 tex_none0,
101 tex_none1;
102 };
103
104 struct mdl_bone
105 {
106 v3f co, end;
107 u32 parent,
108 collider,
109 ik_target,
110 ik_pole,
111 flags,
112 pstr_name;
113
114 boxf hitbox;
115 v3f conevx, conevy, coneva;
116 float conet;
117 };
118
119 enum bone_flag
120 {
121 k_bone_flag_deform = 0x1,
122 k_bone_flag_ik = 0x2,
123 k_bone_flag_cone_constraint = 0x4
124 };
125
126 enum bone_collider
127 {
128 k_bone_collider_none = 0,
129 k_bone_collider_box = 1,
130 k_bone_collider_capsule = 2
131 };
132
133 struct mdl_armature
134 {
135 mdl_transform transform;
136 u32 bone_start,
137 bone_count,
138 anim_start,
139 anim_count;
140 };
141
142 struct mdl_animation
143 {
144 u32 pstr_name,
145 length;
146 float rate;
147 u32 offset;
148 };
149
150 struct mdl_mesh
151 {
152 mdl_transform transform;
153 u32 submesh_start,
154 submesh_count,
155 pstr_name,
156 entity_id, /* upper 16 bits: type, lower 16 bits: index */
157 armature_id;
158 };
159
160 struct mdl_file
161 {
162 u32 pstr_path,
163 pack_offset,
164 pack_size;
165 };
166
167 struct mdl_texture
168 {
169 mdl_file file;
170 u32 glname;
171 };
172
173 struct mdl_array
174 {
175 u32 file_offset,
176 item_count,
177 item_size;
178
179 char name[16];
180 };
181
182 struct mdl_header
183 {
184 u32 version;
185 mdl_array index;
186 };
187
188 struct mdl_context
189 {
190 FILE *file;
191 mdl_header info;
192
193 struct mdl_array_ptr
194 {
195 void *data;
196 u32 count, stride;
197 }
198 index,
199
200 /* metadata */
201 strings,
202 meshs,
203 submeshs,
204 materials,
205 textures,
206 armatures,
207 bones,
208 animations,
209
210 /* animation buffers */
211 keyframes,
212
213 /* mesh buffers */
214 verts,
215 indices;
216
217 u32 pack_base_offset;
218
219 /* pack data */
220 //pack;
221 };
222
223
224 VG_STATIC void mdl_load_fatal_corrupt( mdl_context *mdl )
225 {
226 fclose( mdl->file );
227 vg_file_print_invalid( mdl->file );
228 vg_fatal_exit_loop( "Corrupt model" );
229 }
230
231 /*
232 * Model implementation
233 */
234
235 VG_STATIC u32 mdl_query_array_size( mdl_array *arr )
236 {
237 if( arr->item_count ){
238 u32 size = arr->item_size*arr->item_count;
239 return vg_align8(size);
240 }
241 else
242 return 0;
243 }
244
245 VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr );
246 VG_STATIC
247 void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst )
248 {
249 if( !info->pack_size ){
250 vg_warn( "path: %s\n", mdl_pstr( mdl, info->pstr_path ) );
251 vg_fatal_exit_loop( "Packed file is only a header; it is not packed" );
252 }
253
254 fseek( mdl->file, mdl->pack_base_offset+info->pack_offset, SEEK_SET );
255 u64 l = fread( dst, info->pack_size, 1, mdl->file );
256
257 if( l != 1 )
258 mdl_load_fatal_corrupt( mdl );
259 }
260
261 VG_STATIC void mdl_load_array_file( mdl_context *mdl, mdl_array_ptr *ptr,
262 mdl_array *arr, void *lin_alloc )
263 {
264 if( arr->item_count ){
265 u32 size = arr->item_size*arr->item_count;
266 ptr->data = vg_linear_alloc( lin_alloc, vg_align8(size) );
267
268 fseek( mdl->file, arr->file_offset, SEEK_SET );
269 u64 l = fread( ptr->data, arr->item_size*arr->item_count, 1, mdl->file );
270
271 if( l != 1 )
272 mdl_load_fatal_corrupt( mdl );
273 }
274 else
275 ptr->data = NULL;
276
277 ptr->count = arr->item_count;
278 ptr->stride = arr->item_size;
279 }
280
281 VG_STATIC void *mdl_arritm( mdl_array_ptr *arr, u32 index )
282 {
283 return ((u8 *)arr->data) + index*arr->stride;
284 }
285
286 VG_STATIC u32 mdl_arrcount( mdl_array_ptr *arr )
287 {
288 return arr->count;
289 }
290
291 VG_STATIC mdl_array *mdl_find_array( mdl_context *mdl, const char *name )
292 {
293 for( u32 i=0; i<mdl_arrcount(&mdl->index); i++ ){
294 mdl_array *arr = mdl_arritm( &mdl->index, i );
295
296 if( !strncmp(arr->name,name,16) ){
297 return arr;
298 }
299 }
300
301 return NULL;
302 }
303
304 VG_STATIC int mdl_load_array( mdl_context *mdl, mdl_array_ptr *ptr,
305 const char *name, void *lin_alloc )
306 {
307 mdl_array *arr = mdl_find_array( mdl, name );
308
309 if( arr ){
310 mdl_load_array_file( mdl, ptr, arr, lin_alloc );
311 return 1;
312 }
313 else{
314 ptr->data = NULL;
315 ptr->count = 0;
316 ptr->stride = 0;
317 return 0;
318 }
319 }
320
321 VG_STATIC int mdl_load_mesh_block( mdl_context *mdl, void *lin_alloc )
322 {
323 int success = 1;
324
325 success &= mdl_load_array( mdl, &mdl->verts, "mdl_vert", lin_alloc );
326 success &= mdl_load_array( mdl, &mdl->indices, "mdl_indice", lin_alloc );
327
328 return success;
329 }
330
331 VG_STATIC int mdl_load_metadata_block( mdl_context *mdl, void *lin_alloc )
332 {
333 int success = 1;
334
335 success &= mdl_load_array( mdl, &mdl->strings, "strings", lin_alloc );
336 success &= mdl_load_array( mdl, &mdl->meshs, "mdl_mesh", lin_alloc );
337 success &= mdl_load_array( mdl, &mdl->submeshs, "mdl_submesh", lin_alloc );
338 success &= mdl_load_array( mdl, &mdl->materials, "mdl_material", lin_alloc );
339 success &= mdl_load_array( mdl, &mdl->textures, "mdl_texture", lin_alloc );
340 success &= mdl_load_array( mdl, &mdl->armatures, "mdl_armature", lin_alloc );
341 success &= mdl_load_array( mdl, &mdl->bones, "mdl_bone", lin_alloc );
342 success &= mdl_load_array( mdl, &mdl->animations,"mdl_animation",lin_alloc );
343
344 return success;
345 }
346
347 VG_STATIC int mdl_load_animation_block( mdl_context *mdl, void *lin_alloc )
348 {
349 return mdl_load_array( mdl, &mdl->keyframes, "mdl_keyframe", lin_alloc );
350 }
351
352 /*
353 * if calling mdl_open, and the file does not exist, the game will fatal quit
354 */
355 VG_STATIC void mdl_open( mdl_context *mdl, const char *path, void *lin_alloc )
356 {
357 memset( mdl, 0, sizeof( mdl_context ) );
358 mdl->file = fopen( path, "rb" );
359
360 if( !mdl->file ){
361 vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) );
362 vg_fatal_exit_loop( "see above for details" );
363 }
364
365 u64 l = fread( &mdl->info, sizeof(mdl_header), 1, mdl->file );
366 if( l != 1 )
367 mdl_load_fatal_corrupt( mdl );
368
369 mdl_load_array_file( mdl, &mdl->index, &mdl->info.index, lin_alloc );
370
371 mdl_array *pack = mdl_find_array( mdl, "pack" );
372 if( pack ) mdl->pack_base_offset = pack->file_offset;
373 else mdl->pack_base_offset = 0;
374 }
375
376 /*
377 * close file handle
378 */
379 VG_STATIC void mdl_close( mdl_context *mdl )
380 {
381 fclose( mdl->file );
382 mdl->file = NULL;
383 }
384
385 /* useful things you can do with the model */
386
387 VG_STATIC void mdl_transform_m4x3( mdl_transform *transform, m4x3f mtx )
388 {
389 q_m3x3( transform->q, mtx );
390 v3_muls( mtx[0], transform->s[0], mtx[0] );
391 v3_muls( mtx[1], transform->s[1], mtx[1] );
392 v3_muls( mtx[2], transform->s[2], mtx[2] );
393 v3_copy( transform->co, mtx[3] );
394 }
395
396 VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr )
397 {
398 return mdl_arritm( &mdl->strings, pstr );
399 }
400
401 /*
402 * Simple mesh interface for OpenGL
403 * ----------------------------------------------------------------------------
404 */
405
406 typedef struct glmesh glmesh;
407 struct glmesh
408 {
409 GLuint vao, vbo, ebo;
410 u32 indice_count;
411 u32 loaded;
412 };
413
414 VG_STATIC void mesh_upload( glmesh *mesh,
415 mdl_vert *verts, u32 vert_count,
416 u32 *indices, u32 indice_count )
417 {
418 //assert( mesh->loaded == 0 );
419
420 glGenVertexArrays( 1, &mesh->vao );
421 glGenBuffers( 1, &mesh->vbo );
422 glGenBuffers( 1, &mesh->ebo );
423 glBindVertexArray( mesh->vao );
424
425 size_t stride = sizeof(mdl_vert);
426
427 glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo );
428 glBufferData( GL_ARRAY_BUFFER, vert_count*stride, verts, GL_STATIC_DRAW );
429
430 glBindVertexArray( mesh->vao );
431 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo );
432 glBufferData( GL_ELEMENT_ARRAY_BUFFER, indice_count*sizeof(u32),
433 indices, GL_STATIC_DRAW );
434
435 /* 0: coordinates */
436 glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 );
437 glEnableVertexAttribArray( 0 );
438
439 /* 1: normal */
440 glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE,
441 stride, (void *)offsetof(mdl_vert, norm) );
442 glEnableVertexAttribArray( 1 );
443
444 /* 2: uv */
445 glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE,
446 stride, (void *)offsetof(mdl_vert, uv) );
447 glEnableVertexAttribArray( 2 );
448
449 /* 3: colour */
450 glVertexAttribPointer( 3, 4, GL_UNSIGNED_BYTE, GL_TRUE,
451 stride, (void *)offsetof(mdl_vert, colour) );
452 glEnableVertexAttribArray( 3 );
453
454 /* 4: weights */
455 glVertexAttribPointer( 4, 4, GL_UNSIGNED_SHORT, GL_TRUE,
456 stride, (void *)offsetof(mdl_vert, weights) );
457 glEnableVertexAttribArray( 4 );
458
459 /* 5: groups */
460 glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE,
461 stride, (void *)offsetof(mdl_vert, groups) );
462 glEnableVertexAttribArray( 5 );
463
464 VG_CHECK_GL_ERR();
465
466 mesh->indice_count = indice_count;
467 mesh->loaded = 1;
468 }
469
470 VG_STATIC void mesh_bind( glmesh *mesh )
471 {
472 glBindVertexArray( mesh->vao );
473 }
474
475 VG_STATIC void mesh_drawn( u32 start, u32 count )
476 {
477 glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT,
478 (void *)(start*sizeof(u32)) );
479 }
480
481 VG_STATIC void mesh_draw( glmesh *mesh )
482 {
483 mesh_drawn( 0, mesh->indice_count );
484 }
485
486 VG_STATIC void mesh_free( glmesh *mesh )
487 {
488 if( mesh->loaded ){
489 glDeleteVertexArrays( 1, &mesh->vao );
490 glDeleteBuffers( 1, &mesh->ebo );
491 glDeleteBuffers( 1, &mesh->vbo );
492 mesh->loaded = 0;
493 }
494 }
495
496 VG_STATIC void mdl_draw_submesh( mdl_submesh *sm )
497 {
498 mesh_drawn( sm->indice_start, sm->indice_count );
499 }
500
501 /* WARNING: Destructive! Only use this once and then discard the context. */
502 VG_STATIC void mdl_unpack_glmesh( mdl_context *mdl, glmesh *mesh )
503 {
504 if( !mdl->submeshs.count )
505 vg_fatal_exit_loop( "Tried to unpack empty model file" );
506
507 mdl_submesh *sm = mdl_arritm( &mdl->submeshs, 0 );
508 u32 offset = sm->vertex_count;
509
510 for( u32 i=1; i<mdl_arrcount( &mdl->submeshs ); i++ ){
511 mdl_submesh *sm = mdl_arritm( &mdl->submeshs, i );
512 u32 *indices = mdl_arritm( &mdl->indices, sm->indice_start );
513
514 for( u32 j=0; j<sm->indice_count; j++ )
515 indices[j] += offset;
516
517 offset += sm->vertex_count;
518 }
519
520 mesh_upload( mesh, mdl->verts.data, mdl->verts.count,
521 mdl->indices.data, mdl->indices.count );
522 }
523
524 VG_STATIC mdl_mesh *mdl_find_mesh( mdl_context *mdl, const char *name )
525 {
526 for( u32 i=0; i<mdl_arrcount( &mdl->meshs ); i++ ){
527 mdl_mesh *mesh = mdl_arritm( &mdl->meshs, i );
528 if( !strcmp( name, mdl_pstr( mdl, mesh->pstr_name ))){
529 return mesh;
530 }
531 }
532 return NULL;
533 }
534
535 #endif