vrshoot
diff libs/assimp/MS3DLoader.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/MS3DLoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,663 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file MS3DLoader.cpp 1.46 + * @brief Implementation of the Ms3D importer class. 1.47 + * Written against http://chumbalum.swissquake.ch/ms3d/ms3dspec.txt 1.48 + */ 1.49 + 1.50 +#include "AssimpPCH.h" 1.51 +#ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER 1.52 + 1.53 +// internal headers 1.54 +#include "MS3DLoader.h" 1.55 +#include "StreamReader.h" 1.56 +using namespace Assimp; 1.57 + 1.58 +static const aiImporterDesc desc = { 1.59 + "Milkshape 3D Importer", 1.60 + "", 1.61 + "", 1.62 + "http://chumbalum.swissquake.ch/", 1.63 + aiImporterFlags_SupportBinaryFlavour, 1.64 + 0, 1.65 + 0, 1.66 + 0, 1.67 + 0, 1.68 + "ms3d" 1.69 +}; 1.70 + 1.71 +// ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH 1.72 +// (enable old code path, which generates extra nodes per mesh while 1.73 +// the newer code uses aiMesh::mName to express the name of the 1.74 +// meshes (a.k.a. groups in MS3D)) 1.75 + 1.76 +// ------------------------------------------------------------------------------------------------ 1.77 +// Constructor to be privately used by Importer 1.78 +MS3DImporter::MS3DImporter() 1.79 +{} 1.80 + 1.81 +// ------------------------------------------------------------------------------------------------ 1.82 +// Destructor, private as well 1.83 +MS3DImporter::~MS3DImporter() 1.84 +{} 1.85 + 1.86 +// ------------------------------------------------------------------------------------------------ 1.87 +// Returns whether the class can handle the format of the given file. 1.88 +bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const 1.89 +{ 1.90 + // first call - simple extension check 1.91 + const std::string extension = GetExtension(pFile); 1.92 + if (extension == "ms3d") { 1.93 + return true; 1.94 + } 1.95 + 1.96 + // second call - check for magic identifiers 1.97 + else if (!extension.length() || checkSig) { 1.98 + if (!pIOHandler) { 1.99 + return true; 1.100 + } 1.101 + const char* tokens[] = {"MS3D000000"}; 1.102 + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); 1.103 + } 1.104 + return false; 1.105 +} 1.106 + 1.107 +// ------------------------------------------------------------------------------------------------ 1.108 +const aiImporterDesc* MS3DImporter::GetInfo () const 1.109 +{ 1.110 + return &desc; 1.111 +} 1.112 + 1.113 +// ------------------------------------------------------------------------------------------------ 1.114 +void ReadColor(StreamReaderLE& stream, aiColor4D& ambient) 1.115 +{ 1.116 + // aiColor4D is packed on gcc, implicit binding to float& fails therefore. 1.117 + stream >> (float&)ambient.r >> (float&)ambient.g >> (float&)ambient.b >> (float&)ambient.a; 1.118 +} 1.119 + 1.120 +// ------------------------------------------------------------------------------------------------ 1.121 +void ReadVector(StreamReaderLE& stream, aiVector3D& pos) 1.122 +{ 1.123 + // See note in ReadColor() 1.124 + stream >> (float&)pos.x >> (float&)pos.y >> (float&)pos.z; 1.125 +} 1.126 + 1.127 +// ------------------------------------------------------------------------------------------------ 1.128 +template<typename T> 1.129 +void MS3DImporter :: ReadComments(StreamReaderLE& stream, std::vector<T>& outp) 1.130 +{ 1.131 + uint16_t cnt; 1.132 + stream >> cnt; 1.133 + 1.134 + for(unsigned int i = 0; i < cnt; ++i) { 1.135 + uint32_t index, clength; 1.136 + stream >> index >> clength; 1.137 + 1.138 + if(index >= outp.size()) { 1.139 + DefaultLogger::get()->warn("MS3D: Invalid index in comment section"); 1.140 + } 1.141 + else if (clength > stream.GetRemainingSize()) { 1.142 + throw DeadlyImportError("MS3D: Failure reading comment, length field is out of range"); 1.143 + } 1.144 + else { 1.145 + outp[index].comment = std::string(reinterpret_cast<char*>(stream.GetPtr()),clength); 1.146 + } 1.147 + stream.IncPtr(clength); 1.148 + } 1.149 +} 1.150 + 1.151 +// ------------------------------------------------------------------------------------------------ 1.152 +template <typename T, typename T2, typename T3> bool inrange(const T& in, const T2& lower, const T3& higher) 1.153 +{ 1.154 + return in > lower && in <= higher; 1.155 +} 1.156 + 1.157 +// ------------------------------------------------------------------------------------------------ 1.158 +void MS3DImporter :: CollectChildJoints(const std::vector<TempJoint>& joints, 1.159 + std::vector<bool>& hadit, 1.160 + aiNode* nd, 1.161 + const aiMatrix4x4& absTrafo) 1.162 +{ 1.163 + unsigned int cnt = 0; 1.164 + for(size_t i = 0; i < joints.size(); ++i) { 1.165 + if (!hadit[i] && !strcmp(joints[i].parentName,nd->mName.data)) { 1.166 + ++cnt; 1.167 + } 1.168 + } 1.169 + 1.170 + nd->mChildren = new aiNode*[nd->mNumChildren = cnt]; 1.171 + cnt = 0; 1.172 + for(size_t i = 0; i < joints.size(); ++i) { 1.173 + if (!hadit[i] && !strcmp(joints[i].parentName,nd->mName.data)) { 1.174 + aiNode* ch = nd->mChildren[cnt++] = new aiNode(joints[i].name); 1.175 + ch->mParent = nd; 1.176 + 1.177 + ch->mTransformation = aiMatrix4x4::Translation(joints[i].position,aiMatrix4x4()=aiMatrix4x4())* 1.178 + // XXX actually, I don't *know* why we need the inverse here. Probably column vs. row order? 1.179 + aiMatrix4x4().FromEulerAnglesXYZ(joints[i].rotation).Transpose(); 1.180 + 1.181 + const aiMatrix4x4 abs = absTrafo*ch->mTransformation; 1.182 + for(unsigned int a = 0; a < mScene->mNumMeshes; ++a) { 1.183 + aiMesh* const msh = mScene->mMeshes[a]; 1.184 + for(unsigned int n = 0; n < msh->mNumBones; ++n) { 1.185 + aiBone* const bone = msh->mBones[n]; 1.186 + 1.187 + if(bone->mName == ch->mName) { 1.188 + bone->mOffsetMatrix = aiMatrix4x4(abs).Inverse(); 1.189 + } 1.190 + } 1.191 + } 1.192 + 1.193 + hadit[i] = true; 1.194 + CollectChildJoints(joints,hadit,ch,abs); 1.195 + } 1.196 + } 1.197 +} 1.198 + 1.199 +// ------------------------------------------------------------------------------------------------ 1.200 +void MS3DImporter :: CollectChildJoints(const std::vector<TempJoint>& joints, aiNode* nd) 1.201 +{ 1.202 + std::vector<bool> hadit(joints.size(),false); 1.203 + aiMatrix4x4 trafo; 1.204 + 1.205 + CollectChildJoints(joints,hadit,nd,trafo); 1.206 +} 1.207 + 1.208 +// ------------------------------------------------------------------------------------------------ 1.209 +// Imports the given file into the given scene structure. 1.210 +void MS3DImporter::InternReadFile( const std::string& pFile, 1.211 + aiScene* pScene, IOSystem* pIOHandler) 1.212 +{ 1.213 + StreamReaderLE stream(pIOHandler->Open(pFile,"rb")); 1.214 + 1.215 + // CanRead() should have done this already 1.216 + char head[10]; 1.217 + int32_t version; 1.218 + 1.219 + mScene = pScene; 1.220 + 1.221 + 1.222 + // 1 ------------ read into temporary data structures mirroring the original file 1.223 + 1.224 + stream.CopyAndAdvance(head,10); 1.225 + stream >> version; 1.226 + if (strncmp(head,"MS3D000000",10)) { 1.227 + throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: "+pFile); 1.228 + } 1.229 + 1.230 + if (version != 4) { 1.231 + throw DeadlyImportError("MS3D: Unsupported file format version, 4 was expected"); 1.232 + } 1.233 + 1.234 + uint16_t verts; 1.235 + stream >> verts; 1.236 + 1.237 + std::vector<TempVertex> vertices(verts); 1.238 + for (unsigned int i = 0; i < verts; ++i) { 1.239 + TempVertex& v = vertices[i]; 1.240 + 1.241 + stream.IncPtr(1); 1.242 + ReadVector(stream,v.pos); 1.243 + v.bone_id[0] = stream.GetI1(); 1.244 + v.ref_cnt = stream.GetI1(); 1.245 + 1.246 + v.bone_id[1] = v.bone_id[2] = v.bone_id[3] = UINT_MAX; 1.247 + v.weights[1] = v.weights[2] = v.weights[3] = 0.f; 1.248 + v.weights[0] = 1.f; 1.249 + } 1.250 + 1.251 + uint16_t tris; 1.252 + stream >> tris; 1.253 + 1.254 + std::vector<TempTriangle> triangles(tris); 1.255 + for (unsigned int i = 0;i < tris; ++i) { 1.256 + TempTriangle& t = triangles[i]; 1.257 + 1.258 + stream.IncPtr(2); 1.259 + for (unsigned int i = 0; i < 3; ++i) { 1.260 + t.indices[i] = stream.GetI2(); 1.261 + } 1.262 + 1.263 + for (unsigned int i = 0; i < 3; ++i) { 1.264 + ReadVector(stream,t.normals[i]); 1.265 + } 1.266 + 1.267 + for (unsigned int i = 0; i < 3; ++i) { 1.268 + stream >> (float&)(t.uv[i].x); // see note in ReadColor() 1.269 + } 1.270 + for (unsigned int i = 0; i < 3; ++i) { 1.271 + stream >> (float&)(t.uv[i].y); 1.272 + } 1.273 + 1.274 + t.sg = stream.GetI1(); 1.275 + t.group = stream.GetI1(); 1.276 + } 1.277 + 1.278 + uint16_t grp; 1.279 + stream >> grp; 1.280 + 1.281 + bool need_default = false; 1.282 + std::vector<TempGroup> groups(grp); 1.283 + for (unsigned int i = 0;i < grp; ++i) { 1.284 + TempGroup& t = groups[i]; 1.285 + 1.286 + stream.IncPtr(1); 1.287 + stream.CopyAndAdvance(t.name,32); 1.288 + 1.289 + t.name[32] = '\0'; 1.290 + uint16_t num; 1.291 + stream >> num; 1.292 + 1.293 + t.triangles.resize(num); 1.294 + for (unsigned int i = 0; i < num; ++i) { 1.295 + t.triangles[i] = stream.GetI2(); 1.296 + } 1.297 + t.mat = stream.GetI1(); 1.298 + if (t.mat == UINT_MAX) { 1.299 + need_default = true; 1.300 + } 1.301 + } 1.302 + 1.303 + uint16_t mat; 1.304 + stream >> mat; 1.305 + 1.306 + std::vector<TempMaterial> materials(mat); 1.307 + for (unsigned int i = 0;i < mat; ++i) { 1.308 + TempMaterial& t = materials[i]; 1.309 + 1.310 + stream.CopyAndAdvance(t.name,32); 1.311 + t.name[32] = '\0'; 1.312 + 1.313 + ReadColor(stream,t.ambient); 1.314 + ReadColor(stream,t.diffuse); 1.315 + ReadColor(stream,t.specular); 1.316 + ReadColor(stream,t.emissive); 1.317 + stream >> t.shininess >> t.transparency; 1.318 + 1.319 + stream.IncPtr(1); 1.320 + 1.321 + stream.CopyAndAdvance(t.texture,128); 1.322 + t.texture[128] = '\0'; 1.323 + 1.324 + stream.CopyAndAdvance(t.alphamap,128); 1.325 + t.alphamap[128] = '\0'; 1.326 + } 1.327 + 1.328 + float animfps, currenttime; 1.329 + uint32_t totalframes; 1.330 + stream >> animfps >> currenttime >> totalframes; 1.331 + 1.332 + uint16_t joint; 1.333 + stream >> joint; 1.334 + 1.335 + std::vector<TempJoint> joints(joint); 1.336 + for(unsigned int i = 0; i < joint; ++i) { 1.337 + TempJoint& j = joints[i]; 1.338 + 1.339 + stream.IncPtr(1); 1.340 + stream.CopyAndAdvance(j.name,32); 1.341 + j.name[32] = '\0'; 1.342 + 1.343 + stream.CopyAndAdvance(j.parentName,32); 1.344 + j.parentName[32] = '\0'; 1.345 + 1.346 + // DefaultLogger::get()->debug(j.name); 1.347 + // DefaultLogger::get()->debug(j.parentName); 1.348 + 1.349 + ReadVector(stream,j.rotation); 1.350 + ReadVector(stream,j.position); 1.351 + 1.352 + j.rotFrames.resize(stream.GetI2()); 1.353 + j.posFrames.resize(stream.GetI2()); 1.354 + 1.355 + for(unsigned int a = 0; a < j.rotFrames.size(); ++a) { 1.356 + TempKeyFrame& kf = j.rotFrames[a]; 1.357 + stream >> kf.time; 1.358 + ReadVector(stream,kf.value); 1.359 + } 1.360 + for(unsigned int a = 0; a < j.posFrames.size(); ++a) { 1.361 + TempKeyFrame& kf = j.posFrames[a]; 1.362 + stream >> kf.time; 1.363 + ReadVector(stream,kf.value); 1.364 + } 1.365 + } 1.366 + 1.367 + if(stream.GetRemainingSize() > 4) { 1.368 + uint32_t subversion; 1.369 + stream >> subversion; 1.370 + if (subversion == 1) { 1.371 + ReadComments<TempGroup>(stream,groups); 1.372 + ReadComments<TempMaterial>(stream,materials); 1.373 + ReadComments<TempJoint>(stream,joints); 1.374 + 1.375 + // model comment - print it for we have such a nice log. 1.376 + if (stream.GetI4()) { 1.377 + const size_t len = static_cast<size_t>(stream.GetI4()); 1.378 + if (len > stream.GetRemainingSize()) { 1.379 + throw DeadlyImportError("MS3D: Model comment is too long"); 1.380 + } 1.381 + 1.382 + const std::string& s = std::string(reinterpret_cast<char*>(stream.GetPtr()),len); 1.383 + DefaultLogger::get()->debug("MS3D: Model comment: " + s); 1.384 + } 1.385 + 1.386 + if(stream.GetRemainingSize() > 4 && inrange((stream >> subversion,subversion),1u,3u)) { 1.387 + for(unsigned int i = 0; i < verts; ++i) { 1.388 + TempVertex& v = vertices[i]; 1.389 + v.weights[3]=1.f; 1.390 + for(unsigned int n = 0; n < 3; v.weights[3]-=v.weights[n++]) { 1.391 + v.bone_id[n+1] = stream.GetI1(); 1.392 + v.weights[n] = static_cast<float>(static_cast<unsigned int>(stream.GetI1()))/255.f; 1.393 + } 1.394 + stream.IncPtr((subversion-1)<<2u); 1.395 + } 1.396 + 1.397 + // even further extra data is not of interest for us, at least now now. 1.398 + } 1.399 + } 1.400 + } 1.401 + 1.402 + // 2 ------------ convert to proper aiXX data structures ----------------------------------- 1.403 + 1.404 + if (need_default && materials.size()) { 1.405 + DefaultLogger::get()->warn("MS3D: Found group with no material assigned, spawning default material"); 1.406 + // if one of the groups has no material assigned, but there are other 1.407 + // groups with materials, a default material needs to be added ( 1.408 + // scenepreprocessor adds a default material only if nummat==0). 1.409 + materials.push_back(TempMaterial()); 1.410 + TempMaterial& m = materials.back(); 1.411 + 1.412 + strcpy(m.name,"<MS3D_DefaultMat>"); 1.413 + m.diffuse = aiColor4D(0.6f,0.6f,0.6f,1.0); 1.414 + m.transparency = 1.f; 1.415 + m.shininess = 0.f; 1.416 + 1.417 + // this is because these TempXXX struct's have no c'tors. 1.418 + m.texture[0] = m.alphamap[0] = '\0'; 1.419 + 1.420 + for (unsigned int i = 0; i < groups.size(); ++i) { 1.421 + TempGroup& g = groups[i]; 1.422 + if (g.mat == UINT_MAX) { 1.423 + g.mat = materials.size()-1; 1.424 + } 1.425 + } 1.426 + } 1.427 + 1.428 + // convert materials to our generic key-value dict-alike 1.429 + if (materials.size()) { 1.430 + pScene->mMaterials = new aiMaterial*[materials.size()]; 1.431 + for (size_t i = 0; i < materials.size(); ++i) { 1.432 + 1.433 + aiMaterial* mo = new aiMaterial(); 1.434 + pScene->mMaterials[pScene->mNumMaterials++] = mo; 1.435 + 1.436 + const TempMaterial& mi = materials[i]; 1.437 + 1.438 + aiString tmp; 1.439 + if (0[mi.alphamap]) { 1.440 + tmp = aiString(mi.alphamap); 1.441 + mo->AddProperty(&tmp,AI_MATKEY_TEXTURE_OPACITY(0)); 1.442 + } 1.443 + if (0[mi.texture]) { 1.444 + tmp = aiString(mi.texture); 1.445 + mo->AddProperty(&tmp,AI_MATKEY_TEXTURE_DIFFUSE(0)); 1.446 + } 1.447 + if (0[mi.name]) { 1.448 + tmp = aiString(mi.name); 1.449 + mo->AddProperty(&tmp,AI_MATKEY_NAME); 1.450 + } 1.451 + 1.452 + mo->AddProperty(&mi.ambient,1,AI_MATKEY_COLOR_AMBIENT); 1.453 + mo->AddProperty(&mi.diffuse,1,AI_MATKEY_COLOR_DIFFUSE); 1.454 + mo->AddProperty(&mi.specular,1,AI_MATKEY_COLOR_SPECULAR); 1.455 + mo->AddProperty(&mi.emissive,1,AI_MATKEY_COLOR_EMISSIVE); 1.456 + 1.457 + mo->AddProperty(&mi.shininess,1,AI_MATKEY_SHININESS); 1.458 + mo->AddProperty(&mi.transparency,1,AI_MATKEY_OPACITY); 1.459 + 1.460 + const int sm = mi.shininess>0.f?aiShadingMode_Phong:aiShadingMode_Gouraud; 1.461 + mo->AddProperty(&sm,1,AI_MATKEY_SHADING_MODEL); 1.462 + } 1.463 + } 1.464 + 1.465 + // convert groups to meshes 1.466 + if (groups.empty()) { 1.467 + throw DeadlyImportError("MS3D: Didn't get any group records, file is malformed"); 1.468 + } 1.469 + 1.470 + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes=static_cast<unsigned int>(groups.size())](); 1.471 + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { 1.472 + 1.473 + aiMesh* m = pScene->mMeshes[i] = new aiMesh(); 1.474 + const TempGroup& g = groups[i]; 1.475 + 1.476 + if (pScene->mNumMaterials && g.mat > pScene->mNumMaterials) { 1.477 + throw DeadlyImportError("MS3D: Encountered invalid material index, file is malformed"); 1.478 + } // no error if no materials at all - scenepreprocessor adds one then 1.479 + 1.480 + m->mMaterialIndex = g.mat; 1.481 + m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; 1.482 + 1.483 + m->mFaces = new aiFace[m->mNumFaces = g.triangles.size()]; 1.484 + m->mNumVertices = m->mNumFaces*3; 1.485 + 1.486 + // storage for vertices - verbose format, as requested by the postprocessing pipeline 1.487 + m->mVertices = new aiVector3D[m->mNumVertices]; 1.488 + m->mNormals = new aiVector3D[m->mNumVertices]; 1.489 + m->mTextureCoords[0] = new aiVector3D[m->mNumVertices]; 1.490 + m->mNumUVComponents[0] = 2; 1.491 + 1.492 + typedef std::map<unsigned int,unsigned int> BoneSet; 1.493 + BoneSet mybones; 1.494 + 1.495 + for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) { 1.496 + aiFace& f = m->mFaces[i]; 1.497 + if (g.triangles[i]>triangles.size()) { 1.498 + throw DeadlyImportError("MS3D: Encountered invalid triangle index, file is malformed"); 1.499 + } 1.500 + 1.501 + TempTriangle& t = triangles[g.triangles[i]]; 1.502 + f.mIndices = new unsigned int[f.mNumIndices=3]; 1.503 + 1.504 + for (unsigned int i = 0; i < 3; ++i,++n) { 1.505 + if (t.indices[i]>vertices.size()) { 1.506 + throw DeadlyImportError("MS3D: Encountered invalid vertex index, file is malformed"); 1.507 + } 1.508 + 1.509 + const TempVertex& v = vertices[t.indices[i]]; 1.510 + for(unsigned int a = 0; a < 4; ++a) { 1.511 + if (v.bone_id[a] != UINT_MAX) { 1.512 + if (v.bone_id[a] >= joints.size()) { 1.513 + throw DeadlyImportError("MS3D: Encountered invalid bone index, file is malformed"); 1.514 + } 1.515 + if (mybones.find(v.bone_id[a]) == mybones.end()) { 1.516 + mybones[v.bone_id[a]] = 1; 1.517 + } 1.518 + else ++mybones[v.bone_id[a]]; 1.519 + } 1.520 + } 1.521 + 1.522 + // collect vertex components 1.523 + m->mVertices[n] = v.pos; 1.524 + 1.525 + m->mNormals[n] = t.normals[i]; 1.526 + m->mTextureCoords[0][n] = aiVector3D(t.uv[i].x,1.f-t.uv[i].y,0.0); 1.527 + f.mIndices[i] = n; 1.528 + } 1.529 + } 1.530 + 1.531 + // allocate storage for bones 1.532 + if(mybones.size()) { 1.533 + std::vector<unsigned int> bmap(joints.size()); 1.534 + m->mBones = new aiBone*[mybones.size()](); 1.535 + for(BoneSet::const_iterator it = mybones.begin(); it != mybones.end(); ++it) { 1.536 + aiBone* const bn = m->mBones[m->mNumBones] = new aiBone(); 1.537 + const TempJoint& jnt = joints[(*it).first]; 1.538 + 1.539 + bn->mName.Set(jnt.name); 1.540 + bn->mWeights = new aiVertexWeight[(*it).second]; 1.541 + 1.542 + bmap[(*it).first] = m->mNumBones++; 1.543 + } 1.544 + 1.545 + // .. and collect bone weights 1.546 + for (unsigned int i = 0,n = 0; i < m->mNumFaces; ++i) { 1.547 + TempTriangle& t = triangles[g.triangles[i]]; 1.548 + 1.549 + for (unsigned int i = 0; i < 3; ++i,++n) { 1.550 + const TempVertex& v = vertices[t.indices[i]]; 1.551 + for(unsigned int a = 0; a < 4; ++a) { 1.552 + const unsigned int bone = v.bone_id[a]; 1.553 + if(bone==UINT_MAX){ 1.554 + continue; 1.555 + } 1.556 + 1.557 + aiBone* const outbone = m->mBones[bmap[bone]]; 1.558 + aiVertexWeight& outwght = outbone->mWeights[outbone->mNumWeights++]; 1.559 + 1.560 + outwght.mVertexId = n; 1.561 + outwght.mWeight = v.weights[a]; 1.562 + } 1.563 + } 1.564 + } 1.565 + } 1.566 + } 1.567 + 1.568 + // ... add dummy nodes under a single root, each holding a reference to one 1.569 + // mesh. If we didn't do this, we'd loose the group name. 1.570 + aiNode* rt = pScene->mRootNode = new aiNode("<MS3DRoot>"); 1.571 + 1.572 +#ifdef ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH 1.573 + rt->mChildren = new aiNode*[rt->mNumChildren=pScene->mNumMeshes+(joints.size()?1:0)](); 1.574 + 1.575 + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { 1.576 + aiNode* nd = rt->mChildren[i] = new aiNode(); 1.577 + 1.578 + const TempGroup& g = groups[i]; 1.579 + 1.580 + // we need to generate an unique name for all mesh nodes. 1.581 + // since we want to keep the group name, a prefix is 1.582 + // prepended. 1.583 + nd->mName = aiString("<MS3DMesh>_"); 1.584 + nd->mName.Append(g.name); 1.585 + nd->mParent = rt; 1.586 + 1.587 + nd->mMeshes = new unsigned int[nd->mNumMeshes = 1]; 1.588 + nd->mMeshes[0] = i; 1.589 + } 1.590 +#else 1.591 + rt->mMeshes = new unsigned int[pScene->mNumMeshes]; 1.592 + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { 1.593 + rt->mMeshes[rt->mNumMeshes++] = i; 1.594 + } 1.595 +#endif 1.596 + 1.597 + // convert animations as well 1.598 + if(joints.size()) { 1.599 +#ifndef ASSIMP_BUILD_MS3D_ONE_NODE_PER_MESH 1.600 + rt->mChildren = new aiNode*[1](); 1.601 + rt->mNumChildren = 1; 1.602 + 1.603 + aiNode* jt = rt->mChildren[0] = new aiNode(); 1.604 +#else 1.605 + aiNode* jt = rt->mChildren[pScene->mNumMeshes] = new aiNode(); 1.606 +#endif 1.607 + jt->mParent = rt; 1.608 + CollectChildJoints(joints,jt); 1.609 + jt->mName.Set("<MS3DJointRoot>"); 1.610 + 1.611 + pScene->mAnimations = new aiAnimation*[ pScene->mNumAnimations = 1 ]; 1.612 + aiAnimation* const anim = pScene->mAnimations[0] = new aiAnimation(); 1.613 + 1.614 + anim->mName.Set("<MS3DMasterAnim>"); 1.615 + 1.616 + // carry the fps info to the user by scaling all times with it 1.617 + anim->mTicksPerSecond = animfps; 1.618 + 1.619 + // leave duration at its default, so ScenePreprocessor will fill an appropriate 1.620 + // value (the values taken from some MS3D files seem to be too unreliable 1.621 + // to pass the validation) 1.622 + // anim->mDuration = totalframes/animfps; 1.623 + 1.624 + anim->mChannels = new aiNodeAnim*[joints.size()](); 1.625 + for(std::vector<TempJoint>::const_iterator it = joints.begin(); it != joints.end(); ++it) { 1.626 + if ((*it).rotFrames.empty() && (*it).posFrames.empty()) { 1.627 + continue; 1.628 + } 1.629 + 1.630 + aiNodeAnim* nd = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); 1.631 + nd->mNodeName.Set((*it).name); 1.632 + 1.633 + if ((*it).rotFrames.size()) { 1.634 + nd->mRotationKeys = new aiQuatKey[(*it).rotFrames.size()]; 1.635 + for(std::vector<TempKeyFrame>::const_iterator rot = (*it).rotFrames.begin(); rot != (*it).rotFrames.end(); ++rot) { 1.636 + aiQuatKey& q = nd->mRotationKeys[nd->mNumRotationKeys++]; 1.637 + 1.638 + q.mTime = (*rot).time*animfps; 1.639 + 1.640 + // XXX it seems our matrix&quaternion code has faults in its conversion routines -- 1.641 + // aiQuaternion(x,y,z) seems to besomething different as quat(matrix.fromeuler(x,y,z)). 1.642 + q.mValue = aiQuaternion(aiMatrix3x3(aiMatrix4x4().FromEulerAnglesXYZ((*rot).value)* 1.643 + aiMatrix4x4().FromEulerAnglesXYZ((*it).rotation)).Transpose()); 1.644 + } 1.645 + } 1.646 + 1.647 + if ((*it).posFrames.size()) { 1.648 + nd->mPositionKeys = new aiVectorKey[(*it).posFrames.size()]; 1.649 + 1.650 + aiQuatKey* qu = nd->mRotationKeys; 1.651 + for(std::vector<TempKeyFrame>::const_iterator pos = (*it).posFrames.begin(); pos != (*it).posFrames.end(); ++pos,++qu) { 1.652 + aiVectorKey& v = nd->mPositionKeys[nd->mNumPositionKeys++]; 1.653 + 1.654 + v.mTime = (*pos).time*animfps; 1.655 + v.mValue = (*it).position + (*pos).value; 1.656 + } 1.657 + } 1.658 + } 1.659 + // fixup to pass the validation if not a single animation channel is non-trivial 1.660 + if (!anim->mNumChannels) { 1.661 + anim->mChannels = NULL; 1.662 + } 1.663 + } 1.664 +} 1.665 + 1.666 +#endif