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

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