source: trunk/src/formats/md3_loader.cc @ 398

Last change on this file since 398 was 395, checked in by epyon, 10 years ago
  • bulk update copyright update include guards cleanup core/common.hh -> common.hh minor cleanups
File size: 14.0 KB
Line 
1// Copyright (C) 2012-2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/formats/md3_loader.hh"
8
9#include "nv/core/logging.hh"
10
11using namespace nv;
12
13// based on http://www.icculus.org/~phaethon/q3/formats/md3format.html#Surface
14
15// assuming low-endian
16#define MD3_MAX_FRAMES    1024
17#define MD3_MAX_TAGS      16
18#define MD3_MAX_SURFACES  32
19#define MD3_MAX_SHADERS   256
20#define MD3_MAX_VERTS     4096
21#define MD3_MAX_TRIANGLES 8192
22#define MD3_XYZ_SCALE     (1.0f/64.0f)
23
24struct md3_vec3_t
25{
26        float xyz[3];
27};
28
29struct md3_header_t
30{
31        char   ident[4]; // IDP3
32        sint32 version;  // 15
33        uint8  name[64]; // path name
34        sint32 flags;
35        sint32 num_frames;     // Number of Frame objects, with a maximum of MD3_MAX_FRAMES. Current value of MD3_MAX_FRAMES is 1024.
36        sint32 num_tags;       // Number of Tag objects, with a maximum of MD3_MAX_TAGS. Current value of MD3_MAX_TAGS is 16.
37        sint32 num_surfaces;   // Number of Surface objects, with a maximum of MD3_MAX_SURFACES. Current value of MD3_MAX_SURFACES is 32.
38        sint32 num_skins;      // Number of Skin objects. I should note that I have not seen an MD3 using this particular field for anything; this appears to be an artifact from the Quake 2 MD2 format. Surface objects have their own Shader field.
39        sint32 ofs_frames;     // Relative offset from start of MD3 object where Frame objects start. The Frame objects are written sequentially, that is, when you read one Frame object, you do not need to seek() for the next object.
40        sint32 ofs_tags;       // Relative offset from start of MD3 where Tag objects start. Similarly written sequentially.
41        sint32 ofs_surfaces;   // Relative offset from start of MD3 where Surface objects start. Again, written sequentially.
42        sint32 ofs_eof;        // Relative offset from start of MD3 to the end of the MD3 object. Note there is no offset for Skin objects.
43};
44
45struct md3_frame_t
46{
47        md3_vec3_t min_bounds;
48        md3_vec3_t max_bounds;
49        md3_vec3_t local_origin;
50        float      radius;
51        uint8      name[16];
52};
53
54struct md3_tag_t
55{
56        uint8      name[64];
57        md3_vec3_t origin;
58        md3_vec3_t axis[3];
59};
60
61struct md3_surface_header_t
62{
63        char   ident[4]; // IDP3
64        uint8  name[64]; // path name
65        sint32 flags;
66        sint32 num_frames;
67        sint32 num_shaders;
68        sint32 num_verts;
69        sint32 num_triangles;
70        sint32 ofs_triangles;
71        sint32 ofs_shaders;
72        sint32 ofs_st;
73        sint32 ofs_xyznormal;
74        sint32 ofs_end;
75};
76
77struct md3_shader_t
78{
79        uint8  name[64];
80        sint32 shader_index;
81};
82
83struct md3_triangle_t
84{
85        sint32 indexes[3];
86};
87
88struct md3_texcoord_t
89{
90        float  st[2];
91};
92
93struct md3_vertex_t
94{
95        sint16 x;
96        sint16 y;
97        sint16 z;
98        uint16 normal;
99};
100
101struct md3_surface_t
102{
103        md3_surface_header_t header;
104        md3_shader_t*        shaders;
105        md3_triangle_t*      triangles;
106        md3_texcoord_t*      st;
107        md3_vertex_t*        vertices;
108};
109
110struct md3_t
111{
112        md3_header_t   header;
113        md3_frame_t*   frames;
114        md3_tag_t*     tags;
115        md3_surface_t* surfaces;
116        // extra information (not in md3 file)
117        sint32         vertices_per_frame;
118};
119
120static bool check_md3_magic( char* magic )
121{
122        return magic[0] == 'I' && magic[1] == 'D' && magic[2] == 'P' && magic[3] == '3';
123}
124
125static void free_md3_surface( md3_surface_t * surface )
126{
127        delete[] surface->shaders;
128        delete[] surface->triangles;
129        delete[] surface->st;
130        delete[] surface->vertices;
131}
132
133static void free_md3( md3_t * md3 )
134{
135        sint32 count = md3->header.num_surfaces;
136        for ( sint32 i = 0; i < count; ++i )
137        {
138                free_md3_surface( &md3->surfaces[i] );
139        }
140        delete[] md3->frames;
141        delete[] md3->tags;
142        delete[] md3->surfaces;
143}
144
145static bool read_surface( md3_surface_t * surface, nv::stream& source )
146{
147        sint32 pos = static_cast< sint32 >( source.tell() );
148        source.read( &surface->header, sizeof(md3_surface_header_t), 1 );
149
150        if ( !check_md3_magic( surface->header.ident ) )          return false;
151        if ( surface->header.num_frames    >  MD3_MAX_FRAMES )    return false;
152        if ( surface->header.num_shaders   >  MD3_MAX_SHADERS )   return false;
153        if ( surface->header.num_verts     >  MD3_MAX_VERTS )     return false;
154        if ( surface->header.num_triangles >  MD3_MAX_TRIANGLES ) return false;
155
156        surface->shaders   = new md3_shader_t  [ surface->header.num_shaders ];
157        surface->vertices  = new md3_vertex_t  [ surface->header.num_verts * surface->header.num_frames ];
158        surface->st        = new md3_texcoord_t[ surface->header.num_verts ];
159        surface->triangles = new md3_triangle_t[ surface->header.num_triangles ];
160
161        source.seek( pos + surface->header.ofs_shaders, origin::SET );
162        source.read( surface->shaders, sizeof( md3_shader_t ), static_cast<nv::size_t>( surface->header.num_shaders ) );
163
164        source.seek( pos + surface->header.ofs_triangles, origin::SET );
165        source.read( surface->triangles, sizeof( md3_triangle_t ), static_cast<nv::size_t>( surface->header.num_triangles ) );
166
167        source.seek( pos + surface->header.ofs_st, origin::SET );
168        source.read( surface->st, sizeof( md3_texcoord_t ), static_cast<nv::size_t>( surface->header.num_verts ) );
169
170        source.seek( pos + surface->header.ofs_xyznormal, origin::SET );
171        source.read( surface->vertices, sizeof( md3_vertex_t ), static_cast<nv::size_t>( surface->header.num_verts * surface->header.num_frames ) );
172
173        if ( source.tell() != static_cast<nv::size_t>( pos + surface->header.ofs_end ) ) return false;
174
175        return true;
176}
177
178static bool read_md3( md3_t * md3, nv::stream& source )
179{
180        md3->frames   = nullptr;
181        md3->tags     = nullptr;
182        md3->surfaces = nullptr;
183
184        source.read( &md3->header, sizeof(md3_header_t), 1 );
185
186        if ( !check_md3_magic( md3->header.ident ) )        return false;
187        if ( md3->header.num_frames   >  MD3_MAX_FRAMES )   return false;
188        if ( md3->header.num_tags     >  MD3_MAX_TAGS )     return false;
189        if ( md3->header.num_surfaces >  MD3_MAX_SURFACES )
190        {
191                // to always have a safe free
192                md3->header.num_surfaces = 0;
193                return false;
194        }
195
196        md3->frames   = new md3_frame_t  [ md3->header.num_frames ];
197        md3->tags     = new md3_tag_t    [ md3->header.num_tags * md3->header.num_frames ];
198        md3->surfaces = new md3_surface_t[ md3->header.num_surfaces ];
199        nv::raw_zero_n( md3->surfaces, static_cast< nv::size_t >( md3->header.num_surfaces ) );
200
201        source.seek( md3->header.ofs_frames, origin::SET );
202        source.read( md3->frames, sizeof( md3_frame_t ), static_cast<nv::size_t>( md3->header.num_frames ) );
203
204        if ( md3->header.num_tags > 0 )
205        {
206                source.seek( md3->header.ofs_tags, origin::SET );
207                source.read( md3->tags, sizeof( md3_tag_t ), static_cast<nv::size_t>( md3->header.num_tags * md3->header.num_frames ) );
208        }
209
210        source.seek( md3->header.ofs_surfaces, origin::SET );
211        md3->vertices_per_frame = 0;
212
213        for ( sint32 i = 0; i < md3->header.num_surfaces; ++i )
214        {
215                if ( !read_surface( md3->surfaces + i, source ) ) return false;
216                if ( md3->header.num_frames != md3->surfaces[i].header.num_frames ) return false;
217                md3->vertices_per_frame += md3->surfaces[i].header.num_verts;
218        }
219        return true;
220}
221
222static inline vec3 md3_vec3( const md3_vec3_t& v )
223{
224//      return vec3( v.xyz[0], v.xyz[1], v.xyz[2] );
225        return vec3( v.xyz[0], v.xyz[2], v.xyz[1] );
226}
227
228static inline vec2 md3_texcoord( const md3_texcoord_t& v )
229{
230        return vec2( v.st[0], v.st[1] );
231}
232
233static vec3 s_normal_cache[256*256];
234static bool s_normal_ready = false;
235
236md3_loader::md3_loader( bool merge_all )
237        : m_merge_all( merge_all ), m_md3( nullptr )
238{
239        if ( !s_normal_ready )
240        {
241                float pi      = glm::pi<float>();
242                float convert = (2 * pi) / 255.0f;
243                int n = 0;
244                for ( int lat = 0; lat < 256; ++lat )
245                {
246                        float flat    = lat * convert;
247                        float sin_lat = glm::sin( flat );
248                        float cos_lat = glm::cos( flat );
249                        for ( int lng = 0; lng < 256; ++lng, ++n )
250                        {
251                                float flng    = lng * convert;
252                                float sin_lng = glm::sin( flng );
253                                float cos_lng = glm::cos( flng );
254                                s_normal_cache[n].x = cos_lat * sin_lng;
255//                              s_normal_cache[n].y = sin_lat * sin_lng;
256//                              s_normal_cache[n].z = cos_lng;
257                                s_normal_cache[n].z = sin_lat * sin_lng;
258                                s_normal_cache[n].y = cos_lng;
259                        }
260                }
261
262                s_normal_ready = true;
263        }
264}
265
266
267nv::md3_loader::~md3_loader()
268{
269        if (m_md3 != nullptr)
270        {
271                free_md3( (md3_t*)(m_md3) );
272                delete (md3_t*)m_md3;
273        }
274}
275
276bool nv::md3_loader::load( stream& source )
277{
278        m_md3 = (void*)(new md3_t);
279        if ( !read_md3( (md3_t*)m_md3, source ) )
280        {
281                return false;
282        }
283        return true;
284}
285
286nv::key_raw_channel* nv::md3_loader::load_tags( const string_ref& tag )
287{
288        md3_t* md3 = (md3_t*)m_md3;
289        key_raw_channel* result = key_raw_channel::create<md3_key>( (uint32)md3->header.num_frames );
290        // TODO: is this brain damaged in efficiency (loop nest order) or what?
291        for ( sint32 f = 0; f < md3->header.num_frames; ++f )
292        {
293                for ( sint32 i = 0; i < md3->header.num_tags; ++i )
294                {
295                        const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * f];
296                        string_ref rname((char*)(rtag.name));
297                        if (rname == tag)
298                        {
299                                vec3 axisx  ( md3_vec3( rtag.axis[0] ) );
300                                vec3 axisz  ( md3_vec3( rtag.axis[1] ) );
301                                vec3 axisy  ( md3_vec3( rtag.axis[2] ) );
302                                vec3 origin ( md3_vec3( rtag.origin )  );
303                                ((md3_key*)(result->data))[f].tform = transform( origin, quat( mat3( axisx, axisy, axisz ) ) );
304                        }
305                }
306
307        }
308        return result;
309}
310
311struct vtx_md3_pn
312{
313        nv::vec3 position;
314        nv::vec3 normal;
315};
316
317struct vtx_md3_t
318{
319        nv::vec2 texcoord;
320};
321
322mesh_data* nv::md3_loader::release_mesh_data( nv::size_t index )
323{
324        mesh_data* data = new mesh_data;
325        release_mesh_frame( data, -1, (sint32)index );
326        return data;
327}
328
329void nv::md3_loader::release_mesh_frame( mesh_data* data, sint32 frame, sint32 surface )
330{
331        md3_t* md3 = (md3_t*)m_md3;
332        uint32 num_surfaces  = (uint32)md3->header.num_surfaces;
333        uint32 num_verts     = 0;
334        uint32 current_frame = ( frame == -1 ? 0 : (uint32)frame );
335        uint32 frame_count   = ( frame == -1 ? (uint32)md3->header.num_frames : 1 );
336        uint32 current_surf  = ( surface == -1 ? 0 : (uint32)surface );
337        uint32 surf_count    = ( surface == -1 ? (uint32)md3->header.num_surfaces : 1 );
338        uint32 index_count   = 0;
339
340        if ( surface >= 0 )
341        {
342                index_count = (uint32)md3->surfaces[(uint32)surface].header.num_triangles * 3;
343                num_verts   = (uint32)md3->surfaces[(uint32)surface].header.num_verts;
344        }
345        else
346                for ( uint32 i = 0; i < num_surfaces; ++i )
347                {
348                        index_count += (uint32)md3->surfaces[i].header.num_triangles * 3;
349                        num_verts   += (uint32)md3->surfaces[i].header.num_verts;
350                }
351
352        mesh_raw_channel* mc_pn = mesh_raw_channel::create< vtx_md3_pn >( num_verts * frame_count );
353        mesh_raw_channel* mc_t  = mesh_raw_channel::create< vtx_md3_t >( num_verts );
354        mesh_raw_channel* ic = mesh_raw_channel::create_index< uint16 >( index_count );
355        vtx_md3_pn* vtx_pn = (vtx_md3_pn*)mc_pn->data;
356        vtx_md3_t*  vtx_t  = (vtx_md3_t*) mc_t->data;
357        uint16*     icp    = (uint16*)ic->data;
358
359        uint32 index  = 0;
360        uint32 iindex = 0;
361        sint32 index_base = 0;
362
363        while ( surf_count > 0 )
364        {
365                const md3_surface_t& sface  = md3->surfaces[ current_surf ];
366                const uint32         vcount = static_cast< uint32 >( sface.header.num_verts );
367                const uint32         tcount = static_cast< uint32 >( sface.header.num_triangles );
368
369                for (uint32 j = 0; j < vcount; ++j )
370                {
371                        vtx_t[index++].texcoord = md3_texcoord( sface.st[j] );
372                }
373
374                for (size_t j = 0; j < tcount; ++j )
375                {
376                        const md3_triangle_t& t = sface.triangles[j];
377                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[0] );
378                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[1] );
379                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[2] );
380                }
381                index_base += sface.header.num_verts;
382                ++current_surf;
383                --surf_count;
384        }
385
386        index = 0;
387        while ( frame_count > 0 )
388        {
389                current_surf  = ( surface == -1 ? 0 : (uint32)surface );
390                surf_count    = ( surface == -1 ? (uint32)md3->header.num_surfaces : 1 );
391
392                while ( surf_count > 0 )
393                {
394                        md3_surface_t& sface  = md3->surfaces[current_surf];
395                        uint32         vcount = (uint32)sface.header.num_verts;
396                        uint32         offset = vcount * current_frame;
397                        uint32         limit  = vcount + offset;
398                        for (uint32 j = offset; j < limit; ++j )
399                        {
400                                md3_vertex_t& v = sface.vertices[j];
401                                vtx_pn[index].position = vec3( v.x * MD3_XYZ_SCALE, v.z * MD3_XYZ_SCALE, v.y * MD3_XYZ_SCALE );
402                                vtx_pn[index].normal   = s_normal_cache[ v.normal ];
403                                index++;
404                        }
405                        ++current_surf;
406                        --surf_count;
407                }
408                ++current_frame;
409                --frame_count;
410        }
411
412        data->set_name( (char*)md3->header.name );
413        data->add_channel( mc_pn );
414        data->add_channel( mc_t );
415        data->add_channel( ic );
416}
417
418mesh_nodes_data* nv::md3_loader::release_mesh_nodes_data( nv::size_t )
419{
420        md3_t* md3 = (md3_t*)m_md3;
421        uint32 node_count = (uint32)md3->header.num_tags;
422        if ( node_count == 0 ) return nullptr;
423        mesh_node_data* nodes = new mesh_node_data[ node_count ];
424        for ( uint32 i = 0; i < node_count; ++i )
425        {
426                const md3_tag_t& rtag = md3->tags[i];
427                string_ref name( (char*)(rtag.name) );
428
429                nodes[i].transform = mat4();
430                nodes[i].name      = name.to_string();
431                nodes[i].parent_id = -1;
432                nodes[i].target_id = -1;
433                nodes[i].data      = new key_data;
434       
435                key_raw_channel* keys = load_tags( name );
436                nodes[i].data->add_channel( keys );
437        }
438        return new mesh_nodes_data( "tags", node_count, nodes );
439}
440
441mesh_data_pack* nv::md3_loader::release_mesh_data_pack()
442{
443        md3_t* md3 = (md3_t*)m_md3;
444        uint32 count = 1;
445        mesh_data* data = nullptr;
446        if ( m_merge_all )
447        {
448                data = new mesh_data[1];
449                release_mesh_frame( &data[0], -1, -1 );
450                data[0].set_name( (char*)md3->header.name );
451        }
452        else
453        {
454                count = (uint32)md3->header.num_surfaces;
455                data = new mesh_data[ count ];
456                for ( uint32 i = 0; i < count; ++i )
457                {
458                        release_mesh_frame( &data[i], -1, (sint32)i );
459                        data[i].set_name( (char*)md3->surfaces[i].header.name );
460                }
461        }
462        return new mesh_data_pack( count, data, release_mesh_nodes_data() );
463}
464
465nv::size_t md3_loader::get_max_frames() const
466{
467        return static_cast< size_t >( ((md3_t*)m_md3)->header.num_frames );
468}
Note: See TracBrowser for help on using the repository browser.