diff --git a/code/Assimp.cpp b/code/Assimp.cpp index eb8104dcb..5eae9f8eb 100644 --- a/code/Assimp.cpp +++ b/code/Assimp.cpp @@ -67,9 +67,9 @@ static ImporterMap gActiveImports; static std::string gLastErrorString; /** 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) /** 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 // (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 if (pFS) diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index 9daa0922b..a42ccece1 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -371,9 +371,9 @@ void BatchLoader::LoadAll() pp |= aiProcess_ValidateDataStructure; #endif // 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()) { diff --git a/code/BaseImporter.h b/code/BaseImporter.h index 419b1426a..706454927 100644 --- a/code/BaseImporter.h +++ b/code/BaseImporter.h @@ -76,6 +76,62 @@ private: 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 IntPropertyMap; + typedef std::map FloatPropertyMap; + typedef std::map 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 mImporter; + + /** Post processing steps we can apply at the imported data. */ + std::vector 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 * classes. @@ -334,11 +390,12 @@ public: */ 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 { + // fixme: really isocpp? gcc complains return ints == prop.ints && floats == prop.floats && strings == prop.strings; } diff --git a/code/BaseProcess.cpp b/code/BaseProcess.cpp index ed639fef4..6d6accb8a 100644 --- a/code/BaseProcess.cpp +++ b/code/BaseProcess.cpp @@ -64,24 +64,24 @@ BaseProcess::~BaseProcess() // ------------------------------------------------------------------------------------------------ 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 try { - Execute(pImp->mScene); + Execute(pImp->pimpl->mScene); } catch( ImportErrorException* exception) { // 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; // and kill the partially imported data - delete pImp->mScene; - pImp->mScene = NULL; + delete pImp->pimpl->mScene; + pImp->pimpl->mScene = NULL; } } diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 608dfadce..2346b0522 100644 --- a/code/CMakeLists.txt +++ b/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) diff --git a/code/Importer.cpp b/code/Importer.cpp index 924c547e0..5d74c3aef 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -157,7 +157,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # include "LWSLoader.h" #endif - // ======================================================================================= // PostProcess-Steps // ======================================================================================= @@ -221,6 +220,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_BUILD_NO_FINDINSTANCES_PROCESS # include "FindInstancesProcess.h" #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::Intern; @@ -230,273 +235,264 @@ using namespace Assimp::Intern; // new and delete (and their array counterparts) of public API classes (e.g. Logger) to // 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); } -void AllocateFromAssimpHeap::operator delete ( void* data) -{ +void AllocateFromAssimpHeap::operator delete ( void* 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); } -void AllocateFromAssimpHeap::operator delete[] ( void* data) -{ +void AllocateFromAssimpHeap::operator delete[] ( void* data) { return ::operator delete[](data); } // ------------------------------------------------------------------------------------------------ -// Importer Constructor. +// Importer constructor. Importer::Importer() - : mIOHandler (NULL) - , mScene (NULL) - , mErrorString ("") { - // Allocate a default IO handler - mIOHandler = new DefaultIOSystem; - mIsDefaultHandler = true; - bExtraVerbose = false; // disable extra verbose mode by default + // allocate the pimpl first + pimpl = new ImporterPimpl(); - // ====================================================================== + pimpl->mScene = NULL; + pimpl->mErrorString = ""; + + // Allocate a default IO handler + pimpl->mIOHandler = new DefaultIOSystem; + pimpl->mIsDefaultHandler = true; + pimpl->bExtraVerbose = false; // disable extra verbose mode by default + + // ---------------------------------------------------------------------------- // 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. - // ====================================================================== - mImporter.reserve(25); + // ---------------------------------------------------------------------------- + pimpl->mImporter.reserve(25); #if (!defined AI_BUILD_NO_X_IMPORTER) - mImporter.push_back( new XFileImporter()); + pimpl->mImporter.push_back( new XFileImporter()); #endif #if (!defined AI_BUILD_NO_OBJ_IMPORTER) - mImporter.push_back( new ObjFileImporter()); + pimpl->mImporter.push_back( new ObjFileImporter()); #endif #if (!defined AI_BUILD_NO_3DS_IMPORTER) - mImporter.push_back( new Discreet3DSImporter()); + pimpl->mImporter.push_back( new Discreet3DSImporter()); #endif #if (!defined AI_BUILD_NO_MD3_IMPORTER) - mImporter.push_back( new MD3Importer()); + pimpl->mImporter.push_back( new MD3Importer()); #endif #if (!defined AI_BUILD_NO_MD2_IMPORTER) - mImporter.push_back( new MD2Importer()); + pimpl->mImporter.push_back( new MD2Importer()); #endif #if (!defined AI_BUILD_NO_PLY_IMPORTER) - mImporter.push_back( new PLYImporter()); + pimpl->mImporter.push_back( new PLYImporter()); #endif #if (!defined AI_BUILD_NO_MDL_IMPORTER) - mImporter.push_back( new MDLImporter()); + pimpl->mImporter.push_back( new MDLImporter()); #endif #if (!defined AI_BUILD_NO_ASE_IMPORTER) - mImporter.push_back( new ASEImporter()); + pimpl->mImporter.push_back( new ASEImporter()); #endif #if (!defined AI_BUILD_NO_HMP_IMPORTER) - mImporter.push_back( new HMPImporter()); + pimpl->mImporter.push_back( new HMPImporter()); #endif #if (!defined AI_BUILD_NO_SMD_IMPORTER) - mImporter.push_back( new SMDImporter()); + pimpl->mImporter.push_back( new SMDImporter()); #endif #if (!defined AI_BUILD_NO_MDC_IMPORTER) - mImporter.push_back( new MDCImporter()); + pimpl->mImporter.push_back( new MDCImporter()); #endif #if (!defined AI_BUILD_NO_MD5_IMPORTER) - mImporter.push_back( new MD5Importer()); + pimpl->mImporter.push_back( new MD5Importer()); #endif #if (!defined AI_BUILD_NO_STL_IMPORTER) - mImporter.push_back( new STLImporter()); + pimpl->mImporter.push_back( new STLImporter()); #endif #if (!defined AI_BUILD_NO_LWO_IMPORTER) - mImporter.push_back( new LWOImporter()); + pimpl->mImporter.push_back( new LWOImporter()); #endif #if (!defined AI_BUILD_NO_DXF_IMPORTER) - mImporter.push_back( new DXFImporter()); + pimpl->mImporter.push_back( new DXFImporter()); #endif #if (!defined AI_BUILD_NO_NFF_IMPORTER) - mImporter.push_back( new NFFImporter()); + pimpl->mImporter.push_back( new NFFImporter()); #endif #if (!defined AI_BUILD_NO_RAW_IMPORTER) - mImporter.push_back( new RAWImporter()); + pimpl->mImporter.push_back( new RAWImporter()); #endif #if (!defined AI_BUILD_NO_OFF_IMPORTER) - mImporter.push_back( new OFFImporter()); + pimpl->mImporter.push_back( new OFFImporter()); #endif #if (!defined AI_BUILD_NO_AC_IMPORTER) - mImporter.push_back( new AC3DImporter()); + pimpl->mImporter.push_back( new AC3DImporter()); #endif #if (!defined AI_BUILD_NO_BVH_IMPORTER) - mImporter.push_back( new BVHLoader()); + pimpl->mImporter.push_back( new BVHLoader()); #endif #if (!defined AI_BUILD_NO_IRRMESH_IMPORTER) - mImporter.push_back( new IRRMeshImporter()); + pimpl->mImporter.push_back( new IRRMeshImporter()); #endif #if (!defined AI_BUILD_NO_IRR_IMPORTER) - mImporter.push_back( new IRRImporter()); + pimpl->mImporter.push_back( new IRRImporter()); #endif #if (!defined AI_BUILD_NO_Q3D_IMPORTER) - mImporter.push_back( new Q3DImporter()); + pimpl->mImporter.push_back( new Q3DImporter()); #endif #if (!defined AI_BUILD_NO_B3D_IMPORTER) - mImporter.push_back( new B3DImporter()); + pimpl->mImporter.push_back( new B3DImporter()); #endif #if (!defined AI_BUILD_NO_COLLADA_IMPORTER) - mImporter.push_back( new ColladaLoader()); + pimpl->mImporter.push_back( new ColladaLoader()); #endif #if (!defined AI_BUILD_NO_TERRAGEN_IMPORTER) - mImporter.push_back( new TerragenImporter()); + pimpl->mImporter.push_back( new TerragenImporter()); #endif //#if (!defined AI_BUILD_NO_CSM_IMPORTER) // mImporter.push_back( new CSMImporter()); //#endif #if (!defined AI_BUILD_NO_3D_IMPORTER) - mImporter.push_back( new UnrealImporter()); + pimpl->mImporter.push_back( new UnrealImporter()); #endif - - - #if (!defined AI_BUILD_NO_LWS_IMPORTER) - mImporter.push_back( new LWSImporter()); + pimpl->mImporter.push_back( new LWSImporter()); #endif - // ====================================================================== + // ---------------------------------------------------------------------------- // Add an instance of each post processing step here in the order // 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) - mPostProcessingSteps.push_back( new RemoveVCProcess()); + pimpl->mPostProcessingSteps.push_back( new RemoveVCProcess()); #endif - #if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS) - mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess()); + pimpl->mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess()); #endif - #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 - #if (!defined AI_BUILD_NO_FINDDEGENERATES_PROCESS) - mPostProcessingSteps.push_back( new FindDegeneratesProcess()); + pimpl->mPostProcessingSteps.push_back( new FindDegeneratesProcess()); #endif - - - #ifndef AI_BUILD_NO_GENUVCOORDS_PROCESS - mPostProcessingSteps.push_back( new ComputeUVMappingProcess()); + pimpl->mPostProcessingSteps.push_back( new ComputeUVMappingProcess()); #endif #ifndef AI_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS - mPostProcessingSteps.push_back( new TextureTransformStep()); + pimpl->mPostProcessingSteps.push_back( new TextureTransformStep()); #endif - #if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS) - mPostProcessingSteps.push_back( new PretransformVertices()); + pimpl->mPostProcessingSteps.push_back( new PretransformVertices()); #endif #if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS) - mPostProcessingSteps.push_back( new TriangulateProcess()); + pimpl->mPostProcessingSteps.push_back( new TriangulateProcess()); #endif - #if (!defined AI_BUILD_NO_SORTBYPTYPE_PROCESS) - mPostProcessingSteps.push_back( new SortByPTypeProcess()); + pimpl->mPostProcessingSteps.push_back( new SortByPTypeProcess()); #endif - #if (!defined AI_BUILD_NO_FINDINVALIDDATA_PROCESS) - mPostProcessingSteps.push_back( new FindInvalidDataProcess()); + pimpl->mPostProcessingSteps.push_back( new FindInvalidDataProcess()); #endif - #if (!defined AI_BUILD_NO_FIXINFACINGNORMALS_PROCESS) - mPostProcessingSteps.push_back( new FixInfacingNormalsProcess()); + pimpl->mPostProcessingSteps.push_back( new FixInfacingNormalsProcess()); #endif #if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS) - mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Triangle()); + pimpl->mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Triangle()); #endif #if (!defined AI_BUILD_NO_GENFACENORMALS_PROCESS) - mPostProcessingSteps.push_back( new GenFaceNormalsProcess()); + pimpl->mPostProcessingSteps.push_back( new GenFaceNormalsProcess()); #endif - // 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) - mPostProcessingSteps.push_back( new GenVertexNormalsProcess()); + pimpl->mPostProcessingSteps.push_back( new GenVertexNormalsProcess()); #endif #if (!defined AI_BUILD_NO_CALCTANGENTS_PROCESS) - mPostProcessingSteps.push_back( new CalcTangentsProcess()); + pimpl->mPostProcessingSteps.push_back( new CalcTangentsProcess()); #endif #if (!defined AI_BUILD_NO_JOINVERTICES_PROCESS) - mPostProcessingSteps.push_back( new JoinVerticesProcess()); + pimpl->mPostProcessingSteps.push_back( new JoinVerticesProcess()); #endif - mPostProcessingSteps.push_back( new DestroySpatialSortProcess()); - + pimpl->mPostProcessingSteps.push_back( new DestroySpatialSortProcess()); #if (!defined AI_BUILD_NO_SPLITLARGEMESHES_PROCESS) - mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Vertex()); + pimpl->mPostProcessingSteps.push_back( new SplitLargeMeshesProcess_Vertex()); #endif #if (!defined AI_BUILD_NO_MAKELEFTHANDED_PROCESS) - mPostProcessingSteps.push_back( new MakeLeftHandedProcess()); + pimpl->mPostProcessingSteps.push_back( new MakeLeftHandedProcess()); #endif #if (!defined AI_BUILD_NO_FLIPUVS_PROCESS) - mPostProcessingSteps.push_back( new FlipUVsProcess()); + pimpl->mPostProcessingSteps.push_back( new FlipUVsProcess()); #endif #if (!defined AI_BUILD_NO_FLIPWINDINGORDER_PROCESS) - mPostProcessingSteps.push_back( new FlipWindingOrderProcess()); + pimpl->mPostProcessingSteps.push_back( new FlipWindingOrderProcess()); #endif #if (!defined AI_BUILD_NO_LIMITBONEWEIGHTS_PROCESS) - mPostProcessingSteps.push_back( new LimitBoneWeightsProcess()); + pimpl->mPostProcessingSteps.push_back( new LimitBoneWeightsProcess()); #endif #if (!defined AI_BUILD_NO_IMPROVECACHELOCALITY_PROCESS) - mPostProcessingSteps.push_back( new ImproveCacheLocalityProcess()); + pimpl->mPostProcessingSteps.push_back( new ImproveCacheLocalityProcess()); #endif - // Allocate a SharedPostProcessInfo object and store pointers to it // in all post-process steps in the list. - mPPShared = new SharedPostProcessInfo(); - for (std::vector::iterator it = mPostProcessingSteps.begin(), - end = mPostProcessingSteps.end(); it != end; ++it) + pimpl->mPPShared = new SharedPostProcessInfo(); + for (std::vector::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() { // 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 - 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 mIOHandler; + delete pimpl->mIOHandler; // Kill imported scene. Destructors should do that recursivly - delete mScene; + delete pimpl->mScene; // 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) { - // Call the default constructor 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) { ai_assert(NULL != pImp); - // ====================================================================== + + // -------------------------------------------------------------------- // 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; pImp->GetExtensionList(st); @@ -524,31 +521,26 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp) #endif // add the loader - mImporter.push_back(pImp); + pimpl->mImporter.push_back(pImp); DefaultLogger::get()->info("Registering custom importer: " + st); return AI_SUCCESS; } // ------------------------------------------------------------------------------------------------ -// Unregister a custom loader +// Unregister a custom loader plugin aiReturn Importer::UnregisterLoader(BaseImporter* pImp) { ai_assert(NULL != pImp); - for (std::vector::iterator - it = mImporter.begin(),end = mImporter.end(); - it != end;++it) - { - if (pImp == (*it)) - { - mImporter.erase(it); + std::vector::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; - } + 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; } @@ -560,30 +552,30 @@ void Importer::SetIOHandler( IOSystem* pIOHandler) if (!pIOHandler) { // 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 - 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() { - return mIOHandler; + return pimpl->mIOHandler; } // ------------------------------------------------------------------------------------------------ +// Check whether a custom IO handler is currently set bool Importer::IsDefaultIOHandler() { - return mIsDefaultHandler; + return pimpl->mIsDefaultHandler; } // ------------------------------------------------------------------------------------------------ @@ -604,37 +596,42 @@ bool _ValidateFlags(unsigned int pFlags) // Free the current scene void Importer::FreeScene( ) { - delete mScene; - mScene = NULL; + delete pimpl->mScene; + pimpl->mScene = NULL; + + pimpl->mErrorString = ""; } // ------------------------------------------------------------------------------------------------ // 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 void Importer::SetExtraVerbose(bool bDo) { - bExtraVerbose = bDo; + pimpl->bExtraVerbose = bDo; } // ------------------------------------------------------------------------------------------------ // Get the current scene 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* s = mScene; - mScene = NULL; + aiScene* s = pimpl->mScene; + pimpl->mScene = NULL; + + pimpl->mErrorString = ""; /* reset error string */ return s; } @@ -646,24 +643,22 @@ bool Importer::ValidateFlags(unsigned int pFlags) if(!_ValidateFlags(pFlags)) 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 if (pFlags & aiProcess_ValidateDataStructure) return false; #endif 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. for (unsigned int mask = 1; mask < (1 << (sizeof(unsigned int)*8-1));mask <<= 1) { if (pFlags & mask) { 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; break; @@ -680,42 +675,41 @@ bool Importer::ValidateFlags(unsigned int pFlags) // Reads the given file and returns its contents if successful. 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)); - const std::string pFile(_pFile); - // ====================================================================== + // ---------------------------------------------------------------------- // Put a large try block around everything to catch all std::exception's // that might be thrown by STL containers or by new(). // ImportErrorException's are throw by ourselves and caught elsewhere. - // ====================================================================== + //----------------------------------------------------------------------- #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS try #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS { // Check whether this Importer instance has already loaded // a scene. In this case we need to delete the old one - if (mScene) + if (pimpl->mScene) { DefaultLogger::get()->debug("Deleting previous scene"); FreeScene(); } // 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; } // Find an worker class which can handle the file 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; } } @@ -726,10 +720,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) std::string::size_type s = pFile.find_last_of('.'); if (s != std::string::npos) { 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; } } @@ -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 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; } } @@ -746,10 +740,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // Dispatch the reading to the worker class for this format DefaultLogger::get()->info("Found a matching importer for this file format"); 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( mScene) + if( pimpl->mScene) { #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS // 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; ds.ExecuteOnScene (this); - if (!mScene) + if (!pimpl->mScene) return NULL; } #endif // no validation // Preprocess the scene - ScenePreprocessor pre(mScene); + ScenePreprocessor pre(pimpl->mScene); pre.ProcessScene(); DefaultLogger::get()->info("Import successful, entering postprocessing-steps"); #ifdef _DEBUG - if (bExtraVerbose) + if (pimpl->bExtraVerbose) { #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS @@ -781,17 +775,19 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) pFlags |= aiProcess_ValidateDataStructure; } #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 - 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)) { process->SetupProperties( this ); process->ExecuteOnScene ( this ); } - if( !mScene)break; + if( !pimpl->mScene) + break; #ifdef _DEBUG #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 // VaidateDataStructureStep again after each step - if (bExtraVerbose) + if (pimpl->bExtraVerbose) { DefaultLogger::get()->debug("Extra verbose: revalidating data structures"); ValidateDSProcess ds; ds.ExecuteOnScene (this); - if( !mScene) + if( !pimpl->mScene) { DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures"); break; @@ -816,29 +812,29 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } } // 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 - mPPShared->Clean(); + pimpl->mPPShared->Clean(); } #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS catch (std::exception &e) { #if (defined _MSC_VER) && (defined _CPPRTTI) // 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 - mErrorString = std::string("std::exception: ") + e.what(); + pimpl->mErrorString = std::string("std::exception: ") + e.what(); #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 // 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) { const std::string szExtension(_szExtension); - for (std::vector::const_iterator - i = mImporter.begin(); - i != mImporter.end();++i) + for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { // 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; } @@ -867,10 +862,8 @@ BaseImporter* Importer::FindLoader (const char* _szExtension) void Importer::GetExtensionList(aiString& szOut) { unsigned int iNum = 0; - std::string tmp; // todo: Rewrite baseImporter::GetExtensionList to use aiString, too - for (std::vector::const_iterator - i = mImporter.begin(); - i != mImporter.end();++i,++iNum) + std::string tmp; + for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i,++iNum) { // Insert a comma as delimiter character // 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, bool* bWasExisting /*= NULL*/) { - SetGenericProperty(mIntProperties, szName,iValue,bWasExisting); + SetGenericProperty(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, bool* bWasExisting /*= NULL*/) { - SetGenericProperty(mFloatProperties, szName,iValue,bWasExisting); + SetGenericProperty(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, bool* bWasExisting /*= NULL*/) { - SetGenericProperty(mStringProperties, szName,value,bWasExisting); + SetGenericProperty(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 iErrorReturn /*= 0xffffffff*/) const { - return GetGenericProperty(mIntProperties,szName,iErrorReturn); + return GetGenericProperty(pimpl->mIntProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ @@ -921,7 +914,7 @@ int Importer::GetPropertyInteger(const char* szName, float Importer::GetPropertyFloat(const char* szName, float iErrorReturn /*= 10e10*/) const { - return GetGenericProperty(mFloatProperties,szName,iErrorReturn); + return GetGenericProperty(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& iErrorReturn /*= ""*/) const { - return GetGenericProperty(mStringProperties,szName,iErrorReturn); + return GetGenericProperty(pimpl->mStringProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ @@ -948,9 +941,13 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) void Importer::GetMemoryRequirements(aiMemoryInfo& in) const { in = aiMemoryInfo(); + aiScene* mScene = pimpl->mScene; // return if we have no scene loaded - if (!this->mScene)return; + if (!pimpl->mScene) + return; + + in.total = sizeof(aiScene); // add all meshes diff --git a/code/JoinVerticesProcess.cpp b/code/JoinVerticesProcess.cpp index aaee1aaf6..2814fa071 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/JoinVerticesProcess.cpp @@ -44,8 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "AssimpPCH.h" +#ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS -// internal headers #include "JoinVerticesProcess.h" #include "ProcessHelper.h" @@ -412,3 +412,5 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) } return pMesh->mNumVertices; } + +#endif // !! ASSIMP_BUILD_NO_JOINVERTICES_PROCESS \ No newline at end of file diff --git a/code/OptimizeGraph.cpp b/code/OptimizeGraph.cpp new file mode 100644 index 000000000..63ad651bf --- /dev/null +++ b/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& nodes) +{ + nodes_in += nd->mNumChildren; + + // Process children + std::list 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::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 join; + for (std::list::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::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::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::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::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 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 \ No newline at end of file diff --git a/code/OptimizeGraph.h b/code/OptimizeGraph.h new file mode 100644 index 000000000..5d28ad609 --- /dev/null +++ b/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& nodes); + void FindInstancedMeshes (aiNode* pNode); + +private: + +#ifdef AI_OG_USE_HASHING + typedef std::set LockedSetType; +#else + typedef std::set 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 locked_nodes; + + //! Node counters for logging purposes + unsigned int nodes_in,nodes_out, count_merged; + + //! Reference counters for meshes + std::vector meshes; +}; + +} // end of namespace Assimp + +#endif // AI_OPTIMIZEGRAPHPROCESS_H_INC diff --git a/code/OptimizeMeshes.cpp b/code/OptimizeMeshes.cpp new file mode 100644 index 000000000..fd6b31afd --- /dev/null +++ b/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 \ No newline at end of file diff --git a/code/OptimizeMeshes.h b/code/OptimizeMeshes.h new file mode 100644 index 000000000..37b37672c --- /dev/null +++ b/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 meshes; + + //! Next output mesh + aiMesh* mesh; + + //! Output meshes + std::vector output; + + //! @see EnablePrimitiveTypeSorting + mutable bool pts; + + //! @see SetPreferredMeshSizeLimit + mutable unsigned int max_verts,max_faces; + + //! Temporary storage + std::vector merge_list; +}; + +} // end of namespace Assimp + +#endif // AI_CALCTANGENTSPROCESS_H_INC diff --git a/code/ProcessHelper.h b/code/ProcessHelper.h index c1fe8818d..f15ffff84 100644 --- a/code/ProcessHelper.h +++ b/code/ProcessHelper.h @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SpatialSort.h" #include "BaseProcess.h" +#include "ParsingUtils.h" // ------------------------------------------------------------------------------- // 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& 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 * diff --git a/code/RemoveRedundantMaterials.cpp b/code/RemoveRedundantMaterials.cpp index 9132f8552..6139c4708 100644 --- a/code/RemoveRedundantMaterials.cpp +++ b/code/RemoveRedundantMaterials.cpp @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssimpPCH.h" #include "RemoveRedundantMaterials.h" #include "ParsingUtils.h" +#include "ProcessHelper.h" using namespace Assimp; @@ -78,31 +79,6 @@ void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) 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& 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. void RemoveRedundantMatsProcess::Execute( aiScene* pScene) diff --git a/code/SceneCombiner.cpp b/code/SceneCombiner.cpp index 2864a1f46..24120c803 100644 --- a/code/SceneCombiner.cpp +++ b/code/SceneCombiner.cpp @@ -675,10 +675,8 @@ void SceneCombiner::BuildUniqueBoneList(std::list& asBones, std::vector::const_iterator end) { 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]; uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length); @@ -691,8 +689,7 @@ void SceneCombiner::BuildUniqueBoneList(std::list& asBones, break; } } - if (end2 == it2) - { + if (end2 == it2) { // need to begin a new bone entry asBones.push_back(BoneWithHash()); BoneWithHash& btz = asBones.back(); @@ -721,29 +718,23 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector::const_iterator BuildUniqueBoneList(asBones, it,end); // now create the output bones + out->mNumBones = 0; out->mBones = new aiBone*[asBones.size()]; - for (std::list::const_iterator it = asBones.begin(),end = asBones.end(); - it != end;++it) - { + for (std::list::const_iterator it = asBones.begin(),end = asBones.end(); it != end;++it) { // Allocate a bone and setup it's name aiBone* pc = out->mBones[out->mNumBones++] = new aiBone(); pc->mName = aiString( *((*it).second )); - // Get an itrator to the end of the list std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end(); // 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; // NOTE: different offset matrices for bones with equal names // 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"); continue; } @@ -755,12 +746,9 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector::const_iterator // And copy the final weights - adjust the vertex IDs by the // 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; - 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]; avw->mWeight = vfi.mWeight; avw->mVertexId = vfi.mVertexId + (*wmit).second; @@ -777,8 +765,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int flags, { ai_assert(NULL != _out); - if (begin == end) - { + if (begin == end) { *_out = NULL; // no meshes ... return; } @@ -788,8 +775,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int flags, out->mMaterialIndex = (*begin)->mMaterialIndex; // Find out how much output storage we'll need - for (std::vector::const_iterator it = begin; it != end;++it) - { + for (std::vector::const_iterator it = begin; it != end;++it) { out->mNumVertices += (*it)->mNumVertices; out->mNumFaces += (*it)->mNumFaces; out->mNumBones += (*it)->mNumBones; @@ -798,86 +784,75 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int flags, out->mPrimitiveTypes |= (*it)->mPrimitiveTypes; } - if (out->mNumVertices) // just for safety - { + if (out->mNumVertices) { aiVector3D* pv2; // copy vertex positions - if ((**begin).HasPositions()) - { + if ((**begin).HasPositions()) { + pv2 = out->mVertices = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) - { - if ((*it)->mNormals) - { + for (std::vector::const_iterator it = begin; it != end;++it) { + if ((*it)->mVertices) { ::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; } } // copy normals - if ((**begin).HasNormals()) - { + if ((**begin).HasNormals()) { + pv2 = out->mNormals = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) - { - if ((*it)->mNormals) - { + for (std::vector::const_iterator it = begin; it != end;++it) { + if ((*it)->mNormals) { ::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; } } // copy tangents and bitangents - if ((**begin).HasTangentsAndBitangents()) - { + if ((**begin).HasTangentsAndBitangents()) { + pv2 = out->mTangents = new aiVector3D[out->mNumVertices]; aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) - { - if ((*it)->mTangents) - { + for (std::vector::const_iterator it = begin; it != end;++it) { + if ((*it)->mTangents) { ::memcpy(pv2, (*it)->mTangents, (*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; pv2b += (*it)->mNumVertices; } } // copy texture coordinates unsigned int n = 0; - while ((**begin).HasTextureCoords(n)) - { + while ((**begin).HasTextureCoords(n)) { out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n]; pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) - { - if ((*it)->mTextureCoords[n]) - { + for (std::vector::const_iterator it = begin; it != end;++it) { + + if ((*it)->mTextureCoords[n]) { ::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; } ++n; } // copy vertex colors n = 0; - while ((**begin).HasVertexColors(n)) - { + while ((**begin).HasVertexColors(n)) { aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) - { - if ((*it)->mColors[n]) - { + for (std::vector::const_iterator it = begin; it != end;++it) { + + if ((*it)->mColors[n]) { ::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; } ++n; @@ -891,23 +866,20 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int flags, aiFace* pf2 = out->mFaces; unsigned int ofs = 0; - for (std::vector::const_iterator it = begin; it != end;++it) - { - for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2) - { + for (std::vector::const_iterator it = begin; it != end;++it) { + for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2) { aiFace& face = (*it)->mFaces[m]; pf2->mNumIndices = face.mNumIndices; pf2->mIndices = face.mIndices; - if (ofs) - { + if (ofs) { // add the offset to the vertex for (unsigned int q = 0; q < face.mNumIndices; ++q) face.mIndices[q] += ofs; } - ofs += (*it)->mNumVertices; face.mIndices = NULL; } + ofs += (*it)->mNumVertices; } } diff --git a/doc/AssimpCmdDoc_Html/AssimpCmdDoc.chm b/doc/AssimpCmdDoc_Html/AssimpCmdDoc.chm index e45d7e7b1..f16532006 100644 Binary files a/doc/AssimpCmdDoc_Html/AssimpCmdDoc.chm and b/doc/AssimpCmdDoc_Html/AssimpCmdDoc.chm differ diff --git a/doc/AssimpDoc_Html/AssimpDoc.chm b/doc/AssimpDoc_Html/AssimpDoc.chm index 9fe3d427e..612645c45 100644 Binary files a/doc/AssimpDoc_Html/AssimpDoc.chm and b/doc/AssimpDoc_Html/AssimpDoc.chm differ diff --git a/doc/Doxyfile b/doc/Doxyfile index 25c691e12..9f312d78d 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -31,7 +31,7 @@ PROJECT_NAME = assimp # This could be handy for archiving the generated documentation or # 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) # base path where the generated documentation will be put. diff --git a/doc/Doxyfile_Cmd b/doc/Doxyfile_Cmd index 71956901e..850015109 100644 --- a/doc/Doxyfile_Cmd +++ b/doc/Doxyfile_Cmd @@ -31,7 +31,7 @@ PROJECT_NAME = AssimpCMD # This could be handy for archiving the generated documentation or # 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) # base path where the generated documentation will be put. diff --git a/doc/Preamble.txt b/doc/Preamble.txt index 2293293a6..f7ce7b948 100644 --- a/doc/Preamble.txt +++ b/doc/Preamble.txt @@ -3,7 +3,7 @@ Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- -Copyright (c) 2006-2008, ASSIMP Development Team +Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. diff --git a/doc/dox_cmd.h b/doc/dox_cmd.h index af0cbce9e..85c874a0e 100644 --- a/doc/dox_cmd.h +++ b/doc/dox_cmd.h @@ -305,7 +305,7 @@ more information can be found in the aiPostProcess.h header. Find and process degenerates primitives. - -slm + -slm --split-large-meshes Split large meshes over a specific treshold in smaller sub meshes. The default vertex & face limit is 1000000 @@ -373,6 +373,19 @@ more information can be found in the aiPostProcess.h header. 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. + + + -og + --optimize-graph + Simplify and optimize the scenegraph. Use it with care, all hierarchy information could be lost. + Animations remain untouched. + + + + -om + --optimize-mesh + Optimize mesh usage. Meshes are merged, if possible. Very effective in combination with --optimize-graph + For convenience some default postprocessing configurations are provided. @@ -392,17 +405,19 @@ The corresponding command line parameter is -c (or --config=< default - Balanced post processing config, performs most optimizations + Balanced post processing config; performs most optimizations -cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv full - Full post processing. May take a while, but results in best output quality for most purposes - -cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv, -fi, -vds + Full post processing. May take a while but results in best output quality for most purposes + -cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv, -fi, -vds -om -There are also some common flags to specify Assimp's logging behaviour: + The -tuv, -ptv, -og flags always need to be enabled manually. + +There are also some common flags to customize Assimp's logging behaviour: @@ -420,8 +435,8 @@ There are also some common flags to specify Assimp's logging behaviour: - +
-v or --verboseEnables verbose logging. Debug messages will be produced, too. This will - decrease loading performance and might result in *very* long logs ...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.
*/ diff --git a/include/aiConfig.h b/include/aiConfig.h index 0182cbf99..660c5596b 100644 --- a/include/aiConfig.h +++ b/include/aiConfig.h @@ -58,6 +58,123 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef 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: + * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'". + * 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.
+ * 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: + * "keep-me and_me_to anotherNodeToBeKept \'name with whitespace\'". + * If a node matches on of these names, it will not be modified or + * removed by the postprocessing step.
+ * 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. * @@ -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" +// --------------------------------------------------------------------------- +/** @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 @@ -244,6 +506,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY \ "IMPORT_LWO_ONE_LAYER_ONLY" +// --------------------------------------------------------------------------- +/** @brief Configures the MD5 loader to not load the MD5ANIM file for + * a MD5MESH file automatically. + * + * The default strategy is to look for a file with the same name but the + * MD5ANIM extension in the same directory. If it is found, it is loaded + * and combined with the MD5MESH file. This configuration option can be + * used to disable this behaviour. + * + * Property type: integer (0: false; !0: true). Default value: false. + */ +#define AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD \ + "IMPORT_MD5_NO_ANIM_AUTOLOAD" + +#if 0 +// --------------------------------------------------------------------------- +/** @brief Specifies the shape of the scene returned by the CSM format loader. + * + * If this property is set to 1, the loader tries to build a hierarchy from + * the capture points laoded from the file. A dummy mesh representing the + * recorded human is build. Otherwise, no meshes are returned, there's just + * a single root node with several children. These children represent the + * capture points, their translation channel is absolute. + * Property type: integer. Default value: 1 + */ +#define AI_CONFIG_IMPORT_CSM_BUILD_HIERARCHY "imp.csm.mkhier" +#endif // --------------------------------------------------------------------------- /** @brief Defines the begin of the time range for which the LWS loader @@ -277,252 +566,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #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: - * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'". - * 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.
- * 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 - * a MD5MESH file automatically. - * - * The default strategy is to look for a file with the same name but the - * MD5ANIM extension in the same directory. If it is found, it is loaded - * and combined with the MD5MESH file. This configuration option can be - * used to disable this behaviour. - * - * Property type: integer (0: false; !0: true). Default value: false. - */ -#define AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD \ - "IMPORT_MD5_NO_ANIM_AUTOLOAD" - -#if 0 -// --------------------------------------------------------------------------- -/** @brief Specifies the shape of the scene returned by the CSM format loader. - * - * If this property is set to 1, the loader tries to build a hierarchy from - * the capture points laoded from the file. A dummy mesh representing the - * recorded human is build. Otherwise, no meshes are returned, there's just - * a single root node with several children. These children represent the - * capture points, their translation channel is absolute. - * Property type: integer. Default value: 1 - */ -#define AI_CONFIG_IMPORT_CSM_BUILD_HIERARCHY "imp.csm.mkhier" -#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. - * - * 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" #endif // !! AI_CONFIG_H_INC diff --git a/include/aiPostProcess.h b/include/aiPostProcess.h index 9b6e226c6..0ce283da5 100644 --- a/include/aiPostProcess.h +++ b/include/aiPostProcess.h @@ -416,6 +416,46 @@ enum aiPostProcessSteps */ aiProcess_FindInstances = 0x100000, + // ------------------------------------------------------------------------- + /**
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, + + + // ------------------------------------------------------------------------- + /**
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 + * #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, + // ------------------------------------------------------------------------- /**
This step flips all UV coordinates along the y-axis and adjusts * material settings and bitangents accordingly. @@ -433,7 +473,7 @@ enum aiPostProcessSteps * setting and boundles all conversions typically required for D3D-based * applications. */ - aiProcess_FlipUVs = 0x80000000, /* don't change */ + aiProcess_FlipUVs = 0x800000, // ------------------------------------------------------------------------- /**
This step adjusts the output face winding order to be cw. @@ -447,13 +487,11 @@ enum aiPostProcessSteps * x1 * @endcode */ - aiProcess_FlipWindingOrder = 0x40000000 /* don't change */ - - + aiProcess_FlipWindingOrder = 0x1000000 // aiProcess_GenEntityMeshes = 0x100000, // aiProcess_OptimizeAnimations = 0x200000 - // aiProcess_OptimizeNodes = 0x400000 + // aiProcess_FixTexturePaths = 0x200000 }; @@ -547,6 +585,7 @@ enum aiPostProcessSteps aiProcessPreset_TargetRealtime_Quality | \ aiProcess_FindInstances | \ aiProcess_ValidateDataStructure | \ + aiProcess_OptimizeMeshes | \ 0 ) diff --git a/include/assimp.hpp b/include/assimp.hpp index 0bc803fc9..d494acccf 100644 --- a/include/assimp.hpp +++ b/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. */ #ifndef INCLUDED_AI_ASSIMP_HPP #define INCLUDED_AI_ASSIMP_HPP #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 -#include -#include - -// Public ASSIMP data structure headers +// Public ASSIMP data structures #include "aiTypes.h" #include "aiConfig.h" #include "aiAssert.h" namespace Assimp { - // ======================================================================= // Public interface to Assimp - // ======================================================================= class Importer; class IOStream; class IOSystem; // ======================================================================= // Plugin development - // Include the following headers for the definitions: - // ======================================================================= + // + // Include the following headers for the declarations: // BaseImporter.h // BaseProcess.h class BaseImporter; class BaseProcess; class SharedPostProcessInfo; class BatchLoader; + + // ======================================================================= + // Holy stuff, only for members of the high council of the Jedi. + class ImporterPimpl; } //! namespace Assimp #define AI_PROPERTY_WAS_NOT_EXISTING 0xffffffff @@ -109,7 +107,7 @@ namespace Assimp { * standard C++ IO logic will be used. * * @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 { @@ -118,23 +116,16 @@ class ASSIMP_API Importer friend class BatchLoader; friend const aiScene* ::aiImportFileEx( const char*, unsigned int, aiFileIO*); -public: - - typedef unsigned int KeyType; - typedef std::map IntPropertyMap; - typedef std::map FloatPropertyMap; - typedef std::map StringPropertyMap; - public: // ------------------------------------------------------------------- /** 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(); - // ------------------------------------------------------------------- /** Copy constructor. * @@ -144,7 +135,6 @@ public: */ Importer(const Importer& other); - // ------------------------------------------------------------------- /** Destructor. The object kept ownership of the imported data, * which now will be destroyed along with the object. @@ -163,7 +153,6 @@ public: */ aiReturn RegisterLoader(BaseImporter* pImp); - // ------------------------------------------------------------------- /** Unregisters a loader. * @@ -230,7 +219,6 @@ public: void SetPropertyString(const char* szName, const std::string& sValue, bool* bWasExisting = NULL); - // ------------------------------------------------------------------- /** Get a configuration property. * @param szName Name of the property. All supported properties @@ -263,7 +251,6 @@ public: const std::string& GetPropertyString(const char* szName, const std::string& sErrorReturn = "") const; - // ------------------------------------------------------------------- /** 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 @@ -281,7 +268,6 @@ public: */ void SetIOHandler( IOSystem* pIOHandler); - // ------------------------------------------------------------------- /** Retrieves the IO handler that is currently set. * You can use IsDefaultIOHandler() to check whether the returned @@ -292,7 +278,6 @@ public: */ IOSystem* GetIOHandler(); - // ------------------------------------------------------------------- /** Checks whether a default IO handler is active * A default handler is active as long the application doesn't @@ -301,7 +286,6 @@ public: */ bool IsDefaultIOHandler(); - // ------------------------------------------------------------------- /** @brief Check whether a given set of postprocessing flags * is supported. @@ -348,7 +332,6 @@ public: */ const aiScene* ReadFile( const std::string& pFile, unsigned int pFlags); - // ------------------------------------------------------------------- /** Frees the current scene. * @@ -358,25 +341,26 @@ public: */ void FreeScene( ); - // ------------------------------------------------------------------- /** 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. - * - * @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); // ------------------------------------------------------------------- @@ -386,18 +370,17 @@ public: * See the const char* version for detailled docs. * @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. - * - * 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); // ------------------------------------------------------------------- @@ -409,7 +392,6 @@ public: */ inline void GetExtensionList(std::string& szOut); - // ------------------------------------------------------------------- /** Find the loader corresponding to a specific file extension. * @@ -421,7 +403,6 @@ public: */ BaseImporter* FindLoader (const char* szExtension); - // ------------------------------------------------------------------- /** Returns the scene loaded by the last successful call to ReadFile() * @@ -429,7 +410,6 @@ public: */ const aiScene* GetScene() const; - // ------------------------------------------------------------------- /** Returns the scene loaded by the last successful call to ReadFile() * 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(). * * @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(); - // ------------------------------------------------------------------- - /** Returns the storage allocated by ASSIMP to hold the asset data + /** Returns the storage allocated by ASSIMP to hold the scene data * 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; - // ------------------------------------------------------------------- - /** 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); 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 mImporter; - - /** Post processing steps we can apply at the imported data. */ - std::vector 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 diff --git a/mkutil/revision.h b/mkutil/revision.h index c019ccfc1..922e9a3d5 100644 --- a/mkutil/revision.h +++ b/mkutil/revision.h @@ -1 +1 @@ -#define SVNRevision 394 +#define SVNRevision 402 diff --git a/tools/assimp_cmd/Main.cpp b/tools/assimp_cmd/Main.cpp index ede8945dd..e9442de27 100644 --- a/tools/assimp_cmd/Main.cpp +++ b/tools/assimp_cmd/Main.cpp @@ -190,12 +190,15 @@ int ProcessStandardArguments(ImportData& fill, const char** params, // -lh --convert-to-lh // -fuv --flip-uv // -fwo --flip-winding-order - // -ett --evaluate-texture-transform + // -tuv --transform-uv-coords // -guv --gen-uvcoords // -fid --find-invalid-data // -fixn --fix normals // -tri --triangulate // -fi --find-instances + // -fi --find-instances + // -og --optimize-graph + // -om --optimize-meshes // // -c --config-file= @@ -248,7 +251,7 @@ int ProcessStandardArguments(ImportData& fill, const char** params, else if (! ::strcmp(params[i], "-fwo") || ! ::strcmp(params[i], "--flip-winding-order")) { 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; } 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")) { 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)) { const unsigned int ofs = (params[i][1] == '-' ? 9 : 2); diff --git a/tools/assimp_view/SceneAnimator.h b/tools/assimp_view/SceneAnimator.h index 2907f2471..12483f140 100644 --- a/tools/assimp_view/SceneAnimator.h +++ b/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 #define AV_SCENEANIMATOR_H_INCLUDED +#include + namespace AssimpView { // --------------------------------------------------------------------------------- diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index 9b62ae0db..edb551096 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -151,6 +151,8 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter) aiProcess_TransformUVCoords | // preprocess UV transformations (scaling, translation ...) aiProcess_FindInstances | // search for instanced meshes and remove them by references to one master aiProcess_LimitBoneWeights | // limit bone weights to 4 per vertex + aiProcess_OptimizeMeshes | // join small meshes, if possible +// aiProcess_OptimizeGraph | // optimize unneeded nodes away // aiProcess_PreTransformVertices | 0); diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index 8a18b6fd6..1e1aeb8a2 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -1328,148 +1328,148 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2261,7 +2277,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +