source: trunk/src/formats/md2_loader.cc @ 200

Last change on this file since 200 was 200, checked in by epyon, 12 years ago
  • compilation and warning fixes
File size: 10.1 KB
RevLine 
[189]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/md2_loader.hh"
8
9#include <glm/gtc/constants.hpp>
10#include "nv/logging.hh"
11#include <cstring>
12
13using namespace nv;
14
15// based on http://tfc.duke.free.fr/coding/md2-specs-en.html
16
17// assuming low-endian
18#define MD2_MAX_FRAMES    512
19#define MD2_MAX_SKINS     32
20#define MD2_MAX_VERTS     2048
21#define MD2_MAX_TRIANGLES 4096
22#define MD2_MAX_TEXCOORDS 2048
23#define MD2_NORMAL_COUNT  162
24
25typedef float md2_vec3_t[3];
26
27static const md2_vec3_t md2_normal_table[MD2_NORMAL_COUNT] = {
28#include "src/formats/md2_normals.inc"
29};
30
31struct md2_header_t
32{
33        char magic[4];
34        int version;
35
36        int skinwidth;
37        int skinheight;
38
39        int framesize;
40
41        int num_skins;
42        int num_vertices;
43        int num_st;
44        int num_tris;
45        int num_glcmds;
46        int num_frames;
47
48        int offset_skins;
49        int offset_st;
50        int offset_tris;
51        int offset_frames;
52        int offset_glcmds;
53        int offset_end;
54};
55
56struct md2_skin_t
57{
58        char name[64];
59};
60
61struct md2_texcoord_t
62{
63        short s;
64        short t;
65};
66
67struct md2_triangle_t
68{
69        unsigned short vertex[3];
70        unsigned short st[3];
71};
72
73struct md2_vertex_t
74{
[198]75        uint8 v[3];
76        uint8 n;
[189]77};
78
79struct md2_frame_t
80{
81        md2_vec3_t scale;
82        md2_vec3_t translate;
83        char name[16];
84        md2_vertex_t *vertices;
85};
86
87struct md2_glcmd_t
88{
89        float s;
90        float t;
91        int index;
92};
93
94struct md2_t
95{
96        md2_header_t    header;
97        md2_skin_t*     skins;
98        md2_texcoord_t* texcoords;
99        md2_triangle_t* triangles;
100        md2_frame_t*    frames;
101        int*            glcmds;
102};
103
104static bool check_md2_magic( char* magic )
105{
106        return magic[0] == 'I' && magic[1] == 'D' && magic[2] == 'P' && magic[3] == '2';
107}
108
109static void free_md2_frame( md2_frame_t* frame )
110{
111        delete[] frame->vertices;
112}
113
114static void free_md2( md2_t* md2 )
115{
116        delete[] md2->skins;
117        delete[] md2->texcoords;
118        delete[] md2->triangles;
119        delete[] md2->glcmds;
120        for ( int i = 0; i < md2->header.num_frames; ++i )
121        {
122                free_md2_frame( &(md2->frames[i]) );
123        }
124        delete[] md2->frames;
125}
126
[198]127static bool read_md2_frame( md2_frame_t* frame, unsigned vcount, nv::stream& source )
[189]128{
129        frame->vertices = new md2_vertex_t[ vcount ];
130        source.read( frame->scale,     sizeof(md2_vec3_t), 1 );
131        source.read( frame->translate, sizeof(md2_vec3_t), 1 );
132        source.read( frame->name,      sizeof(char), 16 );
133        source.read( frame->vertices,  sizeof(md2_vertex_t), vcount );
134        return true;
135}
136
137static bool read_md2( md2_t* md2, nv::stream& source )
138{
139        md2->frames     = nullptr;
140        md2->skins      = nullptr;
141        md2->texcoords  = nullptr;
142        md2->triangles  = nullptr;
143        md2->glcmds     = nullptr;
144
145        source.read( &(md2->header), sizeof(md2_header_t), 1 );
146
147        if ( !check_md2_magic( md2->header.magic )       ||
148                md2->header.num_skins    > MD2_MAX_SKINS     ||
149                md2->header.num_vertices > MD2_MAX_VERTS     ||
150                md2->header.num_st       > MD2_MAX_TEXCOORDS ||
151                md2->header.num_tris     > MD2_MAX_TRIANGLES ||
152                md2->header.num_frames   > MD2_MAX_FRAMES )
153        {
154                return false;
155        }
156
157        NV_LOG( LOG_INFO, "num_skins    = " << md2->header.num_skins );
158        NV_LOG( LOG_INFO, "num_vertices = " << md2->header.num_vertices );
159        NV_LOG( LOG_INFO, "num_st       = " << md2->header.num_st );
160        NV_LOG( LOG_INFO, "num_tris     = " << md2->header.num_tris );
161        NV_LOG( LOG_INFO, "num_frames   = " << md2->header.num_frames );
162
163
164        md2->skins      = new md2_skin_t    [ md2->header.num_skins ];
165        md2->texcoords  = new md2_texcoord_t[ md2->header.num_st ];
166        md2->triangles  = new md2_triangle_t[ md2->header.num_tris ];
167        md2->glcmds     = new int           [ md2->header.num_glcmds ];
168       
169        source.seek( md2->header.offset_skins, origin::SET );
[198]170        source.read( md2->skins, sizeof(md2_skin_t), static_cast<size_t>( md2->header.num_skins ) );
[189]171
172        source.seek( md2->header.offset_st, origin::SET );
[198]173        source.read( md2->texcoords, sizeof(md2_texcoord_t), static_cast<size_t>( md2->header.num_st ) );
[189]174
175        source.seek( md2->header.offset_tris, origin::SET );
[198]176        source.read( md2->triangles, sizeof(md2_triangle_t), static_cast<size_t>( md2->header.num_tris ) );
[189]177
178        source.seek( md2->header.offset_glcmds, origin::SET);
[198]179        source.read( md2->glcmds, sizeof(int), static_cast<size_t>( md2->header.num_glcmds ) );
[189]180
181        md2->frames    = new md2_frame_t   [ md2->header.num_frames ];
182        source.seek( md2->header.offset_frames, origin::SET );
183        for ( int i = 0; i < md2->header.num_frames; ++i )
184        {
[198]185                if (!read_md2_frame( &(md2->frames[i]), static_cast<unsigned>( md2->header.num_vertices ), source ) ) return false;
[189]186        }
187
188        return true;
189}
190
191static inline vec3 md2_vec3( const md2_vec3_t& v )
192{
193        //      return vec3( v[0], v[1], v[2] );
194        return vec3( v[0], v[2], v[1] );
195}
196
[198]197static inline vec3 md2_normal( uint8 normal )
[189]198{
199        return md2_vec3( md2_normal_table[normal] );
200}
201
202static vec3 s_md2_normal_cache[MD2_NORMAL_COUNT];
203static bool s_md2_normal_ready = false;
204
205md2_loader::md2_loader() : m_md2( nullptr ), m_size( 0 )
206{
207        if ( !s_md2_normal_ready )
208        {
209                for ( int i = 0; i < MD2_NORMAL_COUNT; ++i )
210                {
211                        s_md2_normal_cache[i].x = md2_normal_table[i][0];
212//                      s_md2_normal_cache[i].y = md2_normal_table[i][1];
213//                      s_md2_normal_cache[i].z = md2_normal_table[i][2];
214                        s_md2_normal_cache[i].y = md2_normal_table[i][2];
215                        s_md2_normal_cache[i].z = md2_normal_table[i][1];
216                }
217        }
218}
219
220
221md2_loader::~md2_loader()
222{
223        if (m_md2 != nullptr)
224        {
225                free_md2( (md2_t*)(m_md2) );
226                delete (md2_t*)m_md2;
227        }
228}
229
230bool md2_loader::load( stream& source )
231{
232        m_size = 0;
233        m_md2 = (void*)(new md2_t);
234        if ( !read_md2( (md2_t*)m_md2, source ) )
235        {
236                return false;
237        }
238        reindex();
239        m_size = m_new_indexes.size();
240        return true;
241}
242
243mesh* nv::md2_loader::release_mesh()
244{
245        return get_frame( 0 );
246}
247
248mesh* nv::md2_loader::get_frame( sint32 frame )
249{
250        md2_t* md2 = (md2_t*)m_md2;
251        if ( md2 == nullptr || frame >= md2->header.num_frames ) return nullptr;
252        mesh* m = new mesh();
253
254        vertex_attribute< vec3 >*   position = m->add_attribute<vec3>("nv_position");
255        vertex_attribute< vec3 >*   normal   = m->add_attribute<vec3>("nv_normal");
256        vertex_attribute< vec2 >*   texcoord = m->add_attribute<vec2>("nv_texcoord");
257        vertex_attribute< uint16 >* indices  = m->add_indices<uint16>();
258
259        load_positions( position->get(), frame );
260        load_normals( normal->get(), frame );
261
262        load_texcoords( texcoord->get() );
263        load_indicies( indices->get() );
264
265        m_size = indices->get().size();
266        return m;
267}
268
[198]269size_t md2_loader::get_max_frames() const
[189]270{
[198]271        return static_cast< size_t >( ((md2_t*)m_md2)->header.num_frames );
[189]272}
273
274void md2_loader::load_positions( std::vector<vec3>& p, sint32 frame /*=-1*/ )
275{
276        md2_t* md2 = (md2_t*)m_md2;
[198]277        size_t num_frames = static_cast< size_t >( md2->header.num_frames );
278        size_t num_verts  =     m_new_vindexes.size();
[189]279        p.clear();
[198]280        size_t current_frame = ( frame == -1 ? 0 : static_cast< size_t >( frame ) );
281        size_t frame_count   = ( frame == -1 ? num_frames : 1 );
[189]282
283        p.reserve( num_verts * frame_count );
284
285        while ( frame_count > 0 )
286        {
[198]287                const md2_frame_t& cframe = md2->frames[current_frame];
288                NV_LOG( LOG_INFO, "FrameID = " << cframe.name );
[189]289
[198]290                vec3 scale     = md2_vec3( cframe.scale );
291                vec3 translate = md2_vec3( cframe.translate );
[189]292
[198]293                for (size_t i = 0; i < num_verts; ++i )
[189]294                {
[198]295                        const md2_vertex_t& v = cframe.vertices[ m_new_vindexes[ i ] ];
[189]296                        p.push_back( vec3( v.v[0], v.v[2], v.v[1] ) * scale + translate );
297                }
298                ++current_frame;
299                --frame_count;
300        }
301}
302
303void md2_loader::load_normals( std::vector<vec3>& n, sint32 frame /*=-1*/ )
304{
305        md2_t* md2 = (md2_t*)m_md2;
[198]306        size_t num_frames = static_cast< size_t >( md2->header.num_frames );
307        size_t num_verts  =     m_new_vindexes.size();
[189]308        n.clear();
[198]309        size_t current_frame = ( frame == -1 ? 0 : static_cast< size_t>( frame ) );
310        size_t frame_count   = ( frame == -1 ? num_frames : 1 );
[189]311
312        n.reserve( num_verts * frame_count );
313
314        while ( frame_count > 0 )
315        {
[198]316                const md2_frame_t& cframe = md2->frames[current_frame];
[189]317
[198]318                for (size_t i = 0; i < num_verts; ++i )
[189]319                {
[198]320                        const md2_vertex_t& v = cframe.vertices[ m_new_vindexes[ i ] ];
[189]321                        n.push_back( s_md2_normal_cache[ v.n ] );
322                }
323                ++current_frame;
324                --frame_count;
325        }
326}
327
328void md2_loader::load_texcoords( std::vector<vec2>& t )
329{
330        md2_t* md2 = (md2_t*)m_md2;
[198]331        size_t num_verts  = m_new_vindexes.size();
[189]332
333        t.clear();
334        t.reserve( num_verts );
335
336        vec2 scale( 1.0f / (float) md2->header.skinwidth, 1.0f / (float) md2->header.skinheight );
337
[198]338        for (size_t i = 0; i < num_verts; ++i )
[189]339        {
340                const md2_texcoord_t& st = md2->texcoords[ m_new_tindexes[ i ] ];
341                t.push_back( scale * vec2( st.s, st.t ) );
342        }
343
344}
345
346void md2_loader::load_indicies( std::vector<uint16>& idx )
347{
348        idx.assign( m_new_indexes.begin(), m_new_indexes.end() );
349}
350
351void nv::md2_loader::reindex()
352{
353        md2_t* md2 = (md2_t*)m_md2;
[198]354        uint32 num_indexes = static_cast< uint32 >( md2->header.num_tris * 3 );
[189]355
356        uint32 stats_reuse      = 0;
357        uint32 stats_collision  = 0;
358
359        std::vector< sint32 > index_translation( md2->header.num_vertices, -1 );
360
361        m_new_indexes.clear();
362        m_new_indexes.reserve( num_indexes );
363        m_new_vindexes.reserve( num_indexes );
364        m_new_tindexes.reserve( num_indexes );
365
366        uint16 index_count = 0;
367
368        for ( int i = 0; i < md2->header.num_tris; ++i )
369        {
370                const md2_triangle_t& t = md2->triangles[i];
371                for ( int j = 0; j < 3; ++j )
372                {
[198]373                        uint16 index  = t.vertex[j];
374                        uint16 tindex = t.st[j];
[189]375
376                        if ( index_translation[ index ] != -1 )
377                        {
[198]378                                uint16 prev = static_cast< uint16 >( index_translation[ index ] );
[189]379                                if ( m_new_tindexes[ prev ] == tindex )
380                                {
381                                        m_new_indexes.push_back( prev );
382                                        stats_reuse++;
383                                        continue;
384                                }
385                        }
386                       
387                        m_new_vindexes.push_back( index );
388                        m_new_tindexes.push_back( tindex );
389                        m_new_indexes.push_back( index_count );
390                        if ( index_translation[ index ] == -1 )
391                        {
392                                index_translation[ index ] = index_count;
393                        }
394                        else
395                        {
396                                stats_collision++;
397                        }
398                        index_count++;
399                }
400        }
401
402        NV_LOG( LOG_INFO, "New vertex count = " << m_new_vindexes.size() );
403        NV_LOG( LOG_INFO, "Collisions       = " << stats_collision );
404        NV_LOG( LOG_INFO, "Reuse count      = " << stats_reuse );
405}
Note: See TracBrowser for help on using the repository browser.