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

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