1 //********************************************************************************************
2 //*
3 //* This file is part of Egoboo.
4 //*
5 //* Egoboo is free software: you can redistribute it and/or modify it
6 //* under the terms of the GNU General Public License as published by
7 //* the Free Software Foundation, either version 3 of the License, or
8 //* (at your option) any later version.
9 //*
10 //* Egoboo is distributed in the hope that it will be useful, but
11 //* WITHOUT ANY WARRANTY; without even the implied warranty of
12 //* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 //* General Public License for more details.
14 //*
15 //* You should have received a copy of the GNU General Public License
16 //* along with Egoboo. If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19
20 ///
21 /// @file md2.c
22 /// @brief Raw MD2 loader
23 /// @details Raw model loader for ID Software's MD2 file format
24
25 #include "md2.inl"
26
27 #include "log.h"
28
29 #include "egoboo_endian.h"
30 #include "egoboo_math.inl"
31
32 #include "egoboo_mem.h"
33
34 //--------------------------------------------------------------------------------------------
35 //--------------------------------------------------------------------------------------------
36 float kMd2Normals[EGO_NORMAL_COUNT][3] =
37 {
38 #include "id_normals.inl"
39 , {0, 0, 0} ///< the "equal light" normal
40 };
41
42 //--------------------------------------------------------------------------------------------
43 //--------------------------------------------------------------------------------------------
44 static MD2_Frame_t * MD2_Frame_ctor( MD2_Frame_t * pframe, size_t size );
45 static MD2_Frame_t * MD2_Frame_dtor( MD2_Frame_t * pframe );
46
47 //--------------------------------------------------------------------------------------------
48 //--------------------------------------------------------------------------------------------
MD2_Frame_ctor(MD2_Frame_t * pframe,size_t size)49 MD2_Frame_t * MD2_Frame_ctor( MD2_Frame_t * pframe, size_t size )
50 {
51 if ( NULL == pframe ) return pframe;
52
53 memset( pframe, 0, sizeof( *pframe ) );
54
55 pframe->vertex_lst = EGOBOO_NEW_ARY( MD2_Vertex_t, size );
56 if ( NULL != pframe->vertex_lst ) pframe->vertex_count = size;
57
58 return pframe;
59 }
60
61 //--------------------------------------------------------------------------------------------
MD2_Frame_dtor(MD2_Frame_t * pframe)62 MD2_Frame_t * MD2_Frame_dtor( MD2_Frame_t * pframe )
63 {
64 if ( NULL == pframe ) return pframe;
65
66 EGOBOO_DELETE_ARY( pframe->vertex_lst );
67 pframe->vertex_count = 0;
68
69 memset( pframe, 0, sizeof( *pframe ) );
70
71 return pframe;
72 }
73
74 //--------------------------------------------------------------------------------------------
75 //--------------------------------------------------------------------------------------------
MD2_GLCommand_ctor(MD2_GLCommand_t * m)76 void MD2_GLCommand_ctor( MD2_GLCommand_t * m )
77 {
78 if ( NULL == m ) return;
79
80 memset( m, 0, sizeof( *m ) );
81
82 m->next = NULL;
83 m->data = NULL;
84 }
85
86 //--------------------------------------------------------------------------------------------
MD2_GLCommand_dtor(MD2_GLCommand_t * m)87 void MD2_GLCommand_dtor( MD2_GLCommand_t * m )
88 {
89 if ( NULL == m ) return;
90
91 EGOBOO_DELETE_ARY( m->data );
92
93 memset( m, 0, sizeof( *m ) );
94 }
95
96 //--------------------------------------------------------------------------------------------
MD2_GLCommand_create()97 MD2_GLCommand_t * MD2_GLCommand_create()
98 {
99 MD2_GLCommand_t * m;
100
101 m = EGOBOO_NEW( MD2_GLCommand_t );
102
103 MD2_GLCommand_ctor( m );
104
105 return m;
106 }
107
108 //--------------------------------------------------------------------------------------------
MD2_GLCommand_new_vector(int n)109 MD2_GLCommand_t * MD2_GLCommand_new_vector( int n )
110 {
111 int i;
112 MD2_GLCommand_t * v = EGOBOO_NEW_ARY( MD2_GLCommand_t, n );
113 for ( i = 0; i < n; i++ ) MD2_GLCommand_ctor( v + i );
114 return v;
115 }
116
117 //--------------------------------------------------------------------------------------------
MD2_GLCommand_destroy(MD2_GLCommand_t ** m)118 void MD2_GLCommand_destroy( MD2_GLCommand_t ** m )
119 {
120 if ( NULL == m || NULL == * m ) return;
121
122 MD2_GLCommand_dtor( *m );
123
124 EGOBOO_DELETE( *m );
125 }
126
127 //--------------------------------------------------------------------------------------------
MD2_GLCommand_delete_list(MD2_GLCommand_t * command_ptr,int command_count)128 void MD2_GLCommand_delete_list( MD2_GLCommand_t * command_ptr, int command_count )
129 {
130 int cnt;
131
132 if ( NULL == command_ptr ) return;
133
134 for ( cnt = 0; cnt < command_count && NULL != command_ptr; cnt++ )
135 {
136 MD2_GLCommand_t * tmp = command_ptr;
137 command_ptr = command_ptr->next;
138
139 MD2_GLCommand_destroy( &tmp );
140 }
141 }
142
143 //--------------------------------------------------------------------------------------------
144 //--------------------------------------------------------------------------------------------
MD2_Model_ctor(MD2_Model_t * m)145 MD2_Model_t * MD2_Model_ctor( MD2_Model_t * m )
146 {
147 if ( NULL == m ) return m;
148
149 memset( m, 0, sizeof( *m ) );
150
151 return m;
152 }
153
154 //--------------------------------------------------------------------------------------------
md2_free(MD2_Model_t * m)155 void md2_free( MD2_Model_t * m )
156 {
157 EGOBOO_DELETE_ARY( m->m_skins );
158 m->m_numSkins = 0;
159
160 EGOBOO_DELETE_ARY( m->m_texCoords );
161 m->m_numTexCoords = 0;
162
163 EGOBOO_DELETE_ARY( m->m_triangles );
164 m->m_numTriangles = 0;
165
166 if ( NULL != m->m_frames )
167 {
168 int i;
169 for ( i = 0; i < m->m_numFrames; i++ )
170 {
171 MD2_Frame_dtor( m->m_frames + i );
172 }
173
174 EGOBOO_DELETE_ARY( m->m_frames );
175 m->m_numFrames = 0;
176 }
177
178 MD2_GLCommand_delete_list( m->m_commands, m->m_numCommands );
179 m->m_commands = NULL;
180 m->m_numCommands = 0;
181 }
182
183 //--------------------------------------------------------------------------------------------
MD2_Model_dtor(MD2_Model_t * m)184 MD2_Model_t * MD2_Model_dtor( MD2_Model_t * m )
185 {
186 if ( NULL == m ) return NULL;
187
188 md2_free( m );
189
190 return m;
191 }
192
193 //--------------------------------------------------------------------------------------------
MD2_Model_create()194 MD2_Model_t * MD2_Model_create()
195 {
196 MD2_Model_t * m = EGOBOO_NEW( MD2_Model_t );
197
198 MD2_Model_ctor( m );
199
200 return m;
201 }
202
203 //--------------------------------------------------------------------------------------------
MD2_Model_new_vector(int n)204 MD2_Model_t * MD2_Model_new_vector( int n )
205 {
206 int i;
207 MD2_Model_t * v = EGOBOO_NEW_ARY( MD2_Model_t, n );
208 for ( i = 0; i < n; i++ ) MD2_Model_ctor( v + i );
209 return v;
210 }
211
212 //--------------------------------------------------------------------------------------------
MD2_Model_destroy(MD2_Model_t ** m)213 void MD2_Model_destroy( MD2_Model_t ** m )
214 {
215 if ( NULL == m || NULL == *m ) return;
216
217 MD2_Model_dtor( *m );
218
219 EGOBOO_DELETE( *m );
220 }
221
222 //--------------------------------------------------------------------------------------------
MD2_Model_delete_vector(MD2_Model_t * v,int n)223 void MD2_Model_delete_vector( MD2_Model_t * v, int n )
224 {
225 int i;
226 if ( NULL == v || 0 == n ) return;
227 for ( i = 0; i < n; i++ ) MD2_Model_dtor( v + i );
228 EGOBOO_DELETE( v );
229 }
230
231 //--------------------------------------------------------------------------------------------
232 //--------------------------------------------------------------------------------------------
md2_scale_model(MD2_Model_t * pmd2,float scale_x,float scale_y,float scale_z)233 void md2_scale_model( MD2_Model_t * pmd2, float scale_x, float scale_y, float scale_z )
234 {
235 /// @details BB@> scale every vertex in the md2 by the given amount
236
237 int cnt, tnc;
238 int num_frames, num_verts;
239 MD2_Frame_t * pframe;
240
241 num_frames = pmd2->m_numFrames;
242 num_verts = pmd2->m_numVertices;
243
244 for ( cnt = 0; cnt < num_frames; cnt++ )
245 {
246 bool_t bfound;
247
248 pframe = pmd2->m_frames + cnt;
249
250 bfound = bfalse;
251 for ( tnc = 0; tnc < num_verts; tnc++ )
252 {
253 oct_vec_t opos;
254
255 pframe->vertex_lst[tnc].pos.x *= scale_x;
256 pframe->vertex_lst[tnc].pos.y *= scale_y;
257 pframe->vertex_lst[tnc].pos.z *= scale_z;
258
259 pframe->vertex_lst[tnc].nrm.x *= SGN( scale_x );
260 pframe->vertex_lst[tnc].nrm.y *= SGN( scale_y );
261 pframe->vertex_lst[tnc].nrm.z *= SGN( scale_z );
262
263 pframe->vertex_lst[tnc].nrm = fvec3_normalize( pframe->vertex_lst[tnc].nrm.v );
264
265 oct_vec_ctor( opos, pframe->vertex_lst[tnc].pos.v );
266
267 // Re-calculate the bounding box for this frame
268 if ( !bfound )
269 {
270 oct_bb_set_ovec( &( pframe->bb ), opos );
271 bfound = btrue;
272 }
273 else
274 {
275 oct_bb_self_sum_ovec( &( pframe->bb ), opos );
276 }
277 }
278
279 // we don't really want objects that have extent in more than one
280 // dimension to be called empty
281 if ( pframe->bb.empty )
282 {
283 if ( ABS( pframe->bb.maxs[OCT_X] - pframe->bb.mins[OCT_X] ) +
284 ABS( pframe->bb.maxs[OCT_Y] - pframe->bb.mins[OCT_Y] ) +
285 ABS( pframe->bb.maxs[OCT_Z] - pframe->bb.mins[OCT_Z] ) > 0.0f )
286 {
287 oct_vec_t ovec;
288
289 ovec[OCT_X] = ovec[OCT_Y] = ovec[OCT_Z] = 1e-6;
290 ovec[OCT_XY] = ovec[OCT_YX] = SQRT_TWO * ovec[OCT_X];
291 oct_bb_self_grow( &( pframe->bb ), ovec );
292 }
293 }
294 }
295 }
296
297 //--------------------------------------------------------------------------------------------
298 //--------------------------------------------------------------------------------------------
md2_load(const char * szFilename,MD2_Model_t * mdl)299 MD2_Model_t* md2_load( const char * szFilename, MD2_Model_t* mdl )
300 {
301 FILE * f;
302 int i, v;
303 bool_t bfound;
304
305 id_md2_header_t md2_header;
306 MD2_Model_t *model;
307
308 // Open up the file, and make sure it's a MD2 model
309 f = fopen( szFilename, "rb" );
310 if ( NULL == f )
311 {
312 log_warning( "md2_load() - could not open model (%s)\n", szFilename );
313 return NULL;
314 }
315
316 fread( &md2_header, sizeof( md2_header ), 1, f );
317
318 // Convert the byte ordering in the md2_header, if we need to
319 md2_header.ident = ENDIAN_INT32( md2_header.ident );
320 md2_header.version = ENDIAN_INT32( md2_header.version );
321 md2_header.skinwidth = ENDIAN_INT32( md2_header.skinwidth );
322 md2_header.skinheight = ENDIAN_INT32( md2_header.skinheight );
323 md2_header.framesize = ENDIAN_INT32( md2_header.framesize );
324 md2_header.num_skins = ENDIAN_INT32( md2_header.num_skins );
325 md2_header.num_vertices = ENDIAN_INT32( md2_header.num_vertices );
326 md2_header.num_st = ENDIAN_INT32( md2_header.num_st );
327 md2_header.num_tris = ENDIAN_INT32( md2_header.num_tris );
328 md2_header.size_glcmds = ENDIAN_INT32( md2_header.size_glcmds );
329 md2_header.num_frames = ENDIAN_INT32( md2_header.num_frames );
330 md2_header.offset_skins = ENDIAN_INT32( md2_header.offset_skins );
331 md2_header.offset_st = ENDIAN_INT32( md2_header.offset_st );
332 md2_header.offset_tris = ENDIAN_INT32( md2_header.offset_tris );
333 md2_header.offset_frames = ENDIAN_INT32( md2_header.offset_frames );
334 md2_header.offset_glcmds = ENDIAN_INT32( md2_header.offset_glcmds );
335 md2_header.offset_end = ENDIAN_INT32( md2_header.offset_end );
336
337 if ( md2_header.ident != MD2_MAGIC_NUMBER || md2_header.version != MD2_VERSION )
338 {
339 fclose( f );
340 log_warning( "md2_load() - model does not have valid header or identifier (%s)\n", szFilename );
341 return NULL;
342 }
343
344 // Allocate a MD2_Model_t to hold all this stuff
345 model = ( NULL == mdl ) ? MD2_Model_create() : mdl;
346 if ( NULL == model )
347 {
348 log_error( "md2_load() - could create MD2_Model_t\n" );
349 return NULL;
350 }
351
352 model->m_numVertices = md2_header.num_vertices;
353 model->m_numTexCoords = md2_header.num_st;
354 model->m_numTriangles = md2_header.num_tris;
355 model->m_numSkins = md2_header.num_skins;
356 model->m_numFrames = md2_header.num_frames;
357
358 model->m_texCoords = EGOBOO_NEW_ARY( MD2_TexCoord_t, md2_header.num_st );
359 model->m_triangles = EGOBOO_NEW_ARY( MD2_Triangle_t, md2_header.num_tris );
360 model->m_skins = EGOBOO_NEW_ARY( MD2_SkinName_t, md2_header.num_skins );
361 model->m_frames = EGOBOO_NEW_ARY( MD2_Frame_t, md2_header.num_frames );
362
363 for ( i = 0; i < md2_header.num_frames; i++ )
364 {
365 MD2_Frame_ctor( model->m_frames + i, md2_header.num_vertices );
366 }
367
368 // Load the texture coordinates from the file, normalizing them as we go
369 fseek( f, md2_header.offset_st, SEEK_SET );
370 for ( i = 0; i < md2_header.num_st; i++ )
371 {
372 id_md2_texcoord_t tc;
373 fread( &tc, sizeof( tc ), 1, f );
374
375 // auto-convert the byte ordering of the texture coordinates
376 tc.s = ENDIAN_INT16( tc.s );
377 tc.t = ENDIAN_INT16( tc.t );
378
379 model->m_texCoords[i].tex.s = tc.s / ( float )md2_header.skinwidth;
380 model->m_texCoords[i].tex.t = tc.t / ( float )md2_header.skinheight;
381 }
382
383 // Load triangles from the file. I use the same memory layout as the file
384 // on a little endian machine, so they can just be read directly
385 fseek( f, md2_header.offset_tris, SEEK_SET );
386 fread( model->m_triangles, sizeof( id_md2_triangle_t ), md2_header.num_tris, f );
387
388 // auto-convert the byte ordering on the triangles
389 for ( i = 0; i < md2_header.num_tris; i++ )
390 {
391 for ( v = 0; v < 3; v++ )
392 {
393 model->m_triangles[i].vertex[v] = ENDIAN_INT16( model->m_triangles[i].vertex[v] );
394 model->m_triangles[i].st[v] = ENDIAN_INT16( model->m_triangles[i].st[v] );
395 }
396 }
397
398 // Load the skin names. Again, I can load them directly
399 fseek( f, md2_header.offset_skins, SEEK_SET );
400 fread( model->m_skins, sizeof( id_md2_skin_t ), md2_header.num_skins, f );
401
402 // Load the frames of animation
403 fseek( f, md2_header.offset_frames, SEEK_SET );
404 for ( i = 0; i < md2_header.num_frames; i++ )
405 {
406 id_md2_frame_header_t frame_header;
407
408 // read the current frame
409 fread( &frame_header, sizeof( frame_header ), 1, f );
410
411 // Convert the byte ordering on the scale & translate vectors, if necessary
412 #if SDL_BYTEORDER != SDL_LIL_ENDIAN
413 frame_header.scale[0] = ENDIAN_FLOAT( frame_header.scale[0] );
414 frame_header.scale[1] = ENDIAN_FLOAT( frame_header.scale[1] );
415 frame_header.scale[2] = ENDIAN_FLOAT( frame_header.scale[2] );
416
417 frame_header.translate[0] = ENDIAN_FLOAT( frame_header.translate[0] );
418 frame_header.translate[1] = ENDIAN_FLOAT( frame_header.translate[1] );
419 frame_header.translate[2] = ENDIAN_FLOAT( frame_header.translate[2] );
420 #endif
421
422 // unpack the md2 vertex_lst from this frame
423 bfound = bfalse;
424 for ( v = 0; v < md2_header.num_vertices; v++ )
425 {
426 oct_vec_t ovec;
427 MD2_Frame_t * pframe;
428 id_md2_vertex_t frame_vert;
429
430 // read vertex_lst one-by-one. I hope this is not endian dependent, but I have no way to check it.
431 fread( &frame_vert, sizeof( id_md2_vertex_t ), 1, f );
432
433 pframe = model->m_frames + i;
434
435 // grab the vertex position
436 pframe->vertex_lst[v].pos.x = frame_vert.v[0] * frame_header.scale[0] + frame_header.translate[0];
437 pframe->vertex_lst[v].pos.y = frame_vert.v[1] * frame_header.scale[1] + frame_header.translate[1];
438 pframe->vertex_lst[v].pos.z = frame_vert.v[2] * frame_header.scale[2] + frame_header.translate[2];
439
440 // grab the normal index
441 pframe->vertex_lst[v].normal = frame_vert.normalIndex;
442 if ( pframe->vertex_lst[v].normal > EGO_AMBIENT_INDEX ) pframe->vertex_lst[v].normal = EGO_AMBIENT_INDEX;
443
444 // expand the normal index into an actual normal
445 pframe->vertex_lst[v].nrm.x = kMd2Normals[frame_vert.normalIndex][0];
446 pframe->vertex_lst[v].nrm.y = kMd2Normals[frame_vert.normalIndex][1];
447 pframe->vertex_lst[v].nrm.z = kMd2Normals[frame_vert.normalIndex][2];
448
449 // Calculate the bounding box for this frame
450 oct_vec_ctor( ovec, pframe->vertex_lst[v].pos.v );
451 if ( !bfound )
452 {
453 oct_bb_set_ovec( &( pframe->bb ), ovec );
454 bfound = btrue;
455 }
456 else
457 {
458 oct_bb_self_sum_ovec( &( pframe->bb ), ovec );
459 }
460 }
461
462 //make sure to copy the frame name!
463 strncpy( model->m_frames[i].name, frame_header.name, 16 );
464 }
465
466 //Load up the pre-computed OpenGL optimizations
467 if ( md2_header.size_glcmds > 0 )
468 {
469 Uint32 cmd_cnt = 0, cmd_size;
470 MD2_GLCommand_t * cmd = NULL;
471 fseek( f, md2_header.offset_glcmds, SEEK_SET );
472
473 //count the commands
474 cmd_size = 0;
475 while ( cmd_size < md2_header.size_glcmds )
476 {
477 Sint32 commands;
478
479 fread( &commands, sizeof( Sint32 ), 1, f );
480 cmd_size += sizeof( Sint32 ) / sizeof( Uint32 );
481
482 // auto-convert the byte ordering
483 commands = ENDIAN_INT32( commands );
484
485 if ( 0 == commands || cmd_size == md2_header.size_glcmds ) break;
486
487 cmd = MD2_GLCommand_create();
488 cmd->command_count = commands;
489
490 //set the GL drawing mode
491 if ( cmd->command_count > 0 )
492 {
493 cmd->gl_mode = GL_TRIANGLE_STRIP;
494 }
495 else
496 {
497 cmd->command_count = -cmd->command_count;
498 cmd->gl_mode = GL_TRIANGLE_FAN;
499 }
500
501 //allocate the data
502 cmd->data = EGOBOO_NEW_ARY( id_glcmd_packed_t, cmd->command_count );
503
504 //read in the data
505 fread( cmd->data, sizeof( id_glcmd_packed_t ), cmd->command_count, f );
506 cmd_size += ( sizeof( id_glcmd_packed_t ) * cmd->command_count ) / sizeof( Uint32 );
507
508 //translate the data, if necessary
509 #if SDL_BYTEORDER != SDL_LIL_ENDIAN
510 {
511 int i;
512 for ( i = 0; i < cmd->command_count; i++ )
513 {
514 cmd->data[i].index = SDL_Swap32( cmd->data[i].s );
515 cmd->data[i].s = ENDIAN_FLOAT( cmd->data[i].s );
516 cmd->data[i].t = ENDIAN_FLOAT( cmd->data[i].t );
517 };
518 }
519 #endif
520
521 // attach it to the command list
522 cmd->next = model->m_commands;
523 model->m_commands = cmd;
524
525 cmd_cnt += cmd->command_count;
526 };
527
528 model->m_numCommands = cmd_cnt;
529 }
530
531 // Close the file, we're done with it
532 fclose( f );
533
534 return model;
535 }
536
537