Browse Source

Integrating aiProcess_OptimizeGraph and aiProcess_OptimizeMeshes back into the Assimp core. They're stable enough now.
Moving private members of Assimp::Importer to a pimpl, hopefully solving strange crashes with vc9 debug builds.
Updating assimp_cmd to reflect these changes.

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

aramis_acg 16 years ago
parent
commit
9abcba4bc2

+ 6 - 6
code/Assimp.cpp

@@ -67,9 +67,9 @@ static ImporterMap gActiveImports;
 static std::string gLastErrorString;
 static std::string gLastErrorString;
 
 
 /** Configuration properties */
 /** Configuration properties */
-static Importer::IntPropertyMap			gIntProperties;
-static Importer::FloatPropertyMap		gFloatProperties;
-static Importer::StringPropertyMap		gStringProperties;
+static ImporterPimpl::IntPropertyMap		gIntProperties;
+static ImporterPimpl::FloatPropertyMap		gFloatProperties;
+static ImporterPimpl::StringPropertyMap		gStringProperties;
 
 
 #if (defined AI_C_THREADSAFE)
 #if (defined AI_C_THREADSAFE)
 /** Global mutex to manage the access to the importer map */
 /** Global mutex to manage the access to the importer map */
@@ -214,9 +214,9 @@ const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,
 
 
 	// copy the global property lists to the Importer instance
 	// copy the global property lists to the Importer instance
 	// (we are a friend of Importer)
 	// (we are a friend of Importer)
-	imp->mIntProperties		= gIntProperties;
-	imp->mFloatProperties	= gFloatProperties;
-	imp->mStringProperties	= gStringProperties;
+	imp->pimpl->mIntProperties = gIntProperties;
+	imp->pimpl->mFloatProperties = gFloatProperties;
+	imp->pimpl->mStringProperties = gStringProperties;
 
 
 	// setup a custom IO system if necessary
 	// setup a custom IO system if necessary
 	if (pFS)
 	if (pFS)

+ 3 - 3
code/BaseImporter.cpp

@@ -371,9 +371,9 @@ void BatchLoader::LoadAll()
 		pp |= aiProcess_ValidateDataStructure;
 		pp |= aiProcess_ValidateDataStructure;
 #endif
 #endif
 		// setup config properties if necessary
 		// setup config properties if necessary
-		data->pImporter->mFloatProperties  = (*it).map.floats;
-		data->pImporter->mIntProperties    = (*it).map.ints;
-		data->pImporter->mStringProperties = (*it).map.strings;
+		data->pImporter->pimpl->mFloatProperties  = (*it).map.floats;
+		data->pImporter->pimpl->mIntProperties    = (*it).map.ints;
+		data->pImporter->pimpl->mStringProperties = (*it).map.strings;
 
 
 		if (!DefaultLogger::isNullLogger())
 		if (!DefaultLogger::isNullLogger())
 		{
 		{

+ 60 - 3
code/BaseImporter.h

@@ -76,6 +76,62 @@ private:
 	std::string mErrorText;
 	std::string mErrorText;
 };
 };
 
 
