vrshoot

diff libs/assimp/TextureTransform.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/TextureTransform.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,564 @@
     1.4 +/*
     1.5 +Open Asset Import Library (assimp)
     1.6 +----------------------------------------------------------------------
     1.7 +
     1.8 +Copyright (c) 2006-2012, assimp team
     1.9 +All rights reserved.
    1.10 +
    1.11 +Redistribution and use of this software in source and binary forms, 
    1.12 +with or without modification, are permitted provided that the 
    1.13 +following conditions are met:
    1.14 +
    1.15 +* Redistributions of source code must retain the above
    1.16 +  copyright notice, this list of conditions and the
    1.17 +  following disclaimer.
    1.18 +
    1.19 +* Redistributions in binary form must reproduce the above
    1.20 +  copyright notice, this list of conditions and the
    1.21 +  following disclaimer in the documentation and/or other
    1.22 +  materials provided with the distribution.
    1.23 +
    1.24 +* Neither the name of the assimp team, nor the names of its
    1.25 +  contributors may be used to endorse or promote products
    1.26 +  derived from this software without specific prior
    1.27 +  written permission of the assimp team.
    1.28 +
    1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
    1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.40 +
    1.41 +----------------------------------------------------------------------
    1.42 +*/
    1.43 +
    1.44 +/** @file A helper class that processes texture transformations */
    1.45 +
    1.46 +
    1.47 +#include "AssimpPCH.h"
    1.48 +#include "TextureTransform.h"
    1.49 +
    1.50 +using namespace Assimp;
    1.51 +
    1.52 +
    1.53 +// ------------------------------------------------------------------------------------------------
    1.54 +// Constructor to be privately used by Importer
    1.55 +TextureTransformStep::TextureTransformStep()
    1.56 +{
    1.57 +	// nothing to do here
    1.58 +}
    1.59 +
    1.60 +// ------------------------------------------------------------------------------------------------
    1.61 +// Destructor, private as well
    1.62 +TextureTransformStep::~TextureTransformStep()
    1.63 +{
    1.64 +	// nothing to do here
    1.65 +}
    1.66 +
    1.67 +// ------------------------------------------------------------------------------------------------
    1.68 +// Returns whether the processing step is present in the given flag field.
    1.69 +bool TextureTransformStep::IsActive( unsigned int pFlags) const
    1.70 +{
    1.71 +	return	(pFlags & aiProcess_TransformUVCoords) != 0;
    1.72 +}
    1.73 +
    1.74 +// ------------------------------------------------------------------------------------------------
    1.75 +// Setup properties
    1.76 +void TextureTransformStep::SetupProperties(const Importer* pImp)
    1.77 +{
    1.78 +	configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL);
    1.79 +}
    1.80 +
    1.81 +// ------------------------------------------------------------------------------------------------
    1.82 +void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
    1.83 +{
    1.84 +	/*  This function tries to simplify the input UV transformation.
    1.85 +	 *  That's very important as it allows us to reduce the number 
    1.86 +	 *  of output UV channels. The oder in which the transformations
    1.87 +	 *  are applied is - as always - scaling, rotation, translation.
    1.88 +	 */
    1.89 +
    1.90 +	char szTemp[512];
    1.91 +	int rounded = 0;
    1.92 +
    1.93 +
    1.94 +	/* Optimize the rotation angle. That's slightly difficult as
    1.95 +	 * we have an inprecise floating-point number (when comparing
    1.96 +	 * UV transformations we'll take that into account by using
    1.97 +	 * an epsilon of 5 degrees). If there is a rotation value, we can't
    1.98 +	 * perform any further optimizations.
    1.99 +	 */
   1.100 +	if (info.mRotation)
   1.101 +	{
   1.102 +		float out = info.mRotation;
   1.103 +		if ((rounded = (int)(info.mRotation / (float)AI_MATH_TWO_PI)))
   1.104 +		{
   1.105 +			out -= rounded*(float)AI_MATH_PI;
   1.106 +
   1.107 +			sprintf(szTemp,"Texture coordinate rotation %f can be simplified to %f",info.mRotation,out);
   1.108 +			DefaultLogger::get()->info(szTemp);
   1.109 +		}
   1.110 +
   1.111 +		// Next step - convert negative rotation angles to positives
   1.112 +		if (out < 0.f)
   1.113 +			out = (float)AI_MATH_TWO_PI * 2 + out;
   1.114 +
   1.115 +		info.mRotation = out;
   1.116 +		return;
   1.117 +	}
   1.118 +
   1.119 +
   1.120 +	/* Optimize UV translation in the U direction. To determine whether
   1.121 +	 * or not we can optimize we need to look at the requested mapping
   1.122 +	 * type (e.g. if mirroring is active there IS a difference between
   1.123 +	 * offset 2 and 3)
   1.124 +	 */
   1.125 +	if ((rounded  = (int)info.mTranslation.x))	{
   1.126 +		float out;
   1.127 +		szTemp[0] = 0;
   1.128 +		if (aiTextureMapMode_Wrap == info.mapU)	{
   1.129 +			// Wrap - simple take the fraction of the field
   1.130 +			out = info.mTranslation.x-(float)rounded;
   1.131 +			sprintf(szTemp,"[w] UV U offset %f can be simplified to %f",info.mTranslation.x,out);
   1.132 +		}
   1.133 +		else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded)	{
   1.134 +			// Mirror 
   1.135 +			if (rounded % 2)
   1.136 +				rounded--;
   1.137 +			out = info.mTranslation.x-(float)rounded;
   1.138 +
   1.139 +			sprintf(szTemp,"[m/d] UV U offset %f can be simplified to %f",info.mTranslation.x,out);
   1.140 +		}
   1.141 +		else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU)	{
   1.142 +			// Clamp - translations beyond 1,1 are senseless
   1.143 +			sprintf(szTemp,"[c] UV U offset %f can be clamped to 1.0f",info.mTranslation.x);
   1.144 +
   1.145 +			out = 1.f;
   1.146 +		}
   1.147 +		if (szTemp[0])		{
   1.148 +			DefaultLogger::get()->info(szTemp);
   1.149 +			info.mTranslation.x = out;
   1.150 +		}
   1.151 +	}
   1.152 +
   1.153 +	/* Optimize UV translation in the V direction. To determine whether
   1.154 +	 * or not we can optimize we need to look at the requested mapping
   1.155 +	 * type (e.g. if mirroring is active there IS a difference between
   1.156 +	 * offset 2 and 3)
   1.157 +	 */
   1.158 +	if ((rounded  = (int)info.mTranslation.y))	{
   1.159 +		float out;
   1.160 +		szTemp[0] = 0;
   1.161 +		if (aiTextureMapMode_Wrap == info.mapV)	{
   1.162 +			// Wrap - simple take the fraction of the field
   1.163 +			out = info.mTranslation.y-(float)rounded;
   1.164 +			sprintf(szTemp,"[w] UV V offset %f can be simplified to %f",info.mTranslation.y,out);
   1.165 +		}
   1.166 +		else if (aiTextureMapMode_Mirror == info.mapV  && 1 != rounded)	{
   1.167 +			// Mirror 
   1.168 +			if (rounded % 2)
   1.169 +				rounded--;
   1.170 +			out = info.mTranslation.x-(float)rounded;
   1.171 +
   1.172 +			sprintf(szTemp,"[m/d] UV V offset %f can be simplified to %f",info.mTranslation.y,out);
   1.173 +		}
   1.174 +		else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV)	{
   1.175 +			// Clamp - translations beyond 1,1 are senseless
   1.176 +			sprintf(szTemp,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y);
   1.177 +
   1.178 +			out = 1.f;
   1.179 +		}
   1.180 +		if (szTemp[0])	{
   1.181 +			DefaultLogger::get()->info(szTemp);
   1.182 +			info.mTranslation.y = out;
   1.183 +		}
   1.184 +	}
   1.185 +	return;
   1.186 +}
   1.187 +
   1.188 +// ------------------------------------------------------------------------------------------------
   1.189 +void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n)
   1.190 +{
   1.191 +	// Don't set if == 0 && wasn't set before
   1.192 +	for (std::list<TTUpdateInfo>::const_iterator it = l.begin();it != l.end(); ++it) {
   1.193 +		const TTUpdateInfo& info = *it;
   1.194 +
   1.195 +		if (info.directShortcut)
   1.196 +			*info.directShortcut = n;
   1.197 +		else if (!n)
   1.198 +		{
   1.199 +			info.mat->AddProperty<int>((int*)&n,1,AI_MATKEY_UVWSRC(info.semantic,info.index));
   1.200 +		}
   1.201 +	}
   1.202 +}
   1.203 +
   1.204 +// ------------------------------------------------------------------------------------------------
   1.205 +inline const char* MappingModeToChar(aiTextureMapMode map)
   1.206 +{
   1.207 +	if (aiTextureMapMode_Wrap == map)
   1.208 +		return "-w";
   1.209 +
   1.210 +	if (aiTextureMapMode_Mirror == map)
   1.211 +		return "-m";
   1.212 +	
   1.213 +	return "-c";
   1.214 +}
   1.215 +
   1.216 +// ------------------------------------------------------------------------------------------------
   1.217 +void TextureTransformStep::Execute( aiScene* pScene) 
   1.218 +{
   1.219 +	DefaultLogger::get()->debug("TransformUVCoordsProcess begin");
   1.220 +	
   1.221 +
   1.222 +	/*  We build a per-mesh list of texture transformations we'll need
   1.223 +	 *  to apply. To achieve this, we iterate through all materials, 
   1.224 +	 *  find all textures and get their transformations and UV indices. 
   1.225 +	 *  Then we search for all meshes using this material.
   1.226 +	 */
   1.227 +	typedef std::list<STransformVecInfo> MeshTrafoList;
   1.228 +	std::vector<MeshTrafoList> meshLists(pScene->mNumMeshes);
   1.229 +
   1.230 +	for (unsigned int i = 0; i < pScene->mNumMaterials;++i)	{
   1.231 +
   1.232 +		aiMaterial* mat = pScene->mMaterials[i];
   1.233 +		for (unsigned int a = 0; a < mat->mNumProperties;++a)	{
   1.234 +
   1.235 +			aiMaterialProperty* prop = mat->mProperties[a];
   1.236 +			if (!::strcmp( prop->mKey.data, "$tex.file"))	{
   1.237 +				STransformVecInfo info;
   1.238 +
   1.239 +				// Setup a shortcut structure to allow for a fast updating
   1.240 +				// of the UV index later
   1.241 +				TTUpdateInfo update;
   1.242 +				update.mat = (aiMaterial*) mat;
   1.243 +				update.semantic = prop->mSemantic;
   1.244 +				update.index = prop->mIndex;
   1.245 +
   1.246 +				// Get textured properties and transform
   1.247 +				for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)  {
   1.248 +					aiMaterialProperty* prop2 = mat->mProperties[a2];
   1.249 +					if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) {
   1.250 +						continue;
   1.251 +					}
   1.252 +
   1.253 +					if ( !::strcmp( prop2->mKey.data, "$tex.uvwsrc")) {
   1.254 +						info.uvIndex = *((int*)prop2->mData);
   1.255 +
   1.256 +						// Store a direct pointer for later use
   1.257 +						update.directShortcut = (unsigned int*) prop2->mData;
   1.258 +					}
   1.259 +
   1.260 +					else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu")) {
   1.261 +						info.mapU = *((aiTextureMapMode*)prop2->mData);
   1.262 +					}
   1.263 +					else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodev")) {
   1.264 +						info.mapV = *((aiTextureMapMode*)prop2->mData);
   1.265 +					}
   1.266 +					else if ( !::strcmp( prop2->mKey.data, "$tex.uvtrafo"))  {
   1.267 +						// ValidateDS should check this
   1.268 +						ai_assert(prop2->mDataLength >= 20); 
   1.269 +						::memcpy(&info.mTranslation.x,prop2->mData,sizeof(float)*5);
   1.270 +
   1.271 +						// Directly remove this property from the list 
   1.272 +						mat->mNumProperties--;
   1.273 +						for (unsigned int a3 = a2; a3 < mat->mNumProperties;++a3) {
   1.274 +							mat->mProperties[a3] = mat->mProperties[a3+1];
   1.275 +						}
   1.276 +
   1.277 +						delete prop2;
   1.278 +
   1.279 +						// Warn: could be an underflow, but this does not invoke undefined behaviour
   1.280 +						--a2; 
   1.281 +					}
   1.282 +				}
   1.283 +
   1.284 +				// Find out which transformations are to be evaluated
   1.285 +				if (!(configFlags & AI_UVTRAFO_ROTATION)) {
   1.286 +					info.mRotation = 0.f;
   1.287 +				}
   1.288 +				if (!(configFlags & AI_UVTRAFO_SCALING)) {
   1.289 +					info.mScaling = aiVector2D(1.f,1.f);
   1.290 +				}
   1.291 +				if (!(configFlags & AI_UVTRAFO_TRANSLATION)) {
   1.292 +					info.mTranslation = aiVector2D(0.f,0.f);
   1.293 +				}
   1.294 +
   1.295 +				// Do some preprocessing
   1.296 +				PreProcessUVTransform(info);
   1.297 +				info.uvIndex = std::min(info.uvIndex,AI_MAX_NUMBER_OF_TEXTURECOORDS -1u);
   1.298 +
   1.299 +				// Find out whether this material is used by more than
   1.300 +				// one mesh. This will make our task much, much more difficult!
   1.301 +				unsigned int cnt = 0;
   1.302 +				for (unsigned int n = 0; n < pScene->mNumMeshes;++n)	{
   1.303 +					if (pScene->mMeshes[n]->mMaterialIndex == i)
   1.304 +						++cnt;
   1.305 +				}
   1.306 +
   1.307 +				if (!cnt)
   1.308 +					continue;
   1.309 +				else if (1 != cnt)	{
   1.310 +					// This material is referenced by more than one mesh!
   1.311 +					// So we need to make sure the UV index for the texture
   1.312 +					// is identical for each of it ...
   1.313 +					info.lockedPos = AI_TT_UV_IDX_LOCK_TBD;
   1.314 +				}
   1.315 +
   1.316 +				// Get all coresponding meshes
   1.317 +				for (unsigned int n = 0; n < pScene->mNumMeshes;++n)	{
   1.318 +					aiMesh* mesh = pScene->mMeshes[n];
   1.319 +					if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0])
   1.320 +						continue;
   1.321 +
   1.322 +					unsigned int uv = info.uvIndex;
   1.323 +					if (!mesh->mTextureCoords[uv])	{
   1.324 +						// If the requested UV index is not available, take the first one instead.
   1.325 +						uv = 0;
   1.326 +					}
   1.327 +					
   1.328 +					if (mesh->mNumUVComponents[info.uvIndex] >= 3){
   1.329 +						DefaultLogger::get()->warn("UV transformations on 3D mapping channels are not supported");
   1.330 +						continue;
   1.331 +					}
   1.332 +
   1.333 +					MeshTrafoList::iterator it;
   1.334 +
   1.335 +					// Check whether we have this transform setup already
   1.336 +					for (it = meshLists[n].begin();it != meshLists[n].end(); ++it)	{
   1.337 +
   1.338 +						if ((*it) == info && (*it).uvIndex == uv)	{
   1.339 +							(*it).updateList.push_back(update);
   1.340 +							break;
   1.341 +						}
   1.342 +					}
   1.343 +
   1.344 +					if (it == meshLists[n].end())	{
   1.345 +						meshLists[n].push_back(info);
   1.346 +						meshLists[n].back().uvIndex = uv;
   1.347 +						meshLists[n].back().updateList.push_back(update);
   1.348 +					}
   1.349 +				}
   1.350 +			}
   1.351 +		}
   1.352 +	}
   1.353 +
   1.354 +	char buffer[1024]; // should be sufficiently large
   1.355 +	unsigned int outChannels = 0, inChannels = 0, transformedChannels = 0;
   1.356 +
   1.357 +	// Now process all meshes. Important: we don't remove unreferenced UV channels.
   1.358 +	// This is a job for the RemoveUnreferencedData-Step.
   1.359 +	for (unsigned int q = 0; q < pScene->mNumMeshes;++q)	{
   1.360 +
   1.361 +		aiMesh* mesh = pScene->mMeshes[q];
   1.362 +		MeshTrafoList& trafo =  meshLists[q];
   1.363 +
   1.364 +		inChannels += mesh->GetNumUVChannels();
   1.365 +
   1.366 +		if (!mesh->mTextureCoords[0] || trafo.empty() ||  (trafo.size() == 1 && trafo.begin()->IsUntransformed())) {
   1.367 +			outChannels += mesh->GetNumUVChannels();
   1.368 +			continue;
   1.369 +		}
   1.370 +
   1.371 +		// Move untransformed UV channels to the first position in the list .... 
   1.372 +		// except if we need a new locked index which should be as small as possible
   1.373 +		bool veto = false, need = false;
   1.374 +		unsigned int cnt = 0;
   1.375 +		unsigned int untransformed = 0;
   1.376 +
   1.377 +		MeshTrafoList::iterator it,it2;
   1.378 +		for (it = trafo.begin();it != trafo.end(); ++it,++cnt)	{
   1.379 +
   1.380 +			if (!(*it).IsUntransformed()) {
   1.381 +				need = true;
   1.382 +			}
   1.383 +
   1.384 +			if ((*it).lockedPos == AI_TT_UV_IDX_LOCK_TBD)	{
   1.385 +				// Lock this index and make sure it won't be changed
   1.386 +				(*it).lockedPos = cnt;
   1.387 +				veto = true;
   1.388 +				continue;
   1.389 +			}
   1.390 +
   1.391 +			if (!veto && it != trafo.begin() && (*it).IsUntransformed())	{
   1.392 +				for (it2 = trafo.begin();it2 != it; ++it2) {
   1.393 +					if (!(*it2).IsUntransformed()) 
   1.394 +						break;
   1.395 +				}
   1.396 +				trafo.insert(it2,*it);
   1.397 +				trafo.erase(it);
   1.398 +				break;
   1.399 +			}
   1.400 +		}
   1.401 +		if (!need)
   1.402 +			continue;
   1.403 +
   1.404 +		// Find all that are not at their 'locked' position and move them to it. 
   1.405 +		// Conflicts are possible but quite unlikely.
   1.406 +		cnt = 0;
   1.407 +		for (it = trafo.begin();it != trafo.end(); ++it,++cnt) {
   1.408 +			if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt) {
   1.409 +				it2 = trafo.begin();unsigned int t = 0;
   1.410 +				while (t != (*it).lockedPos)
   1.411 +					++it2;
   1.412 +
   1.413 +				if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE) {
   1.414 +					DefaultLogger::get()->error("Channel mismatch, can't compute all transformations properly [design bug]");
   1.415 +					continue;
   1.416 +				}
   1.417 +
   1.418 +				std::swap(*it2,*it);
   1.419 +				if ((*it).lockedPos == untransformed)
   1.420 +					untransformed = cnt;
   1.421 +			}
   1.422 +		}
   1.423 +
   1.424 +		// ... and add dummies for all unreferenced channels
   1.425 +		// at the end of the list
   1.426 +		bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS];
   1.427 +		for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
   1.428 +			ref[n] = (!mesh->mTextureCoords[n] ? true : false);
   1.429 +
   1.430 +		for (it = trafo.begin();it != trafo.end(); ++it)
   1.431 +			ref[(*it).uvIndex] = true;
   1.432 +
   1.433 +		for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
   1.434 +			if (ref[n])
   1.435 +				continue;
   1.436 +			trafo.push_back(STransformVecInfo());
   1.437 +			trafo.back().uvIndex = n;
   1.438 +		}
   1.439 +
   1.440 +		// Then check whether this list breaks the channel limit.
   1.441 +		// The unimportant ones are at the end of the list, so
   1.442 +		// it shouldn't be too worse if we remove them.
   1.443 +		unsigned int size = (unsigned int)trafo.size();
   1.444 +		if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) {
   1.445 +
   1.446 +			if (!DefaultLogger::isNullLogger()) {
   1.447 +				::sprintf(buffer,"%u UV channels required but just %u available", 
   1.448 +					static_cast<unsigned int>(trafo.size()),AI_MAX_NUMBER_OF_TEXTURECOORDS);
   1.449 +
   1.450 +				DefaultLogger::get()->error(buffer);
   1.451 +			}
   1.452 +			size = AI_MAX_NUMBER_OF_TEXTURECOORDS;
   1.453 +		}
   1.454 +
   1.455 +
   1.456 +		aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS];
   1.457 +		for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
   1.458 +			old[n] = mesh->mTextureCoords[n];
   1.459 +
   1.460 +		// Now continue and generate the output channels. Channels
   1.461 +		// that we're not going to need later can be overridden.
   1.462 +		it = trafo.begin();
   1.463 +		for (unsigned int n = 0; n < trafo.size();++n,++it)	{
   1.464 +
   1.465 +			if (n >= size)	{
   1.466 +				// Try to use an untransformed channel for all channels we threw over board
   1.467 +				UpdateUVIndex((*it).updateList,untransformed);
   1.468 +				continue;
   1.469 +			}
   1.470 +
   1.471 +			outChannels++;
   1.472 +
   1.473 +			// Write to the log
   1.474 +			if (!DefaultLogger::isNullLogger())	{
   1.475 +				sprintf(buffer,"Mesh %u, channel %u: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s",
   1.476 +					q,n,
   1.477 +					(*it).mTranslation.x,
   1.478 +					(*it).mTranslation.y,
   1.479 +					(*it).mScaling.x,
   1.480 +					(*it).mScaling.y,
   1.481 +					AI_RAD_TO_DEG( (*it).mRotation),
   1.482 +					MappingModeToChar ((*it).mapU),
   1.483 +					MappingModeToChar ((*it).mapV));
   1.484 +
   1.485 +				DefaultLogger::get()->info(buffer);
   1.486 +			}
   1.487 +
   1.488 +			// Check whether we need a new buffer here
   1.489 +			if (mesh->mTextureCoords[n])	{
   1.490 +
   1.491 +				it2 = it;++it2;
   1.492 +				for (unsigned int m = n+1; m < size;++m, ++it2)	{
   1.493 +
   1.494 +					if ((*it2).uvIndex == n){
   1.495 +						it2 = trafo.begin();
   1.496 +						break;
   1.497 +					}
   1.498 +				}
   1.499 +				if (it2 == trafo.begin()){
   1.500 +					mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
   1.501 +				} 
   1.502 +			}
   1.503 +			else mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
   1.504 +
   1.505 +			aiVector3D* src = old[(*it).uvIndex];
   1.506 +			aiVector3D* dest, *end;
   1.507 +			dest = mesh->mTextureCoords[n];
   1.508 +
   1.509 +			ai_assert(NULL != src);
   1.510 +
   1.511 +			// Copy the data to the destination array
   1.512 +			if (dest != src)
   1.513 +				::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices);
   1.514 +
   1.515 +			end = dest + mesh->mNumVertices;
   1.516 +
   1.517 +			// Build a transformation matrix and transform all UV coords with it
   1.518 +			if (!(*it).IsUntransformed()) {
   1.519 +				const aiVector2D& trl = (*it).mTranslation;
   1.520 +				const aiVector2D& scl = (*it).mScaling;
   1.521 +
   1.522 +				// fixme: simplify ..
   1.523 +				++transformedChannels;
   1.524 +				aiMatrix3x3 matrix;
   1.525 +
   1.526 +				aiMatrix3x3 m2,m3,m4,m5;
   1.527 +
   1.528 +				m4.a1 = scl.x;
   1.529 +				m4.b2 = scl.y;
   1.530 +				
   1.531 +				m2.a3 = m2.b3 = 0.5f;
   1.532 +				m3.a3 = m3.b3 = -0.5f;
   1.533 +
   1.534 +				if ((*it).mRotation > AI_TT_ROTATION_EPSILON )
   1.535 +					aiMatrix3x3::RotationZ((*it).mRotation,matrix);
   1.536 +
   1.537 +				m5.a3 += trl.x; m5.b3 += trl.y;
   1.538 +				matrix = m2 * m4 * matrix * m3 * m5;
   1.539 +				
   1.540 +				for (src = dest; src != end; ++src)	{ /* manual homogenious divide */
   1.541 +					src->z = 1.f;
   1.542 +					*src = matrix * *src;
   1.543 +					src->x /= src->z;
   1.544 +					src->y /= src->z;
   1.545 +					src->z = 0.f;
   1.546 +				}
   1.547 +			}
   1.548 +
   1.549 +			// Update all UV indices
   1.550 +			UpdateUVIndex((*it).updateList,n);
   1.551 +		}
   1.552 +	}
   1.553 +
   1.554 +	// Print some detailled statistics into the log
   1.555 +	if (!DefaultLogger::isNullLogger())	{
   1.556 +
   1.557 +		if (transformedChannels)	{
   1.558 +			::sprintf(buffer,"TransformUVCoordsProcess end: %u output channels (in: %u, modified: %u)",
   1.559 +				outChannels,inChannels,transformedChannels);
   1.560 +
   1.561 +			DefaultLogger::get()->info(buffer);
   1.562 +		}
   1.563 +		else DefaultLogger::get()->debug("TransformUVCoordsProcess finished");
   1.564 +	}
   1.565 +}
   1.566 +
   1.567 +