6 typedef struct glmesh glmesh
;
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
;
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
54 union{ u32 submesh_start
, sub_uid
; };
64 u32 identifier
, version
, file_length
;
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
;
75 * Entity data structures
78 struct classtype_block
88 struct classtype_spawn
93 struct classtype_water
98 struct classtype_car_path
106 * Simple mesh interface for OpenGL
111 GLuint vao
, vbo
, ebo
;
115 static void mesh_upload( glmesh
*mesh
,
116 mdl_vert
*verts
, u32 vert_count
,
117 u32
*indices
, u32 indice_count
)
119 glGenVertexArrays( 1, &mesh
->vao
);
120 glGenBuffers( 1, &mesh
->vbo
);
121 glGenBuffers( 1, &mesh
->ebo
);
122 glBindVertexArray( mesh
->vao
);
124 size_t stride
= sizeof(mdl_vert
);
126 glBindBuffer( GL_ARRAY_BUFFER
, mesh
->vbo
);
127 glBufferData( GL_ARRAY_BUFFER
, vert_count
*stride
, verts
, GL_STATIC_DRAW
);
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
);
134 glVertexAttribPointer( 0, 3, GL_FLOAT
, GL_FALSE
, stride
, (void*)0 );
135 glEnableVertexAttribArray( 0 );
137 glVertexAttribPointer( 1, 3, GL_FLOAT
, GL_FALSE
,
138 stride
, (void *)offsetof(mdl_vert
, norm
) );
139 glEnableVertexAttribArray( 1 );
141 glVertexAttribPointer( 2, 4, GL_FLOAT
, GL_FALSE
,
142 stride
, (void *)offsetof(mdl_vert
, colour
) );
143 glEnableVertexAttribArray( 2 );
145 glVertexAttribPointer( 3, 2, GL_FLOAT
, GL_FALSE
,
146 stride
, (void *)offsetof(mdl_vert
, uv
) );
147 glEnableVertexAttribArray( 3 );
150 mesh
->indice_count
= indice_count
;
153 static void mesh_bind( glmesh
*mesh
)
155 glBindVertexArray( mesh
->vao
);
158 static void mesh_drawn( u32 start
, u32 count
)
160 glDrawElements( GL_TRIANGLES
, count
, GL_UNSIGNED_INT
,
161 (void *)(start
*sizeof(u32
)) );
164 static void mesh_draw( glmesh
*mesh
)
166 mesh_drawn( 0, mesh
->indice_count
);
169 static void mesh_free( glmesh
*mesh
)
171 glDeleteVertexArrays( 1, &mesh
->vao
);
172 glDeleteBuffers( 1, &mesh
->ebo
);
173 glDeleteBuffers( 1, &mesh
->vbo
);
178 * Model implementation
181 static mdl_header
*mdl_load( const char *path
)
184 mdl_header
*header
= vg_asset_read_s( path
, &size
);
187 * Check file is valid
191 vg_error( "Could not open '%s'\n", path
);
195 if( size
< sizeof(mdl_header
) )
198 vg_error( "Invalid file '%s' (too small for header)\n", path
);
202 if( header
->file_length
!= size
)
204 vg_error( "Invalid file '%s'"
205 "(wrong .file_length, %ub != real file size %ub)\n",
206 path
, header
->file_length
, size
);
212 * Validate offsets and memory sections, to ensure all arrays are in-bounds,
213 * and that they do not overlap.
219 u32 count
, max_count
, size
, offset
;
224 header
->vertex_count
, MDL_VERT_MAX
,
225 sizeof(mdl_vert
), header
->vertex_offset
229 header
->indice_count
, MDL_INDICE_MAX
,
230 sizeof(u32
), header
->indice_offset
234 header
->submesh_count
, MDL_SUBMESH_MAX
,
235 sizeof(mdl_submesh
), header
->submesh_offset
239 header
->material_count
, MDL_MATERIAL_MAX
,
240 sizeof(mdl_material
), header
->material_offset
244 header
->node_count
, MDL_NODE_MAX
,
245 sizeof(mdl_node
), header
->node_count
249 for( int i
=0; i
<vg_list_size(regions
); i
++ )
251 struct memregion
*ri
= ®ions
[i
];
256 if( ri
->count
> ri
->max_count
)
259 vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n",
260 path
, ri
->desc
, ri
->count
, ri
->max_count
);
264 if( ri
->offset
>= header
->file_length
)
267 vg_error( "'%s': '%s' buffer offset is out of range\n",
272 if( ri
->offset
+ ri
->size
*ri
->count
> header
->file_length
)
275 vg_error( "'%s': '%s' buffer size is out of range\n",
280 for( int j
=0; j
<vg_list_size(regions
); j
++ )
282 struct memregion
*rj
= ®ions
[j
];
286 if( ri
->offset
>= rj
->offset
&&
287 (ri
->offset
+ri
->size
*ri
->count
< rj
->offset
+rj
->size
*rj
->count
))
290 vg_error( "'%s': '%s' buffer overlaps '%s'\n",
291 path
, ri
->desc
, rj
->desc
);
298 * Pointer validation TODO(workshop)
302 * strings TODO(workshop)
308 static void *mdl_baseptr( mdl_header
*mdl
, u32 offset
)
310 return (void *)mdl
+ offset
;
313 static const char *mdl_pstr( mdl_header
*mdl
, u32 pstr
)
315 return (const char *)(mdl_baseptr( mdl
, mdl
->strings_offset
)) + pstr
;
318 static mdl_node
*mdl_node_from_id( mdl_header
*mdl
, u32 id
)
320 return ((mdl_node
*)mdl_baseptr( mdl
, mdl
->node_offset
)) + id
;
323 static mdl_node
*mdl_node_from_name( mdl_header
*mdl
, const char *name
)
325 for( int i
=0; i
<mdl
->node_count
; i
++ )
327 mdl_node
*pnode
= mdl_node_from_id( mdl
, i
);
329 if( !strcmp( name
, mdl_pstr( mdl
, pnode
->pstr_name
)) )
336 static mdl_submesh
*mdl_submesh_from_id( mdl_header
*mdl
, u32 id
)
338 if( id
>= mdl
->submesh_count
)
341 return ((mdl_submesh
*)mdl_baseptr( mdl
, mdl
->submesh_offset
)) + id
;
344 static mdl_submesh
*mdl_node_submesh( mdl_header
*mdl
, mdl_node
*node
, u32 i
)
346 if( i
>= node
->submesh_count
)
349 return mdl_submesh_from_id( mdl
, node
->submesh_start
+i
);
352 static u32
*mdl_submesh_indices( mdl_header
*mdl
, mdl_submesh
*sm
)
354 return ((u32
*)mdl_baseptr( mdl
, mdl
->indice_offset
)) + sm
->indice_start
;
357 static mdl_vert
*mdl_submesh_vertices( mdl_header
*mdl
, mdl_submesh
*sm
)
359 return ((mdl_vert
*)mdl_baseptr(mdl
,mdl
->vertex_offset
)) + sm
->vertex_start
;
362 static mdl_material
*mdl_material_from_id( mdl_header
*mdl
, u32 id
)
364 return ((mdl_material
*)mdl_baseptr(mdl
,mdl
->material_offset
)) + id
;
367 static void mdl_node_transform( mdl_node
*pnode
, m4x3f transform
)
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] );
376 static void mdl_unpack_submesh( mdl_header
*mdl
, glmesh
*mesh
, mdl_submesh
*sm
)
378 mesh_upload( mesh
, mdl_submesh_vertices( mdl
, sm
), sm
->vertex_count
,
379 mdl_submesh_indices( mdl
, sm
), sm
->indice_count
);
382 static void mdl_unpack_glmesh( mdl_header
*mdl
, glmesh
*mesh
)
384 u32 offset
= mdl_submesh_from_id( mdl
, 0 )->vertex_count
;
386 for( int i
=1; i
< mdl
->submesh_count
; i
++ )
388 mdl_submesh
*sm
= mdl_submesh_from_id( mdl
, i
);
389 u32
*indices
= mdl_submesh_indices( mdl
, sm
);
391 for( u32 j
=0; j
<sm
->indice_count
; j
++ )
392 indices
[j
] += offset
;
394 offset
+= sm
->vertex_count
;
397 mdl_vert
*vertex_base
= mdl_baseptr( mdl
, mdl
->vertex_offset
);
398 u32
*indice_base
= mdl_baseptr( mdl
, mdl
->indice_offset
);
400 mesh_upload( mesh
, vertex_base
, mdl
->vertex_count
,
401 indice_base
, mdl
->indice_count
);
404 static void mdl_draw_submesh( mdl_submesh
*sm
)
406 mesh_drawn( sm
->indice_start
, sm
->indice_count
);
409 static void *mdl_get_entdata( mdl_header
*mdl
, mdl_node
*pnode
)
411 return mdl_baseptr( mdl
, mdl
->entdata_offset
) + pnode
->offset
;