source: trunk/legacy/md5_loader.cc @ 541

Last change on this file since 541 was 441, checked in by epyon, 10 years ago
  • md5 support moved to legacy code
  • more std::string removal
  • minor fixes in algorithm
File size: 15.4 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/md5_loader.hh"
8
9#include "nv/core/logging.hh"
10#include "nv/stl/vector.hh"
11#include "nv/io/std_stream.hh"
12#include "nv/interface/data_channel_access.hh"
13
14#include <stdio.h>  // sscanf
15#include <stdlib.h> // atof
16
17#include <string> // TODO: remove
18
19using namespace nv;
20
21static void next_line( std::istream& stream )
22{
23        stream.ignore( 1024*1024, '\n' );
24}
25
26static inline void discard( std::istream& stream, const std::string& token )
27{
28        std::string discarded;
29        stream >> discarded;
30        assert( discarded == token );
31}
32
33static void remove_quotes( std::string& str )
34{
35        nv::size_t n;
36        while ( ( n = str.find('\"') ) != std::string::npos ) str.erase(n,1);
37}
38
39static void unit_quat_w( nv::quat& quat )
40{
41        float t = 1.0f - ( quat.x * quat.x ) - ( quat.y * quat.y ) - ( quat.z * quat.z );
42        quat.w = ( t < 0.0f ? 0.0f : -sqrtf(t) );
43}
44
45bool md5_loader::load( stream& source )
46{
47        reset();
48        std_stream sstream( &source );
49        std::string command;
50        size_t num_joints = 0;
51
52        // MESH data
53        dynamic_array< md5_weight > weights;
54        dynamic_array< md5_weight_info > weight_info;
55        size_t num_meshes = 0;
56
57        // MESH data
58        dynamic_array< md5_joint_info > joint_infos;
59        vector< transform >             base_frames;
60        size_t num_animated_components = 0;
61        size_t frame_rate = 0;
62        size_t num_frames = 0;
63
64        sstream >> command;
65        while ( !sstream.eof() )
66        {
67                if ( command == "MD5Version" )
68                {
69                        sstream >> m_md5_version;
70                        assert( m_md5_version == 10 );
71                }
72                else if ( command == "commandline" )
73                {
74                        next_line( sstream );
75                }
76                else if ( command == "numJoints" )
77                {
78                        sstream >> num_joints;
79                        next_line( sstream );
80                }
81                else if ( command == "numMeshes" )
82                {
83                        assert( m_type == UNKNOWN );
84                        m_type = MESH;
85                        sstream >> num_meshes;
86                        m_meshes.resize( num_meshes );
87                        num_meshes = 0;
88                }
89                else if ( command == "numFrames" )
90                {
91                        assert( m_type == UNKNOWN || m_type == ANIMATION );
92                        m_type = ANIMATION;
93                        sstream >> num_frames;
94                        next_line( sstream );
95                }
96                else if ( command == "frameRate" )
97                {
98                        assert( m_type == UNKNOWN || m_type == ANIMATION );
99                        m_type = ANIMATION;
100                        sstream >> frame_rate;
101                        next_line( sstream );
102                }
103                else if ( command == "numAnimatedComponents" )
104                {
105                        assert( m_type == UNKNOWN || m_type == ANIMATION );
106                        m_type = ANIMATION;
107                        sstream >> num_animated_components;
108                        next_line( sstream );
109                }
110                else if ( command == "joints" )
111                {
112                        assert( m_type == MESH );
113                        assert( m_nodes == nullptr );
114                        m_nodes = new mesh_nodes_data( make_name( "md5_bones") );
115                        discard( sstream, "{" );
116                        for ( size_t i = 0; i < m_nodes->size(); ++i )
117                        {
118                                std::string name;
119                                sint16 parent_id;
120                                sstream >> name >> parent_id;
121                                vec3 pos;
122                                quat orient;
123                                discard( sstream, "(" );
124                                sstream >> pos.x >> pos.y >> pos.z;
125                                discard( sstream, ")" );
126                                discard( sstream, "(" );
127                                sstream >> orient.x >> orient.y >> orient.z;
128                                unit_quat_w( orient );
129                                remove_quotes( name );
130                                data_channel_set* set = data_channel_set_creator::create_set( 0 );
131                                data_channel_set_creator access( set );
132                                access.set_parent_id( parent_id );
133                                access.set_transform( transform( pos, orient ).inverse().extract() );
134                                access.set_name( make_name( name.c_str() ) );
135                                next_line( sstream );
136                                m_nodes->push_back( set );
137                        }
138                        discard( sstream, "}" );
139                }
140                else if ( command == "mesh" )
141                {
142                        assert( m_type == MESH );
143                        data_channel_set* mesh = data_channel_set_creator::create_set( 4 );
144                        data_channel_set_creator maccess( mesh );
145
146                        uint32 num_verts   = 0;
147                        uint32 num_tris    = 0;
148                        uint32 num_weights = 0;
149
150                        discard( sstream, "{" );
151                        sstream >> command;
152                        while ( command != "}" )
153                        {
154                                if ( command == "shader" )
155                                {
156                                        std::string shader;
157                                        sstream >> shader;
158                                        remove_quotes( shader );
159                                        maccess.set_name( make_name( shader.c_str() ) );
160                                        next_line( sstream );
161                                }
162                                else if ( command == "numverts")
163                                {
164                                        sstream >> num_verts;
165
166                                        md5_vtx_t* tdata = nullptr;
167                                        {
168                                                maccess.add_channel<md5_vtx_pnt>( num_verts );
169                                                tdata = maccess.add_channel<md5_vtx_t>( num_verts ).data();
170                                                maccess.add_channel<md5_vtx_pntiw>( num_verts );
171                                        }
172                                        weight_info.resize( num_verts );
173
174                                        next_line( sstream );
175                                        std::string line;
176                                        for ( uint32 i = 0; i < num_verts; ++i )
177                                        {
178                                                size_t weight_count;
179                                                size_t start_weight;
180                                                vec2 texcoord;
181
182                                                std::getline( sstream, line );
183                                                sscanf( line.c_str(), "%*s %*u ( %f %f ) %u %u", &(texcoord.x), &(texcoord.y), &(start_weight), &(weight_count) );
184                                                weight_info[i].start_weight = start_weight;
185                                                weight_info[i].weight_count = weight_count;
186                                                tdata[i].texcoord = texcoord;
187                                        } 
188                                }
189                                else if ( command == "numtris" )
190                                {
191                                        sstream >> num_tris;
192
193                                        uint32* vtx_i = reinterpret_cast< uint32* >( maccess.add_channel< index_u32 >( num_tris * 3 ).raw_data() );
194                                        uint32 idx = 0;
195
196                                        next_line( sstream );
197                                        std::string line;
198                                        for ( uint32 i = 0; i < num_tris; ++i )
199                                        {
200                                                unsigned ti0;
201                                                unsigned ti1;
202                                                unsigned ti2;
203
204                                                std::getline( sstream, line );
205                                                sscanf( line.c_str(), "%*s %*u %u %u %u )", &(ti0), &(ti1), &(ti2));
206
207                                                vtx_i[idx++] = ti0;
208                                                vtx_i[idx++] = ti1;
209                                                vtx_i[idx++] = ti2;
210                                        }             
211
212                                }
213                                else if ( command == "numweights" )
214                                {
215                                        sstream >> num_weights;
216                                        weights.resize( num_weights );
217                                        next_line( sstream );
218                                        std::string line;
219                                        for ( uint32 i = 0; i < num_weights; ++i )
220                                        {
221                                                md5_weight weight;
222
223                                                std::getline( sstream, line );
224                                                sscanf( line.c_str(), "%*s %*u %u %f ( %f %f %f )", &(weight.joint_id), &(weight.bias), &(weight.pos.x), &(weight.pos.y), &(weight.pos.z));
225                                                weights[i] = weight;
226                                        }
227                                }
228                                else
229                                {
230                                        next_line( sstream );
231                                }
232
233                                sstream >> command;
234                        }
235
236                        prepare_mesh( m_nodes, weight_info.size(), mesh, weights.data(), weight_info.data() );
237
238                        m_meshes[ num_meshes ] = mesh;
239                        num_meshes++;
240                } // mesh
241                else if ( command == "hierarchy" )
242                {
243                        assert( m_type == ANIMATION );
244                        assert( m_nodes == nullptr );
245                        m_nodes = new mesh_nodes_data( make_name( "md5_animation" ), static_cast< nv::uint16 >( frame_rate ), static_cast< float >( num_frames ), true );
246                        joint_infos.resize( num_joints );
247
248                        discard( sstream, "{" );
249                        for ( size_t i = 0; i < m_nodes->size(); ++i )
250                        {
251                                std::string    name;
252                                sint16 parent_id;
253                                sstream >> name >> parent_id >> joint_infos[i].flags >> joint_infos[i].start_index;
254                                remove_quotes( name );
255                                data_channel_set* set = data_channel_set_creator::create_set( 1 );
256                                data_channel_set_creator access( set );
257                                access.add_channel< md5_key_t >( num_frames );
258                                access.set_name( make_name( name.c_str() ) );
259                                access.set_parent_id( parent_id );
260                                m_nodes->push_back( set );
261                                next_line( sstream );
262                        }
263                        discard( sstream, "}" );
264                }
265                else if ( command == "bounds" )
266                {
267                        assert( m_type == ANIMATION );
268                        discard( sstream, "{" );
269                        next_line( sstream );
270                        for ( size_t i = 0; i < num_frames; ++i )
271                        {
272                                //                              vec3 min;
273                                //                              vec3 max;
274                                //                              discard( sstream, "(" );
275                                //                              sstream >> min.x >> min.y >> min.z;
276                                //                              discard( sstream, ")" );
277                                //                              discard( sstream, "(" );
278                                //                              sstream >> max.x >> max.y >> max.z;
279                                //                              m_bounds.push_back( bound );
280                                next_line( sstream );
281                        }
282
283                        discard( sstream, "}" );
284                        next_line( sstream );
285                }
286                else if ( command == "baseframe" )
287                {
288                        assert( m_type == ANIMATION );
289                        discard( sstream, "{" );
290                        next_line( sstream );
291
292                        for ( size_t i = 0; i < m_nodes->size(); ++i )
293                        {
294                                transform base_frame;
295                                vec3 pos;
296                                quat orient;
297                                discard( sstream, "(" );
298                                sstream >> pos.x >> pos.y >> pos.z;
299                                discard( sstream, ")" );
300                                discard( sstream, "(" );
301                                sstream >> orient.x >> orient.y >> orient.z;
302                                next_line( sstream );
303
304                                base_frames.emplace_back( pos, orient );
305                        }
306                        discard( sstream, "}" );
307                        next_line( sstream );
308                }
309                else if ( command == "frame" )
310                {
311                        vector<float> frame;
312                        uint32 frame_id;
313                        sstream >> frame_id;
314                        discard( sstream, "{" );
315                        next_line( sstream );
316
317                        frame.reserve( num_animated_components );
318                        char buf[50];
319                        for ( size_t i = 0; i < num_animated_components; ++i )
320                        {
321                                sstream >> buf;
322                                frame.push_back( static_cast< float >( atof(buf) ) );
323                        }
324
325                        build_frame_skeleton( m_nodes, frame_id, joint_infos, base_frames, frame );
326
327                        discard( sstream, "}" );
328                        next_line( sstream );
329                }
330
331                sstream >> command;
332        }
333
334        return true;
335}
336
337bool md5_loader::prepare_mesh( mesh_nodes_data* nodes, uint32 vtx_count, data_channel_set* mdata, md5_weight* weights, md5_weight_info* weight_info )
338{
339        assert( m_type == MESH );
340        data_channel_access< md5_vtx_pnt >   pnt  ( const_cast< raw_data_channel* >( mdata->get_channel< md5_vtx_pnt >() ) );
341        data_channel_access< md5_vtx_pntiw > pntiw( const_cast< raw_data_channel* >( mdata->get_channel< md5_vtx_pntiw >() ) );
342        md5_vtx_pntiw* vtx_data = pntiw.data();
343        md5_vtx_pnt* vtcs = pnt.data();
344
345        for ( uint32 i = 0; i < vtx_count; ++i )
346        {
347                size_t start_weight = weight_info[i].start_weight;
348                size_t weight_count = weight_info[i].weight_count;
349                md5_vtx_pntiw& vdata = vtx_data[i];
350                md5_vtx_pnt& vtc = vtcs[i];
351
352                vtc.position = vec3(0);
353                vtc.normal   = vec3(0);
354                vtc.tangent  = vec3(0);
355
356                stable_sort( weights + start_weight, weights + start_weight + weight_count, [] ( const md5_weight& a, const md5_weight& b ) -> bool { return a.bias > b.bias; } );
357                //std::sort( weights + start_weight, weights + start_weight + weight_count, [](const md5_weight& a, const md5_weight& b) -> bool { return a.bias > b.bias; } );
358
359                if ( weight_count > 4 )
360                {
361                        float sum = 0.0f;
362                        for ( size_t j = 0; j < 4; ++j )
363                        {
364                                sum += weights[start_weight + j].bias;
365                        }
366                        float ratio = 1.0f / sum;
367                        for ( size_t j = 0; j < 4; ++j )
368                        {
369                                weights[start_weight + j].bias = ratio * weights[start_weight + j].bias;
370                        }
371                        weight_count = 4;
372                }
373
374                for ( int j = 0; j < 4; ++j )
375                {
376                        if ( j < int(weight_count) )
377                        {
378                                vdata.boneindex[j]  = int( weights[int(start_weight) + j].joint_id );
379                                vdata.boneweight[j] = weights[int(start_weight) + j].bias;
380                        }
381                        else
382                        {
383                                vdata.boneindex[j]  = 0;
384                                vdata.boneweight[j] = 0.0f;
385                        }
386                }
387
388                for ( size_t j = 0; j < 4; ++j )
389                {
390                        if ( j < weight_count )
391                        {
392                                md5_weight& weight             = weights[start_weight + j];
393                                const data_channel_set*  joint = (*nodes)[weight.joint_id];
394                                const transform tr = transform( joint->get_transform() ).inverse();
395                                vec3 rot_pos = tr.get_orientation() * weight.pos;
396
397                                vtc.position += ( tr.get_position() + rot_pos ) * weight.bias;
398                        }
399                }
400        }
401
402        const uint32*    idata = reinterpret_cast< uint32* >( const_cast< uint8* >( mdata->get_channel( slot::INDEX )->raw_data() ) );
403        const md5_vtx_t* tdata = mdata->get_channel_data<md5_vtx_t>();
404
405        // Prepare normals
406        uint32 tri_count = mdata->get_channel_size( slot::INDEX ) / 3;
407        for ( unsigned int i = 0; i < tri_count; ++i )
408        {
409                uint32 ti0 = idata[ i * 3 ];
410                uint32 ti1 = idata[ i * 3 + 1 ];
411                uint32 ti2 = idata[ i * 3 + 2 ];
412 
413                vec3 v1 = vtcs[ ti0 ].position;
414                vec3 v2 = vtcs[ ti1 ].position;
415                vec3 v3 = vtcs[ ti2 ].position;
416                vec3 xyz1 = v3 - v1;
417                vec3 xyz2 = v2 - v1;
418
419                vec3 normal = glm::cross( xyz1, xyz2 );
420
421                vtcs[ ti0 ].normal += normal;
422                vtcs[ ti1 ].normal += normal;
423                vtcs[ ti2 ].normal += normal;
424
425                const vec2& w1 = tdata[ ti0 ].texcoord;
426                const vec2& w2 = tdata[ ti1 ].texcoord;
427                const vec2& w3 = tdata[ ti2 ].texcoord;
428
429                vec2 st1 = w3 - w1;
430                vec2 st2 = w2 - w1;
431
432                float coef = 1.0f / (st1.x * st2.y - st2.x * st1.y);
433
434                vec3 tangent = (( xyz1 * st2.y ) - ( xyz2 * st1.y )) * coef;
435
436                vtcs[ ti0 ].tangent += tangent;
437                vtcs[ ti1 ].tangent += tangent;
438                vtcs[ ti2 ].tangent += tangent;
439        }
440
441        for ( size_t i = 0; i < vtx_count; ++i )
442        {
443                md5_vtx_pntiw& vdata = vtx_data[i];
444
445                vec3 normal  = glm::normalize( vtcs[i].normal );
446                vec3 tangent = glm::normalize( vtcs[i].tangent );
447                vtcs[i].normal   = normal;
448                vtcs[i].tangent  = tangent;
449
450                vdata.position = vtcs[i].position;
451                vdata.normal   = vec3(0);
452                vdata.tangent  = vec3(0);
453 
454                for ( int j = 0; j < 4; ++j )
455                {
456                        const data_channel_set*  joint = ( *nodes )[vdata.boneindex[j]];
457                        const transform tr = transform( joint->get_transform() ).inverse();
458                        vdata.normal  += ( normal  * tr.get_orientation() ) * vdata.boneweight[j];
459                        vdata.tangent += ( tangent * tr.get_orientation() ) * vdata.boneweight[j];
460                }
461        }
462
463        return true;
464}
465
466void md5_loader::build_frame_skeleton( mesh_nodes_data* nodes, uint32 index, const array_view<md5_joint_info>& joint_infos, const array_view<transform>& base_frames, const array_view<float>& frame_data )
467{
468        assert( m_type == ANIMATION );
469        for ( unsigned int i = 0; i < joint_infos.size(); ++i )
470        {
471                unsigned int j = 0;
472
473                const md5_joint_info& jinfo = joint_infos[i];
474                const data_channel_set* joint = (*nodes)[i];
475                int parent_id         = joint->get_parent_id();
476
477                vec3 pos    = base_frames[i].get_position();
478                quat orient = base_frames[i].get_orientation();
479                if ( jinfo.flags & 1 )  pos.x    = frame_data[ jinfo.start_index + j++ ];
480                if ( jinfo.flags & 2 )  pos.y    = frame_data[ jinfo.start_index + j++ ];
481                if ( jinfo.flags & 4 )  pos.z    = frame_data[ jinfo.start_index + j++ ];
482                if ( jinfo.flags & 8 )  orient.x = frame_data[ jinfo.start_index + j++ ];
483                if ( jinfo.flags & 16 ) orient.y = frame_data[ jinfo.start_index + j++ ];
484                if ( jinfo.flags & 32 ) orient.z = frame_data[ jinfo.start_index + j++ ];
485                unit_quat_w( orient );
486
487                if ( parent_id >= 0 ) // Has a parent joint
488                {
489                        const data_channel_set* pjoint = ( *nodes )[i];
490                        const transform* ptv = reinterpret_cast< const transform* >( pjoint->get_channel(0)->raw_data() );
491                        transform ptr;
492                        if ( pjoint->get_channel(0)->size() > index ) ptr = ptv[ index ];
493                        vec3 rot_pos = ptr.get_orientation() * pos;
494
495                        pos    = ptr.get_position() + rot_pos;
496                        orient = ptr.get_orientation() * orient;
497
498                        orient = glm::normalize( orient );
499                }
500
501                reinterpret_cast< transform* >( const_cast< uint8* >( joint->get_channel(0)->raw_data() ) )[index] = transform( pos, orient );
502        }
503}
504
505data_channel_set* nv::md5_loader::release_mesh_data( size_t index )
506{
507        data_channel_set* result = m_meshes[ index ];
508        m_meshes[ index ] = nullptr;
509        return result;
510}
511
512mesh_nodes_data* nv::md5_loader::release_mesh_nodes_data( size_t )
513{
514        mesh_nodes_data* nodes = m_nodes;
515        m_nodes = nullptr;
516        return nodes;
517}
518
519mesh_data_pack* nv::md5_loader::release_mesh_data_pack()
520{
521        uint32 size = m_meshes.size();
522        data_channel_set* meshes = data_channel_set_creator::create_set_array( size, 4 );
523        for ( uint32 i = 0; i < size; ++i )
524        {
525                meshes[i] = move( *m_meshes[i] );
526                delete m_meshes[i];
527                m_meshes[i] = nullptr;
528        }
529        return new mesh_data_pack( size, meshes, release_mesh_nodes_data() );
530}
531
532
533nv::md5_loader::~md5_loader()
534{
535        reset();
536}
537
538void nv::md5_loader::reset()
539{
540        if ( m_nodes ) delete m_nodes;
541        for ( auto m : m_meshes ) { if (m) delete m; }
542        m_meshes.resize(0);
543        m_nodes = nullptr;
544}
545
Note: See TracBrowser for help on using the repository browser.