- improve symmetry between Assimp::Importer and Assimp::Exporter.

+ aiCopyScene -- a bit dysfunctional because we will also need getters and setters for all other scene components to avoid running into ownership & heap issues when users modify scenes.
# fix handling of postprocessing during exporting

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1061 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/2/head
aramis_acg 2011-08-04 08:53:59 +00:00
parent 665f73861e
commit 36b3695a31
8 changed files with 185 additions and 85 deletions

View File

@ -47,6 +47,7 @@ Assimp C export interface. See Exporter.cpp for some notes.
#ifndef ASSIMP_BUILD_NO_EXPORT
#include "CInterfaceIOWrapper.h"
#include "SceneCombiner.h"
using namespace Assimp;
@ -63,6 +64,15 @@ ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex
return Exporter().GetExportFormatDescription(pIndex);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut)
{
if (!pOut || !pIn) {
return;
}
SceneCombiner::CopyScene(pOut,pIn,false);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing )
@ -97,7 +107,7 @@ ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene*
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API C_STRUCT void aiReleaseExportData( const aiExportDataBlob* pData )
ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData )
{
delete pData;
}

View File

@ -185,6 +185,8 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
// XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
// take all input meshes and clone them

View File

@ -145,6 +145,9 @@ public:
/** Post processing steps we can apply at the imported data. */
std::vector< BaseProcess* > mPostProcessingSteps;
/** Last fatal export error */
std::string mError;
};
#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0]))
@ -168,7 +171,7 @@ Exporter :: Exporter()
// ------------------------------------------------------------------------------------------------
Exporter :: ~Exporter()
{
delete pimpl;
FreeBlob();
}
@ -224,6 +227,8 @@ const aiExportDataBlob* Exporter :: ExportToBlob( const aiScene* pScene, const
aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing )
{
ASSIMP_BEGIN_EXCEPTION_REGION();
pimpl->mError = "";
for (size_t i = 0; i < ASSIMP_NUM_EXPORTERS; ++i) {
if (!strcmp(gExporters[i].mDescription.id,pFormatId)) {
@ -235,8 +240,24 @@ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
const ScenePrivateData* const priv = ScenePriv(pScene);
// steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
// original state before the step was applied first. When checking which steps we don't need
// to run, those are excluded.
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
? (priv->mPPStepsApplied & ~nonIdempotentSteps)
: 0u);
// If no extra postprocessing was specified, and we obtained this scene from an
// Assimp importer, apply the reverse steps automatically.
if (!pPreprocessing && priv) {
pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
}
const unsigned int pp = (gExporters[i].mEnforcePP | pPreprocessing);
if (pp) {
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
BaseProcess* const p = pimpl->mPostProcessingSteps[a];
@ -245,23 +266,45 @@ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const
p->Execute(scenecopy.get());
}
}
ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
ai_assert(privOut);
privOut->mPPStepsApplied |= pp;
}
gExporters[i].mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get());
}
catch (DeadlyExportError& err) {
// XXX what to do with the error message? Maybe introduce extra member to hold it, similar to Assimp.Importer
DefaultLogger::get()->error(err.what());
pimpl->mError = err.what();
return AI_FAILURE;
}
return AI_SUCCESS;
}
}
pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_FAILURE;
}
// ------------------------------------------------------------------------------------------------
const char* Exporter :: GetErrorString() const
{
return pimpl->mError.c_str();
}
// ------------------------------------------------------------------------------------------------
void Exporter :: FreeBlob( )
{
delete pimpl->blob;
pimpl->blob = NULL;
pimpl->mError = "";
}
// ------------------------------------------------------------------------------------------------
const aiExportDataBlob* Exporter :: GetBlob() const
{

View File

@ -917,11 +917,15 @@ void SceneCombiner::CopySceneFlat(aiScene** _dest,const aiScene* src)
}
// ------------------------------------------------------------------------------------------------
void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src)
void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
{
ai_assert(NULL != _dest && NULL != src);
aiScene* dest = *_dest = new aiScene();
if (allocate) {
*_dest = new aiScene();
}
aiScene* dest = *_dest;
ai_assert(dest);
// copy animations
dest->mNumAnimations = src->mNumAnimations;
@ -958,6 +962,9 @@ void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src)
// and keep the flags ...
dest->mFlags = src->mFlags;
// source private data might be NULL if the scene is user-allocated (i.e. for use with the export API)
ScenePriv(dest)->mPPStepsApplied = ScenePriv(src) ? ScenePriv(src)->mPPStepsApplied : NULL;
}
// ------------------------------------------------------------------------------------------------

