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

Last change on this file since 190 was 190, checked in by epyon, 12 years ago
  • formats - md5 loader - no animations yet, but tangent calculation in
File size: 7.9 KB
RevLine 
[190]1// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/formats/md5_loader.hh"
8
9#include <glm/gtc/constants.hpp>
10#include <glm/gtx/string_cast.hpp>
11#include "nv/logging.hh"
12#include "nv/io/std_stream.hh"
13#include <cstring>
14
15using namespace nv;
16
17static void next_line( std::istream& stream )
18{
19        stream.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
20}
21
22static inline void discard( std::istream& stream, const std::string& token )
23{
24        std::string discarded;
25        stream >> discarded;
26        assert( discarded == token );
27}
28
29
30static void remove_quotes( std::string& str )
31{
32        size_t n;
33        while ( ( n = str.find('\"') ) != std::string::npos ) str.erase(n,1);
34}
35
36void unit_quat_w( glm::quat& quat )
37{
38        float t = 1.0f - ( quat.x * quat.x ) - ( quat.y * quat.y ) - ( quat.z * quat.z );
39        quat.w = ( t < 0.0f ? 0.0f : -sqrtf(t) );
40}
41
42bool md5_loader::load( stream& source )
43{
44        std_stream sstream( &source );
45        std::string command;
46
47        sstream >> command;
48        while ( !sstream.eof() )
49        {
50                if ( command == "MD5Version" )
51                {
52                        sstream >> m_md5_version;
53                        assert( m_md5_version == 10 );
54                }
55                else if ( command == "commandline" )
56                {
57                        next_line( sstream );
58                }
59                else if ( command == "numJoints" )
60                {
61                        sstream >> m_num_joints;
62                        m_joints.reserve( m_num_joints );
63                }
64                else if ( command == "numMeshes" )
65                {
66                        sstream >> m_num_meshes;
67                        m_meshes.reserve( m_num_meshes );
68                }
69                else if ( command == "joints" )
70                {
71                        discard( sstream, "{" );
72                        md5_joint joint;
73                        for ( int i = 0; i < m_num_joints; ++i )
74                        {
75                                sstream >> joint.name >> joint.parent_id;
76                                discard( sstream, "(" );
77                                sstream >> joint.pos.x >> joint.pos.y >> joint.pos.z;
78                                discard( sstream, ")" );
79                                discard( sstream, "(" );
80                                sstream >> joint.orient.x >> joint.orient.y >> joint.orient.z;
81                                remove_quotes( joint.name );
82                                unit_quat_w( joint.orient );
83                                m_joints.push_back( joint );
84                                next_line( sstream );
85                        }
86                        discard( sstream, "}" );
87                }
88                else if ( command == "mesh" )
89                {
90                        // TODO : efficiency dammit
91                        md5_mesh mesh;
92                        int num_verts, num_tris, num_weights;
93
94                        discard( sstream, "{" );
95                        sstream >> command;
96                        while ( command != "}" )
97                        {
98                                if ( command == "shader" )
99                                {
100                                        sstream >> mesh.shader;
101                                        remove_quotes( mesh.shader );
102                                        // texturePath.replace_extension( ".tga" );
103                                        next_line( sstream );
104                                }
105                                else if ( command == "numverts")
106                                {
107                                        sstream >> num_verts;
108                                        next_line( sstream );
109                                        for ( int i = 0; i < num_verts; ++i )
110                                        {
111                                                md5_vertex vert;
112                                                std::string ignore;
113                                                discard( sstream, "vert" );
114                                                sstream >> ignore;
115                                                discard( sstream, "(" );
116                                                sstream >> vert.texcoord.x >> vert.texcoord.y;
117                                                discard( sstream, ")" );
118                                                sstream >> vert.start_weight >> vert.weight_count;
119                                                next_line( sstream );
120
121                                                mesh.verts.push_back(vert);
122                                                mesh.texcoord_buffer.push_back( vert.texcoord );
123                                        } 
124                                }
125                                else if ( command == "numtris" )
126                                {
127                                        sstream >> num_tris;
128                                        next_line( sstream );
129                                        for ( int i = 0; i < num_tris; ++i )
130                                        {
131                                                md5_triangle tri;
132                                                std::string ignore;
133                                                discard( sstream, "tri" );
134                                                sstream >> ignore >> tri.indices[0] >> tri.indices[1] >> tri.indices[2];
135                                                next_line( sstream );
136
137                                                mesh.tris.push_back( tri );
138                                                mesh.index_buffer.push_back( (uint32)tri.indices[0] );
139                                                mesh.index_buffer.push_back( (uint32)tri.indices[1] );
140                                                mesh.index_buffer.push_back( (uint32)tri.indices[2] );
141                                        }             
142                                }
143                                else if ( command == "numweights" )
144                                {
145                                        sstream >> num_weights;
146                                        next_line( sstream );
147                                        for ( int i = 0; i < num_weights; ++i )
148                                        {
149                                                md5_weight weight;
150                                                std::string ignore;
151                                                discard( sstream, "weight" );
152                                                sstream >> ignore >> weight.joint_id >> weight.bias;
153                                                discard( sstream, "(" );
154                                                sstream >> weight.pos.x >> weight.pos.y >> weight.pos.z;
155                                                discard( sstream, ")" );
156                                                next_line( sstream );
157                                                mesh.weights.push_back(weight);
158                                        }
159                                }
160                                else
161                                {
162                                        next_line( sstream );
163                                }
164
165                                sstream >> command;
166                        }
167
168                        prepare_mesh( mesh );
169                        prepare_normals( mesh );
170
171                        m_meshes.push_back(mesh);
172                }
173                sstream >> command;
174        }
175
176        assert( m_joints.size() == m_num_joints );
177        assert( m_meshes.size() == m_num_meshes );
178        return true;
179}
180
181bool md5_loader::prepare_mesh( md5_mesh& mesh )
182{
183        mesh.position_buffer.clear();
184        mesh.texcoord_buffer.clear();
185
186        for ( uint32 i = 0; i < mesh.verts.size(); ++i )
187        {
188                md5_vertex& vert = mesh.verts[i];
189
190                vert.position = glm::vec3(0);
191                vert.normal   = glm::vec3(0);
192                vert.tangent  = glm::vec3(0);
193
194                for ( int j = 0; j < vert.weight_count; ++j )
195                {
196                        md5_weight& weight = mesh.weights[vert.start_weight + j];
197                        md5_joint&  joint  = m_joints[weight.joint_id];
198
199                        glm::vec3 rot_pos = joint.orient * weight.pos;
200
201                        vert.position += ( joint.pos + rot_pos ) * weight.bias;
202                }
203
204                mesh.position_buffer.push_back(vert.position);
205                mesh.texcoord_buffer.push_back(vert.texcoord);
206        }
207
208        return true;
209}
210
211bool md5_loader::prepare_normals( md5_mesh& mesh )
212{
213        mesh.normal_buffer.clear();
214
215        for ( unsigned int i = 0; i < mesh.tris.size(); ++i )
216        {
217                const md5_triangle& tri = mesh.tris[i];
218                glm::vec3 v1 = mesh.verts[ tri.indices[0] ].position;
219                glm::vec3 v2 = mesh.verts[ tri.indices[1] ].position;
220                glm::vec3 v3 = mesh.verts[ tri.indices[2] ].position;
221                glm::vec3 xyz1 = v3 - v1;
222                glm::vec3 xyz2 = v2 - v1;
223
224                glm::vec3 normal = glm::cross( xyz1, xyz2 );
225
226                mesh.verts[ tri.indices[0] ].normal += normal;
227                mesh.verts[ tri.indices[1] ].normal += normal;
228                mesh.verts[ tri.indices[2] ].normal += normal;
229
230                const vec2& w1 = mesh.verts[ tri.indices[0] ].texcoord;
231                const vec2& w2 = mesh.verts[ tri.indices[1] ].texcoord;
232                const vec2& w3 = mesh.verts[ tri.indices[2] ].texcoord;
233
234                vec2 st1 = w3 - w1;
235                vec2 st2 = w2 - w1;
236
237                float coef = 1.0f / (st1.x * st2.y - st2.x * st1.y);
238
239                vec3 tangent = (( xyz1 * st2.y ) - ( xyz2 * st1.y )) * coef;
240
241                mesh.verts[ tri.indices[0] ].tangent += tangent;
242                mesh.verts[ tri.indices[1] ].tangent += tangent;
243                mesh.verts[ tri.indices[2] ].tangent += tangent;
244        }
245
246        for ( unsigned int i = 0; i < mesh.verts.size(); ++i )
247        {
248                md5_vertex& vert = mesh.verts[i];
249
250                glm::vec3 normal  = glm::normalize( vert.normal );
251                glm::vec3 tangent = glm::normalize( vert.tangent );
252                mesh.normal_buffer.push_back( normal );
253                mesh.tangent_buffer.push_back( tangent );
254
255                vert.normal  = glm::vec3(0);
256                vert.tangent = glm::vec3(0);
257
258                for ( int j = 0; j < vert.weight_count; ++j )
259                {
260                        const md5_weight& weight = mesh.weights[vert.start_weight + j];
261                        const md5_joint&  joint  = m_joints[weight.joint_id];
262                        vert.normal  += ( normal  * joint.orient ) * weight.bias;
263                        vert.tangent += ( tangent * joint.orient ) * weight.bias;
264                }
265        }
266
267        return true;
268}
269
270mesh* md5_loader::release_mesh()
271{
272        mesh* m = new mesh();
273        auto position = m->add_attribute< vec3 >( "nv_position" );
274        auto normal   = m->add_attribute< vec3 >( "nv_normal" );
275        auto texcoord = m->add_attribute< vec2 >( "nv_texcoord" );
276        auto tangent  = m->add_attribute< vec2 >( "nv_tangent" );
277        auto indices  = m->add_indices< uint32 >();
278
279        position->get().assign( m_meshes[0].position_buffer.begin(), m_meshes[0].position_buffer.end() );
280        normal  ->get().assign( m_meshes[0].normal_buffer.begin(),   m_meshes[0].normal_buffer.end() );
281        texcoord->get().assign( m_meshes[0].texcoord_buffer.begin(), m_meshes[0].texcoord_buffer.end() );
282        tangent ->get().assign( m_meshes[0].tangent_buffer.begin(),  m_meshes[0].tangent_buffer.end() );
283        indices ->get().assign( m_meshes[0].index_buffer.begin(),    m_meshes[0].index_buffer.end() );
284
285        m_size = m_meshes[0].index_buffer.size();
286        return m;
287}
Note: See TracBrowser for help on using the repository browser.