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

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