source: trunk/src/formats/md5_loader.cc @ 287

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