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