1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4
5 Copyright (c) 2006-2019, assimp team
6
7
8 All rights reserved.
9
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the
12 following conditions are met:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
40 ----------------------------------------------------------------------
41 */
42
43 /// @file ProcessHelper.cpp
44 /** Implement shared utility functions for postprocessing steps */
45
46
47 #include "ProcessHelper.h"
48
49
50 #include <limits>
51
52 namespace Assimp {
53
54 // -------------------------------------------------------------------------------
ConvertListToStrings(const std::string & in,std::list<std::string> & out)55 void ConvertListToStrings(const std::string& in, std::list<std::string>& out)
56 {
57 const char* s = in.c_str();
58 while (*s) {
59 SkipSpacesAndLineEnd(&s);
60 if (*s == '\'') {
61 const char* base = ++s;
62 while (*s != '\'') {
63 ++s;
64 if (*s == '\0') {
65 ASSIMP_LOG_ERROR("ConvertListToString: String list is ill-formatted");
66 return;
67 }
68 }
69 out.push_back(std::string(base,(size_t)(s-base)));
70 ++s;
71 }
72 else {
73 out.push_back(GetNextToken(s));
74 }
75 }
76 }
77
78 // -------------------------------------------------------------------------------
FindAABBTransformed(const aiMesh * mesh,aiVector3D & min,aiVector3D & max,const aiMatrix4x4 & m)79 void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max,
80 const aiMatrix4x4& m)
81 {
82 min = aiVector3D ( ai_real( 10e10 ), ai_real( 10e10 ), ai_real( 10e10 ) );
83 max = aiVector3D ( ai_real( -10e10 ), ai_real( -10e10 ), ai_real( -10e10 ) );
84 for (unsigned int i = 0;i < mesh->mNumVertices;++i)
85 {
86 const aiVector3D v = m * mesh->mVertices[i];
87 min = std::min(v,min);
88 max = std::max(v,max);
89 }
90 }
91
92 // -------------------------------------------------------------------------------
FindMeshCenter(aiMesh * mesh,aiVector3D & out,aiVector3D & min,aiVector3D & max)93 void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max)
94 {
95 ArrayBounds(mesh->mVertices,mesh->mNumVertices, min,max);
96 out = min + (max-min)*(ai_real)0.5;
97 }
98
99 // -------------------------------------------------------------------------------
FindSceneCenter(aiScene * scene,aiVector3D & out,aiVector3D & min,aiVector3D & max)100 void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max) {
101 if ( NULL == scene ) {
102 return;
103 }
104
105 if ( 0 == scene->mNumMeshes ) {
106 return;
107 }
108 FindMeshCenter(scene->mMeshes[0], out, min, max);
109 for (unsigned int i = 1; i < scene->mNumMeshes; ++i) {
110 aiVector3D tout, tmin, tmax;
111 FindMeshCenter(scene->mMeshes[i], tout, tmin, tmax);
112 if (min[0] > tmin[0]) min[0] = tmin[0];
113 if (min[1] > tmin[1]) min[1] = tmin[1];
114 if (min[2] > tmin[2]) min[2] = tmin[2];
115 if (max[0] < tmax[0]) max[0] = tmax[0];
116 if (max[1] < tmax[1]) max[1] = tmax[1];
117 if (max[2] < tmax[2]) max[2] = tmax[2];
118 }
119 out = min + (max-min)*(ai_real)0.5;
120 }
121
122
123 // -------------------------------------------------------------------------------
FindMeshCenterTransformed(aiMesh * mesh,aiVector3D & out,aiVector3D & min,aiVector3D & max,const aiMatrix4x4 & m)124 void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min,
125 aiVector3D& max, const aiMatrix4x4& m)
126 {
127 FindAABBTransformed(mesh,min,max,m);
128 out = min + (max-min)*(ai_real)0.5;
129 }
130
131 // -------------------------------------------------------------------------------
FindMeshCenter(aiMesh * mesh,aiVector3D & out)132 void FindMeshCenter (aiMesh* mesh, aiVector3D& out)
133 {
134 aiVector3D min,max;
135 FindMeshCenter(mesh,out,min,max);
136 }
137
138 // -------------------------------------------------------------------------------
FindMeshCenterTransformed(aiMesh * mesh,aiVector3D & out,const aiMatrix4x4 & m)139 void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,
140 const aiMatrix4x4& m)
141 {
142 aiVector3D min,max;
143 FindMeshCenterTransformed(mesh,out,min,max,m);
144 }
145
146 // -------------------------------------------------------------------------------
ComputePositionEpsilon(const aiMesh * pMesh)147 ai_real ComputePositionEpsilon(const aiMesh* pMesh)
148 {
149 const ai_real epsilon = ai_real( 1e-4 );
150
151 // calculate the position bounds so we have a reliable epsilon to check position differences against
152 aiVector3D minVec, maxVec;
153 ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,minVec,maxVec);
154 return (maxVec - minVec).Length() * epsilon;
155 }
156
157 // -------------------------------------------------------------------------------
ComputePositionEpsilon(const aiMesh * const * pMeshes,size_t num)158 ai_real ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num)
159 {
160 ai_assert( NULL != pMeshes );
161
162 const ai_real epsilon = ai_real( 1e-4 );
163
164 // calculate the position bounds so we have a reliable epsilon to check position differences against
165 aiVector3D minVec, maxVec, mi, ma;
166 MinMaxChooser<aiVector3D>()(minVec,maxVec);
167
168 for (size_t a = 0; a < num; ++a) {
169 const aiMesh* pMesh = pMeshes[a];
170 ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,mi,ma);
171
172 minVec = std::min(minVec,mi);
173 maxVec = std::max(maxVec,ma);
174 }
175 return (maxVec - minVec).Length() * epsilon;
176 }
177
178
179 // -------------------------------------------------------------------------------
GetMeshVFormatUnique(const aiMesh * pcMesh)180 unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh)
181 {
182 ai_assert(NULL != pcMesh);
183
184 // FIX: the hash may never be 0. Otherwise a comparison against
185 // nullptr could be successful
186 unsigned int iRet = 1;
187
188 // normals
189 if (pcMesh->HasNormals())iRet |= 0x2;
190 // tangents and bitangents
191 if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4;
192
193 #ifdef BOOST_STATIC_ASSERT
194 BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
195 BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
196 #endif
197
198 // texture coordinates
199 unsigned int p = 0;
200 while (pcMesh->HasTextureCoords(p))
201 {
202 iRet |= (0x100 << p);
203 if (3 == pcMesh->mNumUVComponents[p])
204 iRet |= (0x10000 << p);
205
206 ++p;
207 }
208 // vertex colors
209 p = 0;
210 while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++);
211 return iRet;
212 }
213
214 // -------------------------------------------------------------------------------
ComputeVertexBoneWeightTable(const aiMesh * pMesh)215 VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh)
216 {
217 if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
218 return NULL;
219 }
220
221 VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
222 for (unsigned int i = 0; i < pMesh->mNumBones;++i) {
223
224 aiBone* bone = pMesh->mBones[i];
225 for (unsigned int a = 0; a < bone->mNumWeights;++a) {
226 const aiVertexWeight& weight = bone->mWeights[a];
227 avPerVertexWeights[weight.mVertexId].push_back( std::pair<unsigned int,float>(i,weight.mWeight) );
228 }
229 }
230 return avPerVertexWeights;
231 }
232
233
234 // -------------------------------------------------------------------------------
TextureTypeToString(aiTextureType in)235 const char* TextureTypeToString(aiTextureType in)
236 {
237 switch (in)
238 {
239 case aiTextureType_NONE:
240 return "n/a";
241 case aiTextureType_DIFFUSE:
242 return "Diffuse";
243 case aiTextureType_SPECULAR:
244 return "Specular";
245 case aiTextureType_AMBIENT:
246 return "Ambient";
247 case aiTextureType_EMISSIVE:
248 return "Emissive";
249 case aiTextureType_OPACITY:
250 return "Opacity";
251 case aiTextureType_NORMALS:
252 return "Normals";
253 case aiTextureType_HEIGHT:
254 return "Height";
255 case aiTextureType_SHININESS:
256 return "Shininess";
257 case aiTextureType_DISPLACEMENT:
258 return "Displacement";
259 case aiTextureType_LIGHTMAP:
260 return "Lightmap";
261 case aiTextureType_REFLECTION:
262 return "Reflection";
263 case aiTextureType_UNKNOWN:
264 return "Unknown";
265 default:
266 break;
267 }
268
269 ai_assert(false);
270 return "BUG";
271 }
272
273 // -------------------------------------------------------------------------------
MappingTypeToString(aiTextureMapping in)274 const char* MappingTypeToString(aiTextureMapping in)
275 {
276 switch (in)
277 {
278 case aiTextureMapping_UV:
279 return "UV";
280 case aiTextureMapping_BOX:
281 return "Box";
282 case aiTextureMapping_SPHERE:
283 return "Sphere";
284 case aiTextureMapping_CYLINDER:
285 return "Cylinder";
286 case aiTextureMapping_PLANE:
287 return "Plane";
288 case aiTextureMapping_OTHER:
289 return "Other";
290 default:
291 break;
292 }
293
294 ai_assert(false);
295 return "BUG";
296 }
297
298
299 // -------------------------------------------------------------------------------
MakeSubmesh(const aiMesh * pMesh,const std::vector<unsigned int> & subMeshFaces,unsigned int subFlags)300 aiMesh* MakeSubmesh(const aiMesh *pMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags)
301 {
302 aiMesh *oMesh = new aiMesh();
303 std::vector<unsigned int> vMap(pMesh->mNumVertices,UINT_MAX);
304
305 size_t numSubVerts = 0;
306 size_t numSubFaces = subMeshFaces.size();
307
308 for(unsigned int i=0;i<numSubFaces;i++) {
309 const aiFace &f = pMesh->mFaces[subMeshFaces[i]];
310
311 for(unsigned int j=0;j<f.mNumIndices;j++) {
312 if(vMap[f.mIndices[j]]==UINT_MAX) {
313 vMap[f.mIndices[j]] = static_cast<unsigned int>(numSubVerts++);
314 }
315 }
316 }
317
318 oMesh->mName = pMesh->mName;
319
320 oMesh->mMaterialIndex = pMesh->mMaterialIndex;
321 oMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
322
323 // create all the arrays for this mesh if the old mesh contained them
324
325 oMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
326 oMesh->mNumVertices = static_cast<unsigned int>(numSubVerts);
327 oMesh->mVertices = new aiVector3D[numSubVerts];
328 if( pMesh->HasNormals() ) {
329 oMesh->mNormals = new aiVector3D[numSubVerts];
330 }
331
332 if( pMesh->HasTangentsAndBitangents() ) {
333 oMesh->mTangents = new aiVector3D[numSubVerts];
334 oMesh->mBitangents = new aiVector3D[numSubVerts];
335 }
336
337 for( size_t a = 0; pMesh->HasTextureCoords(static_cast<unsigned int>(a)) ; ++a ) {
338 oMesh->mTextureCoords[a] = new aiVector3D[numSubVerts];
339 oMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
340 }
341
342 for( size_t a = 0; pMesh->HasVertexColors( static_cast<unsigned int>(a)); ++a ) {
343 oMesh->mColors[a] = new aiColor4D[numSubVerts];
344 }
345
346 // and copy over the data, generating faces with linear indices along the way
347 oMesh->mFaces = new aiFace[numSubFaces];
348
349 for(unsigned int a = 0; a < numSubFaces; ++a ) {
350
351 const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
352 aiFace& dstFace = oMesh->mFaces[a];
353 dstFace.mNumIndices = srcFace.mNumIndices;
354 dstFace.mIndices = new unsigned int[dstFace.mNumIndices];
355
356 // accumulate linearly all the vertices of the source face
357 for( size_t b = 0; b < dstFace.mNumIndices; ++b ) {
358 dstFace.mIndices[b] = vMap[srcFace.mIndices[b]];
359 }
360 }
361
362 for(unsigned int srcIndex = 0; srcIndex < pMesh->mNumVertices; ++srcIndex ) {
363 unsigned int nvi = vMap[srcIndex];
364 if(nvi==UINT_MAX) {
365 continue;
366 }
367
368 oMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
369 if( pMesh->HasNormals() ) {
370 oMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
371 }
372
373 if( pMesh->HasTangentsAndBitangents() ) {
374 oMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
375 oMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex];
376 }
377 for( size_t c = 0, cc = pMesh->GetNumUVChannels(); c < cc; ++c ) {
378 oMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
379 }
380 for( size_t c = 0, cc = pMesh->GetNumColorChannels(); c < cc; ++c ) {
381 oMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
382 }
383 }
384
385 if(~subFlags&AI_SUBMESH_FLAGS_SANS_BONES) {
386 std::vector<unsigned int> subBones(pMesh->mNumBones,0);
387
388 for(unsigned int a=0;a<pMesh->mNumBones;++a) {
389 const aiBone* bone = pMesh->mBones[a];
390
391 for(unsigned int b=0;b<bone->mNumWeights;b++) {
392 unsigned int v = vMap[bone->mWeights[b].mVertexId];
393
394 if(v!=UINT_MAX) {
395 subBones[a]++;
396 }
397 }
398 }
399
400 for(unsigned int a=0;a<pMesh->mNumBones;++a) {
401 if(subBones[a]>0) {
402 oMesh->mNumBones++;
403 }
404 }
405
406 if(oMesh->mNumBones) {
407 oMesh->mBones = new aiBone*[oMesh->mNumBones]();
408 unsigned int nbParanoia = oMesh->mNumBones;
409
410 oMesh->mNumBones = 0; //rewind
411
412 for(unsigned int a=0;a<pMesh->mNumBones;++a) {
413 if(subBones[a]==0) {
414 continue;
415 }
416 aiBone *newBone = new aiBone;
417 oMesh->mBones[oMesh->mNumBones++] = newBone;
418
419 const aiBone* bone = pMesh->mBones[a];
420
421 newBone->mName = bone->mName;
422 newBone->mOffsetMatrix = bone->mOffsetMatrix;
423 newBone->mWeights = new aiVertexWeight[subBones[a]];
424
425 for(unsigned int b=0;b<bone->mNumWeights;b++) {
426 const unsigned int v = vMap[bone->mWeights[b].mVertexId];
427
428 if(v!=UINT_MAX) {
429 aiVertexWeight w(v,bone->mWeights[b].mWeight);
430 newBone->mWeights[newBone->mNumWeights++] = w;
431 }
432 }
433 }
434
435 ai_assert(nbParanoia==oMesh->mNumBones);
436 (void)nbParanoia; // remove compiler warning on release build
437 }
438 }
439
440 return oMesh;
441 }
442
443 } // namespace Assimp
444