View File

@ -303,7 +303,7 @@ public:
* @param dest Receives a pointer to the destination scene
* @param src Source scene - remains unmodified.
*/
static void CopyScene(aiScene** dest,const aiScene* source);
static void CopyScene(aiScene** dest,const aiScene* source,bool allocate = true);
// -------------------------------------------------------------------

View File

@ -362,7 +362,7 @@ struct aiScene
#endif // __cplusplus
// internal scene data, do not touch
/** Internal data, do not touch */
#ifdef __cplusplus
void* mPrivate;
#else

View File

@ -56,14 +56,16 @@ extern "C" {
struct aiScene; // aiScene.h
/** Describes an file format which Assimp can export to. Use aiGetExportFormatCount() to
* learn how many export formats the current Assimp build supports and aiGetExportFormatDescription()
// --------------------------------------------------------------------------------
/** Describes an file format which Assimp can export to. Use #aiGetExportFormatCount() to
* learn how many export formats the current Assimp build supports and #aiGetExportFormatDescription()
* to retrieve a description of an export format option.
*/
struct aiExportFormatDesc
{
/// a short string ID to uniquely identify the export format. Use this ID string to
/// specify which file format you want to export to when calling aiExportScene().
/// specify which file format you want to export to when calling #aiExportScene().
/// Example: "dae" or "obj"
const char* id;
@ -75,20 +77,89 @@ struct aiExportFormatDesc
const char* fileExtension;
};
// --------------------------------------------------------------------------------
/** Returns the number of export file formats available in the current Assimp build.
* Use aiGetExportFormatDescription() to retrieve infos of a specific export format.
*/
* Use aiGetExportFormatDescription() to retrieve infos of a specific export format.
*/
ASSIMP_API size_t aiGetExportFormatCount(void);
/** Returns a description of the nth export file format. Use aiGetExportFormatCount()
* to learn how many export formats are supported.
* @param pIndex Index of the export format to retrieve information for. Valid range is 0 to aiGetExportFormatCount()
* @return A description of that specific export format. NULL if pIndex is out of range.
*/
// --------------------------------------------------------------------------------
/** Returns a description of the nth export file format. Use #aiGetExportFormatCount()
* to learn how many export formats are supported.
* @param pIndex Index of the export format to retrieve information for. Valid range is
* 0 to #aiGetExportFormatCount()
* @return A description of that specific export format. NULL if pIndex is out of range.
*/
ASSIMP_API const C_STRUCT aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex);
/** Describes a blob of exported scene data. Use aiExportScene() to create a blob containing an
* exported scene. The memory referred by this structure is owned by Assimp. Use aiReleaseExportedFile()
// --------------------------------------------------------------------------------
/** Create a modifyable copy of a scene.
* This is useful to import files via Assimp, change their topology and
* export them again. Since the scene returned by the various importer functions
* is const, a modifyable copy is needed.
* @param pIn Valid scene to be copied
* @param pOut User-allocated scene to be filled.
*/
ASSIMP_API void aiCopyScene(const C_STRUCT aiScene* pIn, C_STRUCT aiScene** pOut);
// --------------------------------------------------------------------------------
/** Exports the given scene to a chosen file format and writes the result file(s) to disk.
* @param pScene The scene to export. Stays in possession of the caller, is not changed by the function.
* The scene is expected to conform to Assimp's Importer output format as specified
* in the @link data Data Structures Page @endlink. In short, this means the model data
* should use a right-handed coordinate systems, face winding should be counter-clockwise
* and the UV coordinate origin is assumed to be in the upper left. If your input data
* uses different conventions, have a look at the last parameter.
* @param pFormatId ID string to specify to which format you want to export to. Use
* aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available.
* @param pFileName Output file to write
* @param pIO custom IO implementation to be used. Use this if you use your own storage methods.
* If none is supplied, a default implementation using standard file IO is used. Note that
* #aiExportSceneToBlob is provided as convenience function to export to memory buffers.
* @param pPreprocessing Accepts any choice of the #aiPostProcessing enumerated
* flags, but in reality only a subset of them makes sense here. Specifying
* 'preprocessing' flags is useful if the input scene does not conform to
* Assimp's default conventions as specified in the @link data Data Structures Page @endlink.
* In short, this means the geometry data should use a right-handed coordinate systems, face
* winding should be counter-clockwise and the UV coordinate origin is assumed to be in
* the upper left. The #aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and
* #aiProcess_FlipWindingOrder flags are used in the import side to allow users
* to have those defaults automatically adapted to their conventions. Specifying those flags
* for exporting has the opposite effect, respectively. Some other of the
* #aiPostProcessSteps enumerated values may be useful as well, but you'll need
* to try out what their effect on the exported file is. Many formats impose
* their own restrictions on the structure of the geometry stored therein,
* so some preprocessing may have little or no effect at all, or may be
* redundant as exporters would apply them anyhow. A good example
* is triangulation - whilst you can enforce it by specifying
* the #aiProcess_Triangulate flag, most export formats support only
* triangulate data so they would run the step anyway.
* @return a status code indicating the result of the export
*/
ASSIMP_API aiReturn aiExportScene( const C_STRUCT aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing);
// --------------------------------------------------------------------------------
/** Exports the given scene to a chosen file format using custom IO logic supplied by you.
* @param pScene The scene to export. Stays in possession of the caller, is not changed by the function.
* @param pFormatId ID string to specify to which format you want to export to. Use
* aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available.
* @param pFileName Output file to write
* @param pIO custom IO implementation to be used. Use this if you use your own storage methods.
* If none is supplied, a default implementation using standard file IO is used. Note that
* #aiExportSceneToBlob is provided as convienience function to export to memory buffers.
* @param pPreprocessing Please see the documentation for #aiExportScene
* @return a status code indicating the result of the export
*/
ASSIMP_API aiReturn aiExportSceneEx( const C_STRUCT aiScene* pScene, const char* pFormatId, const char* pFileName, C_STRUCT aiFileIO* pIO, unsigned int pPreprocessing );
// --------------------------------------------------------------------------------
/** Describes a blob of exported scene data. Use #aiExportSceneToBlob() to create a blob containing an
* exported scene. The memory referred by this structure is owned by Assimp. Use #aiReleaseExportedFile()
* to free its resources. Don't try to free the memory on your side - it will crash for most build configurations
* due to conflicting heaps.
*
@ -132,78 +203,25 @@ struct aiExportDataBlob
#endif // __cplusplus
};
// --------------------------------------------------------------------------------
/** Exports the given scene to a chosen file format and writes the result file(s) to disk.
* @param pScene The scene to export. Stays in possession of the caller, is not changed by the function.
* The scene is expected to conform to Assimp's Importer output format as specified
* in the @link data Data Structures Page @endlink. In short, this means the model data
* should use a right-handed coordinate systems, face winding should be counter-clockwise
* and the UV coordinate origin is assumed to be in the upper left. If your input data
* uses different conventions, have a look at the last parameter.
* @param pFormatId ID string to specify to which format you want to export to. Use
* aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available.
* @param pFileName Output file to write
* @param pIO custom IO implementation to be used. Use this if you use your own storage methods.
* If none is supplied, a default implementation using standard file IO is used. Note that
* #aiExportSceneToBlob is provided as convenience function to export to memory buffers.
* @param pPreprocessing Accepts any choice of the #aiPostProcessing enumerated
* flags, but in reality only a subset of them makes sense here. Specifying
* 'preprocessing' flags is useful if the input scene does not conform to
* Assimp's default conventions as specified in the @link data Data Structures Page @endlink.
* In short, this means the geometry data should use a right-handed coordinate systems, face
* winding should be counter-clockwise and the UV coordinate origin is assumed to be in
* the upper left. The #aiProcess_MakeLeftHanded, #aiProcess_FlipUVs and
* #aiProcess_FlipWindingOrder flags are used in the import side to allow users
* to have those defaults automatically adapted to their conventions. Specifying those flags
* for exporting has the opposite effect, respectively. Some other of the
* #aiPostProcessSteps enumerated values may be useful as well, but you'll need
* to try out what their effect on the exported file is. Many formats impose
* their own restrictions on the structure of the geometry stored therein,
* so some preprocessing may have little or no effect at all, or may be
* redundant as exporters would apply them anyhow. A good example
* is triangulation - whilst you can enforce it by specifying
* the #aiProcess_Triangulate flag, most export formats support only
* triangulate data so they would run the step even if it wasn't requested.
* @return a status code indicating the result of the export
*/
ASSIMP_API aiReturn aiExportScene( const C_STRUCT aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing);
// --------------------------------------------------------------------------------
/** Exports the given scene to a chosen file format using custom IO logic supplied by you.
* @param pScene The scene to export. Stays in possession of the caller, is not changed by the function.
* @param pFormatId ID string to specify to which format you want to export to. Use
* aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available.
* @param pFileName Output file to write
* @param pIO custom IO implementation to be used. Use this if you use your own storage methods.
* If none is supplied, a default implementation using standard file IO is used. Note that
* #aiExportSceneToBlob is provided as convienience function to export to memory buffers.
* @param pPreprocessing Please see the documentation for #aiExportScene
* @return a status code indicating the result of the export
*/
ASSIMP_API aiReturn aiExportSceneEx( const C_STRUCT aiScene* pScene, const char* pFormatId, const char* pFileName, C_STRUCT aiFileIO* pIO, unsigned int pPreprocessing );
// --------------------------------------------------------------------------------
/** Exports the given scene to a chosen file format. Returns the exported data as a binary blob which
* you can write into a file or something. When you're done with the data, use aiReleaseExportedBlob()
* you can write into a file or something. When you're done with the data, use #aiReleaseExportBlob()
* to free the resources associated with the export.
* @param pScene The scene to export. Stays in possession of the caller, is not changed by the function.
* @param pFormatId ID string to specify to which format you want to export to. Use
* aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available.
* #aiGetExportFormatCount() / #aiGetExportFormatDescription() to learn which export formats are available.
* @param pPreprocessing Please see the documentation for #aiExportScene
* @return the exported data or NULL in case of error
*/
ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const C_STRUCT aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing );
// --------------------------------------------------------------------------------
/** Releases the memory associated with the given exported data. Use this function to free a data blob
* returned by aiExportScene().
* @param pData the data blob returned by aiExportScenetoBlob
* @param pData the data blob returned by #aiExportSceneToBlob
*/
ASSIMP_API C_STRUCT void aiReleaseExportData( const C_STRUCT aiExportDataBlob* pData );
ASSIMP_API C_STRUCT void aiReleaseExportBlob( const C_STRUCT aiExportDataBlob* pData );
#ifdef __cplusplus
}

