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

Last change on this file since 392 was 392, checked in by epyon, 10 years ago
  • massive shift towards nova STL
  • include cleanups


File size: 15.0 KB
RevLine 
[319]1// Copyright (C) 2012-2014 ChaosForge Ltd
[190]2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/formats/md5_loader.hh"
6
[319]7#include "nv/core/logging.hh"
[392]8#include "nv/stl/vector.hh"
[190]9#include "nv/io/std_stream.hh"
10
11using namespace nv;
12
13static void next_line( std::istream& stream )
14{
[367]15        stream.ignore( 1024*1024, '\n' );
[190]16}
17
18static inline void discard( std::istream& stream, const std::string& token )
19{
20        std::string discarded;
21        stream >> discarded;
22        assert( discarded == token );
23}
24
25static void remove_quotes( std::string& str )
26{
[376]27        nv::size_t n;
[190]28        while ( ( n = str.find('\"') ) != std::string::npos ) str.erase(n,1);
29}
30
[198]31static void unit_quat_w( glm::quat& quat )
[190]32{
33        float t = 1.0f - ( quat.x * quat.x ) - ( quat.y * quat.y ) - ( quat.z * quat.z );
34        quat.w = ( t < 0.0f ? 0.0f : -sqrtf(t) );
35}
36
37bool md5_loader::load( stream& source )
38{
[289]39        reset();
[190]40        std_stream sstream( &source );
41        std::string command;
[289]42        mesh_node_data* nodes = nullptr;
43        size_t num_joints = 0;
44
45        // MESH data
[261]46        dynamic_array< md5_weight > weights;
47        dynamic_array< md5_weight_info > weight_info;
[289]48        size_t num_meshes = 0;
[190]49
[289]50        // MESH data
[383]51        dynamic_array< md5_joint_info > joint_infos;
52        vector< transform >             base_frames;
[289]53        size_t num_animated_components = 0;
54        size_t frame_rate = 0;
55        size_t num_frames = 0;
56
[190]57        sstream >> command;
58        while ( !sstream.eof() )
59        {
60                if ( command == "MD5Version" )
61                {
62                        sstream >> m_md5_version;
63                        assert( m_md5_version == 10 );
64                }
65                else if ( command == "commandline" )
66                {
67                        next_line( sstream );
68                }
69                else if ( command == "numJoints" )
70                {
[289]71                        sstream >> num_joints;
72                        next_line( sstream );
[190]73                }
74                else if ( command == "numMeshes" )
75                {
[289]76                        assert( m_type == UNKNOWN );
77                        m_type = MESH;
78                        sstream >> num_meshes;
79                        m_meshes.resize( num_meshes );
80                        num_meshes = 0;
[190]81                }
[289]82                else if ( command == "numFrames" )
83                {
84                        assert( m_type == UNKNOWN || m_type == ANIMATION );
85                        m_type = ANIMATION;
86                        sstream >> num_frames;
87                        next_line( sstream );
88                }
89                else if ( command == "frameRate" )
90                {
91                        assert( m_type == UNKNOWN || m_type == ANIMATION );
92                        m_type = ANIMATION;
93                        sstream >> frame_rate;
94                        next_line( sstream );
95                }
96                else if ( command == "numAnimatedComponents" )
97                {
98                        assert( m_type == UNKNOWN || m_type == ANIMATION );
99                        m_type = ANIMATION;
100                        sstream >> num_animated_components;
101                        next_line( sstream );
102                }
[190]103                else if ( command == "joints" )
104                {
[289]105                        assert( m_type == MESH );
106                        assert( m_nodes == nullptr );
107                        nodes = new mesh_node_data[ num_joints ];
108                        m_nodes = new mesh_nodes_data( "md5_bones", num_joints, nodes );
[190]109                        discard( sstream, "{" );
[289]110                        for ( size_t i = 0; i < m_nodes->get_count(); ++i )
[190]111                        {
[289]112                                sstream >> nodes[i].name >> nodes[i].parent_id;
113                                vec3 pos;
114                                quat orient;
[190]115                                discard( sstream, "(" );
[289]116                                sstream >> pos.x >> pos.y >> pos.z;
[190]117                                discard( sstream, ")" );
118                                discard( sstream, "(" );
[289]119                                sstream >> orient.x >> orient.y >> orient.z;
120                                unit_quat_w( orient );
121                                remove_quotes( nodes[i].name );
122                                nodes[i].target_id       = -1;
123                                nodes[i].parent_id       = -1;
124                                nodes[i].transform       = transform( pos, orient ).inverse().extract();
125                                nodes[i].data            = nullptr;
[190]126                                next_line( sstream );
127                        }
128                        discard( sstream, "}" );
129                }
130                else if ( command == "mesh" )
131                {
[289]132                        assert( m_type == MESH );
[287]133                        mesh_data* mesh = new mesh_data("md5_mesh");
[239]134
[323]135                        uint32 num_verts   = 0;
136                        uint32 num_tris    = 0;
137                        uint32 num_weights = 0;
[190]138
139                        discard( sstream, "{" );
140                        sstream >> command;
141                        while ( command != "}" )
142                        {
143                                if ( command == "shader" )
144                                {
[287]145                                        std::string shader;
146                                        sstream >> shader;
147                                        remove_quotes( shader );
[190]148                                        next_line( sstream );
149                                }
150                                else if ( command == "numverts")
151                                {
152                                        sstream >> num_verts;
[239]153
[287]154                                        md5_vtx_t* tdata = nullptr;
[239]155                                        {
156                                                mesh_raw_channel* ch_pnt = mesh_raw_channel::create<md5_vtx_pnt>( num_verts );
157                                                mesh_raw_channel* ch_t   = mesh_raw_channel::create<md5_vtx_t>( num_verts );
[287]158                                                mesh_raw_channel* ch_pntiw = mesh_raw_channel::create<md5_vtx_pntiw>( num_verts );
159                                                tdata = (md5_vtx_t*)ch_t->data;
[239]160                                                mesh->add_channel( ch_pnt );
161                                                mesh->add_channel( ch_t );
[287]162                                                // TODO: hack to prevent rendering
163                                                ch_pntiw->count = 0;
164                                                mesh->add_channel( ch_pntiw );
[239]165                                        }
[259]166                                        weight_info.resize( num_verts );
[239]167
[190]168                                        next_line( sstream );
[226]169                                        std::string line;
[323]170                                        for ( uint32 i = 0; i < num_verts; ++i )
[190]171                                        {
[239]172                                                size_t weight_count;
173                                                size_t start_weight;
174                                                vec2 texcoord;
[190]175
[226]176                                                std::getline( sstream, line );
[239]177                                                sscanf( line.c_str(), "%*s %*u ( %f %f ) %u %u", &(texcoord.x), &(texcoord.y), &(start_weight), &(weight_count) );
[259]178                                                weight_info[i].start_weight = start_weight;
179                                                weight_info[i].weight_count = weight_count;
[287]180                                                tdata[i].texcoord = texcoord;
[190]181                                        } 
182                                }
183                                else if ( command == "numtris" )
184                                {
185                                        sstream >> num_tris;
[239]186
[280]187                                        mesh_raw_channel* ch_i = mesh_raw_channel::create_index<uint32>( num_tris * 3 );
[239]188                                        uint32* vtx_i                = (uint32*)ch_i->data;
189                                        uint32 idx = 0;
[280]190                                        mesh->add_channel( ch_i );
[239]191
[190]192                                        next_line( sstream );
[226]193                                        std::string line;
[323]194                                        for ( uint32 i = 0; i < num_tris; ++i )
[190]195                                        {
[239]196                                                size_t ti0;
197                                                size_t ti1;
198                                                size_t ti2;
[190]199
[226]200                                                std::getline( sstream, line );
[239]201                                                sscanf( line.c_str(), "%*s %*u %u %u %u )", &(ti0), &(ti1), &(ti2));
[226]202
[239]203                                                vtx_i[idx++] = (uint32)ti0;
204                                                vtx_i[idx++] = (uint32)ti1;
205                                                vtx_i[idx++] = (uint32)ti2;
[190]206                                        }             
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
[289]231                        prepare_mesh( nodes, weight_info.size(), mesh, weights.data(), weight_info.data() );
[190]232
[289]233                        m_meshes[ num_meshes ] = mesh;
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 ];
241                        m_nodes = new mesh_nodes_data( "md5_animation", num_joints, nodes, (nv::uint16)frame_rate, (float)num_frames, true );
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;
252                                nodes[i].data      = new key_data;
253                                nodes[i].data->add_channel( key_raw_channel::create< md5_key_t >( num_frames ) );
254                                next_line( sstream );
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;
315                                frame.push_back((float)atof(buf));
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
[289]330bool md5_loader::prepare_mesh( mesh_node_data* nodes, uint32 vtx_count, mesh_data* mdata, md5_weight* weights, md5_weight_info* weight_info )
[190]331{
[289]332        assert( m_type == MESH );
[287]333        md5_vtx_pnt* vtcs = (md5_vtx_pnt*)mdata->get_channel< md5_vtx_pnt >()->data;
334        md5_vtx_pntiw* vtx_data = (md5_vtx_pntiw*)mdata->get_channel< md5_vtx_pntiw >()->data;
[190]335
[239]336        for ( uint32 i = 0; i < vtx_count; ++i )
[190]337        {
[259]338                size_t start_weight = weight_info[i].start_weight;
339                size_t weight_count = weight_info[i].weight_count;
[287]340                md5_vtx_pntiw& vdata = vtx_data[i];
[239]341                md5_vtx_pnt& vtc = vtcs[i];
[190]342
[239]343                vtc.position = glm::vec3(0);
344                vtc.normal   = glm::vec3(0);
345                vtc.tangent  = glm::vec3(0);
[190]346
[374]347                stable_sort( weights + start_weight, weights + start_weight + weight_count, [] ( const md5_weight& a, const md5_weight& b ) -> bool { return a.bias > b.bias; } );
348                //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]349
[259]350                if ( weight_count > 4 )
[258]351                {
352                        float sum = 0.0f;
353                        for ( size_t j = 0; j < 4; ++j )
354                        {
[259]355                                sum += weights[start_weight + j].bias;
[258]356                        }
357                        float ratio = 1.0f / sum;
358                        for ( size_t j = 0; j < 4; ++j )
359                        {
[259]360                                weights[start_weight + j].bias = ratio * weights[start_weight + j].bias;
[258]361                        }
[259]362                        weight_count = 4;
[258]363                }
364
[259]365                for ( size_t j = 0; j < 4; ++j )
[190]366                {
[259]367                        if ( j < weight_count )
368                        {
[323]369                                vdata.boneindex[j]  = (int)weights[start_weight + j].joint_id;
[259]370                                vdata.boneweight[j] = weights[start_weight + j].bias;
371                        }
372                        else
373                        {
374                                vdata.boneindex[j]  = 0;
375                                vdata.boneweight[j] = 0.0f;
376                        }
377                }
[190]378
[259]379                for ( size_t j = 0; j < 4; ++j )
380                {
381                        if ( j < weight_count )
382                        {
[289]383                                md5_weight& weight           = weights[start_weight + j];
384                                const mesh_node_data&  joint = nodes[weight.joint_id];
385                                const transform tr = transform( joint.transform ).inverse();
386                                glm::vec3 rot_pos = tr.get_orientation() * weight.pos;
[190]387
[289]388                                vtc.position += ( tr.get_position() + rot_pos ) * weight.bias;
[259]389                        }
[190]390                }
391        }
392
[287]393        const uint32*    idata = (uint32*)mdata->get_index_channel()->data;
394        const md5_vtx_t* tdata = mdata->get_channel_data<md5_vtx_t>();
395
[239]396        // Prepare normals
397        uint32 tri_count = mdata->get_count() / 3;
398        for ( unsigned int i = 0; i < tri_count; ++i )
[190]399        {
[287]400                uint32 ti0 = idata[ i * 3 ];
401                uint32 ti1 = idata[ i * 3 + 1 ];
402                uint32 ti2 = idata[ i * 3 + 2 ];
[239]403 
404                glm::vec3 v1 = vtcs[ ti0 ].position;
405                glm::vec3 v2 = vtcs[ ti1 ].position;
406                glm::vec3 v3 = vtcs[ ti2 ].position;
[190]407                glm::vec3 xyz1 = v3 - v1;
408                glm::vec3 xyz2 = v2 - v1;
409
410                glm::vec3 normal = glm::cross( xyz1, xyz2 );
411
[239]412                vtcs[ ti0 ].normal += normal;
413                vtcs[ ti1 ].normal += normal;
414                vtcs[ ti2 ].normal += normal;
[190]415
[287]416                const vec2& w1 = tdata[ ti0 ].texcoord;
417                const vec2& w2 = tdata[ ti1 ].texcoord;
418                const vec2& w3 = tdata[ ti2 ].texcoord;
[190]419
420                vec2 st1 = w3 - w1;
421                vec2 st2 = w2 - w1;
422
423                float coef = 1.0f / (st1.x * st2.y - st2.x * st1.y);
424
425                vec3 tangent = (( xyz1 * st2.y ) - ( xyz2 * st1.y )) * coef;
426
[239]427                vtcs[ ti0 ].tangent += tangent;
428                vtcs[ ti1 ].tangent += tangent;
429                vtcs[ ti2 ].tangent += tangent;
[190]430        }
431
[239]432        for ( size_t i = 0; i < vtx_count; ++i )
[190]433        {
[287]434                md5_vtx_pntiw& vdata = vtx_data[i];
[190]435
[239]436                glm::vec3 normal  = glm::normalize( vtcs[i].normal );
437                glm::vec3 tangent = glm::normalize( vtcs[i].tangent );
438                vtcs[i].normal   = normal;
439                vtcs[i].tangent  = tangent;
[190]440
[259]441                vdata.position = vtcs[i].position;
442                vdata.normal   = glm::vec3(0);
443                vdata.tangent  = glm::vec3(0);
[239]444 
[259]445                for ( size_t j = 0; j < 4; ++j )
[239]446                {
[289]447                        const mesh_node_data&  joint = nodes[vdata.boneindex[j]];
448                        const transform tr = transform( joint.transform ).inverse();
449                        vdata.normal  += ( normal  * tr.get_orientation() ) * vdata.boneweight[j];
450                        vdata.tangent += ( tangent * tr.get_orientation() ) * vdata.boneweight[j];
[239]451                }
[190]452        }
453
454        return true;
455}
456
[383]457void md5_loader::build_frame_skeleton( mesh_node_data* nodes, uint32 index, const const_array_ref<md5_joint_info>& joint_infos, const const_array_ref<transform>& base_frames, const const_array_ref<float>& frame_data )
[191]458{
[289]459        assert( m_type == ANIMATION );
[191]460        for ( unsigned int i = 0; i < joint_infos.size(); ++i )
461        {
462                unsigned int j = 0;
463
464                const md5_joint_info& jinfo = joint_infos[i];
[289]465                mesh_node_data& joint = nodes[i];
466                int parent_id         = joint.parent_id;
[191]467
[241]468                vec3 pos    = base_frames[i].get_position();
469                quat orient = base_frames[i].get_orientation();
470                if ( jinfo.flags & 1 )  pos.x    = frame_data[ jinfo.start_index + j++ ];
471                if ( jinfo.flags & 2 )  pos.y    = frame_data[ jinfo.start_index + j++ ];
472                if ( jinfo.flags & 4 )  pos.z    = frame_data[ jinfo.start_index + j++ ];
473                if ( jinfo.flags & 8 )  orient.x = frame_data[ jinfo.start_index + j++ ];
474                if ( jinfo.flags & 16 ) orient.y = frame_data[ jinfo.start_index + j++ ];
475                if ( jinfo.flags & 32 ) orient.z = frame_data[ jinfo.start_index + j++ ];
476                unit_quat_w( orient );
[191]477
[241]478                if ( parent_id >= 0 ) // Has a parent joint
[191]479                {
[289]480                        const mesh_node_data& pjoint = nodes[parent_id];
481                        const transform* ptv = (const transform*)pjoint.data->get_channel(0)->data;
[241]482                        transform ptr;
[289]483                        if ( pjoint.data->get_channel(0)->count > index ) ptr = ptv[ index ];
[241]484                        glm::vec3 rot_pos = ptr.get_orientation() * pos;
[191]485
[241]486                        pos    = ptr.get_position() + rot_pos;
487                        orient = ptr.get_orientation() * orient;
[191]488
[241]489                        orient = glm::normalize( orient );
[191]490                }
491
[289]492                ((transform*)joint.data->get_channel(0)->data)[index] = transform( pos, orient );
[191]493        }
[241]494}
[191]495
[241]496mesh_data* nv::md5_loader::release_mesh_data( size_t index )
497{
498        mesh_data* result = m_meshes[ index ];
499        m_meshes[ index ] = nullptr;
500        return result;
[191]501}
502
[291]503mesh_nodes_data* nv::md5_loader::release_mesh_nodes_data( size_t )
[191]504{
[289]505        mesh_nodes_data* nodes = m_nodes;
506        m_nodes = nullptr;
507        return nodes;
[191]508}
509
[287]510mesh_data_pack* nv::md5_loader::release_mesh_data_pack()
[191]511{
[287]512        uint32 size = m_meshes.size();
513        mesh_data* meshes = new mesh_data[ size ];
514        for ( uint32 i = 0; i < size; ++i )
515        {
516                m_meshes[i]->move_to( meshes[i] );
517                delete m_meshes[i];
518                m_meshes[i] = nullptr;
519        }
520        return new mesh_data_pack( size, meshes, release_mesh_nodes_data() );
[191]521}
522
[287]523
524nv::md5_loader::~md5_loader()
[191]525{
[289]526        reset();
527}
528
529void nv::md5_loader::reset()
530{
531        if ( m_nodes ) delete m_nodes;
[287]532        for ( auto m : m_meshes ) { if (m) delete m; }
[289]533        m_meshes.resize(0);
534        m_nodes = nullptr;
[239]535}
536
Note: See TracBrowser for help on using the repository browser.