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

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