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:
+6
-6
@@ -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)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+202
-205
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user