dbacchet avatar dbacchet committed ba058cd

*updated assimp to rev 1322 (fixes a build problem with clang)
*minor fixes for osx

Comments (0)

Files changed (303)

 *.obj
 *.suo
 *.log
+build
+dh_install
+*.DS_Store
+*.pyc
+.lock-waf*

3rdparty/assimp/src/3DSConverter.cpp

-/*
----------------------------------------------------------------------------
-Open Asset Import Library (assimp)
----------------------------------------------------------------------------
-
-Copyright (c) 2006-2012, assimp team
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms, 
-with or without modification, are permitted provided that the following 
-conditions are met:
-
-* Redistributions of source code must retain the above
-  copyright notice, this list of conditions and the
-  following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-  copyright notice, this list of conditions and the
-  following disclaimer in the documentation and/or other
-  materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
-  contributors may be used to endorse or promote products
-  derived from this software without specific prior
-  written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
-*/
-
-/** @file Implementation of the 3ds importer class */
-
-#include "AssimpPCH.h"
-#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
-
-// internal headers
-#include "3DSLoader.h"
-#include "TargetAnimation.h"
-
-using namespace Assimp;
-
-// ------------------------------------------------------------------------------------------------
-// Setup final material indices, generae a default material if necessary
-void Discreet3DSImporter::ReplaceDefaultMaterial()
-{
-	
-	// Try to find an existing material that matches the
-	// typical default material setting:
-	// - no textures
-	// - diffuse color (in grey!)
-	// NOTE: This is here to workaround the fact that some
-	// exporters are writing a default material, too.
-	unsigned int idx = 0xcdcdcdcd;
-	for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
-	{
-		std::string s = mScene->mMaterials[i].mName;
-		for (std::string::iterator it = s.begin(); it != s.end(); ++it)
-			*it = ::tolower(*it);
-
-		if (std::string::npos == s.find("default"))continue;
-
-		if (mScene->mMaterials[i].mDiffuse.r !=
-			mScene->mMaterials[i].mDiffuse.g ||
-			mScene->mMaterials[i].mDiffuse.r !=
-			mScene->mMaterials[i].mDiffuse.b)continue;
-
-		if (mScene->mMaterials[i].sTexDiffuse.mMapName.length()   != 0	||
-			mScene->mMaterials[i].sTexBump.mMapName.length()      != 0	|| 
-			mScene->mMaterials[i].sTexOpacity.mMapName.length()   != 0	||
-			mScene->mMaterials[i].sTexEmissive.mMapName.length()  != 0	||
-			mScene->mMaterials[i].sTexSpecular.mMapName.length()  != 0	||
-			mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
-		{
-			continue;
-		}
-		idx = i;
-	}
-	if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
-
-	// now iterate through all meshes and through all faces and
-	// find all faces that are using the default material
-	unsigned int cnt = 0;
-	for (std::vector<D3DS::Mesh>::iterator
-		i =  mScene->mMeshes.begin();
-		i != mScene->mMeshes.end();++i)
-	{
-		for (std::vector<unsigned int>::iterator
-			a =  (*i).mFaceMaterials.begin();
-			a != (*i).mFaceMaterials.end();++a)
-		{
-			// NOTE: The additional check seems to be necessary,
-			// some exporters seem to generate invalid data here
-			if (0xcdcdcdcd == (*a))
-			{
-				(*a) = idx;
-				++cnt;
-			}
-			else if ( (*a) >= mScene->mMaterials.size())
-			{
-				(*a) = idx;
-				DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
-				++cnt;
-			}
-		}
-	}
-	if (cnt && idx == mScene->mMaterials.size())
-	{
-		// We need to create our own default material
-		D3DS::Material sMat;
-		sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
-		sMat.mName = "%%%DEFAULT";
-		mScene->mMaterials.push_back(sMat);
-
-		DefaultLogger::get()->info("3DS: Generating default material");
-	}
-}
-
-// ------------------------------------------------------------------------------------------------
-// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
-void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
-{
-	for (std::vector< D3DS::Face >::iterator i =  sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
-	{
-		// check whether all indices are in range
-		for (unsigned int a = 0; a < 3;++a)
-		{
-			if ((*i).mIndices[a] >= sMesh.mPositions.size())
-			{
-				DefaultLogger::get()->warn("3DS: Vertex index overflow)");
-				(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
-			}
-			if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
-			{
-				DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
-				(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
-			}
-		}
-	}
-}
-
-// ------------------------------------------------------------------------------------------------
-// Generate out unique verbose format representation
-void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
-{
-	// TODO: really necessary? I don't think. Just a waste of memory and time
-	// to do it now in a separate buffer. 
-
-	// Allocate output storage
-	std::vector<aiVector3D> vNew  (sMesh.mFaces.size() * 3);
-	std::vector<aiVector3D> vNew2;
-	if (sMesh.mTexCoords.size())
-		vNew2.resize(sMesh.mFaces.size() * 3);
-
-	for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
-	{
-		D3DS::Face& face = sMesh.mFaces[i];
-
-		// Positions
-		for (unsigned int a = 0; a < 3;++a,++base)
-		{
-			vNew[base] = sMesh.mPositions[face.mIndices[a]];
-			if (sMesh.mTexCoords.size())
-				vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
-
-			face.mIndices[a] = base;
-		}
-	}
-	sMesh.mPositions = vNew;
-	sMesh.mTexCoords = vNew2;
-}
-
-// ------------------------------------------------------------------------------------------------
-// Convert a 3DS texture to texture keys in an aiMaterial
-void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
-{
-	// Setup the texture name
-	aiString tex;
-	tex.Set( texture.mMapName);
-	mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
-
-	// Setup the texture blend factor
-	if (is_not_qnan(texture.mTextureBlend))
-		mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
-
-	// Setup the texture mapping mode
-	mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
-	mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
-
-	// Mirroring - double the scaling values 
-	// FIXME: this is not really correct ...
-	if (texture.mMapMode == aiTextureMapMode_Mirror)
-	{
-		texture.mScaleU *= 2.f;
-		texture.mScaleV *= 2.f;
-		texture.mOffsetU /= 2.f;
-		texture.mOffsetV /= 2.f;
-	}
-	
-	// Setup texture UV transformations
-	mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
-}
-
-// ------------------------------------------------------------------------------------------------
-// Convert a 3DS material to an aiMaterial
-void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
-	aiMaterial& mat)
-{
-	// NOTE: Pass the background image to the viewer by bypassing the
-	// material system. This is an evil hack, never do it again!
-	if (0 != mBackgroundImage.length() && bHasBG)
-	{
-		aiString tex;
-		tex.Set( mBackgroundImage);
-		mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
-
-		// Be sure this is only done for the first material
-		mBackgroundImage = std::string("");
-	}
-
-	// At first add the base ambient color of the scene to the material
-	oldMat.mAmbient.r += mClrAmbient.r;
-	oldMat.mAmbient.g += mClrAmbient.g;
-	oldMat.mAmbient.b += mClrAmbient.b;
-
-	aiString name;
-	name.Set( oldMat.mName);
-	mat.AddProperty( &name, AI_MATKEY_NAME);
-
-	// Material colors
-	mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
-	mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
-	mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
-	mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
-
-	// Phong shininess and shininess strength
-	if (D3DS::Discreet3DS::Phong == oldMat.mShading || 
-		D3DS::Discreet3DS::Metal == oldMat.mShading)
-	{
-		if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
-		{
-			oldMat.mShading = D3DS::Discreet3DS::Gouraud;
-		}
-		else
-		{
-			mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
-			mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
-		}
-	}
-
-	// Opacity
-	mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
-
-	// Bump height scaling
-	mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
-
-	// Two sided rendering?
-	if (oldMat.mTwoSided)
-	{
-		int i = 1;
-		mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
-	}
-
-	// Shading mode
-	aiShadingMode eShading = aiShadingMode_NoShading;
-	switch (oldMat.mShading)
-	{
-		case D3DS::Discreet3DS::Flat:
-			eShading = aiShadingMode_Flat; break;
-
-		// I don't know what "Wire" shading should be,
-		// assume it is simple lambertian diffuse shading
-		case D3DS::Discreet3DS::Wire:
-			{
-				// Set the wireframe flag
-				unsigned int iWire = 1;
-				mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
-			}
-
-		case D3DS::Discreet3DS::Gouraud:
-			eShading = aiShadingMode_Gouraud; break;
-
-		// assume cook-torrance shading for metals.
-		case D3DS::Discreet3DS::Phong :
-			eShading = aiShadingMode_Phong; break;
-
-		case D3DS::Discreet3DS::Metal :
-			eShading = aiShadingMode_CookTorrance; break;
-
-			// FIX to workaround a warning with GCC 4 who complained
-			// about a missing case Blinn: here - Blinn isn't a valid
-			// value in the 3DS Loader, it is just needed for ASE
-		case D3DS::Discreet3DS::Blinn :
-			eShading = aiShadingMode_Blinn; break;
-	}
-	mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
-
-	// DIFFUSE texture
-	if( oldMat.sTexDiffuse.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
-
-	// SPECULAR texture
-	if( oldMat.sTexSpecular.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
-
-	// OPACITY texture
-	if( oldMat.sTexOpacity.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
-
-	// EMISSIVE texture
-	if( oldMat.sTexEmissive.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
-
-	// BUMP texture
-	if( oldMat.sTexBump.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
-
-	// SHININESS texture
-	if( oldMat.sTexShininess.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
-
-	// REFLECTION texture
-	if( oldMat.sTexReflective.mMapName.length() > 0)
-		CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
-
-	// Store the name of the material itself, too
-	if( oldMat.mName.length())	{
-		aiString tex;
-		tex.Set( oldMat.mName);
-		mat.AddProperty( &tex, AI_MATKEY_NAME);
-	}
-}
-
-// ------------------------------------------------------------------------------------------------
-// Split meshes by their materials and generate output aiMesh'es
-void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
-{
-	std::vector<aiMesh*> avOutMeshes;
-	avOutMeshes.reserve(mScene->mMeshes.size() * 2);
-
-	unsigned int iFaceCnt = 0,num = 0;
-	aiString name;
-
-	// we need to split all meshes by their materials
-	for (std::vector<D3DS::Mesh>::iterator i =  mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i)	{
-		boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
-
-		name.length = ASSIMP_itoa10(name.data,num++);
-
-		unsigned int iNum = 0;
-		for (std::vector<unsigned int>::const_iterator a =  (*i).mFaceMaterials.begin();
-			a != (*i).mFaceMaterials.end();++a,++iNum)
-		{
-			aiSplit[*a].push_back(iNum);
-		}
-		// now generate submeshes
-		for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
-		{
-			if (aiSplit[p].empty())	{
-				continue;
-			}
-			aiMesh* meshOut = new aiMesh();
-			meshOut->mName = name;
-			meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
-
-			// be sure to setup the correct material index
-			meshOut->mMaterialIndex = p;
-
-			// use the color data as temporary storage
-			meshOut->mColors[0] = (aiColor4D*)(&*i);
-			avOutMeshes.push_back(meshOut);
-
-			// convert vertices
-			meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
-			meshOut->mNumVertices = meshOut->mNumFaces*3;
-
-			// allocate enough storage for faces
-			meshOut->mFaces = new aiFace[meshOut->mNumFaces];
-			iFaceCnt += meshOut->mNumFaces;
-
-			meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
-			meshOut->mNormals  = new aiVector3D[meshOut->mNumVertices];
-			if ((*i).mTexCoords.size())
-			{
-				meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
-			}
-			for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
-			{
-				register unsigned int index = aiSplit[p][q];
-				aiFace& face = meshOut->mFaces[q];
-
-				face.mIndices = new unsigned int[3];
-				face.mNumIndices = 3;
-
-				for (unsigned int a = 0; a < 3;++a,++base)
-				{
-					unsigned int idx = (*i).mFaces[index].mIndices[a];
-					meshOut->mVertices[base]  = (*i).mPositions[idx];
-					meshOut->mNormals [base]  = (*i).mNormals[idx];
-
-					if ((*i).mTexCoords.size())
-						meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
-
-					face.mIndices[a] = base;
-				}
-			}
-		}
-	}
-
-	// Copy them to the output array
-	pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
-	pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
-	for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
-		pcOut->mMeshes[a] = avOutMeshes[a];
-	}
-
-	// We should have at least one face here
-	if (!iFaceCnt) {
-		throw DeadlyImportError("No faces loaded. The mesh is empty");
-	}
-}
-
-// ------------------------------------------------------------------------------------------------
-// Add a node to the scenegraph and setup its final transformation
-void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
-	D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
-{
-	std::vector<unsigned int> iArray;
-	iArray.reserve(3);
-
-	aiMatrix4x4 abs;
-
-	// Find all meshes with the same name as the node
-	for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
-	{
-		const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
-		ai_assert(NULL != pcMesh);
-
-		if (pcIn->mName == pcMesh->mName)
-			iArray.push_back(a);
-	}
-	if (!iArray.empty())
-	{
-		// The matrix should be identical for all meshes with the 
-		// same name. It HAS to be identical for all meshes .....
-		D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
-
-		// Compute the inverse of the transformation matrix to move the
-		// vertices back to their relative and local space
-		aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
-		mInv.Inverse();mInvTransposed.Transpose();
-		aiVector3D pivot = pcIn->vPivot;
-
-		pcOut->mNumMeshes = (unsigned int)iArray.size();
-		pcOut->mMeshes = new unsigned int[iArray.size()];
-		for (unsigned int i = 0;i < iArray.size();++i)	{
-			const unsigned int iIndex = iArray[i];
-			aiMesh* const mesh = pcSOut->mMeshes[iIndex];
-
-			// Transform the vertices back into their local space
-			// fixme: consider computing normals after this, so we don't need to transform them
-			const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
-			aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
-
-			for (;pvCurrent != pvEnd;++pvCurrent,++t2) {
-				*pvCurrent = mInv * (*pvCurrent);
-				*t2 = mInvTransposed * (*t2);
-			}
-
-			// Handle negative transformation matrix determinant -> invert vertex x
-			if (imesh->mMat.Determinant() < 0.0f)
-			{
-				/* we *must* have normals */
-				for (pvCurrent = mesh->mVertices,t2 = mesh->mNormals;pvCurrent != pvEnd;++pvCurrent,++t2) {
-					pvCurrent->x *= -1.f;
-					t2->x *= -1.f;
-				}
-				DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
-			}
-
-			// Handle pivot point
-			if(pivot.x || pivot.y || pivot.z)
-			{
-				for (pvCurrent = mesh->mVertices;pvCurrent != pvEnd;++pvCurrent)	{
-					*pvCurrent -= pivot;	
-				}
-			}
-
-			// Setup the mesh index
-			pcOut->mMeshes[i] = iIndex;
-		}
-	}
-
-	// Setup the name of the node
-	pcOut->mName.Set(pcIn->mName);
-
-	// Now build the transformation matrix of the node
-	// ROTATION
-	if (pcIn->aRotationKeys.size()){
-
-		// FIX to get to Assimp's quaternion conventions
-		for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
-			(*it).mValue.w *= -1.f;
-		}
-
-		pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
-	}
-	else if (pcIn->aCameraRollKeys.size()) 
-	{
-		aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
-			pcOut->mTransformation);
-	}
-
-	// SCALING
-	aiMatrix4x4& m = pcOut->mTransformation;
-	if (pcIn->aScalingKeys.size())
-	{
-		const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
-		m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
-		m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
-		m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
-	}
-
-	// TRANSLATION
-	if (pcIn->aPositionKeys.size())
-	{
-		const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
-		m.a4 += v.x;
-		m.b4 += v.y;
-		m.c4 += v.z;
-	}
-
-	// Generate animation channels for the node
-	if (pcIn->aPositionKeys.size()  > 1  || pcIn->aRotationKeys.size()   > 1 ||
-		pcIn->aScalingKeys.size()   > 1  || pcIn->aCameraRollKeys.size() > 1 ||
-		pcIn->aTargetPositionKeys.size() > 1)
-	{
-		aiAnimation* anim = pcSOut->mAnimations[0];
-		ai_assert(NULL != anim);
-
-		if (pcIn->aCameraRollKeys.size() > 1)
-		{
-			DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
-
-			// Camera roll keys - in fact they're just rotations
-			// around the camera's z axis. The angles are given
-			// in degrees (and they're clockwise).
-			pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
-			for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
-			{
-				aiQuatKey&  q = pcIn->aRotationKeys[i];
-				aiFloatKey& f = pcIn->aCameraRollKeys[i];
-
-				q.mTime  = f.mTime;
-
-				// FIX to get to Assimp quaternion conventions
-				q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
-			}
-		}
-#if 0
-		if (pcIn->aTargetPositionKeys.size() > 1)
-		{
-			DefaultLogger::get()->debug("3DS: Converting target track ...");
-
-			// Camera or spot light - need to convert the separate
-			// target position channel to our representation
-			TargetAnimationHelper helper;
-
-			if (pcIn->aPositionKeys.empty())
-			{
-				// We can just pass zero here ...
-				helper.SetFixedMainAnimationChannel(aiVector3D());
-			}
-			else  helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
-			helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
-
-			// Do the conversion
-			std::vector<aiVectorKey> distanceTrack;
-			helper.Process(&distanceTrack);
-
-			// Now add a new node as child, name it <ourName>.Target
-			// and assign the distance track to it. This is that the
-			// information where the target is and how it moves is
-			// not lost
-			D3DS::Node* nd = new D3DS::Node();
-			pcIn->push_back(nd);
-
-			nd->mName = pcIn->mName + ".Target";
-
-			aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
-			nda->mNodeName.Set(nd->mName);
-
-			nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
-			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
-			::memcpy(nda->mPositionKeys,&distanceTrack[0],
-				sizeof(aiVectorKey)*nda->mNumPositionKeys);
-		}
-#endif
-
-		// Cameras or lights define their transformation in their parent node and in the
-		// corresponding light or camera chunks. However, we read and process the latter
-		// to to be able to return valid cameras/lights even if no scenegraph is given.
-		for (unsigned int n = 0; n < pcSOut->mNumCameras;++n)	{
-			if (pcSOut->mCameras[n]->mName == pcOut->mName) {
-				pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
-			}
-		}
-		for (unsigned int n = 0; n < pcSOut->mNumLights;++n)	{
-			if (pcSOut->mLights[n]->mName == pcOut->mName) {
-				pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
-			}
-		}
-
-		// Allocate a new node anim and setup its name
-		aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
-		nda->mNodeName.Set(pcIn->mName);
-
-		// POSITION keys
-		if (pcIn->aPositionKeys.size()  > 0)
-		{
-			nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
-			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
-			::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
-				sizeof(aiVectorKey)*nda->mNumPositionKeys);
-		}
-
-		// ROTATION keys
-		if (pcIn->aRotationKeys.size()  > 0)
-		{
-			nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
-			nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
-
-			// Rotations are quaternion offsets
-			aiQuaternion abs;
-			for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
-			{
-				const aiQuatKey& q = pcIn->aRotationKeys[n];
-
-				abs = (n ? abs * q.mValue : q.mValue);
-				nda->mRotationKeys[n].mTime  = q.mTime;
-				nda->mRotationKeys[n].mValue = abs.Normalize();
-			}
-		}
-
-		// SCALING keys
-		if (pcIn->aScalingKeys.size()  > 0)
-		{
-			nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
-			nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
-			::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
-				sizeof(aiVectorKey)*nda->mNumScalingKeys);
-		}
-	}
-
-	// Allocate storage for children 
-	pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
-	pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
-
-	// Recursively process all children
-	const unsigned int size = pcIn->mChildren.size();
-	for (unsigned int i = 0; i < size;++i)
-	{
-		pcOut->mChildren[i] = new aiNode();
-		pcOut->mChildren[i]->mParent = pcOut;
-		AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
-	}
-}
-
-// ------------------------------------------------------------------------------------------------
-// Find out how many node animation channels we'll have finally
-void CountTracks(D3DS::Node* node, unsigned int& cnt)
-{
-	//////////////////////////////////////////////////////////////////////////////
-	// We will never generate more than one channel for a node, so
-	// this is rather easy here.
-
-	if (node->aPositionKeys.size()  > 1  || node->aRotationKeys.size()   > 1   ||
-		node->aScalingKeys.size()   > 1  || node->aCameraRollKeys.size() > 1 ||
-		node->aTargetPositionKeys.size()  > 1)
-	{
-		++cnt;
-
-		// account for the additional channel for the camera/spotlight target position
-		if (node->aTargetPositionKeys.size()  > 1)++cnt;
-	}
-
-	// Recursively process all children
-	for (unsigned int i = 0; i < node->mChildren.size();++i)
-		CountTracks(node->mChildren[i],cnt);
-}
-
-// ------------------------------------------------------------------------------------------------
-// Generate the output node graph
-void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
-{
-	pcOut->mRootNode = new aiNode();
-	if (0 == mRootNode->mChildren.size())
-	{
-		//////////////////////////////////////////////////////////////////////////////
-		// It seems the file is so fucked up that it has not even a hierarchy.
-		// generate a flat hiearachy which looks like this:
-		//
-		//                ROOT_NODE
-		//                   |
-		//   ----------------------------------------
-		//   |       |       |            |         |  
-		// MESH_0  MESH_1  MESH_2  ...  MESH_N    CAMERA_0 ....
-		//
-		DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
-
-		pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + 
-			mScene->mCameras.size() + mScene->mLights.size();
-
-		pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
-		pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
-
-		// Build dummy nodes for all meshes
-		unsigned int a = 0;
-		for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
-		{
-			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
-			pcNode->mParent = pcOut->mRootNode;
-			pcNode->mMeshes = new unsigned int[1];
-			pcNode->mMeshes[0] = i;
-			pcNode->mNumMeshes = 1;
-
-			// Build a name for the node
-			pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i);	
-		}
-
-		// Build dummy nodes for all cameras
-		for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
-		{
-			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
-			pcNode->mParent = pcOut->mRootNode;
-
-			// Build a name for the node
-			pcNode->mName = mScene->mCameras[i]->mName;
-		}
-
-		// Build dummy nodes for all lights
-		for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
-		{
-			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
-			pcNode->mParent = pcOut->mRootNode;
-
-			// Build a name for the node
-			pcNode->mName = mScene->mLights[i]->mName;
-		}
-	}
-	else
-	{
-		// First of all: find out how many scaling, rotation and translation
-		// animation tracks we'll have afterwards
-		unsigned int numChannel = 0;
-		CountTracks(mRootNode,numChannel);
-
-		if (numChannel)
-		{
-			// Allocate a primary animation channel
-			pcOut->mNumAnimations = 1;
-			pcOut->mAnimations    = new aiAnimation*[1];
-			aiAnimation* anim     = pcOut->mAnimations[0] = new aiAnimation();
-
-			anim->mName.Set("3DSMasterAnim");
-
-			// Allocate enough storage for all node animation channels, 
-			// but don't set the mNumChannels member - we'll use it to
-			// index into the array
-			anim->mChannels = new aiNodeAnim*[numChannel];
-		}
-
-		aiMatrix4x4 m;
-		AddNodeToGraph(pcOut,  pcOut->mRootNode, mRootNode,m);
-	}
-
-	// We used the first vertex color set to store some emporary values so we need to cleanup here
-	for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
-		pcOut->mMeshes[a]->mColors[0] = NULL;
-
-	pcOut->mRootNode->mTransformation = aiMatrix4x4(
-		1.f,0.f,0.f,0.f,
-		0.f,0.f,1.f,0.f,
-		0.f,-1.f,0.f,0.f,
-		0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
-
-	// If the root node is unnamed name it "<3DSRoot>"
-	if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
-		(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
-	{
-		pcOut->mRootNode->mName.Set("<3DSRoot>");
-	}
-}
-
-// ------------------------------------------------------------------------------------------------
-// Convert all meshes in the scene and generate the final output scene.
-void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
-{
-	// Allocate enough storage for all output materials
-	pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
-	pcOut->mMaterials    = new aiMaterial*[pcOut->mNumMaterials];
-
-	//  ... and convert the 3DS materials to aiMaterial's
-	for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
-	{
-		aiMaterial* pcNew = new aiMaterial();
-		ConvertMaterial(mScene->mMaterials[i],*pcNew);
-		pcOut->mMaterials[i] = pcNew;
-	}
-
-	// Generate the output mesh list
-	ConvertMeshes(pcOut);
-
-	// Now copy all light sources to the output scene
-	pcOut->mNumLights = (unsigned int)mScene->mLights.size();
-	if (pcOut->mNumLights)
-	{
-		pcOut->mLights = new aiLight*[pcOut->mNumLights];
-		::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
-	}
-
-	// Now copy all cameras to the output scene
-	pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
-	if (pcOut->mNumCameras)
-	{
-		pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
-		::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
-	}
-}
-
-#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the following 
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+/** @file Implementation of the 3ds importer class */
+
+#include "AssimpPCH.h"
+#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
+
+// internal headers
+#include "3DSLoader.h"
+#include "TargetAnimation.h"
+
+using namespace Assimp;
+
+// ------------------------------------------------------------------------------------------------
+// Setup final material indices, generae a default material if necessary
+void Discreet3DSImporter::ReplaceDefaultMaterial()
+{
+	
+	// Try to find an existing material that matches the
+	// typical default material setting:
+	// - no textures
+	// - diffuse color (in grey!)
+	// NOTE: This is here to workaround the fact that some
+	// exporters are writing a default material, too.
+	unsigned int idx = 0xcdcdcdcd;
+	for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
+	{
+		std::string s = mScene->mMaterials[i].mName;
+		for (std::string::iterator it = s.begin(); it != s.end(); ++it)
+			*it = ::tolower(*it);
+
+		if (std::string::npos == s.find("default"))continue;
+
+		if (mScene->mMaterials[i].mDiffuse.r !=
+			mScene->mMaterials[i].mDiffuse.g ||
+			mScene->mMaterials[i].mDiffuse.r !=
+			mScene->mMaterials[i].mDiffuse.b)continue;
+
+		if (mScene->mMaterials[i].sTexDiffuse.mMapName.length()   != 0	||
+			mScene->mMaterials[i].sTexBump.mMapName.length()      != 0	|| 
+			mScene->mMaterials[i].sTexOpacity.mMapName.length()   != 0	||
+			mScene->mMaterials[i].sTexEmissive.mMapName.length()  != 0	||
+			mScene->mMaterials[i].sTexSpecular.mMapName.length()  != 0	||
+			mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
+		{
+			continue;
+		}
+		idx = i;
+	}
+	if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
+
+	// now iterate through all meshes and through all faces and
+	// find all faces that are using the default material
+	unsigned int cnt = 0;
+	for (std::vector<D3DS::Mesh>::iterator
+		i =  mScene->mMeshes.begin();
+		i != mScene->mMeshes.end();++i)
+	{
+		for (std::vector<unsigned int>::iterator
+			a =  (*i).mFaceMaterials.begin();
+			a != (*i).mFaceMaterials.end();++a)
+		{
+			// NOTE: The additional check seems to be necessary,
+			// some exporters seem to generate invalid data here
+			if (0xcdcdcdcd == (*a))
+			{
+				(*a) = idx;
+				++cnt;
+			}
+			else if ( (*a) >= mScene->mMaterials.size())
+			{
+				(*a) = idx;
+				DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
+				++cnt;
+			}
+		}
+	}
+	if (cnt && idx == mScene->mMaterials.size())
+	{
+		// We need to create our own default material
+		D3DS::Material sMat;
+		sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
+		sMat.mName = "%%%DEFAULT";
+		mScene->mMaterials.push_back(sMat);
+
+		DefaultLogger::get()->info("3DS: Generating default material");
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
+void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
+{
+	for (std::vector< D3DS::Face >::iterator i =  sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
+	{
+		// check whether all indices are in range
+		for (unsigned int a = 0; a < 3;++a)
+		{
+			if ((*i).mIndices[a] >= sMesh.mPositions.size())
+			{
+				DefaultLogger::get()->warn("3DS: Vertex index overflow)");
+				(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
+			}
+			if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
+			{
+				DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
+				(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
+			}
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Generate out unique verbose format representation
+void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
+{
+	// TODO: really necessary? I don't think. Just a waste of memory and time
+	// to do it now in a separate buffer. 
+
+	// Allocate output storage
+	std::vector<aiVector3D> vNew  (sMesh.mFaces.size() * 3);
+	std::vector<aiVector3D> vNew2;
+	if (sMesh.mTexCoords.size())
+		vNew2.resize(sMesh.mFaces.size() * 3);
+
+	for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
+	{
+		D3DS::Face& face = sMesh.mFaces[i];
+
+		// Positions
+		for (unsigned int a = 0; a < 3;++a,++base)
+		{
+			vNew[base] = sMesh.mPositions[face.mIndices[a]];
+			if (sMesh.mTexCoords.size())
+				vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
+
+			face.mIndices[a] = base;
+		}
+	}
+	sMesh.mPositions = vNew;
+	sMesh.mTexCoords = vNew2;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Convert a 3DS texture to texture keys in an aiMaterial
+void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
+{
+	// Setup the texture name
+	aiString tex;
+	tex.Set( texture.mMapName);
+	mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
+
+	// Setup the texture blend factor
+	if (is_not_qnan(texture.mTextureBlend))
+		mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
+
+	// Setup the texture mapping mode
+	mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
+	mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
+
+	// Mirroring - double the scaling values 
+	// FIXME: this is not really correct ...
+	if (texture.mMapMode == aiTextureMapMode_Mirror)
+	{
+		texture.mScaleU *= 2.f;
+		texture.mScaleV *= 2.f;
+		texture.mOffsetU /= 2.f;
+		texture.mOffsetV /= 2.f;
+	}
+	
+	// Setup texture UV transformations
+	mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
+}
+
+// ------------------------------------------------------------------------------------------------
+// Convert a 3DS material to an aiMaterial
+void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
+	aiMaterial& mat)
+{
+	// NOTE: Pass the background image to the viewer by bypassing the
+	// material system. This is an evil hack, never do it again!
+	if (0 != mBackgroundImage.length() && bHasBG)
+	{
+		aiString tex;
+		tex.Set( mBackgroundImage);
+		mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
+
+		// Be sure this is only done for the first material
+		mBackgroundImage = std::string("");
+	}
+
+	// At first add the base ambient color of the scene to the material
+	oldMat.mAmbient.r += mClrAmbient.r;
+	oldMat.mAmbient.g += mClrAmbient.g;
+	oldMat.mAmbient.b += mClrAmbient.b;
+
+	aiString name;
+	name.Set( oldMat.mName);
+	mat.AddProperty( &name, AI_MATKEY_NAME);
+
+	// Material colors
+	mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
+	mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
+	mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
+	mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
+
+	// Phong shininess and shininess strength
+	if (D3DS::Discreet3DS::Phong == oldMat.mShading || 
+		D3DS::Discreet3DS::Metal == oldMat.mShading)
+	{
+		if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
+		{
+			oldMat.mShading = D3DS::Discreet3DS::Gouraud;
+		}
+		else
+		{
+			mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
+			mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
+		}
+	}
+
+	// Opacity
+	mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
+
+	// Bump height scaling
+	mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
+
+	// Two sided rendering?
+	if (oldMat.mTwoSided)
+	{
+		int i = 1;
+		mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
+	}
+
+	// Shading mode
+	aiShadingMode eShading = aiShadingMode_NoShading;
+	switch (oldMat.mShading)
+	{
+		case D3DS::Discreet3DS::Flat:
+			eShading = aiShadingMode_Flat; break;
+
+		// I don't know what "Wire" shading should be,
+		// assume it is simple lambertian diffuse shading
+		case D3DS::Discreet3DS::Wire:
+			{
+				// Set the wireframe flag
+				unsigned int iWire = 1;
+				mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
+			}
+
+		case D3DS::Discreet3DS::Gouraud:
+			eShading = aiShadingMode_Gouraud; break;
+
+		// assume cook-torrance shading for metals.
+		case D3DS::Discreet3DS::Phong :
+			eShading = aiShadingMode_Phong; break;
+
+		case D3DS::Discreet3DS::Metal :
+			eShading = aiShadingMode_CookTorrance; break;
+
+			// FIX to workaround a warning with GCC 4 who complained
+			// about a missing case Blinn: here - Blinn isn't a valid
+			// value in the 3DS Loader, it is just needed for ASE
+		case D3DS::Discreet3DS::Blinn :
+			eShading = aiShadingMode_Blinn; break;
+	}
+	mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
+
+	// DIFFUSE texture
+	if( oldMat.sTexDiffuse.mMapName.length() > 0)
+		CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
+
+	// SPECULAR texture
+	if( oldMat.sTexSpecular.mMapName.length() > 0)
+		CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
+
+	// OPACITY texture
+	if( oldMat.sTexOpacity.mMapName.length() > 0)
+		CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
+
+	// EMISSIVE texture
+	if( oldMat.sTexEmissive.mMapName.length() > 0)
+		CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
+
+	// BUMP texture
+	if( oldMat.sTexBump.mMapName.length() > 0)
+		CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
+
+	// SHININESS texture
+	if( oldMat.sTexShininess.mMapName.length() > 0)
+		CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
+
+	// REFLECTION texture
+	if( oldMat.sTexReflective.mMapName.length() > 0)
+		CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
+
+	// Store the name of the material itself, too
+	if( oldMat.mName.length())	{
+		aiString tex;
+		tex.Set( oldMat.mName);
+		mat.AddProperty( &tex, AI_MATKEY_NAME);
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Split meshes by their materials and generate output aiMesh'es
+void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
+{
+	std::vector<aiMesh*> avOutMeshes;
+	avOutMeshes.reserve(mScene->mMeshes.size() * 2);
+
+	unsigned int iFaceCnt = 0,num = 0;
+	aiString name;
+
+	// we need to split all meshes by their materials
+	for (std::vector<D3DS::Mesh>::iterator i =  mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i)	{
+		boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
+
+		name.length = ASSIMP_itoa10(name.data,num++);
+
+		unsigned int iNum = 0;
+		for (std::vector<unsigned int>::const_iterator a =  (*i).mFaceMaterials.begin();
+			a != (*i).mFaceMaterials.end();++a,++iNum)
+		{
+			aiSplit[*a].push_back(iNum);
+		}
+		// now generate submeshes
+		for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
+		{
+			if (aiSplit[p].empty())	{
+				continue;
+			}
+			aiMesh* meshOut = new aiMesh();
+			meshOut->mName = name;
+			meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+
+			// be sure to setup the correct material index
+			meshOut->mMaterialIndex = p;
+
+			// use the color data as temporary storage
+			meshOut->mColors[0] = (aiColor4D*)(&*i);
+			avOutMeshes.push_back(meshOut);
+
+			// convert vertices
+			meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
+			meshOut->mNumVertices = meshOut->mNumFaces*3;
+
+			// allocate enough storage for faces
+			meshOut->mFaces = new aiFace[meshOut->mNumFaces];
+			iFaceCnt += meshOut->mNumFaces;
+
+			meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
+			meshOut->mNormals  = new aiVector3D[meshOut->mNumVertices];
+			if ((*i).mTexCoords.size())
+			{
+				meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
+			}
+			for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
+			{
+				register unsigned int index = aiSplit[p][q];
+				aiFace& face = meshOut->mFaces[q];
+
+				face.mIndices = new unsigned int[3];
+				face.mNumIndices = 3;
+
+				for (unsigned int a = 0; a < 3;++a,++base)
+				{
+					unsigned int idx = (*i).mFaces[index].mIndices[a];
+					meshOut->mVertices[base]  = (*i).mPositions[idx];
+					meshOut->mNormals [base]  = (*i).mNormals[idx];
+
+					if ((*i).mTexCoords.size())
+						meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
+
+					face.mIndices[a] = base;
+				}
+			}
+		}
+	}
+
+	// Copy them to the output array
+	pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
+	pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
+	for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
+		pcOut->mMeshes[a] = avOutMeshes[a];
+	}
+
+	// We should have at least one face here
+	if (!iFaceCnt) {
+		throw DeadlyImportError("No faces loaded. The mesh is empty");
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Add a node to the scenegraph and setup its final transformation
+void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
+	D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
+{
+	std::vector<unsigned int> iArray;
+	iArray.reserve(3);
+
+	aiMatrix4x4 abs;
+
+	// Find all meshes with the same name as the node
+	for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
+	{
+		const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
+		ai_assert(NULL != pcMesh);
+
+		if (pcIn->mName == pcMesh->mName)
+			iArray.push_back(a);
+	}
+	if (!iArray.empty())
+	{
+		// The matrix should be identical for all meshes with the 
+		// same name. It HAS to be identical for all meshes .....
+		D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
+
+		// Compute the inverse of the transformation matrix to move the
+		// vertices back to their relative and local space
+		aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
+		mInv.Inverse();mInvTransposed.Transpose();
+		aiVector3D pivot = pcIn->vPivot;
+
+		pcOut->mNumMeshes = (unsigned int)iArray.size();
+		pcOut->mMeshes = new unsigned int[iArray.size()];
+		for (unsigned int i = 0;i < iArray.size();++i)	{
+			const unsigned int iIndex = iArray[i];
+			aiMesh* const mesh = pcSOut->mMeshes[iIndex];
+
+			// Transform the vertices back into their local space
+			// fixme: consider computing normals after this, so we don't need to transform them
+			const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
+			aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
+
+			for (;pvCurrent != pvEnd;++pvCurrent,++t2) {
+				*pvCurrent = mInv * (*pvCurrent);
+				*t2 = mInvTransposed * (*t2);
+			}
+
+			// Handle negative transformation matrix determinant -> invert vertex x
+			if (imesh->mMat.Determinant() < 0.0f)
+			{
+				/* we *must* have normals */
+				for (pvCurrent = mesh->mVertices,t2 = mesh->mNormals;pvCurrent != pvEnd;++pvCurrent,++t2) {
+					pvCurrent->x *= -1.f;
+					t2->x *= -1.f;
+				}
+				DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
+			}
+
+			// Handle pivot point
+			if(pivot.x || pivot.y || pivot.z)
+			{
+				for (pvCurrent = mesh->mVertices;pvCurrent != pvEnd;++pvCurrent)	{
+					*pvCurrent -= pivot;	
+				}
+			}
+
+			// Setup the mesh index
+			pcOut->mMeshes[i] = iIndex;
+		}
+	}
+
+	// Setup the name of the node
+	pcOut->mName.Set(pcIn->mName);
+
+	// Now build the transformation matrix of the node
+	// ROTATION
+	if (pcIn->aRotationKeys.size()){
+
+		// FIX to get to Assimp's quaternion conventions
+		for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
+			(*it).mValue.w *= -1.f;
+		}
+
+		pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
+	}
+	else if (pcIn->aCameraRollKeys.size()) 
+	{
+		aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
+			pcOut->mTransformation);
+	}
+
+	// SCALING
+	aiMatrix4x4& m = pcOut->mTransformation;
+	if (pcIn->aScalingKeys.size())
+	{
+		const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
+		m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
+		m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
+		m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
+	}
+
+	// TRANSLATION
+	if (pcIn->aPositionKeys.size())
+	{
+		const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
+		m.a4 += v.x;
+		m.b4 += v.y;
+		m.c4 += v.z;
+	}
+
+	// Generate animation channels for the node
+	if (pcIn->aPositionKeys.size()  > 1  || pcIn->aRotationKeys.size()   > 1 ||
+		pcIn->aScalingKeys.size()   > 1  || pcIn->aCameraRollKeys.size() > 1 ||
+		pcIn->aTargetPositionKeys.size() > 1)
+	{
+		aiAnimation* anim = pcSOut->mAnimations[0];
+		ai_assert(NULL != anim);
+
+		if (pcIn->aCameraRollKeys.size() > 1)
+		{
+			DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
+
+			// Camera roll keys - in fact they're just rotations
+			// around the camera's z axis. The angles are given
+			// in degrees (and they're clockwise).
+			pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
+			for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
+			{
+				aiQuatKey&  q = pcIn->aRotationKeys[i];
+				aiFloatKey& f = pcIn->aCameraRollKeys[i];
+
+				q.mTime  = f.mTime;
+
+				// FIX to get to Assimp quaternion conventions
+				q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
+			}
+		}
+#if 0
+		if (pcIn->aTargetPositionKeys.size() > 1)
+		{
+			DefaultLogger::get()->debug("3DS: Converting target track ...");
+
+			// Camera or spot light - need to convert the separate
+			// target position channel to our representation
+			TargetAnimationHelper helper;
+
+			if (pcIn->aPositionKeys.empty())
+			{
+				// We can just pass zero here ...
+				helper.SetFixedMainAnimationChannel(aiVector3D());
+			}
+			else  helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
+			helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
+
+			// Do the conversion
+			std::vector<aiVectorKey> distanceTrack;
+			helper.Process(&distanceTrack);
+
+			// Now add a new node as child, name it <ourName>.Target
+			// and assign the distance track to it. This is that the
+			// information where the target is and how it moves is
+			// not lost
+			D3DS::Node* nd = new D3DS::Node();
+			pcIn->push_back(nd);
+
+			nd->mName = pcIn->mName + ".Target";
+
+			aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
+			nda->mNodeName.Set(nd->mName);
+
+			nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
+			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
+			::memcpy(nda->mPositionKeys,&distanceTrack[0],
+				sizeof(aiVectorKey)*nda->mNumPositionKeys);
+		}
+#endif
+
+		// Cameras or lights define their transformation in their parent node and in the
+		// corresponding light or camera chunks. However, we read and process the latter
+		// to to be able to return valid cameras/lights even if no scenegraph is given.
+		for (unsigned int n = 0; n < pcSOut->mNumCameras;++n)	{
+			if (pcSOut->mCameras[n]->mName == pcOut->mName) {
+				pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
+			}
+		}
+		for (unsigned int n = 0; n < pcSOut->mNumLights;++n)	{
+			if (pcSOut->mLights[n]->mName == pcOut->mName) {
+				pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
+			}
+		}
+
+		// Allocate a new node anim and setup its name
+		aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
+		nda->mNodeName.Set(pcIn->mName);
+
+		// POSITION keys
+		if (pcIn->aPositionKeys.size()  > 0)
+		{
+			nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
+			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
+			::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
+				sizeof(aiVectorKey)*nda->mNumPositionKeys);
+		}
+
+		// ROTATION keys
+		if (pcIn->aRotationKeys.size()  > 0)
+		{
+			nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
+			nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
+
+			// Rotations are quaternion offsets
+			aiQuaternion abs;
+			for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
+			{
+				const aiQuatKey& q = pcIn->aRotationKeys[n];
+
+				abs = (n ? abs * q.mValue : q.mValue);
+				nda->mRotationKeys[n].mTime  = q.mTime;
+				nda->mRotationKeys[n].mValue = abs.Normalize();
+			}
+		}
+
+		// SCALING keys
+		if (pcIn->aScalingKeys.size()  > 0)
+		{
+			nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
+			nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
+			::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
+				sizeof(aiVectorKey)*nda->mNumScalingKeys);
+		}
+	}
+
+	// Allocate storage for children 
+	pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
+	pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
+
+	// Recursively process all children
+	const unsigned int size = pcIn->mChildren.size();
+	for (unsigned int i = 0; i < size;++i)
+	{
+		pcOut->mChildren[i] = new aiNode();
+		pcOut->mChildren[i]->mParent = pcOut;
+		AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Find out how many node animation channels we'll have finally
+void CountTracks(D3DS::Node* node, unsigned int& cnt)
+{
+	//////////////////////////////////////////////////////////////////////////////
+	// We will never generate more than one channel for a node, so
+	// this is rather easy here.
+
+	if (node->aPositionKeys.size()  > 1  || node->aRotationKeys.size()   > 1   ||
+		node->aScalingKeys.size()   > 1  || node->aCameraRollKeys.size() > 1 ||
+		node->aTargetPositionKeys.size()  > 1)
+	{
+		++cnt;
+
+		// account for the additional channel for the camera/spotlight target position
+		if (node->aTargetPositionKeys.size()  > 1)++cnt;
+	}
+
+	// Recursively process all children
+	for (unsigned int i = 0; i < node->mChildren.size();++i)
+		CountTracks(node->mChildren[i],cnt);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Generate the output node graph
+void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
+{
+	pcOut->mRootNode = new aiNode();
+	if (0 == mRootNode->mChildren.size())
+	{
+		//////////////////////////////////////////////////////////////////////////////
+		// It seems the file is so fucked up that it has not even a hierarchy.
+		// generate a flat hiearachy which looks like this:
+		//
+		//                ROOT_NODE
+		//                   |
+		//   ----------------------------------------
+		//   |       |       |            |         |  
+		// MESH_0  MESH_1  MESH_2  ...  MESH_N    CAMERA_0 ....
+		//
+		DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
+
+		pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + 
+			mScene->mCameras.size() + mScene->mLights.size();
+
+		pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
+		pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
+
+		// Build dummy nodes for all meshes
+		unsigned int a = 0;
+		for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
+		{
+			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
+			pcNode->mParent = pcOut->mRootNode;
+			pcNode->mMeshes = new unsigned int[1];
+			pcNode->mMeshes[0] = i;
+			pcNode->mNumMeshes = 1;
+
+			// Build a name for the node
+			pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i);	
+		}
+
+		// Build dummy nodes for all cameras
+		for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
+		{
+			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
+			pcNode->mParent = pcOut->mRootNode;
+
+			// Build a name for the node
+			pcNode->mName = mScene->mCameras[i]->mName;
+		}
+
+		// Build dummy nodes for all lights
+		for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
+		{
+			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
+			pcNode->mParent = pcOut->mRootNode;
+
+			// Build a name for the node
+			pcNode->mName = mScene->mLights[i]->mName;
+		}
+	}
+	else
+	{
+		// First of all: find out how many scaling, rotation and translation
+		// animation tracks we'll have afterwards
+		unsigned int numChannel = 0;
+		CountTracks(mRootNode,numChannel);
+
+		if (numChannel)
+		{
+			// Allocate a primary animation channel
+			pcOut->mNumAnimations = 1;
+			pcOut->mAnimations    = new aiAnimation*[1];
+			aiAnimation* anim     = pcOut->mAnimations[0] = new aiAnimation();
+
+			anim->mName.Set("3DSMasterAnim");
+
+			// Allocate enough storage for all node animation channels, 
+			// but don't set the mNumChannels member - we'll use it to
+			// index into the array
+			anim->mChannels = new aiNodeAnim*[numChannel];
+		}
+
+		aiMatrix4x4 m;
+		AddNodeToGraph(pcOut,  pcOut->mRootNode, mRootNode,m);
+	}
+
+	// We used the first vertex color set to store some emporary values so we need to cleanup here
+	for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
+		pcOut->mMeshes[a]->mColors[0] = NULL;
+
+	pcOut->mRootNode->mTransformation = aiMatrix4x4(
+		1.f,0.f,0.f,0.f,
+		0.f,0.f,1.f,0.f,
+		0.f,-1.f,0.f,0.f,
+		0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
+
+	// If the root node is unnamed name it "<3DSRoot>"
+	if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
+		(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
+	{
+		pcOut->mRootNode->mName.Set("<3DSRoot>");
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Convert all meshes in the scene and generate the final output scene.
+void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
+{
+	// Allocate enough storage for all output materials
+	pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
+	pcOut->mMaterials    = new aiMaterial*[pcOut->mNumMaterials];
+
+	//  ... and convert the 3DS materials to aiMaterial's
+	for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
+	{
+		aiMaterial* pcNew = new aiMaterial();
+		ConvertMaterial(mScene->mMaterials[i],*pcNew);
+		pcOut->mMaterials[i] = pcNew;
+	}
+
+	// Generate the output mesh list
+	ConvertMeshes(pcOut);
+
+	// Now copy all light sources to the output scene
+	pcOut->mNumLights = (unsigned int)mScene->mLights.size();
+	if (pcOut->mNumLights)
+	{
+		pcOut->mLights = new aiLight*[pcOut->mNumLights];
+		::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
+	}
+
+	// Now copy all cameras to the output scene
+	pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
+	if (pcOut->mNumCameras)
+	{
+		pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
+		::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
+	}
+}
+
+#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER

3rdparty/assimp/src/3DSHelper.h

-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2012, assimp team
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms, 
-with or without modification, are permitted provided that the 
-following conditions are met:
-
-* Redistributions of source code must retain the above
-  copyright notice, this list of conditions and the
-  following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-  copyright notice, this list of conditions and the
-  following disclaimer in the documentation and/or other
-  materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
-  contributors may be used to endorse or promote products