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

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