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
pull/1/head
aramis_acg 2009-04-24 20:53:24 +00:00
parent 760bcbbf69
commit 9abcba4bc2
29 changed files with 2630 additions and 1421 deletions

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

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

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

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

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

View File

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

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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