dont remember
[carveJwlIkooP6JGAAIwe30JlM.git] / model.h
1 #ifndef MODEL_H
2 #define MODEL_H
3
4 #include "common.h"
5
6 typedef struct glmesh glmesh;
7
8 typedef struct mdl_vert mdl_vert;
9 typedef struct mdl_submesh mdl_submesh;
10 typedef struct mdl_material mdl_material;
11 typedef struct mdl_node mdl_node;
12 typedef struct mdl_header mdl_header;
13 typedef struct mdl_animation mdl_animation;
14 typedef struct mdl_keyframe mdl_keyframe;
15
16 #define MDL_SIZE_MAX 0x1000000
17 #define MDL_VERT_MAX 1000000
18 #define MDL_INDICE_MAX 1000000
19 #define MDL_MATERIAL_MAX 32
20 #define MDL_NODE_MAX 4000
21 #define MDL_SUBMESH_MAX 8000
22 #define MDL_STRING_LENGTH_MAX 64
23
24 enum classtype
25 {
26 k_classtype_none = 0,
27 k_classtype_gate = 1,
28 k_classtype_block = 2,
29 k_classtype_spawn = 3,
30 k_classtype_water = 4,
31 k_classtype_car_path = 5,
32 k_classtype_instance = 6,
33 k_classtype_capsule = 7,
34 k_classtype_route_node = 8,
35 k_classtype_route = 9,
36 k_classtype_bone = 10,
37 k_classtype_skeleton = 11,
38 k_classtype_skin = 12
39 };
40
41
42 #pragma pack(push,1)
43
44 struct mdl_vert
45 {
46 v3f co,
47 norm;
48 v2f uv;
49 u8 colour[4];
50 u16 weights[4];
51 u8 groups[4];
52 };
53
54 struct mdl_submesh
55 {
56 u32 indice_start,
57 indice_count,
58 vertex_start,
59 vertex_count;
60
61 boxf bbx;
62 u32 material_id;
63 };
64
65 struct mdl_material
66 {
67 u32 pstr_name;
68 };
69
70 struct mdl_node
71 {
72 v3f co;
73 v4f q;
74 v3f s;
75
76 union{ u32 submesh_start, sub_uid; };
77
78 u32
79 submesh_count,
80 classtype,
81 offset,
82 parent,
83 pstr_name;
84 };
85
86 struct mdl_keyframe
87 {
88 v3f co;
89 v4f q;
90 v3f s;
91 };
92
93 struct mdl_animation
94 {
95 u32 pstr_name,
96 length;
97
98 float rate;
99
100 u32 offset;
101 };
102
103 struct mdl_header
104 {
105 u32 identifier, version, file_length;
106
107 u32 vertex_count, vertex_offset,
108 indice_count, indice_offset,
109 submesh_count, submesh_offset,
110 material_count, material_offset,
111 node_count, node_offset,
112 anim_count, anim_offset,
113 strings_offset, entdata_offset, animdata_offset;
114 };
115
116 /*
117 * Entity data structures
118 */
119
120 struct classtype_block
121 {
122 boxf bbx;
123 };
124
125 struct classtype_gate
126 {
127 u32 target;
128 v3f dims;
129 };
130
131 struct classtype_spawn
132 {
133 u32 target;
134 };
135
136 struct classtype_water
137 {
138 u32 temp;
139 };
140
141 struct classtype_car_path
142 {
143 u32 target, target1;
144 };
145
146 struct classtype_instance
147 {
148 u32 pstr_file;
149 };
150
151 struct classtype_capsule
152 {
153 float height, radius;
154 };
155
156 struct classtype_route_node
157 {
158 u32 target, target1;
159 };
160
161 struct classtype_route
162 {
163 u32 id_start;
164 v3f colour;
165 };
166
167 struct classtype_bone
168 {
169 u32 deform,
170 ik_target,
171 ik_pole,
172 collider,
173 use_limits;
174
175 v3f angle_limits[2];
176 boxf hitbox;
177 };
178
179 struct classtype_skeleton
180 {
181 u32 channels,
182 ik_count,
183 collider_count,
184 anim_start,
185 anim_count;
186 };
187
188 struct classtype_skin
189 {
190 u32 skeleton;
191 };
192
193 #pragma pack(pop)
194
195 /*
196 * Simple mesh interface for OpenGL
197 */
198
199 struct glmesh
200 {
201 GLuint vao, vbo, ebo;
202 u32 indice_count;
203 u32 loaded;
204 };
205
206 static void mesh_upload( glmesh *mesh,
207 mdl_vert *verts, u32 vert_count,
208 u32 *indices, u32 indice_count )
209 {
210 //assert( mesh->loaded == 0 );
211
212 glGenVertexArrays( 1, &mesh->vao );
213 glGenBuffers( 1, &mesh->vbo );
214 glGenBuffers( 1, &mesh->ebo );
215 glBindVertexArray( mesh->vao );
216
217 size_t stride = sizeof(mdl_vert);
218
219 glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo );
220 glBufferData( GL_ARRAY_BUFFER, vert_count*stride, verts, GL_STATIC_DRAW );
221
222 glBindVertexArray( mesh->vao );
223 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo );
224 glBufferData( GL_ELEMENT_ARRAY_BUFFER, indice_count*sizeof(u32),
225 indices, GL_STATIC_DRAW );
226
227 /* 0: coordinates */
228 glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 );
229 glEnableVertexAttribArray( 0 );
230
231 /* 1: normal */
232 glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE,
233 stride, (void *)offsetof(mdl_vert, norm) );
234 glEnableVertexAttribArray( 1 );
235
236 /* 2: uv */
237 glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE,
238 stride, (void *)offsetof(mdl_vert, uv) );
239 glEnableVertexAttribArray( 2 );
240
241 /* 3: colour */
242 glVertexAttribPointer( 3, 4, GL_UNSIGNED_BYTE, GL_TRUE,
243 stride, (void *)offsetof(mdl_vert, colour) );
244 glEnableVertexAttribArray( 3 );
245
246 /* 4: weights */
247 glVertexAttribPointer( 4, 4, GL_UNSIGNED_SHORT, GL_TRUE,
248 stride, (void *)offsetof(mdl_vert, weights) );
249 glEnableVertexAttribArray( 4 );
250
251 /* 5: groups */
252 glVertexAttribIPointer( 5, 4, GL_UNSIGNED_BYTE,
253 stride, (void *)offsetof(mdl_vert, groups) );
254 glEnableVertexAttribArray( 5 );
255
256 VG_CHECK_GL_ERR();
257
258 mesh->indice_count = indice_count;
259 mesh->loaded = 1;
260 }
261
262 static void mesh_bind( glmesh *mesh )
263 {
264 glBindVertexArray( mesh->vao );
265 }
266
267 static void mesh_drawn( u32 start, u32 count )
268 {
269 glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT,
270 (void *)(start*sizeof(u32)) );
271 }
272
273 static void mesh_draw( glmesh *mesh )
274 {
275 mesh_drawn( 0, mesh->indice_count );
276 }
277
278 static void mesh_free( glmesh *mesh )
279 {
280 if( mesh->loaded )
281 {
282 glDeleteVertexArrays( 1, &mesh->vao );
283 glDeleteBuffers( 1, &mesh->ebo );
284 glDeleteBuffers( 1, &mesh->vbo );
285 }
286 }
287
288
289 /*
290 * Model implementation
291 */
292
293 static mdl_header *mdl_load( const char *path )
294 {
295 i64 size;
296 mdl_header *header = vg_asset_read_s( path, &size );
297
298 /*
299 * Check file is valid
300 */
301 if( !header )
302 {
303 vg_error( "Could not open '%s'\n", path );
304 return NULL;
305 }
306
307 if( size < sizeof(mdl_header) )
308 {
309 vg_free( header );
310 vg_error( "Invalid file '%s' (too small for header)\n", path );
311 return NULL;
312 }
313
314 if( header->file_length != size )
315 {
316 vg_error( "Invalid file '%s'"
317 "(wrong .file_length, %ub != real file size %ub)\n",
318 path, header->file_length, size );
319 vg_free( header );
320 return NULL;
321 }
322
323 /*
324 * Validate offsets and memory sections, to ensure all arrays are in-bounds,
325 * and that they do not overlap.
326 */
327
328 struct memregion
329 {
330 const char *desc;
331 u32 count, max_count, size, offset;
332 }
333 regions[] = {
334 {
335 "Vertices",
336 header->vertex_count, MDL_VERT_MAX,
337 sizeof(mdl_vert), header->vertex_offset
338 },
339 {
340 "Indices",
341 header->indice_count, MDL_INDICE_MAX,
342 sizeof(u32), header->indice_offset
343 },
344 {
345 "Submesh",
346 header->submesh_count, MDL_SUBMESH_MAX,
347 sizeof(mdl_submesh), header->submesh_offset
348 },
349 {
350 "Materials",
351 header->material_count, MDL_MATERIAL_MAX,
352 sizeof(mdl_material), header->material_offset
353 },
354 {
355 "Nodes",
356 header->node_count, MDL_NODE_MAX,
357 sizeof(mdl_node), header->node_count
358 }
359 };
360
361 for( int i=0; i<vg_list_size(regions); i++ )
362 {
363 struct memregion *ri = &regions[i];
364
365 if( ri->count == 0 )
366 continue;
367
368 if( ri->count > ri->max_count )
369 {
370 vg_free( header );
371 vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n",
372 path, ri->desc, ri->count, ri->max_count );
373 return NULL;
374 }
375
376 if( ri->offset >= header->file_length )
377 {
378 vg_free( header );
379 vg_error( "'%s': '%s' buffer offset is out of range\n",
380 path, ri->desc );
381 return NULL;
382 }
383
384 if( ri->offset + ri->size*ri->count > header->file_length )
385 {
386 vg_free( header );
387 vg_error( "'%s': '%s' buffer size is out of range\n",
388 path, ri->desc );
389 return NULL;
390 }
391
392 for( int j=0; j<vg_list_size(regions); j++ )
393 {
394 struct memregion *rj = &regions[j];
395 if( rj->count == 0 )
396 continue;
397
398 if( ri->offset >= rj->offset &&
399 (ri->offset+ri->size*ri->count < rj->offset+rj->size*rj->count))
400 {
401 vg_free( header );
402 vg_error( "'%s': '%s' buffer overlaps '%s'\n",
403 path, ri->desc, rj->desc );
404 return NULL;
405 }
406 }
407 }
408
409 /*
410 * Pointer validation TODO(workshop)
411 */
412
413 /*
414 * strings TODO(workshop)
415 */
416
417 return header;
418 }
419
420 static void *mdl_baseptr( mdl_header *mdl, u32 offset )
421 {
422 return (void *)mdl + offset;
423 }
424
425 static const char *mdl_pstr( mdl_header *mdl, u32 pstr )
426 {
427 return (const char *)(mdl_baseptr( mdl, mdl->strings_offset )) + pstr;
428 }
429
430 static mdl_node *mdl_node_from_id( mdl_header *mdl, u32 id )
431 {
432 return ((mdl_node *)mdl_baseptr( mdl, mdl->node_offset )) + id;
433 }
434
435 static mdl_node *mdl_node_from_name( mdl_header *mdl, const char *name )
436 {
437 for( int i=0; i<mdl->node_count; i++ )
438 {
439 mdl_node *pnode = mdl_node_from_id( mdl, i );
440
441 if( !strcmp( name, mdl_pstr( mdl, pnode->pstr_name )) )
442 return pnode;
443 }
444
445 return NULL;
446 }
447
448 static mdl_submesh *mdl_submesh_from_id( mdl_header *mdl, u32 id )
449 {
450 if( id >= mdl->submesh_count )
451 return NULL;
452
453 return ((mdl_submesh *)mdl_baseptr( mdl, mdl->submesh_offset )) + id;
454 }
455
456 static mdl_submesh *mdl_node_submesh( mdl_header *mdl, mdl_node *node, u32 i )
457 {
458 if( i >= node->submesh_count )
459 return NULL;
460
461 return mdl_submesh_from_id( mdl, node->submesh_start+i );
462 }
463
464 static u32 *mdl_submesh_indices( mdl_header *mdl, mdl_submesh *sm )
465 {
466 return ((u32 *)mdl_baseptr( mdl, mdl->indice_offset )) + sm->indice_start;
467 }
468
469 static mdl_vert *mdl_submesh_vertices( mdl_header *mdl, mdl_submesh *sm )
470 {
471 return ((mdl_vert *)mdl_baseptr(mdl,mdl->vertex_offset)) + sm->vertex_start;
472 }
473
474 static mdl_material *mdl_material_from_id( mdl_header *mdl, u32 id )
475 {
476 return ((mdl_material *)mdl_baseptr(mdl,mdl->material_offset)) + id;
477 }
478
479 static mdl_animation *mdl_animation_from_id( mdl_header *mdl, u32 id )
480 {
481 return ((mdl_animation *)mdl_baseptr(mdl,mdl->anim_offset)) + id;
482 }
483
484 static void mdl_node_transform( mdl_node *pnode, m4x3f transform )
485 {
486 q_m3x3( pnode->q, transform );
487 v3_muls( transform[0], pnode->s[0], transform[0] );
488 v3_muls( transform[1], pnode->s[1], transform[1] );
489 v3_muls( transform[2], pnode->s[2], transform[2] );
490 v3_copy( pnode->co, transform[3] );
491 }
492
493 static void mdl_unpack_submesh( mdl_header *mdl, glmesh *mesh, mdl_submesh *sm )
494 {
495 mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count,
496 mdl_submesh_indices( mdl, sm ), sm->indice_count );
497 }
498
499 static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh )
500 {
501 u32 offset = mdl_submesh_from_id( mdl, 0 )->vertex_count;
502
503 for( int i=1; i< mdl->submesh_count; i++ )
504 {
505 mdl_submesh *sm = mdl_submesh_from_id( mdl, i );
506 u32 *indices = mdl_submesh_indices( mdl, sm );
507
508 for( u32 j=0; j<sm->indice_count; j++ )
509 indices[j] += offset;
510
511 offset += sm->vertex_count;
512 }
513
514 mdl_vert *vertex_base = mdl_baseptr( mdl, mdl->vertex_offset );
515 u32 *indice_base = mdl_baseptr( mdl, mdl->indice_offset );
516
517 mesh_upload( mesh, vertex_base, mdl->vertex_count,
518 indice_base, mdl->indice_count );
519 }
520
521 static void mdl_draw_submesh( mdl_submesh *sm )
522 {
523 mesh_drawn( sm->indice_start, sm->indice_count );
524 }
525
526 static void *mdl_get_entdata( mdl_header *mdl, mdl_node *pnode )
527 {
528 return mdl_baseptr( mdl, mdl->entdata_offset ) + pnode->offset;
529 }
530
531 static mdl_keyframe *mdl_get_animdata( mdl_header *mdl, mdl_animation *anim )
532 {
533 return mdl_baseptr( mdl, mdl->animdata_offset ) + anim->offset;
534 }
535
536 static void mdl_link_materials( mdl_header *root, mdl_header *child )
537 {
538 u32 lookup[MDL_MATERIAL_MAX];
539
540 for( int i=0; i<child->material_count; i++ )
541 {
542 mdl_material *mi = mdl_material_from_id( child, i );
543 const char *si = mdl_pstr( child, mi->pstr_name );
544
545 lookup[i] = 0;
546
547 for( int j=0; j<root->material_count; j++ )
548 {
549 mdl_material *mj = mdl_material_from_id( root, j );
550 const char *sj = mdl_pstr( root, mj->pstr_name );
551
552 if( !strcmp( si, sj ) )
553 {
554 lookup[i] = j;
555 break;
556 }
557 }
558
559 if( lookup[i] == 0 && i != 0 )
560 {
561 vg_warn( "Could not link material '%s' (not present in root model)\n",
562 si );
563 }
564 }
565
566 for( int i=0; i<child->submesh_count; i++ )
567 {
568 mdl_submesh *sm = mdl_submesh_from_id( child, i );
569 sm->material_id = lookup[sm->material_id];
570 }
571 }
572
573
574 #endif