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