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