Integrating aiProcess_OptimizeGraph and aiProcess_OptimizeMeshes back into the Assimp core. They're stable enough now.

Moving private members of Assimp::Importer to a pimpl, hopefully solving strange crashes with vc9 debug builds.
Updating assimp_cmd to reflect these changes.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@403 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
This commit is contained in:
aramis_acg
2009-04-24 20:53:24 +00:00
parent 760bcbbf69
commit 9abcba4bc2
29 changed files with 2630 additions and 1421 deletions
+6 -6
View File
@@ -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)
+3 -3
View File
@@ -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())
{
+60 -3
View File
@@ -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<KeyType, int> IntPropertyMap;
typedef std::map<KeyType, float> FloatPropertyMap;
typedef std::map<KeyType, std::string> StringPropertyMap;
public:
/** IO handler to use for all file accesses. */
IOSystem* mIOHandler;
bool mIsDefaultHandler;
/** Format-specific importer worker objects - one for each format we can read.*/
std::vector<BaseImporter*> mImporter;
/** Post processing steps we can apply at the imported data. */
std::vector<BaseProcess*> mPostProcessingSteps;
/** The imported data, if ReadFile() was successful, NULL otherwise. */
aiScene* mScene;
/** The error description, if there was one. */
std::string mErrorString;
/** List of integer properties */
IntPropertyMap mIntProperties;
/** List of floating-point properties */
FloatPropertyMap mFloatProperties;
/** List of string properties */
StringPropertyMap mStringProperties;
/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
* to be executed before and after every single postprocess step */
bool bExtraVerbose;
/** Used by post-process steps to share data */
SharedPostProcessInfo* mPPShared;
};
// ---------------------------------------------------------------------------
/** The BaseImporter defines a common interface for all importer worker
* 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;
}
+6 -6
View File
@@ -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;
}
}
+572 -564
View File
File diff suppressed because it is too large Load Diff
+202 -205
View File
@@ -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<BaseProcess*>::iterator it = mPostProcessingSteps.begin(),
end = mPostProcessingSteps.end(); it != end; ++it)
pimpl->mPPShared = new SharedPostProcessInfo();
for (std::vector<BaseProcess*>::iterator it = pimpl->mPostProcessingSteps.begin(),
end = pimpl->mPostProcessingSteps.end(); it != end; ++it)
{
(*it)->SetSharedData(mPPShared);
(*it)->SetSharedData(pimpl->mPPShared);
}
}
// ------------------------------------------------------------------------------------------------
// Destructor.
// Destructor of Importer
Importer::~Importer()
{
// 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<BaseImporter*>::iterator
it = mImporter.begin(),end = mImporter.end();
it != end;++it)
{
if (pImp == (*it))
{
mImporter.erase(it);
std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),pimpl->mImporter.end(),pImp);
if (it != pimpl->mImporter.end()) {
pimpl->mImporter.erase(it);
std::string st;
pImp->GetExtensionList(st);
DefaultLogger::get()->info("Unregistering custom importer: " + st);
return AI_SUCCESS;
}
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<BaseImporter*>::const_iterator
i = mImporter.begin();
i != mImporter.end();++i)
for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)
{
// pass the file extension to the CanRead(..,NULL)-method
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<BaseImporter*>::const_iterator
i = mImporter.begin();
i != mImporter.end();++i,++iNum)
std::string tmp;
for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i,++iNum)
{
// Insert a comma as delimiter character
// 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<int>(mIntProperties, szName,iValue,bWasExisting);
SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue,bWasExisting);
}
// ------------------------------------------------------------------------------------------------
@@ -897,7 +890,7 @@ void Importer::SetPropertyInteger(const char* szName, int iValue,
void Importer::SetPropertyFloat(const char* szName, float iValue,
bool* bWasExisting /*= NULL*/)
{
SetGenericProperty<float>(mFloatProperties, szName,iValue,bWasExisting);
SetGenericProperty<float>(pimpl->mFloatProperties, szName,iValue,bWasExisting);
}
// ------------------------------------------------------------------------------------------------
@@ -905,7 +898,7 @@ void Importer::SetPropertyFloat(const char* szName, float iValue,
void Importer::SetPropertyString(const char* szName, const std::string& value,
bool* bWasExisting /*= NULL*/)
{
SetGenericProperty<std::string>(mStringProperties, szName,value,bWasExisting);
SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value,bWasExisting);
}
// ------------------------------------------------------------------------------------------------
@@ -913,7 +906,7 @@ void Importer::SetPropertyString(const char* szName, const std::string& value,
int Importer::GetPropertyInteger(const char* szName,
int iErrorReturn /*= 0xffffffff*/) const
{
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
@@ -921,7 +914,7 @@ int Importer::GetPropertyInteger(const char* szName,
float Importer::GetPropertyFloat(const char* szName,
float iErrorReturn /*= 10e10*/) const
{
return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
return GetGenericProperty<float>(pimpl->mFloatProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
@@ -929,7 +922,7 @@ float Importer::GetPropertyFloat(const char* szName,
const std::string& Importer::GetPropertyString(const char* szName,
const std::string& iErrorReturn /*= ""*/) const
{
return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
@@ -948,9 +941,13 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
{
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
+3 -1
View File
@@ -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
+347
View File
@@ -0,0 +1,347 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (ASSIMP)
---------------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file OptimizeGraph.cpp
* @brief Implementation of the aiProcess_OptimizGraph step
*/
#include "AssimpPCH.h"
#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
using namespace Assimp;
#include "OptimizeGraph.h"
#include "ProcessHelper.h"
#include "SceneCombiner.h"
#define AI_RESERVED_NODE_NAME "$Reserved_And_Evil"
/* AI_OG_USE_HASHING enables the use of hashing to speed-up std::set lookups.
* The unhashed variant should be faster, except for *very* large data sets
*/
#ifdef AI_OG_USE_HASHING
// Use our standard hashing function to compute the hash
# define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length)
#else
// Otherwise hope that std::string will utilize a static buffer
// for shorter node names. This would avoid endless heap copying.
# define AI_OG_GETKEY(str) std::string(str.data)
#endif
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
OptimizeGraphProcess::OptimizeGraphProcess()
{}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
OptimizeGraphProcess::~OptimizeGraphProcess()
{}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const
{
return (0 != (pFlags & aiProcess_OptimizeGraph));
}
// ------------------------------------------------------------------------------------------------
// Setup properties for the postprocessing step
void OptimizeGraphProcess::SetupProperties(const Importer* pImp)
{
// Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST
std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,"");
AddLockedNodeList(tmp);
}
// ------------------------------------------------------------------------------------------------
// Collect new children
void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes)
{
nodes_in += nd->mNumChildren;
// Process children
std::list<aiNode*> child_nodes;
for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
CollectNewChildren(nd->mChildren[i],child_nodes);
nd->mChildren[i] = NULL;
}
// Check whether we need this node; if not we can replace it by our own children (warn, danger of incest).
if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end() ) {
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) {
(*it)->mTransformation = nd->mTransformation * (*it)->mTransformation;
nodes.push_back(*it);
it = child_nodes.erase(it);
continue;
}
++it;
}
if (nd->mNumMeshes || child_nodes.size()) {
nodes.push_back(nd);
}
else {
delete nd; /* bye, node */
return;
}
}
else {
// Retain our current position in the hierarchy
nodes.push_back(nd);
// Now check for possible optimizations in our list of child nodes. join as many as possible
aiNode* join_master = NULL;
aiMatrix4x4 inv;
const LockedSetType::const_iterator end = locked.end();
std::list<aiNode*> join;
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
aiNode* child = *it;
if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) {
// There may be no instanced meshes
unsigned int n = 0;
for (; n < child->mNumMeshes;++n) {
if (meshes[child->mMeshes[n]] > 1) {
break;
}
}
if (n == child->mNumMeshes) {
if (!join_master) {
join_master = child;
inv = join_master->mTransformation;
inv.Inverse();
}
else {
child->mTransformation = inv * child->mTransformation ;
join.push_back(child);
it = child_nodes.erase(it);
continue;
}
}
}
++it;
}
if (join_master && join.size()) {
join_master->mName.length = sprintf(join_master->mName.data,"$MergedNode_%i",count_merged++);
unsigned int out_meshes = 0;
for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
out_meshes += (*it)->mNumMeshes;
}
// copy all mesh references in one array
if (out_meshes) {
unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes;
for (unsigned int n = 0; n < join_master->mNumMeshes;++n) {
*tmp++ = join_master->mMeshes[n];
}
for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) {
*tmp = (*it)->mMeshes[n];
aiMesh* mesh = mScene->mMeshes[*tmp++];
// manually move the mesh into the right coordinate system
const aiMatrix3x3 IT = aiMatrix3x3( (*it)->mTransformation ).Inverse().Transpose();
for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
mesh->mVertices[a] *= (*it)->mTransformation;
if (mesh->HasNormals())
mesh->mNormals[a] *= IT;
if (mesh->HasTangentsAndBitangents()) {
mesh->mTangents[a] *= IT;
mesh->mBitangents[a] *= IT;
}
}
}
delete *it; // bye, node
}
delete[] join_master->mMeshes;
join_master->mMeshes = meshes;
join_master->mNumMeshes += out_meshes;
}
}
}
// reassign children if something changed
if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) {
delete[] nd->mChildren;
if (child_nodes.size())
nd->mChildren = new aiNode*[child_nodes.size()];
else nd->mChildren = NULL;
}
nd->mNumChildren = child_nodes.size();
aiNode** tmp = nd->mChildren;
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
aiNode* node = *tmp++ = *it;
node->mParent = nd;
}
nodes_out += child_nodes.size();
}
// ------------------------------------------------------------------------------------------------
// Execute the postprocessing step on the given scene
void OptimizeGraphProcess::Execute( aiScene* pScene)
{
DefaultLogger::get()->debug("OptimizeGraphProcess begin");
nodes_in = nodes_out = count_merged = 0;
mScene = pScene;
meshes.resize(pScene->mNumMeshes,0);
FindInstancedMeshes(pScene->mRootNode);
// build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it
locked.clear();
for (std::list<std::string>::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) {
#ifdef AI_OG_USE_HASHING
locked.insert(SuperFastHash((*it).c_str()));
#else
locked.insert(*it);
#endif
}
for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {
for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) {
aiNodeAnim* anim = pScene->mAnimations[i]->mChannels[a];
locked.insert(AI_OG_GETKEY(anim->mNodeName));
}
}
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) {
aiBone* bone = pScene->mMeshes[i]->mBones[a];
locked.insert(AI_OG_GETKEY(bone->mName));
// HACK: Meshes referencing bones may not be transformed; we need to look them.
// The easiest way to do this is to increase their reference counters ...
meshes[i] += 2;
}
}
for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {
aiCamera* cam = pScene->mCameras[i];
locked.insert(AI_OG_GETKEY(cam->mName));
}
for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
aiLight* lgh = pScene->mLights[i];
locked.insert(AI_OG_GETKEY(lgh->mName));
}
// Insert a dummy master node and make it read-only
aiNode* dummy_root = new aiNode(AI_RESERVED_NODE_NAME);
locked.insert(AI_OG_GETKEY(dummy_root->mName));
const aiString prev = pScene->mRootNode->mName;
pScene->mRootNode->mParent = dummy_root;
dummy_root->mChildren = new aiNode*[dummy_root->mNumChildren = 1];
dummy_root->mChildren[0] = pScene->mRootNode;
// Do our recursive processing of scenegraph nodes. For each node collect
// a fully new list of children and allow their children to place themselves
// on the same hierarchy layer as their parents.
std::list<aiNode*> nodes;
CollectNewChildren (dummy_root,nodes);
ai_assert(nodes.size() == 1);
if (dummy_root->mNumChildren > 1) {
pScene->mRootNode = dummy_root;
// Keep the dummy node but assign the name of the old root node to it
pScene->mRootNode->mName = prev;
}
else {
// Remove the dummy root node again.
pScene->mRootNode = dummy_root->mChildren[0];
dummy_root->mChildren[0] = NULL;
delete dummy_root;
}
pScene->mRootNode->mParent = NULL;
if (!DefaultLogger::isNullLogger()) {
if ( nodes_in != nodes_out) {
char buf[512];
sprintf(buf,"OptimizeGraphProcess finished; Input nodes: %i, Output nodes: %i",nodes_in,nodes_out);
DefaultLogger::get()->info(buf);
}
else DefaultLogger::get()->debug("OptimizeGraphProcess finished");
}
meshes.clear();
locked.clear();
}
// ------------------------------------------------------------------------------------------------
// Buidl a LUT of all instanced meshes
void OptimizeGraphProcess::FindInstancedMeshes (aiNode* pNode)
{
for (unsigned int i = 0; i < pNode->mNumMeshes;++i) {
++meshes[pNode->mMeshes[i]];
}
for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
FindInstancedMeshes(pNode->mChildren[i]);
}
#endif // !! ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
+147
View File
@@ -0,0 +1,147 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file OptimizeGraph.h
* @brief Declares a post processing step to optimize the scenegraph
*/
#ifndef AI_OPTIMIZEGRAPHPROCESS_H_INC
#define AI_OPTIMIZEGRAPHPROCESS_H_INC
#include "BaseProcess.h"
#include "ProcessHelper.h"
#include "../include/aiTypes.h"
struct aiMesh;
class OptimizeGraphProcessTest;
namespace Assimp {
// -----------------------------------------------------------------------------
/** @brief Postprocessing step to optimize the scenegraph
*
* The implementation tries to merge nodes, even if they use different
* transformations. Animations are preserved.
*
* @see aiProcess_OptimizeGraph for a detailed description of the
* algorithm being applied.
*/
class ASSIMP_API OptimizeGraphProcess : public BaseProcess
{
friend class Importer;
friend class ::OptimizeGraphProcessTest;
protected:
/** Constructor to be privately used by Importer */
OptimizeGraphProcess();
/** Destructor, private as well */
~OptimizeGraphProcess();
public:
// -------------------------------------------------------------------
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
void Execute( aiScene* pScene);
// -------------------------------------------------------------------
void SetupProperties(const Importer* pImp);
// -------------------------------------------------------------------
/** @brief Add a list of node names to be locked and not modified.
* @param in List of nodes. See #AI_CONFIG_PP_OG_EXCLUDE_LIST for
* format explanations.
*/
inline void AddLockedNodeList(std::string& in)
{
ConvertListToStrings (in,locked_nodes);
}
// -------------------------------------------------------------------
/** @brief Add another node to be locked and not modified.
* @param name Name to be locked
*/
inline void AddLockedNode(std::string& name)
{
locked_nodes.push_back(name);
}
// -------------------------------------------------------------------
/** @brief Rmeove a node from the list of locked nodes.
* @param name Name to be unlocked
*/
inline void RemoveLockedNode(std::string& name)
{
locked_nodes.remove(name);
}
protected:
void CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes);
void FindInstancedMeshes (aiNode* pNode);
private:
#ifdef AI_OG_USE_HASHING
typedef std::set<unsigned int> LockedSetType;
#else
typedef std::set<std::string> LockedSetType;
#endif
//! Scene we're working with
aiScene* mScene;
//! List of locked names. Stored is the hash of the name
LockedSetType locked;
//! List of nodes to be locked in addition to those with animations, lights or cameras assigned.
std::list<std::string> locked_nodes;
//! Node counters for logging purposes
unsigned int nodes_in,nodes_out, count_merged;
//! Reference counters for meshes
std::vector<unsigned int> meshes;
};
} // end of namespace Assimp
#endif // AI_OPTIMIZEGRAPHPROCESS_H_INC
+239
View File
@@ -0,0 +1,239 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (ASSIMP)
---------------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file OptimizeMeshes.cpp
* @brief Implementation of the aiProcess_OptimizeMeshes step
*/
#include "AssimpPCH.h"
#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
using namespace Assimp;
#include "OptimizeMeshes.h"
#include "ProcessHelper.h"
#include "SceneCombiner.h"
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
OptimizeMeshesProcess::OptimizeMeshesProcess()
: pts (false)
, max_verts (0xffffffff)
, max_faces (0xffffffff)
{}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
OptimizeMeshesProcess::~OptimizeMeshesProcess()
{}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const
{
// Our behaviour needs to be different if the SortByPType or SplitLargeMeshes
// steps are active. Thus we need to query their flags here and store the
// information, although we're breaking const-correctness.
// That's a serious design flaw, consider redesign.
if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
pts = (0 != (pFlags & aiProcess_SortByPType));
max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : 0;
return true;
}
return false;
}
// ------------------------------------------------------------------------------------------------
// Setup properties for the postprocessing step
void OptimizeMeshesProcess::SetupProperties(const Importer* pImp)
{
if (max_verts == 0xdeadbeef /* magic hack */) {
max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
}
}
// ------------------------------------------------------------------------------------------------
// Execute step
void OptimizeMeshesProcess::Execute( aiScene* pScene)
{
const unsigned int num_old = pScene->mNumMeshes;
if (num_old <= 1) {
DefaultLogger::get()->debug("Skipping OptimizeMeshesProcess");
return;
}
DefaultLogger::get()->debug("OptimizeMeshesProcess begin");
mScene = pScene;
merge_list.reserve(pScene->mNumMeshes);
output.reserve(pScene->mNumMeshes);
// Prepare lookup tables
meshes.resize(pScene->mNumMeshes);
FindInstancedMeshes(pScene->mRootNode);
if (max_verts == 0xdeadbeef) /* undo the magic hack */
max_verts = 0xffffffff;
// ... instanced meshes are immediately processed and added to the output list
for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) {
meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]);
if (meshes[i].instance_cnt > 1 && meshes[i].output_id == 0xffffffff) {
meshes[i].output_id = n++;
output.push_back(mScene->mMeshes[i]);
}
}
// and process all nodes in the scenegraoh recursively
ProcessNode(pScene->mRootNode);
if (!output.size()) {
throw new ImportErrorException("OptimizeMeshes: No meshes remaining; there's definitely something wrong");
}
meshes.clear();
ai_assert(output.size() <= num_old);
mScene->mNumMeshes = output.size();
std::copy(output.begin(),output.end(),mScene->mMeshes);
if (output.size() != num_old) {
char tmp[512];
::sprintf(tmp,"OptimizeMeshesProcess finished. Input meshes: %i, Output meshes: %i",num_old,pScene->mNumMeshes);
DefaultLogger::get()->info(tmp);
}
else DefaultLogger::get()->debug("OptimizeMeshesProcess finished");
}
// ------------------------------------------------------------------------------------------------
// Process meshes for a single node
void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
{
for (unsigned int i = 0; i < pNode->mNumMeshes;++i) {
unsigned int& im = pNode->mMeshes[i];
if (meshes[im].instance_cnt > 1) {
im = meshes[im].output_id;
}
else {
merge_list.clear();
unsigned int verts = 0, faces = 0;
// Find meshes to merge with us
for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) {
register unsigned int am = pNode->mMeshes[a];
if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) {
merge_list.push_back(mScene->mMeshes[am]);
verts += mScene->mMeshes[am]->mNumVertices;
faces += mScene->mMeshes[am]->mNumFaces;
--pNode->mNumMeshes;
for (unsigned int n = a; n < pNode->mNumMeshes; ++n)
pNode->mMeshes[n] = pNode->mMeshes[n+1];
--a;
}
}
// and merge all meshes which we found, replace the old ones
if (!merge_list.empty()) {
merge_list.push_back(mScene->mMeshes[im]);
aiMesh* out;
SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end());
output.push_back(out);
}
else {
output.push_back(mScene->mMeshes[im]);
}
im = output.size()-1;
}
}
for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
ProcessNode(pNode->mChildren[i]);
}
// ------------------------------------------------------------------------------------------------
// Check whether two meshes can be joined
bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned int verts, unsigned int faces )
{
if (meshes[a].vertex_format != meshes[b].vertex_format)
return false;
aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b];
if (0xffffffff != max_verts && verts+mb->mNumVertices > max_verts ||
0xffffffff != max_faces && faces+mb->mNumFaces > max_faces) {
return false;
}
// Never merge unskinned meshes with skinned meshes
if (ma->mMaterialIndex != mb->mMaterialIndex || ma->HasBones() != mb->HasBones())
return false;
// Never merge meshes with different kinds of primitives if SortByPType did already
// do its work. We would destroy everything again ...
if (pts && ma->mPrimitiveTypes != mb->mPrimitiveTypes)
return false;
// If both meshes are skinned, check whether we have many bones defined in both meshes.
// If yes, we can savely join them.
if (ma->HasBones()) {
// TODO
return false;
}
return true;
}
// ------------------------------------------------------------------------------------------------
// Buidl a LUT of all instanced meshes
void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode)
{
for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
++meshes[pNode->mMeshes[i]].instance_cnt;
for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
FindInstancedMeshes(pNode->mChildren[i]);
}
#endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
+187
View File
@@ -0,0 +1,187 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file OptimizeMeshes.h
* @brief Declares a post processing step to join meshes, if possible
*/
#ifndef AI_OPTIMIZEMESHESPROCESS_H_INC
#define AI_OPTIMIZEMESHESPROCESS_H_INC
#include "BaseProcess.h"
#include "../include/aiTypes.h"
struct aiMesh;
class OptimizeMeshesProcessTest;
namespace Assimp {
// ---------------------------------------------------------------------------
/** @brief Postprocessing step to optimize mesh usage
*
* The implementation looks for meshes that could be joined and joins them.
* Usually this will reduce the number of drawcalls.
*
* @note Instanced meshes are currently not processed.
*/
class ASSIMP_API OptimizeMeshesProcess : public BaseProcess
{
friend class Importer;
friend class ::OptimizeMeshesProcessTest;
protected:
/** Constructor to be privately used by Importer */
OptimizeMeshesProcess();
/** Destructor, private as well */
~OptimizeMeshesProcess();
/** @brief Internal utility to store additional mesh info
*/
struct MeshInfo
{
MeshInfo()
: instance_cnt (0)
, vertex_format (0)
, output_id (0xffffffff)
{}
//! Number of times this mesh is referenced
unsigned int instance_cnt;
//! Vertex format id
unsigned int vertex_format;
//! Output ID
unsigned int output_id;
};
public:
// -------------------------------------------------------------------
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
void Execute( aiScene* pScene);
// -------------------------------------------------------------------
void SetupProperties(const Importer* pImp);
// -------------------------------------------------------------------
/** @brief Specify whether you want meshes with different
* primitive types to be merged as well.
*
* IsActive() sets this property automatically to true if the
* aiProcess_SortByPType flag is found.
*/
void EnablePrimitiveTypeSorting(bool enable) {
pts = enable;
}
// Getter
bool IsPrimitiveTypeSortingEnabled () const {
return pts;
}
// -------------------------------------------------------------------
/** @brief Specify a maximum size of a single output mesh.
*
* If a single input mesh already exceeds this limit, it won't
* be splitted.
* @param verts Maximum number of vertices per mesh
* @param faces Maximum number of faces per mesh
*/
void SetPreferredMeshSizeLimit (unsigned int verts, unsigned int faces)
{
max_verts = verts;
max_faces = faces;
}
protected:
// -------------------------------------------------------------------
/** @brief Do the actual optimization on all meshes of this node
* @param pNode Node we're working with
*/
void ProcessNode( aiNode* pNode);
// -------------------------------------------------------------------
/** @brief Returns true if b can be joined with a
*
* @param verts Number of output verts up to now
* @param faces Number of output faces up to now
*/
bool CanJoin ( unsigned int a, unsigned int b,
unsigned int verts, unsigned int faces );
// -------------------------------------------------------------------
/** @brief Find instanced meshes, for the moment we're excluding
* them from all optimizations
*/
void FindInstancedMeshes (aiNode* pNode);
private:
//! Scene we're working with
aiScene* mScene;
//! Per mesh info
std::vector<MeshInfo> meshes;
//! Next output mesh
aiMesh* mesh;
//! Output meshes
std::vector<aiMesh*> output;
//! @see EnablePrimitiveTypeSorting
mutable bool pts;
//! @see SetPreferredMeshSizeLimit
mutable unsigned int max_verts,max_faces;
//! Temporary storage
std::vector<aiMesh*> merge_list;
};
} // end of namespace Assimp
#endif // AI_CALCTANGENTSPROCESS_H_INC
+30
View File
@@ -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<std::string>& out)
{
const char* s = in.c_str();
while (*s) {
SkipSpacesAndLineEnd(&s);
if (*s == '\'') {
const char* base = ++s;
while (*s != '\'') {
++s;
if (*s == '\0') {
DefaultLogger::get()->error("ConvertListToString: String list is ill-formatted");
return;
}
}
out.push_back(std::string(base,(size_t)(s-base)));
++s;
}
else {
out.push_back(GetNextToken(s));
}
}
}
// -------------------------------------------------------------------------------
/** @brief Compute the newell normal of a polygon regardless of its shape
*
+1 -25
View File
@@ -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<std::string>& out)
{
const char* s = in.c_str();
while (*s) {
SkipSpacesAndLineEnd(&s);
if (*s == '\'') {
const char* base = ++s;
while (*s != '\'') {
++s;
if (*s == '\0') {
DefaultLogger::get()->error("RemoveRedundantMaterials: String list is ill-formatted");
return;
}
}
out.push_back(std::string(base,(size_t)(s-base)));
++s;
}
else {
out.push_back(GetNextToken(s));
}
}
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
+41 -69
View File
@@ -675,10 +675,8 @@ void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash>& asBones,
std::vector<aiMesh*>::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<BoneWithHash>& 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<aiMesh*>::const_iterator
BuildUniqueBoneList(asBones, it,end);
// now create the output bones
out->mNumBones = 0;
out->mBones = new aiBone*[asBones.size()];
for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),end = asBones.end();
it != end;++it)
{
for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),end = asBones.end(); it != end;++it) {
// Allocate a bone and setup it's name
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<aiMesh*>::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<aiMesh*>::const_iterator it = begin; it != end;++it)
{
for (std::vector<aiMesh*>::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<aiMesh*>::const_iterator it = begin; it != end;++it)
{
if ((*it)->mNormals)
{
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
if ((*it)->mVertices) {
::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D));
}
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<aiMesh*>::const_iterator it = begin; it != end;++it)
{
if ((*it)->mNormals)
{
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
if ((*it)->mNormals) {
::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
}
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<aiMesh*>::const_iterator it = begin; it != end;++it)
{
if ((*it)->mTangents)
{
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
if ((*it)->mTangents) {
::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D));
::memcpy(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<aiMesh*>::const_iterator it = begin; it != end;++it)
{
if ((*it)->mTextureCoords[n])
{
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
if ((*it)->mTextureCoords[n]) {
::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
}
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<aiMesh*>::const_iterator it = begin; it != end;++it)
{
if ((*it)->mColors[n])
{
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
if ((*it)->mColors[n]) {
::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
}
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<aiMesh*>::const_iterator it = begin; it != end;++it)
{
for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2)
{
for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2) {
aiFace& face = (*it)->mFaces[m];
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;
}
}