+// ---------------------------------------------------------------------------
+/** @brief Internal PIMPL implementation for Assimp::Importer
+ *
+ *  Using this idiom here allows us to drop the dependency from
+ *  std::vector and std::map in the public headers. Furthermore we are dropping
+ *  any STL interface problems caused by mismatching STL settings. All
+ *  size calculation are now done by us, not the app heap.
+ */
+class ASSIMP_API ImporterPimpl 
+{
+public:
+
+	// Data type to store the key hash
+	typedef unsigned int KeyType;
+	
+	// typedefs for our three configuration maps.
+	// We don't need more, so there is no need for a generic solution
+	typedef std::map<KeyType, int> IntPropertyMap;
+	typedef std::map<KeyType, float> FloatPropertyMap;
+	typedef std::map<KeyType, std::string> StringPropertyMap;
+
+public:
+
+	/** IO handler to use for all file accesses. */
+	IOSystem* mIOHandler;
+	bool mIsDefaultHandler;
+
+	/** Format-specific importer worker objects - one for each format we can read.*/
+	std::vector<BaseImporter*> mImporter;
+
+	/** Post processing steps we can apply at the imported data. */
+	std::vector<BaseProcess*> mPostProcessingSteps;
+
+	/** The imported data, if ReadFile() was successful, NULL otherwise. */
+	aiScene* mScene;
+
+	/** The error description, if there was one. */
+	std::string mErrorString;
+
+	/** List of integer properties */
+	IntPropertyMap mIntProperties;
+
+	/** List of floating-point properties */
+	FloatPropertyMap mFloatProperties;
+
+	/** List of string properties */
+	StringPropertyMap mStringProperties;
+
+	/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
+	 *  to be executed before and after every single postprocess step */
+	bool bExtraVerbose;
+
+	/** Used by post-process steps to share data */
+	SharedPostProcessInfo* mPPShared;
+};
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** The BaseImporter defines a common interface for all importer worker 
 /** The BaseImporter defines a common interface for all importer worker 
  *  classes.
  *  classes.
@@ -334,11 +390,12 @@ public:
 	 */
 	 */
 	struct PropertyMap
 	struct PropertyMap
 	{
 	{
-		Importer::IntPropertyMap     ints;
-		Importer::FloatPropertyMap   floats;
-		Importer::StringPropertyMap  strings;
+		ImporterPimpl::IntPropertyMap     ints;
+		ImporterPimpl::FloatPropertyMap   floats;
+		ImporterPimpl::StringPropertyMap  strings;
 
 
 		bool operator == (const PropertyMap& prop) const {
 		bool operator == (const PropertyMap& prop) const {
+			// fixme: really isocpp? gcc complains
 			return ints == prop.ints && floats == prop.floats && strings == prop.strings; 
 			return ints == prop.ints && floats == prop.floats && strings == prop.strings; 
 		}
 		}
 
 

+ 6 - 6
code/BaseProcess.cpp

@@ -64,24 +64,24 @@ BaseProcess::~BaseProcess()
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void BaseProcess::ExecuteOnScene( Importer* pImp)
 void BaseProcess::ExecuteOnScene( Importer* pImp)
 {
 {
-	ai_assert(NULL != pImp && NULL != pImp->mScene);
+	ai_assert(NULL != pImp && NULL != pImp->pimpl->mScene);
 
 
 	// catch exceptions thrown inside the PostProcess-Step
 	// catch exceptions thrown inside the PostProcess-Step
 	try
 	try
 	{
 	{
-		Execute(pImp->mScene);
+		Execute(pImp->pimpl->mScene);
 
 
 	} catch( ImportErrorException* exception)
 	} catch( ImportErrorException* exception)
 	{
 	{
 		// extract error description
 		// extract error description
-		pImp->mErrorString = exception->GetErrorText();
-		DefaultLogger::get()->error(pImp->mErrorString);
+		pImp->pimpl->mErrorString = exception->GetErrorText();
+		DefaultLogger::get()->error(pImp->pimpl->mErrorString);
 
 
 		delete exception;
 		delete exception;
 
 
 		// and kill the partially imported data
 		// and kill the partially imported data
-		delete pImp->mScene;
-		pImp->mScene = NULL;
+		delete pImp->pimpl->mScene;
+		pImp->pimpl->mScene = NULL;
 	}
 	}
 }
 }
 
 

+ 572 - 564
code/CMakeLists.txt

@@ -1,564 +1,572 @@
-
-SET( HEADER_PATH ../include/ )
-
-SOURCE_GROUP( Logging FILES 
-	${HEADER_PATH}/DefaultLogger.h 
-	${HEADER_PATH}/IOStream.h
-	${HEADER_PATH}/LogStream.h
-	${HEADER_PATH}/Logger.h
-	${HEADER_PATH}/NullLogger.h
-	Win32DebugLogStream.h
-	DefaultLogger.cpp
-	FileLogStream.h
-)
-SOURCE_GROUP( Common FILES 
-	aiAssert.cpp
-	fast_atof.h	
-	qnan.h
-	BaseImporter.cpp
-	BaseImporter.h
-	BaseProcess.cpp
-	BaseProcess.h
-	ByteSwap.h
-	ProcessHelper.h
-	DefaultIOStream.cpp
-	DefaultIOStream.h
-	DefaultIOSystem.cpp
-	DefaultIOSystem.h
-	Hash.h
-	Importer.cpp
-	IFF.h
-	ParsingUtils.h
-	StdOStreamLogStream.h
-	StreamReader.h
-	StringComparison.h
-)
-
-SOURCE_GROUP( 3DS FILES 
-	3DSConverter.cpp
-	3DSHelper.h
-	3DSLoader.cpp
-	3DSLoader.h
-)
-
-SOURCE_GROUP( AC FILES
-	ACLoader.cpp
-	ACLoader.h
-)
-
-SOURCE_GROUP( ASE FILES
-	ASELoader.cpp
-	ASELoader.h
-	ASEParser.cpp
-	ASEParser.h
-)
-SOURCE_GROUP( B3D FILES
-	B3DImporter.cpp
-	B3DImporter.h
-)
-
-SOURCE_GROUP( BVH FILES
-	BVHLoader.cpp
-	BVHLoader.h
-)
-
-SOURCE_GROUP(Collada FILES
-	ColladaHelper.h
-	ColladaLoader.cpp
-	ColladaLoader.h
-	ColladaParser.cpp
-	ColladaParser.h
-)
-
-SOURCE_GROUP(DXF FILES
-	DXFLoader.cpp
-	DXFLoader.h
-)
-
-SOURCE_GROUP(HMP FILES
-	HMPFileData.h
-	HMPLoader.cpp
-	HMPLoader.h
-	HalfLifeFileData.h
-)
-
-SOURCE_GROUP(Irr FILES
-	IRRLoader.cpp
-	IRRLoader.h
-	IRRMeshLoader.cpp
-	IRRMeshLoader.h
-	IRRShared.cpp
-	IRRShared.h
-)
-
-SOURCE_GROUP(LWO FILES
-	LWOAnimation.cpp
-	LWOAnimation.h
-	LWOBLoader.cpp
-	LWOFileData.h
-	LWOLoader.cpp
-	LWOLoader.h
-	LWOMaterial.cpp
-)
-
-SOURCE_GROUP(LWS FILES
-	LWSLoader.cpp
-	LWSLoader.h
-)
-
-SOURCE_GROUP(MD2 FILES
-	MD2FileData.h
-	MD2Loader.cpp
-	MD2Loader.h
-	MD2NormalTable.h
-)
-
-SOURCE_GROUP( MD3 FILES
-	MD3FileData.h
-	MD3Loader.cpp
-	MD3Loader.h
-)
-
-SOURCE_GROUP( MD5 FILES
-	MD5Loader.cpp
-	MD5Loader.h
-	MD5Parser.cpp
-	MD5Parser.h
-)
-
-SOURCE_GROUP( MDC FILES
-	MDCFileData.h
-	MDCLoader.cpp
-	MDCLoader.h
-	MDCNormalTable.h
-)
-
-SOURCE_GROUP( MDL FILES
-	MDLDefaultColorMap.h
-	MDLFileData.h
-	MDLLoader.cpp
-	MDLLoader.h
-	MDLMaterialLoader.cpp
-)
-
-SOURCE_GROUP( MaterialSystem FILES
-	MaterialSystem.cpp
-	MaterialSystem.h
-)
-
-SOURCE_GROUP( NFF FILES
-	NFFLoader.cpp
-	NFFLoader.h
-)
-
-SOURCE_GROUP( OFFFormat FILES
-	OFFLoader.cpp
-	OFFLoader.h
-)
-
-SOURCE_GROUP( Obj FILES
-	ObjFileData.h
-	ObjFileImporter.cpp
-	ObjFileImporter.h
-	ObjFileMtlImporter.cpp
-	ObjFileMtlImporter.h
-	ObjFileParser.cpp
-	ObjFileParser.h
-	ObjTools.h
-)
-
-SOURCE_GROUP( Ply FILES
-	PlyLoader.cpp
-	PlyLoader.h
-	PlyParser.cpp
-	PlyParser.h
-)
-
-SOURCE_GROUP( PostProcessing FILES
-	CalcTangentsProcess.cpp
-	CalcTangentsProcess.h
-	ComputeUVMappingProcess.cpp
-	ComputeUVMappingProcess.h
-	ConvertToLHProcess.cpp
-	ConvertToLHProcess.h
-	FindDegenerates.cpp
-	FindDegenerates.h
-	FindInstancesProcess.cpp
-	FindInstancesProcess.h
-	FindInvalidDataProcess.cpp
-	FindInvalidDataProcess.h
-	FixNormalsStep.cpp
-	FixNormalsStep.h
-	GenFaceNormalsProcess.cpp
-	GenFaceNormalsProcess.h
-	GenVertexNormalsProcess.cpp
-	GenVertexNormalsProcess.h
-	GenericProperty.h
-	PretransformVertices.cpp
-	PretransformVertices.h
-	ImproveCacheLocality.cpp
-	ImproveCacheLocality.h
-	JoinVerticesProcess.cpp
-	JoinVerticesProcess.h
-	LimitBoneWeightsProcess.cpp
-	LimitBoneWeightsProcess.h
-	RemoveComments.cpp
-	RemoveComments.h
-	RemoveRedundantMaterials.cpp
-	RemoveRedundantMaterials.h
-	RemoveVCProcess.cpp
-	RemoveVCProcess.h
-	SGSpatialSort.cpp
-	SGSpatialSort.h
-	SceneCombiner.cpp
-	SceneCombiner.h
-	ScenePreprocessor.cpp
-	ScenePreprocessor.h
-	SkeletonMeshBuilder.cpp
-	SkeletonMeshBuilder.h
-	SmoothingGroups.h
-	SortByPTypeProcess.cpp
-	SortByPTypeProcess.h
-	SpatialSort.cpp
-	SpatialSort.h
-	SplitLargeMeshes.cpp
-	SplitLargeMeshes.h
-	StandardShapes.cpp
-	StandardShapes.h
-	TargetAnimation.cpp
-	TargetAnimation.h
-	TerragenLoader.cpp
-	TerragenLoader.h
-	TextureTransform.cpp
-	TextureTransform.h
-	TriangulateProcess.cpp
-	TriangulateProcess.h
-	ValidateDataStructure.cpp
-	ValidateDataStructure.h
-	VertexTriangleAdjacency.cpp
-	VertexTriangleAdjacency.h
-)
-
-SOURCE_GROUP( Q3D FILES
-	Q3DLoader.cpp
-	Q3DLoader.h
-)
-
-SOURCE_GROUP( Raw FILES
-	RawLoader.cpp
-	RawLoader.h
-)
-
-SOURCE_GROUP( SMD FILES
-	SMDLoader.cpp
-	SMDLoader.h
-)
-
-SOURCE_GROUP( STL FILES
-	STLLoader.cpp
-	STLLoader.h
-)
-
-SOURCE_GROUP( Unreal FILES
-	UnrealLoader.cpp
-	UnrealLoader.h
-)
-
-SOURCE_GROUP( XFile FILES
-	XFileHelper.h
-	XFileImporter.cpp
-	XFileImporter.h
-	XFileParser.cpp
-	XFileParser.h
-)
-
-SOURCE_GROUP( Extra FILES
-	extra/MakeVerboseFormat.cpp
-	extra/MakeVerboseFormat.h
-	extra/MD4FileData.h
-)
-
-SOURCE_GROUP( IrrXML FILES
-	irrXMLWrapper.h
-	../contrib/irrXML/CXMLReaderImpl.h
-	../contrib/irrXML/heapsort.h
-	../contrib/irrXML/irrArray.h
-	../contrib/irrXML/irrString.h
-	../contrib/irrXML/irrTypes.h
-	../contrib/irrXML/irrXML.cpp
-	../contrib/irrXML/irrXML.h
-)
-
-SOURCE_GROUP( zlib FILES
-	../contrib/zlib/adler32.c
-	../contrib/zlib/compress.c
-	../contrib/zlib/crc32.c
-	../contrib/zlib/crc32.h
-	../contrib/zlib/deflate.c
-	../contrib/zlib/deflate.h
-	../contrib/zlib/inffast.c
-	../contrib/zlib/inffast.h
-	../contrib/zlib/inffixed.h
-	../contrib/zlib/inflate.c
-	../contrib/zlib/inflate.h
-	../contrib/zlib/inftrees.c
-	../contrib/zlib/inftrees.h
-	../contrib/zlib/trees.c
-	../contrib/zlib/trees.h
-	../contrib/zlib/zconf.h
-	../contrib/zlib/zconf.in.h
-	../contrib/zlib/zlib.h
-	../contrib/zlib/zutil.c
-	../contrib/zlib/zutil.h
-)
-
-ADD_LIBRARY( assimp SHARED
-	${HEADER_PATH}/DefaultLogger.h
-	${HEADER_PATH}/IOStream.h
-	${HEADER_PATH}/IOSystem.h
-	${HEADER_PATH}/LogStream.h
-	${HEADER_PATH}/Logger.h
-	${HEADER_PATH}/NullLogger.h
-	${HEADER_PATH}/TDepGraphNode.h
-	${HEADER_PATH}/aiAnim.h
-	${HEADER_PATH}/aiAssert.h
-	${HEADER_PATH}/aiCamera.h
-	${HEADER_PATH}/aiConfig.h
-	${HEADER_PATH}/aiDefines.h
-	${HEADER_PATH}/aiFileIO.h
-	${HEADER_PATH}/aiLight.h
-	${HEADER_PATH}/aiMaterial.h
-	${HEADER_PATH}/aiMatrix3x3.h
-	${HEADER_PATH}/aiMatrix4x4.h
-	${HEADER_PATH}/aiMesh.h
-	${HEADER_PATH}/aiPostProcess.h
-	${HEADER_PATH}/aiQuaternion.h
-	${HEADER_PATH}/aiScene.h
-	${HEADER_PATH}/aiTexture.h
-	${HEADER_PATH}/aiTypes.h
-	${HEADER_PATH}/aiVector2D.h
-	${HEADER_PATH}/aiVector3D.h
-	${HEADER_PATH}/aiVersion.h
-	${HEADER_PATH}/assimp.h
-
-	3DSConverter.cpp
-	3DSHelper.h
-	3DSLoader.cpp
-	3DSLoader.h
-	ACLoader.cpp
-	ACLoader.h
-	ASELoader.cpp
-	ASELoader.h
-	ASEParser.cpp
-	ASEParser.h
-	Assimp.cpp
-	AssimpPCH.cpp
-	AssimpPCH.h
-	B3DImporter.cpp
-	B3DImporter.h
-	BVHLoader.cpp
-	BVHLoader.h
-	BaseImporter.cpp
-	BaseImporter.h
-	BaseProcess.cpp
-	BaseProcess.h
-	ByteSwap.h
-	CalcTangentsProcess.cpp
-	CalcTangentsProcess.h
-	ColladaHelper.h
-	ColladaLoader.cpp
-	ColladaLoader.h
-	ColladaParser.cpp
-	ColladaParser.h
-	ComputeUVMappingProcess.cpp
-	ComputeUVMappingProcess.h
-	ConvertToLHProcess.cpp
-	ConvertToLHProcess.h
-	DXFLoader.cpp
-	DXFLoader.h
-	DefaultIOStream.cpp
-	DefaultIOStream.h
-	DefaultIOSystem.cpp
-	DefaultIOSystem.h
-	DefaultLogger.cpp
-	FileLogStream.h
-	FindDegenerates.cpp
-	FindDegenerates.h
-	FindInstancesProcess.cpp
-	FindInstancesProcess.h
-	FindInvalidDataProcess.cpp
-	FindInvalidDataProcess.h
-	FixNormalsStep.cpp
-	FixNormalsStep.h
-	GenFaceNormalsProcess.cpp
-	GenFaceNormalsProcess.h
-	GenVertexNormalsProcess.cpp
-	GenVertexNormalsProcess.h
-	GenericProperty.h
-	HMPFileData.h
-	HMPLoader.cpp
-	HMPLoader.h
-	HalfLifeFileData.h
-	Hash.h
-	IFF.h
-	IRRLoader.cpp
-	IRRLoader.h
-	IRRMeshLoader.cpp
-	IRRMeshLoader.h
-	IRRShared.cpp
-	IRRShared.h
-	Importer.cpp
-	ImproveCacheLocality.cpp
-	ImproveCacheLocality.h
-	JoinVerticesProcess.cpp
-	JoinVerticesProcess.h
-	LWOAnimation.cpp
-	LWOAnimation.h
-	LWOBLoader.cpp
-	LWOFileData.h
-	LWOLoader.cpp
-	LWOLoader.h
-	LWOMaterial.cpp
-	LWSLoader.cpp
-	LWSLoader.h
-	LimitBoneWeightsProcess.cpp
-	LimitBoneWeightsProcess.h
-	MD2FileData.h
-	MD2Loader.cpp
-	MD2Loader.h
-	MD2NormalTable.h
-	MD3FileData.h
-	MD3Loader.cpp
-	MD3Loader.h
-	MD5Loader.cpp
-	MD5Loader.h
-	MD5Parser.cpp
-	MD5Parser.h
-	MDCFileData.h
-	MDCLoader.cpp
-	MDCLoader.h
-	MDCNormalTable.h
-	MDLDefaultColorMap.h
-	MDLFileData.h
-	MDLLoader.cpp
-	MDLLoader.h
-	MDLMaterialLoader.cpp
-	MaterialSystem.cpp
-	MaterialSystem.h
-	NFFLoader.cpp
-	NFFLoader.h
-	OFFLoader.cpp
-	OFFLoader.h
-	ObjFileData.h
-	ObjFileImporter.cpp
-	ObjFileImporter.h
-	ObjFileMtlImporter.cpp
-	ObjFileMtlImporter.h
-	ObjFileParser.cpp
-	ObjFileParser.h
-	ObjTools.h
-	ParsingUtils.h
-	PlyLoader.cpp
-	PlyLoader.h
-	PlyParser.cpp
-	PlyParser.h
-	PretransformVertices.cpp
-	PretransformVertices.h
-	ProcessHelper.h
-	Q3DLoader.cpp
-	Q3DLoader.h
-	RawLoader.cpp
-	RawLoader.h
-	RemoveComments.cpp
-	RemoveComments.h
-	RemoveRedundantMaterials.cpp
-	RemoveRedundantMaterials.h
-	RemoveVCProcess.cpp
-	RemoveVCProcess.h
-	SGSpatialSort.cpp
-	SGSpatialSort.h
-	SMDLoader.cpp
-	SMDLoader.h
-	STLLoader.cpp
-	STLLoader.h
-	SceneCombiner.cpp
-	SceneCombiner.h
-	ScenePreprocessor.cpp
-	ScenePreprocessor.h
-	SkeletonMeshBuilder.cpp
-	SkeletonMeshBuilder.h
-	SmoothingGroups.h
-	SortByPTypeProcess.cpp
-	SortByPTypeProcess.h
-	SpatialSort.cpp
-	SpatialSort.h
-	SplitLargeMeshes.cpp
-	SplitLargeMeshes.h
-	StandardShapes.cpp
-	StandardShapes.h
-	StdOStreamLogStream.h
-	StreamReader.h
-	StringComparison.h
-	TargetAnimation.cpp
-	TargetAnimation.h
-	TerragenLoader.cpp
-	TerragenLoader.h
-	TextureTransform.cpp
-	TextureTransform.h
-	TriangulateProcess.cpp
-	TriangulateProcess.h
-	UnrealLoader.cpp
-	UnrealLoader.h
-	ValidateDataStructure.cpp
-	ValidateDataStructure.h
-	VertexTriangleAdjacency.cpp
-	VertexTriangleAdjacency.h
-	Win32DebugLogStream.h
-	XFileHelper.h
-	XFileImporter.cpp
-	XFileImporter.h
-	XFileParser.cpp
-	XFileParser.h
-	aiAssert.cpp
-	fast_atof.h
-	irrXMLWrapper.h
-	qnan.h
-	extra/MakeVerboseFormat.cpp
-	extra/MakeVerboseFormat.h
-	extra/MD4FileData.h
-	../contrib/irrXML/CXMLReaderImpl.h
-	../contrib/irrXML/heapsort.h
-	../contrib/irrXML/irrArray.h
-	../contrib/irrXML/irrString.h
-	../contrib/irrXML/irrTypes.h
-	../contrib/irrXML/irrXML.cpp
-	../contrib/irrXML/irrXML.h
-	../contrib/zlib/adler32.c
-	../contrib/zlib/compress.c
-	../contrib/zlib/crc32.c
-	../contrib/zlib/crc32.h
-	../contrib/zlib/deflate.c
-	../contrib/zlib/deflate.h
-	../contrib/zlib/inffast.c
-	../contrib/zlib/inffast.h
-	../contrib/zlib/inffixed.h
-	../contrib/zlib/inflate.c
-	../contrib/zlib/inflate.h
-	../contrib/zlib/inftrees.c
-	../contrib/zlib/inftrees.h
-	../contrib/zlib/trees.c
-	../contrib/zlib/trees.h
-	../contrib/zlib/zconf.h
-	../contrib/zlib/zconf.in.h
-	../contrib/zlib/zlib.h
-	../contrib/zlib/zutil.c
-	../contrib/zlib/zutil.h
-)
-ADD_DEFINITIONS(-DASSIMP_BUILD_DLL_EXPORT)
-
-if (WIN32)
-	if ( MSVC80 )
-		ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
-		ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
-	endif( MSVC80 )
-endif (WIN32)
+
+SET( HEADER_PATH ../include/ )
+
+SOURCE_GROUP( Logging FILES 
+	${HEADER_PATH}/DefaultLogger.h 
+	${HEADER_PATH}/IOStream.h
+	${HEADER_PATH}/LogStream.h
+	${HEADER_PATH}/Logger.h
+	${HEADER_PATH}/NullLogger.h
+	Win32DebugLogStream.h
+	DefaultLogger.cpp
+	FileLogStream.h
+)
+SOURCE_GROUP( Common FILES 
+	aiAssert.cpp
+	fast_atof.h	
+	qnan.h
+	BaseImporter.cpp
+	BaseImporter.h
+	BaseProcess.cpp
+	BaseProcess.h
+	ByteSwap.h
+	ProcessHelper.h
+	DefaultIOStream.cpp
+	DefaultIOStream.h
+	DefaultIOSystem.cpp
+	DefaultIOSystem.h
+	Hash.h
+	Importer.cpp
+	IFF.h
+	ParsingUtils.h
+	StdOStreamLogStream.h
+	StreamReader.h
+	StringComparison.h
+	SGSpatialSort.cpp
+	SGSpatialSort.h
+	VertexTriangleAdjacency.cpp
+	VertexTriangleAdjacency.h
+	GenericProperty.h
+	SpatialSort.cpp
+	SpatialSort.h
+	SceneCombiner.cpp
+	SceneCombiner.h
+	ScenePreprocessor.cpp
+	ScenePreprocessor.h
+	SkeletonMeshBuilder.cpp
+	SkeletonMeshBuilder.h
+	SmoothingGroups.h
+	StandardShapes.cpp
+	StandardShapes.h
+	TargetAnimation.cpp
+	TargetAnimation.h
+	RemoveComments.cpp
+	RemoveComments.h
+)
+
+SOURCE_GROUP( 3DS FILES 
+	3DSConverter.cpp
+	3DSHelper.h
+	3DSLoader.cpp
+	3DSLoader.h
+)
+
+SOURCE_GROUP( AC FILES
+	ACLoader.cpp
+	ACLoader.h
+)
+
+SOURCE_GROUP( ASE FILES
+	ASELoader.cpp
+	ASELoader.h
+	ASEParser.cpp
+	ASEParser.h
+)
+SOURCE_GROUP( B3D FILES
+	B3DImporter.cpp
+	B3DImporter.h
+)
+
+SOURCE_GROUP( BVH FILES
+	BVHLoader.cpp
+	BVHLoader.h
+)
+
+SOURCE_GROUP(Collada FILES
+	ColladaHelper.h
+	ColladaLoader.cpp
+	ColladaLoader.h
+	ColladaParser.cpp
+	ColladaParser.h
+)
+
+SOURCE_GROUP(DXF FILES
+	DXFLoader.cpp
+	DXFLoader.h
+)
+
+SOURCE_GROUP(HMP FILES
+	HMPFileData.h
+	HMPLoader.cpp
+	HMPLoader.h
+	HalfLifeFileData.h
+)
+
+SOURCE_GROUP(Irr FILES
+	IRRLoader.cpp
+	IRRLoader.h
+	IRRMeshLoader.cpp
+	IRRMeshLoader.h
+	IRRShared.cpp
+	IRRShared.h
+)
+
+SOURCE_GROUP(LWO FILES
+	LWOAnimation.cpp
+	LWOAnimation.h
+	LWOBLoader.cpp
+	LWOFileData.h
+	LWOLoader.cpp
+	LWOLoader.h
+	LWOMaterial.cpp
+)
+
+SOURCE_GROUP(LWS FILES
+	LWSLoader.cpp
+	LWSLoader.h
+)
+
+SOURCE_GROUP(MD2 FILES
+	MD2FileData.h
+	MD2Loader.cpp
+	MD2Loader.h
+	MD2NormalTable.h
+)
+
+SOURCE_GROUP( MD3 FILES
+	MD3FileData.h
+	MD3Loader.cpp
+	MD3Loader.h
+)
+
+SOURCE_GROUP( MD5 FILES
+	MD5Loader.cpp
+	MD5Loader.h
+	MD5Parser.cpp
+	MD5Parser.h
+)
+
+SOURCE_GROUP( MDC FILES
+	MDCFileData.h
+	MDCLoader.cpp
+	MDCLoader.h
+	MDCNormalTable.h
+)
+
+SOURCE_GROUP( MDL FILES
+	MDLDefaultColorMap.h
+	MDLFileData.h
+	MDLLoader.cpp
+	MDLLoader.h
+	MDLMaterialLoader.cpp
+)
+
+SOURCE_GROUP( MaterialSystem FILES
+	MaterialSystem.cpp
+	MaterialSystem.h
+)
+
+SOURCE_GROUP( NFF FILES
+	NFFLoader.cpp
+	NFFLoader.h
+)
+
+SOURCE_GROUP( OFFFormat FILES
+	OFFLoader.cpp
+	OFFLoader.h
+)
+
+SOURCE_GROUP( Obj FILES
+	ObjFileData.h
+	ObjFileImporter.cpp
+	ObjFileImporter.h
+	ObjFileMtlImporter.cpp
+	ObjFileMtlImporter.h
+	ObjFileParser.cpp
+	ObjFileParser.h
+	ObjTools.h
+)
+
+SOURCE_GROUP( Ply FILES
+	PlyLoader.cpp
+	PlyLoader.h
+	PlyParser.cpp
+	PlyParser.h
+)
+
+SOURCE_GROUP( PostProcessing FILES
+	CalcTangentsProcess.cpp
+	CalcTangentsProcess.h
+	ComputeUVMappingProcess.cpp
+	ComputeUVMappingProcess.h
+	ConvertToLHProcess.cpp
+	ConvertToLHProcess.h
+	FindDegenerates.cpp
+	FindDegenerates.h
+	FindInstancesProcess.cpp
+	FindInstancesProcess.h
+	FindInvalidDataProcess.cpp
+	FindInvalidDataProcess.h
+	FixNormalsStep.cpp
+	FixNormalsStep.h
+	GenFaceNormalsProcess.cpp
+	GenFaceNormalsProcess.h
+	GenVertexNormalsProcess.cpp
+	GenVertexNormalsProcess.h
+	PretransformVertices.cpp
+	PretransformVertices.h
+	ImproveCacheLocality.cpp
+	ImproveCacheLocality.h
+	JoinVerticesProcess.cpp
+	JoinVerticesProcess.h
+	LimitBoneWeightsProcess.cpp
+	LimitBoneWeightsProcess.h
+	RemoveRedundantMaterials.cpp
+	RemoveRedundantMaterials.h
+	RemoveVCProcess.cpp
+	RemoveVCProcess.h
+	SortByPTypeProcess.cpp
+	SortByPTypeProcess.h
+	SplitLargeMeshes.cpp
+	SplitLargeMeshes.h
+	TerragenLoader.cpp
+	TerragenLoader.h
+	TextureTransform.cpp
+	TextureTransform.h
+	TriangulateProcess.cpp
+	TriangulateProcess.h
+	ValidateDataStructure.cpp
+	ValidateDataStructure.h
+	OptimizeGraph.cpp
+	OptimizeGraph.h
+	OptimizeMeshes.cpp
+	OptimizeMeshes.h
+)
+
+SOURCE_GROUP( Q3D FILES
+	Q3DLoader.cpp
+	Q3DLoader.h
+)
+
+SOURCE_GROUP( Raw FILES
+	RawLoader.cpp
+	RawLoader.h
+)
+
+SOURCE_GROUP( SMD FILES
+	SMDLoader.cpp
+	SMDLoader.h
+)
+
+SOURCE_GROUP( STL FILES
+	STLLoader.cpp
+	STLLoader.h
+)
+
+SOURCE_GROUP( Unreal FILES
+	UnrealLoader.cpp
+	UnrealLoader.h
+)
+
+SOURCE_GROUP( XFile FILES
+	XFileHelper.h
+	XFileImporter.cpp
+	XFileImporter.h
+	XFileParser.cpp
+	XFileParser.h
+)
+
+SOURCE_GROUP( Extra FILES
+	extra/MakeVerboseFormat.cpp
+	extra/MakeVerboseFormat.h
+	extra/MD4FileData.h
+)
+
+SOURCE_GROUP( IrrXML FILES
+	irrXMLWrapper.h
+	../contrib/irrXML/CXMLReaderImpl.h
+	../contrib/irrXML/heapsort.h
+	../contrib/irrXML/irrArray.h
+	../contrib/irrXML/irrString.h
+	../contrib/irrXML/irrTypes.h
+	../contrib/irrXML/irrXML.cpp
+	../contrib/irrXML/irrXML.h
+)
+
+SOURCE_GROUP( zlib FILES
+	../contrib/zlib/adler32.c
+	../contrib/zlib/compress.c
+	../contrib/zlib/crc32.c
+	../contrib/zlib/crc32.h
+	../contrib/zlib/deflate.c
+	../contrib/zlib/deflate.h
+	../contrib/zlib/inffast.c
+	../contrib/zlib/inffast.h
+	../contrib/zlib/inffixed.h
+	../contrib/zlib/inflate.c
+	../contrib/zlib/inflate.h
+	../contrib/zlib/inftrees.c
+	../contrib/zlib/inftrees.h
+	../contrib/zlib/trees.c
+	../contrib/zlib/trees.h
+	../contrib/zlib/zconf.h
+	../contrib/zlib/zconf.in.h
+	../contrib/zlib/zlib.h
+	../contrib/zlib/zutil.c
+	../contrib/zlib/zutil.h
+)
+
+ADD_LIBRARY( assimp SHARED
+	${HEADER_PATH}/DefaultLogger.h
+	${HEADER_PATH}/IOStream.h
+	${HEADER_PATH}/IOSystem.h
+	${HEADER_PATH}/LogStream.h
+	${HEADER_PATH}/Logger.h
+	${HEADER_PATH}/NullLogger.h
+	${HEADER_PATH}/TDepGraphNode.h
+	${HEADER_PATH}/aiAnim.h
+	${HEADER_PATH}/aiAssert.h
+	${HEADER_PATH}/aiCamera.h
+	${HEADER_PATH}/aiConfig.h
+	${HEADER_PATH}/aiDefines.h
+	${HEADER_PATH}/aiFileIO.h
+	${HEADER_PATH}/aiLight.h
+	${HEADER_PATH}/aiMaterial.h
+	${HEADER_PATH}/aiMatrix3x3.h
+	${HEADER_PATH}/aiMatrix4x4.h
+	${HEADER_PATH}/aiMesh.h
+	${HEADER_PATH}/aiPostProcess.h
+	${HEADER_PATH}/aiQuaternion.h
+	${HEADER_PATH}/aiScene.h
+	${HEADER_PATH}/aiTexture.h
+	${HEADER_PATH}/aiTypes.h
+	${HEADER_PATH}/aiVector2D.h
+	${HEADER_PATH}/aiVector3D.h
+	${HEADER_PATH}/aiVersion.h
+	${HEADER_PATH}/assimp.h
+
+	3DSConverter.cpp
+	3DSHelper.h
+	3DSLoader.cpp
+	3DSLoader.h
+	ACLoader.cpp
+	ACLoader.h
+	ASELoader.cpp
+	ASELoader.h
+	ASEParser.cpp
+	ASEParser.h
+	Assimp.cpp
+	AssimpPCH.cpp
+	AssimpPCH.h
+	B3DImporter.cpp
+	B3DImporter.h
+	BVHLoader.cpp
+	BVHLoader.h
+	BaseImporter.cpp
+	BaseImporter.h
+	BaseProcess.cpp
+	BaseProcess.h
+	ByteSwap.h
+	CalcTangentsProcess.cpp
+	CalcTangentsProcess.h
+	ColladaHelper.h
+	ColladaLoader.cpp
+	ColladaLoader.h
+	ColladaParser.cpp
+	ColladaParser.h
+	ComputeUVMappingProcess.cpp
+	ComputeUVMappingProcess.h
+	ConvertToLHProcess.cpp
+	ConvertToLHProcess.h
+	DXFLoader.cpp
+	DXFLoader.h
+	DefaultIOStream.cpp
+	DefaultIOStream.h
+	DefaultIOSystem.cpp
+	DefaultIOSystem.h
+	DefaultLogger.cpp
+	FileLogStream.h
+	FindDegenerates.cpp
+	FindDegenerates.h
+	FindInstancesProcess.cpp
+	FindInstancesProcess.h
+	FindInvalidDataProcess.cpp
+	FindInvalidDataProcess.h
+	FixNormalsStep.cpp
+	FixNormalsStep.h
+	GenFaceNormalsProcess.cpp
+	GenFaceNormalsProcess.h
+	GenVertexNormalsProcess.cpp
+	GenVertexNormalsProcess.h
+	GenericProperty.h
+	HMPFileData.h
+	HMPLoader.cpp
+	HMPLoader.h
+	HalfLifeFileData.h
+	Hash.h
+	IFF.h
+	IRRLoader.cpp
+	IRRLoader.h
+	IRRMeshLoader.cpp
+	IRRMeshLoader.h
+	IRRShared.cpp
+	IRRShared.h
+	Importer.cpp
+	ImproveCacheLocality.cpp
+	ImproveCacheLocality.h
+	JoinVerticesProcess.cpp
+	JoinVerticesProcess.h
+	LWOAnimation.cpp
+	LWOAnimation.h
+	LWOBLoader.cpp
+	LWOFileData.h
+	LWOLoader.cpp
+	LWOLoader.h
+	LWOMaterial.cpp
+	LWSLoader.cpp
+	LWSLoader.h
+	LimitBoneWeightsProcess.cpp
+	LimitBoneWeightsProcess.h
+	MD2FileData.h
+	MD2Loader.cpp
+	MD2Loader.h
+	MD2NormalTable.h
+	MD3FileData.h
+	MD3Loader.cpp
+	MD3Loader.h
+	MD5Loader.cpp
+	MD5Loader.h
+	MD5Parser.cpp
+	MD5Parser.h
+	MDCFileData.h
+	MDCLoader.cpp
+	MDCLoader.h
+	MDCNormalTable.h
+	MDLDefaultColorMap.h
+	MDLFileData.h
+	MDLLoader.cpp
+	MDLLoader.h
+	MDLMaterialLoader.cpp
+	MaterialSystem.cpp
+	MaterialSystem.h
+	NFFLoader.cpp
+	NFFLoader.h
+	OFFLoader.cpp
+	OFFLoader.h
+	ObjFileData.h
+	ObjFileImporter.cpp
+	ObjFileImporter.h
+	ObjFileMtlImporter.cpp
+	ObjFileMtlImporter.h
+	ObjFileParser.cpp
+	ObjFileParser.h
+	ObjTools.h
+	OptimizeGraph.cpp
+	OptimizeGraph.h
+	OptimizeMeshes.cpp
+	OptimizeMeshes.h
+	ParsingUtils.h
+	PlyLoader.cpp
+	PlyLoader.h
+	PlyParser.cpp
+	PlyParser.h
+	PretransformVertices.cpp
+	PretransformVertices.h
+	ProcessHelper.h
+	Q3DLoader.cpp
+	Q3DLoader.h
+	RawLoader.cpp
+	RawLoader.h
+	RemoveComments.cpp
+	RemoveComments.h
+	RemoveRedundantMaterials.cpp
+	RemoveRedundantMaterials.h
+	RemoveVCProcess.cpp
+	RemoveVCProcess.h
+	SGSpatialSort.cpp
+	SGSpatialSort.h
+	SMDLoader.cpp
+	SMDLoader.h
+	STLLoader.cpp
+	STLLoader.h
+	SceneCombiner.cpp
+	SceneCombiner.h
+	ScenePreprocessor.cpp
+	ScenePreprocessor.h
+	SkeletonMeshBuilder.cpp
+	SkeletonMeshBuilder.h
+	SmoothingGroups.h
+	SortByPTypeProcess.cpp
+	SortByPTypeProcess.h
+	SpatialSort.cpp
+	SpatialSort.h
+	SplitLargeMeshes.cpp
+	SplitLargeMeshes.h
+	StandardShapes.cpp
+	StandardShapes.h
+	StdOStreamLogStream.h
+	StreamReader.h
+	StringComparison.h
+	TargetAnimation.cpp
+	TargetAnimation.h
+	TerragenLoader.cpp
+	TerragenLoader.h
+	TextureTransform.cpp
+	TextureTransform.h
+	TriangulateProcess.cpp
+	TriangulateProcess.h
+	UnrealLoader.cpp
+	UnrealLoader.h
+	ValidateDataStructure.cpp
+	ValidateDataStructure.h
+	VertexTriangleAdjacency.cpp
+	VertexTriangleAdjacency.h
+	Win32DebugLogStream.h
+	XFileHelper.h
+	XFileImporter.cpp
+	XFileImporter.h
+	XFileParser.cpp
+	XFileParser.h
+	aiAssert.cpp
+	fast_atof.h
+	irrXMLWrapper.h
+	qnan.h
+	extra/MakeVerboseFormat.cpp
+	extra/MakeVerboseFormat.h
+	extra/MD4FileData.h
+	../contrib/irrXML/CXMLReaderImpl.h
+	../contrib/irrXML/heapsort.h
+	../contrib/irrXML/irrArray.h
+	../contrib/irrXML/irrString.h
+	../contrib/irrXML/irrTypes.h
+	../contrib/irrXML/irrXML.cpp
+	../contrib/irrXML/irrXML.h
+	../contrib/zlib/adler32.c
+	../contrib/zlib/compress.c
+	../contrib/zlib/crc32.c
+	../contrib/zlib/crc32.h
+	../contrib/zlib/deflate.c
+	../contrib/zlib/deflate.h
+	../contrib/zlib/inffast.c
+	../contrib/zlib/inffast.h
+	../contrib/zlib/inffixed.h
+	../contrib/zlib/inflate.c
+	../contrib/zlib/inflate.h
+	../contrib/zlib/inftrees.c
+	../contrib/zlib/inftrees.h
+	../contrib/zlib/trees.c
+	../contrib/zlib/trees.h
+	../contrib/zlib/zconf.h
+	../contrib/zlib/zconf.in.h
+	../contrib/zlib/zlib.h
+	../contrib/zlib/zutil.c
+	../contrib/zlib/zutil.h
+)
+ADD_DEFINITIONS(-DASSIMP_BUILD_DLL_EXPORT)
+
+if (WIN32)
+	if ( MSVC80 )
+		ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
+		ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
+	endif( MSVC80 )
+endif (WIN32)

+ 202 - 205
code/Importer.cpp

@@ -157,7 +157,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #	include "LWSLoader.h"
 #	include "LWSLoader.h"
 #endif
 #endif
 
 
-
 // =======================================================================================
 // =======================================================================================
 // PostProcess-Steps
 // PostProcess-Steps
 // =======================================================================================
 // =======================================================================================
@@ -221,6 +220,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_BUILD_NO_FINDINSTANCES_PROCESS
 #ifndef AI_BUILD_NO_FINDINSTANCES_PROCESS
 #	include "FindInstancesProcess.h"
 #	include "FindInstancesProcess.h"
 #endif
 #endif
+#ifndef AI_BUILD_NO_OPTIMIZEMESHES_PROCESS
+#	include "OptimizeMeshes.h"
+#endif
+#ifndef AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS
+#	include "OptimizeGraph.h"
+#endif
 
 
 using namespace Assimp;
 using namespace Assimp;
 using namespace Assimp::Intern;
 using namespace Assimp::Intern;
@@ -230,273 +235,264 @@ using namespace Assimp::Intern;
 // new and delete (and their array counterparts) of public API classes (e.g. Logger) to
 // new and delete (and their array counterparts) of public API classes (e.g. Logger) to
 // utilize our DLL heap
 // utilize our DLL heap
 // =======================================================================================
 // =======================================================================================
-void* AllocateFromAssimpHeap::operator new ( size_t num_bytes)	
-{
+void* AllocateFromAssimpHeap::operator new ( size_t num_bytes)	{
 	return ::operator new(num_bytes);
 	return ::operator new(num_bytes);
 }
 }
 
 
-void AllocateFromAssimpHeap::operator delete ( void* data)	
-{
+void AllocateFromAssimpHeap::operator delete ( void* data)	{
 	return ::operator delete(data);
 	return ::operator delete(data);
 }
 }
 
 
-void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes)	
-{
+void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes)	{
 	return ::operator new[](num_bytes);
 	return ::operator new[](num_bytes);
 }
 }
 
 