View File

@ -99,8 +99,7 @@ public:
* to use its default implementation, which uses plain file IO.
*
* @param pIOHandler The IO handler to be used in all file accesses
* of the Importer.
*/
* of the Importer. */
void SetIOHandler( IOSystem* pIOHandler);
// -------------------------------------------------------------------
@ -109,16 +108,14 @@ public:
* interface is the default IO handler provided by ASSIMP. The default
* handler is active as long the application doesn't supply its own
* custom IO handler via #SetIOHandler().
* @return A valid IOSystem interface, never NULL.
*/
* @return A valid IOSystem interface, never NULL. */
IOSystem* GetIOHandler() const;
// -------------------------------------------------------------------
/** Checks whether a default IO handler is active
* A default handler is active as long the application doesn't
* supply its own custom IO handler via #SetIOHandler().
* @return true by default
*/
* @return true by default */
bool IsDefaultIOHandler() const;
@ -172,6 +169,18 @@ public:
inline aiReturn Export( const aiScene* pScene, const std::string& pFormatId, const std::string& pPath, unsigned int pPreprocessing = 0u);
// -------------------------------------------------------------------
/** Returns an error description of an error that occurred in #Export
* or #ExportToBlob
*
* Returns an empty string if no error occurred.
* @return A description of the last error, an empty string if no
* error occurred. The string is never NULL.
*
* @note The returned function remains valid until one of the
* following methods is called: #Export, #ExportToBlob, #FreeBlob */
const char* GetErrorString() const;
// -------------------------------------------------------------------
/** Return the blob obtained from the last call to #ExportToBlob */
@ -181,10 +190,21 @@ public:
// -------------------------------------------------------------------
/** Orphan the blob from the last call to #ExportToBlob. This means
* the caller takes ownership and is thus responsible for calling
* #aiReleaseExportData to free the data again. */
* the C API function #aiReleaseExportBlob to release it. */
const aiExportDataBlob* GetOrphanedBlob() const;
// -------------------------------------------------------------------
/** Frees the current blob.
*
* The function does nothing if no blob has previously been
* previously produced via #ExportToBlob. #FreeBlob is called
* automatically by the destructor. The only reason to call
* it manually would be to reclain as much storage as possible
* without giving up the #Exporter instance yet. */
void FreeBlob( );
// -------------------------------------------------------------------
/** Returns the number of export file formats available in the current
* Assimp build. Use #Exporter::GetExportFormatDescription to