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 +