source: trunk/src/formats/md3_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: 14.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/md3_loader.hh"
8
9#include "nv/core/logging.hh"
10
11using namespace nv;
12
13// based on http://www.icculus.org/~phaethon/q3/formats/md3format.html#Surface
14
15// assuming low-endian
16#define MD3_MAX_FRAMES    1024
17#define MD3_MAX_TAGS      16
18#define MD3_MAX_SURFACES  32
19#define MD3_MAX_SHADERS   256
20#define MD3_MAX_VERTS     4096
21#define MD3_MAX_TRIANGLES 8192
22#define MD3_XYZ_SCALE     (1.0f/64.0f)
23
24struct md3_vec3_t
25{
26        float xyz[3];
27};
28
29struct md3_header_t
30{
31        char   ident[4]; // IDP3
32        sint32 version;  // 15
33        uint8  name[64]; // path name
34        sint32 flags;
35        sint32 num_frames;     // Number of Frame objects, with a maximum of MD3_MAX_FRAMES. Current value of MD3_MAX_FRAMES is 1024.
36        sint32 num_tags;       // Number of Tag objects, with a maximum of MD3_MAX_TAGS. Current value of MD3_MAX_TAGS is 16.
37        sint32 num_surfaces;   // Number of Surface objects, with a maximum of MD3_MAX_SURFACES. Current value of MD3_MAX_SURFACES is 32.
38        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.
39        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.
40        sint32 ofs_tags;       // Relative offset from start of MD3 where Tag objects start. Similarly written sequentially.
41        sint32 ofs_surfaces;   // Relative offset from start of MD3 where Surface objects start. Again, written sequentially.
42        sint32 ofs_eof;        // Relative offset from start of MD3 to the end of the MD3 object. Note there is no offset for Skin objects.
43};
44
45struct md3_frame_t
46{
47        md3_vec3_t min_bounds;
48        md3_vec3_t max_bounds;
49        md3_vec3_t local_origin;
50        float      radius;
51        uint8      name[16];
52};
53
54struct md3_tag_t
55{
56        uint8      name[64];
57        md3_vec3_t origin;
58        md3_vec3_t axis[3];
59};
60
61struct md3_surface_header_t
62{
63        char   ident[4]; // IDP3
64        uint8  name[64]; // path name
65        sint32 flags;
66        sint32 num_frames;
67        sint32 num_shaders;
68        sint32 num_verts;
69        sint32 num_triangles;
70        sint32 ofs_triangles;
71        sint32 ofs_shaders;
72        sint32 ofs_st;
73        sint32 ofs_xyznormal;
74        sint32 ofs_end;
75};
76
77struct md3_shader_t
78{
79        uint8  name[64];
80        sint32 shader_index;
81};
82
83struct md3_triangle_t
84{
85        sint32 indexes[3];
86};
87
88struct md3_texcoord_t
89{
90        float  st[2];
91};
92
93struct md3_vertex_t
94{
95        sint16 x;
96        sint16 y;
97        sint16 z;
98        uint16 normal;
99};
100
101struct md3_surface_t
102{
103        md3_surface_header_t header;
104        md3_shader_t*        shaders;
105        md3_triangle_t*      triangles;
106        md3_texcoord_t*      st;
107        md3_vertex_t*        vertices;
108};
109
110struct md3_t
111{
112        md3_header_t   header;
113        md3_frame_t*   frames;
114        md3_tag_t*     tags;
115        md3_surface_t* surfaces;
116        // extra information (not in md3 file)
117        sint32         vertices_per_frame;
118};
119
120static bool check_md3_magic( char* magic )
121{
122        return magic[0] == 'I' && magic[1] == 'D' && magic[2] == 'P' && magic[3] == '3';
123}
124
125static void free_md3_surface( md3_surface_t * surface )
126{
127        delete[] surface->shaders;
128        delete[] surface->triangles;
129        delete[] surface->st;
130        delete[] surface->vertices;
131}
132
133static void free_md3( md3_t * md3 )
134{
135        sint32 count = md3->header.num_surfaces;
136        for ( sint32 i = 0; i < count; ++i )
137        {
138                free_md3_surface( &md3->surfaces[i] );
139        }
140        delete[] md3->frames;
141        delete[] md3->tags;
142        delete[] md3->surfaces;
143}
144
145static bool read_surface( md3_surface_t * surface, nv::stream& source )
146{
147        sint32 pos = static_cast< sint32 >( source.tell() );
148        source.read( &surface->header, sizeof(md3_surface_header_t), 1 );
149
150        if ( !check_md3_magic( surface->header.ident ) )          return false;
151        if ( surface->header.num_frames    >  MD3_MAX_FRAMES )    return false;
152        if ( surface->header.num_shaders   >  MD3_MAX_SHADERS )   return false;
153        if ( surface->header.num_verts     >  MD3_MAX_VERTS )     return false;
154        if ( surface->header.num_triangles >  MD3_MAX_TRIANGLES ) return false;
155
156        surface->shaders   = new md3_shader_t  [ surface->header.num_shaders ];
157        surface->vertices  = new md3_vertex_t  [ surface->header.num_verts * surface->header.num_frames ];
158        surface->st        = new md3_texcoord_t[ surface->header.num_verts ];
159        surface->triangles = new md3_triangle_t[ surface->header.num_triangles ];
160
161        source.seek( pos + surface->header.ofs_shaders, origin::SET );
162        source.read( surface->shaders, sizeof( md3_shader_t ), static_cast<nv::size_t>( surface->header.num_shaders ) );
163
164        source.seek( pos + surface->header.ofs_triangles, origin::SET );
165        source.read( surface->triangles, sizeof( md3_triangle_t ), static_cast<nv::size_t>( surface->header.num_triangles ) );
166
167        source.seek( pos + surface->header.ofs_st, origin::SET );
168        source.read( surface->st, sizeof( md3_texcoord_t ), static_cast<nv::size_t>( surface->header.num_verts ) );
169
170        source.seek( pos + surface->header.ofs_xyznormal, origin::SET );
171        source.read( surface->vertices, sizeof( md3_vertex_t ), static_cast<nv::size_t>( surface->header.num_verts * surface->header.num_frames ) );
172
173        if ( source.tell() != static_cast<nv::size_t>( pos + surface->header.ofs_end ) ) return false;
174
175        return true;
176}
177
178static bool read_md3( md3_t * md3, nv::stream& source )
179{
180        md3->frames   = nullptr;
181        md3->tags     = nullptr;
182        md3->surfaces = nullptr;
183
184        source.read( &md3->header, sizeof(md3_header_t), 1 );
185
186        if ( !check_md3_magic( md3->header.ident ) )        return false;
187        if ( md3->header.num_frames   >  MD3_MAX_FRAMES )   return false;
188        if ( md3->header.num_tags     >  MD3_MAX_TAGS )     return false;
189        if ( md3->header.num_surfaces >  MD3_MAX_SURFACES )
190        {
191                // to always have a safe free
192                md3->header.num_surfaces = 0;
193                return false;
194        }
195
196        md3->frames   = new md3_frame_t  [ md3->header.num_frames ];
197        md3->tags     = new md3_tag_t    [ md3->header.num_tags * md3->header.num_frames ];
198        md3->surfaces = new md3_surface_t[ md3->header.num_surfaces ];
199        nv::raw_zero_n( md3->surfaces, static_cast< nv::size_t >( md3->header.num_surfaces ) );
200
201        source.seek( md3->header.ofs_frames, origin::SET );
202        source.read( md3->frames, sizeof( md3_frame_t ), static_cast<nv::size_t>( md3->header.num_frames ) );
203
204        if ( md3->header.num_tags > 0 )
205        {
206                source.seek( md3->header.ofs_tags, origin::SET );
207                source.read( md3->tags, sizeof( md3_tag_t ), static_cast<nv::size_t>( md3->header.num_tags * md3->header.num_frames ) );
208        }
209
210        source.seek( md3->header.ofs_surfaces, origin::SET );
211        md3->vertices_per_frame = 0;
212
213        for ( sint32 i = 0; i < md3->header.num_surfaces; ++i )
214        {
215                if ( !read_surface( md3->surfaces + i, source ) ) return false;
216                if ( md3->header.num_frames != md3->surfaces[i].header.num_frames ) return false;
217                md3->vertices_per_frame += md3->surfaces[i].header.num_verts;
218        }
219        return true;
220}
221
222static inline vec3 md3_vec3( const md3_vec3_t& v )
223{
224//      return vec3( v.xyz[0], v.xyz[1], v.xyz[2] );
225        return vec3( v.xyz[0], v.xyz[2], v.xyz[1] );
226}
227
228static inline vec2 md3_texcoord( const md3_texcoord_t& v )
229{
230        return vec2( v.st[0], v.st[1] );
231}
232
233static vec3 s_normal_cache[256*256];
234static bool s_normal_ready = false;
235
236md3_loader::md3_loader( bool merge_all )
237        : m_merge_all( merge_all ), m_md3( nullptr )
238{
239        if ( !s_normal_ready )
240        {
241                float pi      = glm::pi<float>();
242                float convert = (2 * pi) / 255.0f;
243                int n = 0;
244                for ( int lat = 0; lat < 256; ++lat )
245                {
246                        float flat    = lat * convert;
247                        float sin_lat = glm::sin( flat );
248                        float cos_lat = glm::cos( flat );
249                        for ( int lng = 0; lng < 256; ++lng, ++n )
250                        {
251                                float flng    = lng * convert;
252                                float sin_lng = glm::sin( flng );
253                                float cos_lng = glm::cos( flng );
254                                s_normal_cache[n].x = cos_lat * sin_lng;
255//                              s_normal_cache[n].y = sin_lat * sin_lng;
256//                              s_normal_cache[n].z = cos_lng;
257                                s_normal_cache[n].z = sin_lat * sin_lng;
258                                s_normal_cache[n].y = cos_lng;
259                        }
260                }
261
262                s_normal_ready = true;
263        }
264}
265
266
267nv::md3_loader::~md3_loader()
268{
269        md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
270        if ( md3 != nullptr )
271        {
272                free_md3( md3 );
273                delete md3;
274        }
275}
276
277bool nv::md3_loader::load( stream& source )
278{
279        md3_t* md3 = new md3_t;
280        m_md3 = md3;
281        if ( !read_md3( md3, source ) )
282        {
283                return false;
284        }
285        return true;
286}
287
288nv::raw_data_channel* nv::md3_loader::load_tags( const string_view& tag )
289{
290        md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
291        raw_data_channel* result = raw_data_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                        string_view rname( reinterpret_cast< const 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                                reinterpret_cast< 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( nv::size_t index )
325{
326        mesh_data* data = new mesh_data;
327        release_mesh_frame( data, -1, static_cast< 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 = reinterpret_cast< md3_t* >( m_md3 );
334        sint32 num_surfaces  = md3->header.num_surfaces;
335        sint32 num_verts     = 0;
336        sint32 current_frame = ( frame == -1 ? 0 : frame );
337        sint32 frame_count   = ( frame == -1 ? md3->header.num_frames : 1 );
338        sint32 current_surf  = ( surface == -1 ? 0 : surface );
339        sint32 surf_count    = ( surface == -1 ? md3->header.num_surfaces : 1 );
340        sint32 index_count   = 0;
341
342        if ( surface >= 0 )
343        {
344                index_count = md3->surfaces[surface].header.num_triangles * 3;
345                num_verts   = md3->surfaces[surface].header.num_verts;
346        }
347        else
348                for ( sint32 i = 0; i < num_surfaces; ++i )
349                {
350                        index_count += md3->surfaces[i].header.num_triangles * 3;
351                        num_verts   += md3->surfaces[i].header.num_verts;
352                }
353
354        raw_data_channel* mc_pn = raw_data_channel::create< vtx_md3_pn >( uint32( num_verts * frame_count ) );
355        raw_data_channel* mc_t  = raw_data_channel::create< vtx_md3_t >( uint32( num_verts ) );
356        raw_data_channel* ic = raw_data_channel::create< index_u16 >( uint32( index_count ) );
357        vtx_md3_pn* vtx_pn = reinterpret_cast< vtx_md3_pn* >( mc_pn->data );
358        vtx_md3_t*  vtx_t  = reinterpret_cast< vtx_md3_t* >( mc_t->data );
359        uint16*     icp    = reinterpret_cast< 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 : surface );
392                surf_count    = ( surface == -1 ? md3->header.num_surfaces : 1 );
393
394                while ( surf_count > 0 )
395                {
396                        md3_surface_t& sface  = md3->surfaces[current_surf];
397                        sint32 vcount = sface.header.num_verts;
398                        sint32 offset = vcount * current_frame;
399                        sint32 limit  = vcount + offset;
400                        for ( sint32 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( reinterpret_cast< 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( nv::size_t )
421{
422        md3_t* md3 = reinterpret_cast< 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                string_view name( reinterpret_cast< const char* >(rtag.name) );
430
431                nodes[i].transform = mat4();
432                nodes[i].name      = name.to_string();
433                nodes[i].parent_id = -1;
434                nodes[i].target_id = -1;
435                nodes[i].data      = new key_data;
436       
437                raw_data_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 = reinterpret_cast<md3_t*>( m_md3 );
446        int 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( reinterpret_cast< char* >( md3->header.name ) );
453        }
454        else
455        {
456                count = md3->header.num_surfaces;
457                data = new mesh_data[ count ];
458                for ( int i = 0; i < count; ++i )
459                {
460                        release_mesh_frame( &data[i], -1, i );
461                        data[i].set_name( reinterpret_cast< char* >( md3->surfaces[i].header.name ) );
462                }
463        }
464        return new mesh_data_pack( uint32( count ), data, release_mesh_nodes_data() );
465}
466
467nv::size_t md3_loader::get_max_frames() const
468{
469        return static_cast<size_t>( reinterpret_cast<md3_t*>( m_md3 )->header.num_frames );
470}
Note: See TracBrowser for help on using the repository browser.