vrshoot
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/FindInvalidDataProcess.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,419 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file Defines a post processing step to search an importer's output 1.46 + for data that is obviously invalid */ 1.47 + 1.48 +#include "AssimpPCH.h" 1.49 + 1.50 +#ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS 1.51 + 1.52 +// internal headers 1.53 +#include "FindInvalidDataProcess.h" 1.54 +#include "ProcessHelper.h" 1.55 + 1.56 +using namespace Assimp; 1.57 + 1.58 +// ------------------------------------------------------------------------------------------------ 1.59 +// Constructor to be privately used by Importer 1.60 +FindInvalidDataProcess::FindInvalidDataProcess() 1.61 +{ 1.62 + // nothing to do here 1.63 +} 1.64 + 1.65 +// ------------------------------------------------------------------------------------------------ 1.66 +// Destructor, private as well 1.67 +FindInvalidDataProcess::~FindInvalidDataProcess() 1.68 +{ 1.69 + // nothing to do here 1.70 +} 1.71 + 1.72 +// ------------------------------------------------------------------------------------------------ 1.73 +// Returns whether the processing step is present in the given flag field. 1.74 +bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const 1.75 +{ 1.76 + return 0 != (pFlags & aiProcess_FindInvalidData); 1.77 +} 1.78 + 1.79 +// ------------------------------------------------------------------------------------------------ 1.80 +// Setup import configuration 1.81 +void FindInvalidDataProcess::SetupProperties(const Importer* pImp) 1.82 +{ 1.83 + // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY 1.84 + configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY,0.f)); 1.85 +} 1.86 + 1.87 +// ------------------------------------------------------------------------------------------------ 1.88 +// Update mesh references in the node graph 1.89 +void UpdateMeshReferences(aiNode* node, const std::vector<unsigned int>& meshMapping) 1.90 +{ 1.91 + if (node->mNumMeshes) { 1.92 + unsigned int out = 0; 1.93 + for (unsigned int a = 0; a < node->mNumMeshes;++a) { 1.94 + 1.95 + register unsigned int ref = node->mMeshes[a]; 1.96 + if (UINT_MAX != (ref = meshMapping[ref])) { 1.97 + node->mMeshes[out++] = ref; 1.98 + } 1.99 + } 1.100 + // just let the members that are unused, that's much cheaper 1.101 + // than a full array realloc'n'copy party ... 1.102 + if(!(node->mNumMeshes = out)) { 1.103 + 1.104 + delete[] node->mMeshes; 1.105 + node->mMeshes = NULL; 1.106 + } 1.107 + } 1.108 + // recursively update all children 1.109 + for (unsigned int i = 0; i < node->mNumChildren;++i) { 1.110 + UpdateMeshReferences(node->mChildren[i],meshMapping); 1.111 + } 1.112 +} 1.113 + 1.114 +// ------------------------------------------------------------------------------------------------ 1.115 +// Executes the post processing step on the given imported data. 1.116 +void FindInvalidDataProcess::Execute( aiScene* pScene) 1.117 +{ 1.118 + DefaultLogger::get()->debug("FindInvalidDataProcess begin"); 1.119 + 1.120 + bool out = false; 1.121 + std::vector<unsigned int> meshMapping(pScene->mNumMeshes); 1.122 + unsigned int real = 0; 1.123 + 1.124 + // Process meshes 1.125 + for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { 1.126 + 1.127 + int result; 1.128 + if ((result = ProcessMesh( pScene->mMeshes[a]))) { 1.129 + out = true; 1.130 + 1.131 + if (2 == result) { 1.132 + // remove this mesh 1.133 + delete pScene->mMeshes[a]; 1.134 + AI_DEBUG_INVALIDATE_PTR(pScene->mMeshes[a]); 1.135 + 1.136 + meshMapping[a] = UINT_MAX; 1.137 + continue; 1.138 + } 1.139 + } 1.140 + pScene->mMeshes[real] = pScene->mMeshes[a]; 1.141 + meshMapping[a] = real++; 1.142 + } 1.143 + 1.144 + // Process animations 1.145 + for (unsigned int a = 0; a < pScene->mNumAnimations;++a) { 1.146 + ProcessAnimation( pScene->mAnimations[a]); 1.147 + } 1.148 + 1.149 + 1.150 + if (out) { 1.151 + if ( real != pScene->mNumMeshes) { 1.152 + if (!real) { 1.153 + throw DeadlyImportError("No meshes remaining"); 1.154 + } 1.155 + 1.156 + // we need to remove some meshes. 1.157 + // therefore we'll also need to remove all references 1.158 + // to them from the scenegraph 1.159 + UpdateMeshReferences(pScene->mRootNode,meshMapping); 1.160 + pScene->mNumMeshes = real; 1.161 + } 1.162 + 1.163 + DefaultLogger::get()->info("FindInvalidDataProcess finished. Found issues ..."); 1.164 + } 1.165 + else DefaultLogger::get()->debug("FindInvalidDataProcess finished. Everything seems to be OK."); 1.166 +} 1.167 + 1.168 +// ------------------------------------------------------------------------------------------------ 1.169 +template <typename T> 1.170 +inline const char* ValidateArrayContents(const T* arr, unsigned int size, 1.171 + const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) 1.172 +{ 1.173 + return NULL; 1.174 +} 1.175 + 1.176 +// ------------------------------------------------------------------------------------------------ 1.177 +template <> 1.178 +inline const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsigned int size, 1.179 + const std::vector<bool>& dirtyMask, bool mayBeIdentical , bool mayBeZero ) 1.180 +{ 1.181 + bool b = false; 1.182 + unsigned int cnt = 0; 1.183 + for (unsigned int i = 0; i < size;++i) { 1.184 + 1.185 + if (dirtyMask.size() && dirtyMask[i]) { 1.186 + continue; 1.187 + } 1.188 + ++cnt; 1.189 + 1.190 + const aiVector3D& v = arr[i]; 1.191 + if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) { 1.192 + return "INF/NAN was found in a vector component"; 1.193 + } 1.194 + if (!mayBeZero && !v.x && !v.y && !v.z ) { 1.195 + return "Found zero-length vector"; 1.196 + } 1.197 + if (i && v != arr[i-1])b = true; 1.198 + } 1.199 + if (cnt > 1 && !b && !mayBeIdentical) { 1.200 + return "All vectors are identical"; 1.201 + } 1.202 + return NULL; 1.203 +} 1.204 + 1.205 +// ------------------------------------------------------------------------------------------------ 1.206 +template <typename T> 1.207 +inline bool ProcessArray(T*& in, unsigned int num,const char* name, 1.208 + const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) 1.209 +{ 1.210 + const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero); 1.211 + if (err) { 1.212 + DefaultLogger::get()->error(std::string("FindInvalidDataProcess fails on mesh ") + name + ": " + err); 1.213 + 1.214 + delete[] in; 1.215 + in = NULL; 1.216 + return true; 1.217 + } 1.218 + return false; 1.219 +} 1.220 + 1.221 +// ------------------------------------------------------------------------------------------------ 1.222 +template <typename T> 1.223 +AI_FORCE_INLINE bool EpsilonCompare(const T& n, const T& s, float epsilon); 1.224 + 1.225 +// ------------------------------------------------------------------------------------------------ 1.226 +AI_FORCE_INLINE bool EpsilonCompare(float n, float s, float epsilon) { 1.227 + return fabs(n-s)>epsilon; 1.228 +} 1.229 + 1.230 +// ------------------------------------------------------------------------------------------------ 1.231 +template <> 1.232 +bool EpsilonCompare<aiVectorKey>(const aiVectorKey& n, const aiVectorKey& s, float epsilon) { 1.233 + return 1.234 + EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) && 1.235 + EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) && 1.236 + EpsilonCompare(n.mValue.z,s.mValue.z,epsilon); 1.237 +} 1.238 + 1.239 +// ------------------------------------------------------------------------------------------------ 1.240 +template <> 1.241 +bool EpsilonCompare<aiQuatKey>(const aiQuatKey& n, const aiQuatKey& s, float epsilon) { 1.242 + return 1.243 + EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) && 1.244 + EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) && 1.245 + EpsilonCompare(n.mValue.z,s.mValue.z,epsilon) && 1.246 + EpsilonCompare(n.mValue.w,s.mValue.w,epsilon); 1.247 +} 1.248 + 1.249 +// ------------------------------------------------------------------------------------------------ 1.250 +template <typename T> 1.251 +inline bool AllIdentical(T* in, unsigned int num, float epsilon) 1.252 +{ 1.253 + if (num <= 1) { 1.254 + return true; 1.255 + } 1.256 + 1.257 + if (epsilon > 0.f) { 1.258 + for (unsigned int i = 0; i < num-1;++i) { 1.259 + 1.260 + if (!EpsilonCompare(in[i],in[i+1],epsilon)) { 1.261 + return false; 1.262 + } 1.263 + } 1.264 + } 1.265 + else { 1.266 + for (unsigned int i = 0; i < num-1;++i) { 1.267 + 1.268 + if (in[i] != in[i+1]) { 1.269 + return false; 1.270 + } 1.271 + } 1.272 + } 1.273 + return true; 1.274 +} 1.275 + 1.276 +// ------------------------------------------------------------------------------------------------ 1.277 +// Search an animation for invalid content 1.278 +void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim) 1.279 +{ 1.280 + // Process all animation channels 1.281 + for (unsigned int a = 0; a < anim->mNumChannels;++a) { 1.282 + ProcessAnimationChannel( anim->mChannels[a]); 1.283 + } 1.284 +} 1.285 + 1.286 +// ------------------------------------------------------------------------------------------------ 1.287 +void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) 1.288 +{ 1.289 + int i = 0; 1.290 + 1.291 + // ScenePreprocessor's work ... 1.292 + ai_assert((0 != anim->mPositionKeys && 0 != anim->mRotationKeys && 0 != anim->mScalingKeys)); 1.293 + 1.294 + // Check whether all values in a tracks are identical - in this case 1.295 + // we can remove al keys except one. 1.296 + // POSITIONS 1.297 + if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys,configEpsilon)) 1.298 + { 1.299 + aiVectorKey v = anim->mPositionKeys[0]; 1.300 + 1.301 + // Reallocate ... we need just ONE element, it makes no sense to reuse the array 1.302 + delete[] anim->mPositionKeys; 1.303 + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = 1]; 1.304 + anim->mPositionKeys[0] = v; 1.305 + i = 1; 1.306 + } 1.307 + 1.308 + // ROTATIONS 1.309 + if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys,configEpsilon)) 1.310 + { 1.311 + aiQuatKey v = anim->mRotationKeys[0]; 1.312 + 1.313 + // Reallocate ... we need just ONE element, it makes no sense to reuse the array 1.314 + delete[] anim->mRotationKeys; 1.315 + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = 1]; 1.316 + anim->mRotationKeys[0] = v; 1.317 + i = 1; 1.318 + } 1.319 + 1.320 + // SCALINGS 1.321 + if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys,configEpsilon)) 1.322 + { 1.323 + aiVectorKey v = anim->mScalingKeys[0]; 1.324 + 1.325 + // Reallocate ... we need just ONE element, it makes no sense to reuse the array 1.326 + delete[] anim->mScalingKeys; 1.327 + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = 1]; 1.328 + anim->mScalingKeys[0] = v; 1.329 + i = 1; 1.330 + } 1.331 + if (1 == i) 1.332 + DefaultLogger::get()->warn("Simplified dummy tracks with just one key"); 1.333 +} 1.334 + 1.335 +// ------------------------------------------------------------------------------------------------ 1.336 +// Search a mesh for invalid contents 1.337 +int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) 1.338 +{ 1.339 + bool ret = false; 1.340 + std::vector<bool> dirtyMask(pMesh->mNumVertices,(pMesh->mNumFaces ? true : false)); 1.341 + 1.342 + // Ignore elements that are not referenced by vertices. 1.343 + // (they are, for example, caused by the FindDegenerates step) 1.344 + for (unsigned int m = 0; m < pMesh->mNumFaces;++m) { 1.345 + const aiFace& f = pMesh->mFaces[m]; 1.346 + 1.347 + for (unsigned int i = 0; i < f.mNumIndices;++i) { 1.348 + dirtyMask[f.mIndices[i]] = false; 1.349 + } 1.350 + } 1.351 + 1.352 + // Process vertex positions 1.353 + if(pMesh->mVertices && ProcessArray(pMesh->mVertices,pMesh->mNumVertices,"positions",dirtyMask)) { 1.354 + DefaultLogger::get()->error("Deleting mesh: Unable to continue without vertex positions"); 1.355 + return 2; 1.356 + } 1.357 + 1.358 + // process texture coordinates 1.359 + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i];++i) { 1.360 + if (ProcessArray(pMesh->mTextureCoords[i],pMesh->mNumVertices,"uvcoords",dirtyMask)) { 1.361 + 1.362 + // delete all subsequent texture coordinate sets. 1.363 + for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { 1.364 + delete[] pMesh->mTextureCoords[a]; pMesh->mTextureCoords[a] = NULL; 1.365 + } 1.366 + ret = true; 1.367 + } 1.368 + } 1.369 + 1.370 + // -- we don't validate vertex colors, it's difficult to say whether 1.371 + // they are invalid or not. 1.372 + 1.373 + // Normals and tangents are undefined for point and line faces. 1.374 + if (pMesh->mNormals || pMesh->mTangents) { 1.375 + 1.376 + if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes || 1.377 + aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) 1.378 + { 1.379 + if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes || 1.380 + aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) 1.381 + { 1.382 + // We need to update the lookup-table 1.383 + for (unsigned int m = 0; m < pMesh->mNumFaces;++m) 1.384 + { 1.385 + const aiFace& f = pMesh->mFaces[m]; 1.386 + 1.387 + if (f.mNumIndices < 3) { 1.388 + dirtyMask[f.mIndices[0]] = true; 1.389 + 1.390 + if (f.mNumIndices == 2) { 1.391 + dirtyMask[f.mIndices[1]] = true; 1.392 + } 1.393 + } 1.394 + } 1.395 + } 1.396 + // Normals, tangents and bitangents are undefined for 1.397 + // the whole mesh (and should not even be there) 1.398 + else return ret; 1.399 + } 1.400 + 1.401 + // Process mesh normals 1.402 + if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices, 1.403 + "normals",dirtyMask,true,false)) 1.404 + ret = true; 1.405 + 1.406 + // Process mesh tangents 1.407 + if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,"tangents",dirtyMask)) { 1.408 + delete[] pMesh->mBitangents; pMesh->mBitangents = NULL; 1.409 + ret = true; 1.410 + } 1.411 + 1.412 + // Process mesh bitangents 1.413 + if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,"bitangents",dirtyMask)) { 1.414 + delete[] pMesh->mTangents; pMesh->mTangents = NULL; 1.415 + ret = true; 1.416 + } 1.417 + } 1.418 + return ret ? 1 : 0; 1.419 +} 1.420 + 1.421 + 1.422 +#endif // !! ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS