a lot
[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
14 #define MDL_SIZE_MAX 0x1000000
15 #define MDL_VERT_MAX 1000000
16 #define MDL_INDICE_MAX 1000000
17 #define MDL_MATERIAL_MAX 500
18 #define MDL_NODE_MAX 4000
19 #define MDL_SUBMESH_MAX 8000
20 #define MDL_STRING_LENGTH_MAX 64
21
22 #pragma pack(push,1)
23
24 struct mdl_vert
25 {
26 v3f co,
27 norm;
28 v4f colour;
29 v2f uv;
30 };
31
32 struct mdl_submesh
33 {
34 u32 indice_start,
35 indice_count,
36 vertex_start,
37 vertex_count;
38
39 boxf bbx;
40 u32 material_id;
41 };
42
43 struct mdl_material
44 {
45 u32 pstr_name;
46 };
47
48 struct mdl_node
49 {
50 v3f co;
51 v4f q;
52 v3f s;
53
54 union{ u32 submesh_start, sub_uid; };
55 u32
56 submesh_count,
57 classtype,
58 offset,
59 pstr_name;
60 };
61
62 struct mdl_header
63 {
64 u32 identifier, version, file_length;
65
66 u32 vertex_count, vertex_offset,
67 indice_count, indice_offset,
68 submesh_count, submesh_offset,
69 material_count, material_offset,
70 node_count, node_offset,
71 strings_offset, entdata_offset;
72 };
73
74 /*
75 * Entity data structures
76 */
77
78 struct classtype_block
79 {
80 boxf bbx;
81 };
82
83 struct classtype_gate
84 {
85 u32 target;
86 };
87
88 struct classtype_spawn
89 {
90 u32 target;
91 };
92
93 struct classtype_water
94 {
95 u32 temp;
96 };
97
98 struct classtype_car_path
99 {
100 u32 target, target1;
101 };
102
103 #pragma pack(pop)
104
105 /*
106 * Simple mesh interface for OpenGL
107 */
108
109 struct glmesh
110 {
111 GLuint vao, vbo, ebo;
112 u32 indice_count;
113 };
114
115 static void mesh_upload( glmesh *mesh,
116 mdl_vert *verts, u32 vert_count,
117 u32 *indices, u32 indice_count )
118 {
119 glGenVertexArrays( 1, &mesh->vao );
120 glGenBuffers( 1, &mesh->vbo );
121 glGenBuffers( 1, &mesh->ebo );
122 glBindVertexArray( mesh->vao );
123
124 size_t stride = sizeof(mdl_vert);
125
126 glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo );
127 glBufferData( GL_ARRAY_BUFFER, vert_count*stride, verts, GL_STATIC_DRAW );
128
129 glBindVertexArray( mesh->vao );
130 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo );
131 glBufferData( GL_ELEMENT_ARRAY_BUFFER, indice_count*sizeof(u32),
132 indices, GL_STATIC_DRAW );
133
134 glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 );
135 glEnableVertexAttribArray( 0 );
136
137 glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE,
138 stride, (void *)offsetof(mdl_vert, norm) );
139 glEnableVertexAttribArray( 1 );
140
141 glVertexAttribPointer( 2, 4, GL_FLOAT, GL_FALSE,
142 stride, (void *)offsetof(mdl_vert, colour) );
143 glEnableVertexAttribArray( 2 );
144
145 glVertexAttribPointer( 3, 2, GL_FLOAT, GL_FALSE,
146 stride, (void *)offsetof(mdl_vert, uv) );
147 glEnableVertexAttribArray( 3 );
148
149 VG_CHECK_GL();
150 mesh->indice_count = indice_count;
151 }
152
153 static void mesh_bind( glmesh *mesh )
154 {
155 glBindVertexArray( mesh->vao );
156 }
157
158 static void mesh_drawn( u32 start, u32 count )
159 {
160 glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT,
161 (void *)(start*sizeof(u32)) );
162 }
163
164 static void mesh_draw( glmesh *mesh )
165 {
166 mesh_drawn( 0, mesh->indice_count );
167 }
168
169 static void mesh_free( glmesh *mesh )
170 {
171 glDeleteVertexArrays( 1, &mesh->vao );
172 glDeleteBuffers( 1, &mesh->ebo );
173 glDeleteBuffers( 1, &mesh->vbo );
174 }
175
176
177 /*
178 * Model implementation
179 */
180
181 static mdl_header *mdl_load( const char *path )
182 {
183 i64 size;
184 mdl_header *header = vg_asset_read_s( path, &size );
185
186 /*
187 * Check file is valid
188 */
189 if( !header )
190 {
191 vg_error( "Could not open '%s'\n", path );
192 return NULL;
193 }
194
195 if( size < sizeof(mdl_header) )
196 {
197 free( header );
198 vg_error( "Invalid file '%s' (too small for header)\n", path );
199 return NULL;
200 }
201
202 if( header->file_length != size )
203 {
204 vg_error( "Invalid file '%s'"
205 "(wrong .file_length, %ub != real file size %ub)\n",
206 path, header->file_length, size );
207 free( header );
208 return NULL;
209 }
210
211 /*
212 * Validate offsets and memory sections, to ensure all arrays are in-bounds,
213 * and that they do not overlap.
214 */
215
216 struct memregion
217 {
218 const char *desc;
219 u32 count, max_count, size, offset;
220 }
221 regions[] = {
222 {
223 "Vertices",
224 header->vertex_count, MDL_VERT_MAX,
225 sizeof(mdl_vert), header->vertex_offset
226 },
227 {
228 "Indices",
229 header->indice_count, MDL_INDICE_MAX,
230 sizeof(u32), header->indice_offset
231 },
232 {
233 "Submesh",
234 header->submesh_count, MDL_SUBMESH_MAX,
235 sizeof(mdl_submesh), header->submesh_offset
236 },
237 {
238 "Materials",
239 header->material_count, MDL_MATERIAL_MAX,
240 sizeof(mdl_material), header->material_offset
241 },
242 {
243 "Nodes",
244 header->node_count, MDL_NODE_MAX,
245 sizeof(mdl_node), header->node_count
246 }
247 };
248
249 for( int i=0; i<vg_list_size(regions); i++ )
250 {
251 struct memregion *ri = &regions[i];
252
253 if( ri->count == 0 )
254 continue;
255
256 if( ri->count > ri->max_count )
257 {
258 free( header );
259 vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n",
260 path, ri->desc, ri->count, ri->max_count );
261 return NULL;
262 }
263
264 if( ri->offset >= header->file_length )
265 {
266 free( header );
267 vg_error( "'%s': '%s' buffer offset is out of range\n",
268 path, ri->desc );
269 return NULL;
270 }
271
272 if( ri->offset + ri->size*ri->count > header->file_length )
273 {
274 free( header );
275 vg_error( "'%s': '%s' buffer size is out of range\n",
276 path, ri->desc );
277 return NULL;
278 }
279
280 for( int j=0; j<vg_list_size(regions); j++ )
281 {
282 struct memregion *rj = &regions[j];
283 if( rj->count == 0 )
284 continue;
285
286 if( ri->offset >= rj->offset &&
287 (ri->offset+ri->size*ri->count < rj->offset+rj->size*rj->count))
288 {
289 free( header );
290 vg_error( "'%s': '%s' buffer overlaps '%s'\n",
291 path, ri->desc, rj->desc );
292 return NULL;
293 }
294 }
295 }
296
297 /*
298 * Pointer validation TODO(workshop)
299 */
300
301 /*
302 * strings TODO(workshop)
303 */
304
305 return header;
306 }
307
308 static void *mdl_baseptr( mdl_header *mdl, u32 offset )
309 {
310 return (void *)mdl + offset;
311 }
312
313 static const char *mdl_pstr( mdl_header *mdl, u32 pstr )
314 {
315 return (const char *)(mdl_baseptr( mdl, mdl->strings_offset )) + pstr;
316 }
317
318 static mdl_node *mdl_node_from_id( mdl_header *mdl, u32 id )
319 {
320 return ((mdl_node *)mdl_baseptr( mdl, mdl->node_offset )) + id;
321 }
322
323 static mdl_node *mdl_node_from_name( mdl_header *mdl, const char *name )
324 {
325 for( int i=0; i<mdl->node_count; i++ )
326 {
327 mdl_node *pnode = mdl_node_from_id( mdl, i );
328
329 if( !strcmp( name, mdl_pstr( mdl, pnode->pstr_name )) )
330 return pnode;
331 }
332
333 return NULL;
334 }
335
336 static mdl_submesh *mdl_submesh_from_id( mdl_header *mdl, u32 id )
337 {
338 if( id >= mdl->submesh_count )
339 return NULL;
340
341 return ((mdl_submesh *)mdl_baseptr( mdl, mdl->submesh_offset )) + id;
342 }
343
344 static mdl_submesh *mdl_node_submesh( mdl_header *mdl, mdl_node *node, u32 i )
345 {
346 if( i >= node->submesh_count )
347 return NULL;
348
349 return mdl_submesh_from_id( mdl, node->submesh_start+i );
350 }
351
352 static u32 *mdl_submesh_indices( mdl_header *mdl, mdl_submesh *sm )
353 {
354 return ((u32 *)mdl_baseptr( mdl, mdl->indice_offset )) + sm->indice_start;
355 }
356
357 static mdl_vert *mdl_submesh_vertices( mdl_header *mdl, mdl_submesh *sm )
358 {
359 return ((mdl_vert *)mdl_baseptr(mdl,mdl->vertex_offset)) + sm->vertex_start;
360 }
361
362 static mdl_material *mdl_material_from_id( mdl_header *mdl, u32 id )
363 {
364 return ((mdl_material *)mdl_baseptr(mdl,mdl->material_offset)) + id;
365 }
366
367 static void mdl_node_transform( mdl_node *pnode, m4x3f transform )
368 {
369 q_m3x3( pnode->q, transform );
370 v3_muls( transform[0], pnode->s[0], transform[0] );
371 v3_muls( transform[1], pnode->s[1], transform[1] );
372 v3_muls( transform[2], pnode->s[2], transform[2] );
373 v3_copy( pnode->co, transform[3] );
374 }
375
376 static void mdl_unpack_submesh( mdl_header *mdl, glmesh *mesh, mdl_submesh *sm )
377 {
378 mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count,
379 mdl_submesh_indices( mdl, sm ), sm->indice_count );
380 }
381
382 static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh )
383 {
384 u32 offset = mdl_submesh_from_id( mdl, 0 )->vertex_count;
385
386 for( int i=1; i< mdl->submesh_count; i++ )
387 {
388 mdl_submesh *sm = mdl_submesh_from_id( mdl, i );
389 u32 *indices = mdl_submesh_indices( mdl, sm );
390
391 for( u32 j=0; j<sm->indice_count; j++ )
392 indices[j] += offset;
393
394 offset += sm->vertex_count;
395 }
396
397 mdl_vert *vertex_base = mdl_baseptr( mdl, mdl->vertex_offset );
398 u32 *indice_base = mdl_baseptr( mdl, mdl->indice_offset );
399
400 mesh_upload( mesh, vertex_base, mdl->vertex_count,
401 indice_base, mdl->indice_count );
402 }
403
404 static void mdl_draw_submesh( mdl_submesh *sm )
405 {
406 mesh_drawn( sm->indice_start, sm->indice_count );
407 }
408
409 static void *mdl_get_entdata( mdl_header *mdl, mdl_node *pnode )
410 {
411 return mdl_baseptr( mdl, mdl->entdata_offset ) + pnode->offset;
412 }
413
414
415 #endif