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

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