diff --git a/code/Exporter.cpp b/code/Exporter.cpp index 7fa01f706..97dbbd064 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -75,47 +75,20 @@ void ExportSceneObj(const char*,IOSystem*, const aiScene*); void ExportSceneSTL(const char*,IOSystem*, const aiScene*); void ExportScene3DS(const char*, IOSystem*, const aiScene*) {} -/// Function pointer type of a Export worker function -typedef void (*fpExportFunc)(const char*,IOSystem*,const aiScene*); - -// ------------------------------------------------------------------------------------------------ -/// Internal description of an Assimp export format option -struct ExportFormatEntry -{ - /// Public description structure to be returned by aiGetExportFormatDescription() - aiExportFormatDesc mDescription; - - // Worker function to do the actual exporting - fpExportFunc mExportFunction; - - // Postprocessing steps to be executed PRIOR to calling mExportFunction - unsigned int mEnforcePP; - - // Constructor to fill all entries - ExportFormatEntry( const char* pId, const char* pDesc, const char* pExtension, fpExportFunc pFunction, unsigned int pEnforcePP = 0u) - { - mDescription.id = pId; - mDescription.description = pDesc; - mDescription.fileExtension = pExtension; - mExportFunction = pFunction; - mEnforcePP = pEnforcePP; - } -}; - // ------------------------------------------------------------------------------------------------ // global array of all export formats which Assimp supports in its current build -ExportFormatEntry gExporters[] = +Exporter::ExportFormatEntry gExporters[] = { #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER - ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada), + Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada), #endif #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER - ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj), + Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj), #endif #ifndef ASSIMP_BUILD_NO_STL_EXPORTER - ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL, + Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL, aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices ), #endif @@ -125,6 +98,8 @@ ExportFormatEntry gExporters[] = //#endif }; +#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0])) + class ExporterPimpl { public: @@ -135,6 +110,10 @@ public: , mIsDefaultIOHandler(true) { GetPostProcessingStepInstanceList(mPostProcessingSteps); + + // grab all builtin exporters + mExporters.resize(ASSIMP_NUM_EXPORTERS); + std::copy(gExporters,gExporters+ASSIMP_NUM_EXPORTERS,mExporters.begin()); } ~ExporterPimpl() @@ -158,9 +137,11 @@ public: /** Last fatal export error */ std::string mError; + + /** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */ + std::vector mExporters; }; -#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0])) } // end of namespace Assimp @@ -239,8 +220,9 @@ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const ASSIMP_BEGIN_EXCEPTION_REGION(); pimpl->mError = ""; - for (size_t i = 0; i < ASSIMP_NUM_EXPORTERS; ++i) { - if (!strcmp(gExporters[i].mDescription.id,pFormatId)) { + for (size_t i = 0; i < pimpl->mExporters.size(); ++i) { + const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i]; + if (!strcmp(exp.mDescription.id,pFormatId)) { try { @@ -258,7 +240,7 @@ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded; // Erase all pp steps that were already applied to this scene - unsigned int pp = (gExporters[i].mEnforcePP | pPreprocessing) & ~(priv + unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv ? (priv->mPPStepsApplied & ~nonIdempotentSteps) : 0u); @@ -282,7 +264,7 @@ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const } } - if (verbosify || (gExporters[i].mEnforcePP & aiProcess_JoinIdenticalVertices)) { + if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { DefaultLogger::get()->debug("export: Scene data not in verbose format, applying MakeVerboseFormat step first"); MakeVerboseFormatProcess proc; @@ -331,7 +313,7 @@ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const privOut->mPPStepsApplied |= pp; } - gExporters[i].mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get()); + exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get()); } catch (DeadlyExportError& err) { pimpl->mError = err.what(); @@ -383,18 +365,42 @@ const aiExportDataBlob* Exporter :: GetOrphanedBlob() const // ------------------------------------------------------------------------------------------------ size_t Exporter :: GetExportFormatCount() const { - return ASSIMP_NUM_EXPORTERS; + return pimpl->mExporters.size(); } // ------------------------------------------------------------------------------------------------ const aiExportFormatDesc* Exporter :: GetExportFormatDescription( size_t pIndex ) const { - if (pIndex >= ASSIMP_NUM_EXPORTERS) { + if (pIndex >= GetExportFormatCount()) { return NULL; } - return &gExporters[pIndex].mDescription; + return &pimpl->mExporters[pIndex].mDescription; +} + +// ------------------------------------------------------------------------------------------------ +aiReturn Exporter :: RegisterExporter(const ExportFormatEntry& desc) +{ + BOOST_FOREACH(const ExportFormatEntry& e, pimpl->mExporters) { + if (!strcmp(e.mDescription.id,desc.mDescription.id)) { + return aiReturn_FAILURE; + } + } + + pimpl->mExporters.push_back(desc); + return aiReturn_SUCCESS; } +// ------------------------------------------------------------------------------------------------ +void Exporter :: UnregisterExporter(const char* id) +{ + for(std::vector::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) { + if (!strcmp((*it).mDescription.id,id)) { + pimpl->mExporters.erase(it); + break; + } + } +} + #endif // !ASSIMP_BUILD_NO_EXPORT diff --git a/include/export.hpp b/include/export.hpp index 43013e589..1dab7bf8a 100644 --- a/include/export.hpp +++ b/include/export.hpp @@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { class ExporterPimpl; + // ---------------------------------------------------------------------------------- /** CPP-API: The Exporter class forms an C++ interface to the export functionality * of the Open Asset Import Library. Note that the export interface is available @@ -76,6 +77,37 @@ class ASSIMP_API Exporter // : public boost::noncopyable //#endif // __cplusplus { +public: + + /** Function pointer type of a Export worker function */ + typedef void (*fpExportFunc)(const char*,IOSystem*,const aiScene*); + + /** Internal description of an Assimp export format option */ + struct ExportFormatEntry + { + /// Public description structure to be returned by aiGetExportFormatDescription() + aiExportFormatDesc mDescription; + + // Worker function to do the actual exporting + fpExportFunc mExportFunction; + + // Postprocessing steps to be executed PRIOR to invoking mExportFunction + unsigned int mEnforcePP; + + // Constructor to fill all entries + ExportFormatEntry( const char* pId, const char* pDesc, const char* pExtension, fpExportFunc pFunction, unsigned int pEnforcePP = 0u) + { + mDescription.id = pId; + mDescription.description = pDesc; + mDescription.fileExtension = pExtension; + mExportFunction = pFunction; + mEnforcePP = pEnforcePP; + } + + ExportFormatEntry() : mExportFunction(), mEnforcePP() {} + }; + + public: @@ -223,6 +255,30 @@ public: const aiExportFormatDesc* GetExportFormatDescription( size_t pIndex ) const; + // ------------------------------------------------------------------- + /** Register a custom exporter. Custom export formats are limited to + * to the current #Exporter instance and do not affect the + * library globally. + * @param desc Exporter description. + * @return aiReturn_SUCCESS if the export format was successfully + * registered. A common cause that would prevent an exporter + * from being registered is that its format id is already + * occupied by another format. */ + aiReturn RegisterExporter(const ExportFormatEntry& desc); + + + // ------------------------------------------------------------------- + /** Remove an export format previously registered with #RegisterExporter + * from the #Exporter instance (this can also be used to drop + * builtin exporters because those are implicitly registered + * using #RegisterExporter). + * @param id Format id to be unregistered, this refers to the + * 'id' field of #aiExportFormatDesc. + * @note Calling this method on a format description not yet registered + * has no effect.*/ + void UnregisterExporter(const char* id); + + protected: // Just because we don't want you to know how we're hacking around.