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