fov slider input maps menu stuff
[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 typedef struct glmesh glmesh;
11
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_file_header mdl_file_header;
17 typedef struct mdl_animation mdl_animation;
18 typedef struct mdl_keyframe mdl_keyframe;
19 typedef struct mdl_texture mdl_texture;
20 typedef struct mdl_context mdl_context;
21
22 #define MDL_SIZE_MAX 0x1000000
23 #define MDL_VERT_MAX 1000000
24 #define MDL_INDICE_MAX 1000000
25 #define MDL_MATERIAL_MAX 32
26 #define MDL_NODE_MAX 4000
27 #define MDL_SUBMESH_MAX 8000
28 #define MDL_STRING_LENGTH_MAX 64
29
30 enum classtype
31 {
32 k_classtype_none = 0,
33 k_classtype_gate = 1,
34 k_classtype_spawn = 3,
35 k_classtype_water = 4,
36 k_classtype_route_node = 8,
37 k_classtype_route = 9,
38 k_classtype_bone = 10,
39 k_classtype_skeleton = 11,
40 k_classtype_skin = 12,
41 k_classtype_audio = 14,
42 k_classtype_trigger = 100,
43 k_classtype_logic_achievement = 101,
44 k_classtype_logic_relay = 102
45 };
46
47 enum mdl_shader
48 {
49 k_shader_standard = 0,
50 k_shader_standard_cutout = 1,
51 k_shader_terrain_blend = 2,
52 k_shader_standard_vertex_blend = 3,
53 k_shader_water = 4
54 };
55
56 enum mdl_surface_prop
57 {
58 k_surface_prop_concrete = 0,
59 k_surface_prop_wood = 1,
60 k_surface_prop_grass = 2
61 };
62
63 enum material_flag
64 {
65 k_material_flag_skate_surface = 0x1,
66 k_material_flag_collision = 0x2,
67 k_material_flag_grow_grass = 0x4
68 };
69
70 #pragma pack(push,1)
71
72 struct mdl_vert
73 {
74 v3f co,
75 norm;
76 v2f uv;
77 u8 colour[4];
78 u16 weights[4];
79 u8 groups[4];
80 };
81
82 struct mdl_submesh
83 {
84 u32 indice_start,
85 indice_count,
86 vertex_start,
87 vertex_count;
88
89 boxf bbx;
90 u32 material_id;
91 };
92
93 struct mdl_texture
94 {
95 u32 pstr_name,
96 pack_offset,
97 pack_length;
98 };
99
100 struct mdl_material
101 {
102 u32 pstr_name,
103 shader,
104 flags,
105 surface_prop;
106
107 v4f colour,
108 colour1;
109
110 u32 tex_diffuse,
111 tex_decal,
112 tex_normal;
113 };
114
115 struct mdl_node
116 {
117 v3f co;
118 v4f q;
119 v3f s;
120
121 u32 sub_uid, /* allocated in-file... too bad. */
122 submesh_start,
123 submesh_count,
124 classtype,
125 offset,
126 parent,
127 pstr_name;
128 };
129
130 struct mdl_keyframe
131 {
132 v3f co;
133 v4f q;
134 v3f s;
135 };
136
137 struct mdl_animation
138 {
139 u32 pstr_name,
140 length;
141
142 float rate;
143
144 u32 offset;
145 };
146
147 struct mdl_file_header
148 {
149 u32 identifier, version, file_length, pad0;
150
151 u32
152 node_count, node_offset,
153 submesh_count, submesh_offset,
154 material_count, material_offset,
155 texture_count, texture_offset,
156 anim_count, anim_offset,
157 entdata_size, entdata_offset,
158 strings_size, strings_offset,
159
160 keyframe_count, keyframe_offset,
161
162 vertex_count, vertex_offset,
163 indice_count, indice_offset,
164
165 pack_size, pack_offset;
166 };
167
168 /*
169 * Entity data structures
170 */
171
172 struct classtype_gate
173 {
174 u32 target;
175 v3f dims;
176 };
177
178 struct classtype_spawn
179 {
180 u32 pstr_alias;
181 };
182
183 struct classtype_water
184 {
185 u32 temp;
186 };
187
188 struct classtype_route_node
189 {
190 u32 target, target1;
191 };
192
193 struct classtype_route
194 {
195 u32 id_start;
196 u32 pstr_name;
197 v3f colour;
198 };
199
200 struct classtype_bone
201 {
202 u32 deform,
203 ik_target,
204 ik_pole,
205 collider,
206 use_limits;
207
208 v3f angle_limits[2];
209 boxf hitbox;
210 };
211
212 struct classtype_skeleton
213 {
214 u32 channels,
215 ik_count,
216 collider_count,
217 anim_start,
218 anim_count;
219 };
220
221 struct classtype_skin
222 {
223 u32 skeleton;
224 };
225
226 struct classtype_trigger
227 {
228 u32 target;
229 };
230
231 struct classtype_logic_relay
232 {
233 u32 targets[4];
234 };
235
236 struct classtype_logic_achievement
237 {
238 u32 pstr_name;
239 };
240
241 struct classtype_audio
242 {
243 u32 pstr_file,
244 flags;
245
246 float volume;
247 };
248
249 #pragma pack(pop)
250
251
252 struct mdl_context
253 {
254 FILE *file;
255 mdl_file_header info;
256
257 /* each buffer becomes availible after each _load function is called */
258 mdl_node *node_buffer; /* mdl_load_metadata() */
259 mdl_submesh *submesh_buffer;
260 mdl_material *material_buffer;
261 mdl_texture *texture_buffer;
262 mdl_animation *anim_buffer;
263 void *entdata_buffer;
264 const char *string_buffer;
265
266 mdl_keyframe *keyframe_buffer; /* mdl_load_anim_data() */
267
268 mdl_vert *vertex_buffer; /* mdl_load_mesh_data() */
269 u32 *index_buffer;
270
271 void *pack; /* mdl_load_pack_data() */
272 };
273
274 /*
275 * Simple mesh interface for OpenGL
276 */
277
278 struct glmesh
279 {
280 GLuint vao, vbo, ebo;
281 u32 indice_count;
282 u32 loaded;
283 };
284
285 VG_STATIC void mesh_upload( glmesh *mesh,
286 mdl_vert *verts, u32 vert_count,
287 u32 *indices, u32 indice_count )
288 {
289 //assert( mesh->loaded == 0 );
290
291 glGenVertexArrays( 1, &mesh->vao );
292 glGenBuffers( 1, &mesh->vbo );
293 glGenBuffers( 1, &mesh->ebo );
294 glBindVertexArray( mesh->vao );
295
296 size_t stride = sizeof(mdl_vert);
297
298 glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo );
299 glBufferData( GL_ARRAY_BUFFER, vert_count*stride, verts, GL_STATIC_DRAW );
300
301 glBindVertexArray( mesh->vao );
302 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo );
303 glBufferData( GL_ELEMENT_ARRAY_BUFFER, indice_count*sizeof(u32),
304 indices, GL_STATIC_DRAW );
305
306 /* 0: coordinates */
307 glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 );
308 glEnableVertexAttribArray( 0 );
309
310 /* 1: normal */
311 glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE,
312 stride, (void *)offsetof(mdl_vert, norm) );
313 glEnableVertexAttribArray( 1 );
314
315 /* 2: uv */
316 glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE,
317 stride, (void *)offsetof(mdl_vert, uv) );
318 glEnableVertexAttribArray( 2 );
319
320 /* 3: colour */
321 glVertexAttribPointer( 3, 4, GL_UNSIGNED_BYTE, GL_TRUE,
322 stride, (void *)offsetof(mdl_vert, colour) );
323 glEnableVertexAttribArray( 3 );
324
325 /* 4: weights */
326 glVertexAttribPointer( 4, 4, GL_UNSIGNED_SHORT, GL_TRUE,
327 stride, (void *)offsetof(mdl_vert, weights) );
328 glEnableVertexAttribArray( 4 );
329
330 /* 5: groups */
331 glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE,
332 stride, (void *)offsetof(mdl_vert, groups) );
333 glEnableVertexAttribArray( 5 );
334
335 VG_CHECK_GL_ERR();
336
337 mesh->indice_count = indice_count;
338 mesh->loaded = 1;
339 }
340
341 VG_STATIC void mesh_bind( glmesh *mesh )
342 {
343 glBindVertexArray( mesh->vao );
344 }
345
346 VG_STATIC void mesh_drawn( u32 start, u32 count )
347 {
348 glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT,
349 (void *)(start*sizeof(u32)) );
350 }
351
352 VG_STATIC void mesh_draw( glmesh *mesh )
353 {
354 mesh_drawn( 0, mesh->indice_count );
355 }
356
357 VG_STATIC void mesh_free( glmesh *mesh )
358 {
359 if( mesh->loaded )
360 {
361 glDeleteVertexArrays( 1, &mesh->vao );
362 glDeleteBuffers( 1, &mesh->ebo );
363 glDeleteBuffers( 1, &mesh->vbo );
364 mesh->loaded = 0;
365 }
366 }
367
368 VG_STATIC void mdl_load_fatal_corrupt( mdl_context *mdl )
369 {
370 fclose( mdl->file );
371 vg_file_print_invalid( mdl->file );
372 vg_fatal_exit_loop( "Corrupt model" );
373 }
374
375 /*
376 * Model implementation
377 *
378 * TODO.
379 *
380 * you have two api options for loading a model, first, the easy way:
381 * mdl_load ...
382 * will put the entire model straight into the linear_alloc
383 *
384 * or, to target different allocators:
385 *
386 * mdl_open
387 * mdl_load_metadata
388 * mdl_load_vertex_data
389 * mdl_load_indice_data
390 * mdl_close
391 *
392 * these should ideally be called in quick succession to limit stalls.
393 */
394
395 /*
396 * if calling mdl_open, and the file does not exist, the game will fatal quit
397 */
398 VG_STATIC void mdl_open( mdl_context *mdl, const char *path )
399 {
400 memset( mdl, 0, sizeof( mdl_context ) );
401 mdl->file = fopen( path, "rb" );
402
403 if( !mdl->file )
404 {
405 vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) );
406 vg_fatal_exit_loop( "see above for details" );
407 }
408
409 u64 l = fread( &mdl->info, sizeof(mdl_file_header), 1, mdl->file );
410 if( l != 1 )
411 mdl_load_fatal_corrupt( mdl );
412 }
413
414 /*
415 * Load all metadata (everything up until the large buffers). Probs at most 50k
416 */
417 VG_STATIC void mdl_load_metadata( mdl_context *mdl, void *lin_alloc )
418 {
419 assert( mdl->file );
420
421 u64 lheader = sizeof(mdl_file_header),
422 ldata = mdl->info.keyframe_offset - lheader;
423
424 void *all_data = vg_linear_alloc( lin_alloc, ldata );
425
426 fseek( mdl->file, lheader, SEEK_SET );
427 u64 l = fread( all_data, ldata, 1, mdl->file );
428
429 if( l != 1 )
430 {
431 vg_file_print_invalid( mdl->file );
432 vg_fatal_exit_loop( "Corrupt model" );
433 }
434
435 mdl->node_buffer = all_data + (mdl->info.node_offset - lheader);
436 mdl->submesh_buffer = all_data + (mdl->info.submesh_offset - lheader);
437 mdl->material_buffer = all_data + (mdl->info.material_offset - lheader);
438 mdl->texture_buffer = all_data + (mdl->info.texture_offset - lheader);
439 mdl->anim_buffer = all_data + (mdl->info.anim_offset - lheader);
440 mdl->entdata_buffer = all_data + (mdl->info.entdata_offset - lheader);
441 mdl->string_buffer = all_data + (mdl->info.strings_offset - lheader);
442 }
443
444 /*
445 * Load just the mesh data
446 */
447 VG_STATIC void mdl_load_mesh_data( mdl_context *mdl, void *lin_alloc )
448 {
449 assert( mdl->file );
450
451 u64 size_verts = mdl->info.vertex_count * sizeof(mdl_vert),
452 size_index = mdl->info.indice_count * sizeof(u32);
453
454 mdl->vertex_buffer = vg_linear_alloc( lin_alloc, size_verts );
455 mdl->index_buffer = vg_linear_alloc( lin_alloc, size_index );
456
457 {
458 fseek( mdl->file, mdl->info.vertex_offset, SEEK_SET );
459 u64 l = fread( mdl->vertex_buffer, size_verts, 1, mdl->file );
460 if( l != 1 )
461 mdl_load_fatal_corrupt( mdl );
462 }
463 {
464 fseek( mdl->file, mdl->info.indice_offset, SEEK_SET );
465 u64 l = fread( mdl->index_buffer, size_index, 1, mdl->file );
466 if( l != 1 )
467 mdl_load_fatal_corrupt( mdl );
468 }
469 }
470
471 /*
472 * Load animation data
473 */
474 VG_STATIC void mdl_load_anim_data( mdl_context *mdl, void *lin_alloc )
475 {
476 assert( mdl->file );
477
478 if( mdl->info.keyframe_count == 0 )
479 return;
480
481 u64 size_kf = mdl->info.keyframe_count * sizeof(mdl_keyframe);
482 mdl->keyframe_buffer = vg_linear_alloc( lin_alloc, size_kf );
483
484 fseek( mdl->file, mdl->info.keyframe_offset, SEEK_SET );
485 u64 l = fread( mdl->keyframe_buffer, size_kf, 1, mdl->file );
486 if( l != 1 )
487 mdl_load_fatal_corrupt( mdl );
488 }
489
490 /*
491 * Load pack contents
492 *
493 * TODO request specific files (low)
494 */
495 VG_STATIC void mdl_load_pack_data( mdl_context *mdl, void *lin_alloc )
496 {
497 assert( mdl->file );
498
499 if( mdl->info.pack_size == 0 )
500 return;
501
502 mdl->pack = vg_linear_alloc( lin_alloc, mdl->info.pack_size );
503 fseek( mdl->file, mdl->info.pack_offset, SEEK_SET );
504
505 u64 l = fread( mdl->pack, mdl->info.pack_size, 1, mdl->file );
506 if( l != 1 )
507 mdl_load_fatal_corrupt( mdl );
508 }
509
510 /*
511 * close file handle
512 */
513 VG_STATIC void mdl_close( mdl_context *mdl )
514 {
515 fclose( mdl->file );
516 mdl->file = NULL;
517 }
518
519 /* open a model. TODO: make this flags ( ANIM_DATA|MESH_DATA ... ) */
520 VG_STATIC mdl_context *mdl_load_full( void *lin_alloc, const char *path )
521 {
522 /* Inspect the header by opening it, give us the size needed */
523 mdl_context temp_ctx;
524 mdl_open( &temp_ctx, path );
525
526 /* create allocator */
527 u32 tot_size = temp_ctx.info.file_length + sizeof( mdl_context );
528 void *data = vg_create_linear_allocator( lin_alloc, tot_size,
529 VG_MEMORY_SYSTEM );
530
531 /* copy context and load all other data */
532 mdl_context *ctx = vg_linear_alloc( data, sizeof(mdl_context) );
533 memcpy( ctx, &temp_ctx, sizeof(mdl_context) );
534
535 mdl_load_metadata( ctx, data );
536 mdl_load_anim_data( ctx, data );
537 mdl_load_mesh_data( ctx, data );
538 mdl_load_pack_data( ctx, data );
539 mdl_close( ctx );
540
541 return ctx;
542 }
543
544 /*
545 * Item getters
546 * ----------------------------------------------------------------------------
547 * TODO: Clamp access and oob errors
548 */
549 VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr )
550 {
551 return mdl->string_buffer + pstr;
552 }
553
554 VG_STATIC mdl_node *mdl_node_from_id( mdl_context *mdl, u32 id )
555 {
556 return &mdl->node_buffer[id];
557 }
558
559 VG_STATIC mdl_node *mdl_node_from_name( mdl_context *mdl, const char *name )
560 {
561 for( int i=0; i < mdl->info.node_count; i++ )
562 {
563 mdl_node *pnode = mdl_node_from_id( mdl, i );
564
565 if( !strcmp( name, mdl_pstr( mdl, pnode->pstr_name )) )
566 return pnode;
567 }
568
569 return NULL;
570 }
571
572 VG_STATIC mdl_submesh *mdl_node_submesh( mdl_context *mdl,
573 mdl_node *node, u32 i )
574 {
575 return &mdl->submesh_buffer[ node->submesh_start+i ];
576 }
577
578 VG_STATIC u32 *mdl_submesh_indices( mdl_context *mdl, mdl_submesh *sm )
579 {
580 return &mdl->index_buffer[ sm->indice_start ];
581 }
582
583 VG_STATIC mdl_vert *mdl_submesh_vertices( mdl_context *mdl, mdl_submesh *sm )
584 {
585 return &mdl->vertex_buffer[ sm->vertex_start ];
586 }
587
588 VG_STATIC void mdl_node_transform( mdl_node *pnode, m4x3f transform )
589 {
590 q_m3x3( pnode->q, transform );
591 v3_muls( transform[0], pnode->s[0], transform[0] );
592 v3_muls( transform[1], pnode->s[1], transform[1] );
593 v3_muls( transform[2], pnode->s[2], transform[2] );
594 v3_copy( pnode->co, transform[3] );
595 }
596
597 /* upload a mesh based on file submesh */
598 VG_STATIC void mdl_unpack_submesh( mdl_context *mdl, glmesh *mesh,
599 mdl_submesh *sm )
600 {
601 mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count,
602 mdl_submesh_indices( mdl, sm ), sm->indice_count );
603 }
604
605 /* upload entire mesh from model */
606 VG_STATIC void mdl_unpack_glmesh( mdl_context *mdl, glmesh *mesh )
607 {
608 u32 offset = mdl->submesh_buffer[0].vertex_count;
609
610 for( int i=1; i< mdl->info.submesh_count; i++ )
611 {
612 mdl_submesh *sm = &mdl->submesh_buffer[i];
613 u32 *indices = mdl_submesh_indices( mdl, sm );
614
615 for( u32 j=0; j<sm->indice_count; j++ )
616 indices[j] += offset;
617
618 offset += sm->vertex_count;
619 }
620
621 mesh_upload( mesh, mdl->vertex_buffer, mdl->info.vertex_count,
622 mdl->index_buffer, mdl->info.indice_count );
623 }
624
625 VG_STATIC void mdl_draw_submesh( mdl_submesh *sm )
626 {
627 mesh_drawn( sm->indice_start, sm->indice_count );
628 }
629
630 VG_STATIC void *mdl_get_entdata( mdl_context *mdl, mdl_node *pnode )
631 {
632 return mdl->entdata_buffer + pnode->offset;
633 }
634
635 VG_STATIC mdl_keyframe *mdl_get_animdata( mdl_context *mdl, mdl_animation *anim )
636 {
637 return mdl->keyframe_buffer + anim->offset;
638 }
639
640 VG_STATIC void mdl_link_materials( mdl_context *root, mdl_context *child )
641 {
642 u32 lookup[MDL_MATERIAL_MAX];
643
644 for( int i=0; i<child->info.material_count; i++ )
645 {
646 mdl_material *mi = &child->material_buffer[i];
647 const char *si = mdl_pstr( child, mi->pstr_name );
648
649 lookup[i] = 0;
650
651 for( int j=0; j<root->info.material_count; j++ )
652 {
653 mdl_material *mj = &root->material_buffer[j];
654 const char *sj = mdl_pstr( root, mj->pstr_name );
655
656 if( !strcmp( si, sj ) )
657 {
658 lookup[i] = j;
659 break;
660 }
661 }
662
663 if( lookup[i] == 0 && i != 0 )
664 {
665 vg_warn( "Could not link material '%s' (not present in root model)\n",
666 si );
667 }
668 }
669
670 for( int i=0; i<child->info.submesh_count; i++ )
671 {
672 mdl_submesh *sm = &child->submesh_buffer[i];
673 sm->material_id = lookup[sm->material_id];
674 }
675 }
676
677 VG_STATIC void mdl_invert_uv_coordinates( mdl_context *mdl )
678 {
679 for( int i=0; i<mdl->info.vertex_count; i++ )
680 {
681 mdl_vert *vert = &mdl->vertex_buffer[i];
682 vert->uv[1] = 1.0f-vert->uv[1];
683 }
684 }
685
686 #endif