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

Last change on this file since 248 was 240, checked in by epyon, 11 years ago
  • multiple mesh per file interface for all mesh loaders added
  • multiple mesh per file obj and md5 loader support added
File size: 9.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 "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{
75        uint8 v[3];
76        uint8 n;
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
127static bool read_md2_frame( md2_frame_t* frame, unsigned vcount, nv::stream& source )
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 );
170        source.read( md2->skins, sizeof(md2_skin_t), static_cast<size_t>( md2->header.num_skins ) );
171
172        source.seek( md2->header.offset_st, origin::SET );
173        source.read( md2->texcoords, sizeof(md2_texcoord_t), static_cast<size_t>( md2->header.num_st ) );
174
175        source.seek( md2->header.offset_tris, origin::SET );
176        source.read( md2->triangles, sizeof(md2_triangle_t), static_cast<size_t>( md2->header.num_tris ) );
177
178        source.seek( md2->header.offset_glcmds, origin::SET);
179        source.read( md2->glcmds, sizeof(int), static_cast<size_t>( md2->header.num_glcmds ) );
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        {
185                if (!read_md2_frame( &(md2->frames[i]), static_cast<unsigned>( md2->header.num_vertices ), source ) ) return false;
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
197static inline vec3 md2_normal( uint8 normal )
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 )
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_md2 = (void*)(new md2_t);
233        if ( !read_md2( (md2_t*)m_md2, source ) )
234        {
235                return false;
236        }
237        reindex();
238        return true;
239}
240
241size_t md2_loader::get_max_frames() const
242{
243        return static_cast< size_t >( ((md2_t*)m_md2)->header.num_frames );
244}
245
246void nv::md2_loader::reindex()
247{
248        md2_t* md2 = (md2_t*)m_md2;
249        uint32 num_indexes = static_cast< uint32 >( md2->header.num_tris * 3 );
250
251        uint32 stats_reuse      = 0;
252        uint32 stats_collision  = 0;
253
254        std::vector< sint32 > index_translation( static_cast< uint32 >( md2->header.num_vertices ), -1 );
255
256        m_new_indexes.clear();
257        m_new_indexes.reserve( num_indexes );
258        m_new_vindexes.reserve( num_indexes );
259        m_new_tindexes.reserve( num_indexes );
260
261        uint16 index_count = 0;
262
263        for ( int i = 0; i < md2->header.num_tris; ++i )
264        {
265                const md2_triangle_t& t = md2->triangles[i];
266                for ( int j = 0; j < 3; ++j )
267                {
268                        uint16 index  = t.vertex[j];
269                        uint16 tindex = t.st[j];
270
271                        if ( index_translation[ index ] != -1 )
272                        {
273                                uint16 prev = static_cast< uint16 >( index_translation[ index ] );
274                                if ( m_new_tindexes[ prev ] == tindex )
275                                {
276                                        m_new_indexes.push_back( prev );
277                                        stats_reuse++;
278                                        continue;
279                                }
280                        }
281                       
282                        m_new_vindexes.push_back( index );
283                        m_new_tindexes.push_back( tindex );
284                        m_new_indexes.push_back( index_count );
285                        if ( index_translation[ index ] == -1 )
286                        {
287                                index_translation[ index ] = index_count;
288                        }
289                        else
290                        {
291                                stats_collision++;
292                        }
293                        index_count++;
294                }
295        }
296
297        NV_LOG( LOG_INFO, "New vertex count = " << m_new_vindexes.size() );
298        NV_LOG( LOG_INFO, "Collisions       = " << stats_collision );
299        NV_LOG( LOG_INFO, "Reuse count      = " << stats_reuse );
300}
301
302
303struct vtx_md2_pn
304{
305        nv::vec3 position;
306        nv::vec3 normal;
307};
308
309struct vtx_md2_t
310{
311        nv::vec2 texcoord;
312};
313
314
315mesh_data* nv::md2_loader::release_mesh_data( size_t )
316{
317        return release_mesh_frame( -1 );
318}
319
320mesh_data* nv::md2_loader::release_mesh_frame( sint32 frame )
321{
322        md2_t* md2 = (md2_t*)m_md2;
323        size_t num_frames = static_cast< size_t >( md2->header.num_frames );
324        size_t num_verts  =     m_new_vindexes.size();
325        size_t current_frame = ( frame == -1 ? 0 : static_cast< size_t >( frame ) );
326        size_t frame_count   = ( frame == -1 ? num_frames : 1 );
327
328        mesh_raw_channel* mc_pn = mesh_raw_channel::create< vtx_md2_pn >( num_verts * frame_count );
329        vtx_md2_pn* vtx_pn = (vtx_md2_pn*)mc_pn->data;
330
331        uint32 index = 0;
332        while ( frame_count > 0 )
333        {
334                const md2_frame_t& cframe = md2->frames[current_frame];
335                NV_LOG( LOG_INFO, "FrameID = " << cframe.name );
336
337                vec3 scale     = md2_vec3( cframe.scale );
338                vec3 translate = md2_vec3( cframe.translate );
339
340                for (size_t i = 0; i < num_verts; ++i )
341                {
342                        const md2_vertex_t& v = cframe.vertices[ m_new_vindexes[ i ] ];
343                        vtx_pn[index].position = vec3( v.v[0], v.v[2], v.v[1] ) * scale + translate;
344                        vtx_pn[index].normal   = s_md2_normal_cache[ v.n ];
345                        index++;
346                }
347                ++current_frame;
348                --frame_count;
349        }
350
351        mesh_raw_channel* mc_t = mesh_raw_channel::create< vtx_md2_t >( num_verts );
352        vtx_md2_t* vtx_t = (vtx_md2_t*)mc_t->data;
353
354        vec2 scale( 1.0f / (float) md2->header.skinwidth, 1.0f / (float) md2->header.skinheight );
355        for (size_t i = 0; i < num_verts; ++i )
356        {
357                const md2_texcoord_t& st = md2->texcoords[ m_new_tindexes[ i ] ];
358                vtx_t[i].texcoord = scale * vec2( st.s, st.t );
359        }
360
361        mesh_raw_index_channel* ic = mesh_raw_index_channel::create< uint16 >( m_new_indexes.size() );
362        if ( m_new_indexes.size() > 0 )
363        {
364                uint16* icp = (uint16*)ic->data;
365                std::copy_n( m_new_indexes.data(), m_new_indexes.size(), icp );
366        }
367
368        mesh_data* result = new mesh_data();
369        result->add_channel( mc_pn );
370        result->add_channel( mc_t );
371        result->set_index_channel( ic );
372        return result;
373}
Note: See TracBrowser for help on using the repository browser.