-void AllocateFromAssimpHeap::operator delete[] ( void* data)
-{
+void AllocateFromAssimpHeap::operator delete[] ( void* data)	{
 	return ::operator delete[](data);
 	return ::operator delete[](data);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// Importer Constructor. 
+// Importer constructor. 
 Importer::Importer() 
 Importer::Importer() 
-	:	mIOHandler		(NULL)
-	,	mScene			(NULL)
-	,	mErrorString	("")	
 {
 {
+	// allocate the pimpl first
+	pimpl = new ImporterPimpl();
+
+	pimpl->mScene = NULL;
+	pimpl->mErrorString = "";
+
 	// Allocate a default IO handler
 	// Allocate a default IO handler
-	mIOHandler = new DefaultIOSystem;
-	mIsDefaultHandler = true; 
-	bExtraVerbose     = false; // disable extra verbose mode by default
+	pimpl->mIOHandler = new DefaultIOSystem;
+	pimpl->mIsDefaultHandler = true; 
+	pimpl->bExtraVerbose     = false; // disable extra verbose mode by default
 
 
-	// ======================================================================
+	// ----------------------------------------------------------------------------
 	// Add an instance of each worker class here
 	// Add an instance of each worker class here
-	// The order doesn't really care, however file formats that are
+	// The order doesn't really care. File formats that are
 	// used more frequently than others should be at the beginning.
 	// used more frequently than others should be at the beginning.
-	// ======================================================================
-	mImporter.reserve(25);
+	// ----------------------------------------------------------------------------
+	pimpl->mImporter.reserve(25);
 
 
 #if (!defined AI_BUILD_NO_X_IMPORTER)
 #if (!defined AI_BUILD_NO_X_IMPORTER)
-	mImporter.push_back( new XFileImporter());
+	pimpl->mImporter.push_back( new XFileImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_OBJ_IMPORTER)
 #if (!defined AI_BUILD_NO_OBJ_IMPORTER)
-	mImporter.push_back( new ObjFileImporter());
+	pimpl->mImporter.push_back( new ObjFileImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_3DS_IMPORTER)
 #if (!defined AI_BUILD_NO_3DS_IMPORTER)
-	mImporter.push_back( new Discreet3DSImporter());
+	pimpl->mImporter.push_back( new Discreet3DSImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_MD3_IMPORTER)
 #if (!defined AI_BUILD_NO_MD3_IMPORTER)
-	mImporter.push_back( new MD3Importer());
+	pimpl->mImporter.push_back( new MD3Importer());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_MD2_IMPORTER)
 #if (!defined AI_BUILD_NO_MD2_IMPORTER)
-	mImporter.push_back( new MD2Importer());
+	pimpl->mImporter.push_back( new MD2Importer());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_PLY_IMPORTER)
 #if (!defined AI_BUILD_NO_PLY_IMPORTER)
-	mImporter.push_back( new PLYImporter());
+	pimpl->mImporter.push_back( new PLYImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_MDL_IMPORTER)
 #if (!defined AI_BUILD_NO_MDL_IMPORTER)
-	mImporter.push_back( new MDLImporter());
+	pimpl->mImporter.push_back( new MDLImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_ASE_IMPORTER)
 #if (!defined AI_BUILD_NO_ASE_IMPORTER)
-	mImporter.push_back( new ASEImporter());
+	pimpl->mImporter.push_back( new ASEImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_HMP_IMPORTER)
 #if (!defined AI_BUILD_NO_HMP_IMPORTER)
-	mImporter.push_back( new HMPImporter());
+	pimpl->mImporter.push_back( new HMPImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_SMD_IMPORTER)
 #if (!defined AI_BUILD_NO_SMD_IMPORTER)
-	mImporter.push_back( new SMDImporter());
+	pimpl->mImporter.push_back( new SMDImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_MDC_IMPORTER)
 #if (!defined AI_BUILD_NO_MDC_IMPORTER)
-	mImporter.push_back( new MDCImporter());
+	pimpl->mImporter.push_back( new MDCImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_MD5_IMPORTER)
 #if (!defined AI_BUILD_NO_MD5_IMPORTER)
-	mImporter.push_back( new MD5Importer());
+	pimpl->mImporter.push_back( new MD5Importer());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_STL_IMPORTER)
 #if (!defined AI_BUILD_NO_STL_IMPORTER)
-	mImporter.push_back( new STLImporter());
+	pimpl->mImporter.push_back( new STLImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_LWO_IMPORTER)
 #if (!defined AI_BUILD_NO_LWO_IMPORTER)
-	mImporter.push_back( new LWOImporter());
+	pimpl->mImporter.push_back( new LWOImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_DXF_IMPORTER)
 #if (!defined AI_BUILD_NO_DXF_IMPORTER)
-	mImporter.push_back( new DXFImporter());
+	pimpl->mImporter.push_back( new DXFImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_NFF_IMPORTER)
 #if (!defined AI_BUILD_NO_NFF_IMPORTER)
-	mImporter.push_back( new NFFImporter());
+	pimpl->mImporter.push_back( new NFFImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_RAW_IMPORTER)
 #if (!defined AI_BUILD_NO_RAW_IMPORTER)
-	mImporter.push_back( new RAWImporter());
+	pimpl->mImporter.push_back( new RAWImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_OFF_IMPORTER)
 #if (!defined AI_BUILD_NO_OFF_IMPORTER)
-	mImporter.push_back( new OFFImporter());
+	pimpl->mImporter.push_back( new OFFImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_AC_IMPORTER)
 #if (!defined AI_BUILD_NO_AC_IMPORTER)
-	mImporter.push_back( new AC3DImporter());
+	pimpl->mImporter.push_back( new AC3DImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_BVH_IMPORTER)
 #if (!defined AI_BUILD_NO_BVH_IMPORTER)
-	mImporter.push_back( new BVHLoader());
+	pimpl->mImporter.push_back( new BVHLoader());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_IRRMESH_IMPORTER)
 #if (!defined AI_BUILD_NO_IRRMESH_IMPORTER)
-	mImporter.push_back( new IRRMeshImporter());
+	pimpl->mImporter.push_back( new IRRMeshImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_IRR_IMPORTER)
 #if (!defined AI_BUILD_NO_IRR_IMPORTER)
-	mImporter.push_back( new IRRImporter());
+	pimpl->mImporter.push_back( new IRRImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_Q3D_IMPORTER)
 #if (!defined AI_BUILD_NO_Q3D_IMPORTER)
-	mImporter.push_back( new Q3DImporter());
+	pimpl->mImporter.push_back( new Q3DImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_B3D_IMPORTER)
 #if (!defined AI_BUILD_NO_B3D_IMPORTER)
-	mImporter.push_back( new B3DImporter());
+	pimpl->mImporter.push_back( new B3DImporter());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_COLLADA_IMPORTER)
 #if (!defined AI_BUILD_NO_COLLADA_IMPORTER)
-	mImporter.push_back( new ColladaLoader());
+	pimpl->mImporter.push_back( new ColladaLoader());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_TERRAGEN_IMPORTER)
 #if (!defined AI_BUILD_NO_TERRAGEN_IMPORTER)
-	mImporter.push_back( new TerragenImporter());
+	pimpl->mImporter.push_back( new TerragenImporter());
 #endif
 #endif
 //#if (!defined AI_BUILD_NO_CSM_IMPORTER)
 //#if (!defined AI_BUILD_NO_CSM_IMPORTER)
 //	mImporter.push_back( new CSMImporter());
 //	mImporter.push_back( new CSMImporter());
 //#endif
 //#endif
 #if (!defined AI_BUILD_NO_3D_IMPORTER)
 #if (!defined AI_BUILD_NO_3D_IMPORTER)
-	mImporter.push_back( new UnrealImporter());
+	pimpl->mImporter.push_back( new UnrealImporter());
 #endif
 #endif
-
-
-
 #if (!defined AI_BUILD_NO_LWS_IMPORTER)
 #if (!defined AI_BUILD_NO_LWS_IMPORTER)
-	mImporter.push_back( new LWSImporter());
+	pimpl->mImporter.push_back( new LWSImporter());
 #endif
 #endif
 
 
-	// ======================================================================
+	// ----------------------------------------------------------------------------
 	// Add an instance of each post processing step here in the order 
 	// Add an instance of each post processing step here in the order 
 	// of sequence it is executed. Steps that are added here are not
 	// of sequence it is executed. Steps that are added here are not
-	// validated - as RegisterPPStep() does - all dependencies must be there.
-	// ======================================================================
-	mPostProcessingSteps.reserve(25);
+	// validated - as RegisterPPStep() does - all dependencies must be given.
+	// ----------------------------------------------------------------------------
+
+	pimpl->mPostProcessingSteps.reserve(25);
 
 
 #if (!defined AI_BUILD_NO_REMOVEVC_PROCESS)
 #if (!defined AI_BUILD_NO_REMOVEVC_PROCESS)
-	mPostProcessingSteps.push_back( new RemoveVCProcess());
+	pimpl->mPostProcessingSteps.push_back( new RemoveVCProcess());
 #endif
 #endif
-
 #if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
 #if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
-	mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
+	pimpl->mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
 #endif
 #endif
-
 #if (!defined AI_BUILD_NO_FINDINSTANCES_PROCESS)
 #if (!defined AI_BUILD_NO_FINDINSTANCES_PROCESS)
-	mPostProcessingSteps.push_back( new FindInstancesProcess());
+	pimpl->mPostProcessingSteps.push_back( new FindInstancesProcess());
+#endif
+#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
+	pimpl->mPostProcessingSteps.push_back( new OptimizeGraphProcess());
+#endif
+#if (!defined AI_BUILD_NO_OPTIMIZEMESHES_PROCESS)
+	pimpl->mPostProcessingSteps.push_back( new OptimizeMeshesProcess());
 #endif
 #endif
-
 #if (!defined AI_BUILD_NO_FINDDEGENERATES_PROCESS)
 #if (!defined AI_BUILD_NO_FINDDEGENERATES_PROCESS)
-	mPostProcessingSteps.push_back( new FindDegeneratesProcess());
+	pimpl->mPostProcessingSteps.push_back( new FindDegeneratesProcess());
 #endif
 #endif
-
-
-	
 #ifndef AI_BUILD_NO_GENUVCOORDS_PROCESS
 #ifndef AI_BUILD_NO_GENUVCOORDS_PROCESS
-	mPostProcessingSteps.push_back( new ComputeUVMappingProcess());
+	pimpl->mPostProcessingSteps.push_back( new ComputeUVMappingProcess());
 #endif
 #endif
 #ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
 #ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
-	mPostProcessingSteps.push_back( new TextureTransformStep());
+	pimpl->mPostProcessingSteps.push_back( new TextureTransformStep());
 #endif
 #endif
-
 #if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
 #if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
-	mPostProcessingSteps.push_back( new PretransformVertices());
+	pimpl->mPostProcessingSteps.push_back( new PretransformVertices());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
 #if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
-	mPostProcessingSteps.push_back( new TriangulateProcess());
+	pimpl->mPostProcessingSteps.push_back( new TriangulateProcess());
 #endif
 #endif
-	
 #if (!defined AI_BUILD_NO_SORTBYPTYPE_PROCESS)
 #if (!defined AI_BUILD_NO_SORTBYPTYPE_PROCESS)
-	mPostProcessingSteps.push_back( new SortByPTypeProcess());
+	pimpl->mPostProcessingSteps.push_back( new SortByPTypeProcess());
 #endif
 #endif
-
 #if (!defined AI_BUILD_NO_FINDINVALIDDATA_PROCESS)
 #if (!defined AI_BUILD_NO_FINDINVALIDDATA_PROCESS)
-	mPostProcessingSteps.push_back( new FindInvalidDataProcess());
+	pimpl->mPostProcessingSteps.push_back( new FindInvalidDataProcess());
 #endif
 #endif
-
 #if (!defined AI_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
 #if (!defined AI_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
-	mPostProcessingSteps.push_back( new FixInfacingNormalsProcess());
+	pimpl->mPostProcessingSteps.push_back( new FixInfacingNormalsProcess());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS)
 #if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS)
-	mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Triangle());
+	pimpl->mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Triangle());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_GENFACENORMALS_PROCESS)
 #if (!defined AI_BUILD_NO_GENFACENORMALS_PROCESS)
-	mPostProcessingSteps.push_back( new GenFaceNormalsProcess());
+	pimpl->mPostProcessingSteps.push_back( new GenFaceNormalsProcess());
 #endif
 #endif
 
 
-
 	// DON'T change the order of these five!
 	// DON'T change the order of these five!
-	mPostProcessingSteps.push_back( new ComputeSpatialSortProcess());
+	pimpl->mPostProcessingSteps.push_back( new ComputeSpatialSortProcess());
 
 
 #if (!defined AI_BUILD_NO_GENVERTEXNORMALS_PROCESS)
 #if (!defined AI_BUILD_NO_GENVERTEXNORMALS_PROCESS)
-	mPostProcessingSteps.push_back( new GenVertexNormalsProcess());
+	pimpl->mPostProcessingSteps.push_back( new GenVertexNormalsProcess());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_CALCTANGENTS_PROCESS)
 #if (!defined AI_BUILD_NO_CALCTANGENTS_PROCESS)
-	mPostProcessingSteps.push_back( new CalcTangentsProcess());
+	pimpl->mPostProcessingSteps.push_back( new CalcTangentsProcess());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_JOINVERTICES_PROCESS)
 #if (!defined AI_BUILD_NO_JOINVERTICES_PROCESS)
-	mPostProcessingSteps.push_back( new JoinVerticesProcess());
+	pimpl->mPostProcessingSteps.push_back( new JoinVerticesProcess());
 #endif
 #endif
 
 
-	mPostProcessingSteps.push_back( new DestroySpatialSortProcess());
-
+	pimpl->mPostProcessingSteps.push_back( new DestroySpatialSortProcess());
 
 
 #if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS)
 #if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS)
-	mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Vertex());
+	pimpl->mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Vertex());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_MAKELEFTHANDED_PROCESS)
 #if (!defined AI_BUILD_NO_MAKELEFTHANDED_PROCESS)
-	mPostProcessingSteps.push_back( new MakeLeftHandedProcess());
+	pimpl->mPostProcessingSteps.push_back( new MakeLeftHandedProcess());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_FLIPUVS_PROCESS)
 #if (!defined AI_BUILD_NO_FLIPUVS_PROCESS)
-	mPostProcessingSteps.push_back( new FlipUVsProcess());
+	pimpl->mPostProcessingSteps.push_back( new FlipUVsProcess());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_FLIPWINDINGORDER_PROCESS)
 #if (!defined AI_BUILD_NO_FLIPWINDINGORDER_PROCESS)
-	mPostProcessingSteps.push_back( new FlipWindingOrderProcess());
+	pimpl->mPostProcessingSteps.push_back( new FlipWindingOrderProcess());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
 #if (!defined AI_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
-	mPostProcessingSteps.push_back( new LimitBoneWeightsProcess());
+	pimpl->mPostProcessingSteps.push_back( new LimitBoneWeightsProcess());
 #endif
 #endif
 #if (!defined AI_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
 #if (!defined AI_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
-	mPostProcessingSteps.push_back( new ImproveCacheLocalityProcess());
+	pimpl->mPostProcessingSteps.push_back( new ImproveCacheLocalityProcess());
 #endif
 #endif
 
 
-
 	// Allocate a SharedPostProcessInfo object and store pointers to it
 	// Allocate a SharedPostProcessInfo object and store pointers to it
 	// in all post-process steps in the list.
 	// in all post-process steps in the list.
-	mPPShared = new SharedPostProcessInfo();
-	for (std::vector<BaseProcess*>::iterator it = mPostProcessingSteps.begin(),
-		 end =  mPostProcessingSteps.end(); it != end; ++it)
+	pimpl->mPPShared = new SharedPostProcessInfo();
+	for (std::vector<BaseProcess*>::iterator it = pimpl->mPostProcessingSteps.begin(), 
+		end =  pimpl->mPostProcessingSteps.end(); it != end; ++it)
 	{
 	{
-		(*it)->SetSharedData(mPPShared);
+		(*it)->SetSharedData(pimpl->mPPShared);
 	}
 	}
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// Destructor. 
+// Destructor of Importer
 Importer::~Importer()
 Importer::~Importer()
 {
 {
 	// Delete all import plugins
 	// Delete all import plugins
-	for( unsigned int a = 0; a < mImporter.size(); a++)
-		delete mImporter[a];
+	for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)
+		delete pimpl->mImporter[a];
 
 
 	// Delete all post-processing plug-ins
 	// Delete all post-processing plug-ins
-	for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++)
-		delete mPostProcessingSteps[a];
+	for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)
+		delete pimpl->mPostProcessingSteps[a];
 
 
 	// Delete the assigned IO handler
 	// Delete the assigned IO handler
-	delete mIOHandler;
+	delete pimpl->mIOHandler;
 
 
 	// Kill imported scene. Destructors should do that recursivly
 	// Kill imported scene. Destructors should do that recursivly
-	delete mScene;
+	delete pimpl->mScene;
 
 
 	// Delete shared post-processing data
 	// Delete shared post-processing data
