source: trunk/legacy/md2_loader.cc @ 504

Last change on this file since 504 was 480, checked in by epyon, 10 years ago
  • cleanup of legacy code
  • resource updates
File size: 9.2 KB
Line 
1// Copyright (C) 2012-2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/formats/md2_loader.hh"
8
9#include "nv/core/logging.hh"
10#include "nv/interface/data_channel_access.hh"
11
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_INFO( "num_skins    = ", md2->header.num_skins );
159        NV_LOG_INFO( "num_vertices = ", md2->header.num_vertices );
160        NV_LOG_INFO( "num_st       = ", md2->header.num_st );
161        NV_LOG_INFO( "num_tris     = ", md2->header.num_tris );
162        NV_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<nv::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<nv::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<nv::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<nv::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 vec3 s_md2_normal_cache[MD2_NORMAL_COUNT];
199static bool s_md2_normal_ready = false;
200
201md2_loader::md2_loader( string_table* strings )
202        : mesh_loader( strings ), m_md2( nullptr )
203{
204        if ( !s_md2_normal_ready )
205        {
206                for ( int i = 0; i < MD2_NORMAL_COUNT; ++i )
207                {
208                        s_md2_normal_cache[i].x = md2_normal_table[i][0];
209//                      s_md2_normal_cache[i].y = md2_normal_table[i][1];
210//                      s_md2_normal_cache[i].z = md2_normal_table[i][2];
211                        s_md2_normal_cache[i].y = md2_normal_table[i][2];
212                        s_md2_normal_cache[i].z = md2_normal_table[i][1];
213                }
214        }
215}
216
217
218md2_loader::~md2_loader()
219{
220        md2_t* md2 = reinterpret_cast< md2_t* >( m_md2 );
221        if ( md2 != nullptr)
222        {
223                free_md2( md2 );
224                delete md2;
225        }
226}
227
228bool md2_loader::load( stream& source )
229{
230        md2_t* md2 = new md2_t;
231        m_md2 = md2;
232        if ( !read_md2( md2, source ) )
233        {
234                return false;
235        }
236        reindex();
237        return true;
238}
239
240nv::size_t md2_loader::get_max_frames() const
241{
242        return static_cast<size_t>( reinterpret_cast<md2_t*>( m_md2 )->header.num_frames );
243}
244
245void nv::md2_loader::reindex()
246{
247        md2_t* md2 = reinterpret_cast< md2_t* >( m_md2 );
248        uint32 num_indexes = static_cast< uint32 >( md2->header.num_tris * 3 );
249
250        uint32 stats_reuse      = 0;
251        uint32 stats_collision  = 0;
252
253        vector< sint32 > index_translation( static_cast< uint32 >( md2->header.num_vertices ), -1 );
254
255        m_new_indexes.clear();
256        m_new_indexes.reserve( num_indexes );
257        m_new_vindexes.reserve( num_indexes );
258        m_new_tindexes.reserve( num_indexes );
259
260        uint16 index_count = 0;
261
262        for ( int i = 0; i < md2->header.num_tris; ++i )
263        {
264                const md2_triangle_t& t = md2->triangles[i];
265                for ( int j = 0; j < 3; ++j )
266                {
267                        uint16 index  = t.vertex[j];
268                        uint16 tindex = t.st[j];
269
270                        if ( index_translation[ index ] != -1 )
271                        {
272                                uint16 prev = static_cast< uint16 >( index_translation[ index ] );
273                                if ( m_new_tindexes[ prev ] == tindex )
274                                {
275                                        m_new_indexes.push_back( prev );
276                                        stats_reuse++;
277                                        continue;
278                                }
279                        }
280                       
281                        m_new_vindexes.push_back( index );
282                        m_new_tindexes.push_back( tindex );
283                        m_new_indexes.push_back( index_count );
284                        if ( index_translation[ index ] == -1 )
285                        {
286                                index_translation[ index ] = index_count;
287                        }
288                        else
289                        {
290                                stats_collision++;
291                        }
292                        index_count++;
293                }
294        }
295
296        NV_LOG_INFO( "New vertex count = ", m_new_vindexes.size() );
297        NV_LOG_INFO( "Collisions       = ", stats_collision );
298        NV_LOG_INFO( "Reuse count      = ", stats_reuse );
299}
300
301
302struct vtx_md2_pn
303{
304        nv::vec3 position;
305        nv::vec3 normal;
306};
307
308struct vtx_md2_t
309{
310        nv::vec2 texcoord;
311};
312
313
314data_channel_set* nv::md2_loader::release_mesh_data( size_t )
315{
316        data_channel_set* data = data_channel_set_creator::create_set( 3 );
317        release_mesh_frame( data, -1 );
318        return data;
319}
320
321void nv::md2_loader::release_mesh_frame( data_channel_set* data, sint32 frame )
322{
323        md2_t* md2 = reinterpret_cast< md2_t* >( m_md2 );
324        size_t num_frames = static_cast< size_t >( md2->header.num_frames );
325        size_t num_verts  =     m_new_vindexes.size();
326        size_t current_frame = ( frame == -1 ? 0 : static_cast< size_t >( frame ) );
327        size_t frame_count   = ( frame == -1 ? num_frames : 1 );
328
329        data_channel_set_creator maccess( data );
330        vtx_md2_pn* vtx_pn = maccess.add_channel< vtx_md2_pn >( num_verts * frame_count ).data();
331        vtx_md2_t* vtx_t   = maccess.add_channel< vtx_md2_t >( num_verts ).data();
332        uint16* icp        = &maccess.add_channel< index_u16 >( m_new_indexes.size() ).data()->index;
333
334        maccess.set_name( make_name( "md2_mesh" ) );
335
336        uint32 index = 0;
337        while ( frame_count > 0 )
338        {
339                const md2_frame_t& cframe = md2->frames[current_frame];
340                NV_LOG_INFO( "FrameID = ", cframe.name );
341
342                vec3 scale     = md2_vec3( cframe.scale );
343                vec3 translate = md2_vec3( cframe.translate );
344
345                for (size_t i = 0; i < num_verts; ++i )
346                {
347                        const md2_vertex_t& v = cframe.vertices[ m_new_vindexes[ i ] ];
348                        vtx_pn[index].position = vec3( v.v[0], v.v[2], v.v[1] ) * scale + translate;
349                        vtx_pn[index].normal   = s_md2_normal_cache[ v.n ];
350                        index++;
351                }
352                ++current_frame;
353                --frame_count;
354        }
355
356        vec2 scale( 1.0f / static_cast<float>( md2->header.skinwidth ), 1.0f / static_cast<float>( md2->header.skinheight ) );
357        for (size_t i = 0; i < num_verts; ++i )
358        {
359                const md2_texcoord_t& st = md2->texcoords[ m_new_tindexes[ i ] ];
360                vtx_t[i].texcoord = scale * vec2( st.s, st.t );
361        }
362
363        if ( m_new_indexes.size() > 0 )
364        {
365                raw_copy_n( m_new_indexes.data(), m_new_indexes.size(), icp );
366        }
367
368}
369
Note: See TracBrowser for help on using the repository browser.