closes https://github.com/assimp/assimp/issues/2199: introduce first version for exporter.

pull/2217/head
Kim Kulling 2018-11-12 22:26:10 +01:00
parent 3fbe9095d1
commit b6af80f2fd
8 changed files with 194 additions and 65 deletions

View File

@ -52,9 +52,7 @@ namespace Assimp {
// ------------------------------------------------------------------------------------
/** @brief Internal default implementation of the #ProgressHandler interface. */
class DefaultProgressHandler
: public ProgressHandler {
class DefaultProgressHandler : public ProgressHandler {
virtual bool Update(float /*percentage*/) {
return false;

View File

@ -56,22 +56,22 @@ Here we implement only the C++ interface (Assimp::Exporter).
#include <assimp/BlobIOSystem.h>
#include <assimp/SceneCombiner.h>
#include "BaseProcess.h"
#include "Importer.h" // need this for GetPostProcessingStepInstanceList()
#include <assimp/DefaultIOSystem.h>
#include <assimp/Exporter.hpp>
#include <assimp/mesh.h>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include "DefaultProgressHandler.h"
#include "BaseProcess.h"
#include "JoinVerticesProcess.h"
#include "MakeVerboseFormat.h"
#include "ConvertToLHProcess.h"
#include "PretransformVertices.h"
#include <assimp/Exceptional.h>
#include "ScenePrivate.h"
#include <memory>
#include <assimp/DefaultIOSystem.h>
#include <assimp/Exporter.hpp>
#include <assimp/mesh.h>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <memory>
namespace Assimp {
@ -188,10 +188,14 @@ Exporter::ExportFormatEntry gExporters[] =
class ExporterPimpl {
public:
ExporterPimpl()
: blob()
, mIOSystem(new Assimp::DefaultIOSystem())
, mIsDefaultIOHandler(true)
{
: blob()
, mIOSystem(new Assimp::DefaultIOSystem())
, mIsDefaultIOHandler(true)
, mProgressHandler( nullptr )
, mIsDefaultProgressHandler( true )
, mPostProcessingSteps()
, mError()
, mExporters() {
GetPostProcessingStepInstanceList(mPostProcessingSteps);
// grab all built-in exporters
@ -201,8 +205,7 @@ public:
}
}
~ExporterPimpl()
{
~ExporterPimpl() {
delete blob;
// Delete all post-processing plug-ins
@ -216,6 +219,10 @@ public:
std::shared_ptr< Assimp::IOSystem > mIOSystem;
bool mIsDefaultIOHandler;
/** The progress handler */
ProgressHandler *mProgressHandler;
bool mIsDefaultProgressHandler;
/** Post processing steps we can apply at the imported data. */
std::vector< BaseProcess* > mPostProcessingSteps;
@ -233,13 +240,16 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------
Exporter :: Exporter()
: pimpl(new ExporterPimpl()) {
// empty
pimpl->mProgressHandler = new DefaultProgressHandler();
}
// ------------------------------------------------------------------------------------------------
Exporter::~Exporter() {
FreeBlob();
if (pimpl->mIsDefaultProgressHandler) {
delete pimpl->mProgressHandler;
pimpl->mProgressHandler = nullptr;
}
delete pimpl;
}
@ -259,12 +269,32 @@ bool Exporter::IsDefaultIOHandler() const {
return pimpl->mIsDefaultIOHandler;
}
// ------------------------------------------------------------------------------------------------
void Exporter::SetProgressHandler(ProgressHandler* pHandler) {
ai_assert(nullptr != pimpl);
if ( nullptr == pHandler) {
// Release pointer in the possession of the caller
pimpl->mProgressHandler = new DefaultProgressHandler();
pimpl->mIsDefaultProgressHandler = true;
return;
}
if (pimpl->mProgressHandler == pHandler) {
return;
}
delete pimpl->mProgressHandler;
pimpl->mProgressHandler = pHandler;
pimpl->mIsDefaultProgressHandler = false;
}
// ------------------------------------------------------------------------------------------------
const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId,
unsigned int, const ExportProperties* /*pProperties*/ ) {
if (pimpl->blob) {
delete pimpl->blob;
pimpl->blob = NULL;
pimpl->blob = nullptr;
}
std::shared_ptr<IOSystem> old = pimpl->mIOSystem;
@ -273,7 +303,7 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha
if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) {
pimpl->mIOSystem = old;
return NULL;
return nullptr;
}
pimpl->blob = blobio->GetBlobChain();
@ -295,6 +325,7 @@ bool IsVerboseFormat(const aiMesh* mesh) {
}
}
}
return true;
}
@ -305,6 +336,7 @@ bool IsVerboseFormat(const aiScene* pScene) {
return false;
}
}
return true;
}
@ -319,6 +351,8 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
// meshes upfront.
const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene);
pimpl->mProgressHandler->UpdateFileWrite(0, 4);
pimpl->mError = "";
for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
@ -326,9 +360,11 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
try {
// Always create a full copy of the scene. We might optimize this one day,
// but for now it is the most pragmatic way.
aiScene* scenecopy_tmp = NULL;
aiScene* scenecopy_tmp = nullptr;
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
pimpl->mProgressHandler->UpdateFileWrite(1, 4);
std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
const ScenePrivateData* const priv = ScenePriv(pScene);
@ -375,6 +411,8 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
}
}
pimpl->mProgressHandler->UpdateFileWrite(2, 4);
if (pp) {
// the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
{
@ -418,11 +456,13 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
}
}
ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
ai_assert(privOut);
ai_assert(nullptr != privOut);
privOut->mPPStepsApplied |= pp;
}
pimpl->mProgressHandler->UpdateFileWrite(3, 4);
if(must_join_again) {
JoinVerticesProcess proc;
proc.Execute(scenecopy.get());
@ -430,6 +470,8 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry.
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties);
pimpl->mProgressHandler->UpdateFileWrite(4, 4);
} catch (DeadlyExportError& err) {
pimpl->mError = err.what();
return AI_FAILURE;
@ -452,7 +494,7 @@ const char* Exporter::GetErrorString() const {
// ------------------------------------------------------------------------------------------------
void Exporter::FreeBlob() {
delete pimpl->blob;
pimpl->blob = NULL;
pimpl->blob = nullptr;
pimpl->mError = "";
}
@ -465,7 +507,7 @@ const aiExportDataBlob* Exporter::GetBlob() const {
// ------------------------------------------------------------------------------------------------
const aiExportDataBlob* Exporter::GetOrphanedBlob() const {
const aiExportDataBlob* tmp = pimpl->blob;
pimpl->blob = NULL;
pimpl->blob = nullptr;
return tmp;
}
@ -545,75 +587,63 @@ bool ExportProperties::SetPropertyString(const char* szName, const std::string&
// ------------------------------------------------------------------------------------------------
// Set a configuration property
bool ExportProperties :: SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
{
bool ExportProperties::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
int ExportProperties :: GetPropertyInteger(const char* szName,
int iErrorReturn /*= 0xffffffff*/) const
{
int ExportProperties::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
ai_real ExportProperties :: GetPropertyFloat(const char* szName,
ai_real iErrorReturn /*= 10e10*/) const
{
ai_real ExportProperties::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
return GetGenericProperty<ai_real>(mFloatProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
const std::string ExportProperties :: GetPropertyString(const char* szName,
const std::string& iErrorReturn /*= ""*/) const
{
const std::string ExportProperties::GetPropertyString(const char* szName,
const std::string& iErrorReturn /*= ""*/) const {
return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
const aiMatrix4x4 ExportProperties :: GetPropertyMatrix(const char* szName,
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
{
const aiMatrix4x4 ExportProperties::GetPropertyMatrix(const char* szName,
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties :: HasPropertyInteger(const char* szName) const
{
bool ExportProperties::HasPropertyInteger(const char* szName) const {
return HasGenericProperty<int>(mIntProperties, szName);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties :: HasPropertyBool(const char* szName) const
{
bool ExportProperties::HasPropertyBool(const char* szName) const {
return HasGenericProperty<int>(mIntProperties, szName);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties :: HasPropertyFloat(const char* szName) const
{
bool ExportProperties::HasPropertyFloat(const char* szName) const {
return HasGenericProperty<ai_real>(mFloatProperties, szName);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties :: HasPropertyString(const char* szName) const
{
bool ExportProperties::HasPropertyString(const char* szName) const {
return HasGenericProperty<std::string>(mStringProperties, szName);
}
// ------------------------------------------------------------------------------------------------
// Has a configuration property
bool ExportProperties :: HasPropertyMatrix(const char* szName) const
{
bool ExportProperties::HasPropertyMatrix(const char* szName) const {
return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
}

View File

@ -315,22 +315,19 @@ void Importer::SetIOHandler( IOSystem* pIOHandler)
// ------------------------------------------------------------------------------------------------
// Get the currently set IO handler
IOSystem* Importer::GetIOHandler() const
{
IOSystem* Importer::GetIOHandler() const {
return pimpl->mIOHandler;
}
// ------------------------------------------------------------------------------------------------
// Check whether a custom IO handler is currently set
bool Importer::IsDefaultIOHandler() const
{
bool Importer::IsDefaultIOHandler() const {
return pimpl->mIsDefaultHandler;
}
// ------------------------------------------------------------------------------------------------
// Supplies a custom progress handler to get regular callbacks during importing
void Importer::SetProgressHandler ( ProgressHandler* pHandler )
{
void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
ASSIMP_BEGIN_EXCEPTION_REGION();
// If the new handler is zero, allocate a default implementation.
if (!pHandler)
@ -351,15 +348,13 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler )
// ------------------------------------------------------------------------------------------------
// Get the currently set progress handler
ProgressHandler* Importer::GetProgressHandler() const
{
ProgressHandler* Importer::GetProgressHandler() const {
return pimpl->mProgressHandler;
}
// ------------------------------------------------------------------------------------------------
// Check whether a custom progress handler is currently set
bool Importer::IsDefaultProgressHandler() const
{
bool Importer::IsDefaultProgressHandler() const {
return pimpl->mIsDefaultProgressHandler;
}

View File

@ -57,6 +57,7 @@ namespace Assimp {
class ExporterPimpl;
class IOSystem;
class ProgressHandler;
// ----------------------------------------------------------------------------------
/** CPP-API: The Exporter class forms an C++ interface to the export functionality
@ -84,8 +85,7 @@ public:
typedef void (*fpExportFunc)(const char*, IOSystem*, const aiScene*, const ExportProperties*);
/** Internal description of an Assimp export format option */
struct ExportFormatEntry
{
struct ExportFormatEntry {
/// Public description structure to be returned by aiGetExportFormatDescription()
aiExportFormatDesc mDescription;
@ -158,6 +158,19 @@ public:
* @return true by default */
bool IsDefaultIOHandler() const;
// -------------------------------------------------------------------
/** Supplies a custom progress handler to the exporter. This
* interface exposes an #Update() callback, which is called
* more or less periodically (please don't sue us if it
* isn't as periodically as you'd like it to have ...).
* This can be used to implement progress bars and loading
* timeouts.
* @param pHandler Progress callback interface. Pass nullptr to
* disable progress reporting.
* @note Progress handlers can be used to abort the loading
* at almost any time.*/
void SetProgressHandler(ProgressHandler* pHandler);
// -------------------------------------------------------------------
/** 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.

View File

@ -330,7 +330,7 @@ public:
// -------------------------------------------------------------------
/** Supplies a custom progress handler to the importer. This
* interface exposes a #Update() callback, which is called
* interface exposes an #Update() callback, which is called
* more or less periodically (please don't sue us if it
* isn't as periodically as you'd like it to have ...).
* This can be used to implement progress bars and loading

View File

@ -62,11 +62,13 @@ class ASSIMP_API ProgressHandler
#endif
{
protected:
/** @brief Default constructor */
ProgressHandler () AI_NO_EXCEPT {
/// @brief Default constructor
ProgressHandler () AI_NO_EXCEPT {
// empty
}
public:
/** @brief Virtual destructor */
/// @brief Virtual destructor.
virtual ~ProgressHandler () {
}
@ -120,8 +122,24 @@ public:
Update( f * 0.5f + 0.5f );
}
// -------------------------------------------------------------------
/** @brief Progress callback for export steps.
* @param numberOfSteps The number of total processing
* steps
* @param currentStep The index of the current post-processing
* step that will run, or equal to numberOfSteps if all of
* them has finished. This number is always strictly monotone
* increasing, although not necessarily linearly.
* */
virtual void UpdateFileWrite(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) {
float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f;
Update(f * 0.5f);
}
}; // !class ProgressHandler
// ------------------------------------------------------------------------------------
} // Namespace Assimp
#endif // AI_PROGRESSHANDLER_H_INC

View File

@ -87,6 +87,7 @@ SET( IMPORTERS
unit/utIFCImportExport.cpp
unit/utFBXImporterExporter.cpp
unit/utImporter.cpp
unit/ImportExport/utExporter.cpp
unit/ut3DImportExport.cpp
unit/ut3DSImportExport.cpp
unit/utACImportExport.cpp

View File

@ -0,0 +1,74 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2018, assimp 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 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.
---------------------------------------------------------------------------
*/
#include "UnitTestPCH.h"
#include <assimp/Exporter.hpp>
#include <assimp/ProgressHandler.hpp>
using namespace Assimp;
class TestProgressHandler : public ProgressHandler {
public:
TestProgressHandler() : ProgressHandler() {
// empty
}
virtual ~TestProgressHandler() {
// empty
}
bool Update(float percentage = -1.f) override {
return true;
}
};
class ExporterTest : public ::testing::Test {
// empty
};
TEST_F(ExporterTest, ProgressHandlerTest) {
Exporter exporter;
TestProgressHandler *ph(new TestProgressHandler);
exporter.SetProgressHandler(ph);
delete ph;
}