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

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