source: trunk/legacy/md3_loader.cc @ 505

Last change on this file since 505 was 480, checked in by epyon, 10 years ago
  • cleanup of legacy code
  • resource updates
File size: 13.5 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#include "nv/interface/data_channel_access.hh"
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;
99        uint16 normal;
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;
117        // extra information (not in md3 file)
118        sint32         vertices_per_frame;
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{
148        sint32 pos = static_cast< sint32 >( source.tell() );
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 );
163        source.read( surface->shaders, sizeof( md3_shader_t ), static_cast<nv::size_t>( surface->header.num_shaders ) );
164
165        source.seek( pos + surface->header.ofs_triangles, origin::SET );
166        source.read( surface->triangles, sizeof( md3_triangle_t ), static_cast<nv::size_t>( surface->header.num_triangles ) );
167
168        source.seek( pos + surface->header.ofs_st, origin::SET );
169        source.read( surface->st, sizeof( md3_texcoord_t ), static_cast<nv::size_t>( surface->header.num_verts ) );
170
171        source.seek( pos + surface->header.ofs_xyznormal, origin::SET );
172        source.read( surface->vertices, sizeof( md3_vertex_t ), static_cast<nv::size_t>( surface->header.num_verts * surface->header.num_frames ) );
173
174        if ( source.tell() != static_cast<nv::size_t>( pos + surface->header.ofs_end ) ) return false;
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 ];
200        nv::raw_zero_n( md3->surfaces, static_cast< nv::size_t >( md3->header.num_surfaces ) );
201
202        source.seek( md3->header.ofs_frames, origin::SET );
203        source.read( md3->frames, sizeof( md3_frame_t ), static_cast<nv::size_t>( md3->header.num_frames ) );
204
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<nv::size_t>( md3->header.num_tags * md3->header.num_frames ) );
209        }
210
211        source.seek( md3->header.ofs_surfaces, origin::SET );
212        md3->vertices_per_frame = 0;
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;
218                md3->vertices_per_frame += md3->surfaces[i].header.num_verts;
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
234static vec3 s_normal_cache[256*256];
235static bool s_normal_ready = false;
236
237md3_loader::md3_loader( string_table* strings, bool merge_all )
238        : mesh_loader( strings ), m_merge_all( merge_all ), m_md3( nullptr )
239{
240        if ( !s_normal_ready )
241        {
242                float pi      = math::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 = nv::sin( flat );
249                        float cos_lat = nv::cos( flat );
250                        for ( int lng = 0; lng < 256; ++lng, ++n )
251                        {
252                                float flng    = lng * convert;
253                                float sin_lng = nv::sin( flng );
254                                float cos_lng = nv::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        }
265}
266
267
268nv::md3_loader::~md3_loader()
269{
270        md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
271        if ( md3 != nullptr )
272        {
273                free_md3( md3 );
274                delete md3;
275        }
276}
277
278bool nv::md3_loader::load( stream& source )
279{
280        md3_t* md3 = new md3_t;
281        m_md3 = md3;
282        if ( !read_md3( md3, source ) )
283        {
284                return false;
285        }
286        return true;
287}
288
289void nv::md3_loader::load_tags( raw_data_channel* channel, const string_view& tag )
290{
291        md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
292        data_channel_access< md3_key > access( channel );
293        // TODO: is this brain damaged in efficiency (loop nest order) or what?
294        for ( sint32 f = 0; f < md3->header.num_frames; ++f )
295        {
296                for ( sint32 i = 0; i < md3->header.num_tags; ++i )
297                {
298                        const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * f];
299                        string_view rname( reinterpret_cast< const char* >(rtag.name) );
300                        if (rname == tag)
301                        {
302                                vec3 axisx  ( md3_vec3( rtag.axis[0] ) );
303                                vec3 axisz  ( md3_vec3( rtag.axis[1] ) );
304                                vec3 axisy  ( md3_vec3( rtag.axis[2] ) );
305                                vec3 origin ( md3_vec3( rtag.origin )  );
306                                access.data()[f].tform = transform( origin, quat( mat3( axisx, axisy, axisz ) ) );
307                        }
308                }
309
310        }
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
324data_channel_set* nv::md3_loader::release_mesh_data( nv::size_t index )
325{
326        data_channel_set* data = data_channel_set_creator::create_set(3);
327        release_mesh_frame( data, -1, static_cast< sint32 >( index ) );
328        return data;
329}
330
331void nv::md3_loader::release_mesh_frame( data_channel_set* 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        data_channel_set_creator maccess( data );
355        maccess.set_name( make_name( reinterpret_cast<char*>( md3->header.name ) ) );
356
357
358        vtx_md3_pn* vtx_pn = maccess.add_channel< vtx_md3_pn >( static_cast< uint32 >( num_verts * frame_count ) ).data();
359        vtx_md3_t*  vtx_t  = maccess.add_channel< vtx_md3_t >( static_cast< uint32 >( num_verts ) ).data();
360        uint16*     icp    = reinterpret_cast< uint16* >( maccess.add_channel< index_u16 >( static_cast< uint32 >( index_count ) ).data() );
361
362        uint32 index  = 0;
363        uint32 iindex = 0;
364        sint32 index_base = 0;
365
366        while ( surf_count > 0 )
367        {
368                const md3_surface_t& sface  = md3->surfaces[ current_surf ];
369                const uint32         vcount = static_cast< uint32 >( sface.header.num_verts );
370                const uint32         tcount = static_cast< uint32 >( sface.header.num_triangles );
371
372                for (uint32 j = 0; j < vcount; ++j )
373                {
374                        vtx_t[index++].texcoord = md3_texcoord( sface.st[j] );
375                }
376
377                for (size_t j = 0; j < tcount; ++j )
378                {
379                        const md3_triangle_t& t = sface.triangles[j];
380                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[0] );
381                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[1] );
382                        icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[2] );
383                }
384                index_base += sface.header.num_verts;
385                ++current_surf;
386                --surf_count;
387        }
388
389        index = 0;
390        while ( frame_count > 0 )
391        {
392                current_surf  = ( surface == -1 ? 0 : surface );
393                surf_count    = ( surface == -1 ? md3->header.num_surfaces : 1 );
394
395                while ( surf_count > 0 )
396                {
397                        md3_surface_t& sface  = md3->surfaces[current_surf];
398                        sint32 vcount = sface.header.num_verts;
399                        sint32 offset = vcount * current_frame;
400                        sint32 limit  = vcount + offset;
401                        for ( sint32 j = offset; j < limit; ++j )
402                        {
403                                md3_vertex_t& v = sface.vertices[j];
404                                vtx_pn[index].position = vec3( v.x * MD3_XYZ_SCALE, v.z * MD3_XYZ_SCALE, v.y * MD3_XYZ_SCALE );
405                                vtx_pn[index].normal   = s_normal_cache[ v.normal ];
406                                index++;
407                        }
408                        ++current_surf;
409                        --surf_count;
410                }
411                ++current_frame;
412                --frame_count;
413        }
414
415}
416
417mesh_nodes_data* nv::md3_loader::release_mesh_nodes_data( nv::size_t )
418{
419        md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
420        uint32 node_count = uint32( md3->header.num_tags );
421        if ( node_count == 0 ) return nullptr;
422        mesh_nodes_data* result = new mesh_nodes_data( m_strings ? m_strings->insert( "tags" ) : shash64() );
423        for ( uint32 i = 0; i < node_count; ++i )
424        {
425                const md3_tag_t& rtag = md3->tags[i];
426                string_view name( reinterpret_cast< const char* >(rtag.name) );
427                data_channel_set* set = data_channel_set_creator::create_set( 1 );
428                data_channel_set_creator access( set );
429                access.set_name( make_name( name ) );
430                load_tags( access.add_channel<md3_key>( uint32( md3->header.num_frames ) ).channel(), name );
431                result->append( set );
432        }
433        result->initialize();
434        return result;
435}
436
437nv::size_t md3_loader::get_max_frames() const
438{
439        return static_cast<size_t>( reinterpret_cast<md3_t*>( m_md3 )->header.num_frames );
440}
Note: See TracBrowser for help on using the repository browser.