vrshoot

diff libs/assimp/3DSConverter.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/3DSConverter.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,841 @@
     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 Implementation of the 3ds importer class */
    1.46 +
    1.47 +#include "AssimpPCH.h"
    1.48 +#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
    1.49 +
    1.50 +// internal headers
    1.51 +#include "3DSLoader.h"
    1.52 +#include "TargetAnimation.h"
    1.53 +
    1.54 +using namespace Assimp;
    1.55 +
    1.56 +// ------------------------------------------------------------------------------------------------
    1.57 +// Setup final material indices, generae a default material if necessary
    1.58 +void Discreet3DSImporter::ReplaceDefaultMaterial()
    1.59 +{
    1.60 +	
    1.61 +	// Try to find an existing material that matches the
    1.62 +	// typical default material setting:
    1.63 +	// - no textures
    1.64 +	// - diffuse color (in grey!)
    1.65 +	// NOTE: This is here to workaround the fact that some
    1.66 +	// exporters are writing a default material, too.
    1.67 +	unsigned int idx = 0xcdcdcdcd;
    1.68 +	for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
    1.69 +	{
    1.70 +		std::string s = mScene->mMaterials[i].mName;
    1.71 +		for (std::string::iterator it = s.begin(); it != s.end(); ++it)
    1.72 +			*it = ::tolower(*it);
    1.73 +
    1.74 +		if (std::string::npos == s.find("default"))continue;
    1.75 +
    1.76 +		if (mScene->mMaterials[i].mDiffuse.r !=
    1.77 +			mScene->mMaterials[i].mDiffuse.g ||
    1.78 +			mScene->mMaterials[i].mDiffuse.r !=
    1.79 +			mScene->mMaterials[i].mDiffuse.b)continue;
    1.80 +
    1.81 +		if (mScene->mMaterials[i].sTexDiffuse.mMapName.length()   != 0	||
    1.82 +			mScene->mMaterials[i].sTexBump.mMapName.length()      != 0	|| 
    1.83 +			mScene->mMaterials[i].sTexOpacity.mMapName.length()   != 0	||
    1.84 +			mScene->mMaterials[i].sTexEmissive.mMapName.length()  != 0	||
    1.85 +			mScene->mMaterials[i].sTexSpecular.mMapName.length()  != 0	||
    1.86 +			mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 )
    1.87 +		{
    1.88 +			continue;
    1.89 +		}
    1.90 +		idx = i;
    1.91 +	}
    1.92 +	if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
    1.93 +
    1.94 +	// now iterate through all meshes and through all faces and
    1.95 +	// find all faces that are using the default material
    1.96 +	unsigned int cnt = 0;
    1.97 +	for (std::vector<D3DS::Mesh>::iterator
    1.98 +		i =  mScene->mMeshes.begin();
    1.99 +		i != mScene->mMeshes.end();++i)
   1.100 +	{
   1.101 +		for (std::vector<unsigned int>::iterator
   1.102 +			a =  (*i).mFaceMaterials.begin();
   1.103 +			a != (*i).mFaceMaterials.end();++a)
   1.104 +		{
   1.105 +			// NOTE: The additional check seems to be necessary,
   1.106 +			// some exporters seem to generate invalid data here
   1.107 +			if (0xcdcdcdcd == (*a))
   1.108 +			{
   1.109 +				(*a) = idx;
   1.110 +				++cnt;
   1.111 +			}
   1.112 +			else if ( (*a) >= mScene->mMaterials.size())
   1.113 +			{
   1.114 +				(*a) = idx;
   1.115 +				DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
   1.116 +				++cnt;
   1.117 +			}
   1.118 +		}
   1.119 +	}
   1.120 +	if (cnt && idx == mScene->mMaterials.size())
   1.121 +	{
   1.122 +		// We need to create our own default material
   1.123 +		D3DS::Material sMat;
   1.124 +		sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
   1.125 +		sMat.mName = "%%%DEFAULT";
   1.126 +		mScene->mMaterials.push_back(sMat);
   1.127 +
   1.128 +		DefaultLogger::get()->info("3DS: Generating default material");
   1.129 +	}
   1.130 +}
   1.131 +
   1.132 +// ------------------------------------------------------------------------------------------------
   1.133 +// Check whether all indices are valid. Otherwise we'd crash before the validation step is reached
   1.134 +void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
   1.135 +{
   1.136 +	for (std::vector< D3DS::Face >::iterator i =  sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i)
   1.137 +	{
   1.138 +		// check whether all indices are in range
   1.139 +		for (unsigned int a = 0; a < 3;++a)
   1.140 +		{
   1.141 +			if ((*i).mIndices[a] >= sMesh.mPositions.size())
   1.142 +			{
   1.143 +				DefaultLogger::get()->warn("3DS: Vertex index overflow)");
   1.144 +				(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
   1.145 +			}
   1.146 +			if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
   1.147 +			{
   1.148 +				DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
   1.149 +				(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
   1.150 +			}
   1.151 +		}
   1.152 +	}
   1.153 +}
   1.154 +
   1.155 +// ------------------------------------------------------------------------------------------------
   1.156 +// Generate out unique verbose format representation
   1.157 +void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh)
   1.158 +{
   1.159 +	// TODO: really necessary? I don't think. Just a waste of memory and time
   1.160 +	// to do it now in a separate buffer. 
   1.161 +
   1.162 +	// Allocate output storage
   1.163 +	std::vector<aiVector3D> vNew  (sMesh.mFaces.size() * 3);
   1.164 +	std::vector<aiVector3D> vNew2;
   1.165 +	if (sMesh.mTexCoords.size())
   1.166 +		vNew2.resize(sMesh.mFaces.size() * 3);
   1.167 +
   1.168 +	for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i)
   1.169 +	{
   1.170 +		D3DS::Face& face = sMesh.mFaces[i];
   1.171 +
   1.172 +		// Positions
   1.173 +		for (unsigned int a = 0; a < 3;++a,++base)
   1.174 +		{
   1.175 +			vNew[base] = sMesh.mPositions[face.mIndices[a]];
   1.176 +			if (sMesh.mTexCoords.size())
   1.177 +				vNew2[base] = sMesh.mTexCoords[face.mIndices[a]];
   1.178 +
   1.179 +			face.mIndices[a] = base;
   1.180 +		}
   1.181 +	}
   1.182 +	sMesh.mPositions = vNew;
   1.183 +	sMesh.mTexCoords = vNew2;
   1.184 +}
   1.185 +
   1.186 +// ------------------------------------------------------------------------------------------------
   1.187 +// Convert a 3DS texture to texture keys in an aiMaterial
   1.188 +void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
   1.189 +{
   1.190 +	// Setup the texture name
   1.191 +	aiString tex;
   1.192 +	tex.Set( texture.mMapName);
   1.193 +	mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
   1.194 +
   1.195 +	// Setup the texture blend factor
   1.196 +	if (is_not_qnan(texture.mTextureBlend))
   1.197 +		mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
   1.198 +
   1.199 +	// Setup the texture mapping mode
   1.200 +	mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
   1.201 +	mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
   1.202 +
   1.203 +	// Mirroring - double the scaling values 
   1.204 +	// FIXME: this is not really correct ...
   1.205 +	if (texture.mMapMode == aiTextureMapMode_Mirror)
   1.206 +	{
   1.207 +		texture.mScaleU *= 2.f;
   1.208 +		texture.mScaleV *= 2.f;
   1.209 +		texture.mOffsetU /= 2.f;
   1.210 +		texture.mOffsetV /= 2.f;
   1.211 +	}
   1.212 +	
   1.213 +	// Setup texture UV transformations
   1.214 +	mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
   1.215 +}
   1.216 +
   1.217 +// ------------------------------------------------------------------------------------------------
   1.218 +// Convert a 3DS material to an aiMaterial
   1.219 +void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
   1.220 +	aiMaterial& mat)
   1.221 +{
   1.222 +	// NOTE: Pass the background image to the viewer by bypassing the
   1.223 +	// material system. This is an evil hack, never do it again!
   1.224 +	if (0 != mBackgroundImage.length() && bHasBG)
   1.225 +	{
   1.226 +		aiString tex;
   1.227 +		tex.Set( mBackgroundImage);
   1.228 +		mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
   1.229 +
   1.230 +		// Be sure this is only done for the first material
   1.231 +		mBackgroundImage = std::string("");
   1.232 +	}
   1.233 +
   1.234 +	// At first add the base ambient color of the scene to the material
   1.235 +	oldMat.mAmbient.r += mClrAmbient.r;
   1.236 +	oldMat.mAmbient.g += mClrAmbient.g;
   1.237 +	oldMat.mAmbient.b += mClrAmbient.b;
   1.238 +
   1.239 +	aiString name;
   1.240 +	name.Set( oldMat.mName);
   1.241 +	mat.AddProperty( &name, AI_MATKEY_NAME);
   1.242 +
   1.243 +	// Material colors
   1.244 +	mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
   1.245 +	mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
   1.246 +	mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
   1.247 +	mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
   1.248 +
   1.249 +	// Phong shininess and shininess strength
   1.250 +	if (D3DS::Discreet3DS::Phong == oldMat.mShading || 
   1.251 +		D3DS::Discreet3DS::Metal == oldMat.mShading)
   1.252 +	{
   1.253 +		if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength)
   1.254 +		{
   1.255 +			oldMat.mShading = D3DS::Discreet3DS::Gouraud;
   1.256 +		}
   1.257 +		else
   1.258 +		{
   1.259 +			mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
   1.260 +			mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
   1.261 +		}
   1.262 +	}
   1.263 +
   1.264 +	// Opacity
   1.265 +	mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY);
   1.266 +
   1.267 +	// Bump height scaling
   1.268 +	mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING);
   1.269 +
   1.270 +	// Two sided rendering?
   1.271 +	if (oldMat.mTwoSided)
   1.272 +	{
   1.273 +		int i = 1;
   1.274 +		mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
   1.275 +	}
   1.276 +
   1.277 +	// Shading mode
   1.278 +	aiShadingMode eShading = aiShadingMode_NoShading;
   1.279 +	switch (oldMat.mShading)
   1.280 +	{
   1.281 +		case D3DS::Discreet3DS::Flat:
   1.282 +			eShading = aiShadingMode_Flat; break;
   1.283 +
   1.284 +		// I don't know what "Wire" shading should be,
   1.285 +		// assume it is simple lambertian diffuse shading
   1.286 +		case D3DS::Discreet3DS::Wire:
   1.287 +			{
   1.288 +				// Set the wireframe flag
   1.289 +				unsigned int iWire = 1;
   1.290 +				mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
   1.291 +			}
   1.292 +
   1.293 +		case D3DS::Discreet3DS::Gouraud:
   1.294 +			eShading = aiShadingMode_Gouraud; break;
   1.295 +
   1.296 +		// assume cook-torrance shading for metals.
   1.297 +		case D3DS::Discreet3DS::Phong :
   1.298 +			eShading = aiShadingMode_Phong; break;
   1.299 +
   1.300 +		case D3DS::Discreet3DS::Metal :
   1.301 +			eShading = aiShadingMode_CookTorrance; break;
   1.302 +
   1.303 +			// FIX to workaround a warning with GCC 4 who complained
   1.304 +			// about a missing case Blinn: here - Blinn isn't a valid
   1.305 +			// value in the 3DS Loader, it is just needed for ASE
   1.306 +		case D3DS::Discreet3DS::Blinn :
   1.307 +			eShading = aiShadingMode_Blinn; break;
   1.308 +	}
   1.309 +	mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
   1.310 +
   1.311 +	// DIFFUSE texture
   1.312 +	if( oldMat.sTexDiffuse.mMapName.length() > 0)
   1.313 +		CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE);
   1.314 +
   1.315 +	// SPECULAR texture
   1.316 +	if( oldMat.sTexSpecular.mMapName.length() > 0)
   1.317 +		CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR);
   1.318 +
   1.319 +	// OPACITY texture
   1.320 +	if( oldMat.sTexOpacity.mMapName.length() > 0)
   1.321 +		CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY);
   1.322 +
   1.323 +	// EMISSIVE texture
   1.324 +	if( oldMat.sTexEmissive.mMapName.length() > 0)
   1.325 +		CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE);
   1.326 +
   1.327 +	// BUMP texture
   1.328 +	if( oldMat.sTexBump.mMapName.length() > 0)
   1.329 +		CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT);
   1.330 +
   1.331 +	// SHININESS texture
   1.332 +	if( oldMat.sTexShininess.mMapName.length() > 0)
   1.333 +		CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS);
   1.334 +
   1.335 +	// REFLECTION texture
   1.336 +	if( oldMat.sTexReflective.mMapName.length() > 0)
   1.337 +		CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION);
   1.338 +
   1.339 +	// Store the name of the material itself, too
   1.340 +	if( oldMat.mName.length())	{
   1.341 +		aiString tex;
   1.342 +		tex.Set( oldMat.mName);
   1.343 +		mat.AddProperty( &tex, AI_MATKEY_NAME);
   1.344 +	}
   1.345 +}
   1.346 +
   1.347 +// ------------------------------------------------------------------------------------------------
   1.348 +// Split meshes by their materials and generate output aiMesh'es
   1.349 +void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
   1.350 +{
   1.351 +	std::vector<aiMesh*> avOutMeshes;
   1.352 +	avOutMeshes.reserve(mScene->mMeshes.size() * 2);
   1.353 +
   1.354 +	unsigned int iFaceCnt = 0,num = 0;
   1.355 +	aiString name;
   1.356 +
   1.357 +	// we need to split all meshes by their materials
   1.358 +	for (std::vector<D3DS::Mesh>::iterator i =  mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i)	{
   1.359 +		boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]);
   1.360 +
   1.361 +		name.length = ASSIMP_itoa10(name.data,num++);
   1.362 +
   1.363 +		unsigned int iNum = 0;
   1.364 +		for (std::vector<unsigned int>::const_iterator a =  (*i).mFaceMaterials.begin();
   1.365 +			a != (*i).mFaceMaterials.end();++a,++iNum)
   1.366 +		{
   1.367 +			aiSplit[*a].push_back(iNum);
   1.368 +		}
   1.369 +		// now generate submeshes
   1.370 +		for (unsigned int p = 0; p < mScene->mMaterials.size();++p)
   1.371 +		{
   1.372 +			if (aiSplit[p].empty())	{
   1.373 +				continue;
   1.374 +			}
   1.375 +			aiMesh* meshOut = new aiMesh();
   1.376 +			meshOut->mName = name;
   1.377 +			meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
   1.378 +
   1.379 +			// be sure to setup the correct material index
   1.380 +			meshOut->mMaterialIndex = p;
   1.381 +
   1.382 +			// use the color data as temporary storage
   1.383 +			meshOut->mColors[0] = (aiColor4D*)(&*i);
   1.384 +			avOutMeshes.push_back(meshOut);
   1.385 +
   1.386 +			// convert vertices
   1.387 +			meshOut->mNumFaces = (unsigned int)aiSplit[p].size();
   1.388 +			meshOut->mNumVertices = meshOut->mNumFaces*3;
   1.389 +
   1.390 +			// allocate enough storage for faces
   1.391 +			meshOut->mFaces = new aiFace[meshOut->mNumFaces];
   1.392 +			iFaceCnt += meshOut->mNumFaces;
   1.393 +
   1.394 +			meshOut->mVertices = new aiVector3D[meshOut->mNumVertices];
   1.395 +			meshOut->mNormals  = new aiVector3D[meshOut->mNumVertices];
   1.396 +			if ((*i).mTexCoords.size())
   1.397 +			{
   1.398 +				meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices];
   1.399 +			}
   1.400 +			for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
   1.401 +			{
   1.402 +				register unsigned int index = aiSplit[p][q];
   1.403 +				aiFace& face = meshOut->mFaces[q];
   1.404 +
   1.405 +				face.mIndices = new unsigned int[3];
   1.406 +				face.mNumIndices = 3;
   1.407 +
   1.408 +				for (unsigned int a = 0; a < 3;++a,++base)
   1.409 +				{
   1.410 +					unsigned int idx = (*i).mFaces[index].mIndices[a];
   1.411 +					meshOut->mVertices[base]  = (*i).mPositions[idx];
   1.412 +					meshOut->mNormals [base]  = (*i).mNormals[idx];
   1.413 +
   1.414 +					if ((*i).mTexCoords.size())
   1.415 +						meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx];
   1.416 +
   1.417 +					face.mIndices[a] = base;
   1.418 +				}
   1.419 +			}
   1.420 +		}
   1.421 +	}
   1.422 +
   1.423 +	// Copy them to the output array
   1.424 +	pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
   1.425 +	pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
   1.426 +	for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) {
   1.427 +		pcOut->mMeshes[a] = avOutMeshes[a];
   1.428 +	}
   1.429 +
   1.430 +	// We should have at least one face here
   1.431 +	if (!iFaceCnt) {
   1.432 +		throw DeadlyImportError("No faces loaded. The mesh is empty");
   1.433 +	}
   1.434 +}
   1.435 +
   1.436 +// ------------------------------------------------------------------------------------------------
   1.437 +// Add a node to the scenegraph and setup its final transformation
   1.438 +void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
   1.439 +	D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/)
   1.440 +{
   1.441 +	std::vector<unsigned int> iArray;
   1.442 +	iArray.reserve(3);
   1.443 +
   1.444 +	aiMatrix4x4 abs;
   1.445 +
   1.446 +	// Find all meshes with the same name as the node
   1.447 +	for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a)
   1.448 +	{
   1.449 +		const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
   1.450 +		ai_assert(NULL != pcMesh);
   1.451 +
   1.452 +		if (pcIn->mName == pcMesh->mName)
   1.453 +			iArray.push_back(a);
   1.454 +	}
   1.455 +	if (!iArray.empty())
   1.456 +	{
   1.457 +		// The matrix should be identical for all meshes with the 
   1.458 +		// same name. It HAS to be identical for all meshes .....
   1.459 +		D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]);
   1.460 +
   1.461 +		// Compute the inverse of the transformation matrix to move the
   1.462 +		// vertices back to their relative and local space
   1.463 +		aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat;
   1.464 +		mInv.Inverse();mInvTransposed.Transpose();
   1.465 +		aiVector3D pivot = pcIn->vPivot;
   1.466 +
   1.467 +		pcOut->mNumMeshes = (unsigned int)iArray.size();
   1.468 +		pcOut->mMeshes = new unsigned int[iArray.size()];
   1.469 +		for (unsigned int i = 0;i < iArray.size();++i)	{
   1.470 +			const unsigned int iIndex = iArray[i];
   1.471 +			aiMesh* const mesh = pcSOut->mMeshes[iIndex];
   1.472 +
   1.473 +			// Transform the vertices back into their local space
   1.474 +			// fixme: consider computing normals after this, so we don't need to transform them
   1.475 +			const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
   1.476 +			aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
   1.477 +
   1.478 +			for (;pvCurrent != pvEnd;++pvCurrent,++t2) {
   1.479 +				*pvCurrent = mInv * (*pvCurrent);
   1.480 +				*t2 = mInvTransposed * (*t2);
   1.481 +			}
   1.482 +
   1.483 +			// Handle negative transformation matrix determinant -> invert vertex x
   1.484 +			if (imesh->mMat.Determinant() < 0.0f)
   1.485 +			{
   1.486 +				/* we *must* have normals */
   1.487 +				for (pvCurrent = mesh->mVertices,t2 = mesh->mNormals;pvCurrent != pvEnd;++pvCurrent,++t2) {
   1.488 +					pvCurrent->x *= -1.f;
   1.489 +					t2->x *= -1.f;
   1.490 +				}
   1.491 +				DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
   1.492 +			}
   1.493 +
   1.494 +			// Handle pivot point
   1.495 +			if(pivot.x || pivot.y || pivot.z)
   1.496 +			{
   1.497 +				for (pvCurrent = mesh->mVertices;pvCurrent != pvEnd;++pvCurrent)	{
   1.498 +					*pvCurrent -= pivot;	
   1.499 +				}
   1.500 +			}
   1.501 +
   1.502 +			// Setup the mesh index
   1.503 +			pcOut->mMeshes[i] = iIndex;
   1.504 +		}
   1.505 +	}
   1.506 +
   1.507 +	// Setup the name of the node
   1.508 +	pcOut->mName.Set(pcIn->mName);
   1.509 +
   1.510 +	// Now build the transformation matrix of the node
   1.511 +	// ROTATION
   1.512 +	if (pcIn->aRotationKeys.size()){
   1.513 +
   1.514 +		// FIX to get to Assimp's quaternion conventions
   1.515 +		for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) {
   1.516 +			(*it).mValue.w *= -1.f;
   1.517 +		}
   1.518 +
   1.519 +		pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() );
   1.520 +	}
   1.521 +	else if (pcIn->aCameraRollKeys.size()) 
   1.522 +	{
   1.523 +		aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue),
   1.524 +			pcOut->mTransformation);
   1.525 +	}
   1.526 +
   1.527 +	// SCALING
   1.528 +	aiMatrix4x4& m = pcOut->mTransformation;
   1.529 +	if (pcIn->aScalingKeys.size())
   1.530 +	{
   1.531 +		const aiVector3D& v = pcIn->aScalingKeys[0].mValue;
   1.532 +		m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x;
   1.533 +		m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y;
   1.534 +		m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z;
   1.535 +	}
   1.536 +
   1.537 +	// TRANSLATION
   1.538 +	if (pcIn->aPositionKeys.size())
   1.539 +	{
   1.540 +		const aiVector3D& v = pcIn->aPositionKeys[0].mValue;
   1.541 +		m.a4 += v.x;
   1.542 +		m.b4 += v.y;
   1.543 +		m.c4 += v.z;
   1.544 +	}
   1.545 +
   1.546 +	// Generate animation channels for the node
   1.547 +	if (pcIn->aPositionKeys.size()  > 1  || pcIn->aRotationKeys.size()   > 1 ||
   1.548 +		pcIn->aScalingKeys.size()   > 1  || pcIn->aCameraRollKeys.size() > 1 ||
   1.549 +		pcIn->aTargetPositionKeys.size() > 1)
   1.550 +	{
   1.551 +		aiAnimation* anim = pcSOut->mAnimations[0];
   1.552 +		ai_assert(NULL != anim);
   1.553 +
   1.554 +		if (pcIn->aCameraRollKeys.size() > 1)
   1.555 +		{
   1.556 +			DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
   1.557 +
   1.558 +			// Camera roll keys - in fact they're just rotations
   1.559 +			// around the camera's z axis. The angles are given
   1.560 +			// in degrees (and they're clockwise).
   1.561 +			pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size());
   1.562 +			for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i)
   1.563 +			{
   1.564 +				aiQuatKey&  q = pcIn->aRotationKeys[i];
   1.565 +				aiFloatKey& f = pcIn->aCameraRollKeys[i];
   1.566 +
   1.567 +				q.mTime  = f.mTime;
   1.568 +
   1.569 +				// FIX to get to Assimp quaternion conventions
   1.570 +				q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue));
   1.571 +			}
   1.572 +		}
   1.573 +#if 0
   1.574 +		if (pcIn->aTargetPositionKeys.size() > 1)
   1.575 +		{
   1.576 +			DefaultLogger::get()->debug("3DS: Converting target track ...");
   1.577 +
   1.578 +			// Camera or spot light - need to convert the separate
   1.579 +			// target position channel to our representation
   1.580 +			TargetAnimationHelper helper;
   1.581 +
   1.582 +			if (pcIn->aPositionKeys.empty())
   1.583 +			{
   1.584 +				// We can just pass zero here ...
   1.585 +				helper.SetFixedMainAnimationChannel(aiVector3D());
   1.586 +			}
   1.587 +			else  helper.SetMainAnimationChannel(&pcIn->aPositionKeys);
   1.588 +			helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys);
   1.589 +
   1.590 +			// Do the conversion
   1.591 +			std::vector<aiVectorKey> distanceTrack;
   1.592 +			helper.Process(&distanceTrack);
   1.593 +
   1.594 +			// Now add a new node as child, name it <ourName>.Target
   1.595 +			// and assign the distance track to it. This is that the
   1.596 +			// information where the target is and how it moves is
   1.597 +			// not lost
   1.598 +			D3DS::Node* nd = new D3DS::Node();
   1.599 +			pcIn->push_back(nd);
   1.600 +
   1.601 +			nd->mName = pcIn->mName + ".Target";
   1.602 +
   1.603 +			aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
   1.604 +			nda->mNodeName.Set(nd->mName);
   1.605 +
   1.606 +			nda->mNumPositionKeys = (unsigned int)distanceTrack.size();
   1.607 +			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
   1.608 +			::memcpy(nda->mPositionKeys,&distanceTrack[0],
   1.609 +				sizeof(aiVectorKey)*nda->mNumPositionKeys);
   1.610 +		}
   1.611 +#endif
   1.612 +
   1.613 +		// Cameras or lights define their transformation in their parent node and in the
   1.614 +		// corresponding light or camera chunks. However, we read and process the latter
   1.615 +		// to to be able to return valid cameras/lights even if no scenegraph is given.
   1.616 +		for (unsigned int n = 0; n < pcSOut->mNumCameras;++n)	{
   1.617 +			if (pcSOut->mCameras[n]->mName == pcOut->mName) {
   1.618 +				pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f);
   1.619 +			}
   1.620 +		}
   1.621 +		for (unsigned int n = 0; n < pcSOut->mNumLights;++n)	{
   1.622 +			if (pcSOut->mLights[n]->mName == pcOut->mName) {
   1.623 +				pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f);
   1.624 +			}
   1.625 +		}
   1.626 +
   1.627 +		// Allocate a new node anim and setup its name
   1.628 +		aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim();
   1.629 +		nda->mNodeName.Set(pcIn->mName);
   1.630 +
   1.631 +		// POSITION keys
   1.632 +		if (pcIn->aPositionKeys.size()  > 0)
   1.633 +		{
   1.634 +			nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size();
   1.635 +			nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys];
   1.636 +			::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0],
   1.637 +				sizeof(aiVectorKey)*nda->mNumPositionKeys);
   1.638 +		}
   1.639 +
   1.640 +		// ROTATION keys
   1.641 +		if (pcIn->aRotationKeys.size()  > 0)
   1.642 +		{
   1.643 +			nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size();
   1.644 +			nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys];
   1.645 +
   1.646 +			// Rotations are quaternion offsets
   1.647 +			aiQuaternion abs;
   1.648 +			for (unsigned int n = 0; n < nda->mNumRotationKeys;++n)
   1.649 +			{
   1.650 +				const aiQuatKey& q = pcIn->aRotationKeys[n];
   1.651 +
   1.652 +				abs = (n ? abs * q.mValue : q.mValue);
   1.653 +				nda->mRotationKeys[n].mTime  = q.mTime;
   1.654 +				nda->mRotationKeys[n].mValue = abs.Normalize();
   1.655 +			}
   1.656 +		}
   1.657 +
   1.658 +		// SCALING keys
   1.659 +		if (pcIn->aScalingKeys.size()  > 0)
   1.660 +		{
   1.661 +			nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size();
   1.662 +			nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys];
   1.663 +			::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0],
   1.664 +				sizeof(aiVectorKey)*nda->mNumScalingKeys);
   1.665 +		}
   1.666 +	}
   1.667 +
   1.668 +	// Allocate storage for children 
   1.669 +	pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
   1.670 +	pcOut->mChildren = new aiNode*[pcIn->mChildren.size()];
   1.671 +
   1.672 +	// Recursively process all children
   1.673 +	const unsigned int size = pcIn->mChildren.size();
   1.674 +	for (unsigned int i = 0; i < size;++i)
   1.675 +	{
   1.676 +		pcOut->mChildren[i] = new aiNode();
   1.677 +		pcOut->mChildren[i]->mParent = pcOut;
   1.678 +		AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs);
   1.679 +	}
   1.680 +}
   1.681 +
   1.682 +// ------------------------------------------------------------------------------------------------
   1.683 +// Find out how many node animation channels we'll have finally
   1.684 +void CountTracks(D3DS::Node* node, unsigned int& cnt)
   1.685 +{
   1.686 +	//////////////////////////////////////////////////////////////////////////////
   1.687 +	// We will never generate more than one channel for a node, so
   1.688 +	// this is rather easy here.
   1.689 +
   1.690 +	if (node->aPositionKeys.size()  > 1  || node->aRotationKeys.size()   > 1   ||
   1.691 +		node->aScalingKeys.size()   > 1  || node->aCameraRollKeys.size() > 1 ||
   1.692 +		node->aTargetPositionKeys.size()  > 1)
   1.693 +	{
   1.694 +		++cnt;
   1.695 +
   1.696 +		// account for the additional channel for the camera/spotlight target position
   1.697 +		if (node->aTargetPositionKeys.size()  > 1)++cnt;
   1.698 +	}
   1.699 +
   1.700 +	// Recursively process all children
   1.701 +	for (unsigned int i = 0; i < node->mChildren.size();++i)
   1.702 +		CountTracks(node->mChildren[i],cnt);
   1.703 +}
   1.704 +
   1.705 +// ------------------------------------------------------------------------------------------------
   1.706 +// Generate the output node graph
   1.707 +void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
   1.708 +{
   1.709 +	pcOut->mRootNode = new aiNode();
   1.710 +	if (0 == mRootNode->mChildren.size())
   1.711 +	{
   1.712 +		//////////////////////////////////////////////////////////////////////////////
   1.713 +		// It seems the file is so messed up that it has not even a hierarchy.
   1.714 +		// generate a flat hiearachy which looks like this:
   1.715 +		//
   1.716 +		//                ROOT_NODE
   1.717 +		//                   |
   1.718 +		//   ----------------------------------------
   1.719 +		//   |       |       |            |         |  
   1.720 +		// MESH_0  MESH_1  MESH_2  ...  MESH_N    CAMERA_0 ....
   1.721 +		//
   1.722 +		DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
   1.723 +
   1.724 +		pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + 
   1.725 +			mScene->mCameras.size() + mScene->mLights.size();
   1.726 +
   1.727 +		pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ];
   1.728 +		pcOut->mRootNode->mName.Set("<3DSDummyRoot>");
   1.729 +
   1.730 +		// Build dummy nodes for all meshes
   1.731 +		unsigned int a = 0;
   1.732 +		for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a)
   1.733 +		{
   1.734 +			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
   1.735 +			pcNode->mParent = pcOut->mRootNode;
   1.736 +			pcNode->mMeshes = new unsigned int[1];
   1.737 +			pcNode->mMeshes[0] = i;
   1.738 +			pcNode->mNumMeshes = 1;
   1.739 +
   1.740 +			// Build a name for the node
   1.741 +			pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i);	
   1.742 +		}
   1.743 +
   1.744 +		// Build dummy nodes for all cameras
   1.745 +		for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a)
   1.746 +		{
   1.747 +			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
   1.748 +			pcNode->mParent = pcOut->mRootNode;
   1.749 +
   1.750 +			// Build a name for the node
   1.751 +			pcNode->mName = mScene->mCameras[i]->mName;
   1.752 +		}
   1.753 +
   1.754 +		// Build dummy nodes for all lights
   1.755 +		for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a)
   1.756 +		{
   1.757 +			aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode();
   1.758 +			pcNode->mParent = pcOut->mRootNode;
   1.759 +
   1.760 +			// Build a name for the node
   1.761 +			pcNode->mName = mScene->mLights[i]->mName;
   1.762 +		}
   1.763 +	}
   1.764 +	else
   1.765 +	{
   1.766 +		// First of all: find out how many scaling, rotation and translation
   1.767 +		// animation tracks we'll have afterwards
   1.768 +		unsigned int numChannel = 0;
   1.769 +		CountTracks(mRootNode,numChannel);
   1.770 +
   1.771 +		if (numChannel)
   1.772 +		{
   1.773 +			// Allocate a primary animation channel
   1.774 +			pcOut->mNumAnimations = 1;
   1.775 +			pcOut->mAnimations    = new aiAnimation*[1];
   1.776 +			aiAnimation* anim     = pcOut->mAnimations[0] = new aiAnimation();
   1.777 +
   1.778 +			anim->mName.Set("3DSMasterAnim");
   1.779 +
   1.780 +			// Allocate enough storage for all node animation channels, 
   1.781 +			// but don't set the mNumChannels member - we'll use it to
   1.782 +			// index into the array
   1.783 +			anim->mChannels = new aiNodeAnim*[numChannel];
   1.784 +		}
   1.785 +
   1.786 +		aiMatrix4x4 m;
   1.787 +		AddNodeToGraph(pcOut,  pcOut->mRootNode, mRootNode,m);
   1.788 +	}
   1.789 +
   1.790 +	// We used the first vertex color set to store some emporary values so we need to cleanup here
   1.791 +	for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
   1.792 +		pcOut->mMeshes[a]->mColors[0] = NULL;
   1.793 +
   1.794 +	pcOut->mRootNode->mTransformation = aiMatrix4x4(
   1.795 +		1.f,0.f,0.f,0.f,
   1.796 +		0.f,0.f,1.f,0.f,
   1.797 +		0.f,-1.f,0.f,0.f,
   1.798 +		0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation;
   1.799 +
   1.800 +	// If the root node is unnamed name it "<3DSRoot>"
   1.801 +	if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) ||
   1.802 +		(pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') )
   1.803 +	{
   1.804 +		pcOut->mRootNode->mName.Set("<3DSRoot>");
   1.805 +	}
   1.806 +}
   1.807 +
   1.808 +// ------------------------------------------------------------------------------------------------
   1.809 +// Convert all meshes in the scene and generate the final output scene.
   1.810 +void Discreet3DSImporter::ConvertScene(aiScene* pcOut)
   1.811 +{
   1.812 +	// Allocate enough storage for all output materials
   1.813 +	pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size();
   1.814 +	pcOut->mMaterials    = new aiMaterial*[pcOut->mNumMaterials];
   1.815 +
   1.816 +	//  ... and convert the 3DS materials to aiMaterial's
   1.817 +	for (unsigned int i = 0; i < pcOut->mNumMaterials;++i)
   1.818 +	{
   1.819 +		aiMaterial* pcNew = new aiMaterial();
   1.820 +		ConvertMaterial(mScene->mMaterials[i],*pcNew);
   1.821 +		pcOut->mMaterials[i] = pcNew;
   1.822 +	}
   1.823 +
   1.824 +	// Generate the output mesh list
   1.825 +	ConvertMeshes(pcOut);
   1.826 +
   1.827 +	// Now copy all light sources to the output scene
   1.828 +	pcOut->mNumLights = (unsigned int)mScene->mLights.size();
   1.829 +	if (pcOut->mNumLights)
   1.830 +	{
   1.831 +		pcOut->mLights = new aiLight*[pcOut->mNumLights];
   1.832 +		::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights);
   1.833 +	}
   1.834 +
   1.835 +	// Now copy all cameras to the output scene
   1.836 +	pcOut->mNumCameras = (unsigned int)mScene->mCameras.size();
   1.837 +	if (pcOut->mNumCameras)
   1.838 +	{
   1.839 +		pcOut->mCameras = new aiCamera*[pcOut->mNumCameras];
   1.840 +		::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras);
   1.841 +	}
   1.842 +}
   1.843 +
   1.844 +#endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER