فهرست منبع

- 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

aramis_acg 14 سال پیش
والد
کامیت
36b3695a31
8فایلهای تغییر یافته به همراه176 افزوده شده و 76 حذف شده
  1. 11 1
      code/AssimpCExport.cpp
  2. 2 0
      code/BlenderModifier.cpp
  3. 47 4
      code/Exporter.cpp
  4. 9 2
      code/SceneCombiner.cpp
  5. 1 1
      code/SceneCombiner.h
  6. 1 1
      include/aiScene.h
  7. 78 60
      include/export.h
  8. 27 7
      include/export.hpp

+ 11 - 1
code/AssimpCExport.cpp

@@ -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;
 }

+ 2 - 0
code/BlenderModifier.cpp

@@ -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

+ 47 - 4
code/Exporter.cpp

@@ -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 
 {

+ 9 - 2
code/SceneCombiner.cpp

@@ -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;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 1 - 1
code/SceneCombiner.h

@@ -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);
 
 
 	// -------------------------------------------------------------------

+ 1 - 1
include/aiScene.h

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

+ 78 - 60
include/export.h

@@ -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,63 +77,33 @@ 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.
-*/
-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()
-* 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.
-*
-* Blobs can be nested - each blob may reference another blob, which may in turn reference another blob and so on.
-* This is used when exporters write more than one output file for a given #aiScene. See the remarks for
-* #aiExportDataBlob::name for more information.
-*/
-struct aiExportDataBlob 
-#ifdef __cplusplus
-	: public boost::noncopyable
-#endif // __cplusplus
-{
-	/// Size of the data in bytes
-	size_t size;
-
-	/// The data. 
-	void* data;
 
-	/** Name of the blob. An empty string always
-	    indicates the first (and primary) blob,
-	    which contains the actual file data.
-        Any other blobs are auxiliary files produced
-	    by exporters (i.e. material files). Existence
-	    of such files depends on the file format. Most
-	    formats don't split assets across multiple files.
-
-		If used, blob names usually contain the file
-		extension that should be used when writing 
-		the data to disc.
-	 */
-	aiString name;
-
-	/** Pointer to the next blob in the chain or NULL if there is none. */
-	aiExportDataBlob * next;
+// --------------------------------------------------------------------------------
+/** 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);
 
-#ifdef __cplusplus
-	/// Default constructor
-	aiExportDataBlob() { size = 0; data = next = NULL; }
-	/// Releases the data
-	~aiExportDataBlob() { delete static_cast<char*>( data ); delete next; }
-#endif // __cplusplus
-};
 
+// --------------------------------------------------------------------------------
+/** 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.
@@ -164,7 +136,7 @@ struct aiExportDataBlob
 *   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.
+*   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);
@@ -184,26 +156,72 @@ ASSIMP_API aiReturn aiExportScene( const C_STRUCT aiScene* pScene, const char* p
 */
 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.
+*
+* Blobs can be nested - each blob may reference another blob, which may in turn reference another blob and so on.
+* This is used when exporters write more than one output file for a given #aiScene. See the remarks for
+* #aiExportDataBlob::name for more information.
+*/
+struct aiExportDataBlob 
+#ifdef __cplusplus
+	: public boost::noncopyable
+#endif // __cplusplus
+{
+	/// Size of the data in bytes
+	size_t size;
+
+	/// The data. 
+	void* data;
+
+	/** Name of the blob. An empty string always
+	    indicates the first (and primary) blob,
+	    which contains the actual file data.
+        Any other blobs are auxiliary files produced
+	    by exporters (i.e. material files). Existence
+	    of such files depends on the file format. Most
+	    formats don't split assets across multiple files.
+
+		If used, blob names usually contain the file
+		extension that should be used when writing 
+		the data to disc.
+	 */
+	aiString name;
+
+	/** Pointer to the next blob in the chain or NULL if there is none. */
+	aiExportDataBlob * next;
+
+#ifdef __cplusplus
+	/// Default constructor
+	aiExportDataBlob() { size = 0; data = next = NULL; }
+	/// Releases the data
+	~aiExportDataBlob() { delete static_cast<char*>( data ); delete next; }
+#endif // __cplusplus
+};
+
 // --------------------------------------------------------------------------------
 /** 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
 }

+ 27 - 7
include/export.hpp

@@ -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