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

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