[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 |
|
---|
| 15 | using namespace nv;
|
---|
| 16 |
|
---|
| 17 | static void next_line( std::istream& stream )
|
---|
| 18 | {
|
---|
| 19 | stream.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
|
---|
| 20 | }
|
---|
| 21 |
|
---|
| 22 | static 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 |
|
---|
| 30 | static 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 |
|
---|
| 36 | void 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 |
|
---|
| 42 | bool 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 |
|
---|
| 181 | bool 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 |
|
---|
| 211 | bool 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 |
|
---|
| 270 | mesh* 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 | }
|
---|