source: trunk/src/formats/md3_loader.cc @ 352

Last change on this file since 352 was 352, checked in by epyon, 10 years ago
  • rocket utility classes
  • wx utility classes
  • various utilities
  • handle_test
  • various more changes
File size: 14.0 KB
Line 
1// Copyright (C) 2012-2014 ChaosForge Ltd
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/md3_loader.hh"
8
9#include <glm/gtc/constants.hpp>
10#include "nv/core/logging.hh"
11#include <cstring>
12
13using namespace nv;
14
15// based on http://www.icculus.org/~phaethon/q3/formats/md3format.html#Surface
16
17// assuming low-endian
18#define MD3_MAX_FRAMES    1024
19#define MD3_MAX_TAGS      16
20#define MD3_MAX_SURFACES  32
21#define MD3_MAX_SHADERS   256
22#define MD3_MAX_VERTS     4096
23#define MD3_MAX_TRIANGLES 8192
24#define MD3_XYZ_SCALE     (1.0f/64.0f)
25
26struct md3_vec3_t
27{
28        float xyz[3];
29};
30
31struct md3_header_t
32{
33        char   ident[4]; // IDP3
34        sint32 version;  // 15
35        uint8  name[64]; // path name
36        sint32 flags;
37        sint32 num_frames;     // Number of Frame objects, with a maximum of MD3_MAX_FRAMES. Current value of MD3_MAX_FRAMES is 1024.
38        sint32 num_tags;       // Number of Tag objects, with a maximum of MD3_MAX_TAGS. Current value of MD3_MAX_TAGS is 16.
39        sint32 num_surfaces;   // Number of Surface objects, with a maximum of MD3_MAX_SURFACES. Current value of MD3_MAX_SURFACES is 32.
40        sint32 num_skins;      // Number of Skin objects. I should note that I have not seen an MD3 using this particular field for anything; this appears to be an artifact from the Quake 2 MD2 format. Surface objects have their own Shader field.
41        sint32 ofs_frames;     // Relative offset from start of MD3 object where Frame objects start. The Frame objects are written sequentially, that is, when you read one Frame object, you do not need to seek() for the next object.
42        sint32 ofs_tags;       // Relative offset from start of MD3 where Tag objects start. Similarly written sequentially.
43        sint32 ofs_surfaces;   // Relative offset from start of MD3 where Surface objects start. Again, written sequentially.
44        sint32 ofs_eof;        // Relative offset from start of MD3 to the end of the MD3 object. Note there is no offset for Skin objects.
45};
46
47struct md3_frame_t
48{
49        md3_vec3_t min_bounds;
50        md3_vec3_t max_bounds;
51        md3_vec3_t local_origin;
52        float      radius;
53        uint8      name[16];
54};
55
56struct md3_tag_t
57{
58        uint8      name[64];
59        md3_vec3_t origin;
60        md3_vec3_t axis[3];
61};
62
63struct md3_surface_header_t
64{
65        char   ident[4]; // IDP3
66        uint8  name[64]; // path name
67        sint32 flags;
68        sint32 num_frames;
69        sint32 num_shaders;
70        sint32 num_verts;
71        sint32 num_triangles;
72        sint32 ofs_triangles;
73        sint32 ofs_shaders;
74        sint32 ofs_st;
75        sint32 ofs_xyznormal;
76        sint32 ofs_end;
77};
78
79struct md3_shader_t
80{
81        uint8  name[64];
82        sint32 shader_index;
83};
84
85struct md3_triangle_t
86{
87        sint32 indexes[3];
88};
89
90struct md3_texcoord_t
91{
92        float  st[2];
93};
94
95struct md3_vertex_t
96{
97        sint16 x;
98        sint16 y;
99        sint16 z;
100        uint16 normal;
101};
102
103struct md3_surface_t
104{
105        md3_surface_header_t header;
106        md3_shader_t*        shaders;
107        md3_triangle_t*      triangles;
108        md3_texcoord_t*      st;
109        md3_vertex_t*        vertices;
110};
111
112struct md3_t
113{
114        md3_header_t   header;
115        md3_frame_t*   frames;
116        md3_tag_t*     tags;
117        md3_surface_t* surfaces;
118        // extra information (not in md3 file)
119        sint32         vertices_per_frame;
120};
121
122static bool check_md3_magic( char* magic )
123{
124        return magic[0] == 'I' && magic[1] == 'D' && magic[2] == 'P' && magic[3] == '3';
125}
126
127static void free_md3_surface( md3_surface_t * surface )
128{
129        delete[] surface->shaders;
130        delete[] surface->triangles;
131        delete[] surface->st;
132        delete[] surface->vertices;
133}
134
135static void free_md3( md3_t * md3 )
136{
137        sint32 count = md3->header.num_surfaces;
138        for ( sint32 i = 0; i < count; ++i )
139        {
140                free_md3_surface( &md3->surfaces[i] );
141        }
142        delete[] md3->frames;
143        delete[] md3->tags;
144        delete[] md3->surfaces;
145}
146
147static bool read_surface( md3_surface_t * surface, nv::stream& source )
148{
149        sint32 pos = static_cast< sint32 >( source.tell() );
150        source.read( &surface->header, sizeof(md3_surface_header_t), 1 );
151
152        if ( !check_md3_magic( surface->header.ident ) )          return false;
153        if ( surface->header.num_frames    >  MD3_MAX_FRAMES )    return false;
154        if ( surface->header.num_shaders   >  MD3_MAX_SHADERS )   return false;
155        if ( surface->header.num_verts     >  MD3_MAX_VERTS )     return false;
156        if ( surface->header.num_triangles >  MD3_MAX_TRIANGLES ) return false;
157
158        surface->shaders   = new md3_shader_t  [ surface->header.num_shaders ];
159        surface->vertices  = new md3_vertex_t  [ surface->header.num_verts * surface->header.num_frames ];
160        surface->st        = new md3_texcoord_t[ surface->header.num_verts ];
161        surface->triangles = new md3_triangle_t[ surface->header.num_triangles ];
162
163        source.seek( pos + surface->header.ofs_shaders, origin::SET );
164        source.read( surface->shaders, sizeof( md3_shader_t ), static_cast<size_t>( surface->header.num_shaders ) );
165
166        source.seek( pos + surface->header.ofs_triangles, origin::SET );
167        source.read( surface->triangles, sizeof( md3_triangle_t ), static_cast<size_t>( surface->header.num_triangles ) );
168
169        source.seek( pos + surface->header.ofs_st, origin::SET );
170        source.read( surface->st, sizeof( md3_texcoord_t ), static_cast<size_t>( surface->header.num_verts ) );
171
172        source.seek( pos + surface->header.ofs_xyznormal, origin::SET );
173        source.read( surface->vertices, sizeof( md3_vertex_t ), static_cast<size_t>( surface->header.num_verts * surface->header.num_frames ) );
174
175        if ( source.tell() != static_cast<std::size_t>( pos + surface->header.ofs_end ) ) return false;
176
177        return true;
178}
179
180static bool read_md3( md3_t * md3, nv::stream& source )
181{
182        md3->frames   = nullptr;
183        md3->tags     = nullptr;
184        md3->surfaces = nullptr;
185
186        source.read( &md3->header, sizeof(md3_header_t), 1 );
187
188        if ( !check_md3_magic( md3->header.ident ) )        return false;
189        if ( md3->header.num_frames   >  MD3_MAX_FRAMES )   return false;
190        if ( md3->header.num_tags     >  MD3_MAX_TAGS )     return false;
191        if ( md3->header.num_surfaces >  MD3_MAX_SURFACES )
192        {
193                // to always have a safe free
194                md3->header.num_surfaces = 0;
195                return false;
196        }
197
198        md3->frames   = new md3_frame_t  [ md3->header.num_frames ];
199        md3->tags     = new md3_tag_t    [ md3->header.num_tags * md3->header.num_frames ];
200        md3->surfaces = new md3_surface_t[ md3->header.num_surfaces ];
201        std::memset( md3->surfaces, 0, static_cast< size_t >( md3->header.num_surfaces ) * sizeof(md3_surface_t) );
202
203        source.seek( md3->header.ofs_frames, origin::SET );
204        source.read( md3->frames, sizeof( md3_frame_t ), static_cast<size_t>( md3->header.num_frames ) );
205
206        if ( md3->header.num_tags > 0 )
207        {
208                source.seek( md3->header.ofs_tags, origin::SET );
209                source.read( md3->tags, sizeof( md3_tag_t ), static_cast<size_t>( md3->header.num_tags * md3->header.num_frames ) );
210        }
211
212        source.seek( md3->header.ofs_surfaces, origin::SET );
213        md3->vertices_per_frame = 0;
214
215        for ( sint32 i = 0; i < md3->header.num_surfaces; ++i )
216        {
217                if ( !read_surface( md3->surfaces + i, source ) ) return false;
218                if ( md3->header.num_frames != md3->surfaces[i].header.num_frames ) return false;
219                md3->vertices_per_frame += md3->surfaces[i].header.num_verts;
220        }
221        return true;
222}
223
224static inline vec3 md3_vec3( const md3_vec3_t& v )
225{
226//      return vec3( v.xyz[0], v.xyz[1], v.xyz[2] );
227        return vec3( v.xyz[0], v.xyz[2], v.xyz[1] );
228}
229
230static inline vec2 md3_texcoord( const md3_texcoord_t& v )
231{
232        return vec2( v.st[0], v.st[1] );
233}
234
235static vec3 s_normal_cache[256*256];
236static bool s_normal_ready = false;
237
238md3_loader::md3_loader( bool merge_all )
239        : m_merge_all( merge_all ), m_md3( nullptr )
240{
241        if ( !s_normal_ready )
242        {
243                float pi      = glm::pi<float>();
244                float convert = (2 * pi) / 255.0f;
245                int n = 0;
246                for ( int lat = 0; lat < 256; ++lat )
247                {
248                        float flat    = lat * convert;
249                        float sin_lat = glm::sin( flat );
250                        float cos_lat = glm::cos( flat );
251                        for ( int lng = 0; lng < 256; ++lng, ++n )
252                        {
253                                float flng    = lng * convert;
254                                float sin_lng = glm::sin( flng );
255                                float cos_lng = glm::cos( flng );
256                                s_normal_cache[n].x = cos_lat * sin_lng;
257//                              s_normal_cache[n].y = sin_lat * sin_lng;
258//                              s_normal_cache[n].z = cos_lng;
259                                s_normal_cache[n].z = sin_lat * sin_lng;
260                                s_normal_cache[n].y = cos_lng;
261                        }
262                }
263
264                s_normal_ready = true;
265        }
266}
267
268
269nv::md3_loader::~md3_loader()
270{
271        if (m_md3 != nullptr)
272        {
273                free_md3( (md3_t*)(m_md3) );
274                delete (md3_t*)m_md3;
275        }
276}
277
278bool nv::md3_loader::load( stream& source )
279{
280        m_md3 = (void*)(new md3_t);
281        if ( !read_md3( (md3_t*)m_md3, source ) )
282        {
283                return false;
284        }
285        return true;
286}
287
288nv::key_raw_channel* nv::md3_loader::load_tags( const std::string& tag )
289{
290        md3_t* md3 = (md3_t*)m_md3;
291        key_raw_channel* result = key_raw_channel::create<md3_key>( (uint32)md3->header.num_frames );
292        // TODO: is this brain damaged in efficiency (loop nest order) or what?
293        for ( sint32 f = 0; f < md3->header.num_frames; ++f )
294        {
295                for ( sint32 i = 0; i < md3->header.num_tags; ++i )
296                {
297                        const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * f];
298                        std::string rname((char*)(rtag.name));
299                        if (rname == tag)
300                        {
301                                vec3 axisx  ( md3_vec3( rtag.axis[0] ) );
302                                vec3 axisz  ( md3_vec3( rtag.axis[1] ) );
303                                vec3 axisy  ( md3_vec3( rtag.axis[2] ) );
304                                vec3 origin ( md3_vec3( rtag.origin )  );
305                                ((md3_key*)(result->data))[f].tform = transform( origin, quat( mat3( axisx, axisy, axisz ) ) );
306                        }
307                }
308
309        }
310        return result;
311}
312
313struct vtx_md3_pn
314{
315        nv::vec3 position;
316        nv::vec3 normal;
317};
318
319struct vtx_md3_t
320{
321        nv::vec2 texcoord;
322};
323
324mesh_data* nv::md3_loader::release_mesh_data( size_t index )
325{
326        mesh_data* data = new mesh_data;
327        release_mesh_frame( data, -1, (sint32)index );
328        return data;
329}
330
331void nv::md3_loader::release_mesh_frame( mesh_data* data, sint32 frame, sint32 surface )
332{
333        md3_t* md3 = (md3_t*)m_md3;
334        uint32 num_surfaces  = (uint32)md3->header.num_surfaces;
335        uint32 num_verts     = 0;
336        uint32 current_frame = ( frame == -1 ? 0 : (uint32)frame );
337        uint32 frame_count   = ( frame == -1 ? (uint32)md3->header.num_frames : 1 );
338        uint32 current_surf  = ( surface == -1 ? 0 : (uint32)surface );
339        uint32 surf_count    = ( surface == -1 ? (uint32)md3->header.num_surfaces : 1 );
340        uint32 index_count   = 0;
341
342        if ( surface >= 0 )
343        {
344                index_count = (uint32)md3->surfaces[(uint32)surface].header.num_triangles * 3;
345                num_verts   = (uint32)md3->surfaces[(uint32)surface].header.num_verts;
346        }
347        else
348                for ( uint32 i = 0; i < num_surfaces; ++i )
349                {
350                        index_count += (uint32)md3->surfaces[i].header.num_triangles * 3;
351                        num_verts   += (uint32)md3->surfaces[i].header.num_verts;
352                }
353
354        mesh_raw_channel* mc_pn = mesh_raw_channel::create< vtx_md3_pn >( num_verts * frame_count );
355        mesh_raw_channel* mc_t  = mesh_raw_channel::create< vtx_md3_t >( num_verts );
356        mesh_raw_channel* ic = mesh_raw_channel::create_index< uint16 >( index_count );
357        vtx_md3_pn* vtx_pn = (vtx_md3_pn*)mc_pn->data;
358        vtx_md3_t*  vtx_t  = (vtx_md3_t*) mc_t->data;
359        uint16*     icp    = (uint16*)ic->data;
360
361        uint32 index  = 0;
362        uint32 iindex = 0;
363        sint32 index_base = 0;
364
365        while ( surf_count > 0 )
366        {
367                const md3_surface_t& sface  = md3->surfaces[ current_surf ];
368                const uint32         vcount = static_cast< uint32 >( sface.header.num_verts );
369                const uint32         tcount = static_cast< uint32 >( sface.header.num_triangles );
370
371                for (uint32 j = 0; j < vcount; ++j )
372                {
373                        vtx_t[index++].texcoord = md3_texcoord( sface.st[j] );
374                }
375
376                for (size_t j = 0; j < tcount; ++j )
377                {
378                        const md3_triangle_t& t = sface.triangles[j];
379                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[0] );
380                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[1] );
381                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[2] );
382                }
383                index_base += sface.header.num_verts;
384                ++current_surf;
385                --surf_count;
386        }
387
388        index = 0;
389        while ( frame_count > 0 )
390        {
391                current_surf  = ( surface == -1 ? 0 : (uint32)surface );
392                surf_count    = ( surface == -1 ? (uint32)md3->header.num_surfaces : 1 );
393
394                while ( surf_count > 0 )
395                {
396                        md3_surface_t& sface  = md3->surfaces[current_surf];
397                        uint32         vcount = (uint32)sface.header.num_verts;
398                        uint32         offset = vcount * current_frame;
399                        uint32         limit  = vcount + offset;
400                        for (uint32 j = offset; j < limit; ++j )
401                        {
402                                md3_vertex_t& v = sface.vertices[j];
403                                vtx_pn[index].position = vec3( v.x * MD3_XYZ_SCALE, v.z * MD3_XYZ_SCALE, v.y * MD3_XYZ_SCALE );
404                                vtx_pn[index].normal   = s_normal_cache[ v.normal ];
405                                index++;
406                        }
407                        ++current_surf;
408                        --surf_count;
409                }
410                ++current_frame;
411                --frame_count;
412        }
413
414        data->set_name( (char*)md3->header.name );
415        data->add_channel( mc_pn );
416        data->add_channel( mc_t );
417        data->add_channel( ic );
418}
419
420mesh_nodes_data* nv::md3_loader::release_mesh_nodes_data( size_t )
421{
422        md3_t* md3 = (md3_t*)m_md3;
423        uint32 node_count = (uint32)md3->header.num_tags;
424        if ( node_count == 0 ) return nullptr;;
425        mesh_node_data* nodes = new mesh_node_data[ node_count ];
426        for ( uint32 i = 0; i < node_count; ++i )
427        {
428                const md3_tag_t& rtag = md3->tags[i];
429                std::string name( (char*)(rtag.name) );
430
431                nodes[i].transform = mat4();
432                nodes[i].name      = name;
433                nodes[i].parent_id = -1;
434                nodes[i].target_id = -1;
435                nodes[i].data      = new key_data;
436       
437                key_raw_channel* keys = load_tags( name );
438                nodes[i].data->add_channel( keys );
439        }
440        return new mesh_nodes_data( "tags", node_count, nodes );
441}
442
443mesh_data_pack* nv::md3_loader::release_mesh_data_pack()
444{
445        md3_t* md3 = (md3_t*)m_md3;
446        uint32 count = 1;
447        mesh_data* data = nullptr;
448        if ( m_merge_all )
449        {
450                data = new mesh_data[1];
451                release_mesh_frame( &data[0], -1, -1 );
452                data[0].set_name( (char*)md3->header.name );
453        }
454        else
455        {
456                count = (uint32)md3->header.num_surfaces;
457                data = new mesh_data[ count ];
458                for ( uint32 i = 0; i < count; ++i )
459                {
460                        release_mesh_frame( &data[i], -1, (sint32)i );
461                        data[i].set_name( (char*)md3->surfaces[i].header.name );
462                }
463        }
464        return new mesh_data_pack( count, data, release_mesh_nodes_data() );
465}
466
467size_t md3_loader::get_max_frames() const
468{
469        return static_cast< size_t >( ((md3_t*)m_md3)->header.num_frames );
470}
Note: See TracBrowser for help on using the repository browser.