vrshoot

annotate 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
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2012, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41 /** @file A helper class that processes texture transformations */
nuclear@0 42
nuclear@0 43
nuclear@0 44 #include "AssimpPCH.h"
nuclear@0 45 #include "TextureTransform.h"
nuclear@0 46
nuclear@0 47 using namespace Assimp;
nuclear@0 48
nuclear@0 49
nuclear@0 50 // ------------------------------------------------------------------------------------------------
nuclear@0 51 // Constructor to be privately used by Importer
nuclear@0 52 TextureTransformStep::TextureTransformStep()
nuclear@0 53 {
nuclear@0 54 // nothing to do here
nuclear@0 55 }
nuclear@0 56
nuclear@0 57 // ------------------------------------------------------------------------------------------------
nuclear@0 58 // Destructor, private as well
nuclear@0 59 TextureTransformStep::~TextureTransformStep()
nuclear@0 60 {
nuclear@0 61 // nothing to do here
nuclear@0 62 }
nuclear@0 63
nuclear@0 64 // ------------------------------------------------------------------------------------------------
nuclear@0 65 // Returns whether the processing step is present in the given flag field.
nuclear@0 66 bool TextureTransformStep::IsActive( unsigned int pFlags) const
nuclear@0 67 {
nuclear@0 68 return (pFlags & aiProcess_TransformUVCoords) != 0;
nuclear@0 69 }
nuclear@0 70
nuclear@0 71 // ------------------------------------------------------------------------------------------------
nuclear@0 72 // Setup properties
nuclear@0 73 void TextureTransformStep::SetupProperties(const Importer* pImp)
nuclear@0 74 {
nuclear@0 75 configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL);
nuclear@0 76 }
nuclear@0 77
nuclear@0 78 // ------------------------------------------------------------------------------------------------
nuclear@0 79 void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
nuclear@0 80 {
nuclear@0 81 /* This function tries to simplify the input UV transformation.
nuclear@0 82 * That's very important as it allows us to reduce the number
nuclear@0 83 * of output UV channels. The oder in which the transformations
nuclear@0 84 * are applied is - as always - scaling, rotation, translation.
nuclear@0 85 */
nuclear@0 86
nuclear@0 87 char szTemp[512];
nuclear@0 88 int rounded = 0;
nuclear@0 89
nuclear@0 90
nuclear@0 91 /* Optimize the rotation angle. That's slightly difficult as
nuclear@0 92 * we have an inprecise floating-point number (when comparing
nuclear@0 93 * UV transformations we'll take that into account by using
nuclear@0 94 * an epsilon of 5 degrees). If there is a rotation value, we can't
nuclear@0 95 * perform any further optimizations.
nuclear@0 96 */
nuclear@0 97 if (info.mRotation)
nuclear@0 98 {
nuclear@0 99 float out = info.mRotation;
nuclear@0 100 if ((rounded = (int)(info.mRotation / (float)AI_MATH_TWO_PI)))
nuclear@0 101 {
nuclear@0 102 out -= rounded*(float)AI_MATH_PI;
nuclear@0 103
nuclear@0 104 sprintf(szTemp,"Texture coordinate rotation %f can be simplified to %f",info.mRotation,out);
nuclear@0 105 DefaultLogger::get()->info(szTemp);
nuclear@0 106 }
nuclear@0 107
nuclear@0 108 // Next step - convert negative rotation angles to positives
nuclear@0 109 if (out < 0.f)
nuclear@0 110 out = (float)AI_MATH_TWO_PI * 2 + out;
nuclear@0 111
nuclear@0 112 info.mRotation = out;
nuclear@0 113 return;
nuclear@0 114 }
nuclear@0 115
nuclear@0 116
nuclear@0 117 /* Optimize UV translation in the U direction. To determine whether
nuclear@0 118 * or not we can optimize we need to look at the requested mapping
nuclear@0 119 * type (e.g. if mirroring is active there IS a difference between
nuclear@0 120 * offset 2 and 3)
nuclear@0 121 */
nuclear@0 122 if ((rounded = (int)info.mTranslation.x)) {
nuclear@0 123 float out;
nuclear@0 124 szTemp[0] = 0;
nuclear@0 125 if (aiTextureMapMode_Wrap == info.mapU) {
nuclear@0 126 // Wrap - simple take the fraction of the field
nuclear@0 127 out = info.mTranslation.x-(float)rounded;
nuclear@0 128 sprintf(szTemp,"[w] UV U offset %f can be simplified to %f",info.mTranslation.x,out);
nuclear@0 129 }
nuclear@0 130 else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded) {
nuclear@0 131 // Mirror
nuclear@0 132 if (rounded % 2)
nuclear@0 133 rounded--;
nuclear@0 134 out = info.mTranslation.x-(float)rounded;
nuclear@0 135
nuclear@0 136 sprintf(szTemp,"[m/d] UV U offset %f can be simplified to %f",info.mTranslation.x,out);
nuclear@0 137 }
nuclear@0 138 else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU) {
nuclear@0 139 // Clamp - translations beyond 1,1 are senseless
nuclear@0 140 sprintf(szTemp,"[c] UV U offset %f can be clamped to 1.0f",info.mTranslation.x);
nuclear@0 141
nuclear@0 142 out = 1.f;
nuclear@0 143 }
nuclear@0 144 if (szTemp[0]) {
nuclear@0 145 DefaultLogger::get()->info(szTemp);
nuclear@0 146 info.mTranslation.x = out;
nuclear@0 147 }
nuclear@0 148 }
nuclear@0 149
nuclear@0 150 /* Optimize UV translation in the V direction. To determine whether
nuclear@0 151 * or not we can optimize we need to look at the requested mapping
nuclear@0 152 * type (e.g. if mirroring is active there IS a difference between
nuclear@0 153 * offset 2 and 3)
nuclear@0 154 */
nuclear@0 155 if ((rounded = (int)info.mTranslation.y)) {
nuclear@0 156 float out;
nuclear@0 157 szTemp[0] = 0;
nuclear@0 158 if (aiTextureMapMode_Wrap == info.mapV) {
nuclear@0 159 // Wrap - simple take the fraction of the field
nuclear@0 160 out = info.mTranslation.y-(float)rounded;
nuclear@0 161 sprintf(szTemp,"[w] UV V offset %f can be simplified to %f",info.mTranslation.y,out);
nuclear@0 162 }
nuclear@0 163 else if (aiTextureMapMode_Mirror == info.mapV && 1 != rounded) {
nuclear@0 164 // Mirror
nuclear@0 165 if (rounded % 2)
nuclear@0 166 rounded--;
nuclear@0 167 out = info.mTranslation.x-(float)rounded;
nuclear@0 168
nuclear@0 169 sprintf(szTemp,"[m/d] UV V offset %f can be simplified to %f",info.mTranslation.y,out);
nuclear@0 170 }
nuclear@0 171 else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV) {
nuclear@0 172 // Clamp - translations beyond 1,1 are senseless
nuclear@0 173 sprintf(szTemp,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y);
nuclear@0 174
nuclear@0 175 out = 1.f;
nuclear@0 176 }
nuclear@0 177 if (szTemp[0]) {
nuclear@0 178 DefaultLogger::get()->info(szTemp);
nuclear@0 179 info.mTranslation.y = out;
nuclear@0 180 }
nuclear@0 181 }
nuclear@0 182 return;
nuclear@0 183 }
nuclear@0 184
nuclear@0 185 // ------------------------------------------------------------------------------------------------
nuclear@0 186 void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n)
nuclear@0 187 {
nuclear@0 188 // Don't set if == 0 && wasn't set before
nuclear@0 189 for (std::list<TTUpdateInfo>::const_iterator it = l.begin();it != l.end(); ++it) {
nuclear@0 190 const TTUpdateInfo& info = *it;
nuclear@0 191
nuclear@0 192 if (info.directShortcut)
nuclear@0 193 *info.directShortcut = n;
nuclear@0 194 else if (!n)
nuclear@0 195 {
nuclear@0 196 info.mat->AddProperty<int>((int*)&n,1,AI_MATKEY_UVWSRC(info.semantic,info.index));
nuclear@0 197 }
nuclear@0 198 }
nuclear@0 199 }
nuclear@0 200
nuclear@0 201 // ------------------------------------------------------------------------------------------------
nuclear@0 202 inline const char* MappingModeToChar(aiTextureMapMode map)
nuclear@0 203 {
nuclear@0 204 if (aiTextureMapMode_Wrap == map)
nuclear@0 205 return "-w";
nuclear@0 206
nuclear@0 207 if (aiTextureMapMode_Mirror == map)
nuclear@0 208 return "-m";
nuclear@0 209
nuclear@0 210 return "-c";
nuclear@0 211 }
nuclear@0 212
nuclear@0 213 // ------------------------------------------------------------------------------------------------
nuclear@0 214 void TextureTransformStep::Execute( aiScene* pScene)
nuclear@0 215 {
nuclear@0 216 DefaultLogger::get()->debug("TransformUVCoordsProcess begin");
nuclear@0 217
nuclear@0 218
nuclear@0 219 /* We build a per-mesh list of texture transformations we'll need
nuclear@0 220 * to apply. To achieve this, we iterate through all materials,
nuclear@0 221 * find all textures and get their transformations and UV indices.
nuclear@0 222 * Then we search for all meshes using this material.
nuclear@0 223 */
nuclear@0 224 typedef std::list<STransformVecInfo> MeshTrafoList;
nuclear@0 225 std::vector<MeshTrafoList> meshLists(pScene->mNumMeshes);
nuclear@0 226
nuclear@0 227 for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
nuclear@0 228
nuclear@0 229 aiMaterial* mat = pScene->mMaterials[i];
nuclear@0 230 for (unsigned int a = 0; a < mat->mNumProperties;++a) {
nuclear@0 231
nuclear@0 232 aiMaterialProperty* prop = mat->mProperties[a];
nuclear@0 233 if (!::strcmp( prop->mKey.data, "$tex.file")) {
nuclear@0 234 STransformVecInfo info;
nuclear@0 235
nuclear@0 236 // Setup a shortcut structure to allow for a fast updating
nuclear@0 237 // of the UV index later
nuclear@0 238 TTUpdateInfo update;
nuclear@0 239 update.mat = (aiMaterial*) mat;
nuclear@0 240 update.semantic = prop->mSemantic;
nuclear@0 241 update.index = prop->mIndex;
nuclear@0 242
nuclear@0 243 // Get textured properties and transform
nuclear@0 244 for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) {
nuclear@0 245 aiMaterialProperty* prop2 = mat->mProperties[a2];
nuclear@0 246 if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) {
nuclear@0 247 continue;
nuclear@0 248 }
nuclear@0 249
nuclear@0 250 if ( !::strcmp( prop2->mKey.data, "$tex.uvwsrc")) {
nuclear@0 251 info.uvIndex = *((int*)prop2->mData);
nuclear@0 252
nuclear@0 253 // Store a direct pointer for later use
nuclear@0 254 update.directShortcut = (unsigned int*) prop2->mData;
nuclear@0 255 }
nuclear@0 256
nuclear@0 257 else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu")) {
nuclear@0 258 info.mapU = *((aiTextureMapMode*)prop2->mData);
nuclear@0 259 }
nuclear@0 260 else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodev")) {
nuclear@0 261 info.mapV = *((aiTextureMapMode*)prop2->mData);
nuclear@0 262 }
nuclear@0 263 else if ( !::strcmp( prop2->mKey.data, "$tex.uvtrafo")) {
nuclear@0 264 // ValidateDS should check this
nuclear@0 265 ai_assert(prop2->mDataLength >= 20);
nuclear@0 266 ::memcpy(&info.mTranslation.x,prop2->mData,sizeof(float)*5);
nuclear@0 267
nuclear@0 268 // Directly remove this property from the list
nuclear@0 269 mat->mNumProperties--;
nuclear@0 270 for (unsigned int a3 = a2; a3 < mat->mNumProperties;++a3) {
nuclear@0 271 mat->mProperties[a3] = mat->mProperties[a3+1];
nuclear@0 272 }
nuclear@0 273
nuclear@0 274 delete prop2;
nuclear@0 275
nuclear@0 276 // Warn: could be an underflow, but this does not invoke undefined behaviour
nuclear@0 277 --a2;
nuclear@0 278 }
nuclear@0 279 }
nuclear@0 280
nuclear@0 281 // Find out which transformations are to be evaluated
nuclear@0 282 if (!(configFlags & AI_UVTRAFO_ROTATION)) {
nuclear@0 283 info.mRotation = 0.f;
nuclear@0 284 }
nuclear@0 285 if (!(configFlags & AI_UVTRAFO_SCALING)) {
nuclear@0 286 info.mScaling = aiVector2D(1.f,1.f);
nuclear@0 287 }
nuclear@0 288 if (!(configFlags & AI_UVTRAFO_TRANSLATION)) {
nuclear@0 289 info.mTranslation = aiVector2D(0.f,0.f);
nuclear@0 290 }
nuclear@0 291
nuclear@0 292 // Do some preprocessing
nuclear@0 293 PreProcessUVTransform(info);
nuclear@0 294 info.uvIndex = std::min(info.uvIndex,AI_MAX_NUMBER_OF_TEXTURECOORDS -1u);
nuclear@0 295
nuclear@0 296 // Find out whether this material is used by more than
nuclear@0 297 // one mesh. This will make our task much, much more difficult!
nuclear@0 298 unsigned int cnt = 0;
nuclear@0 299 for (unsigned int n = 0; n < pScene->mNumMeshes;++n) {
nuclear@0 300 if (pScene->mMeshes[n]->mMaterialIndex == i)
nuclear@0 301 ++cnt;
nuclear@0 302 }
nuclear@0 303
nuclear@0 304 if (!cnt)
nuclear@0 305 continue;
nuclear@0 306 else if (1 != cnt) {
nuclear@0 307 // This material is referenced by more than one mesh!
nuclear@0 308 // So we need to make sure the UV index for the texture
nuclear@0 309 // is identical for each of it ...
nuclear@0 310 info.lockedPos = AI_TT_UV_IDX_LOCK_TBD;
nuclear@0 311 }
nuclear@0 312
nuclear@0 313 // Get all coresponding meshes
nuclear@0 314 for (unsigned int n = 0; n < pScene->mNumMeshes;++n) {
nuclear@0 315 aiMesh* mesh = pScene->mMeshes[n];
nuclear@0 316 if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0])
nuclear@0 317 continue;
nuclear@0 318
nuclear@0 319 unsigned int uv = info.uvIndex;
nuclear@0 320 if (!mesh->mTextureCoords[uv]) {
nuclear@0 321 // If the requested UV index is not available, take the first one instead.
nuclear@0 322 uv = 0;
nuclear@0 323 }
nuclear@0 324
nuclear@0 325 if (mesh->mNumUVComponents[info.uvIndex] >= 3){
nuclear@0 326 DefaultLogger::get()->warn("UV transformations on 3D mapping channels are not supported");
nuclear@0 327 continue;
nuclear@0 328 }
nuclear@0 329
nuclear@0 330 MeshTrafoList::iterator it;
nuclear@0 331
nuclear@0 332 // Check whether we have this transform setup already
nuclear@0 333 for (it = meshLists[n].begin();it != meshLists[n].end(); ++it) {
nuclear@0 334
nuclear@0 335 if ((*it) == info && (*it).uvIndex == uv) {
nuclear@0 336 (*it).updateList.push_back(update);
nuclear@0 337 break;
nuclear@0 338 }
nuclear@0 339 }
nuclear@0 340
nuclear@0 341 if (it == meshLists[n].end()) {
nuclear@0 342 meshLists[n].push_back(info);
nuclear@0 343 meshLists[n].back().uvIndex = uv;
nuclear@0 344 meshLists[n].back().updateList.push_back(update);
nuclear@0 345 }
nuclear@0 346 }
nuclear@0 347 }
nuclear@0 348 }
nuclear@0 349 }
nuclear@0 350
nuclear@0 351 char buffer[1024]; // should be sufficiently large
nuclear@0 352 unsigned int outChannels = 0, inChannels = 0, transformedChannels = 0;
nuclear@0 353
nuclear@0 354 // Now process all meshes. Important: we don't remove unreferenced UV channels.
nuclear@0 355 // This is a job for the RemoveUnreferencedData-Step.
nuclear@0 356 for (unsigned int q = 0; q < pScene->mNumMeshes;++q) {
nuclear@0 357
nuclear@0 358 aiMesh* mesh = pScene->mMeshes[q];
nuclear@0 359 MeshTrafoList& trafo = meshLists[q];
nuclear@0 360
nuclear@0 361 inChannels += mesh->GetNumUVChannels();
nuclear@0 362
nuclear@0 363 if (!mesh->mTextureCoords[0] || trafo.empty() || (trafo.size() == 1 && trafo.begin()->IsUntransformed())) {
nuclear@0 364 outChannels += mesh->GetNumUVChannels();
nuclear@0 365 continue;
nuclear@0 366 }
nuclear@0 367
nuclear@0 368 // Move untransformed UV channels to the first position in the list ....
nuclear@0 369 // except if we need a new locked index which should be as small as possible
nuclear@0 370 bool veto = false, need = false;
nuclear@0 371 unsigned int cnt = 0;
nuclear@0 372 unsigned int untransformed = 0;
nuclear@0 373
nuclear@0 374 MeshTrafoList::iterator it,it2;
nuclear@0 375 for (it = trafo.begin();it != trafo.end(); ++it,++cnt) {
nuclear@0 376
nuclear@0 377 if (!(*it).IsUntransformed()) {
nuclear@0 378 need = true;
nuclear@0 379 }
nuclear@0 380
nuclear@0 381 if ((*it).lockedPos == AI_TT_UV_IDX_LOCK_TBD) {
nuclear@0 382 // Lock this index and make sure it won't be changed
nuclear@0 383 (*it).lockedPos = cnt;
nuclear@0 384 veto = true;
nuclear@0 385 continue;
nuclear@0 386 }
nuclear@0 387
nuclear@0 388 if (!veto && it != trafo.begin() && (*it).IsUntransformed()) {
nuclear@0 389 for (it2 = trafo.begin();it2 != it; ++it2) {
nuclear@0 390 if (!(*it2).IsUntransformed())
nuclear@0 391 break;
nuclear@0 392 }
nuclear@0 393 trafo.insert(it2,*it);
nuclear@0 394 trafo.erase(it);
nuclear@0 395 break;
nuclear@0 396 }
nuclear@0 397 }
nuclear@0 398 if (!need)
nuclear@0 399 continue;
nuclear@0 400
nuclear@0 401 // Find all that are not at their 'locked' position and move them to it.
nuclear@0 402 // Conflicts are possible but quite unlikely.
nuclear@0 403 cnt = 0;
nuclear@0 404 for (it = trafo.begin();it != trafo.end(); ++it,++cnt) {
nuclear@0 405 if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt) {
nuclear@0 406 it2 = trafo.begin();unsigned int t = 0;
nuclear@0 407 while (t != (*it).lockedPos)
nuclear@0 408 ++it2;
nuclear@0 409
nuclear@0 410 if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE) {
nuclear@0 411 DefaultLogger::get()->error("Channel mismatch, can't compute all transformations properly [design bug]");
nuclear@0 412 continue;
nuclear@0 413 }
nuclear@0 414
nuclear@0 415 std::swap(*it2,*it);
nuclear@0 416 if ((*it).lockedPos == untransformed)
nuclear@0 417 untransformed = cnt;
nuclear@0 418 }
nuclear@0 419 }
nuclear@0 420
nuclear@0 421 // ... and add dummies for all unreferenced channels
nuclear@0 422 // at the end of the list
nuclear@0 423 bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS];
nuclear@0 424 for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
nuclear@0 425 ref[n] = (!mesh->mTextureCoords[n] ? true : false);
nuclear@0 426
nuclear@0 427 for (it = trafo.begin();it != trafo.end(); ++it)
nuclear@0 428 ref[(*it).uvIndex] = true;
nuclear@0 429
nuclear@0 430 for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
nuclear@0 431 if (ref[n])
nuclear@0 432 continue;
nuclear@0 433 trafo.push_back(STransformVecInfo());
nuclear@0 434 trafo.back().uvIndex = n;
nuclear@0 435 }
nuclear@0 436
nuclear@0 437 // Then check whether this list breaks the channel limit.
nuclear@0 438 // The unimportant ones are at the end of the list, so
nuclear@0 439 // it shouldn't be too worse if we remove them.
nuclear@0 440 unsigned int size = (unsigned int)trafo.size();
nuclear@0 441 if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) {
nuclear@0 442
nuclear@0 443 if (!DefaultLogger::isNullLogger()) {
nuclear@0 444 ::sprintf(buffer,"%u UV channels required but just %u available",
nuclear@0 445 static_cast<unsigned int>(trafo.size()),AI_MAX_NUMBER_OF_TEXTURECOORDS);
nuclear@0 446
nuclear@0 447 DefaultLogger::get()->error(buffer);
nuclear@0 448 }
nuclear@0 449 size = AI_MAX_NUMBER_OF_TEXTURECOORDS;
nuclear@0 450 }
nuclear@0 451
nuclear@0 452
nuclear@0 453 aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS];
nuclear@0 454 for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
nuclear@0 455 old[n] = mesh->mTextureCoords[n];
nuclear@0 456
nuclear@0 457 // Now continue and generate the output channels. Channels
nuclear@0 458 // that we're not going to need later can be overridden.
nuclear@0 459 it = trafo.begin();
nuclear@0 460 for (unsigned int n = 0; n < trafo.size();++n,++it) {
nuclear@0 461
nuclear@0 462 if (n >= size) {
nuclear@0 463 // Try to use an untransformed channel for all channels we threw over board
nuclear@0 464 UpdateUVIndex((*it).updateList,untransformed);
nuclear@0 465 continue;
nuclear@0 466 }
nuclear@0 467
nuclear@0 468 outChannels++;
nuclear@0 469
nuclear@0 470 // Write to the log
nuclear@0 471 if (!DefaultLogger::isNullLogger()) {
nuclear@0 472 sprintf(buffer,"Mesh %u, channel %u: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s",
nuclear@0 473 q,n,
nuclear@0 474 (*it).mTranslation.x,
nuclear@0 475 (*it).mTranslation.y,
nuclear@0 476 (*it).mScaling.x,
nuclear@0 477 (*it).mScaling.y,
nuclear@0 478 AI_RAD_TO_DEG( (*it).mRotation),
nuclear@0 479 MappingModeToChar ((*it).mapU),
nuclear@0 480 MappingModeToChar ((*it).mapV));
nuclear@0 481
nuclear@0 482 DefaultLogger::get()->info(buffer);
nuclear@0 483 }
nuclear@0 484
nuclear@0 485 // Check whether we need a new buffer here
nuclear@0 486 if (mesh->mTextureCoords[n]) {
nuclear@0 487
nuclear@0 488 it2 = it;++it2;
nuclear@0 489 for (unsigned int m = n+1; m < size;++m, ++it2) {
nuclear@0 490
nuclear@0 491 if ((*it2).uvIndex == n){
nuclear@0 492 it2 = trafo.begin();
nuclear@0 493 break;
nuclear@0 494 }
nuclear@0 495 }
nuclear@0 496 if (it2 == trafo.begin()){
nuclear@0 497 mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
nuclear@0 498 }
nuclear@0 499 }
nuclear@0 500 else mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
nuclear@0 501
nuclear@0 502 aiVector3D* src = old[(*it).uvIndex];
nuclear@0 503 aiVector3D* dest, *end;
nuclear@0 504 dest = mesh->mTextureCoords[n];
nuclear@0 505
nuclear@0 506 ai_assert(NULL != src);
nuclear@0 507
nuclear@0 508 // Copy the data to the destination array
nuclear@0 509 if (dest != src)
nuclear@0 510 ::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices);
nuclear@0 511
nuclear@0 512 end = dest + mesh->mNumVertices;
nuclear@0 513
nuclear@0 514 // Build a transformation matrix and transform all UV coords with it
nuclear@0 515 if (!(*it).IsUntransformed()) {
nuclear@0 516 const aiVector2D& trl = (*it).mTranslation;
nuclear@0 517 const aiVector2D& scl = (*it).mScaling;
nuclear@0 518
nuclear@0 519 // fixme: simplify ..
nuclear@0 520 ++transformedChannels;
nuclear@0 521 aiMatrix3x3 matrix;
nuclear@0 522
nuclear@0 523 aiMatrix3x3 m2,m3,m4,m5;
nuclear@0 524
nuclear@0 525 m4.a1 = scl.x;
nuclear@0 526 m4.b2 = scl.y;
nuclear@0 527
nuclear@0 528 m2.a3 = m2.b3 = 0.5f;
nuclear@0 529 m3.a3 = m3.b3 = -0.5f;
nuclear@0 530
nuclear@0 531 if ((*it).mRotation > AI_TT_ROTATION_EPSILON )
nuclear@0 532 aiMatrix3x3::RotationZ((*it).mRotation,matrix);
nuclear@0 533
nuclear@0 534 m5.a3 += trl.x; m5.b3 += trl.y;
nuclear@0 535 matrix = m2 * m4 * matrix * m3 * m5;
nuclear@0 536
nuclear@0 537 for (src = dest; src != end; ++src) { /* manual homogenious divide */
nuclear@0 538 src->z = 1.f;
nuclear@0 539 *src = matrix * *src;
nuclear@0 540 src->x /= src->z;
nuclear@0 541 src->y /= src->z;
nuclear@0 542 src->z = 0.f;
nuclear@0 543 }
nuclear@0 544 }
nuclear@0 545
nuclear@0 546 // Update all UV indices
nuclear@0 547 UpdateUVIndex((*it).updateList,n);
nuclear@0 548 }
nuclear@0 549 }
nuclear@0 550
nuclear@0 551 // Print some detailled statistics into the log
nuclear@0 552 if (!DefaultLogger::isNullLogger()) {
nuclear@0 553
nuclear@0 554 if (transformedChannels) {
nuclear@0 555 ::sprintf(buffer,"TransformUVCoordsProcess end: %u output channels (in: %u, modified: %u)",
nuclear@0 556 outChannels,inChannels,transformedChannels);
nuclear@0 557
nuclear@0 558 DefaultLogger::get()->info(buffer);
nuclear@0 559 }
nuclear@0 560 else DefaultLogger::get()->debug("TransformUVCoordsProcess finished");
nuclear@0 561 }
nuclear@0 562 }
nuclear@0 563
nuclear@0 564