vrshoot

diff libs/assimp/ASELoader.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/ASELoader.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,1317 @@
     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  ASELoader.cpp
    1.46 + *  @brief Implementation of the ASE importer class
    1.47 + */
    1.48 +
    1.49 +#include "AssimpPCH.h"
    1.50 +#include "assimp/config.h"
    1.51 +#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
    1.52 +
    1.53 +// internal headers
    1.54 +#include "ASELoader.h"
    1.55 +#include "StringComparison.h"
    1.56 +#include "SkeletonMeshBuilder.h"
    1.57 +#include "TargetAnimation.h"
    1.58 +
    1.59 +// utilities
    1.60 +#include "fast_atof.h"
    1.61 +
    1.62 +using namespace Assimp;
    1.63 +using namespace Assimp::ASE;
    1.64 +
    1.65 +static const aiImporterDesc desc = {
    1.66 +	"ASE Importer",
    1.67 +	"",
    1.68 +	"",
    1.69 +	"Similar to 3DS but text-encoded",
    1.70 +	aiImporterFlags_SupportTextFlavour,
    1.71 +	0,
    1.72 +	0,
    1.73 +	0,
    1.74 +	0,
    1.75 +	"ase ask" 
    1.76 +};
    1.77 +
    1.78 +// ------------------------------------------------------------------------------------------------
    1.79 +// Constructor to be privately used by Importer
    1.80 +ASEImporter::ASEImporter()
    1.81 +: noSkeletonMesh()
    1.82 +{}
    1.83 +
    1.84 +// ------------------------------------------------------------------------------------------------
    1.85 +// Destructor, private as well 
    1.86 +ASEImporter::~ASEImporter()
    1.87 +{}
    1.88 +
    1.89 +// ------------------------------------------------------------------------------------------------
    1.90 +// Returns whether the class can handle the format of the given file. 
    1.91 +bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
    1.92 +{
    1.93 +	// check file extension 
    1.94 +	const std::string extension = GetExtension(pFile);
    1.95 +	
    1.96 +	if( extension == "ase" || extension == "ask")
    1.97 +		return true;
    1.98 +
    1.99 +	if ((!extension.length() || cs) && pIOHandler) {
   1.100 +		const char* tokens[] = {"*3dsmax_asciiexport"};
   1.101 +		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
   1.102 +	}
   1.103 +	return false;
   1.104 +}
   1.105 +
   1.106 +// ------------------------------------------------------------------------------------------------
   1.107 +// Loader meta information
   1.108 +const aiImporterDesc* ASEImporter::GetInfo () const
   1.109 +{
   1.110 +	return &desc;
   1.111 +}
   1.112 +
   1.113 +// ------------------------------------------------------------------------------------------------
   1.114 +// Setup configuration options
   1.115 +void ASEImporter::SetupProperties(const Importer* pImp)
   1.116 +{
   1.117 +	configRecomputeNormals = (pImp->GetPropertyInteger(
   1.118 +		AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false);
   1.119 +
   1.120 +	noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
   1.121 +}
   1.122 +
   1.123 +// ------------------------------------------------------------------------------------------------
   1.124 +// Imports the given file into the given scene structure. 
   1.125 +void ASEImporter::InternReadFile( const std::string& pFile, 
   1.126 +	aiScene* pScene, IOSystem* pIOHandler)
   1.127 +{
   1.128 +	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
   1.129 +
   1.130 +	// Check whether we can read from the file
   1.131 +	if( file.get() == NULL) {
   1.132 +		throw DeadlyImportError( "Failed to open ASE file " + pFile + ".");
   1.133 +	}
   1.134 +
   1.135 +	// Allocate storage and copy the contents of the file to a memory buffer
   1.136 +	std::vector<char> mBuffer2;
   1.137 +	TextFileToBuffer(file.get(),mBuffer2);
   1.138 +
   1.139 +	this->mBuffer = &mBuffer2[0];
   1.140 +	this->pcScene = pScene;
   1.141 +
   1.142 +	// ------------------------------------------------------------------
   1.143 +	// Guess the file format by looking at the extension
   1.144 +	// ASC is considered to be the older format 110,
   1.145 +	// ASE is the actual version 200 (that is currently written by max)
   1.146 +	// ------------------------------------------------------------------
   1.147 +	unsigned int defaultFormat;
   1.148 +	std::string::size_type s = pFile.length()-1;
   1.149 +	switch (pFile.c_str()[s])	{
   1.150 +
   1.151 +	case 'C':
   1.152 +	case 'c':
   1.153 +		defaultFormat = AI_ASE_OLD_FILE_FORMAT;
   1.154 +		break;
   1.155 +	default:
   1.156 +		defaultFormat = AI_ASE_NEW_FILE_FORMAT;
   1.157 +	};
   1.158 +
   1.159 +	// Construct an ASE parser and parse the file
   1.160 +	ASE::Parser parser(mBuffer,defaultFormat);
   1.161 +	mParser = &parser;
   1.162 +	mParser->Parse();
   1.163 +
   1.164 +	//------------------------------------------------------------------
   1.165 +	// Check whether we god at least one mesh. If we did - generate
   1.166 +	// materials and copy meshes. 
   1.167 +	// ------------------------------------------------------------------
   1.168 +	if ( !mParser->m_vMeshes.empty())	{
   1.169 +
   1.170 +		// If absolutely no material has been loaded from the file
   1.171 +		// we need to generate a default material
   1.172 +		GenerateDefaultMaterial();
   1.173 +
   1.174 +		// process all meshes
   1.175 +		bool tookNormals = false;
   1.176 +		std::vector<aiMesh*> avOutMeshes;
   1.177 +		avOutMeshes.reserve(mParser->m_vMeshes.size()*2);
   1.178 +		for (std::vector<ASE::Mesh>::iterator i =  mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i)	{
   1.179 +			if ((*i).bSkip) {
   1.180 +				continue;
   1.181 +			}
   1.182 +			BuildUniqueRepresentation(*i);
   1.183 +
   1.184 +			// Need to generate proper vertex normals if necessary
   1.185 +			if(GenerateNormals(*i)) {
   1.186 +				tookNormals = true;
   1.187 +			}
   1.188 +
   1.189 +			// Convert all meshes to aiMesh objects
   1.190 +			ConvertMeshes(*i,avOutMeshes);
   1.191 +		}
   1.192 +		if (tookNormals)	{
   1.193 +			DefaultLogger::get()->debug("ASE: Taking normals from the file. Use "
   1.194 +				"the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you "
   1.195 +				"experience problems");
   1.196 +		}
   1.197 +
   1.198 +		// Now build the output mesh list. Remove dummies
   1.199 +		pScene->mNumMeshes = (unsigned int)avOutMeshes.size();
   1.200 +		aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
   1.201 +		for (std::vector<aiMesh*>::const_iterator i =  avOutMeshes.begin();i != avOutMeshes.end();++i) {
   1.202 +			if (!(*i)->mNumFaces) {
   1.203 +				continue;
   1.204 +			}
   1.205 +			*pp++ = *i;
   1.206 +		}
   1.207 +		pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes);
   1.208 +
   1.209 +		// Build final material indices (remove submaterials and setup
   1.210 +		// the final list)
   1.211 +		BuildMaterialIndices();
   1.212 +	}
   1.213 +
   1.214 +	// ------------------------------------------------------------------
   1.215 +	// Copy all scene graph nodes - lights, cameras, dummies and meshes
   1.216 +	// into one huge list.
   1.217 +	//------------------------------------------------------------------
   1.218 +	std::vector<BaseNode*> nodes;
   1.219 +	nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
   1.220 +		+ mParser->m_vCameras.size() + mParser->m_vDummies.size());
   1.221 +
   1.222 +	// Lights
   1.223 +	for (std::vector<ASE::Light>::iterator it = mParser->m_vLights.begin(), 
   1.224 +		 end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it));
   1.225 +	// Cameras
   1.226 +	for (std::vector<ASE::Camera>::iterator it = mParser->m_vCameras.begin(), 
   1.227 +		 end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it));
   1.228 +	// Meshes
   1.229 +	for (std::vector<ASE::Mesh>::iterator it = mParser->m_vMeshes.begin(),
   1.230 +		end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it));
   1.231 +	// Dummies
   1.232 +	for (std::vector<ASE::Dummy>::iterator it = mParser->m_vDummies.begin(),
   1.233 +		end = mParser->m_vDummies.end();it != end; ++it)nodes.push_back(&(*it));
   1.234 +
   1.235 +	// build the final node graph
   1.236 +	BuildNodes(nodes);
   1.237 +
   1.238 +	// build output animations
   1.239 +	BuildAnimations(nodes);
   1.240 +
   1.241 +	// build output cameras
   1.242 +	BuildCameras();
   1.243 +
   1.244 +	// build output lights
   1.245 +	BuildLights();
   1.246 +
   1.247 +	// ------------------------------------------------------------------
   1.248 +	// If we have no meshes use the SkeletonMeshBuilder helper class
   1.249 +	// to build a mesh for the animation skeleton
   1.250 +	// FIXME: very strange results
   1.251 +	// ------------------------------------------------------------------
   1.252 +	if (!pScene->mNumMeshes)	{
   1.253 +		pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
   1.254 +		if (!noSkeletonMesh) {
   1.255 +			SkeletonMeshBuilder skeleton(pScene);
   1.256 +		}
   1.257 +	}
   1.258 +}
   1.259 +// ------------------------------------------------------------------------------------------------
   1.260 +void ASEImporter::GenerateDefaultMaterial()
   1.261 +{
   1.262 +	ai_assert(NULL != mParser);
   1.263 +
   1.264 +	bool bHas = false;
   1.265 +	for (std::vector<ASE::Mesh>::iterator i =  mParser->m_vMeshes.begin();i != mParser->m_vMeshes.end();++i) {
   1.266 +		if ((*i).bSkip)continue;
   1.267 +		if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex)	{
   1.268 +			(*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size();
   1.269 +			bHas = true;
   1.270 +		}
   1.271 +	}
   1.272 +	if (bHas || mParser->m_vMaterials.empty())	{
   1.273 +		// add a simple material without submaterials to the parser's list
   1.274 +		mParser->m_vMaterials.push_back ( ASE::Material() );
   1.275 +		ASE::Material& mat = mParser->m_vMaterials.back();
   1.276 +
   1.277 +		mat.mDiffuse  = aiColor3D(0.6f,0.6f,0.6f);
   1.278 +		mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f);
   1.279 +		mat.mAmbient  = aiColor3D(0.05f,0.05f,0.05f);
   1.280 +		mat.mShading  = Discreet3DS::Gouraud;
   1.281 +		mat.mName     = AI_DEFAULT_MATERIAL_NAME;
   1.282 +	}
   1.283 +}
   1.284 +
   1.285 +// ------------------------------------------------------------------------------------------------
   1.286 +void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
   1.287 +{
   1.288 +	// check whether we have at least one mesh which has animations
   1.289 +	std::vector<ASE::BaseNode*>::const_iterator i =  nodes.begin();
   1.290 +	unsigned int iNum = 0;
   1.291 +	for (;i != nodes.end();++i)	{
   1.292 +
   1.293 +		// TODO: Implement Bezier & TCB support
   1.294 +		if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK)	{
   1.295 +			DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
   1.296 +				"This is not supported.");
   1.297 +		}
   1.298 +		if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK)	{
   1.299 +			DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. "
   1.300 +				"This is not supported.");
   1.301 +		}
   1.302 +		if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK)	{
   1.303 +			DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
   1.304 +				"This is not supported.");
   1.305 +		}
   1.306 +
   1.307 +		// We compare against 1 here - firstly one key is not
   1.308 +		// really an animation and secondly MAX writes dummies
   1.309 +		// that represent the node transformation.
   1.310 +		if ((*i)->mAnim.akeyPositions.size()>1 || (*i)->mAnim.akeyRotations.size()>1 || (*i)->mAnim.akeyScaling.size()>1){
   1.311 +			++iNum;
   1.312 +		}
   1.313 +		if ((*i)->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( (*i)->mTargetPosition.x )) {
   1.314 +			++iNum;
   1.315 +		}
   1.316 +	}
   1.317 +	if (iNum)	{
   1.318 +		// Generate a new animation channel and setup everything for it
   1.319 +		pcScene->mNumAnimations = 1;
   1.320 +		pcScene->mAnimations    = new aiAnimation*[1];
   1.321 +		aiAnimation* pcAnim     = pcScene->mAnimations[0] = new aiAnimation();
   1.322 +		pcAnim->mNumChannels    = iNum;
   1.323 +		pcAnim->mChannels       = new aiNodeAnim*[iNum];
   1.324 +		pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame;
   1.325 +
   1.326 +		iNum = 0;
   1.327 +		
   1.328 +		// Now iterate through all meshes and collect all data we can find
   1.329 +		for (i =  nodes.begin();i != nodes.end();++i)	{
   1.330 +
   1.331 +			ASE::BaseNode* me = *i;
   1.332 +			if ( me->mTargetAnim.akeyPositions.size() > 1 && is_not_qnan( me->mTargetPosition.x ))	{
   1.333 +				// Generate an extra channel for the camera/light target.
   1.334 +				// BuildNodes() does also generate an extra node, named
   1.335 +				// <baseName>.Target.
   1.336 +				aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
   1.337 +				nd->mNodeName.Set(me->mName + ".Target");
   1.338 +
   1.339 +				// If there is no input position channel we will need
   1.340 +				// to supply the default position from the node's
   1.341 +				// local transformation matrix.
   1.342 +				/*TargetAnimationHelper helper;
   1.343 +				if (me->mAnim.akeyPositions.empty())
   1.344 +				{
   1.345 +					aiMatrix4x4& mat = (*i)->mTransform;
   1.346 +					helper.SetFixedMainAnimationChannel(aiVector3D(
   1.347 +						mat.a4, mat.b4, mat.c4));
   1.348 +				}
   1.349 +				else helper.SetMainAnimationChannel (&me->mAnim.akeyPositions);
   1.350 +				helper.SetTargetAnimationChannel (&me->mTargetAnim.akeyPositions);
   1.351 +				
   1.352 +				helper.Process(&me->mTargetAnim.akeyPositions);*/
   1.353 +
   1.354 +				// Allocate the key array and fill it
   1.355 +				nd->mNumPositionKeys = (unsigned int) me->mTargetAnim.akeyPositions.size();
   1.356 +				nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
   1.357 +
   1.358 +				::memcpy(nd->mPositionKeys,&me->mTargetAnim.akeyPositions[0],
   1.359 +					nd->mNumPositionKeys * sizeof(aiVectorKey));
   1.360 +			}
   1.361 +
   1.362 +			if (me->mAnim.akeyPositions.size() > 1 || me->mAnim.akeyRotations.size() > 1 || me->mAnim.akeyScaling.size() > 1)	{
   1.363 +				// Begin a new node animation channel for this node
   1.364 +				aiNodeAnim* nd = pcAnim->mChannels[iNum++] = new aiNodeAnim();
   1.365 +				nd->mNodeName.Set(me->mName);
   1.366 +
   1.367 +				// copy position keys
   1.368 +				if (me->mAnim.akeyPositions.size() > 1 )
   1.369 +				{
   1.370 +					// Allocate the key array and fill it
   1.371 +					nd->mNumPositionKeys = (unsigned int) me->mAnim.akeyPositions.size();
   1.372 +					nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
   1.373 +
   1.374 +					::memcpy(nd->mPositionKeys,&me->mAnim.akeyPositions[0],
   1.375 +						nd->mNumPositionKeys * sizeof(aiVectorKey));
   1.376 +				}
   1.377 +				// copy rotation keys
   1.378 +				if (me->mAnim.akeyRotations.size() > 1 )	{
   1.379 +					// Allocate the key array and fill it
   1.380 +					nd->mNumRotationKeys = (unsigned int) me->mAnim.akeyRotations.size();
   1.381 +					nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
   1.382 +
   1.383 +					// --------------------------------------------------------------------
   1.384 +					// Rotation keys are offsets to the previous keys.
   1.385 +					// We have the quaternion representations of all 
   1.386 +					// of them, so we just need to concatenate all
   1.387 +					// (unit-length) quaternions to get the absolute
   1.388 +					// rotations.
   1.389 +					// Rotation keys are ABSOLUTE for older files
   1.390 +					// --------------------------------------------------------------------
   1.391 +
   1.392 +					aiQuaternion cur;
   1.393 +					for (unsigned int a = 0; a < nd->mNumRotationKeys;++a)	{
   1.394 +						aiQuatKey q = me->mAnim.akeyRotations[a];
   1.395 +
   1.396 +						if (mParser->iFileFormat > 110)	{
   1.397 +							cur = (a ? cur*q.mValue : q.mValue);
   1.398 +							q.mValue = cur.Normalize();
   1.399 +						}
   1.400 +						nd->mRotationKeys[a] = q; 
   1.401 +
   1.402 +						// need this to get to Assimp quaternion conventions
   1.403 +						nd->mRotationKeys[a].mValue.w *= -1.f;
   1.404 +					}
   1.405 +				}
   1.406 +				// copy scaling keys
   1.407 +				if (me->mAnim.akeyScaling.size() > 1 )	{
   1.408 +					// Allocate the key array and fill it
   1.409 +					nd->mNumScalingKeys = (unsigned int) me->mAnim.akeyScaling.size();
   1.410 +					nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
   1.411 +
   1.412 +					::memcpy(nd->mScalingKeys,&me->mAnim.akeyScaling[0],
   1.413 +						nd->mNumScalingKeys * sizeof(aiVectorKey));
   1.414 +				}
   1.415 +			}
   1.416 +		}
   1.417 +	}
   1.418 +}
   1.419 +
   1.420 +// ------------------------------------------------------------------------------------------------
   1.421 +// Build output cameras
   1.422 +void ASEImporter::BuildCameras()
   1.423 +{
   1.424 +	if (!mParser->m_vCameras.empty())	{
   1.425 +		pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
   1.426 +		pcScene->mCameras = new aiCamera*[pcScene->mNumCameras];
   1.427 +
   1.428 +		for (unsigned int i = 0; i < pcScene->mNumCameras;++i)	{
   1.429 +			aiCamera* out = pcScene->mCameras[i] = new aiCamera();
   1.430 +			ASE::Camera& in = mParser->m_vCameras[i];
   1.431 +
   1.432 +			// copy members
   1.433 +			out->mClipPlaneFar  = in.mFar;
   1.434 +			out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f); 
   1.435 +			out->mHorizontalFOV = in.mFOV;
   1.436 +
   1.437 +			out->mName.Set(in.mName);
   1.438 +		}
   1.439 +	}
   1.440 +}
   1.441 +
   1.442 +// ------------------------------------------------------------------------------------------------
   1.443 +// Build output lights
   1.444 +void ASEImporter::BuildLights()
   1.445 +{
   1.446 +	if (!mParser->m_vLights.empty())	{
   1.447 +		pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
   1.448 +		pcScene->mLights    = new aiLight*[pcScene->mNumLights];
   1.449 +
   1.450 +		for (unsigned int i = 0; i < pcScene->mNumLights;++i)	{
   1.451 +			aiLight* out = pcScene->mLights[i] = new aiLight();
   1.452 +			ASE::Light& in = mParser->m_vLights[i];
   1.453 +
   1.454 +			// The direction is encoded in the transformation matrix of the node. 
   1.455 +			// In 3DS MAX the light source points into negative Z direction if 
   1.456 +			// the node transformation is the identity. 
   1.457 +			out->mDirection = aiVector3D(0.f,0.f,-1.f);
   1.458 +
   1.459 +			out->mName.Set(in.mName);
   1.460 +			switch (in.mLightType)
   1.461 +			{
   1.462 +			case ASE::Light::TARGET:
   1.463 +				out->mType = aiLightSource_SPOT;
   1.464 +				out->mAngleInnerCone = AI_DEG_TO_RAD(in.mAngle);
   1.465 +				out->mAngleOuterCone = (in.mFalloff ? AI_DEG_TO_RAD(in.mFalloff) : out->mAngleInnerCone);
   1.466 +				break;
   1.467 +
   1.468 +			case ASE::Light::DIRECTIONAL:
   1.469 +				out->mType = aiLightSource_DIRECTIONAL;
   1.470 +				break;
   1.471 +
   1.472 +			default:
   1.473 +			//case ASE::Light::OMNI:
   1.474 +				out->mType = aiLightSource_POINT;
   1.475 +				break;
   1.476 +			};
   1.477 +			out->mColorDiffuse = out->mColorSpecular = in.mColor * in.mIntensity;
   1.478 +		}
   1.479 +	}
   1.480 +}
   1.481 +
   1.482 +// ------------------------------------------------------------------------------------------------
   1.483 +void ASEImporter::AddNodes(const std::vector<BaseNode*>& nodes,
   1.484 +	aiNode* pcParent,const char* szName)
   1.485 +{
   1.486 +	aiMatrix4x4 m;
   1.487 +	AddNodes(nodes,pcParent,szName,m);
   1.488 +}
   1.489 +
   1.490 +// ------------------------------------------------------------------------------------------------
   1.491 +// Add meshes to a given node
   1.492 +void ASEImporter::AddMeshes(const ASE::BaseNode* snode,aiNode* node)
   1.493 +{
   1.494 +	for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)	{
   1.495 +		// Get the name of the mesh (the mesh instance has been temporarily stored in the third vertex color)
   1.496 +		const aiMesh* pcMesh  = pcScene->mMeshes[i];
   1.497 +		const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
   1.498 +
   1.499 +		if (mesh == snode) {
   1.500 +			++node->mNumMeshes;
   1.501 +		}
   1.502 +	}
   1.503 +
   1.504 +	if(node->mNumMeshes)	{
   1.505 +		node->mMeshes = new unsigned int[node->mNumMeshes];
   1.506 +		for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i)	{
   1.507 +
   1.508 +			const aiMesh* pcMesh  = pcScene->mMeshes[i];
   1.509 +			const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
   1.510 +			if (mesh == snode)	{
   1.511 +				node->mMeshes[p++] = i;
   1.512 +
   1.513 +				// Transform all vertices of the mesh back into their local space -> 
   1.514 +				// at the moment they are pretransformed
   1.515 +				aiMatrix4x4 m  = mesh->mTransform;
   1.516 +				m.Inverse();
   1.517 +
   1.518 +				aiVector3D* pvCurPtr = pcMesh->mVertices;
   1.519 +				const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
   1.520 +				while (pvCurPtr != pvEndPtr)	{
   1.521 +					*pvCurPtr = m * (*pvCurPtr);
   1.522 +					pvCurPtr++;
   1.523 +				}
   1.524 +
   1.525 +				// Do the same for the normal vectors, if we have them.
   1.526 +				// As always, inverse transpose.
   1.527 +				if (pcMesh->mNormals)	{
   1.528 +					aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform );
   1.529 +					m3.Transpose();
   1.530 +
   1.531 +					pvCurPtr = pcMesh->mNormals;
   1.532 +					pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
   1.533 +					while (pvCurPtr != pvEndPtr)	{
   1.534 +						*pvCurPtr = m3 * (*pvCurPtr);
   1.535 +						pvCurPtr++;
   1.536 +					}
   1.537 +				}
   1.538 +			}
   1.539 +		}
   1.540 +	}
   1.541 +}
   1.542 +
   1.543 +// ------------------------------------------------------------------------------------------------
   1.544 +// Add child nodes to a given parent node
   1.545 +void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
   1.546 +	aiNode* pcParent, const char* szName,
   1.547 +	const aiMatrix4x4& mat)
   1.548 +{
   1.549 +	const size_t len = szName ? ::strlen(szName) : 0;
   1.550 +	ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
   1.551 +
   1.552 +	// Receives child nodes for the pcParent node
   1.553 +	std::vector<aiNode*> apcNodes;
   1.554 +
   1.555 +	// Now iterate through all nodes in the scene and search for one
   1.556 +	// which has *us* as parent.
   1.557 +	for (std::vector<BaseNode*>::const_iterator it = nodes.begin(), end = nodes.end(); it != end; ++it) {
   1.558 +		const BaseNode* snode = *it;
   1.559 +		if (szName)	{
   1.560 +			if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str()))
   1.561 +				continue;
   1.562 +		}
   1.563 +		else if (snode->mParent.length())
   1.564 +			continue;
   1.565 +
   1.566 +		(*it)->mProcessed = true;
   1.567 +
   1.568 +		// Allocate a new node and add it to the output data structure
   1.569 +		apcNodes.push_back(new aiNode());
   1.570 +		aiNode* node = apcNodes.back();
   1.571 +
   1.572 +		node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node"));
   1.573 +		node->mParent = pcParent;
   1.574 +
   1.575 +		// Setup the transformation matrix of the node
   1.576 +		aiMatrix4x4 mParentAdjust  = mat;
   1.577 +		mParentAdjust.Inverse();
   1.578 +		node->mTransformation = mParentAdjust*snode->mTransform;
   1.579 +
   1.580 +		// Add sub nodes - prevent stack overflow due to recursive parenting
   1.581 +		if (node->mName != node->mParent->mName) {
   1.582 +			AddNodes(nodes,node,node->mName.data,snode->mTransform);
   1.583 +		}
   1.584 +
   1.585 +		// Further processing depends on the type of the node
   1.586 +		if (snode->mType == ASE::BaseNode::Mesh)	{
   1.587 +			// If the type of this node is "Mesh" we need to search
   1.588 +			// the list of output meshes in the data structure for
   1.589 +			// all those that belonged to this node once. This is
   1.590 +			// slightly inconvinient here and a better solution should
   1.591 +			// be used when this code is refactored next.
   1.592 +			AddMeshes(snode,node);
   1.593 +		}
   1.594 +		else if (is_not_qnan( snode->mTargetPosition.x ))	{
   1.595 +			// If this is a target camera or light we generate a small
   1.596 +			// child node which marks the position of the camera
   1.597 +			// target (the direction information is contained in *this*
   1.598 +			// node's animation track but the exact target position
   1.599 +			// would be lost otherwise)
   1.600 +			if (!node->mNumChildren)	{
   1.601 +				node->mChildren = new aiNode*[1];
   1.602 +			}
   1.603 +
   1.604 +			aiNode* nd = new aiNode();
   1.605 +
   1.606 +			nd->mName.Set ( snode->mName + ".Target" );
   1.607 +
   1.608 +			nd->mTransformation.a4 = snode->mTargetPosition.x - snode->mTransform.a4;
   1.609 +			nd->mTransformation.b4 = snode->mTargetPosition.y - snode->mTransform.b4;
   1.610 +			nd->mTransformation.c4 = snode->mTargetPosition.z - snode->mTransform.c4;
   1.611 +
   1.612 +			nd->mParent = node;
   1.613 +
   1.614 +			// The .Target node is always the first child node 
   1.615 +			for (unsigned int m = 0; m < node->mNumChildren;++m)
   1.616 +				node->mChildren[m+1] = node->mChildren[m]; 
   1.617 +		
   1.618 +			node->mChildren[0] = nd;
   1.619 +			node->mNumChildren++;
   1.620 +
   1.621 +			// What we did is so great, it is at least worth a debug message
   1.622 +			DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")");
   1.623 +		}
   1.624 +	}
   1.625 +
   1.626 +	// Allocate enough space for the child nodes
   1.627 +	// We allocate one slot more  in case this is a target camera/light
   1.628 +	pcParent->mNumChildren = (unsigned int)apcNodes.size();
   1.629 +	if (pcParent->mNumChildren)	{
   1.630 +		pcParent->mChildren = new aiNode*[apcNodes.size()+1 /* PLUS ONE !!! */];
   1.631 +
   1.632 +		// now build all nodes for our nice new children
   1.633 +		for (unsigned int p = 0; p < apcNodes.size();++p)
   1.634 +			pcParent->mChildren[p] = apcNodes[p];
   1.635 +	}
   1.636 +	return;
   1.637 +}
   1.638 +
   1.639 +// ------------------------------------------------------------------------------------------------
   1.640 +// Build the output node graph
   1.641 +void ASEImporter::BuildNodes(std::vector<BaseNode*>& nodes)	{
   1.642 +	ai_assert(NULL != pcScene);
   1.643 +
   1.644 +	// allocate the one and only root node
   1.645 +	aiNode* root = pcScene->mRootNode = new aiNode();
   1.646 +	root->mName.Set("<ASERoot>");
   1.647 +
   1.648 +	// Setup the coordinate system transformation
   1.649 +	pcScene->mRootNode->mNumChildren = 1;
   1.650 +	pcScene->mRootNode->mChildren = new aiNode*[1];
   1.651 +	aiNode* ch = pcScene->mRootNode->mChildren[0] = new aiNode();
   1.652 +	ch->mParent = root;
   1.653 +
   1.654 +	// Change the transformation matrix of all nodes
   1.655 +	for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it)	{
   1.656 +		aiMatrix4x4& m = (*it)->mTransform;
   1.657 +		m.Transpose(); // row-order vs column-order
   1.658 +	}
   1.659 +
   1.660 +	// add all nodes
   1.661 +	AddNodes(nodes,ch,NULL);
   1.662 +
   1.663 +	// now iterate through al nodes and find those that have not yet
   1.664 +	// been added to the nodegraph (= their parent could not be recognized)
   1.665 +	std::vector<const BaseNode*> aiList;
   1.666 +	for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();it != end; ++it)	{
   1.667 +		if ((*it)->mProcessed) {
   1.668 +			continue;
   1.669 +		}
   1.670 +
   1.671 +		// check whether our parent is known
   1.672 +		bool bKnowParent = false;
   1.673 +		
   1.674 +		// search the list another time, starting *here* and try to find out whether
   1.675 +		// there is a node that references *us* as a parent
   1.676 +		for (std::vector<BaseNode*>::const_iterator it2 = nodes.begin();it2 != end; ++it2) {
   1.677 +			if (it2 == it) {
   1.678 +				continue;
   1.679 +			}
   1.680 +
   1.681 +			if ((*it2)->mName == (*it)->mParent)	{
   1.682 +				bKnowParent = true;
   1.683 +				break;
   1.684 +			}
   1.685 +		}
   1.686 +		if (!bKnowParent)	{
   1.687 +			aiList.push_back(*it);
   1.688 +		}
   1.689 +	}
   1.690 +
   1.691 +	// Are there ane orphaned nodes?
   1.692 +	if (!aiList.empty())	{
   1.693 +		std::vector<aiNode*> apcNodes;
   1.694 +		apcNodes.reserve(aiList.size() + pcScene->mRootNode->mNumChildren);
   1.695 +
   1.696 +		for (unsigned int i = 0; i < pcScene->mRootNode->mNumChildren;++i)
   1.697 +			apcNodes.push_back(pcScene->mRootNode->mChildren[i]);
   1.698 +
   1.699 +		delete[] pcScene->mRootNode->mChildren;
   1.700 +		for (std::vector<const BaseNode*>::/*const_*/iterator i =  aiList.begin();i != aiList.end();++i)	{
   1.701 +			const ASE::BaseNode* src = *i;
   1.702 +
   1.703 +			// The parent is not known, so we can assume that we must add 
   1.704 +			// this node to the root node of the whole scene
   1.705 +			aiNode* pcNode = new aiNode();
   1.706 +			pcNode->mParent = pcScene->mRootNode;
   1.707 +			pcNode->mName.Set(src->mName);
   1.708 +			AddMeshes(src,pcNode);
   1.709 +			AddNodes(nodes,pcNode,pcNode->mName.data);
   1.710 +			apcNodes.push_back(pcNode);
   1.711 +		}
   1.712 +
   1.713 +		// Regenerate our output array
   1.714 +		pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()];
   1.715 +		for (unsigned int i = 0; i < apcNodes.size();++i)
   1.716 +			pcScene->mRootNode->mChildren[i] = apcNodes[i];
   1.717 +
   1.718 +		pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
   1.719 +	}
   1.720 +
   1.721 +	// Reset the third color set to NULL - we used this field to store a temporary pointer
   1.722 +	for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
   1.723 +		pcScene->mMeshes[i]->mColors[2] = NULL;
   1.724 +
   1.725 +	// The root node should not have at least one child or the file is valid
   1.726 +	if (!pcScene->mRootNode->mNumChildren) {
   1.727 +		throw DeadlyImportError("ASE: No nodes loaded. The file is either empty or corrupt");
   1.728 +	}
   1.729 +	
   1.730 +	// Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
   1.731 +	pcScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
   1.732 +		0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
   1.733 +}
   1.734 +
   1.735 +// ------------------------------------------------------------------------------------------------
   1.736 +// Convert the imported data to the internal verbose representation
   1.737 +void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)	{
   1.738 +	// allocate output storage
   1.739 +	std::vector<aiVector3D> mPositions;
   1.740 +	std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
   1.741 +	std::vector<aiColor4D>  mVertexColors;
   1.742 +	std::vector<aiVector3D> mNormals;
   1.743 +	std::vector<BoneVertex> mBoneVertices;
   1.744 +
   1.745 +	unsigned int iSize = (unsigned int)mesh.mFaces.size() * 3;
   1.746 +	mPositions.resize(iSize);
   1.747 +
   1.748 +	// optional texture coordinates
   1.749 +	for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)	{
   1.750 +		if (!mesh.amTexCoords[i].empty())	{
   1.751 +			amTexCoords[i].resize(iSize);
   1.752 +		}
   1.753 +	}
   1.754 +	// optional vertex colors
   1.755 +	if (!mesh.mVertexColors.empty())	{
   1.756 +		mVertexColors.resize(iSize);
   1.757 +	}
   1.758 +
   1.759 +	// optional vertex normals (vertex normals can simply be copied)
   1.760 +	if (!mesh.mNormals.empty())	{
   1.761 +		mNormals.resize(iSize);
   1.762 +	}
   1.763 +	// bone vertices. There is no need to change the bone list
   1.764 +	if (!mesh.mBoneVertices.empty())	{
   1.765 +		mBoneVertices.resize(iSize);
   1.766 +	}
   1.767 +
   1.768 +	// iterate through all faces in the mesh
   1.769 +	unsigned int iCurrent = 0, fi = 0;
   1.770 +	for (std::vector<ASE::Face>::iterator i =  mesh.mFaces.begin();i != mesh.mFaces.end();++i,++fi)	{
   1.771 +		for (unsigned int n = 0; n < 3;++n,++iCurrent)
   1.772 +		{
   1.773 +			mPositions[iCurrent] = mesh.mPositions[(*i).mIndices[n]];
   1.774 +
   1.775 +			// add texture coordinates
   1.776 +			for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)	{
   1.777 +				if (mesh.amTexCoords[c].empty())break;
   1.778 +				amTexCoords[c][iCurrent] = mesh.amTexCoords[c][(*i).amUVIndices[c][n]];
   1.779 +			}
   1.780 +			// add vertex colors
   1.781 +			if (!mesh.mVertexColors.empty())	{
   1.782 +				mVertexColors[iCurrent] = mesh.mVertexColors[(*i).mColorIndices[n]];
   1.783 +			}
   1.784 +			// add normal vectors
   1.785 +			if (!mesh.mNormals.empty())	{
   1.786 +				mNormals[iCurrent] = mesh.mNormals[fi*3+n];
   1.787 +				mNormals[iCurrent].Normalize();
   1.788 +			}
   1.789 +
   1.790 +			// handle bone vertices
   1.791 +			if ((*i).mIndices[n] < mesh.mBoneVertices.size())	{
   1.792 +				// (sometimes this will cause bone verts to be duplicated
   1.793 +				//  however, I' quite sure Schrompf' JoinVerticesStep
   1.794 +				//  will fix that again ...)
   1.795 +				mBoneVertices[iCurrent] =  mesh.mBoneVertices[(*i).mIndices[n]];
   1.796 +			}
   1.797 +			(*i).mIndices[n] = iCurrent;
   1.798 +		}
   1.799 +	}
   1.800 +
   1.801 +	// replace the old arrays
   1.802 +	mesh.mNormals = mNormals;
   1.803 +	mesh.mPositions = mPositions;
   1.804 +	mesh.mVertexColors = mVertexColors;
   1.805 +
   1.806 +	for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
   1.807 +		mesh.amTexCoords[c] = amTexCoords[c];
   1.808 +}
   1.809 +
   1.810 +// ------------------------------------------------------------------------------------------------
   1.811 +// Copy a texture from the ASE structs to the output material
   1.812 +void CopyASETexture(aiMaterial& mat, ASE::Texture& texture, aiTextureType type)
   1.813 +{
   1.814 +	// Setup the texture name
   1.815 +	aiString tex;
   1.816 +	tex.Set( texture.mMapName);
   1.817 +	mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0));
   1.818 +
   1.819 +	// Setup the texture blend factor
   1.820 +	if (is_not_qnan(texture.mTextureBlend))
   1.821 +		mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
   1.822 +
   1.823 +	// Setup texture UV transformations
   1.824 +	mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0));
   1.825 +}
   1.826 +
   1.827 +// ------------------------------------------------------------------------------------------------
   1.828 +// Convert from ASE material to output material
   1.829 +void ASEImporter::ConvertMaterial(ASE::Material& mat)
   1.830 +{
   1.831 +	// LARGE TODO: Much code her is copied from 3DS ... join them maybe?
   1.832 +
   1.833 +	// Allocate the output material
   1.834 +	mat.pcInstance = new aiMaterial();
   1.835 +
   1.836 +	// At first add the base ambient color of the
   1.837 +	// scene to	the material
   1.838 +	mat.mAmbient.r += mParser->m_clrAmbient.r;
   1.839 +	mat.mAmbient.g += mParser->m_clrAmbient.g;
   1.840 +	mat.mAmbient.b += mParser->m_clrAmbient.b;
   1.841 +
   1.842 +	aiString name;
   1.843 +	name.Set( mat.mName);
   1.844 +	mat.pcInstance->AddProperty( &name, AI_MATKEY_NAME);
   1.845 +
   1.846 +	// material colors
   1.847 +	mat.pcInstance->AddProperty( &mat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
   1.848 +	mat.pcInstance->AddProperty( &mat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
   1.849 +	mat.pcInstance->AddProperty( &mat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
   1.850 +	mat.pcInstance->AddProperty( &mat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE);
   1.851 +
   1.852 +	// shininess
   1.853 +	if (0.0f != mat.mSpecularExponent && 0.0f != mat.mShininessStrength)
   1.854 +	{
   1.855 +		mat.pcInstance->AddProperty( &mat.mSpecularExponent, 1, AI_MATKEY_SHININESS);
   1.856 +		mat.pcInstance->AddProperty( &mat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH);
   1.857 +	}
   1.858 +	// If there is no shininess, we can disable phong lighting
   1.859 +	else if (D3DS::Discreet3DS::Metal == mat.mShading ||
   1.860 +		D3DS::Discreet3DS::Phong == mat.mShading ||
   1.861 +		D3DS::Discreet3DS::Blinn == mat.mShading)
   1.862 +	{
   1.863 +		mat.mShading = D3DS::Discreet3DS::Gouraud;
   1.864 +	}
   1.865 +
   1.866 +	// opacity
   1.867 +	mat.pcInstance->AddProperty<float>( &mat.mTransparency,1,AI_MATKEY_OPACITY);
   1.868 +
   1.869 +	// Two sided rendering?
   1.870 +	if (mat.mTwoSided)
   1.871 +	{
   1.872 +		int i = 1;
   1.873 +		mat.pcInstance->AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
   1.874 +	}
   1.875 +
   1.876 +	// shading mode
   1.877 +	aiShadingMode eShading = aiShadingMode_NoShading;
   1.878 +	switch (mat.mShading)
   1.879 +	{
   1.880 +		case D3DS::Discreet3DS::Flat:
   1.881 +			eShading = aiShadingMode_Flat; break;
   1.882 +		case D3DS::Discreet3DS::Phong :
   1.883 +			eShading = aiShadingMode_Phong; break;
   1.884 +		case D3DS::Discreet3DS::Blinn :
   1.885 +			eShading = aiShadingMode_Blinn; break;
   1.886 +
   1.887 +			// I don't know what "Wire" shading should be,
   1.888 +			// assume it is simple lambertian diffuse (L dot N) shading
   1.889 +		case D3DS::Discreet3DS::Wire:
   1.890 +			{
   1.891 +				// set the wireframe flag
   1.892 +				unsigned int iWire = 1;
   1.893 +				mat.pcInstance->AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME);
   1.894 +			}
   1.895 +		case D3DS::Discreet3DS::Gouraud:
   1.896 +			eShading = aiShadingMode_Gouraud; break;
   1.897 +		case D3DS::Discreet3DS::Metal :
   1.898 +			eShading = aiShadingMode_CookTorrance; break;
   1.899 +	}
   1.900 +	mat.pcInstance->AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
   1.901 +
   1.902 +	// DIFFUSE texture
   1.903 +	if( mat.sTexDiffuse.mMapName.length() > 0)
   1.904 +		CopyASETexture(*mat.pcInstance,mat.sTexDiffuse, aiTextureType_DIFFUSE);
   1.905 +
   1.906 +	// SPECULAR texture
   1.907 +	if( mat.sTexSpecular.mMapName.length() > 0)
   1.908 +		CopyASETexture(*mat.pcInstance,mat.sTexSpecular, aiTextureType_SPECULAR);
   1.909 +
   1.910 +	// AMBIENT texture
   1.911 +	if( mat.sTexAmbient.mMapName.length() > 0)
   1.912 +		CopyASETexture(*mat.pcInstance,mat.sTexAmbient, aiTextureType_AMBIENT);
   1.913 +
   1.914 +	// OPACITY texture
   1.915 +	if( mat.sTexOpacity.mMapName.length() > 0)
   1.916 +		CopyASETexture(*mat.pcInstance,mat.sTexOpacity, aiTextureType_OPACITY);
   1.917 +
   1.918 +	// EMISSIVE texture
   1.919 +	if( mat.sTexEmissive.mMapName.length() > 0)
   1.920 +		CopyASETexture(*mat.pcInstance,mat.sTexEmissive, aiTextureType_EMISSIVE);
   1.921 +
   1.922 +	// BUMP texture
   1.923 +	if( mat.sTexBump.mMapName.length() > 0)
   1.924 +		CopyASETexture(*mat.pcInstance,mat.sTexBump, aiTextureType_HEIGHT);
   1.925 +
   1.926 +	// SHININESS texture
   1.927 +	if( mat.sTexShininess.mMapName.length() > 0)
   1.928 +		CopyASETexture(*mat.pcInstance,mat.sTexShininess, aiTextureType_SHININESS);
   1.929 +
   1.930 +	// store the name of the material itself, too
   1.931 +	if( mat.mName.length() > 0)	{
   1.932 +		aiString tex;tex.Set( mat.mName);
   1.933 +		mat.pcInstance->AddProperty( &tex, AI_MATKEY_NAME);
   1.934 +	}
   1.935 +	return;
   1.936 +}
   1.937 +
   1.938 +// ------------------------------------------------------------------------------------------------
   1.939 +// Build output meshes
   1.940 +void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes)
   1.941 +{
   1.942 +	// validate the material index of the mesh
   1.943 +	if (mesh.iMaterialIndex >= mParser->m_vMaterials.size())	{
   1.944 +		mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1;
   1.945 +		DefaultLogger::get()->warn("Material index is out of range");
   1.946 +	}
   1.947 +
   1.948 +	// If the material the mesh is assigned to is consisting of submeshes, split it
   1.949 +	if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty())	{
   1.950 +		std::vector<ASE::Material> vSubMaterials = mParser->
   1.951 +			m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
   1.952 +
   1.953 +		std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
   1.954 +
   1.955 +		// build a list of all faces per submaterial
   1.956 +		for (unsigned int i = 0; i < mesh.mFaces.size();++i)	{
   1.957 +			// check range
   1.958 +			if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) {
   1.959 +				DefaultLogger::get()->warn("Submaterial index is out of range");
   1.960 +
   1.961 +				// use the last material instead
   1.962 +				aiSplit[vSubMaterials.size()-1].push_back(i);
   1.963 +			}
   1.964 +			else aiSplit[mesh.mFaces[i].iMaterial].push_back(i);
   1.965 +		}
   1.966 +
   1.967 +		// now generate submeshes
   1.968 +		for (unsigned int p = 0; p < vSubMaterials.size();++p)	{
   1.969 +			if (!aiSplit[p].empty())	{
   1.970 +
   1.971 +				aiMesh* p_pcOut = new aiMesh();
   1.972 +				p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
   1.973 +
   1.974 +				// let the sub material index
   1.975 +				p_pcOut->mMaterialIndex = p;
   1.976 +
   1.977 +				// we will need this material
   1.978 +				mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true;
   1.979 +
   1.980 +				// store the real index here ... color channel 3
   1.981 +				p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
   1.982 +
   1.983 +				// store a pointer to the mesh in color channel 2
   1.984 +				p_pcOut->mColors[2] = (aiColor4D*) &mesh;
   1.985 +				avOutMeshes.push_back(p_pcOut);
   1.986 +
   1.987 +				// convert vertices
   1.988 +				p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3;
   1.989 +				p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
   1.990 +
   1.991 +				// receive output vertex weights
   1.992 +				std::vector<std::pair<unsigned int, float> > *avOutputBones = NULL;
   1.993 +				if (!mesh.mBones.empty())	{
   1.994 +					avOutputBones = new std::vector<std::pair<unsigned int, float> >[mesh.mBones.size()];
   1.995 +				}
   1.996 +				
   1.997 +				// allocate enough storage for faces
   1.998 +				p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
   1.999 +
  1.1000 +				unsigned int iBase = 0,iIndex;
  1.1001 +				if (p_pcOut->mNumVertices)	{
  1.1002 +					p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices];
  1.1003 +					p_pcOut->mNormals  = new aiVector3D[p_pcOut->mNumVertices];
  1.1004 +					for (unsigned int q = 0; q < aiSplit[p].size();++q)	{
  1.1005 +
  1.1006 +						iIndex = aiSplit[p][q];
  1.1007 +
  1.1008 +						p_pcOut->mFaces[q].mIndices = new unsigned int[3];
  1.1009 +						p_pcOut->mFaces[q].mNumIndices = 3;
  1.1010 +
  1.1011 +						for (unsigned int t = 0; t < 3;++t, ++iBase)	{
  1.1012 +							const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t];
  1.1013 +
  1.1014 +							p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2];
  1.1015 +							p_pcOut->mNormals [iBase] = mesh.mNormals   [iIndex2];
  1.1016 +
  1.1017 +							// convert bones, if existing
  1.1018 +							if (!mesh.mBones.empty()) {
  1.1019 +								// check whether there is a vertex weight for this vertex index
  1.1020 +								if (iIndex2 < mesh.mBoneVertices.size())	{
  1.1021 +
  1.1022 +									for (std::vector<std::pair<int,float> >::const_iterator
  1.1023 +										blubb =  mesh.mBoneVertices[iIndex2].mBoneWeights.begin();
  1.1024 +										blubb != mesh.mBoneVertices[iIndex2].mBoneWeights.end();++blubb)	{
  1.1025 +
  1.1026 +										// NOTE: illegal cases have already been filtered out
  1.1027 +										avOutputBones[(*blubb).first].push_back(std::pair<unsigned int, float>(
  1.1028 +											iBase,(*blubb).second));
  1.1029 +									}
  1.1030 +								}
  1.1031 +							}
  1.1032 +							p_pcOut->mFaces[q].mIndices[t] = iBase;
  1.1033 +						}
  1.1034 +					}
  1.1035 +				}
  1.1036 +				// convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
  1.1037 +				for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
  1.1038 +					if (!mesh.amTexCoords[c].empty())
  1.1039 +					{
  1.1040 +						p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
  1.1041 +						iBase = 0;
  1.1042 +						for (unsigned int q = 0; q < aiSplit[p].size();++q)	{
  1.1043 +							iIndex = aiSplit[p][q];
  1.1044 +							for (unsigned int t = 0; t < 3;++t)	{
  1.1045 +								p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]];
  1.1046 +							}
  1.1047 +						}
  1.1048 +						// Setup the number of valid vertex components
  1.1049 +						p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
  1.1050 +					}
  1.1051 +				}
  1.1052 +
  1.1053 +				// Convert vertex colors (only one set supported)
  1.1054 +				if (!mesh.mVertexColors.empty()){
  1.1055 +					p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices];
  1.1056 +					iBase = 0;
  1.1057 +					for (unsigned int q = 0; q < aiSplit[p].size();++q)	{
  1.1058 +						iIndex = aiSplit[p][q];
  1.1059 +						for (unsigned int t = 0; t < 3;++t)	{
  1.1060 +							p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]];
  1.1061 +						}
  1.1062 +					}
  1.1063 +				}
  1.1064 +				// Copy bones
  1.1065 +				if (!mesh.mBones.empty())	{
  1.1066 +					p_pcOut->mNumBones = 0;
  1.1067 +					for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
  1.1068 +						if (!avOutputBones[mrspock].empty())p_pcOut->mNumBones++;
  1.1069 +
  1.1070 +					p_pcOut->mBones = new aiBone* [ p_pcOut->mNumBones ];
  1.1071 +					aiBone** pcBone = p_pcOut->mBones;
  1.1072 +					for (unsigned int mrspock = 0; mrspock < mesh.mBones.size();++mrspock)
  1.1073 +					{
  1.1074 +						if (!avOutputBones[mrspock].empty())	{
  1.1075 +							// we will need this bone. add it to the output mesh and
  1.1076 +							// add all per-vertex weights
  1.1077 +							aiBone* pc = *pcBone = new aiBone();
  1.1078 +							pc->mName.Set(mesh.mBones[mrspock].mName);
  1.1079 +
  1.1080 +							pc->mNumWeights = (unsigned int)avOutputBones[mrspock].size();
  1.1081 +							pc->mWeights = new aiVertexWeight[pc->mNumWeights];
  1.1082 +
  1.1083 +							for (unsigned int captainkirk = 0; captainkirk < pc->mNumWeights;++captainkirk)
  1.1084 +							{
  1.1085 +								const std::pair<unsigned int,float>& ref = avOutputBones[mrspock][captainkirk];
  1.1086 +								pc->mWeights[captainkirk].mVertexId = ref.first;
  1.1087 +								pc->mWeights[captainkirk].mWeight = ref.second;
  1.1088 +							}
  1.1089 +							++pcBone;
  1.1090 +						}
  1.1091 +					}
  1.1092 +					// delete allocated storage
  1.1093 +					delete[] avOutputBones;
  1.1094 +				}
  1.1095 +			}
  1.1096 +		}
  1.1097 +		// delete storage
  1.1098 +		delete[] aiSplit;
  1.1099 +	}
  1.1100 +	else
  1.1101 +	{
  1.1102 +		// Otherwise we can simply copy the data to one output mesh
  1.1103 +		// This codepath needs less memory and uses fast memcpy()s
  1.1104 +		// to do the actual copying. So I think it is worth the 
  1.1105 +		// effort here.
  1.1106 +
  1.1107 +		aiMesh* p_pcOut = new aiMesh();
  1.1108 +		p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
  1.1109 +
  1.1110 +		// set an empty sub material index
  1.1111 +		p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX;
  1.1112 +		mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true;
  1.1113 +
  1.1114 +		// store the real index here ... in color channel 3
  1.1115 +		p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
  1.1116 +
  1.1117 +		// store a pointer to the mesh in color channel 2
  1.1118 +		p_pcOut->mColors[2] = (aiColor4D*) &mesh;
  1.1119 +		avOutMeshes.push_back(p_pcOut);
  1.1120 +
  1.1121 +		// If the mesh hasn't faces or vertices, there are two cases
  1.1122 +		// possible: 1. the model is invalid. 2. This is a dummy
  1.1123 +		// helper object which we are going to remove later ...
  1.1124 +		if (mesh.mFaces.empty() || mesh.mPositions.empty())	{
  1.1125 +			return;
  1.1126 +		}
  1.1127 +
  1.1128 +		// convert vertices
  1.1129 +		p_pcOut->mNumVertices = (unsigned int)mesh.mPositions.size();
  1.1130 +		p_pcOut->mNumFaces = (unsigned int)mesh.mFaces.size();
  1.1131 +
  1.1132 +		// allocate enough storage for faces
  1.1133 +		p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
  1.1134 +
  1.1135 +		// copy vertices
  1.1136 +		p_pcOut->mVertices = new aiVector3D[mesh.mPositions.size()];
  1.1137 +		memcpy(p_pcOut->mVertices,&mesh.mPositions[0],
  1.1138 +			mesh.mPositions.size() * sizeof(aiVector3D));
  1.1139 +
  1.1140 +		// copy normals
  1.1141 +		p_pcOut->mNormals = new aiVector3D[mesh.mNormals.size()];
  1.1142 +		memcpy(p_pcOut->mNormals,&mesh.mNormals[0],
  1.1143 +			mesh.mNormals.size() * sizeof(aiVector3D));
  1.1144 +
  1.1145 +		// copy texture coordinates
  1.1146 +		for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)	{
  1.1147 +			if (!mesh.amTexCoords[c].empty())	{
  1.1148 +				p_pcOut->mTextureCoords[c] = new aiVector3D[mesh.amTexCoords[c].size()];
  1.1149 +				memcpy(p_pcOut->mTextureCoords[c],&mesh.amTexCoords[c][0],
  1.1150 +					mesh.amTexCoords[c].size() * sizeof(aiVector3D));
  1.1151 +
  1.1152 +				// setup the number of valid vertex components
  1.1153 +				p_pcOut->mNumUVComponents[c] = mesh.mNumUVComponents[c];
  1.1154 +			}
  1.1155 +		}
  1.1156 +
  1.1157 +		// copy vertex colors
  1.1158 +		if (!mesh.mVertexColors.empty())	{
  1.1159 +			p_pcOut->mColors[0] = new aiColor4D[mesh.mVertexColors.size()];
  1.1160 +			memcpy(p_pcOut->mColors[0],&mesh.mVertexColors[0],
  1.1161 +				mesh.mVertexColors.size() * sizeof(aiColor4D));
  1.1162 +		}
  1.1163 +
  1.1164 +		// copy faces
  1.1165 +		for (unsigned int iFace = 0; iFace < p_pcOut->mNumFaces;++iFace)	{
  1.1166 +			p_pcOut->mFaces[iFace].mNumIndices = 3;
  1.1167 +			p_pcOut->mFaces[iFace].mIndices = new unsigned int[3];
  1.1168 +
  1.1169 +			// copy indices 
  1.1170 +			p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0];
  1.1171 +			p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1];
  1.1172 +			p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2];
  1.1173 +		}
  1.1174 +
  1.1175 +		// copy vertex bones
  1.1176 +		if (!mesh.mBones.empty() && !mesh.mBoneVertices.empty())	{
  1.1177 +			std::vector<std::vector<aiVertexWeight> > avBonesOut( mesh.mBones.size() );
  1.1178 +
  1.1179 +			// find all vertex weights for this bone
  1.1180 +			unsigned int quak = 0;
  1.1181 +			for (std::vector<BoneVertex>::const_iterator harrypotter =  mesh.mBoneVertices.begin();
  1.1182 +				harrypotter != mesh.mBoneVertices.end();++harrypotter,++quak)	{
  1.1183 +
  1.1184 +				for (std::vector<std::pair<int,float> >::const_iterator
  1.1185 +					ronaldweasley  = (*harrypotter).mBoneWeights.begin();
  1.1186 +					ronaldweasley != (*harrypotter).mBoneWeights.end();++ronaldweasley)
  1.1187 +				{
  1.1188 +					aiVertexWeight weight;
  1.1189 +					weight.mVertexId = quak;
  1.1190 +					weight.mWeight = (*ronaldweasley).second;
  1.1191 +					avBonesOut[(*ronaldweasley).first].push_back(weight);
  1.1192 +				}
  1.1193 +			}
  1.1194 +
  1.1195 +			// now build a final bone list
  1.1196 +			p_pcOut->mNumBones = 0;
  1.1197 +			for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy)
  1.1198 +				if (!avBonesOut[jfkennedy].empty())p_pcOut->mNumBones++;
  1.1199 +
  1.1200 +			p_pcOut->mBones = new aiBone*[p_pcOut->mNumBones];
  1.1201 +			aiBone** pcBone = p_pcOut->mBones;
  1.1202 +			for (unsigned int jfkennedy = 0; jfkennedy < mesh.mBones.size();++jfkennedy)	{
  1.1203 +				if (!avBonesOut[jfkennedy].empty())	{
  1.1204 +					aiBone* pc = *pcBone = new aiBone();
  1.1205 +					pc->mName.Set(mesh.mBones[jfkennedy].mName);
  1.1206 +					pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size();
  1.1207 +					pc->mWeights = new aiVertexWeight[pc->mNumWeights];
  1.1208 +					::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0],
  1.1209 +						sizeof(aiVertexWeight) * pc->mNumWeights);
  1.1210 +					++pcBone;
  1.1211 +				}
  1.1212 +			}
  1.1213 +		}
  1.1214 +	}
  1.1215 +}
  1.1216 +
  1.1217 +// ------------------------------------------------------------------------------------------------
  1.1218 +// Setup proper material indices and build output materials
  1.1219 +void ASEImporter::BuildMaterialIndices()
  1.1220 +{
  1.1221 +	ai_assert(NULL != pcScene);
  1.1222 +
  1.1223 +	// iterate through all materials and check whether we need them
  1.1224 +	for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
  1.1225 +	{
  1.1226 +		ASE::Material& mat = mParser->m_vMaterials[iMat];
  1.1227 +		if (mat.bNeed)	{
  1.1228 +			// Convert it to the aiMaterial layout
  1.1229 +			ConvertMaterial(mat);
  1.1230 +			++pcScene->mNumMaterials;
  1.1231 +		}
  1.1232 +		for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)
  1.1233 +		{
  1.1234 +			ASE::Material& submat = mat.avSubMaterials[iSubMat];
  1.1235 +			if (submat.bNeed)	{
  1.1236 +				// Convert it to the aiMaterial layout
  1.1237 +				ConvertMaterial(submat);
  1.1238 +				++pcScene->mNumMaterials;
  1.1239 +			}
  1.1240 +		}
  1.1241 +	}
  1.1242 +
  1.1243 +	// allocate the output material array
  1.1244 +	pcScene->mMaterials = new aiMaterial*[pcScene->mNumMaterials];
  1.1245 +	D3DS::Material** pcIntMaterials = new D3DS::Material*[pcScene->mNumMaterials];
  1.1246 +
  1.1247 +	unsigned int iNum = 0;
  1.1248 +	for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat) {
  1.1249 +		ASE::Material& mat = mParser->m_vMaterials[iMat];
  1.1250 +		if (mat.bNeed)
  1.1251 +		{
  1.1252 +			ai_assert(NULL != mat.pcInstance);
  1.1253 +			pcScene->mMaterials[iNum] = mat.pcInstance;
  1.1254 +
  1.1255 +			// Store the internal material, too
  1.1256 +			pcIntMaterials[iNum] = &mat;
  1.1257 +
  1.1258 +			// Iterate through all meshes and search for one which is using
  1.1259 +			// this top-level material index
  1.1260 +			for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)
  1.1261 +			{
  1.1262 +				aiMesh* mesh = pcScene->mMeshes[iMesh];
  1.1263 +				if (ASE::Face::DEFAULT_MATINDEX == mesh->mMaterialIndex &&
  1.1264 +					iMat == (uintptr_t)mesh->mColors[3])
  1.1265 +				{
  1.1266 +					mesh->mMaterialIndex = iNum;
  1.1267 +					mesh->mColors[3] = NULL;
  1.1268 +				}
  1.1269 +			}
  1.1270 +			iNum++;
  1.1271 +		}
  1.1272 +		for (unsigned int iSubMat = 0; iSubMat < mat.avSubMaterials.size();++iSubMat)	{
  1.1273 +			ASE::Material& submat = mat.avSubMaterials[iSubMat];
  1.1274 +			if (submat.bNeed)	{
  1.1275 +				ai_assert(NULL != submat.pcInstance);
  1.1276 +				pcScene->mMaterials[iNum] = submat.pcInstance;
  1.1277 +
  1.1278 +				// Store the internal material, too
  1.1279 +				pcIntMaterials[iNum] = &submat;
  1.1280 +
  1.1281 +				// Iterate through all meshes and search for one which is using
  1.1282 +				// this sub-level material index
  1.1283 +				for (unsigned int iMesh = 0; iMesh < pcScene->mNumMeshes;++iMesh)	{
  1.1284 +					aiMesh* mesh = pcScene->mMeshes[iMesh];
  1.1285 +
  1.1286 +					if (iSubMat == mesh->mMaterialIndex && iMat == (uintptr_t)mesh->mColors[3])	{
  1.1287 +						mesh->mMaterialIndex = iNum;
  1.1288 +						mesh->mColors[3]     = NULL;
  1.1289 +					}
  1.1290 +				}
  1.1291 +				iNum++;
  1.1292 +			}
  1.1293 +		}
  1.1294 +	}
  1.1295 +
  1.1296 +	// Dekete our temporary array
  1.1297 +	delete[] pcIntMaterials;
  1.1298 +}
  1.1299 +
  1.1300 +// ------------------------------------------------------------------------------------------------
  1.1301 +// Generate normal vectors basing on smoothing groups
  1.1302 +bool ASEImporter::GenerateNormals(ASE::Mesh& mesh)	{
  1.1303 +
  1.1304 +	if (!mesh.mNormals.empty() && !configRecomputeNormals)
  1.1305 +	{
  1.1306 +		// Check whether there are only uninitialized normals. If there are
  1.1307 +		// some, skip all normals from the file and compute them on our own
  1.1308 +		for (std::vector<aiVector3D>::const_iterator qq =  mesh.mNormals.begin();qq != mesh.mNormals.end();++qq) {
  1.1309 +			if ((*qq).x || (*qq).y || (*qq).z)
  1.1310 +			{
  1.1311 +				return true;
  1.1312 +			}
  1.1313 +		}
  1.1314 +	}
  1.1315 +	// The array is reused.
  1.1316 +	ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
  1.1317 +	return false;
  1.1318 +}
  1.1319 +
  1.1320 +#endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER