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
|