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