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

Last change on this file since 225 was 224, checked in by epyon, 11 years ago
  • universal mesh format
  • removed keyframed_mesh_data
File size: 16.8 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        std::string discarded;
26        stream >> discarded;
27        assert( discarded == token );
28}
29
30
31static void remove_quotes( std::string& str )
32{
33        size_t n;
34        while ( ( n = str.find('\"') ) != std::string::npos ) str.erase(n,1);
35}
36
37static void unit_quat_w( glm::quat& quat )
38{
39        float t = 1.0f - ( quat.x * quat.x ) - ( quat.y * quat.y ) - ( quat.z * quat.z );
40        quat.w = ( t < 0.0f ? 0.0f : -sqrtf(t) );
41}
42
43bool md5_loader::load( stream& source )
44{
45        std_stream sstream( &source );
46        std::string command;
47
48        sstream >> command;
49        while ( !sstream.eof() )
50        {
51                if ( command == "MD5Version" )
52                {
53                        sstream >> m_md5_version;
54                        assert( m_md5_version == 10 );
55                }
56                else if ( command == "commandline" )
57                {
58                        next_line( sstream );
59                }
60                else if ( command == "numJoints" )
61                {
62                        sstream >> m_num_joints;
63                        m_joints.reserve( m_num_joints );
64                }
65                else if ( command == "numMeshes" )
66                {
67                        sstream >> m_num_meshes;
68                        m_meshes.reserve( m_num_meshes );
69                }
70                else if ( command == "joints" )
71                {
72                        discard( sstream, "{" );
73                        md5_joint joint;
74                        for ( size_t i = 0; i < m_num_joints; ++i )
75                        {
76                                sstream >> joint.name >> joint.parent_id;
77                                discard( sstream, "(" );
78                                sstream >> joint.pos.x >> joint.pos.y >> joint.pos.z;
79                                discard( sstream, ")" );
80                                discard( sstream, "(" );
81                                sstream >> joint.orient.x >> joint.orient.y >> joint.orient.z;
82                                remove_quotes( joint.name );
83                                unit_quat_w( joint.orient );
84                                m_joints.push_back( joint );
85                                next_line( sstream );
86                        }
87                        discard( sstream, "}" );
88                }
89                else if ( command == "mesh" )
90                {
91                        // TODO : efficiency dammit
92                        md5_mesh* mesh = new md5_mesh;
93                        int num_verts, num_tris, num_weights;
94
95                        discard( sstream, "{" );
96                        sstream >> command;
97                        while ( command != "}" )
98                        {
99                                if ( command == "shader" )
100                                {
101                                        sstream >> mesh->shader;
102                                        remove_quotes( mesh->shader );
103                                        // texturePath.replace_extension( ".tga" );
104                                        next_line( sstream );
105                                }
106                                else if ( command == "numverts")
107                                {
108                                        sstream >> num_verts;
109                                        next_line( sstream );
110                                        for ( int i = 0; i < num_verts; ++i )
111                                        {
112                                                md5_vertex vert;
113                                                std::string ignore;
114                                                discard( sstream, "vert" );
115                                                sstream >> ignore;
116                                                discard( sstream, "(" );
117                                                sstream >> vert.texcoord.x >> vert.texcoord.y;
118                                                discard( sstream, ")" );
119                                                sstream >> vert.start_weight >> vert.weight_count;
120                                                next_line( sstream );
121
122                                                mesh->verts.push_back(vert);
123                                                mesh->texcoord_buffer.push_back( vert.texcoord );
124                                        } 
125                                }
126                                else if ( command == "numtris" )
127                                {
128                                        sstream >> num_tris;
129                                        next_line( sstream );
130                                        for ( int i = 0; i < num_tris; ++i )
131                                        {
132                                                md5_triangle tri;
133                                                std::string ignore;
134                                                discard( sstream, "tri" );
135                                                sstream >> ignore >> tri.indices[0] >> tri.indices[1] >> tri.indices[2];
136                                                next_line( sstream );
137
138                                                mesh->tris.push_back( tri );
139                                                mesh->index_buffer.push_back( (uint32)tri.indices[0] );
140                                                mesh->index_buffer.push_back( (uint32)tri.indices[1] );
141                                                mesh->index_buffer.push_back( (uint32)tri.indices[2] );
142                                        }             
143                                }
144                                else if ( command == "numweights" )
145                                {
146                                        sstream >> num_weights;
147                                        next_line( sstream );
148                                        for ( int i = 0; i < num_weights; ++i )
149                                        {
150                                                md5_weight weight;
151                                                std::string ignore;
152                                                discard( sstream, "weight" );
153                                                sstream >> ignore >> weight.joint_id >> weight.bias;
154                                                discard( sstream, "(" );
155                                                sstream >> weight.pos.x >> weight.pos.y >> weight.pos.z;
156                                                discard( sstream, ")" );
157                                                next_line( sstream );
158                                                mesh->weights.push_back(weight);
159                                        }
160                                }
161                                else
162                                {
163                                        next_line( sstream );
164                                }
165
166                                sstream >> command;
167                        }
168
169                        prepare_mesh( mesh );
170                        prepare_normals( mesh );
171
172                        m_meshes.push_back(mesh);
173                }
174                sstream >> command;
175        }
176
177        assert( m_joints.size() == m_num_joints );
178        assert( m_meshes.size() == m_num_meshes );
179        return true;
180}
181
182bool md5_loader::prepare_mesh( md5_mesh* mesh )
183{
184        mesh->position_buffer.clear();
185        mesh->texcoord_buffer.clear();
186
187        for ( uint32 i = 0; i < mesh->verts.size(); ++i )
188        {
189                md5_vertex& vert = mesh->verts[i];
190
191                vert.position = glm::vec3(0);
192                vert.normal   = glm::vec3(0);
193                vert.tangent  = glm::vec3(0);
194
195                for ( size_t j = 0; j < vert.weight_count; ++j )
196                {
197                        md5_weight& weight = mesh->weights[vert.start_weight + j];
198                        md5_joint&  joint  = m_joints[weight.joint_id];
199
200                        glm::vec3 rot_pos = joint.orient * weight.pos;
201
202                        vert.position += ( joint.pos + rot_pos ) * weight.bias;
203                }
204
205                mesh->position_buffer.push_back(vert.position);
206                mesh->texcoord_buffer.push_back(vert.texcoord);
207        }
208
209        return true;
210}
211
212bool md5_loader::prepare_normals( md5_mesh* mesh )
213{
214        mesh->normal_buffer.clear();
215
216        for ( unsigned int i = 0; i < mesh->tris.size(); ++i )
217        {
218                const md5_triangle& tri = mesh->tris[i];
219                glm::vec3 v1 = mesh->verts[ tri.indices[0] ].position;
220                glm::vec3 v2 = mesh->verts[ tri.indices[1] ].position;
221                glm::vec3 v3 = mesh->verts[ tri.indices[2] ].position;
222                glm::vec3 xyz1 = v3 - v1;
223                glm::vec3 xyz2 = v2 - v1;
224
225                glm::vec3 normal = glm::cross( xyz1, xyz2 );
226
227                mesh->verts[ tri.indices[0] ].normal += normal;
228                mesh->verts[ tri.indices[1] ].normal += normal;
229                mesh->verts[ tri.indices[2] ].normal += normal;
230
231                const vec2& w1 = mesh->verts[ tri.indices[0] ].texcoord;
232                const vec2& w2 = mesh->verts[ tri.indices[1] ].texcoord;
233                const vec2& w3 = mesh->verts[ tri.indices[2] ].texcoord;
234
235                vec2 st1 = w3 - w1;
236                vec2 st2 = w2 - w1;
237
238                float coef = 1.0f / (st1.x * st2.y - st2.x * st1.y);
239
240                vec3 tangent = (( xyz1 * st2.y ) - ( xyz2 * st1.y )) * coef;
241
242                mesh->verts[ tri.indices[0] ].tangent += tangent;
243                mesh->verts[ tri.indices[1] ].tangent += tangent;
244                mesh->verts[ tri.indices[2] ].tangent += tangent;
245        }
246
247        for ( size_t i = 0; i < mesh->verts.size(); ++i )
248        {
249                md5_vertex& vert = mesh->verts[i];
250
251                glm::vec3 normal  = glm::normalize( vert.normal );
252                glm::vec3 tangent = glm::normalize( vert.tangent );
253                mesh->normal_buffer.push_back( normal );
254                mesh->tangent_buffer.push_back( tangent );
255
256                vert.normal  = glm::vec3(0);
257                vert.tangent = glm::vec3(0);
258
259                for ( size_t j = 0; j < vert.weight_count; ++j )
260                {
261                        const md5_weight& weight = mesh->weights[vert.start_weight + j];
262                        const md5_joint&  joint  = m_joints[weight.joint_id];
263                        vert.normal  += ( normal  * joint.orient ) * weight.bias;
264                        vert.tangent += ( tangent * joint.orient ) * weight.bias;
265                }
266        }
267
268        return true;
269}
270
271mesh_data* nv::md5_loader::release_submesh_data( uint32 mesh_id )
272{
273        mesh_data_creator m;
274        m.get_positions().assign( m_meshes[mesh_id]->position_buffer.begin(), m_meshes[mesh_id]->position_buffer.begin() );
275        m.get_normals()  .assign( m_meshes[mesh_id]->normal_buffer.begin(),   m_meshes[mesh_id]->normal_buffer.begin() );
276        m.get_tangents() .assign( m_meshes[mesh_id]->tangent_buffer.begin(),  m_meshes[mesh_id]->tangent_buffer.begin() );
277        m.get_texcoords().assign( m_meshes[mesh_id]->texcoord_buffer.begin(), m_meshes[mesh_id]->texcoord_buffer.begin() );
278        m.get_indices()  .assign( m_meshes[mesh_id]->index_buffer.begin(),    m_meshes[mesh_id]->index_buffer.begin() );
279
280        return m.release();
281}
282
283/*
284mesh* md5_loader::release_mesh()
285{
286        mesh* m = new mesh();
287        auto position = m->add_attribute< vec3 >( "nv_position" );
288        auto normal   = m->add_attribute< vec3 >( "nv_normal" );
289        auto texcoord = m->add_attribute< vec2 >( "nv_texcoord" );
290        auto tangent  = m->add_attribute< vec3 >( "nv_tangent" );
291        auto indices  = m->add_indices< uint32 >();
292
293        position->get().assign( m_meshes[0].position_buffer.begin(), m_meshes[0].position_buffer.end() );
294        normal  ->get().assign( m_meshes[0].normal_buffer.begin(),   m_meshes[0].normal_buffer.end() );
295        texcoord->get().assign( m_meshes[0].texcoord_buffer.begin(), m_meshes[0].texcoord_buffer.end() );
296        tangent ->get().assign( m_meshes[0].tangent_buffer.begin(),  m_meshes[0].tangent_buffer.end() );
297        indices ->get().assign( m_meshes[0].index_buffer.begin(),    m_meshes[0].index_buffer.end() );
298
299        m_size = m_meshes[0].index_buffer.size();
300        return m;
301}
302*/
303
304md5_animation::md5_animation()
305        : m_md5_version( 0 )
306        , m_num_frames( 0 )
307        , m_num_joints( 0 )
308        , m_frame_rate( 0 )
309        , m_num_animated_components( 0 )
310        , m_anim_duration( 0 )
311        , m_frame_duration( 0 )
312        , m_anim_time( 0 )
313{
314
315}
316
317md5_animation::~md5_animation()
318{
319
320}
321
322bool md5_animation::load_animation( stream& source )
323{
324        m_joint_infos.clear();
325        m_bounds.clear();
326        m_base_frames.clear();
327        m_frames.clear();
328        m_animated_skeleton.joints.clear();
329        m_num_frames = 0;
330
331        std_stream sstream( &source );
332        std::string command;
333
334        sstream >> command;
335        while ( !sstream.eof() )
336        {
337                if ( command == "MD5Version" )
338                {
339                        sstream >> m_md5_version;
340                        assert( m_md5_version == 10 );
341                }
342                else if ( command == "commandline" )
343                {
344                        next_line( sstream );
345                }
346                else if ( command == "numFrames" )
347                {
348                        sstream >> m_num_frames;
349                        next_line( sstream );
350                }
351                else if ( command == "numJoints" )
352                {
353                        sstream >> m_num_joints;
354                        next_line( sstream );
355                }
356                else if ( command == "frameRate" )
357                {
358                        sstream >> m_frame_rate;
359                        next_line( sstream );
360                }
361                else if ( command == "numAnimatedComponents" )
362                {
363                        sstream >> m_num_animated_components;
364                        next_line( sstream );
365                }
366                else if ( command == "hierarchy" )
367                {
368                        discard( sstream, "{" );
369                        for ( size_t i = 0; i < m_num_joints; ++i )
370                        {
371                                md5_joint_info joint;
372                                sstream >> joint.name >> joint.parent_id >> joint.flags >> joint.start_index;
373                                remove_quotes( joint.name );
374                                m_joint_infos.push_back( joint );
375                                next_line( sstream );
376                        }
377                        discard( sstream, "}" );
378                }
379                else if ( command == "bounds" )
380                {
381                        discard( sstream, "{" );
382                        next_line( sstream );
383                        for ( size_t i = 0; i < m_num_frames; ++i )
384                        {
385                                md5_bound bound;
386                                discard( sstream, "(" );
387                                sstream >> bound.min.x >> bound.min.y >> bound.min.z;
388                                discard( sstream, ")" );
389                                discard( sstream, "(" );
390                                sstream >> bound.max.x >> bound.max.y >> bound.max.z;
391
392                                m_bounds.push_back( bound );
393
394                                next_line( sstream );
395                        }
396
397                        discard( sstream, "}" );
398                        next_line( sstream );
399                }
400                else if ( command == "baseframe" )
401                {
402                        discard( sstream, "{" );
403                        next_line( sstream );
404
405                        for ( size_t i = 0; i < m_num_joints; ++i )
406                        {
407                                md5_base_frame base_frame;
408                                discard( sstream, "(" );
409                                sstream >> base_frame.pos.x >> base_frame.pos.y >> base_frame.pos.z;
410                                discard( sstream, ")" );
411                                discard( sstream, "(" );
412                                sstream >> base_frame.orient.x >> base_frame.orient.y >> base_frame.orient.z;
413                                next_line( sstream );
414
415                                m_base_frames.push_back( base_frame );
416                        }
417                        discard( sstream, "}" );
418                        next_line( sstream );
419                }
420                else if ( command == "frame" )
421                {
422                        md5_frame_data frame;
423                        sstream >> frame.frame_id;
424                        discard( sstream, "{" );
425                        next_line( sstream );
426
427                        for ( size_t i = 0; i < m_num_animated_components; ++i )
428                        {
429                                float frameData;
430                                sstream >> frameData;
431                                frame.frame_data.push_back(frameData);
432                        }
433
434                        m_frames.push_back(frame);
435
436                        build_frame_skeleton( m_skeletons, m_joint_infos, m_base_frames, frame );
437
438                        discard( sstream, "}" );
439                        next_line( sstream );
440                }
441
442                sstream >> command;
443        }
444
445        m_animated_skeleton.joints.assign( m_num_joints, md5_skeleton_joint() );
446
447        m_frame_duration = 1.0f / (float)m_frame_rate;
448        m_anim_duration = ( m_frame_duration * (float)m_num_frames );
449        m_anim_time = 0.0f;
450
451        assert( m_joint_infos.size() == m_num_joints );
452        assert( m_bounds.size()      == m_num_frames );
453        assert( m_base_frames.size() == m_num_joints );
454        assert( m_frames.size()      == m_num_frames );
455        assert( m_skeletons.size()   == m_num_frames );
456
457        return true;
458}
459
460void md5_animation::update( float delta_time )
461{
462        if ( m_num_frames < 1 ) return;
463
464        m_anim_time += delta_time;
465
466        while ( m_anim_time > m_anim_duration ) m_anim_time -= m_anim_duration;
467        while ( m_anim_time < 0.0f ) m_anim_time += m_anim_duration;
468
469        float frame_num = m_anim_time * (float)m_frame_rate;
470        size_t frame0 = (size_t)floorf( frame_num );
471        size_t frame1 = (size_t)ceilf( frame_num );
472        frame0 = frame0 % m_num_frames;
473        frame1 = frame1 % m_num_frames;
474
475        float interpolate = fmodf( m_anim_time, m_frame_duration ) / m_frame_duration;
476
477        interpolate_skeletons( m_animated_skeleton, m_skeletons[frame0], m_skeletons[frame1], interpolate );
478}
479
480void md5_animation::build_frame_skeleton( md5_frame_skeleton_list& skeletons, const md5_joint_info_list& joint_infos, const md5_base_frame_list& base_frames, const md5_frame_data& frame_data )
481{
482        md5_frame_skeleton skeleton;
483
484        for ( unsigned int i = 0; i < joint_infos.size(); ++i )
485        {
486                unsigned int j = 0;
487
488                const md5_joint_info& jinfo = joint_infos[i];
489                md5_skeleton_joint animated_joint = base_frames[i];
490
491                animated_joint.parent = jinfo.parent_id;
492
493                if ( jinfo.flags & 1 )  animated_joint.pos.x    = frame_data.frame_data[ jinfo.start_index + j++ ];
494                if ( jinfo.flags & 2 )  animated_joint.pos.y    = frame_data.frame_data[ jinfo.start_index + j++ ];
495                if ( jinfo.flags & 4 )  animated_joint.pos.z    = frame_data.frame_data[ jinfo.start_index + j++ ];
496                if ( jinfo.flags & 8 )  animated_joint.orient.x = frame_data.frame_data[ jinfo.start_index + j++ ];
497                if ( jinfo.flags & 16 ) animated_joint.orient.y = frame_data.frame_data[ jinfo.start_index + j++ ];
498                if ( jinfo.flags & 32 ) animated_joint.orient.z = frame_data.frame_data[ jinfo.start_index + j++ ];
499
500                unit_quat_w( animated_joint.orient );
501
502                if ( animated_joint.parent >= 0 ) // Has a parent joint
503                {
504                        md5_skeleton_joint& pjoint = skeleton.joints[static_cast< size_t >( animated_joint.parent ) ];
505                        glm::vec3 rot_pos = pjoint.orient * animated_joint.pos;
506
507                        animated_joint.pos    = pjoint.pos + rot_pos;
508                        animated_joint.orient = pjoint.orient * animated_joint.orient;
509
510                        animated_joint.orient = glm::normalize( animated_joint.orient );
511                }
512
513                skeleton.joints.push_back( animated_joint );
514        }
515
516        skeletons.push_back( skeleton );
517}
518
519void md5_animation::interpolate_skeletons( md5_frame_skeleton& final_skeleton, const md5_frame_skeleton& skeleton0, const md5_frame_skeleton& skeleton1, float interpolate )
520{
521        for ( size_t i = 0; i < m_num_joints; ++i )
522        {
523                md5_skeleton_joint& final_joint = final_skeleton.joints[i];
524                const md5_skeleton_joint& joint0 = skeleton0.joints[i];
525                const md5_skeleton_joint& joint1 = skeleton1.joints[i];
526
527                final_joint.parent = joint0.parent;
528
529                final_joint.orient = glm::slerp( joint0.orient, joint1.orient, interpolate );
530                final_joint.pos    = glm::mix( joint0.pos, joint1.pos, interpolate );
531        }
532}
533
534bool md5_loader::check_animation( const md5_animation& animation ) const
535{
536        if ( m_num_joints != animation.get_num_joints() )
537        {
538                return false;
539        }
540
541        for ( uint32 i = 0; i < m_joints.size(); ++i )
542        {
543                const md5_joint& mjoint = m_joints[i];
544                const md5_animation::md5_joint_info& ajoint = animation.get_joint_info( i );
545
546                if ( mjoint.name != ajoint.name || mjoint.parent_id != ajoint.parent_id )
547                {
548                        return false;
549                }
550        }
551
552        return true;
553}
554
555bool md5_loader::prepare_animated_mesh( md5_mesh* mesh, const md5_animation::md5_frame_skeleton& skel )
556{
557        for ( unsigned int i = 0; i < mesh->verts.size(); ++i )
558        {
559                const md5_vertex& vert = mesh->verts[i];
560                glm::vec3& pos     = mesh->position_buffer[i];
561                glm::vec3& normal  = mesh->normal_buffer[i];
562                glm::vec3& tangent = mesh->tangent_buffer[i];
563
564                pos     = glm::vec3(0);
565                normal  = glm::vec3(0);
566                tangent = glm::vec3(0);
567
568                for ( size_t j = 0; j < vert.weight_count; ++j )
569                {
570                        const md5_weight& weight = mesh->weights[vert.start_weight + j];
571                        const md5_animation::md5_skeleton_joint& joint = skel.joints[weight.joint_id];
572
573                        glm::vec3 rot_pos = joint.orient * weight.pos;
574                        pos += ( joint.pos + rot_pos ) * weight.bias;
575
576                        normal  += ( joint.orient * vert.normal  ) * weight.bias;
577                        tangent += ( joint.orient * vert.tangent ) * weight.bias;
578                }
579        }
580        return true;
581}
582
583void md5_loader::apply( const md5_animation& animation )
584{
585        const md5_animation::md5_frame_skeleton& skeleton = animation.get_skeleton();
586
587        for ( unsigned int i = 0; i < m_meshes.size(); ++i )
588        {
589                prepare_animated_mesh( m_meshes[i], skeleton );
590        }
591}
592
593size_t nv::md5_loader::get_size()
594{
595        return m_size;
596}
Note: See TracBrowser for help on using the repository browser.