-	delete mPPShared;
+	delete pimpl->mPPShared;
+
+	// and finally the pimpl itself
+	delete pimpl;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-//	Copy constructor - copies the config of another Importer, not the scene
+// Copy constructor - copies the config of another Importer, not the scene
 Importer::Importer(const Importer &other)
 Importer::Importer(const Importer &other)
 {
 {
-	// Call the default constructor
 	new(this) Importer();
 	new(this) Importer();
 
 
-	// Copy the property table
-	mIntProperties    = other.mIntProperties;
-	mFloatProperties  = other.mFloatProperties;
-	mStringProperties = other.mStringProperties;
+	pimpl->mIntProperties = other.pimpl->mIntProperties;
+	pimpl->mFloatProperties = other.pimpl->mFloatProperties;
+	pimpl->mStringProperties = other.pimpl->mStringProperties;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -504,11 +500,12 @@ Importer::Importer(const Importer &other)
 aiReturn Importer::RegisterLoader(BaseImporter* pImp)
 aiReturn Importer::RegisterLoader(BaseImporter* pImp)
 {
 {
 	ai_assert(NULL != pImp);
 	ai_assert(NULL != pImp);
-	// ======================================================================
+
+	// --------------------------------------------------------------------
 	// Check whether we would have two loaders for the same file extension 
 	// Check whether we would have two loaders for the same file extension 
-	// This is absolutely OK, but we should warn the developer of the new
-	// loader that his code will propably never be called.
-	// ======================================================================
+	// This is absolutely OK but we should warn the developer of the new
+	// loader that his code will probably never be called.
+	// --------------------------------------------------------------------
 	std::string st;
 	std::string st;
 	pImp->GetExtensionList(st);
 	pImp->GetExtensionList(st);
 
 
@@ -524,31 +521,26 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
 #endif
 #endif
 
 
 	// add the loader
 	// add the loader
-	mImporter.push_back(pImp);
+	pimpl->mImporter.push_back(pImp);
 	DefaultLogger::get()->info("Registering custom importer: " + st);
 	DefaultLogger::get()->info("Registering custom importer: " + st);
 	return AI_SUCCESS;
 	return AI_SUCCESS;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// Unregister a custom loader
+// Unregister a custom loader plugin
 aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
 aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
 {
 {
 	ai_assert(NULL != pImp);
 	ai_assert(NULL != pImp);
-	for (std::vector<BaseImporter*>::iterator
-		it = mImporter.begin(),end = mImporter.end();
-		it != end;++it)
-	{
-		if (pImp == (*it))
-		{
-			mImporter.erase(it);
-
-			std::string st;
-			pImp->GetExtensionList(st);
-			DefaultLogger::get()->info("Unregistering custom importer: " + st);
-			return AI_SUCCESS;
-		}
+	std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),pimpl->mImporter.end(),pImp);
+	if (it != pimpl->mImporter.end())	{
+		pimpl->mImporter.erase(it);
+
+		std::string st;
+		pImp->GetExtensionList(st);
+		DefaultLogger::get()->info("Unregistering custom importer: " + st);
+		return AI_SUCCESS;
 	}
 	}
-	DefaultLogger::get()->warn("Unable to remove importer: importer not found");
+	DefaultLogger::get()->warn("Unable to remove importer: importer object not found in table");
 	return AI_FAILURE;
 	return AI_FAILURE;
 }
 }
 
 
@@ -560,30 +552,30 @@ void Importer::SetIOHandler( IOSystem* pIOHandler)
 	if (!pIOHandler)
 	if (!pIOHandler)
 	{
 	{
 		// Release pointer in the possession of the caller
 		// Release pointer in the possession of the caller
-		// delete mIOHandler; 
-		mIOHandler = new DefaultIOSystem();
-		mIsDefaultHandler = true;
+		pimpl->mIOHandler = new DefaultIOSystem();
+		pimpl->mIsDefaultHandler = true;
 	}
 	}
 	// Otherwise register the custom handler
 	// Otherwise register the custom handler
-	else if (mIOHandler != pIOHandler)
+	else if (pimpl->mIOHandler != pIOHandler)
 	{
 	{
-		delete mIOHandler;
-		mIOHandler = pIOHandler;
-		mIsDefaultHandler = false;
+		delete pimpl->mIOHandler;
+		pimpl->mIOHandler = pIOHandler;
+		pimpl->mIsDefaultHandler = false;
 	}
 	}
-	return;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
+// Get the currently set IO handler
 IOSystem* Importer::GetIOHandler()
 IOSystem* Importer::GetIOHandler()
 {
 {
-	return mIOHandler;
+	return pimpl->mIOHandler;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
+// Check whether a custom IO handler is currently set
 bool Importer::IsDefaultIOHandler()
 bool Importer::IsDefaultIOHandler()
 {
 {
-	return mIsDefaultHandler;
+	return pimpl->mIsDefaultHandler;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -604,37 +596,42 @@ bool _ValidateFlags(unsigned int pFlags)
 // Free the current scene
 // Free the current scene
 void Importer::FreeScene( )
 void Importer::FreeScene( )
 {
 {
-	delete mScene;
-	mScene = NULL;
+	delete pimpl->mScene;
+	pimpl->mScene = NULL;
+
+	pimpl->mErrorString = "";
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the current error string, if any
 // Get the current error string, if any
-const std::string& Importer::GetErrorString() const 
+const char* Importer::GetErrorString() const 
 { 
 { 
-	return mErrorString;
+	 /* Must remain valid as long as ReadFile() or FreeFile() are not called */
+	return pimpl->mErrorString.c_str();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Enable extra-verbose mode
 // Enable extra-verbose mode
 void Importer::SetExtraVerbose(bool bDo)
 void Importer::SetExtraVerbose(bool bDo)
 {
 {
-	bExtraVerbose = bDo;
+	pimpl->bExtraVerbose = bDo;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the current scene
 // Get the current scene
 const aiScene* Importer::GetScene() const
 const aiScene* Importer::GetScene() const
 {
 {
-	return mScene;
+	return pimpl->mScene;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// Orphan the current scene
+// Orphan the current scene and return it.
 aiScene* Importer::GetOrphanedScene()
 aiScene* Importer::GetOrphanedScene()
 {
 {
-	aiScene* s = mScene;
-	mScene = NULL;
+	aiScene* s = pimpl->mScene;
+	pimpl->mScene = NULL;
+
+	pimpl->mErrorString = ""; /* reset error string */
 	return s;
 	return s;
 }
 }
 
 
@@ -646,24 +643,22 @@ bool Importer::ValidateFlags(unsigned int pFlags)
 	if(!_ValidateFlags(pFlags))
 	if(!_ValidateFlags(pFlags))
 		return false;
 		return false;
 
 
-	// ValidateDS does not anymore occur in the pp list, it plays
-	// an awesome extra role ...
+	// ValidateDS does not anymore occur in the pp list, it plays an awesome extra role ...
 #ifdef AI_BUILD_NO_VALIDATEDS_PROCESS
 #ifdef AI_BUILD_NO_VALIDATEDS_PROCESS
 	if (pFlags & aiProcess_ValidateDataStructure)
 	if (pFlags & aiProcess_ValidateDataStructure)
 		return false;
 		return false;
 #endif
 #endif
 	pFlags &= ~aiProcess_ValidateDataStructure;
 	pFlags &= ~aiProcess_ValidateDataStructure;
 
 
-	// Now iterate through all bits which are set in
-	// the flags and check whether we find at least
+	// Now iterate through all bits which are set in the flags and check whether we find at least
 	// one pp plugin which handles it.
 	// one pp plugin which handles it.
 	for (unsigned int mask = 1; mask < (1 << (sizeof(unsigned int)*8-1));mask <<= 1) {
 	for (unsigned int mask = 1; mask < (1 << (sizeof(unsigned int)*8-1));mask <<= 1) {
 		
 		
 		if (pFlags & mask) {
 		if (pFlags & mask) {
 		
 		
 			bool have = false;
 			bool have = false;
-			for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++)	{
-				if (mPostProcessingSteps[a]-> IsActive(mask) ) {
+			for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)	{
+				if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) {
 				
 				
 					have = true;
 					have = true;
 					break;
 					break;
@@ -680,42 +675,41 @@ bool Importer::ValidateFlags(unsigned int pFlags)
 // Reads the given file and returns its contents if successful. 
 // Reads the given file and returns its contents if successful. 
 const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 {
 {
-	// In debug builds, run a basic flag validation
+	// In debug builds: run a basic flag validation
 	ai_assert(_ValidateFlags(pFlags));
 	ai_assert(_ValidateFlags(pFlags));
-
 	const std::string pFile(_pFile);
 	const std::string pFile(_pFile);
 
 
-	// ======================================================================
+	// ----------------------------------------------------------------------
 	// Put a large try block around everything to catch all std::exception's
 	// Put a large try block around everything to catch all std::exception's
 	// that might be thrown by STL containers or by new(). 
 	// that might be thrown by STL containers or by new(). 
 	// ImportErrorException's are throw by ourselves and caught elsewhere.
 	// ImportErrorException's are throw by ourselves and caught elsewhere.
-	// ======================================================================
+	//-----------------------------------------------------------------------
 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 	try
 	try
 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 	{
 	{
 		// Check whether this Importer instance has already loaded
 		// Check whether this Importer instance has already loaded
 		// a scene. In this case we need to delete the old one
 		// a scene. In this case we need to delete the old one
-		if (mScene)
+		if (pimpl->mScene)
 		{
 		{
 			DefaultLogger::get()->debug("Deleting previous scene");
 			DefaultLogger::get()->debug("Deleting previous scene");
 			FreeScene();
 			FreeScene();
 		}
 		}
 
 
 		// First check if the file is accessable at all
 		// First check if the file is accessable at all
-		if( !mIOHandler->Exists( pFile))
+		if( !pimpl->mIOHandler->Exists( pFile))
 		{
 		{
-			mErrorString = "Unable to open file \"" + pFile + "\".";
-			DefaultLogger::get()->error(mErrorString);
+			pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
+			DefaultLogger::get()->error(pimpl->mErrorString);
 			return NULL;
 			return NULL;
 		}
 		}
 
 
 		// Find an worker class which can handle the file
 		// Find an worker class which can handle the file
 		BaseImporter* imp = NULL;
 		BaseImporter* imp = NULL;
-		for( unsigned int a = 0; a < mImporter.size(); a++)	{
+		for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)	{
 
 
-			if( mImporter[a]->CanRead( pFile, mIOHandler, false)) {
-				imp = mImporter[a];
+			if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
+				imp = pimpl->mImporter[a];
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -726,10 +720,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 			std::string::size_type s = pFile.find_last_of('.');
 			std::string::size_type s = pFile.find_last_of('.');
 			if (s != std::string::npos) {
 			if (s != std::string::npos) {
 				DefaultLogger::get()->info("File extension now known, trying signature-based detection");
 				DefaultLogger::get()->info("File extension now known, trying signature-based detection");
-				for( unsigned int a = 0; a < mImporter.size(); a++)	{
+				for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)	{
 
 
-					if( mImporter[a]->CanRead( pFile, mIOHandler, true)) {
-						imp = mImporter[a];
+					if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
+						imp = pimpl->mImporter[a];
 						break;
 						break;
 					}
 					}
 				}
 				}
@@ -737,8 +731,8 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 			// Put a proper error message if no suitable importer was found
 			// Put a proper error message if no suitable importer was found
 			if( !imp)
 			if( !imp)
 			{
 			{
-				mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
-				DefaultLogger::get()->error(mErrorString);
+				pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
+				DefaultLogger::get()->error(pimpl->mErrorString);
 				return NULL;
 				return NULL;
 			}
 			}
 		}
 		}
@@ -746,10 +740,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 		// Dispatch the reading to the worker class for this format
 		// Dispatch the reading to the worker class for this format
 		DefaultLogger::get()->info("Found a matching importer for this file format");
 		DefaultLogger::get()->info("Found a matching importer for this file format");
 		imp->SetupProperties( this );
 		imp->SetupProperties( this );
-		mScene = imp->ReadFile( pFile, mIOHandler);
+		pimpl->mScene = imp->ReadFile( pFile, pimpl->mIOHandler);
 
 
 		// If successful, apply all active post processing steps to the imported data
 		// If successful, apply all active post processing steps to the imported data
-		if( mScene)
+		if( pimpl->mScene)
 		{
 		{
 #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS
 #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS
 			// The ValidateDS process is an exception. It is executed first,
 			// The ValidateDS process is an exception. It is executed first,
@@ -758,18 +752,18 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 			{
 			{
 				ValidateDSProcess ds;
 				ValidateDSProcess ds;
 				ds.ExecuteOnScene (this);
 				ds.ExecuteOnScene (this);
-				if (!mScene)
+				if (!pimpl->mScene)
 					return NULL;
 					return NULL;
 			}
 			}
 #endif // no validation
 #endif // no validation
 
 
 			// Preprocess the scene 
 			// Preprocess the scene 
-			ScenePreprocessor pre(mScene);
+			ScenePreprocessor pre(pimpl->mScene);
 			pre.ProcessScene();
 			pre.ProcessScene();
 
 
 			DefaultLogger::get()->info("Import successful, entering postprocessing-steps");
 			DefaultLogger::get()->info("Import successful, entering postprocessing-steps");
 #ifdef _DEBUG
 #ifdef _DEBUG
-			if (bExtraVerbose)
+			if (pimpl->bExtraVerbose)
 			{
 			{
 #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS
 #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS
 
 
@@ -781,17 +775,19 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 				pFlags |= aiProcess_ValidateDataStructure;
 				pFlags |= aiProcess_ValidateDataStructure;
 			}
 			}
 #else
 #else
-			if (bExtraVerbose)DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
+			if (pimpl->bExtraVerbose)
+				DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
 #endif // ! DEBUG
 #endif // ! DEBUG
-			for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++)
+			for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)
 			{
 			{
-				BaseProcess* process = mPostProcessingSteps[a];
+				BaseProcess* process = pimpl->mPostProcessingSteps[a];
 				if( process->IsActive( pFlags))
 				if( process->IsActive( pFlags))
 				{
 				{
 					process->SetupProperties( this );
 					process->SetupProperties( this );
 					process->ExecuteOnScene	( this );
 					process->ExecuteOnScene	( this );
 				}
 				}
-				if( !mScene)break; 
+				if( !pimpl->mScene)
+					break; 
 #ifdef _DEBUG
 #ifdef _DEBUG
 
 
 #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS
 #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS
@@ -800,13 +796,13 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 
 
 				// If the extra verbose mode is active execute the
 				// If the extra verbose mode is active execute the
 				// VaidateDataStructureStep again after each step
 				// VaidateDataStructureStep again after each step
-				if (bExtraVerbose)
+				if (pimpl->bExtraVerbose)
 				{
 				{
 					DefaultLogger::get()->debug("Extra verbose: revalidating data structures");
 					DefaultLogger::get()->debug("Extra verbose: revalidating data structures");
 					
 					
 					ValidateDSProcess ds; 
 					ValidateDSProcess ds; 
 					ds.ExecuteOnScene (this);
 					ds.ExecuteOnScene (this);
-					if( !mScene)
+					if( !pimpl->mScene)
 					{
 					{
 						DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures");
 						DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures");
 						break; 
 						break; 
@@ -816,29 +812,29 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 			}
 			}
 		}
 		}
 		// if failed, extract the error string
 		// if failed, extract the error string
-		else if( !mScene)
-			mErrorString = imp->GetErrorText();
+		else if( !pimpl->mScene)
+			pimpl->mErrorString = imp->GetErrorText();
 
 
 		// clear any data allocated by post-process steps
 		// clear any data allocated by post-process steps
-		mPPShared->Clean();
+		pimpl->mPPShared->Clean();
 	}
 	}
 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 	catch (std::exception &e)
 	catch (std::exception &e)
 	{
 	{
 #if (defined _MSC_VER) &&	(defined _CPPRTTI) 
 #if (defined _MSC_VER) &&	(defined _CPPRTTI) 
 		// if we have RTTI get the full name of the exception that occured
 		// if we have RTTI get the full name of the exception that occured
-		mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
+		pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
 #else
 #else
-		mErrorString = std::string("std::exception: ") + e.what();
+		pimpl->mErrorString = std::string("std::exception: ") + e.what();
 #endif
 #endif
 
 
-		DefaultLogger::get()->error(mErrorString);
-		delete mScene;mScene = NULL;
+		DefaultLogger::get()->error(pimpl->mErrorString);
+		delete pimpl->mScene; pimpl->mScene = NULL;
 	}
 	}
 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 
 
 	// either successful or failure - the pointer expresses it anyways
 	// either successful or failure - the pointer expresses it anyways
-	return mScene;
+	return pimpl->mScene;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -852,12 +848,11 @@ bool Importer::IsExtensionSupported(const char* szExtension)
 BaseImporter* Importer::FindLoader (const char* _szExtension)
 BaseImporter* Importer::FindLoader (const char* _szExtension)
 {
 {
 	const std::string szExtension(_szExtension);
 	const std::string szExtension(_szExtension);
-	for (std::vector<BaseImporter*>::const_iterator
-		i =  mImporter.begin();
-		i != mImporter.end();++i)
+	for (std::vector<BaseImporter*>::const_iterator i =  pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)
 	{
 	{
 		// pass the file extension to the CanRead(..,NULL)-method
 		// pass the file extension to the CanRead(..,NULL)-method
-		if ((*i)->CanRead(szExtension,NULL,false))return *i;
+		if ((*i)->CanRead(szExtension,NULL,false))
+			return *i;
 	}
 	}
 	return NULL;
 	return NULL;
 }
 }
@@ -867,10 +862,8 @@ BaseImporter* Importer::FindLoader (const char* _szExtension)
 void Importer::GetExtensionList(aiString& szOut)
 void Importer::GetExtensionList(aiString& szOut)
 {
 {
 	unsigned int iNum = 0;
 	unsigned int iNum = 0;
-	std::string tmp; // todo: Rewrite baseImporter::GetExtensionList to use aiString, too
-	for (std::vector<BaseImporter*>::const_iterator
-		i =  mImporter.begin();
-		i != mImporter.end();++i,++iNum)
+	std::string tmp; 
+	for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i,++iNum)
 	{
 	{
 		// Insert a comma as delimiter character
 		// Insert a comma as delimiter character
 		// FIX: to take lazy loader implementations into account, we are
 		// FIX: to take lazy loader implementations into account, we are
@@ -889,7 +882,7 @@ void Importer::GetExtensionList(aiString& szOut)
 void Importer::SetPropertyInteger(const char* szName, int iValue, 
 void Importer::SetPropertyInteger(const char* szName, int iValue, 
 	bool* bWasExisting /*= NULL*/)
 	bool* bWasExisting /*= NULL*/)
 {
 {
-	SetGenericProperty<int>(mIntProperties, szName,iValue,bWasExisting);	
+	SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue,bWasExisting);	
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -897,7 +890,7 @@ void Importer::SetPropertyInteger(const char* szName, int iValue,
 void Importer::SetPropertyFloat(const char* szName, float iValue, 
 void Importer::SetPropertyFloat(const char* szName, float iValue, 
 	bool* bWasExisting /*= NULL*/)
 	bool* bWasExisting /*= NULL*/)
 {
 {
-	SetGenericProperty<float>(mFloatProperties, szName,iValue,bWasExisting);	
+	SetGenericProperty<float>(pimpl->mFloatProperties, szName,iValue,bWasExisting);	
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -905,7 +898,7 @@ void Importer::SetPropertyFloat(const char* szName, float iValue,
 void Importer::SetPropertyString(const char* szName, const std::string& value, 
 void Importer::SetPropertyString(const char* szName, const std::string& value, 
 	bool* bWasExisting /*= NULL*/)
 	bool* bWasExisting /*= NULL*/)
 {
 {
-	SetGenericProperty<std::string>(mStringProperties, szName,value,bWasExisting);	
+	SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value,bWasExisting);	
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -913,7 +906,7 @@ void Importer::SetPropertyString(const char* szName, const std::string& value,
 int Importer::GetPropertyInteger(const char* szName, 
 int Importer::GetPropertyInteger(const char* szName, 
 	int iErrorReturn /*= 0xffffffff*/) const
 	int iErrorReturn /*= 0xffffffff*/) const
 {
 {
-	return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
+	return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -921,7 +914,7 @@ int Importer::GetPropertyInteger(const char* szName,
 float Importer::GetPropertyFloat(const char* szName, 
 float Importer::GetPropertyFloat(const char* szName, 
 	float iErrorReturn /*= 10e10*/) const
 	float iErrorReturn /*= 10e10*/) const
 {
 {
-	return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
+	return GetGenericProperty<float>(pimpl->mFloatProperties,szName,iErrorReturn);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -929,7 +922,7 @@ float Importer::GetPropertyFloat(const char* szName,
 const std::string& Importer::GetPropertyString(const char* szName, 
 const std::string& Importer::GetPropertyString(const char* szName, 
 	const std::string& iErrorReturn /*= ""*/) const
 	const std::string& iErrorReturn /*= ""*/) const
 {
 {
-	return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
+	return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -948,9 +941,13 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
 void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
 void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
 {
 {
 	in = aiMemoryInfo();
 	in = aiMemoryInfo();
+	aiScene* mScene = pimpl->mScene;
 
 
 	// return if we have no scene loaded
 	// return if we have no scene loaded
-	if (!this->mScene)return;
+	if (!pimpl->mScene)
+		return;
+
+
 	in.total = sizeof(aiScene);
 	in.total = sizeof(aiScene);
 
 
 	// add all meshes
 	// add all meshes

+ 3 - 1
code/JoinVerticesProcess.cpp

@@ -44,8 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  */
 
 
 #include "AssimpPCH.h"
 #include "AssimpPCH.h"
+#ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS
 
 
-// internal headers
 #include "JoinVerticesProcess.h"
 #include "JoinVerticesProcess.h"
 #include "ProcessHelper.h"
 #include "ProcessHelper.h"
 
 
@@ -412,3 +412,5 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
 	}
 	}
 	return pMesh->mNumVertices;
 	return pMesh->mNumVertices;
 }
 }
+
+#endif // !! ASSIMP_BUILD_NO_JOINVERTICES_PROCESS

+ 347 - 0
code/OptimizeGraph.cpp

@@ -0,0 +1,347 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (ASSIMP)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development Team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the following 
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the ASSIMP team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the ASSIMP Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+/** @file  OptimizeGraph.cpp
+ *  @brief Implementation of the aiProcess_OptimizGraph step
+ */
+
+#include "AssimpPCH.h"
+#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
+
+using namespace Assimp;
+#include "OptimizeGraph.h"
+#include "ProcessHelper.h"
+#include "SceneCombiner.h"
+
+#define AI_RESERVED_NODE_NAME "$Reserved_And_Evil"
+
+/* AI_OG_USE_HASHING enables the use of hashing to speed-up std::set lookups.
+ * The unhashed variant should be faster, except for *very* large data sets
+ */
+#ifdef AI_OG_USE_HASHING
+	// Use our standard hashing function to compute the hash 
+#	define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length)
+#else
+	// Otherwise hope that std::string will utilize a static buffer 
+	// for shorter node names. This would avoid endless heap copying.
+#	define AI_OG_GETKEY(str) std::string(str.data)
+#endif
+
+// ------------------------------------------------------------------------------------------------
+// Constructor to be privately used by Importer
+OptimizeGraphProcess::OptimizeGraphProcess()
+{}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well
+OptimizeGraphProcess::~OptimizeGraphProcess()
+{}
+
+// ------------------------------------------------------------------------------------------------
+// Returns whether the processing step is present in the given flag field.
+bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const
+{
+	return (0 != (pFlags & aiProcess_OptimizeGraph));
+}
+
+// ------------------------------------------------------------------------------------------------
+// Setup properties for the postprocessing step
+void OptimizeGraphProcess::SetupProperties(const Importer* pImp)
+{	
+	// Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST
+	std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,"");
+	AddLockedNodeList(tmp);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Collect new children
+void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes)
+{
+	nodes_in += nd->mNumChildren;
+
+	// Process children
+	std::list<aiNode*> child_nodes;
+	for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
+
+		CollectNewChildren(nd->mChildren[i],child_nodes);
+		nd->mChildren[i] = NULL;
+	}
+
+	// Check whether we need this node; if not we can replace it by our own children (warn, danger of incest).
+	if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end() ) {
+		for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
+
+			if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) {
+				(*it)->mTransformation = nd->mTransformation * (*it)->mTransformation;
+				nodes.push_back(*it);
+
+				it = child_nodes.erase(it);
+				continue;
+			}
+			++it;
+		}
+
+		if (nd->mNumMeshes || child_nodes.size()) { 
+			nodes.push_back(nd);
+		}
+		else {
+			delete nd; /* bye, node */
+			return;
+		}
+	}
+	else {
+		
+		// Retain our current position in the hierarchy
+		nodes.push_back(nd);
+
+		// Now check for possible optimizations in our list of child nodes. join as many as possible
+		aiNode* join_master = NULL;
+		aiMatrix4x4 inv;
+
+		const LockedSetType::const_iterator end = locked.end();
+
+		std::list<aiNode*> join;
+		for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();)	{
+			aiNode* child = *it;
+			if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) {
+			
+				// There may be no instanced meshes
+				unsigned int n = 0;
+				for (; n < child->mNumMeshes;++n) {
+					if (meshes[child->mMeshes[n]] > 1) {
+						break;
+					}
+				}
+				if (n == child->mNumMeshes) {
+
+					if (!join_master) {
+						join_master = child;
+						inv = join_master->mTransformation;
+						inv.Inverse();
+					}
+					else {
+
+						child->mTransformation = inv * child->mTransformation ;
+
+						join.push_back(child);	
+						it = child_nodes.erase(it);
+						continue;
+					}
+				}
+			}
+			++it;
+		}
+		if (join_master && join.size()) {
+			join_master->mName.length = sprintf(join_master->mName.data,"$MergedNode_%i",count_merged++);
+
+			unsigned int out_meshes = 0;
+			for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
+				out_meshes += (*it)->mNumMeshes;
+			}
+			
+			// copy all mesh references in one array
+			if (out_meshes) {
+				unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes;
+				for (unsigned int n = 0; n < join_master->mNumMeshes;++n) {
+					*tmp++ = join_master->mMeshes[n];		
+				}
+
+				for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
+					for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) {
+
+						*tmp = (*it)->mMeshes[n];
+						aiMesh* mesh = mScene->mMeshes[*tmp++];
+
+						// manually move the mesh into the right coordinate system
+						const aiMatrix3x3 IT = aiMatrix3x3( (*it)->mTransformation ).Inverse().Transpose(); 
+						for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
+						
+							mesh->mVertices[a] *= (*it)->mTransformation;
+
+							if (mesh->HasNormals())
+								mesh->mNormals[a] *= IT;
+
+							if (mesh->HasTangentsAndBitangents()) {
+								mesh->mTangents[a] *= IT;
+								mesh->mBitangents[a] *= IT;
+							}
+						}
+					}
+					delete *it; // bye, node
+				}
+				delete[] join_master->mMeshes;
+				join_master->mMeshes = meshes;
+				join_master->mNumMeshes += out_meshes;
+			}
+		}
+	}
+	// reassign children if something changed
+	if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) {
+
+		delete[] nd->mChildren;
+
+		if (child_nodes.size())
+			nd->mChildren = new aiNode*[child_nodes.size()];
+		else nd->mChildren = NULL;
+	}
+
+	nd->mNumChildren = child_nodes.size();
+
+	aiNode** tmp = nd->mChildren;
+	for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
+		aiNode* node = *tmp++ = *it;
+		node->mParent = nd;
+	}
+
+	nodes_out += child_nodes.size();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Execute the postprocessing step on the given scene
+void OptimizeGraphProcess::Execute( aiScene* pScene)
+{
+	DefaultLogger::get()->debug("OptimizeGraphProcess begin");
+	nodes_in = nodes_out = count_merged = 0;
+	mScene = pScene;
+
+	meshes.resize(pScene->mNumMeshes,0);
+	FindInstancedMeshes(pScene->mRootNode);
+
+	// build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it
+	locked.clear();
+	for (std::list<std::string>::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) {
+#ifdef AI_OG_USE_HASHING
+		locked.insert(SuperFastHash((*it).c_str()));
+#else
+		locked.insert(*it);
+#endif
+	}
+
+	for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {
+		for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) {
+		
+			aiNodeAnim* anim = pScene->mAnimations[i]->mChannels[a];
+			locked.insert(AI_OG_GETKEY(anim->mNodeName));
+		}
+	}
+
+	for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
+		for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) {
+		
+			aiBone* bone = pScene->mMeshes[i]->mBones[a];
+			locked.insert(AI_OG_GETKEY(bone->mName));
+
+			// HACK: Meshes referencing bones may not be transformed; we need to look them.
+			// The easiest way to do this is to increase their reference counters ...
+			meshes[i] += 2;
+		}
+	}
+
+	for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {
+		aiCamera* cam = pScene->mCameras[i];
+		locked.insert(AI_OG_GETKEY(cam->mName));
+	}
+
+	for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
+		aiLight* lgh = pScene->mLights[i];
+		locked.insert(AI_OG_GETKEY(lgh->mName));
+	}
+
+	// Insert a dummy master node and make it read-only
+	aiNode* dummy_root = new aiNode(AI_RESERVED_NODE_NAME);
+	locked.insert(AI_OG_GETKEY(dummy_root->mName));
+
+	const aiString prev = pScene->mRootNode->mName;
+	pScene->mRootNode->mParent = dummy_root;
+
+	dummy_root->mChildren = new aiNode*[dummy_root->mNumChildren = 1];
+	dummy_root->mChildren[0] = pScene->mRootNode;
+
+	// Do our recursive processing of scenegraph nodes. For each node collect
+	// a fully new list of children and allow their children to place themselves
+	// on the same hierarchy layer as their parents.
+	std::list<aiNode*> nodes;
+	CollectNewChildren (dummy_root,nodes);
+
+	ai_assert(nodes.size() == 1);
+
+	if (dummy_root->mNumChildren > 1) {
+		pScene->mRootNode = dummy_root;
+	
+		// Keep the dummy node but assign the name of the old root node to it
+		pScene->mRootNode->mName = prev;
+	}
+	else {
+		
+		// Remove the dummy root node again.
+		pScene->mRootNode = dummy_root->mChildren[0];
+
+		dummy_root->mChildren[0] = NULL;
+		delete dummy_root;
+	}
+
+	pScene->mRootNode->mParent = NULL;
+	if (!DefaultLogger::isNullLogger()) {
+		if ( nodes_in != nodes_out) {
+
+			char buf[512];
+			sprintf(buf,"OptimizeGraphProcess finished; Input nodes: %i, Output nodes: %i",nodes_in,nodes_out);
+			DefaultLogger::get()->info(buf);
+		}
+		else DefaultLogger::get()->debug("OptimizeGraphProcess finished");
+	}
+	meshes.clear();
+	locked.clear();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Buidl a LUT of all instanced meshes
+void OptimizeGraphProcess::FindInstancedMeshes (aiNode* pNode)
+{
+	for (unsigned int i = 0; i < pNode->mNumMeshes;++i) {
+		++meshes[pNode->mMeshes[i]]; 
+	}
+
+	for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
+		FindInstancedMeshes(pNode->mChildren[i]);
+}
+
+#endif // !! ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS

+ 147 - 0
code/OptimizeGraph.h

@@ -0,0 +1,147 @@
+/*
+Open Asset Import Library (ASSIMP)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development Team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the ASSIMP team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the ASSIMP Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file  OptimizeGraph.h
+ *  @brief Declares a post processing step to optimize the scenegraph
+ */
+#ifndef AI_OPTIMIZEGRAPHPROCESS_H_INC
+#define AI_OPTIMIZEGRAPHPROCESS_H_INC
+
+#include "BaseProcess.h"
+#include "ProcessHelper.h"
+#include "../include/aiTypes.h"
+
+struct aiMesh;
+class OptimizeGraphProcessTest;
+namespace Assimp	{
+
+// -----------------------------------------------------------------------------
+/** @brief Postprocessing step to optimize the scenegraph
+ *
+ *  The implementation tries to merge nodes, even if they use different
+ *  transformations. Animations are preserved. 
+ *
+ *  @see aiProcess_OptimizeGraph for a detailed description of the
+ *  algorithm being applied.
+ */
+class ASSIMP_API OptimizeGraphProcess : public BaseProcess
+{
+	friend class Importer;
+	friend class ::OptimizeGraphProcessTest;
+
+protected:
+	/** Constructor to be privately used by Importer */
+	OptimizeGraphProcess();
+
+	/** Destructor, private as well */
+	~OptimizeGraphProcess();
+
+public:
+	// -------------------------------------------------------------------
+	bool IsActive( unsigned int pFlags) const;
+
+	// -------------------------------------------------------------------
+	void Execute( aiScene* pScene);
+	
+	// -------------------------------------------------------------------
+	void SetupProperties(const Importer* pImp);
+
+
+	// -------------------------------------------------------------------
+	/** @brief Add a list of node names to be locked and not modified.
+	 *  @param in List of nodes. See #AI_CONFIG_PP_OG_EXCLUDE_LIST for
+	 *    format explanations.
+	 */
+	inline void AddLockedNodeList(std::string& in)
+	{
+		ConvertListToStrings (in,locked_nodes);
+	}
+
+	// -------------------------------------------------------------------
+	/** @brief Add another node to be locked and not modified.
+	 *  @param name Name to be locked
+	 */
+	inline void AddLockedNode(std::string& name)
+	{
+		locked_nodes.push_back(name);
+	}
+
+	// -------------------------------------------------------------------
+	/** @brief Rmeove a node from the list of locked nodes.
+	 *  @param name Name to be unlocked
+	 */
+	inline void RemoveLockedNode(std::string& name)
+	{
+		locked_nodes.remove(name);
+	}
+
+protected:
+
+	void CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes);
+	void FindInstancedMeshes (aiNode* pNode);
+
+private:
+
+#ifdef AI_OG_USE_HASHING
+	typedef std::set<unsigned int> LockedSetType;
+#else
+	typedef std::set<std::string> LockedSetType;
+#endif
+
+
+	//! Scene we're working with
+	aiScene* mScene;
+
+	//! List of locked names. Stored is the hash of the name
+	LockedSetType locked;
+
+	//! List of nodes to be locked in addition to those with animations, lights or cameras assigned.
+	std::list<std::string> locked_nodes;
+
+	//! Node counters for logging purposes
+	unsigned int nodes_in,nodes_out, count_merged;
+
+	//! Reference counters for meshes
+	std::vector<unsigned int> meshes;
+};
+
+} // end of namespace Assimp
+
+#endif // AI_OPTIMIZEGRAPHPROCESS_H_INC

+ 239 - 0
code/OptimizeMeshes.cpp

@@ -0,0 +1,239 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (ASSIMP)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development Team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the following 
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the ASSIMP team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the ASSIMP Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+/** @file  OptimizeMeshes.cpp
+ *  @brief Implementation of the aiProcess_OptimizeMeshes step
+ */
+
+#include "AssimpPCH.h"
+#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
+
+using namespace Assimp;
+#include "OptimizeMeshes.h"
+#include "ProcessHelper.h"
+#include "SceneCombiner.h"
+
+// ------------------------------------------------------------------------------------------------
+// Constructor to be privately used by Importer
+OptimizeMeshesProcess::OptimizeMeshesProcess()
+: pts (false)
+, max_verts (0xffffffff)
+, max_faces (0xffffffff)
+{}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well
+OptimizeMeshesProcess::~OptimizeMeshesProcess()
+{}
+
+// ------------------------------------------------------------------------------------------------
+// Returns whether the processing step is present in the given flag field.
+bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const
+{
+	// Our behaviour needs to be different if the SortByPType or SplitLargeMeshes
+	// steps are active. Thus we need to query their flags here and store the
+	// information, although we're breaking const-correctness. 
+	// That's a serious design flaw, consider redesign.
+	if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
+		pts = (0 != (pFlags & aiProcess_SortByPType));
+		max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : 0;
+		return true;
+	}
+	return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Setup properties for the postprocessing step
+void OptimizeMeshesProcess::SetupProperties(const Importer* pImp)
+{
+	if (max_verts == 0xdeadbeef /* magic hack */) {
+		max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
+		max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+// Execute step
+void OptimizeMeshesProcess::Execute( aiScene* pScene)
+{
+	const unsigned int num_old = pScene->mNumMeshes;
+	if (num_old <= 1) {
+		DefaultLogger::get()->debug("Skipping OptimizeMeshesProcess");
+		return;
+	}
+
+	DefaultLogger::get()->debug("OptimizeMeshesProcess begin");
+	mScene = pScene;
+
+	merge_list.reserve(pScene->mNumMeshes);
+	output.reserve(pScene->mNumMeshes);
+
+	// Prepare lookup tables
+	meshes.resize(pScene->mNumMeshes);
+	FindInstancedMeshes(pScene->mRootNode);
+	if (max_verts == 0xdeadbeef) /* undo the magic hack */
+		max_verts = 0xffffffff;
+
+	// ... instanced meshes are immediately processed and added to the output list
+	for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) {
+		meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]);
+
+		if (meshes[i].instance_cnt > 1 && meshes[i].output_id == 0xffffffff) {
+			meshes[i].output_id = n++;
+			output.push_back(mScene->mMeshes[i]);
+		}
+	}
+
+	// and process all nodes in the scenegraoh recursively
+	ProcessNode(pScene->mRootNode);
+	if (!output.size()) {
+		throw new ImportErrorException("OptimizeMeshes: No meshes remaining; there's definitely something wrong");
+	}
+
+	meshes.clear();
+	ai_assert(output.size() <= num_old);
+
+	mScene->mNumMeshes = output.size();
+	std::copy(output.begin(),output.end(),mScene->mMeshes);
+
+	if (output.size() != num_old) {
+		char tmp[512];
+		::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %i, Output meshes: %i",num_old,pScene->mNumMeshes);
+		DefaultLogger::get()->info(tmp);
+	}
+	else DefaultLogger::get()->debug("OptimizeMeshesProcess finished");
+}
+
+// ------------------------------------------------------------------------------------------------
+// Process meshes for a single node
+void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
+{
+	for (unsigned int i = 0; i < pNode->mNumMeshes;++i) {
+		unsigned int& im = pNode->mMeshes[i];
+
+		if (meshes[im].instance_cnt > 1) {
+			im = meshes[im].output_id;
+		}
+		else  {
+			merge_list.clear();
+			unsigned int verts = 0, faces = 0;
+
+			// Find meshes to merge with us
+			for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) {
+				register unsigned int am = pNode->mMeshes[a];
+				if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) {
+
+					merge_list.push_back(mScene->mMeshes[am]);
+					verts += mScene->mMeshes[am]->mNumVertices;
+					faces += mScene->mMeshes[am]->mNumFaces;
+
+					--pNode->mNumMeshes;
+					for (unsigned int n = a; n < pNode->mNumMeshes; ++n)
+						pNode->mMeshes[n] = pNode->mMeshes[n+1];
+
+					--a;
+				}
+			}
+
+			// and merge all meshes which we found, replace the old ones
+			if (!merge_list.empty()) {
+				merge_list.push_back(mScene->mMeshes[im]);
+
+				aiMesh* out;
+				SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end());
+				output.push_back(out);
+			}
+			else {
+				output.push_back(mScene->mMeshes[im]);
+			}
+			im = output.size()-1;
+		}
+	}
+
+
+	for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
+		ProcessNode(pNode->mChildren[i]);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Check whether two meshes can be joined
+bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned int verts, unsigned int faces )
+{
+	if (meshes[a].vertex_format != meshes[b].vertex_format)
+		return false;
+
+	aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b];
+
+	if (0xffffffff != max_verts && verts+mb->mNumVertices > max_verts ||
+		0xffffffff != max_faces && faces+mb->mNumFaces    > max_faces) {
+		return false;
+	}
+
+	// Never merge unskinned meshes with skinned meshes
+	if (ma->mMaterialIndex != mb->mMaterialIndex || ma->HasBones() != mb->HasBones())
+		return false;
+
+	// Never merge meshes with different kinds of primitives if SortByPType did already
+	// do its work. We would destroy everything again ...
+	if (pts && ma->mPrimitiveTypes != mb->mPrimitiveTypes)
+		return false;
+
+	// If both meshes are skinned, check whether we have many bones defined in both meshes. 
+	// If yes, we can savely join them. 
+	if (ma->HasBones()) {
+		// TODO
+		return false;
+	}
+	return true;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Buidl a LUT of all instanced meshes
+void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode)
+{
+	for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
+		++meshes[pNode->mMeshes[i]].instance_cnt; 
+
+	for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
+		FindInstancedMeshes(pNode->mChildren[i]);
+}
+
+#endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS

+ 187 - 0
code/OptimizeMeshes.h

@@ -0,0 +1,187 @@
+/*
+Open Asset Import Library (ASSIMP)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2008, ASSIMP Development Team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the ASSIMP team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the ASSIMP Development Team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file  OptimizeMeshes.h
+ *  @brief Declares a post processing step to join meshes, if possible 
+ */
+#ifndef AI_OPTIMIZEMESHESPROCESS_H_INC
+#define AI_OPTIMIZEMESHESPROCESS_H_INC
+
+#include "BaseProcess.h"
+#include "../include/aiTypes.h"
+
+struct aiMesh;
+class OptimizeMeshesProcessTest;
+namespace Assimp	{
+
+// ---------------------------------------------------------------------------
+/** @brief Postprocessing step to optimize mesh usage
+ *
+ *  The implementation looks for meshes that could be joined and joins them.
+ *  Usually this will reduce the number of drawcalls.
+ *
+ *  @note Instanced meshes are currently not processed.
+ */
+class ASSIMP_API OptimizeMeshesProcess : public BaseProcess
+{
+	friend class Importer;
+	friend class ::OptimizeMeshesProcessTest;
+
+protected:
+	/** Constructor to be privately used by Importer */
+	OptimizeMeshesProcess();
+
+	/** Destructor, private as well */
+	~OptimizeMeshesProcess();
+
+
+	/** @brief Internal utility to store additional mesh info
+	 */
+	struct MeshInfo
+	{
+		MeshInfo()
+			:	instance_cnt  (0)
+			,	vertex_format (0)
+			,	output_id	  (0xffffffff)
+		{}
+
+		//! Number of times this mesh is referenced
+		unsigned int instance_cnt;
+
+		//! Vertex format id
+		unsigned int vertex_format;
+
+		//! Output ID
+		unsigned int output_id;
+	};
+
+public:
+	// -------------------------------------------------------------------
+	bool IsActive( unsigned int pFlags) const;
+
+	// -------------------------------------------------------------------
+	void Execute( aiScene* pScene);
+	
+	// -------------------------------------------------------------------
+	void SetupProperties(const Importer* pImp);
+
+
+	// -------------------------------------------------------------------
+	/** @brief Specify whether you want meshes with different 
+	 *   primitive types to be merged as well.
+	 *
+	 *  IsActive() sets this property automatically to true if the
+	 *  aiProcess_SortByPType flag is found.
+	 */
+	void EnablePrimitiveTypeSorting(bool enable) {
+		pts = enable;
+	}
+
+	// Getter 
+	bool IsPrimitiveTypeSortingEnabled () const {
+		return pts;
+	}
+
+
+	// -------------------------------------------------------------------
+	/** @brief Specify a maximum size of a single output mesh.
+	 *  
+	 *  If a single input mesh already exceeds this limit, it won't
+	 *  be splitted.
+	 *  @param verts Maximum number of vertices per mesh
+	 *  @param faces Maximum number of faces per mesh
+	 */
+	void SetPreferredMeshSizeLimit (unsigned int verts, unsigned int faces)
+	{
+		max_verts = verts;
+		max_faces = faces;
+	}
+
+
+protected:
+
+	// -------------------------------------------------------------------
+	/** @brief Do the actual optimization on all meshes of this node
+	 *  @param pNode Node we're working with
+	 */
+	void ProcessNode( aiNode* pNode);
+
+	// -------------------------------------------------------------------
+	/** @brief Returns true if b can be joined with a
+	 *
+	 *  @param verts Number of output verts up to now
+	 *  @param faces Number of output faces up to now
+	 */
+	bool CanJoin ( unsigned int a, unsigned int b,
+		unsigned int verts, unsigned int faces );
+
+	// -------------------------------------------------------------------
+	/** @brief Find instanced meshes, for the moment we're excluding
+	 *   them from all optimizations
+	 */
+	void FindInstancedMeshes (aiNode* pNode);
+
+private:
+
+	//! Scene we're working with
+	aiScene* mScene;
+
+	//! Per mesh info
+	std::vector<MeshInfo> meshes;
+
+	//! Next output mesh
+	aiMesh* mesh;
+
+	//! Output meshes
+	std::vector<aiMesh*> output;
+
+	//! @see EnablePrimitiveTypeSorting
+	mutable bool pts;
+
+	//! @see SetPreferredMeshSizeLimit
+	mutable unsigned int max_verts,max_faces;
+
+	//! Temporary storage
+	std::vector<aiMesh*> merge_list;
+};
+
+} // end of namespace Assimp
+
+#endif // AI_CALCTANGENTSPROCESS_H_INC

+ 30 - 0
code/ProcessHelper.h

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "SpatialSort.h"
 #include "SpatialSort.h"
 #include "BaseProcess.h"
 #include "BaseProcess.h"
+#include "ParsingUtils.h"
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 // Some extensions to std namespace. Mainly std::min and std::max for all
 // Some extensions to std namespace. Mainly std::min and std::max for all
@@ -190,6 +191,35 @@ inline void ArrayBounds(const T* in, unsigned int size, T& min, T& max)
 	}
 	}
 }
 }
 
 
+// -------------------------------------------------------------------------------
+/** @brief Extract single strings from a list of identifiers
+ *  @param in Input string list. 
+ *  @param out Receives a list of clean output strings
+ *  @sdee #AI_CONFIG_PP_OG_EXCLUDE_LIST
+ */
+inline void ConvertListToStrings(const std::string& in, std::list<std::string>& out)
+{
+	const char* s = in.c_str();
+	while (*s) {
+		SkipSpacesAndLineEnd(&s);
+		if (*s == '\'') {
+			const char* base = ++s;
+			while (*s != '\'') {
+				++s;
+				if (*s == '\0') {
+					DefaultLogger::get()->error("ConvertListToString: String list is ill-formatted");
+					return;
+				}
+			}
+			out.push_back(std::string(base,(size_t)(s-base)));
+			++s;
+		}
+		else {
+			out.push_back(GetNextToken(s));
+		}
+	}
+}
+
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 /** @brief Compute the newell normal of a polygon regardless of its shape
 /** @brief Compute the newell normal of a polygon regardless of its shape
  *
  *

+ 1 - 25
code/RemoveRedundantMaterials.cpp

@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AssimpPCH.h"
 #include "AssimpPCH.h"
 #include "RemoveRedundantMaterials.h"
 #include "RemoveRedundantMaterials.h"
 #include "ParsingUtils.h"
 #include "ParsingUtils.h"
+#include "ProcessHelper.h"
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
@@ -78,31 +79,6 @@ void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp)
 	configFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,"");
 	configFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,"");
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-// Extract single strings from a list of identifiers
-void ConvertListToStrings(const std::string& in, std::list<std::string>& out)
-{
-	const char* s = in.c_str();
-	while (*s) {
-		SkipSpacesAndLineEnd(&s);
-		if (*s == '\'') {
-			const char* base = ++s;
-			while (*s != '\'') {
-				++s;
-				if (*s == '\0') {
-					DefaultLogger::get()->error("RemoveRedundantMaterials: String list is ill-formatted");
-					return;
-				}
-			}
-			out.push_back(std::string(base,(size_t)(s-base)));
-			++s;
-		}
-		else {
-			out.push_back(GetNextToken(s));
-		}
-	}
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 // Executes the post processing step on the given imported data.
 void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 void RemoveRedundantMatsProcess::Execute( aiScene* pScene)

+ 41 - 69
code/SceneCombiner.cpp

@@ -675,10 +675,8 @@ void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash>& asBones,
 	std::vector<aiMesh*>::const_iterator end)
 	std::vector<aiMesh*>::const_iterator end)
 {
 {
 	unsigned int iOffset = 0;
 	unsigned int iOffset = 0;
-	for (; it != end;++it)
-	{
-		for (unsigned int l = 0; l < (*it)->mNumBones;++l)
-		{
+	for (; it != end;++it)	{
+		for (unsigned int l = 0; l < (*it)->mNumBones;++l)	{
 			aiBone* p = (*it)->mBones[l];
 			aiBone* p = (*it)->mBones[l];
 			uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length);
 			uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length);
 
 
@@ -691,8 +689,7 @@ void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash>& asBones,
 					break;
 					break;
 				}
 				}
 			}
 			}
-			if (end2 == it2)
-			{
+			if (end2 == it2)	{
 				// need to begin a new bone entry
 				// need to begin a new bone entry
 				asBones.push_back(BoneWithHash());
 				asBones.push_back(BoneWithHash());
 				BoneWithHash& btz = asBones.back();
 				BoneWithHash& btz = asBones.back();
@@ -721,29 +718,23 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator
 	BuildUniqueBoneList(asBones, it,end);
 	BuildUniqueBoneList(asBones, it,end);
 	
 	
 	// now create the output bones
 	// now create the output bones
+	out->mNumBones = 0;
 	out->mBones = new aiBone*[asBones.size()];
 	out->mBones = new aiBone*[asBones.size()];
 
 
-	for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),end = asBones.end(); 
-		 it != end;++it)
-	{
+	for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),end = asBones.end(); it != end;++it)	{
 		// Allocate a bone and setup it's name
 		// Allocate a bone and setup it's name
 		aiBone* pc = out->mBones[out->mNumBones++] = new aiBone();
 		aiBone* pc = out->mBones[out->mNumBones++] = new aiBone();
 		pc->mName = aiString( *((*it).second ));
 		pc->mName = aiString( *((*it).second ));
 
 
-		// Get an itrator to the end of the list
 		std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end();
 		std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end();
 
 
 		// Loop through all bones to be joined for this bone
 		// Loop through all bones to be joined for this bone
-		for (std::vector< BoneSrcIndex >::const_iterator 
-			wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)
-		{
+		for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)	{
 			pc->mNumWeights += (*wmit).first->mNumWeights;
 			pc->mNumWeights += (*wmit).first->mNumWeights;
 
 
 			// NOTE: different offset matrices for bones with equal names
 			// NOTE: different offset matrices for bones with equal names
 			// are - at the moment - not handled correctly. 
 			// are - at the moment - not handled correctly. 
-			if (wmit != (*it).pSrcBones.begin() &&
-				pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix)
-			{
+			if (wmit != (*it).pSrcBones.begin() && pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix)	{
 				DefaultLogger::get()->warn("Bones with equal names but different offset matrices can't be joined at the moment");
 				DefaultLogger::get()->warn("Bones with equal names but different offset matrices can't be joined at the moment");
 				continue;
 				continue;
 			}
 			}
@@ -755,12 +746,9 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator
 
 
 		// And copy the final weights - adjust the vertex IDs by the 
 		// And copy the final weights - adjust the vertex IDs by the 
 		// face index offset of the coresponding mesh.
 		// face index offset of the coresponding mesh.
-		for (std::vector< BoneSrcIndex >::const_iterator 
-			wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)
-		{
+		for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)	{
 			aiBone* pip = (*wmit).first;
 			aiBone* pip = (*wmit).first;
-			for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw)
-			{
+			for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw)	{
 				const aiVertexWeight& vfi = pip->mWeights[mp];
 				const aiVertexWeight& vfi = pip->mWeights[mp];
 				avw->mWeight = vfi.mWeight;
 				avw->mWeight = vfi.mWeight;
 				avw->mVertexId = vfi.mVertexId + (*wmit).second;
 				avw->mVertexId = vfi.mVertexId + (*wmit).second;
@@ -777,8 +765,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int flags,
 {
 {
 	ai_assert(NULL != _out);
 	ai_assert(NULL != _out);
 
 
-	if (begin == end)
-	{
+	if (begin == end)	{
 		*_out = NULL; // no meshes ...
 		*_out = NULL; // no meshes ...
 		return;
 		return;
 	}
 	}
@@ -788,8 +775,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int flags,
 	out->mMaterialIndex = (*begin)->mMaterialIndex;
 	out->mMaterialIndex = (*begin)->mMaterialIndex;
 
 
 	// Find out how much output storage we'll need
 	// Find out how much output storage we'll need
-	for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
-	{
+	for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
 		out->mNumVertices	+= (*it)->mNumVertices;
 		out->mNumVertices	+= (*it)->mNumVertices;
 		out->mNumFaces		+= (*it)->mNumFaces;
 		out->mNumFaces		+= (*it)->mNumFaces;
 		out->mNumBones		+= (*it)->mNumBones;
 		out->mNumBones		+= (*it)->mNumBones;
@@ -798,86 +784,75 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int flags,
 		out->mPrimitiveTypes |= (*it)->mPrimitiveTypes;
 		out->mPrimitiveTypes |= (*it)->mPrimitiveTypes;
 	}
 	}
 
 
-	if (out->mNumVertices) // just for safety
-	{
+	if (out->mNumVertices) {
 		aiVector3D* pv2;
 		aiVector3D* pv2;
 
 
 		// copy vertex positions
 		// copy vertex positions
-		if ((**begin).HasPositions())
-		{
+		if ((**begin).HasPositions())	{
+
 			pv2 = out->mVertices = new aiVector3D[out->mNumVertices];
 			pv2 = out->mVertices = new aiVector3D[out->mNumVertices];
-			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
-			{
-				if ((*it)->mNormals)
-				{
+			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
+				if ((*it)->mVertices)	{
 					::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D));
 					::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D));
 				}
 				}
-				else DefaultLogger::get()->warn("JoinMeshes: Positions expected, but mesh contains no positions");
+				else DefaultLogger::get()->warn("JoinMeshes: Positions expected but input mesh contains no positions");
 				pv2 += (*it)->mNumVertices;
 				pv2 += (*it)->mNumVertices;
 			}
 			}
 		}
 		}
 		// copy normals
 		// copy normals
-		if ((**begin).HasNormals())
-		{
+		if ((**begin).HasNormals())	{
+
 			pv2 = out->mNormals = new aiVector3D[out->mNumVertices];
 			pv2 = out->mNormals = new aiVector3D[out->mNumVertices];
-			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
-			{
-				if ((*it)->mNormals)
-				{
+			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
+				if ((*it)->mNormals)	{
 					::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
 					::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
 				}
 				}
-				else DefaultLogger::get()->warn("JoinMeshes: Normals expected, but mesh contains no normals");
+				else DefaultLogger::get()->warn("JoinMeshes: Normals expected but input mesh contains no normals");
 				pv2 += (*it)->mNumVertices;
 				pv2 += (*it)->mNumVertices;
 			}
 			}
 		}
 		}
 		// copy tangents and bitangents
 		// copy tangents and bitangents
-		if ((**begin).HasTangentsAndBitangents())
-		{
+		if ((**begin).HasTangentsAndBitangents())	{
+
 			pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
 			pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
 			aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
 			aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
 
 
-			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
-			{
-				if ((*it)->mTangents)
-				{
+			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
+				if ((*it)->mTangents)	{
 					::memcpy(pv2, (*it)->mTangents,	 (*it)->mNumVertices*sizeof(aiVector3D));
 					::memcpy(pv2, (*it)->mTangents,	 (*it)->mNumVertices*sizeof(aiVector3D));
 					::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
 					::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
 				}
 				}
-				else DefaultLogger::get()->warn("JoinMeshes: Tangents expected, but mesh contains no tangents");
+				else DefaultLogger::get()->warn("JoinMeshes: Tangents expected but input mesh contains no tangents");
 				pv2  += (*it)->mNumVertices;
 				pv2  += (*it)->mNumVertices;
 				pv2b += (*it)->mNumVertices;
 				pv2b += (*it)->mNumVertices;
 			}
 			}
 		}
 		}
 		// copy texture coordinates
 		// copy texture coordinates
 		unsigned int n = 0;
 		unsigned int n = 0;
-		while ((**begin).HasTextureCoords(n))
-		{
+		while ((**begin).HasTextureCoords(n))	{
 			out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
 			out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
 
 
 			pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
 			pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
-			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
-			{
-				if ((*it)->mTextureCoords[n])
-				{
+			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
+
+				if ((*it)->mTextureCoords[n])	{
 					::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
 					::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
 				}
 				}
-				else DefaultLogger::get()->warn("JoinMeshes: UVs expected, but mesh contains no UVs");
+				else DefaultLogger::get()->warn("JoinMeshes: UVs expected but input mesh contains no UVs");
 				pv2 += (*it)->mNumVertices;
 				pv2 += (*it)->mNumVertices;
 			}
 			}
 			++n;
 			++n;
 		}
 		}
 		// copy vertex colors
 		// copy vertex colors
 		n = 0;
 		n = 0;
-		while ((**begin).HasVertexColors(n))
-		{
+		while ((**begin).HasVertexColors(n))	{
 			aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
 			aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
-			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
-			{
-				if ((*it)->mColors[n])
-				{
+			for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
+
+				if ((*it)->mColors[n])	{
 					::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
 					::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
 				}
 				}
-				else DefaultLogger::get()->warn("JoinMeshes: VCs expected, but mesh contains no VCs");
+				else DefaultLogger::get()->warn("JoinMeshes: VCs expected but input mesh contains no VCs");
 				pv2 += (*it)->mNumVertices;
 				pv2 += (*it)->mNumVertices;
 			}
 			}
 			++n;
 			++n;
@@ -891,23 +866,20 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int flags,
 		aiFace* pf2 = out->mFaces;
 		aiFace* pf2 = out->mFaces;
 
 
 		unsigned int ofs = 0;
 		unsigned int ofs = 0;
-		for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)
-		{
-			for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2)
-			{
+		for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)	{
+			for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2)	{
 				aiFace& face = (*it)->mFaces[m];
 				aiFace& face = (*it)->mFaces[m];
 				pf2->mNumIndices = face.mNumIndices;
 				pf2->mNumIndices = face.mNumIndices;
 				pf2->mIndices = face.mIndices;
 				pf2->mIndices = face.mIndices;
 
 
-				if (ofs)
-				{
+				if (ofs)	{
 					// add the offset to the vertex
 					// add the offset to the vertex
 					for (unsigned int q = 0; q < face.mNumIndices; ++q)
 					for (unsigned int q = 0; q < face.mNumIndices; ++q)
 						face.mIndices[q] += ofs;	
 						face.mIndices[q] += ofs;	
 				}
 				}
-				ofs += (*it)->mNumVertices;
 				face.mIndices = NULL;
 				face.mIndices = NULL;
 			}
 			}
+			ofs += (*it)->mNumVertices;
 		}
 		}
 	}
 	}
 
 

BIN
doc/AssimpCmdDoc_Html/AssimpCmdDoc.chm


BIN
doc/AssimpDoc_Html/AssimpDoc.chm


+ 1 - 1
doc/Doxyfile

@@ -31,7 +31,7 @@ PROJECT_NAME           = assimp
 # This could be handy for archiving the generated documentation or 
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 # if some version control system is used.
 
 
-PROJECT_NUMBER         = r350
+PROJECT_NUMBER         = r400
 
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # base path where the generated documentation will be put. 
 # base path where the generated documentation will be put. 

+ 1 - 1
doc/Doxyfile_Cmd

@@ -31,7 +31,7 @@ PROJECT_NAME           = AssimpCMD
 # This could be handy for archiving the generated documentation or 
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 # if some version control system is used.
 
 
-PROJECT_NUMBER         = r325
+PROJECT_NUMBER         = r400
 
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # base path where the generated documentation will be put. 
 # base path where the generated documentation will be put. 

+ 1 - 1
doc/Preamble.txt

@@ -3,7 +3,7 @@
 Open Asset Import Library (ASSIMP)
 Open Asset Import Library (ASSIMP)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2008, ASSIMP Development Team
+Copyright (c) 2006-2009, ASSIMP Development Team
 
 
 All rights reserved.
 All rights reserved.
 
 

+ 22 - 7
doc/dox_cmd.h

@@ -305,7 +305,7 @@ more information can be found in the <tt>aiPostProcess.h</tt> header.
 	<td>Find and process degenerates primitives.</td>
 	<td>Find and process degenerates primitives.</td>
   </tr>
   </tr>
   <tr>
   <tr>
-    <td>-slm</tt></td>
+    <td><tt>-slm</tt></td>
     <td>--split-large-meshes</tt></td>
     <td>--split-large-meshes</tt></td>
 	<td>Split large meshes over a specific treshold in smaller sub meshes. The default vertex & face limit is 1000000</td>
 	<td>Split large meshes over a specific treshold in smaller sub meshes. The default vertex & face limit is 1000000</td>
   </tr>
   </tr>
@@ -373,6 +373,19 @@ more information can be found in the <tt>aiPostProcess.h</tt> header.
 	<td>Search the data structure for instanced meshes and replace them by references. This can
 	<td>Search the data structure for instanced meshes and replace them by references. This can
 	reduce vertex/face counts but the postprocessing-step takes some time.</td>
 	reduce vertex/face counts but the postprocessing-step takes some time.</td>
   </tr>
   </tr>
+
+    <tr>
+    <td><tt>-og</tt></td>
+    <td><tt>--optimize-graph</tt></td>
+	<td>Simplify and optimize the scenegraph. Use it with care, all hierarchy information could be lost.
+	Animations remain untouched. </td>
+  </tr>
+
+    <tr>
+    <td><tt>-om</tt></td>
+    <td><tt>--optimize-mesh</tt></td>
+	<td>Optimize mesh usage. Meshes are merged, if possible. Very effective in combination with <tt>--optimize-graph</tt></td>
+  </tr>
 </table>
 </table>
 
 
 For convenience some default postprocessing configurations are provided.
 For convenience some default postprocessing configurations are provided.
@@ -392,17 +405,19 @@ The corresponding command line parameter is <tt>-c<name></tt> (or <tt>--config=<
   </tr>
   </tr>
     <tr>
     <tr>
     <td>default</td>
     <td>default</td>
-    <td>Balanced post processing config, performs most optimizations</td>
+    <td>Balanced post processing config; performs most optimizations</td>
 	<td><tt>-cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv</tt></td>
 	<td><tt>-cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv</tt></td>
   </tr>
   </tr>
     <tr>
     <tr>
     <td>full</td>
     <td>full</td>
-    <td>Full post processing. May take a while, but results in best output quality for most purposes</td>
-	<td><tt>-cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv, -fi, -vds</tt></td>
+    <td>Full post processing. May take a while but results in best output quality for most purposes</td>
+	<td><tt>-cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv, -fi, -vds -om</tt></td>
   </tr>
   </tr>
  </table>
  </table>
 
 
-There are also some common flags to specify Assimp's logging behaviour:
+ The <tt>-tuv, -ptv, -og</tt> flags always need to be enabled manually.
+
+There are also some common flags to customize Assimp's logging behaviour:
 
 
 <table border="1">
 <table border="1">
  
  
@@ -420,8 +435,8 @@ There are also some common flags to specify Assimp's logging behaviour:
   </tr>
   </tr>
     <tr>
     <tr>
     <td><tt>-v</tt> or <tt>--verbose</tt></td>
     <td><tt>-v</tt> or <tt>--verbose</tt></td>
-    <td>Enables verbose logging. Debug messages will be produced, too. This will 
-	decrease loading performance and might result in *very* long logs ...</td>
+    <td>Enables verbose logging. Debug messages will be produced too. This might 
+	decrease loading performance and result in *very* long logs ... use with caution if you experience strange issues.</td>
   </tr>
   </tr>
  </table>
  </table>
  */
  */

+ 287 - 244
include/aiConfig.h

@@ -58,6 +58,123 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_CONFIG_H
 #ifndef INCLUDED_AI_CONFIG_H
 #define INCLUDED_AI_CONFIG_H
 #define INCLUDED_AI_CONFIG_H
 
 
+
+// ###########################################################################
+// POST PROCESSING SETTINGS
+// Various stuff to fine-tune the behavior of a specific post processing step.
+// ###########################################################################
+
+// ---------------------------------------------------------------------------
+/** @brief  Specifies the maximum angle that may be between two vertex tangents
+ *         that their tangents and bitangents are smoothed.
+ *
+ * This applies to the CalcTangentSpace-Step. The angle is specified
+ * in degrees, so 180 is PI. The default value is
+ * 45 degrees. The maximum value is 175.
+ * Property type: float. 
+ */
+#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE \
+	"PP_CT_MAX_SMOOTHING_ANGLE"
+
+// ---------------------------------------------------------------------------
+/** @brief  Specifies the maximum angle that may be between two face normals
+ *          at the same vertex position that their are smoothed together.
+ *
+ * Sometimes referred to as 'crease angle'.
+ * This applies to the GenSmoothNormals-Step. The angle is specified
+ * in degrees, so 180 is PI. The default value is 175 degrees (all vertex 
+ * normals are smoothed). The maximum value is 175, too. Property type: float. 
+ * Warning: setting this option may cause a severe loss of performance. The
+ * performance is unaffected if the #AI_CONFIG_FAVOUR_SPEED flag is set but
+ * the output quality may be reduced.
+ */
+#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE \
+	"PP_GSN_MAX_SMOOTHING_ANGLE"
+
+// ---------------------------------------------------------------------------
+/** @brief Sets the colormap (= palette) to be used to decode embedded
+ *         textures in MDL (Quake or 3DGS) files.
+ *
+ * This must be a valid path to a file. The file is 768 (256*3) bytes
+ * large and contains RGB triplets for each of the 256 palette entries.
+ * The default value is colormap.lmp. If the file is not found,
+ * a default palette (from Quake 1) is used. 
+ * Property type: string.
+ */
+#define AI_CONFIG_IMPORT_MDL_COLORMAP		\
+	"IMPORT_MDL_COLORMAP"
+
+// ---------------------------------------------------------------------------
+/** @brief Configures the #aiProcess_RemoveRedundantMaterials step to 
+ *  keep materials matching a name in a given list.
+ *
+ * This is a list of 1 to n strings, ' ' serves as delimiter character.
+ * Identifiers containing whitespaces must be enclosed in *single*
+ * quotation marks. For example:<tt>
+ * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'"</tt>.
+ * If a material matches on of these names, it will not be modified or
+ * removed by the postprocessing step nor will other materials be replaced
+ * by a reference to it. <br> 
+ * This option might be useful if you are using some magic material names
+ * to pass additional semantics through the content pipeline. This ensures
+ * they won't be optimized away, but a general optimization is still 
+ * performed for materials not contained in the list.
+ * Property type: String. Default value: n/a
+ * @note Linefeeds, tabs or carriage returns are treated as whitespace.
+ *   Material names are case sensitive.
+ */
+#define AI_CONFIG_PP_RRM_EXCLUDE_LIST	\
+	"PP_RRM_EXCLUDE_LIST"
+
+// ---------------------------------------------------------------------------
+/** @brief Configures the #aiProcess_PretransformVertices step to
+ *  keep the scene hierarchy. Meshes are moved to worldspace, but
+ *  no optimization is performed (means: meshes are not joined. The total
+ *  number of meshes won't change).
+ *
+ * This option could be of use for you if the scene hierarchy contains
+ * important additional information which you want to interpret. 
+ * For rendering, you can still render all meshes in the scene without
+ * any transformations.
+ * Property type: integer (0: false; !0: true). Default value: false.
+ */
+#define AI_CONFIG_PP_PTV_KEEP_HIERARCHY		\
+	"PP_PTV_KEEP_HIERARCHY"
+
+// ---------------------------------------------------------------------------
+/** @brief Configures the #aiProcess_FindDegenerates step to
+ *  remove degenerated primitives from the import - immediately.
+ *
+ * The default behaviour converts degenerated triangles to lines and
+ * degenerated lines to points. See the documentation to the
+ * #aiProcess_FindDegenerates step for a detailed example of the various ways
+ * to get rid of these lines and points if you don't want them.
+ * Property type: integer (0: false; !0: true). Default value: false.
+ */
+#define AI_CONFIG_PP_FD_REMOVE \
+	"PP_FD_REMOVE"
+
+// ---------------------------------------------------------------------------
+/** @brief Configures the #aiProcess_OptimizeGraph step to preserve nodes
+ * matching a name in a given list.
+ *
+ * This is a list of 1 to n strings, ' ' serves as delimiter character.
+ * Identifiers containing whitespaces must be enclosed in *single*
+ * quotation marks. For example:<tt>
+ * "keep-me and_me_to anotherNodeToBeKept \'name with whitespace\'"</tt>.
+ * If a node matches on of these names, it will not be modified or
+ * removed by the postprocessing step.<br> 
+ * This option might be useful if you are using some magic node names
+ * to pass additional semantics through the content pipeline. This ensures
+ * they won't be optimized away, but a general optimization is still 
+ * performed for nodes not contained in the list.
+ * Property type: String. Default value: n/a
+ * @note Linefeeds, tabs or carriage returns are treated as whitespace.
+ *   Node names are case sensitive.
+ */
+#define AI_CONFIG_PP_OG_EXCLUDE_LIST	\
+	"PP_OG_EXCLUDE_LIST"
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** @brief  Set the maximum number of vertices in a mesh.
 /** @brief  Set the maximum number of vertices in a mesh.
  *
  *
@@ -124,6 +241,151 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  */
 #define AI_CONFIG_PP_ICL_PTCACHE_SIZE	"PP_ICL_PTCACHE_SIZE"
 #define AI_CONFIG_PP_ICL_PTCACHE_SIZE	"PP_ICL_PTCACHE_SIZE"
 
 
+// ---------------------------------------------------------------------------
+/** @brief Enumerates components of the aiScene and aiMesh data structures
+ *  that can be excluded from the import by using the RemoveComponent step.
+ *
+ *  See the documentation to #aiProcess_RemoveComponent for more details.
+ */
+enum aiComponent
+{
+	/** Normal vectors
+	 */
+	aiComponent_NORMALS = 0x2u,
+
+	/** Tangents and bitangents go always together ...
+	 */
+	aiComponent_TANGENTS_AND_BITANGENTS = 0x4u,
+
+	/** ALL color sets
+	 * 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_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
+	 */
+	aiComponent_BONEWEIGHTS = 0x20,
+
+	/** Removes all node animations (aiScene::mAnimations).
+	 * The scenegraph nodes corresponding to the bones are NOT removed.
+	 * use the #aiProcess_OptimizeGraph step to do this
+	 */
+	aiComponent_ANIMATIONS = 0x40,
+
+	/** Removes all embedded textures (aiScene::mTextures)
+	 */
+	aiComponent_TEXTURES = 0x80,
+
+	/** Removes all light sources (aiScene::mLights).
+	 * The scenegraph nodes corresponding to the bones are NOT removed.
+	 * use the #aiProcess_OptimizeGraph step to do this
+	 */
+	aiComponent_LIGHTS = 0x100,
+
+	/** Removes all light sources (aiScene::mCameras).
+	 * The scenegraph nodes corresponding to the bones are NOT removed.
+	 * use the #aiProcess_OptimizeGraph step to do this
+	 */
+	aiComponent_CAMERAS = 0x200,
+
+	/** Removes all meshes (aiScene::mMeshes). 
+	 */
+	aiComponent_MESHES = 0x400,
+
+	/** Removes all materials. One default material will
+	 * 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.
+	 */
+	_aiComponent_Force32Bit = 0x9fffffff
+};
+
+// Remove a specific color channel 'n'
+#define aiComponent_COLORSn(n) (1u << (n+20u))
+
+// Remove a specific UV channel 'n'
+#define aiComponent_TEXCOORDSn(n) (1u << (n+25u))
+
+// ---------------------------------------------------------------------------
+/** @brief Input parameter to the #aiProcess_RemoveComponent step:
+ *  Specifies the parts of the data structure to be removed.
+ *
+ * See the documentation to this step for further details. The property
+ * is expected to be an integer, a bitwise combination of the
+ * #aiComponent flags defined above in this header. The default
+ * value is 0. Important: if no valid mesh is remaining after the
+ * step has been executed (e.g you thought it was funny to specify ALL
+ * of the flags defined above) the import FAILS. Mainly because there is
+ * no data to work on anymore ...
+ */
+#define AI_CONFIG_PP_RVC_FLAGS				\
+	"PP_RVC_FLAGS"
+
+// ---------------------------------------------------------------------------
+/** @brief Input parameter to the #aiProcess_SortByPType step:
+ *  Specifies which primitive types are removed by the step.
+ *
+ *  This is a bitwise combination of the aiPrimitiveType flags.
+ *  Specifying all of them is illegal, of course. A typical use would
+ *  be to exclude all line and point meshes from the import. This
+ *  is an integer property, its default value is 0.
+ */
+#define AI_CONFIG_PP_SBP_REMOVE				\
+	"PP_SBP_REMOVE"
+
+
+// TransformUVCoords evaluates UV scalings
+#define AI_UVTRAFO_SCALING 0x1
+
+// TransformUVCoords evaluates UV rotations
+#define AI_UVTRAFO_ROTATION 0x2
+
+// TransformUVCoords evaluates UV translation
+#define AI_UVTRAFO_TRANSLATION 0x4
+
+// Everything baked together -> default value
+#define AI_UVTRAFO_ALL (AI_UVTRAFO_SCALING | AI_UVTRAFO_ROTATION | AI_UVTRAFO_TRANSLATION)
+
+// ---------------------------------------------------------------------------
+/** @brief Input parameter to the #aiProcess_TransformUVCoords step:
+ *  Specifies which UV transformations are evaluated.
+ *
+ *  This is a bitwise combination of the AI_UVTRAFO_XXX flags (integer
+ *  property, of course). By default all transformations are enabled 
+ * (AI_UVTRAFO_ALL).
+ */
+#define AI_CONFIG_PP_TUV_EVALUATE				\
+	"PP_TUV_EVALUATE"
+
+// ---------------------------------------------------------------------------
+/** @brief A hint to assimp to favour speed against import quality.
+ *
+ * Enabling this option may result in faster loading, but it needn't.
+ * It represents just a hint to loaders and post-processing steps to use
+ * faster code paths, if possible. 
+ * This property is expected to be an integer, != 0 stands for true.
+ * The default value is 0.
+ */
+#define AI_CONFIG_FAVOUR_SPEED				\
+ "FAVOUR_SPEED"
+
+
+// ###########################################################################
+// IMPORTER SETTINGS
+// Various stuff to fine-tune the behaviour of a specific importer plugin.
+// ###########################################################################
+
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** @brief  Set the vertex animation keyframe to be imported
 /** @brief  Set the vertex animation keyframe to be imported
@@ -244,130 +506,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY			\
 #define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY			\
 	"IMPORT_LWO_ONE_LAYER_ONLY"
 	"IMPORT_LWO_ONE_LAYER_ONLY"
 
 
-
-// ---------------------------------------------------------------------------
-/** @brief Defines the begin of the time range for which the LWS loader
- *    evaluates animations and computes aiNodeAnim's.
- * 
- * Assimp provides full conversion of LightWave's envelope system, including
- * pre and post conditions. The loader computes linearly subsampled animation
- * chanels with the frame rate given in the LWS file. This property defines
- * the start time. Note: animation channels are only generated if a node
- * has at least one envelope with more tan one key assigned. This property.
- * is given in frames, '0' is the first frame. By default, if this property
- * is not set, the importer takes the animation start from the input LWS
- * file ('FirstFrame' line)<br>
- * Property type: Integer. Default value: taken from file.
- *
- * @see AI_CONFIG_IMPORT_LWS_ANIM_END - end of the imported time range
- */
-#define AI_CONFIG_IMPORT_LWS_ANIM_START			\
-	"IMPORT_LWS_ANIM_START"
-#define AI_CONFIG_IMPORT_LWS_ANIM_END			\
-	"IMPORT_LWS_ANIM_END"
-
-// ---------------------------------------------------------------------------
-/** @brief Defines the output frame rate of the IRR loader.
- * 
- * IRR animations are difficult to convert for Assimp and there will
- * always be a loss of quality. This setting defines how many keys per second
- * are returned by the converter.<br>
- * Property type: integer. Default value: 100
- */
-#define AI_CONFIG_IMPORT_IRR_ANIM_FPS				\
-	"IMPORT_IRR_ANIM_FPS"
-
-// ---------------------------------------------------------------------------
-/** @brief  Specifies the maximum angle that may be between two vertex tangents
- *         that their tangents and bitangents are smoothed.
- *
- * This applies to the CalcTangentSpace-Step. The angle is specified
- * in degrees, so 180 is PI. The default value is
- * 45 degrees. The maximum value is 175.
- * Property type: float. 
- */
-#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE \
-	"PP_CT_MAX_SMOOTHING_ANGLE"
-
-// ---------------------------------------------------------------------------
-/** @brief  Specifies the maximum angle that may be between two face normals
- *          at the same vertex position that their are smoothed together.
- *
- * Sometimes referred to as 'crease angle'.
- * This applies to the GenSmoothNormals-Step. The angle is specified
- * in degrees, so 180 is PI. The default value is 175 degrees (all vertex 
- * normals are smoothed). The maximum value is 175. Property type: float. 
- * Warning: setting this option may cause a severe loss of performance. The
- * performance is unaffected if the AI_CONFIG_FAVOUR_SPEED flag is set, but
- * the output quality may be reduced.
- */
-#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE \
-	"PP_GSN_MAX_SMOOTHING_ANGLE"
-
-// ---------------------------------------------------------------------------
-/** @brief Sets the colormap (= palette) to be used to decode embedded
- *         textures in MDL (Quake or 3DGS) files.
- *
- * This must be a valid path to a file. The file is 768 (256*3) bytes
- * large and contains RGB triplets for each of the 256 palette entries.
- * The default value is colormap.lmp. If the file is not found,
- * a default palette (from Quake 1) is used. 
- * Property type: string.
- */
-#define AI_CONFIG_IMPORT_MDL_COLORMAP		\
-	"IMPORT_MDL_COLORMAP"
-
-// ---------------------------------------------------------------------------
-/** @brief Configures the #aiProcess_RemoveRedundantMaterials step to 
- *  keep materials matching a name in a given list.
- *
- * This is a list of 1 to n strings, ' ' serves as delimiter character.
- * Identifiers containing whitespaces must be enclosed in *single*
- * quotation marks. For example:<tt>
- * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'"</tt>.
- * If a material matches on of these names, it will not be modified or
- * removed by the postprocessing step nor will other materials be replaced
- * by a reference to it. <br> 
- * This option might be useful if you are using some magic material names
- * to pass additional semantics through the content pipeline. This ensures
- * they won't be optimized away, but a general optimization is still 
- * performed for materials not contained in the list.
- * Property type: String. Default value: n/a
- * @note Linefeeds, tabs or carriage returns are treated as whitespace.
- *   Material names are case sensitive.
- */
-#define AI_CONFIG_PP_RRM_EXCLUDE_LIST	\
-	"PP_RRM_EXCLUDE_LIST"
-
-// ---------------------------------------------------------------------------
-/** @brief Configures the #aiProcess_PretransformVertices step to
- *  keep the scene hierarchy. Meshes are moved to worldspace, but
- *  no optimization is performed (means: meshes are not joined. The total
- *  number of meshes won't change).
- *
- * This option could be of use for you if the scene hierarchy contains
- * important additional information which you want to interpret. 
- * For rendering, you can still render all meshes in the scene without
- * any transformations.
- * Property type: integer (0: false; !0: true). Default value: false.
- */
-#define AI_CONFIG_PP_PTV_KEEP_HIERARCHY		\
-	"PP_PTV_KEEP_HIERARCHY"
-
-// ---------------------------------------------------------------------------
-/** @brief Configures the #aiProcess_FindDegenerates step to
- *  remove degenerated primitives from the import - immediately.
- *
- * The default behaviour converts degenerated triangles to lines and
- * degenerated lines to points. See the documentation to the
- * #aiProcess_FindDegenerates step for a detailed example of the various ways
- * to get rid of these lines and points if you don't want them.
- * Property type: integer (0: false; !0: true). Default value: false.
- */
-#define AI_CONFIG_PP_FD_REMOVE \
-	"PP_FD_REMOVE"
-
-
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** @brief  Configures the MD5 loader to not load the MD5ANIM file for
 /** @brief  Configures the MD5 loader to not load the MD5ANIM file for
  *  a MD5MESH file automatically.
  *  a MD5MESH file automatically.
@@ -397,132 +535,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endif
 #endif
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-/** @brief Enumerates components of the aiScene and aiMesh data structures
- *  that can be excluded from the import with the RemoveComponent step.
- *
- *  See the documentation to #aiProcess_RemoveComponent for more details.
- */
-enum aiComponent
-{
-	//! Normal vectors
-	aiComponent_NORMALS = 0x2u,
-
-	//! Tangents and bitangents go always together ...
-	aiComponent_TANGENTS_AND_BITANGENTS = 0x4u,
-
-	//! ALL color sets
-	//! 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_TEXCOORDS = 0x10,
-
-	//! Removes all bone weights from all meshes.
-	//! The scenegraph nodes corresponding to the
-	//! bones are removed
-	aiComponent_BONEWEIGHTS = 0x20,
-
-	//! Removes all bone animations (aiScene::mAnimations)
-	aiComponent_ANIMATIONS = 0x40,
-
-	//! Removes all embedded textures (aiScene::mTextures)
-	aiComponent_TEXTURES = 0x80,
-
-	//! Removes all light sources (aiScene::mLights)
-	//! The scenegraph nodes corresponding to the
-	//! light sources are removed.
-	aiComponent_LIGHTS = 0x100,
-
-	//! Removes all light sources (aiScene::mCameras)
-	//! The scenegraph nodes corresponding to the
-	//! cameras are removed.
-	aiComponent_CAMERAS = 0x200,
-
-	//! Removes all meshes (aiScene::mMeshes). 
-	aiComponent_MESHES = 0x400,
-
-	//! Removes all materials. One default material will
-	//! be generated, so aiScene::mNumMaterials will be 1.
-	//! This makes no real sense without the aiComponent_TEXTURES flag.
-	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.
-	 */
-	_aiComponent_Force32Bit = 0x9fffffff
-};
-
-// Remove a specific color channel 'n'
-#define aiComponent_COLORSn(n) (1u << (n+20u))
-
-// Remove a specific UV channel 'n'
-#define aiComponent_TEXCOORDSn(n) (1u << (n+25u))
-
-
-// ---------------------------------------------------------------------------
-/** @brief Input parameter to the #aiProcess_RemoveComponent step:
- *  Specifies the parts of the data structure to be removed.
- *
- * See the documentation to this step for further details. The property
- * is expected to be an integer, a bitwise combination of the
- * #aiComponent flags defined above in this header. The default
- * value is 0. Important: if no valid mesh is remaining after the
- * step has been executed (e.g you thought it was funny to specify ALL
- * of the flags defined above) the import FAILS. Mainly because there is
- * no data to work on anymore ...
- */
-#define AI_CONFIG_PP_RVC_FLAGS				\
-	"PP_RVC_FLAGS"
-
-// ---------------------------------------------------------------------------
-/** @brief Input parameter to the #aiProcess_SortByPType step:
- *  Specifies which primitive types are removed by the step.
+/** @brief Defines the begin of the time range for which the LWS loader
+ *    evaluates animations and computes aiNodeAnim's.
+ * 
+ * Assimp provides full conversion of LightWave's envelope system, including
+ * pre and post conditions. The loader computes linearly subsampled animation
+ * chanels with the frame rate given in the LWS file. This property defines
+ * the start time. Note: animation channels are only generated if a node
+ * has at least one envelope with more tan one key assigned. This property.
+ * is given in frames, '0' is the first frame. By default, if this property
+ * is not set, the importer takes the animation start from the input LWS
+ * file ('FirstFrame' line)<br>
+ * Property type: Integer. Default value: taken from file.
  *
  *
- *  This is a bitwise combination of the aiPrimitiveType flags.
- *  Specifying all of them is illegal, of course. A typical use would
- *  be to exclude all line and point meshes from the import. This
- *  is an integer property, its default value is 0.
+ * @see AI_CONFIG_IMPORT_LWS_ANIM_END - end of the imported time range
  */
  */
-#define AI_CONFIG_PP_SBP_REMOVE				\
-	"PP_SBP_REMOVE"
-
-
-// TransformUVCoords evaluates UV scalings
-#define AI_UVTRAFO_SCALING 0x1
-
-// TransformUVCoords evaluates UV rotations
-#define AI_UVTRAFO_ROTATION 0x2
-
-// TransformUVCoords evaluates UV translation
-#define AI_UVTRAFO_TRANSLATION 0x4
-
-// Everything baked together -> default value
-#define AI_UVTRAFO_ALL (AI_UVTRAFO_SCALING | AI_UVTRAFO_ROTATION | AI_UVTRAFO_TRANSLATION)
+#define AI_CONFIG_IMPORT_LWS_ANIM_START			\
+	"IMPORT_LWS_ANIM_START"
+#define AI_CONFIG_IMPORT_LWS_ANIM_END			\
+	"IMPORT_LWS_ANIM_END"
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-/** @brief Input parameter to the #aiProcess_TransformUVCoords step:
- *  Specifies which UV transformations are evaluated.
- *
- *  This is a bitwise combination of the AI_UVTRAFO_XXX flags (integer
- *  property, of course). By default all transformations are enabled 
- * (AI_UVTRAFO_ALL).
+/** @brief Defines the output frame rate of the IRR loader.
+ * 
+ * IRR animations are difficult to convert for Assimp and there will
+ * always be a loss of quality. This setting defines how many keys per second
+ * are returned by the converter.<br>
+ * Property type: integer. Default value: 100
  */
  */
-#define AI_CONFIG_PP_TUV_EVALUATE				\
-	"PP_TUV_EVALUATE"
+#define AI_CONFIG_IMPORT_IRR_ANIM_FPS				\
+	"IMPORT_IRR_ANIM_FPS"
 
 
 
 
-// ---------------------------------------------------------------------------
-/** @brief A hint to assimp to favour speed against import quality.
- *
- * Enabling this option may result in faster loading, but it needn't.
- * It represents just a hint to loaders and post-processing steps to use
- * faster code paths, if possible. 
- * This property is expected to be an integer, != 0 stands for true.
- * The default value is 0.
- */
-#define AI_CONFIG_FAVOUR_SPEED				\
- "FAVOUR_SPEED"
 
 
 #endif // !! AI_CONFIG_H_INC
 #endif // !! AI_CONFIG_H_INC

+ 44 - 5
include/aiPostProcess.h

@@ -416,6 +416,46 @@ enum aiPostProcessSteps
 	 */
 	 */
 	aiProcess_FindInstances = 0x100000,
 	aiProcess_FindInstances = 0x100000,
 
 
+	// -------------------------------------------------------------------------
+	/** <hr>A postprocessing step to reduce the number of meshes.
+	 *
+	 *  In fact, it will reduce the number of drawcalls.
+	 *
+	 *  This is a very effective optimization and is recommended to be used
+	 *  together with #aiProcess_OptimizeGraph, if possible. The flag is fully
+	 *  compatible with both #aiProcess_SplitLargeMeshes and #aiProcess_SortByPType.
+	*/
+	aiProcess_OptimizeMeshes  = 0x200000, 
+
+
+	// -------------------------------------------------------------------------
+	/** <hr>A postprocessing step to optimize the scene hierarchy. 
+	 *
+	 *  Nodes with no animations, bones, lights or cameras assigned are 
+	 *  collapsed and joined.
+	 *
+	 *  Node names can be lost during this step. If you use special 'tag nodes'
+	 *  to pass additional information through your content pipeline, use the
+	 *  <tt>#AI_CONFIG_PP_OG_EXCLUDE_LIST<7tt> setting to specify a list of node 
+	 *  names you want to be kept. Nodes matching one of the names in this list won't
+	 *  be touched or modified.
+	 *
+	 *  Use this flag with caution. Most simple files will be collapsed to a 
+	 *  single node, complex hierarchies are usually completely lost. That's not
+	 *  the right choice for editor environments, but probably a very effective
+	 *  optimization if you just want to get the model data, convert it to your
+	 *  own format and render it as fast as possible. 
+	 *
+	 *  This flag is designed to be used with #aiProcess_OptimizeMeshes for best
+	 *  results.
+	 *
+	 *  @note 'crappy' scenes with thousands of extremely small meshes packed
+	 *  in deeply nested nodes exist for almost all file formats.
+	 *  #aiProcess_OptimizeMeshes in combination with #aiProcess_OptimizeGraph 
+	 *  usually fixes them all and makes them renderable. 
+	*/
+	aiProcess_OptimizeGraph  = 0x400000, 
+
 	// -------------------------------------------------------------------------
 	// -------------------------------------------------------------------------
 	/** <hr>This step flips all UV coordinates along the y-axis and adjusts
 	/** <hr>This step flips all UV coordinates along the y-axis and adjusts
 	 * material settings and bitangents accordingly.
 	 * material settings and bitangents accordingly.
@@ -433,7 +473,7 @@ enum aiPostProcessSteps
 	 * setting and boundles all conversions typically required for D3D-based
 	 * setting and boundles all conversions typically required for D3D-based
 	 * applications.
 	 * applications.
 	*/
 	*/
-	aiProcess_FlipUVs = 0x80000000, /* don't change */
+	aiProcess_FlipUVs = 0x800000, 
 
 
 	// -------------------------------------------------------------------------
 	// -------------------------------------------------------------------------
 	/** <hr>This step adjusts the output face winding order to be cw.
 	/** <hr>This step adjusts the output face winding order to be cw.
@@ -447,13 +487,11 @@ enum aiPostProcessSteps
 	 *  x1
 	 *  x1
 	 * @endcode
 	 * @endcode
 	*/
 	*/
-	aiProcess_FlipWindingOrder  = 0x40000000 /* don't change */
-
-
+	aiProcess_FlipWindingOrder  = 0x1000000
 
 
 	// aiProcess_GenEntityMeshes = 0x100000,
 	// aiProcess_GenEntityMeshes = 0x100000,
 	// aiProcess_OptimizeAnimations = 0x200000
 	// aiProcess_OptimizeAnimations = 0x200000
-	// aiProcess_OptimizeNodes      = 0x400000
+	// aiProcess_FixTexturePaths = 0x200000
 };
 };
 
 
 
 
@@ -547,6 +585,7 @@ enum aiPostProcessSteps
 	aiProcessPreset_TargetRealtime_Quality   |  \
 	aiProcessPreset_TargetRealtime_Quality   |  \
 	aiProcess_FindInstances                  |  \
 	aiProcess_FindInstances                  |  \
 	aiProcess_ValidateDataStructure          |  \
 	aiProcess_ValidateDataStructure          |  \
+	aiProcess_OptimizeMeshes                 |  \
 	0 )
 	0 )
 
 
 
 

+ 50 - 98
include/assimp.hpp

@@ -39,44 +39,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 */
 */
 
 
-/** @file assimp.hpp
+/** @file  assimp.hpp
  *  @brief Defines the C++-API to the Open Asset Import Library.
  *  @brief Defines the C++-API to the Open Asset Import Library.
  */
  */
 #ifndef INCLUDED_AI_ASSIMP_HPP
 #ifndef INCLUDED_AI_ASSIMP_HPP
 #define INCLUDED_AI_ASSIMP_HPP
 #define INCLUDED_AI_ASSIMP_HPP
 
 
 #ifndef __cplusplus
 #ifndef __cplusplus
-#	error This header requires C++ to be used. Use Assimp's C-API (assimp.h) \
-          to access the library from C code.
+#	error This header requires C++ to be used. Use assimp.h for plain C. 
 #endif
 #endif
 
 
-#include <map>
-#include <vector>
-
-// Public ASSIMP data structure headers
+// Public ASSIMP data structures
 #include "aiTypes.h"
 #include "aiTypes.h"
 #include "aiConfig.h"
 #include "aiConfig.h"
 #include "aiAssert.h"
 #include "aiAssert.h"
 
 
 namespace Assimp	{
 namespace Assimp	{
-
 	// =======================================================================
 	// =======================================================================
 	// Public interface to Assimp 
 	// Public interface to Assimp 
-	// =======================================================================
 	class Importer;
 	class Importer;
 	class IOStream;
 	class IOStream;
 	class IOSystem;
 	class IOSystem;
 
 
 	// =======================================================================
 	// =======================================================================
 	// Plugin development
 	// Plugin development
-	// Include the following headers for the definitions:
-	// =======================================================================
+	//
+	// Include the following headers for the declarations:
 	// BaseImporter.h
 	// BaseImporter.h
 	// BaseProcess.h
 	// BaseProcess.h
 	class BaseImporter;
 	class BaseImporter;
 	class BaseProcess;
 	class BaseProcess;
 	class SharedPostProcessInfo;
 	class SharedPostProcessInfo;
 	class BatchLoader;
 	class BatchLoader;
+
+	// =======================================================================
+	// Holy stuff, only for members of the high council of the Jedi.
+	class ImporterPimpl;
 } //! namespace Assimp
 } //! namespace Assimp
 
 
 #define AI_PROPERTY_WAS_NOT_EXISTING 0xffffffff
 #define AI_PROPERTY_WAS_NOT_EXISTING 0xffffffff
@@ -109,7 +107,7 @@ namespace Assimp	{
 * standard C++ IO logic will be used.
 * standard C++ IO logic will be used.
 *
 *
 * @note One Importer instance is not thread-safe. If you use multiple
 * @note One Importer instance is not thread-safe. If you use multiple
-* threads for loading each thread should maintain its own Importer instance.
+* threads for loading, each thread should maintain its own Importer instance.
 */
 */
 class ASSIMP_API Importer
 class ASSIMP_API Importer
 {
 {
@@ -118,23 +116,16 @@ class ASSIMP_API Importer
 	friend class BatchLoader;
 	friend class BatchLoader;
 	friend const aiScene* ::aiImportFileEx( const char*, unsigned int, aiFileIO*);
 	friend const aiScene* ::aiImportFileEx( const char*, unsigned int, aiFileIO*);
 
 
-public:
-
-	typedef unsigned int KeyType;
-	typedef std::map<KeyType, int>  		IntPropertyMap;
-	typedef std::map<KeyType, float>		FloatPropertyMap;
-	typedef std::map<KeyType, std::string>	StringPropertyMap;
-
 public:
 public:
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Constructor. Creates an empty importer object. 
 	/** Constructor. Creates an empty importer object. 
 	 * 
 	 * 
-	 * Call ReadFile() to start the import process.
+	 * Call ReadFile() to start the import process. The configuration
+	 * property table is initially empty.
 	 */
 	 */
 	Importer();
 	Importer();
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Copy constructor.
 	/** Copy constructor.
 	 * 
 	 * 
@@ -144,7 +135,6 @@ public:
 	 */
 	 */
 	Importer(const Importer& other);
 	Importer(const Importer& other);
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Destructor. The object kept ownership of the imported data,
 	/** Destructor. The object kept ownership of the imported data,
 	 * which now will be destroyed along with the object. 
 	 * which now will be destroyed along with the object. 
@@ -163,7 +153,6 @@ public:
 	 */
 	 */
 	aiReturn RegisterLoader(BaseImporter* pImp);
 	aiReturn RegisterLoader(BaseImporter* pImp);
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Unregisters a loader.
 	/** Unregisters a loader.
 	 *
 	 *
@@ -230,7 +219,6 @@ public:
 	void SetPropertyString(const char* szName, const std::string& sValue, 
 	void SetPropertyString(const char* szName, const std::string& sValue, 
 		bool* bWasExisting = NULL);
 		bool* bWasExisting = NULL);
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Get a configuration property.
 	/** Get a configuration property.
 	 * @param szName Name of the property. All supported properties
 	 * @param szName Name of the property. All supported properties
@@ -263,7 +251,6 @@ public:
 	const std::string& GetPropertyString(const char* szName,
 	const std::string& GetPropertyString(const char* szName,
 		const std::string& sErrorReturn = "") const;
 		const std::string& sErrorReturn = "") const;
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Supplies a custom IO handler to the importer to use to open and
 	/** Supplies a custom IO handler to the importer to use to open and
 	 * access files. If you need the importer to use custion IO logic to 
 	 * access files. If you need the importer to use custion IO logic to 
@@ -281,7 +268,6 @@ public:
 	 */
 	 */
 	void SetIOHandler( IOSystem* pIOHandler);
 	void SetIOHandler( IOSystem* pIOHandler);
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Retrieves the IO handler that is currently set.
 	/** Retrieves the IO handler that is currently set.
 	 * You can use IsDefaultIOHandler() to check whether the returned
 	 * You can use IsDefaultIOHandler() to check whether the returned
@@ -292,7 +278,6 @@ public:
 	 */
 	 */
 	IOSystem* GetIOHandler();
 	IOSystem* GetIOHandler();
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Checks whether a default IO handler is active 
 	/** Checks whether a default IO handler is active 
 	 * A default handler is active as long the application doesn't 
 	 * A default handler is active as long the application doesn't 
@@ -301,7 +286,6 @@ public:
 	 */
 	 */
 	bool IsDefaultIOHandler();
 	bool IsDefaultIOHandler();
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** @brief Check whether a given set of postprocessing flags
 	/** @brief Check whether a given set of postprocessing flags
 	 *  is supported.
 	 *  is supported.
@@ -348,7 +332,6 @@ public:
 	 */
 	 */
 	const aiScene* ReadFile( const std::string& pFile, unsigned int pFlags);
 	const aiScene* ReadFile( const std::string& pFile, unsigned int pFlags);
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Frees the current scene.
 	/** Frees the current scene.
 	 *
 	 *
@@ -358,25 +341,26 @@ public:
 	 */
 	 */
 	void FreeScene( );
 	void FreeScene( );
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Returns an error description of an error that occurred in ReadFile(). 
 	/** Returns an error description of an error that occurred in ReadFile(). 
-	*
-	* Returns an empty string if no error occurred.
-	* @return A description of the last error, an empty string if no 
-	*   error occurred.
-	*/
-	const std::string& GetErrorString() const;
-
+	 *
+	 * Returns an empty string if no error occurred.
+	 * @return A description of the last error, an empty string if no 
+	 *   error occurred. The string is never NULL.
+	 *
+	 * @note The returned function remains valid until one of the 
+	 * following methods is called: #ReadFile(), #FreeScene().
+	 */
+	const char* GetErrorString() const;
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Returns whether a given file extension is supported by ASSIMP.
 	/** Returns whether a given file extension is supported by ASSIMP.
-	*
-	* @param szExtension Extension to be checked.
-	*   Must include a trailing dot '.'. Example: ".3ds", ".md3".
-	*   Cases-insensitive.
-	* @return true if the extension is supported, false otherwise
-	*/
+	 *
+	 * @param szExtension Extension to be checked.
+	 *   Must include a trailing dot '.'. Example: ".3ds", ".md3".
+	 *   Cases-insensitive.
+	 * @return true if the extension is supported, false otherwise
+	 */
 	bool IsExtensionSupported(const char* szExtension);
 	bool IsExtensionSupported(const char* szExtension);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
@@ -386,18 +370,17 @@ public:
 	 * See the const char* version for detailled docs.
 	 * See the const char* version for detailled docs.
 	 * @see IsExtensionSupported(const char*)
 	 * @see IsExtensionSupported(const char*)
 	 */
 	 */
-	bool IsExtensionSupported(const std::string& szExtension);
-
+	inline bool IsExtensionSupported(const std::string& szExtension);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Get a full list of all file extensions supported by ASSIMP.
 	/** Get a full list of all file extensions supported by ASSIMP.
-	*
-	* If a file extension is contained in the list this does, of course, not
-	* mean that ASSIMP is able to load all files with this extension.
-	* @param szOut String to receive the extension list. It just means there
-    *   is a loader which handles such files.
-	*   Format of the list: "*.3ds;*.obj;*.dae". 
-	*/
+	 *
+	 * If a file extension is contained in the list this does of course not
+	 * mean that ASSIMP is able to load all files with this extension.
+	 * @param szOut String to receive the extension list. It just means there
+     *   is a loader which handles such files.
+	 *   Format of the list: "*.3ds;*.obj;*.dae". 
+	 */
 	void GetExtensionList(aiString& szOut);
 	void GetExtensionList(aiString& szOut);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
@@ -409,7 +392,6 @@ public:
 	 */
 	 */
 	inline void GetExtensionList(std::string& szOut);
 	inline void GetExtensionList(std::string& szOut);
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Find the loader corresponding to a specific file extension.
 	/** Find the loader corresponding to a specific file extension.
 	*
 	*
@@ -421,7 +403,6 @@ public:
 	*/
 	*/
 	BaseImporter* FindLoader (const char* szExtension);
 	BaseImporter* FindLoader (const char* szExtension);
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Returns the scene loaded by the last successful call to ReadFile()
 	/** Returns the scene loaded by the last successful call to ReadFile()
 	 *
 	 *
@@ -429,7 +410,6 @@ public:
 	 */
 	 */
 	const aiScene* GetScene() const;
 	const aiScene* GetScene() const;
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Returns the scene loaded by the last successful call to ReadFile()
 	/** Returns the scene loaded by the last successful call to ReadFile()
 	 *  and releases the scene from the ownership of the Importer 
 	 *  and releases the scene from the ownership of the Importer 
@@ -438,62 +418,34 @@ public:
 	 *  will return NULL - until a new scene has been loaded via ReadFile().
 	 *  will return NULL - until a new scene has been loaded via ReadFile().
 	 *
 	 *
 	 * @return Current scene or NULL if there is currently no scene loaded
 	 * @return Current scene or NULL if there is currently no scene loaded
+	 * @note Under windows, deleting the returned scene manually will 
+	 * probably not work properly in applications using static runtime linkage.
 	 */
 	 */
 	aiScene* GetOrphanedScene();
 	aiScene* GetOrphanedScene();
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	/** Returns the storage allocated by ASSIMP to hold the asset data
+	/** Returns the storage allocated by ASSIMP to hold the scene data
 	 * in memory.
 	 * in memory.
-	 * \param in Data structure to be filled. 
+	 *
+	 * This refers to the currently loaded file, see #ReadFile().
+	 * @param in Data structure to be filled. 
 	*/
 	*/
 	void GetMemoryRequirements(aiMemoryInfo& in) const;
 	void GetMemoryRequirements(aiMemoryInfo& in) const;
 
 
-
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
-	/** Enables the "extra verbose" mode. In this mode the data 
-	* structure is validated after each post-process step to make sure
-	* all steps behave consequently in the same manner when modifying
-	* data structures.
-	*/
+	/** Enables "extra verbose" mode. 
+	 *
+	 * In this mode the data structure is validated after every single
+	 * post processing step to make sure everyone modifies the data
+	 * structure in the defined manner. This is a debug feature and not
+	 * intended for public use.
+	 */
 	void SetExtraVerbose(bool bDo);
 	void SetExtraVerbose(bool bDo);
 
 
 protected:
 protected:
 
 
-	/** IO handler to use for all file accesses. */
-	IOSystem* mIOHandler;
-	bool mIsDefaultHandler;
-
-	/** Format-specific importer worker objects - 
-	 * one for each format we can read. */
-	std::vector<BaseImporter*> mImporter;
-
-	/** Post processing steps we can apply at the imported data. */
-	std::vector<BaseProcess*> mPostProcessingSteps;
-
-	/** The imported data, if ReadFile() was successful,
-	 * NULL otherwise. */
-	aiScene* mScene;
-
-	/** The error description, if there was one. */
-	std::string mErrorString;
-
-	/** List of integer properties */
-	IntPropertyMap mIntProperties;
-
-	/** List of floating-point properties */
-	FloatPropertyMap mFloatProperties;
-
-	/** List of string properties */
-	StringPropertyMap mStringProperties;
-
-	/** Used for testing - extra verbose mode causes the
-	    validateDataStructure-Step to be executed before
-		 and after every single postprocess step */
-	bool bExtraVerbose;
-
-	/** Used by post-process steps to share data */
-	SharedPostProcessInfo* mPPShared;
+	// Just because we don't want you to know how we're hacking around.
+	ImporterPimpl* pimpl;
 }; //! class Importer
 }; //! class Importer
 
 
 
 

+ 1 - 1
mkutil/revision.h

@@ -1 +1 @@
-#define SVNRevision  394 
+#define SVNRevision  402 

+ 24 - 2
tools/assimp_cmd/Main.cpp

@@ -190,12 +190,15 @@ int ProcessStandardArguments(ImportData& fill, const char** params,
 	// -lh     --convert-to-lh
 	// -lh     --convert-to-lh
 	// -fuv    --flip-uv
 	// -fuv    --flip-uv
 	// -fwo    --flip-winding-order
 	// -fwo    --flip-winding-order
-	// -ett    --evaluate-texture-transform
+	// -tuv    --transform-uv-coords
 	// -guv    --gen-uvcoords
 	// -guv    --gen-uvcoords
 	// -fid    --find-invalid-data
 	// -fid    --find-invalid-data
 	// -fixn   --fix normals
 	// -fixn   --fix normals
 	// -tri    --triangulate
 	// -tri    --triangulate
 	// -fi     --find-instances
 	// -fi     --find-instances
+	// -fi     --find-instances
+	// -og     --optimize-graph
+	// -om     --optimize-meshes
 	//
 	//
 	// -c<file> --config-file=<file>
 	// -c<file> --config-file=<file>
 
 
@@ -248,7 +251,7 @@ int ProcessStandardArguments(ImportData& fill, const char** params,
 		else if (! ::strcmp(params[i], "-fwo") || ! ::strcmp(params[i], "--flip-winding-order")) {
 		else if (! ::strcmp(params[i], "-fwo") || ! ::strcmp(params[i], "--flip-winding-order")) {
 			fill.ppFlags |= aiProcess_ConvertToLeftHanded;
 			fill.ppFlags |= aiProcess_ConvertToLeftHanded;
 		}
 		}
-		else if (! ::strcmp(params[i], "-ett") || ! ::strcmp(params[i], "--evaluate-texture-transform")) {
+		else if (! ::strcmp(params[i], "-tuv") || ! ::strcmp(params[i], "--transform-uv-coords")) {
 			fill.ppFlags |= aiProcess_TransformUVCoords;
 			fill.ppFlags |= aiProcess_TransformUVCoords;
 		}
 		}
 		else if (! ::strcmp(params[i], "-guv") || ! ::strcmp(params[i], "--gen-uvcoords")) {
 		else if (! ::strcmp(params[i], "-guv") || ! ::strcmp(params[i], "--gen-uvcoords")) {
@@ -269,6 +272,25 @@ int ProcessStandardArguments(ImportData& fill, const char** params,
 		else if (! ::strcmp(params[i], "-fi") || ! ::strcmp(params[i], "--find-instances")) {
 		else if (! ::strcmp(params[i], "-fi") || ! ::strcmp(params[i], "--find-instances")) {
 			fill.ppFlags |= aiProcess_FindInstances;
 			fill.ppFlags |= aiProcess_FindInstances;
 		}
 		}
+		else if (! ::strcmp(params[i], "-og") || ! ::strcmp(params[i], "--optimize-graph")) {
+			fill.ppFlags |= aiProcess_OptimizeGraph;
+		}
+		else if (! ::strcmp(params[i], "-om") || ! ::strcmp(params[i], "--optimize-meshes")) {
+			fill.ppFlags |= aiProcess_OptimizeMeshes;
+		}
+
+#if 0
+		else if (! ::strcmp(params[i], "-oa") || ! ::strcmp(params[i], "--optimize-anims")) {
+			fill.ppFlags |= aiProcess_OptimizeAnims;
+		}
+		else if (! ::strcmp(params[i], "-gem") || ! ::strcmp(params[i], "--gen-entity-meshes")) {
+			fill.ppFlags |= aiProcess_GenEntityMeshes;
+		}
+		else if (! ::strcmp(params[i], "-ftp") || ! ::strcmp(params[i], "--fix-texture-paths")) {
+			fill.ppFlags |= aiProcess_FixTexturePaths;
+		}
+#endif
+
 		else if (! ::strncmp(params[i], "-c",2) || ! ::strncmp(params[i], "--config=",9)) {
 		else if (! ::strncmp(params[i], "-c",2) || ! ::strncmp(params[i], "--config=",9)) {
 			
 			
 			const unsigned int ofs = (params[i][1] == '-' ? 9 : 2);
 			const unsigned int ofs = (params[i][1] == '-' ? 9 : 2);

+ 2 - 0
tools/assimp_view/SceneAnimator.h

@@ -47,6 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AV_SCENEANIMATOR_H_INCLUDED
 #ifndef AV_SCENEANIMATOR_H_INCLUDED
 #define AV_SCENEANIMATOR_H_INCLUDED
 #define AV_SCENEANIMATOR_H_INCLUDED
 
 
+#include <map>
+
 namespace AssimpView	{
 namespace AssimpView	{
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------

+ 2 - 0
tools/assimp_view/assimp_view.cpp

@@ -151,6 +151,8 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
 		aiProcess_TransformUVCoords        | // preprocess UV transformations (scaling, translation ...)
 		aiProcess_TransformUVCoords        | // preprocess UV transformations (scaling, translation ...)
 		aiProcess_FindInstances            | // search for instanced meshes and remove them by references to one master
 		aiProcess_FindInstances            | // search for instanced meshes and remove them by references to one master
 		aiProcess_LimitBoneWeights         | // limit bone weights to 4 per vertex
 		aiProcess_LimitBoneWeights         | // limit bone weights to 4 per vertex
+		aiProcess_OptimizeMeshes		   | // join small meshes, if possible
+//		aiProcess_OptimizeGraph            | // optimize unneeded nodes away
 //		aiProcess_PreTransformVertices |
 //		aiProcess_PreTransformVertices |
 		0);
 		0);
 
 

+ 333 - 177
workspaces/vc8/assimp.vcproj

@@ -1328,148 +1328,148 @@
 		<Filter
 		<Filter
 			Name="sources"
 			Name="sources"
 			>
 			>
-			<File
-				RelativePath="..\..\code\aiAssert.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\Assimp.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\BaseImporter.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\BaseImporter.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\BaseProcess.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\BaseProcess.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\FileSystemFilter.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\IFF.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\Importer.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\MaterialSystem.cpp"
-				>
-				<FileConfiguration
-					Name="release|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						GeneratePreprocessedFile="0"
-					/>
-				</FileConfiguration>
-				<FileConfiguration
-					Name="release-dll|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-						GeneratePreprocessedFile="0"
-					/>
-				</FileConfiguration>
-			</File>
-			<File
-				RelativePath="..\..\code\MaterialSystem.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\RemoveComments.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\RemoveComments.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SceneCombiner.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SceneCombiner.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\ScenePreprocessor.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\ScenePreprocessor.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SGSpatialSort.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SGSpatialSort.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SkeletonMeshBuilder.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SkeletonMeshBuilder.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SmoothingGroups.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SmoothingGroups.inl"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SpatialSort.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\SpatialSort.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\StandardShapes.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\StandardShapes.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\TargetAnimation.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\TargetAnimation.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\VertexTriangleAdjacency.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\..\code\VertexTriangleAdjacency.h"
-				>
-			</File>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 			<Filter
 			<Filter
-				Name="Extra"
+				Name="extra"
 				>
 				>
 				<File
 				<File
 					RelativePath="..\..\code\extra\MakeVerboseFormat.cpp"
 					RelativePath="..\..\code\extra\MakeVerboseFormat.cpp"
@@ -1573,10 +1573,10 @@
 				</File>
 				</File>
 			</Filter>
 			</Filter>
 			<Filter
 			<Filter
-				Name="Loaders"
+				Name="import"
 				>
 				>
 				<Filter
 				<Filter
-					Name="3DS"
+					Name="3ds"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\3DSConverter.cpp"
 						RelativePath="..\..\code\3DSConverter.cpp"
@@ -1596,7 +1596,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="ASE"
+					Name="ase"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\ASELoader.cpp"
 						RelativePath="..\..\code\ASELoader.cpp"
@@ -1616,7 +1616,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="HMP"
+					Name="hmp"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\HMPFileData.h"
 						RelativePath="..\..\code\HMPFileData.h"
@@ -1632,7 +1632,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="LWO"
+					Name="lwo"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\LWOBLoader.cpp"
 						RelativePath="..\..\code\LWOBLoader.cpp"
@@ -1656,7 +1656,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="MD2"
+					Name="md2"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\MD2FileData.h"
 						RelativePath="..\..\code\MD2FileData.h"
@@ -1676,7 +1676,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="MD3"
+					Name="md3"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\MD3FileData.h"
 						RelativePath="..\..\code\MD3FileData.h"
@@ -1692,7 +1692,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="MD5"
+					Name="md5"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\MD5Loader.cpp"
 						RelativePath="..\..\code\MD5Loader.cpp"
@@ -1712,7 +1712,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="MDC"
+					Name="mdc"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\MDCFileData.h"
 						RelativePath="..\..\code\MDCFileData.h"
@@ -1732,7 +1732,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="MDL"
+					Name="mdl"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\HalfLifeFileData.h"
 						RelativePath="..\..\code\HalfLifeFileData.h"
@@ -1760,7 +1760,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="Obj"
+					Name="obj"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\ObjFileData.h"
 						RelativePath="..\..\code\ObjFileData.h"
@@ -1796,7 +1796,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="Ply"
+					Name="ply"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\PlyLoader.cpp"
 						RelativePath="..\..\code\PlyLoader.cpp"
@@ -1816,7 +1816,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="SMD"
+					Name="smd"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\SMDLoader.cpp"
 						RelativePath="..\..\code\SMDLoader.cpp"
@@ -1828,7 +1828,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="STL"
+					Name="stl"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\STLLoader.cpp"
 						RelativePath="..\..\code\STLLoader.cpp"
@@ -1840,7 +1840,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="X"
+					Name="x"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\XFileHelper.h"
 						RelativePath="..\..\code\XFileHelper.h"
@@ -1864,7 +1864,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="DXF"
+					Name="dxf"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\DXFLoader.cpp"
 						RelativePath="..\..\code\DXFLoader.cpp"
@@ -1876,7 +1876,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="RAW"
+					Name="raw"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\RawLoader.cpp"
 						RelativePath="..\..\code\RawLoader.cpp"
@@ -1888,7 +1888,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="NFF"
+					Name="nff"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\NFFLoader.cpp"
 						RelativePath="..\..\code\NFFLoader.cpp"
@@ -1900,11 +1900,11 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="VRML97"
+					Name="vrml97"
 					>
 					>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="OFF"
+					Name="off"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\OFFLoader.cpp"
 						RelativePath="..\..\code\OFFLoader.cpp"
@@ -1916,7 +1916,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="AC"
+					Name="ac"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\ACLoader.cpp"
 						RelativePath="..\..\code\ACLoader.cpp"
@@ -1952,7 +1952,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="LWS"
+					Name="lws"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\LWOAnimation.cpp"
 						RelativePath="..\..\code\LWOAnimation.cpp"
@@ -1972,7 +1972,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="BVH"
+					Name="bvh"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\BVHLoader.cpp"
 						RelativePath="..\..\code\BVHLoader.cpp"
@@ -1984,7 +1984,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="IRRMesh"
+					Name="irrmesh"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\IRRMeshLoader.cpp"
 						RelativePath="..\..\code\IRRMeshLoader.cpp"
@@ -1996,7 +1996,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="IRR"
+					Name="irr"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\IRRLoader.cpp"
 						RelativePath="..\..\code\IRRLoader.cpp"
@@ -2016,7 +2016,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="Q3D"
+					Name="q3d"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\Q3DLoader.cpp"
 						RelativePath="..\..\code\Q3DLoader.cpp"
@@ -2028,7 +2028,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="B3D"
+					Name="b3d"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\B3DImporter.cpp"
 						RelativePath="..\..\code\B3DImporter.cpp"
@@ -2040,7 +2040,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="TER"
+					Name="ter"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\TerragenLoader.cpp"
 						RelativePath="..\..\code\TerragenLoader.cpp"
@@ -2052,7 +2052,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="Unreal"
+					Name="unreal"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\UnrealLoader.cpp"
 						RelativePath="..\..\code\UnrealLoader.cpp"
@@ -2064,7 +2064,7 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 				<Filter
 				<Filter
-					Name="Collada"
+					Name="collada"
 					>
 					>
 					<File
 					<File
 						RelativePath="..\..\code\ColladaHelper.h"
 						RelativePath="..\..\code\ColladaHelper.h"
@@ -2089,7 +2089,7 @@
 				</Filter>
 				</Filter>
 			</Filter>
 			</Filter>
 			<Filter
 			<Filter
-				Name="PostProcess"
+				Name="process"
 				>
 				>
 				<File
 				<File
 					RelativePath="..\..\code\CalcTangentsProcess.cpp"
 					RelativePath="..\..\code\CalcTangentsProcess.cpp"
@@ -2195,6 +2195,22 @@
 					RelativePath="..\..\code\LimitBoneWeightsProcess.h"
 					RelativePath="..\..\code\LimitBoneWeightsProcess.h"
 					>
 					>
 				</File>
 				</File>
+				<File
+					RelativePath="..\..\code\OptimizeGraph.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\OptimizeGraph.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\OptimizeMeshes.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\OptimizeMeshes.h"
+					>
+				</File>
 				<File
 				<File
 					RelativePath="..\..\code\PretransformVertices.cpp"
 					RelativePath="..\..\code\PretransformVertices.cpp"
 					>
 					>
@@ -2261,7 +2277,7 @@
 				</File>
 				</File>
 			</Filter>
 			</Filter>
 			<Filter
 			<Filter
-				Name="PCH"
+				Name="pch"
 				>
 				>
 				<File
 				<File
 					RelativePath="..\..\code\AssimpPCH.cpp"
 					RelativePath="..\..\code\AssimpPCH.cpp"
@@ -2369,7 +2385,7 @@
 				</File>
 				</File>
 			</Filter>
 			</Filter>
 			<Filter
 			<Filter
-				Name="Logging"
+				Name="logging"
 				>
 				>
 				<File
 				<File
 					RelativePath="..\..\code\DefaultLogger.cpp"
 					RelativePath="..\..\code\DefaultLogger.cpp"
@@ -2389,7 +2405,7 @@
 				</File>
 				</File>
 			</Filter>
 			</Filter>
 			<Filter
 			<Filter
-				Name="FileSystem"
+				Name="fs"
 				>
 				>
 				<File
 				<File
 					RelativePath="..\..\code\DefaultIOStream.cpp"
 					RelativePath="..\..\code\DefaultIOStream.cpp"
@@ -2413,7 +2429,7 @@
 				</File>
 				</File>
 			</Filter>
 			</Filter>
 			<Filter
 			<Filter
-				Name="Util"
+				Name="util"
 				>
 				>
 				<File
 				<File
 					RelativePath="..\..\code\ByteSwap.h"
 					RelativePath="..\..\code\ByteSwap.h"
@@ -2449,7 +2465,7 @@
 				</File>
 				</File>
 			</Filter>
 			</Filter>
 			<Filter
 			<Filter
-				Name="Extern"
+				Name="extern"
 				>
 				>
 				<Filter
 				<Filter
 					Name="irrXML"
 					Name="irrXML"
@@ -3452,6 +3468,146 @@
 					</File>
 					</File>
 				</Filter>
 				</Filter>
 			</Filter>
 			</Filter>
+			<Filter
+				Name="core"
+				>
+				<File
+					RelativePath="..\..\code\aiAssert.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\Assimp.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\BaseImporter.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\BaseImporter.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\BaseProcess.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\BaseProcess.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\IFF.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\Importer.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\MaterialSystem.cpp"
+					>
+					<FileConfiguration
+						Name="release|Win32"
+						>
+						<Tool
+							Name="VCCLCompilerTool"
+							GeneratePreprocessedFile="0"
+						/>
+					</FileConfiguration>
+					<FileConfiguration
+						Name="release-dll|Win32"
+						>
+						<Tool
+							Name="VCCLCompilerTool"
+							GeneratePreprocessedFile="0"
+						/>
+					</FileConfiguration>
+				</File>
+				<File
+					RelativePath="..\..\code\MaterialSystem.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\RemoveComments.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\RemoveComments.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SceneCombiner.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SceneCombiner.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\ScenePreprocessor.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\ScenePreprocessor.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SGSpatialSort.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SGSpatialSort.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SkeletonMeshBuilder.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SkeletonMeshBuilder.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SmoothingGroups.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SmoothingGroups.inl"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SpatialSort.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\SpatialSort.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\StandardShapes.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\StandardShapes.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\TargetAnimation.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\TargetAnimation.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\VertexTriangleAdjacency.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\VertexTriangleAdjacency.h"
+					>
+				</File>
+			</Filter>
 		</Filter>
 		</Filter>
 		<Filter
 		<Filter
 			Name="doc"
 			Name="doc"

+ 16 - 0
workspaces/vc9/assimp.vcproj

@@ -2023,6 +2023,22 @@
 					RelativePath="..\..\code\LimitBoneWeightsProcess.h"
 					RelativePath="..\..\code\LimitBoneWeightsProcess.h"
 					>
 					>
 				</File>
 				</File>
+				<File
+					RelativePath="..\..\code\OptimizeGraph.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\OptimizeGraph.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\OptimizeMeshes.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\code\OptimizeMeshes.h"
+					>
+				</File>
 				<File
 				<File
 					RelativePath="..\..\code\PretransformVertices.cpp"
 					RelativePath="..\..\code\PretransformVertices.cpp"
 					>
 					>