vrshoot

view libs/assimp/FindInvalidDataProcess.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
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.
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.
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 */
42 /** @file Defines a post processing step to search an importer's output
43 for data that is obviously invalid */
45 #include "AssimpPCH.h"
47 #ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS
49 // internal headers
50 #include "FindInvalidDataProcess.h"
51 #include "ProcessHelper.h"
53 using namespace Assimp;
55 // ------------------------------------------------------------------------------------------------
56 // Constructor to be privately used by Importer
57 FindInvalidDataProcess::FindInvalidDataProcess()
58 {
59 // nothing to do here
60 }
62 // ------------------------------------------------------------------------------------------------
63 // Destructor, private as well
64 FindInvalidDataProcess::~FindInvalidDataProcess()
65 {
66 // nothing to do here
67 }
69 // ------------------------------------------------------------------------------------------------
70 // Returns whether the processing step is present in the given flag field.
71 bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const
72 {
73 return 0 != (pFlags & aiProcess_FindInvalidData);
74 }
76 // ------------------------------------------------------------------------------------------------
77 // Setup import configuration
78 void FindInvalidDataProcess::SetupProperties(const Importer* pImp)
79 {
80 // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
81 configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY,0.f));
82 }
84 // ------------------------------------------------------------------------------------------------
85 // Update mesh references in the node graph
86 void UpdateMeshReferences(aiNode* node, const std::vector<unsigned int>& meshMapping)
87 {
88 if (node->mNumMeshes) {
89 unsigned int out = 0;
90 for (unsigned int a = 0; a < node->mNumMeshes;++a) {
92 register unsigned int ref = node->mMeshes[a];
93 if (UINT_MAX != (ref = meshMapping[ref])) {
94 node->mMeshes[out++] = ref;
95 }
96 }
97 // just let the members that are unused, that's much cheaper
98 // than a full array realloc'n'copy party ...
99 if(!(node->mNumMeshes = out)) {
101 delete[] node->mMeshes;
102 node->mMeshes = NULL;
103 }
104 }
105 // recursively update all children
106 for (unsigned int i = 0; i < node->mNumChildren;++i) {
107 UpdateMeshReferences(node->mChildren[i],meshMapping);
108 }
109 }
111 // ------------------------------------------------------------------------------------------------
112 // Executes the post processing step on the given imported data.
113 void FindInvalidDataProcess::Execute( aiScene* pScene)
114 {
115 DefaultLogger::get()->debug("FindInvalidDataProcess begin");
117 bool out = false;
118 std::vector<unsigned int> meshMapping(pScene->mNumMeshes);
119 unsigned int real = 0;
121 // Process meshes
122 for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
124 int result;
125 if ((result = ProcessMesh( pScene->mMeshes[a]))) {
126 out = true;
128 if (2 == result) {
129 // remove this mesh
130 delete pScene->mMeshes[a];
131 AI_DEBUG_INVALIDATE_PTR(pScene->mMeshes[a]);
133 meshMapping[a] = UINT_MAX;
134 continue;
135 }
136 }
137 pScene->mMeshes[real] = pScene->mMeshes[a];
138 meshMapping[a] = real++;
139 }
141 // Process animations
142 for (unsigned int a = 0; a < pScene->mNumAnimations;++a) {
143 ProcessAnimation( pScene->mAnimations[a]);
144 }
147 if (out) {
148 if ( real != pScene->mNumMeshes) {
149 if (!real) {
150 throw DeadlyImportError("No meshes remaining");
151 }
153 // we need to remove some meshes.
154 // therefore we'll also need to remove all references
155 // to them from the scenegraph
156 UpdateMeshReferences(pScene->mRootNode,meshMapping);
157 pScene->mNumMeshes = real;
158 }
160 DefaultLogger::get()->info("FindInvalidDataProcess finished. Found issues ...");
161 }
162 else DefaultLogger::get()->debug("FindInvalidDataProcess finished. Everything seems to be OK.");
163 }
165 // ------------------------------------------------------------------------------------------------
166 template <typename T>
167 inline const char* ValidateArrayContents(const T* arr, unsigned int size,
168 const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true)
169 {
170 return NULL;
171 }
173 // ------------------------------------------------------------------------------------------------
174 template <>
175 inline const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsigned int size,
176 const std::vector<bool>& dirtyMask, bool mayBeIdentical , bool mayBeZero )
177 {
178 bool b = false;
179 unsigned int cnt = 0;
180 for (unsigned int i = 0; i < size;++i) {
182 if (dirtyMask.size() && dirtyMask[i]) {
183 continue;
184 }
185 ++cnt;
187 const aiVector3D& v = arr[i];
188 if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
189 return "INF/NAN was found in a vector component";
190 }
191 if (!mayBeZero && !v.x && !v.y && !v.z ) {
192 return "Found zero-length vector";
193 }
194 if (i && v != arr[i-1])b = true;
195 }
196 if (cnt > 1 && !b && !mayBeIdentical) {
197 return "All vectors are identical";
198 }
199 return NULL;
200 }
202 // ------------------------------------------------------------------------------------------------
203 template <typename T>
204 inline bool ProcessArray(T*& in, unsigned int num,const char* name,
205 const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true)
206 {
207 const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero);
208 if (err) {
209 DefaultLogger::get()->error(std::string("FindInvalidDataProcess fails on mesh ") + name + ": " + err);
211 delete[] in;
212 in = NULL;
213 return true;
214 }
215 return false;
216 }
218 // ------------------------------------------------------------------------------------------------
219 template <typename T>
220 AI_FORCE_INLINE bool EpsilonCompare(const T& n, const T& s, float epsilon);
222 // ------------------------------------------------------------------------------------------------
223 AI_FORCE_INLINE bool EpsilonCompare(float n, float s, float epsilon) {
224 return fabs(n-s)>epsilon;
225 }
227 // ------------------------------------------------------------------------------------------------
228 template <>
229 bool EpsilonCompare<aiVectorKey>(const aiVectorKey& n, const aiVectorKey& s, float epsilon) {
230 return
231 EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) &&
232 EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) &&
233 EpsilonCompare(n.mValue.z,s.mValue.z,epsilon);
234 }
236 // ------------------------------------------------------------------------------------------------
237 template <>
238 bool EpsilonCompare<aiQuatKey>(const aiQuatKey& n, const aiQuatKey& s, float epsilon) {
239 return
240 EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) &&
241 EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) &&
242 EpsilonCompare(n.mValue.z,s.mValue.z,epsilon) &&
243 EpsilonCompare(n.mValue.w,s.mValue.w,epsilon);
244 }
246 // ------------------------------------------------------------------------------------------------
247 template <typename T>
248 inline bool AllIdentical(T* in, unsigned int num, float epsilon)
249 {
250 if (num <= 1) {
251 return true;
252 }
254 if (epsilon > 0.f) {
255 for (unsigned int i = 0; i < num-1;++i) {
257 if (!EpsilonCompare(in[i],in[i+1],epsilon)) {
258 return false;
259 }
260 }
261 }
262 else {
263 for (unsigned int i = 0; i < num-1;++i) {
265 if (in[i] != in[i+1]) {
266 return false;
267 }
268 }
269 }
270 return true;
271 }
273 // ------------------------------------------------------------------------------------------------
274 // Search an animation for invalid content
275 void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim)
276 {
277 // Process all animation channels
278 for (unsigned int a = 0; a < anim->mNumChannels;++a) {
279 ProcessAnimationChannel( anim->mChannels[a]);
280 }
281 }
283 // ------------------------------------------------------------------------------------------------
284 void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
285 {
286 int i = 0;
288 // ScenePreprocessor's work ...
289 ai_assert((0 != anim->mPositionKeys && 0 != anim->mRotationKeys && 0 != anim->mScalingKeys));
291 // Check whether all values in a tracks are identical - in this case
292 // we can remove al keys except one.
293 // POSITIONS
294 if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys,configEpsilon))
295 {
296 aiVectorKey v = anim->mPositionKeys[0];
298 // Reallocate ... we need just ONE element, it makes no sense to reuse the array
299 delete[] anim->mPositionKeys;
300 anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = 1];
301 anim->mPositionKeys[0] = v;
302 i = 1;
303 }
305 // ROTATIONS
306 if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys,configEpsilon))
307 {
308 aiQuatKey v = anim->mRotationKeys[0];
310 // Reallocate ... we need just ONE element, it makes no sense to reuse the array
311 delete[] anim->mRotationKeys;
312 anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = 1];
313 anim->mRotationKeys[0] = v;
314 i = 1;
315 }
317 // SCALINGS
318 if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys,configEpsilon))
319 {
320 aiVectorKey v = anim->mScalingKeys[0];
322 // Reallocate ... we need just ONE element, it makes no sense to reuse the array
323 delete[] anim->mScalingKeys;
324 anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = 1];
325 anim->mScalingKeys[0] = v;
326 i = 1;
327 }
328 if (1 == i)
329 DefaultLogger::get()->warn("Simplified dummy tracks with just one key");
330 }
332 // ------------------------------------------------------------------------------------------------
333 // Search a mesh for invalid contents
334 int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
335 {
336 bool ret = false;
337 std::vector<bool> dirtyMask(pMesh->mNumVertices,(pMesh->mNumFaces ? true : false));
339 // Ignore elements that are not referenced by vertices.
340 // (they are, for example, caused by the FindDegenerates step)
341 for (unsigned int m = 0; m < pMesh->mNumFaces;++m) {
342 const aiFace& f = pMesh->mFaces[m];
344 for (unsigned int i = 0; i < f.mNumIndices;++i) {
345 dirtyMask[f.mIndices[i]] = false;
346 }
347 }
349 // Process vertex positions
350 if(pMesh->mVertices && ProcessArray(pMesh->mVertices,pMesh->mNumVertices,"positions",dirtyMask)) {
351 DefaultLogger::get()->error("Deleting mesh: Unable to continue without vertex positions");
352 return 2;
353 }
355 // process texture coordinates
356 for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i];++i) {
357 if (ProcessArray(pMesh->mTextureCoords[i],pMesh->mNumVertices,"uvcoords",dirtyMask)) {
359 // delete all subsequent texture coordinate sets.
360 for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
361 delete[] pMesh->mTextureCoords[a]; pMesh->mTextureCoords[a] = NULL;
362 }
363 ret = true;
364 }
365 }
367 // -- we don't validate vertex colors, it's difficult to say whether
368 // they are invalid or not.
370 // Normals and tangents are undefined for point and line faces.
371 if (pMesh->mNormals || pMesh->mTangents) {
373 if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
374 aiPrimitiveType_LINE & pMesh->mPrimitiveTypes)
375 {
376 if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
377 aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes)
378 {
379 // We need to update the lookup-table
380 for (unsigned int m = 0; m < pMesh->mNumFaces;++m)
381 {
382 const aiFace& f = pMesh->mFaces[m];
384 if (f.mNumIndices < 3) {
385 dirtyMask[f.mIndices[0]] = true;
387 if (f.mNumIndices == 2) {
388 dirtyMask[f.mIndices[1]] = true;
389 }
390 }
391 }
392 }
393 // Normals, tangents and bitangents are undefined for
394 // the whole mesh (and should not even be there)
395 else return ret;
396 }
398 // Process mesh normals
399 if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices,
400 "normals",dirtyMask,true,false))
401 ret = true;
403 // Process mesh tangents
404 if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,"tangents",dirtyMask)) {
405 delete[] pMesh->mBitangents; pMesh->mBitangents = NULL;
406 ret = true;
407 }
409 // Process mesh bitangents
410 if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,"bitangents",dirtyMask)) {
411 delete[] pMesh->mTangents; pMesh->mTangents = NULL;
412 ret = true;
413 }
414 }
415 return ret ? 1 : 0;
416 }
419 #endif // !! ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS