- rework exporter interface to be based primarily on the existing IOSystem.

- implement ExportToBlob/aiExportToBlob via a custom IOSystem implementation.
- split exporter C and C++ interfaces.
+ test cases for the exporter interface

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@913 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2011-03-08 16:09:54 +00:00
parent 32c8ca0a37
commit 621bdef663
12 changed files with 800 additions and 203 deletions

View File

@ -44,9 +44,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssimpPCH.h"
#include "../include/assimp.h"
#include "../include/aiFileIO.h"
#include "GenericProperty.h"
#include "CInterfaceIOWrapper.h"
// ------------------------------------------------------------------------------------------------
#ifdef AI_C_THREADSAFE
@ -58,6 +58,7 @@ using namespace Assimp;
namespace Assimp
{
/** Stores the importer objects for all active import processes */
typedef std::map<const aiScene*, Assimp::Importer*> ImporterMap;
@ -101,113 +102,8 @@ static boost::mutex gMutex;
static boost::mutex gLogStreamMutex;
#endif
class CIOSystemWrapper;
class CIOStreamWrapper;
// ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API
class CIOStreamWrapper : public IOStream
{
friend class CIOSystemWrapper;
public:
CIOStreamWrapper(aiFile* pFile)
: mFile(pFile)
{}
// ...................................................................
size_t Read(void* pvBuffer,
size_t pSize,
size_t pCount
){
// need to typecast here as C has no void*
return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
}
// ...................................................................
size_t Write(const void* pvBuffer,
size_t pSize,
size_t pCount
){
// need to typecast here as C has no void*
return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
}
// ...................................................................
aiReturn Seek(size_t pOffset,
aiOrigin pOrigin
){
return mFile->SeekProc(mFile,pOffset,pOrigin);
}
// ...................................................................
size_t Tell(void) const {
return mFile->TellProc(mFile);
}
// ...................................................................
size_t FileSize() const {
return mFile->FileSizeProc(mFile);
}
// ...................................................................
void Flush () {
return mFile->FlushProc(mFile);
}
private:
aiFile* mFile;
};
// ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API
class CIOSystemWrapper : public IOSystem
{
public:
CIOSystemWrapper(aiFileIO* pFile)
: mFileSystem(pFile)
{}
// ...................................................................
bool Exists( const char* pFile) const {
CIOSystemWrapper* pip = const_cast<CIOSystemWrapper*>(this);
IOStream* p = pip->Open(pFile);
if (p){
pip->Close(p);
return true;
}
return false;
}
// ...................................................................
char getOsSeparator() const {
#ifndef _WIN32
return '/';
#else
return '\\';
#endif
}
// ...................................................................
IOStream* Open(const char* pFile,const char* pMode = "rb") {
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode);
if (!p) {
return NULL;
}
return new CIOStreamWrapper(p);
}
// ...................................................................
void Close( IOStream* pFile) {
if (!pFile) {
return;
}
mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
delete pFile;
}
private:
aiFileIO* mFileSystem;
};
// ------------------------------------------------------------------------------------------------
// Custom LogStream implementation for the C-API

View File

@ -0,0 +1,105 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (ASSIMP)
---------------------------------------------------------------------------
Copyright (c) 2006-2010, 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 AssimpCExport.cpp
Assimp C export interface. See Exporter.cpp for some notes.
*/
#include "AssimpPCH.h"
#ifndef ASSIMP_BUILD_NO_EXPORT
#include "CInterfaceIOWrapper.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
ASSIMP_API size_t aiGetExportFormatCount(void)
{
return Exporter().GetExportFormatCount();
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
{
return Exporter().GetExportFormatDescription(pIndex);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName )
{
return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO)
{
Exporter exp;
if (pIO) {
exp.SetIOHandler(new CIOSystemWrapper(pIO));
}
return exp.Export(pScene,pFormatId,pFileName);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId )
{
Exporter exp;
if (!exp.ExportToBlob(pScene,pFormatId)) {
return NULL;
}
const aiExportDataBlob* blob = exp.GetOrphanedBlob();
ai_assert(blob);
return blob;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API C_STRUCT void aiReleaseExportData( const aiExportDataBlob* pData )
{
delete pData;
}
#endif // !ASSIMP_BUILD_NO_EXPORT

326
code/BlobIOSystem.h 100644
View File

@ -0,0 +1,326 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (ASSIMP)
---------------------------------------------------------------------------
Copyright (c) 2006-2010, 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 Provides cheat implementations for IOSystem and IOStream to
* redirect exporter output to a blob chain.*/
#ifndef AI_BLOBIOSYSTEM_H_INCLUDED
#define AI_BLOBIOSYSTEM_H_INCLUDED
namespace Assimp {
class BlobIOSystem;
// --------------------------------------------------------------------------------------------
/** Redirect IOStream to a blob */
// --------------------------------------------------------------------------------------------
class BlobIOStream : public IOStream
{
public:
BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096)
: file_size()
, cursor()
, buffer()
, creator(creator)
, file(file)
, cur_size()
, initial(initial)
{
}
virtual ~BlobIOStream();
public:
// -------------------------------------------------------------------
aiExportDataBlob* GetBlob()
{
aiExportDataBlob* blob = new aiExportDataBlob();
blob->size = file_size;
blob->data = buffer;
buffer = NULL;
return blob;
}
public:
// -------------------------------------------------------------------
virtual size_t Read(void* pvBuffer,
size_t pSize,
size_t pCount)
{
return 0;
}
// -------------------------------------------------------------------
virtual size_t Write(const void* pvBuffer,
size_t pSize,
size_t pCount)
{
pSize *= pCount;
if (cursor + pSize > cur_size) {
Grow(cursor + pSize);
}
memcpy(buffer+cursor, pvBuffer, pSize);
cursor += pSize;
file_size = std::max(file_size,cursor);
return pCount;
}
// -------------------------------------------------------------------
virtual aiReturn Seek(size_t pOffset,
aiOrigin pOrigin)
{
switch(pOrigin)
{
case aiOrigin_CUR:
cursor += pOffset;
case aiOrigin_END:
cursor = file_size - pOffset;
case aiOrigin_SET:
cursor = pOffset;
break;
default:
return AI_FAILURE;
}
if (cursor > file_size) {
Grow(cursor);
}
file_size = std::max(cursor,file_size);
return AI_SUCCESS;
}
// -------------------------------------------------------------------
virtual size_t Tell() const
{
return cursor;
}
// -------------------------------------------------------------------
virtual size_t FileSize() const
{
return file_size;
}
// -------------------------------------------------------------------
virtual void Flush()
{
// ignore
}
private:
// -------------------------------------------------------------------
void Grow(size_t need = 0)
{
// 1.5 and phi are very heap-friendly growth factors (the first
// allows for frequent re-use of heap blocks, the second
// forms a fibonacci sequence with similar characteristics -
// since this heavily depends on the heap implementation
// and other factors as well, i'll just go with 1.5 since
// it is quicker to compute).
size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
const uint8_t* const old = buffer;
buffer = new uint8_t[new_size];
if (old) {
memcpy(buffer,old,cur_size);
delete[] old;
}
cur_size = new_size;
}
private:
uint8_t* buffer;
size_t cur_size,file_size, cursor, initial;
const std::string file;
BlobIOSystem* const creator;
};
#define AI_BLOBIO_MAGIC "$blobfile"
// --------------------------------------------------------------------------------------------
/** Redirect IOSystem to a blob */
// --------------------------------------------------------------------------------------------
class BlobIOSystem : public IOSystem
{
friend class BlobIOStream;
typedef std::pair<std::string, aiExportDataBlob*> BlobEntry;
public:
BlobIOSystem()
{
}
virtual ~BlobIOSystem()
{
BOOST_FOREACH(BlobEntry& blobby, blobs) {
delete blobby.second;
}
}
public:
// -------------------------------------------------------------------
const char* GetMagicFileName() const
{
return AI_BLOBIO_MAGIC;
}
// -------------------------------------------------------------------
aiExportDataBlob* GetBlobChain()
{
// one must be the master
aiExportDataBlob* master = NULL, *cur;
BOOST_FOREACH(const BlobEntry& blobby, blobs) {
if (blobby.first == AI_BLOBIO_MAGIC) {
master = blobby.second;
break;
}
}
if (!master) {
DefaultLogger::get()->error("BlobIOSystem: no data written or master file was not closed properly.");
return NULL;
}
master->name.Set("");
cur = master;
BOOST_FOREACH(const BlobEntry& blobby, blobs) {
if (blobby.second == master) {
continue;
}
cur->next = blobby.second;
cur = cur->next;
// extract the file extension from the file written
const std::string::size_type s = blobby.first.find_first_of('.');
cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1));
}
// give up blob ownership
blobs.clear();
return master;
}
public:
// -------------------------------------------------------------------
virtual bool Exists( const char* pFile) const {
return created.find(std::string(pFile)) != created.end();
}
// -------------------------------------------------------------------
virtual char getOsSeparator() const {
return '/';
}
// -------------------------------------------------------------------
virtual IOStream* Open(const char* pFile,
const char* pMode)
{
if (pMode[0] != 'w') {
return NULL;
}
created.insert(std::string(pFile));
return new BlobIOStream(this,std::string(pFile));
}
// -------------------------------------------------------------------
virtual void Close( IOStream* pFile)
{
delete pFile;
}
private:
// -------------------------------------------------------------------
void OnDestruct(const std::string& filename, BlobIOStream* child)
{
// we don't know in which the files are closed, so we
// can't reliably say that the first must be the master
// file ...
blobs.push_back( BlobEntry(filename,child->GetBlob()) );
}
private:
std::set<std::string> created;
std::vector< BlobEntry > blobs;
};
// --------------------------------------------------------------------------------------------
BlobIOStream :: ~BlobIOStream()
{
creator->OnDestruct(file,this);
delete[] buffer;
}
} // end Assimp
#endif

View File

@ -0,0 +1,159 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (ASSIMP)
---------------------------------------------------------------------------
Copyright (c) 2006-2010, 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 aiFileIO -> IOSystem wrapper*/
#ifndef AI_CIOSYSTEM_H_INCLUDED
#define AI_CIOSYSTEM_H_INCLUDED
#include "../include/aiFileIO.h"
namespace Assimp {
// ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API
class CIOStreamWrapper : public IOStream
{
friend class CIOSystemWrapper;
public:
CIOStreamWrapper(aiFile* pFile)
: mFile(pFile)
{}
// ...................................................................
size_t Read(void* pvBuffer,
size_t pSize,
size_t pCount
){
// need to typecast here as C has no void*
return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
}
// ...................................................................
size_t Write(const void* pvBuffer,
size_t pSize,
size_t pCount
){
// need to typecast here as C has no void*
return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
}
// ...................................................................
aiReturn Seek(size_t pOffset,
aiOrigin pOrigin
){
return mFile->SeekProc(mFile,pOffset,pOrigin);
}
// ...................................................................
size_t Tell(void) const {
return mFile->TellProc(mFile);
}
// ...................................................................
size_t FileSize() const {
return mFile->FileSizeProc(mFile);
}
// ...................................................................
void Flush () {
return mFile->FlushProc(mFile);
}
private:
aiFile* mFile;
};
// ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API
class CIOSystemWrapper : public IOSystem
{
public:
CIOSystemWrapper(aiFileIO* pFile)
: mFileSystem(pFile)
{}
// ...................................................................
bool Exists( const char* pFile) const {
CIOSystemWrapper* pip = const_cast<CIOSystemWrapper*>(this);
IOStream* p = pip->Open(pFile);
if (p){
pip->Close(p);
return true;
}
return false;
}
// ...................................................................
char getOsSeparator() const {
#ifndef _WIN32
return '/';
#else
return '\\';
#endif
}
// ...................................................................
IOStream* Open(const char* pFile,const char* pMode = "rb") {
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode);
if (!p) {
return NULL;
}
return new CIOStreamWrapper(p);
}
// ...................................................................
void Close( IOStream* pFile) {
if (!pFile) {
return;
}
mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
delete pFile;
}
private:
aiFileIO* mFileSystem;
};
}
#endif

View File

@ -48,16 +48,16 @@ namespace Assimp
// ------------------------------------------------------------------------------------------------
// Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
void ExportSceneCollada( aiExportDataBlob* pBlob, const aiScene* pScene)
void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
{
// invoke the exporter
ColladaExporter iDoTheExportThing( pScene);
// we're still here - export successfully completed. Load result into given blob
pBlob->size = iDoTheExportThing.mOutput.tellp();
pBlob->data = new char[pBlob->size];
iDoTheExportThing.mOutput.seekg( 0);
iDoTheExportThing.mOutput.read( (char*) pBlob->data, pBlob->size);
// we're still here - export successfully completed. Write result to the given IOSYstem
boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
// XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
outfile->Write( iDoTheExportThing.mOutput.str().c_str(), iDoTheExportThing.mOutput.tellp(),1);
}
} // end of namespace Assimp

View File

@ -65,6 +65,8 @@ public:
private:
};
typedef DeadlyImportError DeadlyExportError;
#ifdef _MSC_VER
# pragma warning(default : 4275)
#endif

View File

@ -46,24 +46,26 @@ to the import interface (in fact, it is largely symmetric), the internal
implementations differs a lot. Exporters are considered stateless and are
simple callbacks which we maintain in a global list along with their
description strings.
Here we implement only the C++ interface (Assimp::Exporter).
*/
#include "AssimpPCH.h"
#ifndef ASSIMP_BUILD_NO_EXPORT
#include "DefaultIOStream.h"
#include "DefaultIOSystem.h"
#include "BlobIOSystem.h"
namespace Assimp {
// ------------------------------------------------------------------------------------------------
// Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype
void ExportSceneCollada(aiExportDataBlob*, const aiScene*);
void ExportScene3DS(aiExportDataBlob*, const aiScene*) { }
void ExportSceneCollada(const char*,IOSystem*, const aiScene*);
void ExportScene3DS(const char*, IOSystem*, const aiScene*) {}
/// Function pointer type of a Export worker function
typedef void (*fpExportFunc)(aiExportDataBlob*, const aiScene*);
typedef void (*fpExportFunc)(const char*,IOSystem*,const aiScene*);
// ------------------------------------------------------------------------------------------------
/// Internal description of an Assimp export format option
@ -76,10 +78,11 @@ struct ExportFormatEntry
fpExportFunc mExportFunction;
// Constructor to fill all entries
ExportFormatEntry( const char* pId, const char* pDesc, fpExportFunc pFunction)
ExportFormatEntry( const char* pId, const char* pDesc, const char* pExtension, fpExportFunc pFunction)
{
mDescription.id = pId;
mDescription.description = pDesc;
mDescription.fileExtension = pExtension;
mExportFunction = pFunction;
}
};
@ -89,11 +92,11 @@ struct ExportFormatEntry
ExportFormatEntry gExporters[] =
{
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
ExportFormatEntry( "collada", "Collada .dae", &ExportSceneCollada),
ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
#endif
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
ExportFormatEntry( "3ds", "Autodesk .3ds", &ExportScene3DS),
ExportFormatEntry( "3ds", "Autodesk 3DS (legacy format)", "3ds" , &ExportScene3DS),
#endif
};
@ -121,6 +124,8 @@ public:
bool mIsDefaultIOHandler;
};
#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0]))
} // end of namespace Assimp
@ -174,30 +179,43 @@ const aiExportDataBlob* Exporter :: ExportToBlob( const aiScene* pScene, const
pimpl->blob = NULL;
}
/* TODO (ALEX)
boost::shared_ptr<IOSystem*> old = pimpl->mIOSystem;
boost::shared_ptr<IOSystem> old = pimpl->mIOSystem;
BlobIOSystem* blobio;
pimpl->mIOSystem = blobio = new BlobIOSystem();
BlobIOSystem* blobio = new BlobIOSystem();
pimpl->mIOSystem = boost::shared_ptr<IOSystem>( blobio );
if (AI_SUCCESS != Export(pScene,pFormatId)) {
if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) {
pimpl->mIOSystem = old;
return NULL;
}
pimpl->blob = blobio->GetBlob();
pimpl->blob = blobio->GetBlobChain();
pimpl->mIOSystem = old;
return pimpl->blob;
*/
return NULL;
}
// ------------------------------------------------------------------------------------------------
aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const char* pPath )
{
ASSIMP_BEGIN_EXCEPTION_REGION();
for (size_t i = 0; i < ASSIMP_NUM_EXPORTERS; ++i) {
if (!strcmp(gExporters[i].mDescription.id,pFormatId)) {
try {
gExporters[i].mExportFunction(pPath,pimpl->mIOSystem.get(),pScene);
}
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());
return AI_FAILURE;
}
return AI_SUCCESS;
}
}
ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_FAILURE;
}
@ -219,80 +237,20 @@ const aiExportDataBlob* Exporter :: GetOrphanedBlob() const
// ------------------------------------------------------------------------------------------------
size_t Exporter :: aiGetExportFormatCount() const
size_t Exporter :: GetExportFormatCount() const
{
return ::aiGetExportFormatCount();
return ASSIMP_NUM_EXPORTERS;
}
// ------------------------------------------------------------------------------------------------
const aiExportFormatDesc* Exporter :: aiGetExportFormatDescription( size_t pIndex ) const
const aiExportFormatDesc* Exporter :: GetExportFormatDescription( size_t pIndex ) const
{
return ::aiGetExportFormatDescription(pIndex);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API size_t aiGetExportFormatCount(void)
{
return sizeof( Assimp::gExporters) / sizeof( Assimp::ExportFormatEntry);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
{
if( pIndex >= aiGetExportFormatCount() )
return NULL;
return &Assimp::gExporters[pIndex].mDescription;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName )
{
return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, const aiFileIO* pIO)
{
return AI_FAILURE;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId )
{
// find a suitable exporter
const Assimp::ExportFormatEntry* exporter = NULL;
for( size_t a = 0; a < aiGetExportFormatCount(); ++a )
{
if( strcmp( Assimp::gExporters[a].mDescription.id, pFormatId) == 0 )
exporter = Assimp::gExporters + a;
}
if( !exporter )
return NULL;
aiExportDataBlob* blob = new aiExportDataBlob;
exporter->mExportFunction( blob, pScene);
if( !blob->data || blob->size == 0 )
{
delete blob;
if (pIndex >= ASSIMP_NUM_EXPORTERS) {
return NULL;
}
return blob;
return &gExporters[pIndex].mDescription;
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API C_STRUCT void aiReleaseExportData( const aiExportDataBlob* pData )
{
delete pData;
}
#endif // !ASSIMP_BUILD_NO_EXPORT

View File

@ -149,7 +149,7 @@ public:
/** @brief Compares two paths and check whether the point to
* identical files.
*
* The dummy implementation of this virtual performs a
* The dummy implementation of this virtual member performs a
* case-insensitive comparison of the given strings. The default IO
* system implementation uses OS mechanisms to convert relative into
* absolute paths, so the result can be trusted.

View File

@ -91,6 +91,10 @@ ASSIMP_API const C_STRUCT aiExportFormatDesc* aiGetExportFormatDescription( size
* 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
@ -103,11 +107,28 @@ struct aiExportDataBlob
/// 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 = NULL; }
aiExportDataBlob() { size = 0; data = next = NULL; }
/// Releases the data
~aiExportDataBlob() { delete static_cast<char*>( data ); }
~aiExportDataBlob() { delete static_cast<char*>( data ); delete next; }
#endif // __cplusplus
};
@ -137,7 +158,7 @@ ASSIMP_API aiReturn aiExportScene( const C_STRUCT aiScene* pScene, const char* p
* #aiExportSceneToBlob is provided as convienience function to export to memory buffers.
* @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, const C_STRUCT aiFileIO* pIO );
ASSIMP_API aiReturn aiExportSceneEx( const C_STRUCT aiScene* pScene, const char* pFormatId, const char* pFileName, C_STRUCT aiFileIO* pIO );
// --------------------------------------------------------------------------------
/** Exports the given scene to a chosen file format. Returns the exported data as a binary blob which

View File

@ -59,6 +59,16 @@ namespace Assimp {
*
* The interface is modelled after the importer interface and mostly
* symmetric. The same rules for threading etc. apply.
*
* In a nutshell, there are two export interfaces: #Export, which writes the
* output file(s) either to the regular file system or to a user-supplied
* #IOSystem, and #ExportToBlob which returns a linked list of memory
* buffers (blob), each referring to one output file (in most cases
* there will be only one output file of course, but this extra complexity is
* needed since Assimp aims at supporting a wide range of file formats).
*
* #ExportToBlob is especially useful if you intend to work
* with the data in-memory.
*/
class ASSIMP_API Exporter
// TODO: causes good ol' base class has no dll interface warning
@ -77,9 +87,11 @@ public:
// -------------------------------------------------------------------
/** Supplies a custom IO handler to the exporter to use to open and
* access files. If you need the exporter to use custion IO logic to
* access the files, you need to supply a custom implementation of
* IOSystem and IOFile to the exporter.
* access files.
*
* If you need #Export to use custom IO logic to access the files,
* you need to supply a custom implementation of IOSystem and
* IOFile to the exporter.
*
* #Exporter takes ownership of the object and will destroy it
* afterwards. The previously assigned handler will be deleted.
@ -124,7 +136,8 @@ public:
* export formats are available.
* @return the exported data or NULL in case of error.
* @note If the Exporter instance did already hold a blob from
* a previous call to #ExportToBlob, it will be disposed. */
* a previous call to #ExportToBlob, it will be disposed.
* Any IO handlers set via #SetIOHandler are ignored here.*/
const aiExportDataBlob* ExportToBlob( const aiScene* pScene, const char* pFormatId );
@ -155,7 +168,7 @@ public:
/** Returns the number of export file formats available in the current
* Assimp build. Use #Exporter::GetExportFormatDescription to
* retrieve infos of a specific export format */
size_t aiGetExportFormatCount() const;
size_t GetExportFormatCount() const;
// -------------------------------------------------------------------
@ -166,7 +179,7 @@ public:
* for. Valid range is 0 to #Exporter::GetExportFormatCount
* @return A description of that specific export format.
* NULL if pIndex is out of range. */
const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex ) const;
const aiExportFormatDesc* GetExportFormatDescription( size_t pIndex ) const;
protected:

View File

@ -0,0 +1,76 @@
#include "UnitTestPCH.h"
#include "utExport.h"
#ifndef ASSIMP_BUILD_NO_EXPORT
CPPUNIT_TEST_SUITE_REGISTRATION (ExporterTest);
void ExporterTest :: setUp (void)
{
ex = new Assimp::Exporter();
im = new Assimp::Importer();
pTest = im->ReadFile("../../test/models/X/test.x",0);
}
void ExporterTest :: tearDown (void)
{
delete ex;
delete im;
}
void ExporterTest :: testExportToFile (void)
{
const char* file = "unittest_output.dae";
CPPUNIT_ASSERT_EQUAL(AI_SUCCESS,ex->Export(pTest,"collada",file));
// check if we can read it again
CPPUNIT_ASSERT(im->ReadFile(file,0));
}
void ExporterTest :: testExportToBlob (void)
{
const aiExportDataBlob* blob = ex->ExportToBlob(pTest,"collada");
CPPUNIT_ASSERT(blob);
CPPUNIT_ASSERT(blob->data);
CPPUNIT_ASSERT(blob->size > 0);
CPPUNIT_ASSERT(!blob->name.length);
// XXX test chained blobs (i.e. obj file with accompanying mtl script)
// check if we can read it again
CPPUNIT_ASSERT(im->ReadFileFromMemory(blob->data,blob->size,0,"dae"));
}
void ExporterTest :: testCppExportInterface (void)
{
CPPUNIT_ASSERT(ex->GetExportFormatCount() > 0);
for(size_t i = 0; i < ex->GetExportFormatCount(); ++i) {
const aiExportFormatDesc* const desc = ex->GetExportFormatDescription(i);
CPPUNIT_ASSERT(desc);
CPPUNIT_ASSERT(desc->description && strlen(desc->description));
CPPUNIT_ASSERT(desc->fileExtension && strlen(desc->fileExtension));
CPPUNIT_ASSERT(desc->id && strlen(desc->id));
}
CPPUNIT_ASSERT(ex->IsDefaultIOHandler());
}
void ExporterTest :: testCExportInterface (void)
{
CPPUNIT_ASSERT(aiGetExportFormatCount() > 0);
for(size_t i = 0; i < aiGetExportFormatCount(); ++i) {
const aiExportFormatDesc* const desc = aiGetExportFormatDescription(i);
CPPUNIT_ASSERT(desc);
// rest has aleady been validated by testCppExportInterface
}
}
#endif

View File

@ -0,0 +1,41 @@
#ifndef INCLUDED_UT_EXPORT_H
#define INCLUDED_UT_EXPORT_H
#ifndef ASSIMP_BUILD_NO_EXPORT
#include <export.h>
#include <export.hpp>
using namespace Assimp;
class ExporterTest : public CPPUNIT_NS :: TestFixture
{
CPPUNIT_TEST_SUITE (ExporterTest);
CPPUNIT_TEST (testExportToFile);
CPPUNIT_TEST (testExportToBlob);
CPPUNIT_TEST (testCppExportInterface);
CPPUNIT_TEST (testCExportInterface);
CPPUNIT_TEST_SUITE_END ();
public:
void setUp (void);
void tearDown (void);
protected:
void testExportToFile (void);
void testExportToBlob (void);
void testCppExportInterface (void);
void testCExportInterface (void);
private:
const aiScene* pTest;
Assimp::Exporter* ex;
Assimp::Importer* im;
};
#endif
#endif