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