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