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

Last change on this file since 197 was 189, checked in by epyon, 12 years ago
  • formats - full md2 implementation, including re-indexing and frame animation
  • tests/md2_test - with Mancubi For Added Fun (tm)
File size: 14.8 KB
Line 
1// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/formats/md3_loader.hh"
8
9#include <glm/gtc/constants.hpp>
10#include <glm/gtx/string_cast.hpp>
11#include "nv/logging.hh"
12#include <cstring>
13
14using namespace nv;
15
16// based on http://www.icculus.org/~phaethon/q3/formats/md3format.html#Surface
17
18// assuming low-endian
19#define MD3_MAGIC         "IDP3"
20#define MD3_MAX_FRAMES    1024
21#define MD3_MAX_TAGS      16
22#define MD3_MAX_SURFACES  32
23#define MD3_MAX_SHADERS   256
24#define MD3_MAX_VERTS     4096
25#define MD3_MAX_TRIANGLES 8192
26#define MD3_XYZ_SCALE     (1.0f/64.0f)
27
28struct md3_vec3_t
29{
30        float xyz[3];
31};
32
33struct md3_header_t
34{
35        char   ident[4]; // IDP3
36        sint32 version;  // 15
37        uint8  name[64]; // path name
38        sint32 flags;
39        sint32 num_frames;     // Number of Frame objects, with a maximum of MD3_MAX_FRAMES. Current value of MD3_MAX_FRAMES is 1024.
40        sint32 num_tags;       // Number of Tag objects, with a maximum of MD3_MAX_TAGS. Current value of MD3_MAX_TAGS is 16.
41        sint32 num_surfaces;   // Number of Surface objects, with a maximum of MD3_MAX_SURFACES. Current value of MD3_MAX_SURFACES is 32.
42        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.
43        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.
44        sint32 ofs_tags;       // Relative offset from start of MD3 where Tag objects start. Similarly written sequentially.
45        sint32 ofs_surfaces;   // Relative offset from start of MD3 where Surface objects start. Again, written sequentially.
46        sint32 ofs_eof;        // Relative offset from start of MD3 to the end of the MD3 object. Note there is no offset for Skin objects.
47};
48
49struct md3_frame_t
50{
51        md3_vec3_t min_bounds;
52        md3_vec3_t max_bounds;
53        md3_vec3_t local_origin;
54        float      radius;
55        uint8      name[16];
56};
57
58struct md3_tag_t
59{
60        uint8      name[64];
61        md3_vec3_t origin;
62        md3_vec3_t axis[3];
63};
64
65struct md3_surface_header_t
66{
67        char   ident[4]; // IDP3
68        uint8  name[64]; // path name
69        sint32 flags;
70        sint32 num_frames;
71        sint32 num_shaders;
72        sint32 num_verts;
73        sint32 num_triangles;
74        sint32 ofs_triangles;
75        sint32 ofs_shaders;
76        sint32 ofs_st;
77        sint32 ofs_xyznormal;
78        sint32 ofs_end;
79};
80
81struct md3_shader_t
82{
83        uint8  name[64];
84        sint32 shader_index;
85};
86
87struct md3_triangle_t
88{
89        sint32 indexes[3];
90};
91
92struct md3_texcoord_t
93{
94        float  st[2];
95};
96
97struct md3_vertex_t
98{
99        sint16 x;
100        sint16 y;
101        sint16 z;
102        uint16 normal;
103};
104
105struct md3_surface_t
106{
107        md3_surface_header_t header;
108        md3_shader_t*        shaders;
109        md3_triangle_t*      triangles;
110        md3_texcoord_t*      st;
111        md3_vertex_t*        vertices;
112};
113
114struct md3_t
115{
116        md3_header_t   header;
117        md3_frame_t*   frames;
118        md3_tag_t*     tags;
119        md3_surface_t* surfaces;
120        // extra information (not in md3 file)
121        sint32         vertices_per_frame;
122};
123
124static bool check_md3_magic( char* magic )
125{
126        return magic[0] == 'I' && magic[1] == 'D' && magic[2] == 'P' && magic[3] == '3';
127}
128
129static void free_md3_surface( md3_surface_t * surface )
130{
131        delete[] surface->shaders;
132        delete[] surface->triangles;
133        delete[] surface->st;
134        delete[] surface->vertices;
135}
136
137static void free_md3( md3_t * md3 )
138{
139        sint32 count = md3->header.num_surfaces;
140        for ( sint32 i = 0; i < count; ++i )
141        {
142                free_md3_surface( &md3->surfaces[i] );
143        }
144        delete[] md3->frames;
145        delete[] md3->tags;
146        delete[] md3->surfaces;
147}
148
149static bool read_surface( md3_surface_t * surface, nv::stream& source )
150{
151        sint32 pos = source.tell();
152        source.read( &surface->header, sizeof(md3_surface_header_t), 1 );
153
154        if ( !check_md3_magic( surface->header.ident ) )          return false;
155        if ( surface->header.num_frames    >  MD3_MAX_FRAMES )    return false;
156        if ( surface->header.num_shaders   >  MD3_MAX_SHADERS )   return false;
157        if ( surface->header.num_verts     >  MD3_MAX_VERTS )     return false;
158        if ( surface->header.num_triangles >  MD3_MAX_TRIANGLES ) return false;
159
160        surface->shaders   = new md3_shader_t  [ surface->header.num_shaders ];
161        surface->vertices  = new md3_vertex_t  [ surface->header.num_verts * surface->header.num_frames ];
162        surface->st        = new md3_texcoord_t[ surface->header.num_verts ];
163        surface->triangles = new md3_triangle_t[ surface->header.num_triangles ];
164
165        source.seek( pos + surface->header.ofs_shaders, origin::SET );
166        source.read( surface->shaders, sizeof( md3_shader_t ), surface->header.num_shaders );
167
168        source.seek( pos + surface->header.ofs_triangles, origin::SET );
169        source.read( surface->triangles, sizeof( md3_triangle_t ), surface->header.num_triangles );
170
171        source.seek( pos + surface->header.ofs_st, origin::SET );
172        source.read( surface->st, sizeof( md3_texcoord_t ), surface->header.num_verts );
173
174        source.seek( pos + surface->header.ofs_xyznormal, origin::SET );
175        source.read( surface->vertices, sizeof( md3_vertex_t ), surface->header.num_verts * surface->header.num_frames );
176
177        if ( source.tell() != static_cast<std::size_t>( pos + surface->header.ofs_end ) ) return false;
178
179        return true;
180}
181
182static bool read_md3( md3_t * md3, nv::stream& source )
183{
184        md3->frames   = nullptr;
185        md3->tags     = nullptr;
186        md3->surfaces = nullptr;
187
188        source.read( &md3->header, sizeof(md3_header_t), 1 );
189
190        if ( !check_md3_magic( md3->header.ident ) )        return false;
191        if ( md3->header.num_frames   >  MD3_MAX_FRAMES )   return false;
192        if ( md3->header.num_tags     >  MD3_MAX_TAGS )     return false;
193        if ( md3->header.num_surfaces >  MD3_MAX_SURFACES )
194        {
195                // to always have a safe free
196                md3->header.num_surfaces = 0;
197                return false;
198        }
199
200        md3->frames   = new md3_frame_t  [ md3->header.num_frames ];
201        md3->tags     = new md3_tag_t    [ md3->header.num_tags * md3->header.num_frames ];
202        md3->surfaces = new md3_surface_t[ md3->header.num_surfaces ];
203        std::memset( md3->surfaces, 0, md3->header.num_surfaces * sizeof(md3_surface_t) );
204
205        source.seek( md3->header.ofs_frames, origin::SET );
206        source.read( md3->frames, sizeof( md3_frame_t ), md3->header.num_frames );
207
208        source.seek( md3->header.ofs_tags, origin::SET );
209        source.read( md3->tags, sizeof( md3_tag_t ), md3->header.num_tags * md3->header.num_frames );
210
211        source.seek( md3->header.ofs_surfaces, origin::SET );
212        md3->vertices_per_frame = 0;
213
214        for ( sint32 i = 0; i < md3->header.num_surfaces; ++i )
215        {
216                if ( !read_surface( md3->surfaces + i, source ) ) return false;
217                if ( md3->header.num_frames != md3->surfaces[i].header.num_frames ) return false;
218                md3->vertices_per_frame += md3->surfaces[i].header.num_verts;
219        }
220        return true;
221}
222
223static inline vec3 md3_vec3( const md3_vec3_t& v )
224{
225//      return vec3( v.xyz[0], v.xyz[1], v.xyz[2] );
226        return vec3( v.xyz[0], v.xyz[2], v.xyz[1] );
227}
228
229static inline vec2 md3_texcoord( const md3_texcoord_t& v )
230{
231        return vec2( v.st[0], v.st[1] );
232}
233
234static vec3 s_normal_cache[256*256];
235static bool s_normal_ready = false;
236
237md3_loader::md3_loader()
238        : m_md3( nullptr ), m_size( 0 )
239{
240        if ( !s_normal_ready )
241        {
242                float pi      = glm::pi<float>();
243                float convert = (2 * pi) / 255.0f;
244                int n = 0;
245                for ( int lat = 0; lat < 256; ++lat )
246                {
247                        float flat    = lat * convert;
248                        float sin_lat = glm::sin( flat );
249                        float cos_lat = glm::cos( flat );
250                        for ( int lng = 0; lng < 256; ++lng, ++n )
251                        {
252                                float flng    = lng * convert;
253                                float sin_lng = glm::sin( flng );
254                                float cos_lng = glm::cos( flng );
255                                s_normal_cache[n].x = cos_lat * sin_lng;
256//                              s_normal_cache[n].y = sin_lat * sin_lng;
257//                              s_normal_cache[n].z = cos_lng;
258                                s_normal_cache[n].z = sin_lat * sin_lng;
259                                s_normal_cache[n].y = cos_lng;
260                        }
261                }
262
263                s_normal_ready = true;
264        }
265}
266
267
268nv::md3_loader::~md3_loader()
269{
270        if (m_md3 != nullptr)
271        {
272                free_md3( (md3_t*)(m_md3) );
273                delete (md3_t*)m_md3;
274        }
275}
276
277bool nv::md3_loader::load( stream& source )
278{
279        m_tags.clear();
280        m_size = 0;
281
282        m_md3 = (void*)(new md3_t);
283        if ( !read_md3( (md3_t*)m_md3, source ) )
284        {
285                return false;
286        }
287        return true;
288}
289
290mesh* nv::md3_loader::release_mesh()
291{
292        return get_frame( 0 );
293}
294
295mesh* nv::md3_loader::get_frame( sint32 frame )
296{
297        mesh* m = new mesh();
298        md3_t* md3 = (md3_t*)m_md3;
299
300        NV_LOG( LOG_INFO, "Tags:" );
301        for ( sint32 i = 0; i < md3->header.num_tags; ++i )
302        {
303                const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * frame];
304
305                md3_tag& tag   = m_tags[ (char*)(rtag.name) ];
306                tag.name       = (char*)(rtag.name);
307                vec4 axisx     = vec4( md3_vec3( rtag.axis[0] ), 0.0 );
308                vec4 axisz     = vec4( md3_vec3( rtag.axis[1] ), 0.0 );
309                vec4 axisy     = vec4( md3_vec3( rtag.axis[2] ), 0.0 );
310                vec4 origin    = vec4( md3_vec3( rtag.origin ),  1.0 );
311                tag.transform  = glm::mat4( axisx, axisy, axisz, origin );
312                NV_LOG( LOG_INFO, "Tag " << tag.name << " found" );
313        }
314
315        vertex_attribute< vec3 >* position = m->add_attribute<vec3>("nv_position");
316        vertex_attribute< vec3 >* normal   = m->add_attribute<vec3>("nv_normal");
317        vertex_attribute< vec2 >* texcoord = m->add_attribute<vec2>("nv_texcoord");
318        vertex_attribute< uint16 >* indices  = m->add_indices<uint16>();
319
320        load_positions( position->get(), frame );
321        load_normals( normal->get(), frame );
322
323        load_texcoords( texcoord->get() );
324        load_indicies( indices->get() );
325
326        m_size = indices->get().size();
327        return m;
328}
329
330void nv::md3_loader::load_tags( std::vector<mat4>& t, const std::string& tag )
331{
332        md3_t* md3 = (md3_t*)m_md3;
333        t.clear();
334        for ( sint32 f = 0; f < md3->header.num_frames; ++f )
335        {
336                for ( sint32 i = 0; i < md3->header.num_tags; ++i )
337                {
338                        const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * f];
339                        std::string rname((char*)(rtag.name));
340                        if (rname == tag)
341                        {
342                                vec4 axisx     = vec4( md3_vec3( rtag.axis[0] ), 0.0 );
343                                vec4 axisz     = vec4( md3_vec3( rtag.axis[1] ), 0.0 );
344                                vec4 axisy     = vec4( md3_vec3( rtag.axis[2] ), 0.0 );
345                                vec4 origin    = vec4( md3_vec3( rtag.origin ),  1.0 );
346                                t.emplace_back( axisx, axisy, axisz, origin );
347                        }
348                }
349
350        }
351}
352
353sint32 md3_loader::get_max_frames() const
354{
355        return ((md3_t*)m_md3)->header.num_frames;
356}
357
358void md3_loader::load_tag_names( std::vector< std::string >& tags )
359{
360        tags.clear();
361        md3_t* md3 = (md3_t*)m_md3;
362        for ( sint32 i = 0; i < md3->header.num_tags; ++i )
363        {
364                const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags];
365                tags.push_back( (char*)(rtag.name) );
366        }
367}
368
369mat4 md3_loader::get_tag( sint32 frame, const std::string& name ) const
370{
371        md3_t* md3 = (md3_t*)m_md3;
372        for ( sint32 i = 0; i < md3->header.num_tags; ++i )
373        {
374                const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * frame];
375                std::string rname((char*)(rtag.name));
376                if (rname == name)
377                {
378                        vec4 axisx     = vec4( md3_vec3( rtag.axis[0] ), 0.0 );
379                        vec4 axisz     = vec4( md3_vec3( rtag.axis[1] ), 0.0 );
380                        vec4 axisy     = vec4( md3_vec3( rtag.axis[2] ), 0.0 );
381                        vec4 origin    = vec4( md3_vec3( rtag.origin ),  1.0 );
382                        return glm::mat4( axisx, axisy, axisz, origin );
383                }
384        }
385        return glm::mat4();
386}
387
388const md3_tag* md3_loader::get_tag( const std::string& name ) const
389{
390        auto it = m_tags.find( name );
391        if ( it == m_tags.end() ) return nullptr;
392        return &(it->second);
393}
394
395void md3_loader::load_positions( std::vector<vec3>& p, sint32 frame /*=-1*/ )
396{
397        md3_t* md3 = (md3_t*)m_md3;
398        sint32 num_surfaces = md3->header.num_surfaces;
399        p.clear();
400        sint32 current_frame = ( frame == -1 ? 0 : frame );
401        sint32 frame_count   = ( frame == -1 ? md3->header.num_frames : 1 );
402
403        p.reserve( md3->vertices_per_frame * frame_count );
404
405        while ( frame_count > 0 )
406        {
407                for ( sint32 i = 0; i < num_surfaces; ++i )
408                {
409                        md3_surface_t& surface = md3->surfaces[i];
410                        sint32         vcount  = surface.header.num_verts;
411                        sint32         offset  = vcount * current_frame;
412                        sint32         limit   = vcount + offset;
413                        for (sint32 j = offset; j < limit; ++j )
414                        {
415                                md3_vertex_t& v = surface.vertices[j];
416                                p.push_back( vec3( v.x * MD3_XYZ_SCALE, v.z * MD3_XYZ_SCALE, v.y * MD3_XYZ_SCALE ) );
417                        }
418                }
419                ++current_frame;
420                --frame_count;
421        }
422}
423
424void md3_loader::load_normals( std::vector<vec3>& n, sint32 frame /*=-1*/ )
425{
426        md3_t* md3 = (md3_t*)m_md3;
427        sint32 num_surfaces = md3->header.num_surfaces;
428        n.clear();
429        sint32 current_frame = ( frame == -1 ? 0 : frame );
430        sint32 frame_count   = ( frame == -1 ? md3->header.num_frames : 1 );
431
432        n.reserve( md3->vertices_per_frame * frame_count );
433
434        while ( frame_count > 0 )
435        {
436                for ( sint32 i = 0; i < num_surfaces; ++i )
437                {
438                        md3_surface_t& surface = md3->surfaces[i];
439                        sint32         vcount  = surface.header.num_verts;
440                        sint32         offset  = vcount * current_frame;
441                        sint32         limit   = vcount + offset;
442                        for (sint32 j = offset; j < limit; ++j )
443                        {
444                                n.push_back( s_normal_cache[ surface.vertices[j].normal ] );
445                        }
446                }
447                ++current_frame;
448                --frame_count;
449        }
450}
451
452void md3_loader::load_texcoords( std::vector<vec2>& t )
453{
454        md3_t* md3 = (md3_t*)m_md3;
455        sint32 num_surfaces = md3->header.num_surfaces;
456        t.clear();
457        for ( sint32 i = 0; i < num_surfaces; ++i )
458        {
459                const md3_surface_t& surface = md3->surfaces[i];
460                const sint32         vcount  = surface.header.num_verts;
461                t.reserve( t.size() + vcount );
462                for (sint32 j = 0; j < vcount; ++j )
463                {
464                        t.push_back( md3_texcoord( surface.st[j] ) );
465                }
466        }
467}
468
469void md3_loader::load_indicies( std::vector<uint16>& idx )
470{
471        md3_t* md3 = (md3_t*)m_md3;
472        sint32 num_surfaces = md3->header.num_surfaces;
473        idx.clear();
474        sint32 index_base = 0;
475        for ( sint32 i = 0; i < num_surfaces; ++i )
476        {
477                const md3_surface_t& surface = md3->surfaces[i];
478                const sint32         tcount  = surface.header.num_triangles;
479
480                idx.reserve( idx.size() + tcount * 3 );
481                for (sint32 j = 0; j < tcount; ++j )
482                {
483                        const md3_triangle_t& t = surface.triangles[j];
484                        idx.push_back( static_cast< uint16 >( index_base + t.indexes[0] ) );
485                        idx.push_back( static_cast< uint16 >( index_base + t.indexes[1] ) );
486                        idx.push_back( static_cast< uint16 >( index_base + t.indexes[2] ) );
487                }
488
489                index_base += surface.header.num_verts;
490        }
491
492}
493
494keyframed_mesh_data::keyframed_mesh_data( keyframed_loader* loader )
495{
496        loader->load_positions( m_positions );
497        loader->load_normals( m_normals );
498        loader->load_texcoords( m_texcoords );
499        loader->load_indicies( m_indices );
500
501        std::vector< std::string > names;
502
503        md3_loader* md3loader = dynamic_cast< md3_loader* >( loader );
504        if ( md3loader != nullptr )
505        {
506                md3loader->load_tag_names( names );
507                for ( auto& name : names )
508                {
509                        md3loader->load_tags( m_tags[ name ], name );
510                }
511        }
512
513        m_frames = loader->get_max_frames();
514}
515
Note: See TracBrowser for help on using the repository browser.