Parcourir la source

FEATURE: FindInvalidData step now provides a configuration option to fine-tune the accuracy of floating-point comparisons.
Ogre-Importer now compiles with -noboost.
Fixing GCC complaints about inproper 'address of temporary' in Ogre-Importer.


git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@480 67173fc5-114c-0410-ac8e-9d2fd5bffc1f

aramis_acg il y a 16 ans
Parent
commit
c89107a117

+ 108 - 66
code/FindInvalidDataProcess.cpp

@@ -73,32 +73,39 @@ bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const
 	return 0 != (pFlags & aiProcess_FindInvalidData);
 }
 
+// ------------------------------------------------------------------------------------------------
+// Setup import configuration
+void FindInvalidDataProcess::SetupProperties(const Importer* pImp)
+{
+	// Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
+	configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY,0.f));
+}
+
 // ------------------------------------------------------------------------------------------------
 // Update mesh references in the node graph
 void UpdateMeshReferences(aiNode* node, const std::vector<unsigned int>& meshMapping)
 {
-	if (node->mNumMeshes)
-	{
+	if (node->mNumMeshes)	{
 		unsigned int out = 0;
-		for (unsigned int a = 0; a < node->mNumMeshes;++a)
-		{
+		for (unsigned int a = 0; a < node->mNumMeshes;++a)	{
+
 			register unsigned int ref = node->mMeshes[a];
-			if (0xffffffff != (ref = meshMapping[ref]))
-			{
+			if (0xffffffff != (ref = meshMapping[ref]))	{
 				node->mMeshes[out++] = ref;
 			}
 		}
 		// just let the members that are unused, that's much cheaper
 		// than a full array realloc'n'copy party ...
-		if(!(node->mNumMeshes = out))
-		{
+		if(!(node->mNumMeshes = out))	{
+
 			delete[] node->mMeshes;
 			node->mMeshes = NULL;
 		}
 	}
 	// recursively update all children
-	for (unsigned int i = 0; i < node->mNumChildren;++i)
+	for (unsigned int i = 0; i < node->mNumChildren;++i) {
 		UpdateMeshReferences(node->mChildren[i],meshMapping);
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -112,14 +119,13 @@ void FindInvalidDataProcess::Execute( aiScene* pScene)
 	unsigned int real = 0;	
 
 	// Process meshes
-	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
-	{
+	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)	{
+
 		int result;
-		if ((result = ProcessMesh( pScene->mMeshes[a])))
-		{
+		if ((result = ProcessMesh( pScene->mMeshes[a])))	{
 			out = true;
-			if (2 == result)
-			{
+
+			if (2 == result)	{
 				// remove this mesh
 				delete pScene->mMeshes[a];
 				AI_DEBUG_INVALIDATE_PTR(pScene->mMeshes[a]);
@@ -133,17 +139,16 @@ void FindInvalidDataProcess::Execute( aiScene* pScene)
 	}
 
 	// Process animations
-	for (unsigned int a = 0; a < pScene->mNumAnimations;++a)
+	for (unsigned int a = 0; a < pScene->mNumAnimations;++a) {
 		ProcessAnimation( pScene->mAnimations[a]);
+	}
 
 
-	if (out)
-	{
-		if ( real != pScene->mNumMeshes)
-		{
-			if (!real)
+	if (out)	{
+		if ( real != pScene->mNumMeshes)	{
+			if (!real) {
 				throw new ImportErrorException("No meshes remaining");
-
+			}
 			
 			// we need to remove some meshes.
 			// therefore we'll also need to remove all references
@@ -172,24 +177,25 @@ inline const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsi
 {
 	bool b = false;
 	unsigned int cnt = 0;
-	for (unsigned int i = 0; i < size;++i)
-	{
-		if (dirtyMask.size() && dirtyMask[i])continue;
+	for (unsigned int i = 0; i < size;++i)	{
+
+		if (dirtyMask.size() && dirtyMask[i]) {
+			continue;
+		}
 		++cnt;
 
 		const aiVector3D& v = arr[i];
-		if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z))
-		{
+		if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z))	{
 			return "INF/NAN was found in a vector component";
 		}
-		if (!mayBeZero && !v.x && !v.y && !v.z )
-		{
+		if (!mayBeZero && !v.x && !v.y && !v.z )	{
 			return "Found zero-length vector";
 		}
 		if (i && v != arr[i-1])b = true;
 	}
-	if (cnt > 1 && !b && !mayBeIdentical)
+	if (cnt > 1 && !b && !mayBeIdentical) {
 		return "All vectors are identical";
+	}
 	return NULL;
 }
 
@@ -198,10 +204,8 @@ template <typename T>
 inline bool ProcessArray(T*& in, unsigned int num,const char* name,
 	const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true)
 {
-	const char* err = ValidateArrayContents(in,num,dirtyMask,
-		mayBeIdentical,mayBeZero);
-	if (err)
-	{
+	const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero);
+	if (err)	{
 		DefaultLogger::get()->error(std::string("FindInvalidDataProcess fails on mesh ") + name + ": " + err);
 		
 		delete[] in;
@@ -213,12 +217,55 @@ inline bool ProcessArray(T*& in, unsigned int num,const char* name,
 
 // ------------------------------------------------------------------------------------------------
 template <typename T>
-inline bool AllIdentical(T* in, unsigned int num)
+AI_FORCE_INLINE bool EpsilonCompare(const T& n, const T& s, float epsilon);
+
+// ------------------------------------------------------------------------------------------------
+AI_FORCE_INLINE bool EpsilonCompare(float n, float s, float epsilon) {
+	return fabs(n-s)>epsilon;
+}
+
+// ------------------------------------------------------------------------------------------------
+template <>
+bool EpsilonCompare<aiVectorKey>(const aiVectorKey& n, const aiVectorKey& s, float epsilon)	{
+	return 
+		EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) &&
+		EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) &&
+		EpsilonCompare(n.mValue.z,s.mValue.z,epsilon);
+}
+
+// ------------------------------------------------------------------------------------------------
+template <>
+bool EpsilonCompare<aiQuatKey>(const aiQuatKey& n, const aiQuatKey& s, float epsilon)	{
+	return 
+		EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) &&
+		EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) &&
+		EpsilonCompare(n.mValue.z,s.mValue.z,epsilon) &&
+		EpsilonCompare(n.mValue.w,s.mValue.w,epsilon);
+}
+
+// ------------------------------------------------------------------------------------------------
+template <typename T>
+inline bool AllIdentical(T* in, unsigned int num, float epsilon)
 {
-	if (num <= 1)return true;
-	for (unsigned int i = 0; i < num-1;++i)
-	{
-		if (in[i] != in[i+1])return false;
+	if (num <= 1) {
+		return true;
+	}
+
+	if (epsilon > 0.f) {
+		for (unsigned int i = 0; i < num-1;++i) {
+
+			if (!EpsilonCompare(in[i],in[i+1],epsilon)) {
+				return false;
+			}
+		}
+	}
+	else {
+		for (unsigned int i = 0; i < num-1;++i) {
+
+			if (in[i] != in[i+1]) {
+				return false;
+			}
+		}
 	}
 	return true;
 }
@@ -228,8 +275,9 @@ inline bool AllIdentical(T* in, unsigned int num)
 void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim)
 {
 	// Process all animation channels
-	for (unsigned int a = 0; a < anim->mNumChannels;++a)
+	for (unsigned int a = 0; a < anim->mNumChannels;++a) {
 		ProcessAnimationChannel( anim->mChannels[a]);
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -243,7 +291,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
 	// Check whether all values in a tracks are identical - in this case
 	// we can remove al keys except one.
 	// POSITIONS
-	if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys))
+	if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys,configEpsilon))
 	{
 		aiVectorKey v = anim->mPositionKeys[0];
 
@@ -255,7 +303,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
 	}
 
 	// ROTATIONS
-	if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys))
+	if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys,configEpsilon))
 	{
 		aiQuatKey v = anim->mRotationKeys[0];
 
@@ -267,7 +315,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
 	}
 
 	// SCALINGS
-	if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys))
+	if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys,configEpsilon))
 	{
 		aiVectorKey v = anim->mScalingKeys[0];
 
@@ -290,29 +338,26 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 
 	// Ignore elements that are not referenced by vertices.
 	// (they are, for example, caused by the FindDegenerates step)
-	for (unsigned int m = 0; m < pMesh->mNumFaces;++m)
-	{
+	for (unsigned int m = 0; m < pMesh->mNumFaces;++m)	{
 		const aiFace& f = pMesh->mFaces[m];
-		for (unsigned int i = 0; i < f.mNumIndices;++i)
+		
+		for (unsigned int i = 0; i < f.mNumIndices;++i) {
 			dirtyMask[f.mIndices[i]] = false;
+		}
 	}
 
 	// Process vertex positions
-	if(pMesh->mVertices && ProcessArray(pMesh->mVertices,pMesh->mNumVertices,"positions",dirtyMask))
-	{
+	if(pMesh->mVertices && ProcessArray(pMesh->mVertices,pMesh->mNumVertices,"positions",dirtyMask))	{
 		DefaultLogger::get()->error("Deleting mesh: Unable to continue without vertex positions");
 		return 2;
 	}
 
 	// process texture coordinates
-	for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
-	{
-		if (!pMesh->mTextureCoords[i])break;
-		if (ProcessArray(pMesh->mTextureCoords[i],pMesh->mNumVertices,"uvcoords",dirtyMask))
-		{
+	for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i];++i)	{
+		if (ProcessArray(pMesh->mTextureCoords[i],pMesh->mNumVertices,"uvcoords",dirtyMask))	{
+
 			// delete all subsequent texture coordinate sets.
-			for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a)
-			{
+			for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a)	{
 				delete[] pMesh->mTextureCoords[a]; pMesh->mTextureCoords[a] = NULL;
 			}
 			ret = true;
@@ -323,8 +368,8 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 	// they are invalid or not.
 
 	// Normals and tangents are undefined for point and line faces.
-	if (pMesh->mNormals || pMesh->mTangents)
-	{
+	if (pMesh->mNormals || pMesh->mTangents)	{
+
 		if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
 			aiPrimitiveType_LINE  & pMesh->mPrimitiveTypes)
 		{
@@ -336,11 +381,12 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 				{
 					const aiFace& f = pMesh->mFaces[m];
 
-					if (f.mNumIndices < 3) 
-					{
+					if (f.mNumIndices < 3)	{
 						dirtyMask[f.mIndices[0]] = true;
-						if (f.mNumIndices == 2) 
+
+						if (f.mNumIndices == 2) {
 							dirtyMask[f.mIndices[1]] = true;
+						}
 					}
 				}
 			}
@@ -355,17 +401,13 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 			ret = true;
 
 		// Process mesh tangents
-		if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,
-			"tangents",dirtyMask))
-		{
+		if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,"tangents",dirtyMask))	{
 			delete[] pMesh->mBitangents; pMesh->mBitangents = NULL;
 			ret = true;
 		}
 
 		// Process mesh bitangents
-		if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,
-			"bitangents",dirtyMask))
-		{
+		if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,"bitangents",dirtyMask))	{
 			delete[] pMesh->mTangents; pMesh->mTangents = NULL;
 			ret = true;
 		}

+ 16 - 17
code/FindInvalidDataProcess.h

@@ -48,18 +48,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiMesh;
 class FindInvalidDataProcessTest;
-
-namespace Assimp
-{
+namespace Assimp	{
 
 // ---------------------------------------------------------------------------
 /** The FindInvalidData postprocessing step. It searches the mesh data
  *  for parts that are obviously invalid and removes them.
  *
  *  Originally this was a workaround for some models written by Blender
- *  which have zero normal vectors.
- */
-class ASSIMP_API FindInvalidDataProcess : public BaseProcess
+ *  which have zero normal vectors. */
+class ASSIMP_API FindInvalidDataProcess 
+	: public BaseProcess
 {
 	friend class Importer;
 	friend class ::FindInvalidDataProcessTest;
@@ -75,13 +73,15 @@ protected:
 public:
 
 	// -------------------------------------------------------------------
-	/** 
-	*/
+	// 
 	bool IsActive( unsigned int pFlags) const;
 
 	// -------------------------------------------------------------------
-	/** 
-	*/
+	// Setup import settings
+	void SetupProperties(const Importer* pImp);
+
+	// -------------------------------------------------------------------
+	// Run the step
 	void Execute( aiScene* pScene);
 
 protected:
@@ -89,22 +89,21 @@ protected:
 	// -------------------------------------------------------------------
 	/** Executes the postprocessing step on the given mesh
 	 * @param pMesh The mesh to process.
-	 * @return 0 - nothing, 1 - removed sth, 2 - please delete me
-	 */
+	 * @return 0 - nothing, 1 - removed sth, 2 - please delete me  */
 	int ProcessMesh( aiMesh* pMesh);
 
-
 	// -------------------------------------------------------------------
 	/** Executes the postprocessing step on the given animation
-	 * @param anim The animation to process.
-	 */
+	 * @param anim The animation to process.  */
 	void ProcessAnimation (aiAnimation* anim);
 
 	// -------------------------------------------------------------------
 	/** Executes the postprocessing step on the given anim channel
-	 * @param anim The animation channel to process.
-	 */
+	 * @param anim The animation channel to process.*/
 	void ProcessAnimationChannel (aiNodeAnim* anim);
+
+private:
+	float configEpsilon;
 };
 
 } // end of namespace Assimp

+ 16 - 9
code/OgreImporter.cpp

@@ -6,8 +6,8 @@
 #include <sstream>
 using namespace std;
 
-#include "boost/format.hpp"
-#include "boost/foreach.hpp"
+//#include "boost/format.hpp"
+//#include "boost/foreach.hpp"
 using namespace boost;
 
 #include "OgreImporter.h"
@@ -340,7 +340,9 @@ void OgreImporter::ReadSubMesh(SubMesh &theSubMesh, XmlReader *Reader)
 aiMaterial* OgreImporter::LoadMaterial(std::string MaterialName)
 {
 	MaterialHelper *NewMaterial=new MaterialHelper();
-	NewMaterial->AddProperty(&aiString(MaterialName.c_str()), AI_MATKEY_NAME);
+
+	aiString ts(MaterialName.c_str());
+	NewMaterial->AddProperty(&ts, AI_MATKEY_NAME);
 	/*For bettetr understanding of the material parser, here is a material example file:
 
 	material Sarg
@@ -449,7 +451,8 @@ aiMaterial* OgreImporter::LoadMaterial(std::string MaterialName)
 											if(Line=="texture")
 											{
 												ss >> Line;
-												NewMaterial->AddProperty(&aiString(Line.c_str()), AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
+												aiString ts(Line.c_str());
+												NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
 											}
 										}//end of texture unit
 									}
@@ -478,12 +481,14 @@ aiMaterial* OgreImporter::LoadMaterial(std::string MaterialName)
 						if(Line=="$colormap")
 						{
 							ss >> Line;
-							NewMaterial->AddProperty(&aiString(Line.c_str()), AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
+							aiString ts(Line.c_str());
+							NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
 						}
 						if(Line=="$normalmap")
 						{
 							ss >> Line;
-							NewMaterial->AddProperty(&aiString(Line.c_str()), AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
+							aiString ts(Line.c_str());
+							NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
 						}
 					}					
 				}//end of material
@@ -569,7 +574,7 @@ void OgreImporter::LoadSkeleton(std::string FileName)
 		XmlRead(SkeletonFile);
 	}
 	//The bones in the file a not neccesarly ordered by there id's so we do it now:
-	sort(Bones.begin(), Bones.end());
+	std::sort(Bones.begin(), Bones.end());
 	//now the id of each bone should be equal to its position in the vector:
 	//so we do a simple check:
 	{
@@ -779,10 +784,12 @@ aiNode* CreateAiNodeFromBone(int BoneId, std::vector<Bone> Bones, aiNode* Parent
 	//----Create the node for this bone and set its values-----
 	aiNode* NewNode=new aiNode(Bones[BoneId].Name);
 	NewNode->mParent=ParentNode;
+
+	aiMatrix4x4 t0,t1;
 	//create a matrix from the transformation values of the ogre bone
-	NewNode->mTransformation=aiMatrix4x4::Translation(Bones[BoneId].Position, aiMatrix4x4())
+	NewNode->mTransformation=aiMatrix4x4::Translation(Bones[BoneId].Position, t0)
 							*
-							aiMatrix4x4::Rotation(Bones[BoneId].RotationAngle, Bones[BoneId].RotationAxis, aiMatrix4x4())
+							aiMatrix4x4::Rotation(Bones[BoneId].RotationAngle, Bones[BoneId].RotationAxis, t1)
 							;
 	//__________________________________________________________
 

+ 2 - 2
code/OgreImporter.h

@@ -146,10 +146,10 @@ struct Bone
 	///ctor
 	Bone(): Id(-1), ParentId(-1), RotationAngle(0.0f) {}
 	///this operator is needed to sort the bones after Id's
-	bool operator<(const Bone& rval)
+	bool operator<(const Bone& rval) const
 		{return Id<rval.Id; }
 	///this operator is needed to find a bone by its name in a vector<Bone>
-	bool operator==(const std::string& rval)
+	bool operator==(const std::string& rval) const
 		{return Name==rval; }
 	
 };

+ 34 - 33
include/aiConfig.h

@@ -197,7 +197,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * This is used by the "SplitLargeMeshes" PostProcess-Step to determine
  * whether a mesh must be split or not.
  * @note The default value is AI_SLM_DEFAULT_MAX_VERTICES
- * Property type: integer.
+ * Property type: integer. 
  */
 #define AI_CONFIG_PP_SLM_VERTEX_LIMIT \
 	"PP_SLM_VERTEX_LIMIT"
@@ -212,8 +212,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * This is used by the #aiProcess_LimitBoneWeights PostProcess-Step.
  * @note The default value is AI_LBW_MAX_WEIGHTS
- * Property type: integer.
- */
+ * Property type: integer.*/
 #define AI_CONFIG_PP_LBW_MAX_WEIGHTS	\
 	"PP_LBW_MAX_WEIGHTS"
 
@@ -243,71 +242,59 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // ---------------------------------------------------------------------------
 /** @brief Enumerates components of the aiScene and aiMesh data structures
- *  that can be excluded from the import by using the RemoveComponent step.
+ *  that can be excluded from the import using the #aiPrpcess_RemoveComponent step.
  *
  *  See the documentation to #aiProcess_RemoveComponent for more details.
  */
 enum aiComponent
 {
-	/** Normal vectors
-	 */
+	/** Normal vectors */
 	aiComponent_NORMALS = 0x2u,
 
-	/** Tangents and bitangents go always together ...
-	 */
+	/** Tangents and bitangents go always together ... */
 	aiComponent_TANGENTS_AND_BITANGENTS = 0x4u,
 
 	/** ALL color sets
-	 * Use aiComponent_COLORn(N) to specify the N'th set 
-	 */
+	 * Use aiComponent_COLORn(N) to specify the N'th set */
 	aiComponent_COLORS = 0x8,
 
 	/** ALL texture UV sets
-	 * aiComponent_TEXCOORDn(N) to specify the N'th set 
-	 */
+	 * aiComponent_TEXCOORDn(N) to specify the N'th set  */
 	aiComponent_TEXCOORDS = 0x10,
 
 	/** Removes all bone weights from all meshes.
 	 * The scenegraph nodes corresponding to the bones are NOT removed.
-	 * use the #aiProcess_OptimizeGraph step to do this
-	 */
+	 * use the #aiProcess_OptimizeGraph step to do this */
 	aiComponent_BONEWEIGHTS = 0x20,
 
 	/** Removes all node animations (aiScene::mAnimations).
 	 * The corresponding scenegraph nodes are NOT removed.
-	 * use the #aiProcess_OptimizeGraph step to do this
-	 */
+	 * use the #aiProcess_OptimizeGraph step to do this */
 	aiComponent_ANIMATIONS = 0x40,
 
-	/** Removes all embedded textures (aiScene::mTextures)
-	 */
+	/** Removes all embedded textures (aiScene::mTextures) */
 	aiComponent_TEXTURES = 0x80,
 
 	/** Removes all light sources (aiScene::mLights).
 	 * The corresponding scenegraph nodes are NOT removed.
-	 * use the #aiProcess_OptimizeGraph step to do this
-	 */
+	 * use the #aiProcess_OptimizeGraph step to do this */
 	aiComponent_LIGHTS = 0x100,
 
 	/** Removes all light sources (aiScene::mCameras).
 	 * The corresponding scenegraph nodes are NOT removed.
-	 * use the #aiProcess_OptimizeGraph step to do this
-	 */
+	 * use the #aiProcess_OptimizeGraph step to do this */
 	aiComponent_CAMERAS = 0x200,
 
-	/** Removes all meshes (aiScene::mMeshes). 
-	 */
+	/** Removes all meshes (aiScene::mMeshes). */
 	aiComponent_MESHES = 0x400,
 
 	/** Removes all materials. One default material will
-	 * be generated, so aiScene::mNumMaterials will be 1.
-	 */
+	 * be generated, so aiScene::mNumMaterials will be 1. */
 	aiComponent_MATERIALS = 0x800,
 
 
 	/** This value is not used. It is just there to force the
-	 *  compiler to map this enum to a 32 Bit integer.
-	 */
+	 *  compiler to map this enum to a 32 Bit integer. */
 	_aiComponent_Force32Bit = 0x9fffffff
 };
 
@@ -344,6 +331,18 @@ enum aiComponent
 #define AI_CONFIG_PP_SBP_REMOVE				\
 	"PP_SBP_REMOVE"
 
+// ---------------------------------------------------------------------------
+/** @brief Input parameter to the #aiProcess_FindInvalidData step:
+ *  Specifies the floating-point accuracy for animation values. The step
+ *  checks for animation tracks where all frame values are absolutely equal
+ *  and removes them. This tweakable controls the epsilon for floating-point
+ *  comparisons - two keys are considered equal if the invariant 
+ *  abs(n0-n1)>epsilon holds true for all vector respectively quaternion
+ *  components. The default value is 0.f - comparisons are exact then.
+ */
+#define AI_CONFIG_PP_FID_ANIM_ACCURACY				\
+	"PP_FID_ANIM_ACCURACY"
+
 
 // TransformUVCoords evaluates UV scalings
 #define AI_UVTRAFO_SCALING 0x1
@@ -552,11 +551,13 @@ enum aiComponent
 #define AI_CONFIG_IMPORT_IRR_ANIM_FPS				\
 	"IMPORT_IRR_ANIM_FPS"
 
-/// Ogre Importer will try to load this Materialfile
-/**
-Ogre Mehs contain only the MaterialName, not the MaterialFile. If there is no material file
-with the same name as the material, Ogre Importer will try to load this file and search the material in it.
-*/
+
+// ---------------------------------------------------------------------------
+/** Ogre Importer will try to load this Materialfile
+ * Ogre Mehs contain only the MaterialName, not the MaterialFile. If there 
+ * is no material file with the same name as the material, Ogre Importer will 
+ * try to load this file and search the material in it.
+ */
 #define AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE "IMPORT_OGRE_MATERIAL_FILE"
 
 

+ 7 - 3
include/aiPostProcess.h

@@ -358,12 +358,16 @@ enum aiPostProcessSteps
 
 	// -------------------------------------------------------------------------
 	/** <hr>This step searches all meshes for invalid data, such as zeroed
-	 *  normal vectors or invalid UV coords and removes them.
+	 *  normal vectors or invalid UV coords and removes/fixes them. This is
+	 *  intended to get rid of some common exporter errors.
 	 *
 	 * This is especially useful for normals. If they are invalid, and
 	 * the step recognizes this, they will be removed and can later
-	 * be computed by one of the other steps.<br>
-	 * The step will also remove meshes that are infinitely small.
+	 * be recomputed, i.e. by the #aiProcess_GenSmoothNormals flag.<br>
+	 * The step will also remove meshes that are infinitely small and reduce
+	 * animation tracks consisting of hundreds if redundant keys to a single
+	 * key. The <tt>AI_CONFIG_PP_FID_ANIM_ACCURACY</tt> config property decides
+	 * the accuracy of the check for duplicate animation tracks.
 	*/
 	aiProcess_FindInvalidData = 0x20000,