Merge branch 'master' into fixTexcoord

pull/2829/head
Malcolm Tyrrell 2019-12-12 12:19:02 +00:00 committed by GitHub
commit b6553b8a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 2405 additions and 1985 deletions

View File

@ -253,7 +253,7 @@ ELSEIF(MSVC)
IF(MSVC12) IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
ENDIF() ENDIF()
SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi /O0") SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Zi /Od")
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
IF(NOT HUNTER_ENABLED) IF(NOT HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2019, assimp team Copyright (c) 2006-2019, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -78,7 +76,6 @@ static const aiImporterDesc desc = {
"b3d" "b3d"
}; };
// (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings
#ifdef _MSC_VER #ifdef _MSC_VER
# pragma warning (disable: 4018) # pragma warning (disable: 4018)
#endif #endif
@ -86,10 +83,8 @@ static const aiImporterDesc desc = {
//#define DEBUG_B3D //#define DEBUG_B3D
template<typename T> template<typename T>
void DeleteAllBarePointers(std::vector<T>& x) void DeleteAllBarePointers(std::vector<T>& x) {
{ for(auto p : x) {
for(auto p : x)
{
delete p; delete p;
} }
} }
@ -102,10 +97,14 @@ B3DImporter::~B3DImporter()
bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{ bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
size_t pos=pFile.find_last_of( '.' ); size_t pos=pFile.find_last_of( '.' );
if( pos==string::npos ) return false; if( pos==string::npos ) {
return false;
}
string ext=pFile.substr( pos+1 ); string ext=pFile.substr( pos+1 );
if( ext.size()!=3 ) return false; if( ext.size()!=3 ) {
return false;
}
return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D'); return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
} }
@ -117,30 +116,21 @@ const aiImporterDesc* B3DImporter::GetInfo () const
return &desc; return &desc;
} }
#ifdef DEBUG_B3D
extern "C"{ void _stdcall AllocConsole(); }
#endif
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){
#ifdef DEBUG_B3D
AllocConsole();
freopen( "conin$","r",stdin );
freopen( "conout$","w",stdout );
freopen( "conout$","w",stderr );
cout<<"Hello world from the B3DImporter!"<<endl;
#endif
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile)); std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
// Check whether we can read from the file // Check whether we can read from the file
if( file.get() == NULL) if( file.get() == nullptr) {
throw DeadlyImportError( "Failed to open B3D file " + pFile + "."); throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
}
// check whether the .b3d file is large enough to contain // check whether the .b3d file is large enough to contain
// at least one chunk. // at least one chunk.
size_t fileSize = file->FileSize(); size_t fileSize = file->FileSize();
if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small."); if( fileSize<8 ) {
throw DeadlyImportError( "B3D File is too small.");
}
_pos=0; _pos=0;
_buf.resize( fileSize ); _buf.resize( fileSize );
@ -158,14 +148,17 @@ AI_WONT_RETURN void B3DImporter::Oops(){
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void B3DImporter::Fail( string str ){ AI_WONT_RETURN void B3DImporter::Fail( string str ){
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
cout<<"Error in B3D file data: "<<str<<endl; ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
#endif #endif
throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str ); throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
int B3DImporter::ReadByte(){ int B3DImporter::ReadByte(){
if( _pos<_buf.size() ) return _buf[_pos++]; if( _pos<_buf.size() ) {
return _buf[_pos++];
}
Fail( "EOF" ); Fail( "EOF" );
return 0; return 0;
} }
@ -224,7 +217,9 @@ string B3DImporter::ReadString(){
string str; string str;
while( _pos<_buf.size() ){ while( _pos<_buf.size() ){
char c=(char)ReadByte(); char c=(char)ReadByte();
if( !c ) return str; if( !c ) {
return str;
}
str+=c; str+=c;
} }
Fail( "EOF" ); Fail( "EOF" );
@ -238,7 +233,7 @@ string B3DImporter::ReadChunk(){
tag+=char( ReadByte() ); tag+=char( ReadByte() );
} }
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
// cout<<"ReadChunk:"<<tag<<endl; ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
#endif #endif
unsigned sz=(unsigned)ReadInt(); unsigned sz=(unsigned)ReadInt();
_stack.push_back( _pos+sz ); _stack.push_back( _pos+sz );
@ -269,7 +264,6 @@ T *B3DImporter::to_array( const vector<T> &v ){
return p; return p;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template<class T> template<class T>
T **unique_to_array( vector<std::unique_ptr<T> > &v ){ T **unique_to_array( vector<std::unique_ptr<T> > &v ){
@ -283,7 +277,6 @@ T **unique_to_array( vector<std::unique_ptr<T> > &v ){
return p; return p;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void B3DImporter::ReadTEXS(){ void B3DImporter::ReadTEXS(){
while( ChunkSize() ){ while( ChunkSize() ){
@ -376,9 +369,13 @@ void B3DImporter::ReadVRTS(){
v.vertex=ReadVec3(); v.vertex=ReadVec3();
if( _vflags & 1 ) v.normal=ReadVec3(); if( _vflags & 1 ) {
v.normal=ReadVec3();
}
if( _vflags & 2 ) ReadQuat(); //skip v 4bytes... if( _vflags & 2 ) {
ReadQuat(); //skip v 4bytes...
}
for( int i=0;i<_tcsets;++i ){ for( int i=0;i<_tcsets;++i ){
float t[4]={0,0,0,0}; float t[4]={0,0,0,0};
@ -386,53 +383,55 @@ void B3DImporter::ReadVRTS(){
t[j]=ReadFloat(); t[j]=ReadFloat();
} }
t[1]=1-t[1]; t[1]=1-t[1];
if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] ); if( !i ) {
v.texcoords=aiVector3D( t[0],t[1],t[2] );
}
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void B3DImporter::ReadTRIS( int v0 ){ void B3DImporter::ReadTRIS(int v0) {
int matid=ReadInt(); int matid = ReadInt();
if( matid==-1 ){ if (matid == -1) {
matid=0; matid = 0;
}else if( matid<0 || matid>=(int)_materials.size() ){ } else if (matid < 0 || matid >= (int)_materials.size()) {
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
cout<<"material id="<<matid<<endl; ASSIMP_LOG_ERROR_F("material id=", matid);
#endif #endif
Fail( "Bad material id" ); Fail("Bad material id");
} }
std::unique_ptr<aiMesh> mesh(new aiMesh); std::unique_ptr<aiMesh> mesh(new aiMesh);
mesh->mMaterialIndex=matid; mesh->mMaterialIndex = matid;
mesh->mNumFaces=0; mesh->mNumFaces = 0;
mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE; mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
int n_tris=ChunkSize()/12; int n_tris = ChunkSize() / 12;
aiFace *face=mesh->mFaces=new aiFace[n_tris]; aiFace *face = mesh->mFaces = new aiFace[n_tris];
for( int i=0;i<n_tris;++i ){ for (int i = 0; i < n_tris; ++i) {
int i0=ReadInt()+v0; int i0 = ReadInt() + v0;
int i1=ReadInt()+v0; int i1 = ReadInt() + v0;
int i2=ReadInt()+v0; int i2 = ReadInt() + v0;
if( i0<0 || i0>=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){ if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) {
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
cout<<"Bad triangle index: i0="<<i0<<", i1="<<i1<<", i2="<<i2<<endl; ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
#endif #endif
Fail( "Bad triangle index" ); Fail("Bad triangle index");
continue; continue;
} }
face->mNumIndices=3; face->mNumIndices = 3;
face->mIndices=new unsigned[3]; face->mIndices = new unsigned[3];
face->mIndices[0]=i0; face->mIndices[0] = i0;
face->mIndices[1]=i1; face->mIndices[1] = i1;
face->mIndices[2]=i2; face->mIndices[2] = i2;
++mesh->mNumFaces; ++mesh->mNumFaces;
++face; ++face;
} }
_meshes.emplace_back( std::move(mesh) ); _meshes.emplace_back(std::move(mesh));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -453,29 +452,23 @@ void B3DImporter::ReadMESH(){
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void B3DImporter::ReadBONE( int id ){ void B3DImporter::ReadBONE(int id) {
while( ChunkSize() ){ while (ChunkSize()) {
int vertex=ReadInt(); int vertex = ReadInt();
float weight=ReadFloat(); float weight = ReadFloat();
if( vertex<0 || vertex>=(int)_vertices.size() ){ if (vertex < 0 || vertex >= (int)_vertices.size()) {
Fail( "Bad vertex index" ); Fail("Bad vertex index");
} }
Vertex &v=_vertices[vertex]; Vertex &v = _vertices[vertex];
int i; for (int i = 0; i < 4; ++i) {
for( i=0;i<4;++i ){ if (!v.weights[i]) {
if( !v.weights[i] ){ v.bones[i] = id;
v.bones[i]=id; v.weights[i] = weight;
v.weights[i]=weight; break;
break; }
} }
} }
#ifdef DEBUG_B3D
if( i==4 ){
cout<<"Too many bone weights"<<endl;
}
#endif
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -633,11 +626,15 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
} }
ExitChunk(); ExitChunk();
if( !_nodes.size() ) Fail( "No nodes" ); if( !_nodes.size() ) {
Fail( "No nodes" );
}
if( !_meshes.size() ) Fail( "No meshes" ); if( !_meshes.size() ) {
Fail( "No meshes" );
}
//Fix nodes/meshes/bones // Fix nodes/meshes/bones
for(size_t i=0;i<_nodes.size();++i ){ for(size_t i=0;i<_nodes.size();++i ){
aiNode *node=_nodes[i]; aiNode *node=_nodes[i];
@ -648,8 +645,12 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
int n_verts=mesh->mNumVertices=n_tris * 3; int n_verts=mesh->mNumVertices=n_tris * 3;
aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0; aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0;
if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ]; if( _vflags & 1 ) {
if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; mn=mesh->mNormals=new aiVector3D[ n_verts ];
}
if( _tcsets ) {
mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
}
aiFace *face=mesh->mFaces; aiFace *face=mesh->mFaces;

View File

@ -411,6 +411,8 @@ ADD_ASSIMP_IMPORTER( M3D
M3D/M3DMaterials.h M3D/M3DMaterials.h
M3D/M3DImporter.h M3D/M3DImporter.h
M3D/M3DImporter.cpp M3D/M3DImporter.cpp
M3D/M3DWrapper.h
M3D/M3DWrapper.cpp
M3D/m3d.h M3D/m3d.h
) )

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2019, assimp team Copyright (c) 2006-2019, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -78,6 +76,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/Profiler.h> #include <assimp/Profiler.h>
#include <assimp/commonMetaData.h>
#include <set> #include <set>
#include <memory> #include <memory>
#include <cctype> #include <cctype>
@ -119,7 +119,7 @@ void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothro
return AllocateFromAssimpHeap::operator new( num_bytes ); return AllocateFromAssimpHeap::operator new( num_bytes );
} }
catch( ... ) { catch( ... ) {
return NULL; return nullptr;
} }
} }
@ -134,9 +134,8 @@ void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) {
void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() { void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() {
try { try {
return AllocateFromAssimpHeap::operator new[]( num_bytes ); return AllocateFromAssimpHeap::operator new[]( num_bytes );
} } catch( ... ) {
catch( ... ) { return nullptr;
return NULL;
} }
} }
@ -148,7 +147,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) {
// Importer constructor. // Importer constructor.
Importer::Importer() Importer::Importer()
: pimpl( new ImporterPimpl ) { : pimpl( new ImporterPimpl ) {
pimpl->mScene = NULL; pimpl->mScene = nullptr;
pimpl->mErrorString = ""; pimpl->mErrorString = "";
// Allocate a default IO handler // Allocate a default IO handler
@ -174,14 +173,14 @@ Importer::Importer()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor of Importer // Destructor of Importer
Importer::~Importer() Importer::~Importer() {
{
// Delete all import plugins // Delete all import plugins
DeleteImporterInstanceList(pimpl->mImporter); DeleteImporterInstanceList(pimpl->mImporter);
// Delete all post-processing plug-ins // Delete all post-processing plug-ins
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
delete pimpl->mPostProcessingSteps[a]; delete pimpl->mPostProcessingSteps[a];
}
// Delete the assigned IO and progress handler // Delete the assigned IO and progress handler
delete pimpl->mIOHandler; delete pimpl->mIOHandler;
@ -199,9 +198,9 @@ Importer::~Importer()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Register a custom post-processing step // Register a custom post-processing step
aiReturn Importer::RegisterPPStep(BaseProcess* pImp) aiReturn Importer::RegisterPPStep(BaseProcess* pImp) {
{ ai_assert( nullptr != pImp );
ai_assert(NULL != pImp);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
pimpl->mPostProcessingSteps.push_back(pImp); pimpl->mPostProcessingSteps.push_back(pImp);
@ -213,9 +212,9 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Register a custom loader plugin // Register a custom loader plugin
aiReturn Importer::RegisterLoader(BaseImporter* pImp) aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
{ ai_assert(nullptr != pImp);
ai_assert(NULL != pImp);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@ -242,13 +241,13 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
pimpl->mImporter.push_back(pImp); pimpl->mImporter.push_back(pImp);
ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked); ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked);
ASSIMP_END_EXCEPTION_REGION(aiReturn); ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_SUCCESS; return AI_SUCCESS;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Unregister a custom loader plugin // Unregister a custom loader plugin
aiReturn Importer::UnregisterLoader(BaseImporter* pImp) aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
{
if(!pImp) { if(!pImp) {
// unregistering a NULL importer is no problem for us ... really! // unregistering a NULL importer is no problem for us ... really!
return AI_SUCCESS; return AI_SUCCESS;
@ -265,13 +264,13 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
} }
ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ..."); ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ...");
ASSIMP_END_EXCEPTION_REGION(aiReturn); ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_FAILURE; return AI_FAILURE;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Unregister a custom loader plugin // Unregister a custom loader plugin
aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) {
{
if(!pImp) { if(!pImp) {
// unregistering a NULL ppstep is no problem for us ... really! // unregistering a NULL ppstep is no problem for us ... really!
return AI_SUCCESS; return AI_SUCCESS;
@ -288,24 +287,22 @@ aiReturn Importer::UnregisterPPStep(BaseProcess* pImp)
} }
ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you .."); ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you ..");
ASSIMP_END_EXCEPTION_REGION(aiReturn); ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_FAILURE; return AI_FAILURE;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Supplies a custom IO handler to the importer to open and access files. // Supplies a custom IO handler to the importer to open and access files.
void Importer::SetIOHandler( IOSystem* pIOHandler) void Importer::SetIOHandler( IOSystem* pIOHandler) {
{ ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
// If the new handler is zero, allocate a default IO implementation. // If the new handler is zero, allocate a default IO implementation.
if (!pIOHandler) if (!pIOHandler) {
{
// Release pointer in the possession of the caller // Release pointer in the possession of the caller
pimpl->mIOHandler = new DefaultIOSystem(); pimpl->mIOHandler = new DefaultIOSystem();
pimpl->mIsDefaultHandler = true; pimpl->mIsDefaultHandler = true;
} } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
// Otherwise register the custom handler
else if (pimpl->mIOHandler != pIOHandler)
{
delete pimpl->mIOHandler; delete pimpl->mIOHandler;
pimpl->mIOHandler = pIOHandler; pimpl->mIOHandler = pIOHandler;
pimpl->mIsDefaultHandler = false; pimpl->mIsDefaultHandler = false;
@ -316,29 +313,32 @@ void Importer::SetIOHandler( IOSystem* pIOHandler)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get the currently set IO handler // Get the currently set IO handler
IOSystem* Importer::GetIOHandler() const { IOSystem* Importer::GetIOHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIOHandler; return pimpl->mIOHandler;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Check whether a custom IO handler is currently set // Check whether a custom IO handler is currently set
bool Importer::IsDefaultIOHandler() const { bool Importer::IsDefaultIOHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIsDefaultHandler; return pimpl->mIsDefaultHandler;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Supplies a custom progress handler to get regular callbacks during importing // Supplies a custom progress handler to get regular callbacks during importing
void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
// If the new handler is zero, allocate a default implementation. // If the new handler is zero, allocate a default implementation.
if (!pHandler) if (!pHandler) {
{
// Release pointer in the possession of the caller // Release pointer in the possession of the caller
pimpl->mProgressHandler = new DefaultProgressHandler(); pimpl->mProgressHandler = new DefaultProgressHandler();
pimpl->mIsDefaultProgressHandler = true; pimpl->mIsDefaultProgressHandler = true;
} } else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler
// Otherwise register the custom handler
else if (pimpl->mProgressHandler != pHandler)
{
delete pimpl->mProgressHandler; delete pimpl->mProgressHandler;
pimpl->mProgressHandler = pHandler; pimpl->mProgressHandler = pHandler;
pimpl->mIsDefaultProgressHandler = false; pimpl->mIsDefaultProgressHandler = false;
@ -349,19 +349,22 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get the currently set progress handler // Get the currently set progress handler
ProgressHandler* Importer::GetProgressHandler() const { ProgressHandler* Importer::GetProgressHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mProgressHandler; return pimpl->mProgressHandler;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Check whether a custom progress handler is currently set // Check whether a custom progress handler is currently set
bool Importer::IsDefaultProgressHandler() const { bool Importer::IsDefaultProgressHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIsDefaultProgressHandler; return pimpl->mIsDefaultProgressHandler;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Validate post process step flags // Validate post process step flags
bool _ValidateFlags(unsigned int pFlags) bool _ValidateFlags(unsigned int pFlags) {
{
if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) {
ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
return false; return false;
@ -375,12 +378,13 @@ bool _ValidateFlags(unsigned int pFlags)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Free the current scene // Free the current scene
void Importer::FreeScene( ) void Importer::FreeScene( ) {
{ ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
delete pimpl->mScene; delete pimpl->mScene;
pimpl->mScene = NULL; pimpl->mScene = nullptr;
pimpl->mErrorString = ""; pimpl->mErrorString = "";
ASSIMP_END_EXCEPTION_REGION(void); ASSIMP_END_EXCEPTION_REGION(void);
@ -388,44 +392,48 @@ void Importer::FreeScene( )
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get the current error string, if any // Get the current error string, if any
const char* Importer::GetErrorString() const const char* Importer::GetErrorString() const {
{ ai_assert(nullptr != pimpl);
/* Must remain valid as long as ReadFile() or FreeFile() are not called */
// Must remain valid as long as ReadFile() or FreeFile() are not called
return pimpl->mErrorString.c_str(); return pimpl->mErrorString.c_str();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Enable extra-verbose mode // Enable extra-verbose mode
void Importer::SetExtraVerbose(bool bDo) void Importer::SetExtraVerbose(bool bDo) {
{ ai_assert(nullptr != pimpl);
pimpl->bExtraVerbose = bDo; pimpl->bExtraVerbose = bDo;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get the current scene // Get the current scene
const aiScene* Importer::GetScene() const const aiScene* Importer::GetScene() const {
{ ai_assert(nullptr != pimpl);
return pimpl->mScene; return pimpl->mScene;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Orphan the current scene and return it. // Orphan the current scene and return it.
aiScene* Importer::GetOrphanedScene() aiScene* Importer::GetOrphanedScene() {
{ ai_assert(nullptr != pimpl);
aiScene* s = pimpl->mScene; aiScene* s = pimpl->mScene;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
pimpl->mScene = NULL; pimpl->mScene = nullptr;
pimpl->mErrorString = ""; /* reset error string */ pimpl->mErrorString = ""; // reset error string
ASSIMP_END_EXCEPTION_REGION(aiScene*); ASSIMP_END_EXCEPTION_REGION(aiScene*);
return s; return s;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Validate post-processing flags // Validate post-processing flags
bool Importer::ValidateFlags(unsigned int pFlags) const bool Importer::ValidateFlags(unsigned int pFlags) const {
{
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
// run basic checks for mutually exclusive flags // run basic checks for mutually exclusive flags
if(!_ValidateFlags(pFlags)) { if(!_ValidateFlags(pFlags)) {
@ -467,8 +475,9 @@ bool Importer::ValidateFlags(unsigned int pFlags) const
const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
size_t pLength, size_t pLength,
unsigned int pFlags, unsigned int pFlags,
const char* pHint /*= ""*/) const char* pHint /*= ""*/) {
{ ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
if (!pHint) { if (!pHint) {
pHint = ""; pHint = "";
@ -476,12 +485,12 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) { if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
return NULL; return nullptr;
} }
// prevent deletion of the previous IOHandler // prevent deletion of the previous IOHandler
IOSystem* io = pimpl->mIOHandler; IOSystem* io = pimpl->mIOHandler;
pimpl->mIOHandler = NULL; pimpl->mIOHandler = nullptr;
SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io)); SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
@ -498,8 +507,8 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void WriteLogOpening(const std::string& file) void WriteLogOpening(const std::string& file) {
{
ASSIMP_LOG_INFO_F("Load ", file); ASSIMP_LOG_INFO_F("Load ", file);
// print a full version dump. This is nice because we don't // print a full version dump. This is nice because we don't
@ -550,8 +559,9 @@ void WriteLogOpening(const std::string& file)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads the given file and returns its contents if successful. // Reads the given file and returns its contents if successful.
const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
{ ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
const std::string pFile(_pFile); const std::string pFile(_pFile);
@ -580,7 +590,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
ASSIMP_LOG_ERROR(pimpl->mErrorString); ASSIMP_LOG_ERROR(pimpl->mErrorString);
return NULL; return nullptr;
} }
std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
@ -589,7 +599,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
} }
// Find an worker class which can handle the file // Find an worker class which can handle the file
BaseImporter* imp = NULL; BaseImporter* imp = nullptr;
SetPropertyInteger("importerIndex", -1); SetPropertyInteger("importerIndex", -1);
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
@ -617,7 +627,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
if( !imp) { if( !imp) {
pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
ASSIMP_LOG_ERROR(pimpl->mErrorString); ASSIMP_LOG_ERROR(pimpl->mErrorString);
return NULL; return nullptr;
} }
} }
@ -633,7 +643,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
// Dispatch the reading to the worker class for this format // Dispatch the reading to the worker class for this format
const aiImporterDesc *desc( imp->GetInfo() ); const aiImporterDesc *desc( imp->GetInfo() );
std::string ext( "unknown" ); std::string ext( "unknown" );
if ( NULL != desc ) { if ( nullptr != desc ) {
ext = desc->mName; ext = desc->mName;
} }
ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." ); ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." );
@ -654,15 +664,20 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
// If successful, apply all active post processing steps to the imported data // If successful, apply all active post processing steps to the imported data
if( pimpl->mScene) { if( pimpl->mScene) {
if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
if (!pimpl->mScene->mMetaData) {
pimpl->mScene->mMetaData = new aiMetadata;
}
pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
}
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
// The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called. // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
if (pFlags & aiProcess_ValidateDataStructure) if (pFlags & aiProcess_ValidateDataStructure) {
{
ValidateDSProcess ds; ValidateDSProcess ds;
ds.ExecuteOnScene (this); ds.ExecuteOnScene (this);
if (!pimpl->mScene) { if (!pimpl->mScene) {
return NULL; return nullptr;
} }
} }
#endif // no validation #endif // no validation
@ -695,8 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
} }
} }
#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
catch (std::exception &e) catch (std::exception &e) {
{
#if (defined _MSC_VER) && (defined _CPPRTTI) #if (defined _MSC_VER) && (defined _CPPRTTI)
// if we have RTTI get the full name of the exception that occurred // if we have RTTI get the full name of the exception that occurred
pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what(); pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
@ -705,24 +719,26 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
#endif #endif
ASSIMP_LOG_ERROR(pimpl->mErrorString); ASSIMP_LOG_ERROR(pimpl->mErrorString);
delete pimpl->mScene; pimpl->mScene = NULL; delete pimpl->mScene; pimpl->mScene = nullptr;
} }
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
// either successful or failure - the pointer expresses it anyways // either successful or failure - the pointer expresses it anyways
ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
return pimpl->mScene; return pimpl->mScene;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Apply post-processing to the currently bound scene // Apply post-processing to the currently bound scene
const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
{ ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
// Return immediately if no scene is active // Return immediately if no scene is active
if (!pimpl->mScene) { if (!pimpl->mScene) {
return NULL; return nullptr;
} }
// If no flags are given, return the current scene with no further action // If no flags are given, return the current scene with no further action
@ -737,12 +753,11 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
// The ValidateDS process plays an exceptional role. It isn't contained in the global // The ValidateDS process plays an exceptional role. It isn't contained in the global
// list of post-processing steps, so we need to call it manually. // list of post-processing steps, so we need to call it manually.
if (pFlags & aiProcess_ValidateDataStructure) if (pFlags & aiProcess_ValidateDataStructure) {
{
ValidateDSProcess ds; ValidateDSProcess ds;
ds.ExecuteOnScene (this); ds.ExecuteOnScene (this);
if (!pimpl->mScene) { if (!pimpl->mScene) {
return NULL; return nullptr;
} }
} }
#endif // no validation #endif // no validation
@ -762,11 +777,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
BaseProcess* process = pimpl->mPostProcessingSteps[a]; BaseProcess* process = pimpl->mPostProcessingSteps[a];
pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) ); pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
if( process->IsActive( pFlags)) { if( process->IsActive( pFlags)) {
if (profiler) { if (profiler) {
profiler->BeginRegion("postprocess"); profiler->BeginRegion("postprocess");
} }
@ -803,24 +816,28 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
static_cast<int>(pimpl->mPostProcessingSteps.size()) ); static_cast<int>(pimpl->mPostProcessingSteps.size()) );
// update private scene flags // update private scene flags
if( pimpl->mScene ) if( pimpl->mScene ) {
ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
}
// clear any data allocated by post-process steps // clear any data allocated by post-process steps
pimpl->mPPShared->Clean(); pimpl->mPPShared->Clean();
ASSIMP_LOG_INFO("Leaving post processing pipeline"); ASSIMP_LOG_INFO("Leaving post processing pipeline");
ASSIMP_END_EXCEPTION_REGION(const aiScene*); ASSIMP_END_EXCEPTION_REGION(const aiScene*);
return pimpl->mScene; return pimpl->mScene;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) { const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
// Return immediately if no scene is active // Return immediately if no scene is active
if ( NULL == pimpl->mScene ) { if ( nullptr == pimpl->mScene ) {
return NULL; return nullptr;
} }
// If no flags are given, return the current scene with no further action // If no flags are given, return the current scene with no further action
@ -839,7 +856,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
ValidateDSProcess ds; ValidateDSProcess ds;
ds.ExecuteOnScene( this ); ds.ExecuteOnScene( this );
if ( !pimpl->mScene ) { if ( !pimpl->mScene ) {
return NULL; return nullptr;
} }
} }
#endif // no validation #endif // no validation
@ -890,46 +907,50 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Helper function to check whether an extension is supported by ASSIMP // Helper function to check whether an extension is supported by ASSIMP
bool Importer::IsExtensionSupported(const char* szExtension) const bool Importer::IsExtensionSupported(const char* szExtension) const {
{
return nullptr != GetImporter(szExtension); return nullptr != GetImporter(szExtension);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
size_t Importer::GetImporterCount() const size_t Importer::GetImporterCount() const {
{ ai_assert(nullptr != pimpl);
return pimpl->mImporter.size(); return pimpl->mImporter.size();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiImporterDesc* Importer::GetImporterInfo(size_t index) const const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
{ ai_assert(nullptr != pimpl);
if (index >= pimpl->mImporter.size()) { if (index >= pimpl->mImporter.size()) {
return NULL; return nullptr;
} }
return pimpl->mImporter[index]->GetInfo(); return pimpl->mImporter[index]->GetInfo();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
BaseImporter* Importer::GetImporter (size_t index) const BaseImporter* Importer::GetImporter (size_t index) const {
{ ai_assert(nullptr != pimpl);
if (index >= pimpl->mImporter.size()) { if (index >= pimpl->mImporter.size()) {
return NULL; return nullptr;
} }
return pimpl->mImporter[index]; return pimpl->mImporter[index];
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Find a loader plugin for a given file extension // Find a loader plugin for a given file extension
BaseImporter* Importer::GetImporter (const char* szExtension) const BaseImporter* Importer::GetImporter (const char* szExtension) const {
{ ai_assert(nullptr != pimpl);
return GetImporter(GetImporterIndex(szExtension)); return GetImporter(GetImporterIndex(szExtension));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Find a loader plugin for a given file extension // Find a loader plugin for a given file extension
size_t Importer::GetImporterIndex (const char* szExtension) const { size_t Importer::GetImporterIndex (const char* szExtension) const {
ai_assert(nullptr != pimpl);
ai_assert(nullptr != szExtension); ai_assert(nullptr != szExtension);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
@ -960,8 +981,9 @@ size_t Importer::GetImporterIndex (const char* szExtension) const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Helper function to build a list of all file extensions supported by ASSIMP // Helper function to build a list of all file extensions supported by ASSIMP
void Importer::GetExtensionList(aiString& szOut) const void Importer::GetExtensionList(aiString& szOut) const {
{ ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
std::set<std::string> str; std::set<std::string> str;
for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) {
@ -985,8 +1007,9 @@ void Importer::GetExtensionList(aiString& szOut) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Set a configuration property // Set a configuration property
bool Importer::SetPropertyInteger(const char* szName, int iValue) bool Importer::SetPropertyInteger(const char* szName, int iValue) {
{ ai_assert(nullptr != pimpl);
bool existing; bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue); existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
@ -996,8 +1019,9 @@ bool Importer::SetPropertyInteger(const char* szName, int iValue)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Set a configuration property // Set a configuration property
bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
{ ai_assert(nullptr != pimpl);
bool existing; bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue); existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
@ -1007,8 +1031,9 @@ bool Importer::SetPropertyFloat(const char* szName, ai_real iValue)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Set a configuration property // Set a configuration property
bool Importer::SetPropertyString(const char* szName, const std::string& value) bool Importer::SetPropertyString(const char* szName, const std::string& value) {
{ ai_assert(nullptr != pimpl);
bool existing; bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value); existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
@ -1018,8 +1043,9 @@ bool Importer::SetPropertyString(const char* szName, const std::string& value)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Set a configuration property // Set a configuration property
bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
{ ai_assert(nullptr != pimpl);
bool existing; bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value); existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
@ -1029,40 +1055,43 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a configuration property // Get a configuration property
int Importer::GetPropertyInteger(const char* szName, int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
int iErrorReturn /*= 0xffffffff*/) const ai_assert(nullptr != pimpl);
{
return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn); return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a configuration property // Get a configuration property
ai_real Importer::GetPropertyFloat(const char* szName, ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
ai_real iErrorReturn /*= 10e10*/) const ai_assert(nullptr != pimpl);
{
return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn); return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a configuration property // Get a configuration property
const std::string Importer::GetPropertyString(const char* szName, const std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
const std::string& iErrorReturn /*= ""*/) const ai_assert(nullptr != pimpl);
{
return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn); return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a configuration property // Get a configuration property
const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const ai_assert(nullptr != pimpl);
{
return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn); return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get the memory requirements of a single node // Get the memory requirements of a single node
inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) inline
{ void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) {
if ( nullptr == pcNode ) {
return;
}
iScene += sizeof(aiNode); iScene += sizeof(aiNode);
iScene += sizeof(unsigned int) * pcNode->mNumMeshes; iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
iScene += sizeof(void*) * pcNode->mNumChildren; iScene += sizeof(void*) * pcNode->mNumChildren;
@ -1074,8 +1103,9 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get the memory requirements of the scene // Get the memory requirements of the scene
void Importer::GetMemoryRequirements(aiMemoryInfo& in) const void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
{ ai_assert(nullptr != pimpl);
in = aiMemoryInfo(); in = aiMemoryInfo();
aiScene* mScene = pimpl->mScene; aiScene* mScene = pimpl->mScene;
@ -1087,8 +1117,7 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
in.total = sizeof(aiScene); in.total = sizeof(aiScene);
// add all meshes // add all meshes
for (unsigned int i = 0; i < mScene->mNumMeshes;++i) for (unsigned int i = 0; i < mScene->mNumMeshes;++i) {
{
in.meshes += sizeof(aiMesh); in.meshes += sizeof(aiMesh);
if (mScene->mMeshes[i]->HasPositions()) { if (mScene->mMeshes[i]->HasPositions()) {
in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
@ -1105,14 +1134,16 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) { for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
if (mScene->mMeshes[i]->HasVertexColors(a)) { if (mScene->mMeshes[i]->HasVertexColors(a)) {
in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices; in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
} else {
break;
} }
else break;
} }
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
if (mScene->mMeshes[i]->HasTextureCoords(a)) { if (mScene->mMeshes[i]->HasTextureCoords(a)) {
in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
} else {
break;
} }
else break;
} }
if (mScene->mMeshes[i]->HasBones()) { if (mScene->mMeshes[i]->HasBones()) {
in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones; in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
@ -1131,8 +1162,9 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
in.textures += sizeof(aiTexture); in.textures += sizeof(aiTexture);
if (pc->mHeight) { if (pc->mHeight) {
in.textures += 4 * pc->mHeight * pc->mWidth; in.textures += 4 * pc->mHeight * pc->mWidth;
} else {
in.textures += pc->mWidth;
} }
else in.textures += pc->mWidth;
} }
in.total += in.textures; in.total += in.textures;

View File

@ -60,6 +60,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/CreateAnimMesh.h> #include <assimp/CreateAnimMesh.h>
#include <assimp/commonMetaData.h>
#include <assimp/StringUtils.h>
#include <tuple> #include <tuple>
#include <memory> #include <memory>
@ -1597,12 +1599,11 @@ namespace Assimp {
aiBone *bone = nullptr; aiBone *bone = nullptr;
if (bone_map.count(deformer_name)) { if (bone_map.count(deformer_name)) {
std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name);
<< std::endl; bone = bone_map[deformer_name];
bone = bone_map[deformer_name]; } else {
} else { ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl; bone = new aiBone();
bone = new aiBone();
bone->mName = bone_name; bone->mName = bone_name;
// store local transform link for post processing // store local transform link for post processing
@ -1648,7 +1649,7 @@ namespace Assimp {
bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone)); bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone));
} }
std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl; ASSIMP_LOG_DEBUG_F("bone research: Indicies size: ", out_indices.size());
// lookup must be populated in case something goes wrong // lookup must be populated in case something goes wrong
// this also allocates bones to mesh instance outside // this also allocates bones to mesh instance outside
@ -2088,6 +2089,13 @@ namespace Assimp {
TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh);
// 3DSMax PBR
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh);
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh);
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh);
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh);
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
} }
void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh)
@ -3604,7 +3612,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
return; return;
} }
out->mMetaData = aiMetadata::Alloc(15); const bool hasGenerator = !doc.Creator().empty();
out->mMetaData = aiMetadata::Alloc(16 + (hasGenerator ? 1 : 0));
out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis()); out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis());
out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign()); out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign());
out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis()); out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis());
@ -3620,6 +3630,11 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart()); out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart());
out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop()); out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop());
out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate());
out->mMetaData->Set(15, AI_METADATA_SOURCE_FORMAT_VERSION, aiString(to_string(doc.FBXVersion())));
if (hasGenerator)
{
out->mMetaData->Set(16, AI_METADATA_SOURCE_GENERATOR, aiString(doc.Creator()));
}
} }
void FBXConverter::TransferDataToScene() void FBXConverter::TransferDataToScene()

View File

@ -421,6 +421,8 @@ private:
double& minTime, double& minTime,
Model::RotOrder order); Model::RotOrder order);
// ------------------------------------------------------------------------------------------------
// Copy global geometric data and some information about the source asset into scene metadata.
void ConvertGlobalSettings(); void ConvertGlobalSettings();
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -138,8 +138,9 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m
} }
} }
} }
if (outer_polygon_it == end) {
ai_assert(outer_polygon_it != end); return;
}
const size_t outer_polygon_size = *outer_polygon_it; const size_t outer_polygon_size = *outer_polygon_it;
const IfcVector3& master_normal = normals[std::distance(begin, outer_polygon_it)]; const IfcVector3& master_normal = normals[std::distance(begin, outer_polygon_it)];

View File

@ -586,7 +586,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
root->mName.Set("<LWORoot>"); root->mName.Set("<LWORoot>");
//Set parent of all children, inserting pivots //Set parent of all children, inserting pivots
//std::cout << "Set parent of all children" << std::endl;
std::map<uint16_t, aiNode*> mapPivot; std::map<uint16_t, aiNode*> mapPivot;
for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
@ -618,7 +617,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
} }
//Merge pivot map into node map //Merge pivot map into node map
//std::cout << "Merge pivot map into node map" << std::endl;
for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
apcNodes[itMapPivot->first] = itMapPivot->second; apcNodes[itMapPivot->first] = itMapPivot->second;
} }

View File

@ -55,17 +55,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include <vector> #include <vector>
#include <assimp/version.h> // aiGetVersion
#include <assimp/IOSystem.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError #include <assimp/Exceptional.h> // DeadlyExportError
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/material.h> // aiTextureType #include <assimp/material.h> // aiTextureType
#include <assimp/scene.h>
#include <assimp/mesh.h> #include <assimp/mesh.h>
#include <assimp/scene.h>
#include <assimp/version.h> // aiGetVersion
#include <assimp/DefaultLogger.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/IOSystem.hpp>
#include "M3DExporter.h" #include "M3DExporter.h"
#include "M3DMaterials.h" #include "M3DMaterials.h"
#include "M3DWrapper.h"
// RESOURCES: // RESOURCES:
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md // https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
@ -80,341 +82,331 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation * - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation
* triplets, instead of per bone timestamp + lists) * triplets, instead of per bone timestamp + lists)
*/ */
using namespace Assimp;
namespace Assimp {
// ---------------------------------------------------------------------
// Worker function for exporting a scene to binary M3D.
// Prototyped and registered in Exporter.cpp
void ExportSceneM3D (
const char* pFile,
IOSystem* pIOSystem,
const aiScene* pScene,
const ExportProperties* pProperties
){
// initialize the exporter
M3DExporter exporter(pScene, pProperties);
// perform binary export
exporter.doExport(pFile, pIOSystem, false);
}
// ---------------------------------------------------------------------
// Worker function for exporting a scene to ASCII A3D.
// Prototyped and registered in Exporter.cpp
void ExportSceneA3D (
const char* pFile,
IOSystem* pIOSystem,
const aiScene* pScene,
const ExportProperties* pProperties
){
// initialize the exporter
M3DExporter exporter(pScene, pProperties);
// perform ascii export
exporter.doExport(pFile, pIOSystem, true);
}
} // end of namespace Assimp
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
M3DExporter::M3DExporter ( const aiScene* pScene, const ExportProperties* pProperties ) // Conversion functions
: mScene(pScene)
, mProperties(pProperties)
, outfile()
, m3d(nullptr) { }
// ------------------------------------------------------------------------------------------------
void M3DExporter::doExport (
const char* pFile,
IOSystem* pIOSystem,
bool toAscii
){
// TODO: convert mProperties into M3D_EXP_* flags
(void)mProperties;
// open the indicated file for writing (in binary / ASCII mode)
outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb"));
if (!outfile) {
throw DeadlyExportError( "could not open output .m3d file: " + std::string(pFile) );
}
// use malloc() here because m3d_free() will call free()
m3d = (m3d_t*)calloc(1, sizeof(m3d_t));
if(!m3d) {
throw DeadlyExportError( "memory allocation error" );
}
m3d->name = _m3d_safestr((char*)&mScene->mRootNode->mName.data, 2);
// Create a model from assimp structures
aiMatrix4x4 m;
NodeWalk(mScene->mRootNode, m);
// serialize the structures
unsigned int size;
unsigned char *output = m3d_save(m3d, M3D_EXP_FLOAT,
M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), &size);
m3d_free(m3d);
if(!output || size < 8) {
throw DeadlyExportError( "unable to serialize into Model 3D" );
}
// Write out serialized model
outfile->Write(output, size, 1);
// explicitly release file pointer,
// so we don't have to rely on class destruction.
outfile.reset();
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// helper to add a vertex (private to NodeWalk) // helper to add a vertex (private to NodeWalk)
m3dv_t *M3DExporter::AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) {
{ if (v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0;
if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0; if (v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0;
if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0; if (v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0;
if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0; if (v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0; vrtx = (m3dv_t *)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t)); memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t)); *idx = *numvrtx;
*idx = *numvrtx; (*numvrtx)++;
(*numvrtx)++; return vrtx;
return vrtx;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// helper to add a tmap (private to NodeWalk) // helper to add a tmap (private to NodeWalk)
m3dti_t *M3DExporter::AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx) m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx) {
{ tmap = (m3dti_t *)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t)); memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t)); *idx = *numtmap;
*idx = *numtmap; (*numtmap)++;
(*numtmap)++; return tmap;
return tmap;
}
// ------------------------------------------------------------------------------------------------
// recursive node walker
void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
{
aiMatrix4x4 nm = m * pNode->mTransformation;
for(unsigned int i = 0; i < pNode->mNumMeshes; i++) {
const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]];
unsigned int mi = (M3D_INDEX)-1U;
if(mScene->mMaterials) {
// get the material for this mesh
mi = addMaterial(mScene->mMaterials[mesh->mMaterialIndex]);
}
// iterate through the mesh faces
for(unsigned int j = 0; j < mesh->mNumFaces; j++) {
unsigned int n;
const aiFace* face = &(mesh->mFaces[j]);
// only triangle meshes supported for now
if(face->mNumIndices != 3) {
throw DeadlyExportError( "use aiProcess_Triangulate before export" );
}
// add triangle to the output
n = m3d->numface++;
m3d->face = (m3df_t*)M3D_REALLOC(m3d->face,
m3d->numface * sizeof(m3df_t));
if(!m3d->face) {
throw DeadlyExportError( "memory allocation error" );
}
/* set all index to -1 by default */
m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] =
m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] =
m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = -1U;
m3d->face[n].materialid = mi;
for(unsigned int k = 0; k < face->mNumIndices; k++) {
// get the vertex's index
unsigned int l = face->mIndices[k];
unsigned int idx;
m3dv_t vertex;
m3dti_t ti;
// multiply the position vector by the transformation matrix
aiVector3D v = mesh->mVertices[l];
v *= nm;
vertex.x = v.x;
vertex.y = v.y;
vertex.z = v.z;
vertex.w = 1.0;
vertex.color = 0;
vertex.skinid = -1U;
// add color if defined
if(mesh->HasVertexColors(0))
vertex.color = mkColor(&mesh->mColors[0][l]);
// save the vertex to the output
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex,
&vertex, &idx);
m3d->face[n].vertex[k] = (M3D_INDEX)idx;
// do we have texture coordinates?
if(mesh->HasTextureCoords(0)) {
ti.u = mesh->mTextureCoords[0][l].x;
ti.v = mesh->mTextureCoords[0][l].y;
m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx);
m3d->face[n].texcoord[k] = (M3D_INDEX)idx;
}
// do we have normal vectors?
if(mesh->HasNormals()) {
vertex.x = mesh->mNormals[l].x;
vertex.y = mesh->mNormals[l].y;
vertex.z = mesh->mNormals[l].z;
vertex.color = 0;
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx);
m3d->face[n].normal[k] = (M3D_INDEX)idx;
}
}
}
}
// repeat for the children nodes
for (unsigned int i = 0; i < pNode->mNumChildren; i++) {
NodeWalk(pNode->mChildren[i], nm);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// convert aiColor4D into uint32_t // convert aiColor4D into uint32_t
uint32_t M3DExporter::mkColor(aiColor4D* c) uint32_t mkColor(aiColor4D *c) {
{ return ((uint8_t)(c->a * 255) << 24L) |
return ((uint8_t)(c->a*255) << 24L) | ((uint8_t)(c->b * 255) << 16L) |
((uint8_t)(c->b*255) << 16L) | ((uint8_t)(c->g * 255) << 8L) |
((uint8_t)(c->g*255) << 8L) | ((uint8_t)(c->r * 255) << 0L);
((uint8_t)(c->r*255) << 0L);
}
// ------------------------------------------------------------------------------------------------
// add a material to the output
M3D_INDEX M3DExporter::addMaterial(const aiMaterial *mat)
{
unsigned int mi = -1U;
aiColor4D c;
aiString name;
ai_real f;
char *fn;
if(mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length &&
strcmp((char*)&name.data, AI_DEFAULT_MATERIAL_NAME)) {
// check if we have saved a material by this name. This has to be done
// because only the referenced materials should be added to the output
for(unsigned int i = 0; i < m3d->nummaterial; i++)
if(!strcmp((char*)&name.data, m3d->material[i].name)) {
mi = i;
break;
}
// if not found, add the material to the output
if(mi == -1U) {
unsigned int k;
mi = m3d->nummaterial++;
m3d->material = (m3dm_t*)M3D_REALLOC(m3d->material, m3d->nummaterial
* sizeof(m3dm_t));
if(!m3d->material) {
throw DeadlyExportError( "memory allocation error" );
}
m3d->material[mi].name = _m3d_safestr((char*)&name.data, 0);
m3d->material[mi].numprop = 0;
m3d->material[mi].prop = NULL;
// iterate through the material property table and see what we got
for(k = 0; k < 15; k++) {
unsigned int j;
if(m3d_propertytypes[k].format == m3dpf_map)
continue;
if(aiProps[k].pKey) {
switch(m3d_propertytypes[k].format) {
case m3dpf_color:
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, c) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, mkColor(&c));
break;
case m3dpf_float:
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, f) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id,
/* not (uint32_t)f, because we don't want to convert
* it, we want to see it as 32 bits of memory */
*((uint32_t*)&f));
break;
case m3dpf_uint8:
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, j) == AI_SUCCESS) {
// special conversion for illumination model property
if(m3d_propertytypes[k].id == m3dp_il) {
switch(j) {
case aiShadingMode_NoShading: j = 0; break;
case aiShadingMode_Phong: j = 2; break;
default: j = 1; break;
}
}
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, j);
}
break;
default:
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, j) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, j);
break;
}
}
if(aiTxProps[k].pKey &&
mat->GetTexture((aiTextureType)aiTxProps[k].type,
aiTxProps[k].index, &name, NULL, NULL, NULL,
NULL, NULL) == AI_SUCCESS) {
unsigned int i;
for(j = name.length-1; j > 0 && name.data[j]!='.'; j++);
if(j && name.data[j]=='.' &&
(name.data[j+1]=='p' || name.data[j+1]=='P') &&
(name.data[j+1]=='n' || name.data[j+1]=='N') &&
(name.data[j+1]=='g' || name.data[j+1]=='G'))
name.data[j]=0;
// do we have this texture saved already?
fn = _m3d_safestr((char*)&name.data, 0);
for(j = 0, i = -1U; j < m3d->numtexture; j++)
if(!strcmp(fn, m3d->texture[j].name)) {
i = j;
free(fn);
break;
}
if(i == -1U) {
i = m3d->numtexture++;
m3d->texture = (m3dtx_t*)M3D_REALLOC(
m3d->texture,
m3d->numtexture * sizeof(m3dtx_t));
if(!m3d->texture) {
throw DeadlyExportError( "memory allocation error" );
}
// we don't need the texture itself, only its name
m3d->texture[i].name = fn;
m3d->texture[i].w = 0;
m3d->texture[i].h = 0;
m3d->texture[i].d = NULL;
}
addProp(&m3d->material[mi],
m3d_propertytypes[k].id + 128, i);
}
}
}
}
return mi;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// add a material property to the output // add a material property to the output
void M3DExporter::addProp(m3dm_t *m, uint8_t type, uint32_t value) void addProp(m3dm_t *m, uint8_t type, uint32_t value) {
{ unsigned int i;
unsigned int i; i = m->numprop++;
i = m->numprop++; m->prop = (m3dp_t *)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t));
m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); if (!m->prop) {
if(!m->prop) { throw DeadlyExportError( "memory allocation error" ); } throw DeadlyExportError("memory allocation error");
m->prop[i].type = type; }
m->prop[i].value.num = value; m->prop[i].type = type;
m->prop[i].value.num = value;
} }
// ------------------------------------------------------------------------------------------------
// add a material to the output
M3D_INDEX addMaterial(const Assimp::M3DWrapper &m3d, const aiMaterial *mat) {
unsigned int mi = -1U;
aiColor4D c;
aiString name;
ai_real f;
char *fn;
if (mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length &&
strcmp((char *)&name.data, AI_DEFAULT_MATERIAL_NAME)) {
// check if we have saved a material by this name. This has to be done
// because only the referenced materials should be added to the output
for (unsigned int i = 0; i < m3d->nummaterial; i++)
if (!strcmp((char *)&name.data, m3d->material[i].name)) {
mi = i;
break;
}
// if not found, add the material to the output
if (mi == -1U) {
unsigned int k;
mi = m3d->nummaterial++;
m3d->material = (m3dm_t *)M3D_REALLOC(m3d->material, m3d->nummaterial * sizeof(m3dm_t));
if (!m3d->material) {
throw DeadlyExportError("memory allocation error");
}
m3d->material[mi].name = _m3d_safestr((char *)&name.data, 0);
m3d->material[mi].numprop = 0;
m3d->material[mi].prop = NULL;
// iterate through the material property table and see what we got
for (k = 0; k < 15; k++) {
unsigned int j;
if (m3d_propertytypes[k].format == m3dpf_map)
continue;
if (aiProps[k].pKey) {
switch (m3d_propertytypes[k].format) {
case m3dpf_color:
if (mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, c) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, mkColor(&c));
break;
case m3dpf_float:
if (mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, f) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id,
/* not (uint32_t)f, because we don't want to convert
* it, we want to see it as 32 bits of memory */
*((uint32_t *)&f));
break;
case m3dpf_uint8:
if (mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, j) == AI_SUCCESS) {
// special conversion for illumination model property
if (m3d_propertytypes[k].id == m3dp_il) {
switch (j) {
case aiShadingMode_NoShading: j = 0; break;
case aiShadingMode_Phong: j = 2; break;
default: j = 1; break;
}
}
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, j);
}
break;
default:
if (mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, j) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, j);
break;
}
}
if (aiTxProps[k].pKey &&
mat->GetTexture((aiTextureType)aiTxProps[k].type,
aiTxProps[k].index, &name, NULL, NULL, NULL,
NULL, NULL) == AI_SUCCESS) {
unsigned int i;
for (j = name.length - 1; j > 0 && name.data[j] != '.'; j++)
;
if (j && name.data[j] == '.' &&
(name.data[j + 1] == 'p' || name.data[j + 1] == 'P') &&
(name.data[j + 1] == 'n' || name.data[j + 1] == 'N') &&
(name.data[j + 1] == 'g' || name.data[j + 1] == 'G'))
name.data[j] = 0;
// do we have this texture saved already?
fn = _m3d_safestr((char *)&name.data, 0);
for (j = 0, i = -1U; j < m3d->numtexture; j++)
if (!strcmp(fn, m3d->texture[j].name)) {
i = j;
free(fn);
break;
}
if (i == -1U) {
i = m3d->numtexture++;
m3d->texture = (m3dtx_t *)M3D_REALLOC(
m3d->texture,
m3d->numtexture * sizeof(m3dtx_t));
if (!m3d->texture) {
throw DeadlyExportError("memory allocation error");
}
// we don't need the texture itself, only its name
m3d->texture[i].name = fn;
m3d->texture[i].w = 0;
m3d->texture[i].h = 0;
m3d->texture[i].d = NULL;
}
addProp(&m3d->material[mi],
m3d_propertytypes[k].id + 128, i);
}
}
}
}
return mi;
}
namespace Assimp {
// ---------------------------------------------------------------------
// Worker function for exporting a scene to binary M3D.
// Prototyped and registered in Exporter.cpp
void ExportSceneM3D(
const char *pFile,
IOSystem *pIOSystem,
const aiScene *pScene,
const ExportProperties *pProperties) {
// initialize the exporter
M3DExporter exporter(pScene, pProperties);
// perform binary export
exporter.doExport(pFile, pIOSystem, false);
}
// ---------------------------------------------------------------------
// Worker function for exporting a scene to ASCII A3D.
// Prototyped and registered in Exporter.cpp
void ExportSceneA3D(
const char *pFile,
IOSystem *pIOSystem,
const aiScene *pScene,
const ExportProperties *pProperties
) {
// initialize the exporter
M3DExporter exporter(pScene, pProperties);
// perform ascii export
exporter.doExport(pFile, pIOSystem, true);
}
// ------------------------------------------------------------------------------------------------
M3DExporter::M3DExporter(const aiScene *pScene, const ExportProperties *pProperties) :
mScene(pScene),
mProperties(pProperties),
outfile() {}
// ------------------------------------------------------------------------------------------------
void M3DExporter::doExport(
const char *pFile,
IOSystem *pIOSystem,
bool toAscii) {
// TODO: convert mProperties into M3D_EXP_* flags
(void)mProperties;
// open the indicated file for writing (in binary / ASCII mode)
outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb"));
if (!outfile) {
throw DeadlyExportError("could not open output .m3d file: " + std::string(pFile));
}
M3DWrapper m3d;
if (!m3d) {
throw DeadlyExportError("memory allocation error");
}
m3d->name = _m3d_safestr((char *)&mScene->mRootNode->mName.data, 2);
// Create a model from assimp structures
aiMatrix4x4 m;
NodeWalk(m3d, mScene->mRootNode, m);
// serialize the structures
unsigned int size;
unsigned char *output = m3d.Save(M3D_EXP_FLOAT, M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), size);
if (!output || size < 8) {
throw DeadlyExportError("unable to serialize into Model 3D");
}
// Write out serialized model
outfile->Write(output, size, 1);
// explicitly release file pointer,
// so we don't have to rely on class destruction.
outfile.reset();
}
// ------------------------------------------------------------------------------------------------
// recursive node walker
void M3DExporter::NodeWalk(const M3DWrapper &m3d, const aiNode *pNode, aiMatrix4x4 m) {
aiMatrix4x4 nm = m * pNode->mTransformation;
for (unsigned int i = 0; i < pNode->mNumMeshes; i++) {
const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]];
unsigned int mi = (M3D_INDEX)-1U;
if (mScene->mMaterials) {
// get the material for this mesh
mi = addMaterial(m3d, mScene->mMaterials[mesh->mMaterialIndex]);
}
// iterate through the mesh faces
for (unsigned int j = 0; j < mesh->mNumFaces; j++) {
unsigned int n;
const aiFace *face = &(mesh->mFaces[j]);
// only triangle meshes supported for now
if (face->mNumIndices != 3) {
throw DeadlyExportError("use aiProcess_Triangulate before export");
}
// add triangle to the output
n = m3d->numface++;
m3d->face = (m3df_t *)M3D_REALLOC(m3d->face,
m3d->numface * sizeof(m3df_t));
if (!m3d->face) {
throw DeadlyExportError("memory allocation error");
}
/* set all index to -1 by default */
m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] =
m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] =
m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = -1U;
m3d->face[n].materialid = mi;
for (unsigned int k = 0; k < face->mNumIndices; k++) {
// get the vertex's index
unsigned int l = face->mIndices[k];
unsigned int idx;
m3dv_t vertex;
m3dti_t ti;
// multiply the position vector by the transformation matrix
aiVector3D v = mesh->mVertices[l];
v *= nm;
vertex.x = v.x;
vertex.y = v.y;
vertex.z = v.z;
vertex.w = 1.0;
vertex.color = 0;
vertex.skinid = -1U;
// add color if defined
if (mesh->HasVertexColors(0))
vertex.color = mkColor(&mesh->mColors[0][l]);
// save the vertex to the output
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex,
&vertex, &idx);
m3d->face[n].vertex[k] = (M3D_INDEX)idx;
// do we have texture coordinates?
if (mesh->HasTextureCoords(0)) {
ti.u = mesh->mTextureCoords[0][l].x;
ti.v = mesh->mTextureCoords[0][l].y;
m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx);
m3d->face[n].texcoord[k] = (M3D_INDEX)idx;
}
// do we have normal vectors?
if (mesh->HasNormals()) {
vertex.x = mesh->mNormals[l].x;
vertex.y = mesh->mNormals[l].y;
vertex.z = mesh->mNormals[l].z;
vertex.color = 0;
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx);
m3d->face[n].normal[k] = (M3D_INDEX)idx;
}
}
}
}
// repeat for the children nodes
for (unsigned int i = 0; i < pNode->mNumChildren; i++) {
NodeWalk(m3d, pNode->mChildren[i], nm);
}
}
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER #endif // ASSIMP_BUILD_NO_M3D_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT #endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -48,8 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
#include "m3d.h"
#include <assimp/types.h> #include <assimp/types.h>
//#include <assimp/material.h> //#include <assimp/material.h>
#include <assimp/StreamWriter.h> // StreamWriterLE #include <assimp/StreamWriter.h> // StreamWriterLE
@ -68,6 +66,8 @@ namespace Assimp
class IOStream; class IOStream;
class ExportProperties; class ExportProperties;
class M3DWrapper;
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** Helper class to export a given scene to an M3D file. */ /** Helper class to export a given scene to an M3D file. */
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -83,15 +83,9 @@ namespace Assimp
const aiScene* mScene; // the scene to export const aiScene* mScene; // the scene to export
const ExportProperties* mProperties; // currently unused const ExportProperties* mProperties; // currently unused
std::shared_ptr<IOStream> outfile; // file to write to std::shared_ptr<IOStream> outfile; // file to write to
m3d_t *m3d; // model for the C library to convert to
// helper to do the recursive walking // helper to do the recursive walking
void NodeWalk(const aiNode* pNode, aiMatrix4x4 m); void NodeWalk(const M3DWrapper &m3d, const aiNode* pNode, aiMatrix4x4 m);
m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx);
m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx);
uint32_t mkColor(aiColor4D* c);
M3D_INDEX addMaterial(const aiMaterial *mat);
void addProp(m3dm_t *m, uint8_t type, uint32_t value);
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#include "m3d.h"
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
#include <assimp/material.h> #include <assimp/material.h>
#include <vector> #include <vector>
@ -60,43 +59,41 @@ struct aiFace;
namespace Assimp { namespace Assimp {
class M3DWrapper;
class M3DImporter : public BaseImporter { class M3DImporter : public BaseImporter {
public: public:
/// \brief Default constructor /// \brief Default constructor
M3DImporter(); M3DImporter();
/// \brief Destructor
~M3DImporter();
public: public:
/// \brief Returns whether the class can handle the format of the given file. /// \brief Returns whether the class can handle the format of the given file.
/// \remark See BaseImporter::CanRead() for details. /// \remark See BaseImporter::CanRead() for details.
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
private: private:
aiScene* mScene; // the scene to import to aiScene *mScene = nullptr; // the scene to import to
m3d_t *m3d; // model for the C library to convert from
//! \brief Appends the supported extension. //! \brief Appends the supported extension.
const aiImporterDesc* GetInfo () const; const aiImporterDesc *GetInfo() const;
//! \brief File import implementation. //! \brief File import implementation.
void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
void importMaterials(); void importMaterials(const M3DWrapper &m3d);
void importTextures(); void importTextures(const M3DWrapper &m3d);
void importMeshes(); void importMeshes(const M3DWrapper &m3d);
void importBones(unsigned int parentid, aiNode *pParent); void importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent);
void importAnimations(); void importAnimations(const M3DWrapper &m3d);
// helper functions // helper functions
aiColor4D mkColor(uint32_t c); aiColor4D mkColor(uint32_t c);
void convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid); void convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid);
aiNode *findNode(aiNode *pNode, aiString name); aiNode *findNode(aiNode *pNode, aiString name);
void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m); void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m);
void populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces, void populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces,
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors, std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
std::vector<unsigned int> *vertexids); std::vector<unsigned int> *vertexids);
}; };
} // Namespace Assimp } // Namespace Assimp

View File

@ -0,0 +1,142 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
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.
----------------------------------------------------------------------
*/
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
#include "M3DWrapper.h"
#include <assimp/DefaultIOSystem.h>
#include <assimp/IOStreamBuffer.h>
#include <assimp/ai_assert.h>
#ifndef AI_M3D_USE_STDMUTEX
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900) // C++11 and MSVC 2015 onwards
#define AI_M3D_USE_STDMUTEX 1
#else
#define AI_M3D_USE_STDMUTEX 0
#endif
#endif
#if AI_M3D_USE_STDMUTEX
#include <mutex>
std::mutex file_mutex;
#endif
// workaround: the M3D SDK expects a C callback, but we want to use Assimp::IOSystem to implement that
// This makes it non-rentrant so lock a mutex (requires C++11)
extern "C" {
void *m3dimporter_pIOHandler;
unsigned char *m3dimporter_readfile(char *fn, unsigned int *size) {
ai_assert(nullptr != fn);
ai_assert(nullptr != size);
std::string file(fn);
std::unique_ptr<Assimp::IOStream> pStream(
(reinterpret_cast<Assimp::IOSystem *>(m3dimporter_pIOHandler))->Open(file, "rb"));
size_t fileSize = 0;
unsigned char *data = NULL;
// sometimes pStream is nullptr for some reason (should be an empty object returning nothing I guess)
if (pStream) {
fileSize = pStream->FileSize();
// should be allocated with malloc(), because the library will call free() to deallocate
data = (unsigned char *)malloc(fileSize);
if (!data || !pStream.get() || !fileSize || fileSize != pStream->Read(data, 1, fileSize)) {
pStream.reset();
*size = 0;
// don't throw a deadly exception, it's not fatal if we can't read an external asset
return nullptr;
}
pStream.reset();
}
*size = (int)fileSize;
return data;
}
}
namespace Assimp {
M3DWrapper::M3DWrapper() {
// use malloc() here because m3d_free() will call free()
m3d_ = (m3d_t *)calloc(1, sizeof(m3d_t));
}
M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer) {
#if AI_M3D_USE_STDMUTEX
// M3D is NOT thread-safe, so lock the global mutex
const std::lock_guard<std::mutex> lock(file_mutex);
#endif
// pass this IOHandler to the C callback
m3dimporter_pIOHandler = pIOHandler;
m3d_ = m3d_load(const_cast<unsigned char *>(buffer.data()), m3dimporter_readfile, free, nullptr);
// Clear the C callback
m3dimporter_pIOHandler = nullptr;
}
M3DWrapper::~M3DWrapper() {
reset();
}
void M3DWrapper::reset() {
ClearSave();
if (m3d_)
m3d_free(m3d_);
m3d_ = nullptr;
}
unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) {
#if (!(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER))
ClearSave();
saved_output_ = m3d_save(m3d_, quality, flags, &size);
return saved_output_;
#else
return nullptr;
#endif
}
void M3DWrapper::ClearSave() {
if (saved_output_)
M3D_FREE(saved_output_);
saved_output_ = nullptr;
}
} // namespace Assimp
#endif

View File

@ -0,0 +1,97 @@
#pragma once
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
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.
----------------------------------------------------------------------
*/
/** @file M3DWrapper.h
* @brief Declares a class to wrap the C m3d SDK
*/
#ifndef AI_M3DWRAPPER_H_INC
#define AI_M3DWRAPPER_H_INC
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
#include <memory>
#include <vector>
#include <string>
#include "m3d.h"
namespace Assimp {
class IOSystem;
class M3DWrapper {
m3d_t *m3d_ = nullptr;
unsigned char *saved_output_ = nullptr;
public:
// Construct an empty M3D model
explicit M3DWrapper();
// Construct an M3D model from provided buffer
// NOTE: The m3d.h SDK function does not mark the data as const. Have assumed it does not write.
// BUG: SECURITY: The m3d.h SDK cannot be informed of the buffer size. BUFFER OVERFLOW IS CERTAIN
explicit M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer);
~M3DWrapper();
void reset();
// Name
inline std::string Name() const {
if (m3d_) return std::string(m3d_->name);
return std::string();
}
// Execute a save
unsigned char *Save(int quality, int flags, unsigned int &size);
void ClearSave();
inline explicit operator bool() const { return m3d_ != nullptr; }
// Allow direct access to M3D API
inline m3d_t *operator->() const { return m3d_; }
inline m3d_t *M3D() const { return m3d_; }
};
} // namespace Assimp
#endif
#endif // AI_M3DWRAPPER_H_INC

View File

@ -137,8 +137,9 @@ public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void Execute( aiScene* pScene); void Execute( aiScene* pScene);
protected: public:
void ProcessMesh( aiMesh* pMesh); /** Some other types of post-processing require winding order flips */
static void ProcessMesh( aiMesh* pMesh);
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -43,13 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the aiProcess_OptimizGraph step * @brief Implementation of the aiProcess_OptimizGraph step
*/ */
#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS #ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
#include "OptimizeGraph.h" #include "OptimizeGraph.h"
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include <assimp/SceneCombiner.h> #include "ConvertToLHProcess.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/SceneCombiner.h>
#include <stdio.h> #include <stdio.h>
using namespace Assimp; using namespace Assimp;
@ -60,292 +60,299 @@ using namespace Assimp;
* The unhashed variant should be faster, except for *very* large data sets * The unhashed variant should be faster, except for *very* large data sets
*/ */
#ifdef AI_OG_USE_HASHING #ifdef AI_OG_USE_HASHING
// Use our standard hashing function to compute the hash // Use our standard hashing function to compute the hash
# define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length) #define AI_OG_GETKEY(str) SuperFastHash(str.data, str.length)
#else #else
// Otherwise hope that std::string will utilize a static buffer // Otherwise hope that std::string will utilize a static buffer
// for shorter node names. This would avoid endless heap copying. // for shorter node names. This would avoid endless heap copying.
# define AI_OG_GETKEY(str) std::string(str.data) #define AI_OG_GETKEY(str) std::string(str.data)
#endif #endif
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
OptimizeGraphProcess::OptimizeGraphProcess() OptimizeGraphProcess::OptimizeGraphProcess() :
: mScene() mScene(),
, nodes_in() nodes_in(),
, nodes_out() nodes_out(),
, count_merged() { count_merged() {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
OptimizeGraphProcess::~OptimizeGraphProcess() { OptimizeGraphProcess::~OptimizeGraphProcess() {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const { bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const {
return (0 != (pFlags & aiProcess_OptimizeGraph)); return (0 != (pFlags & aiProcess_OptimizeGraph));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup properties for the post-processing step // Setup properties for the post-processing step
void OptimizeGraphProcess::SetupProperties(const Importer* pImp) { void OptimizeGraphProcess::SetupProperties(const Importer *pImp) {
// Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST // Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST
std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,""); std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST, "");
AddLockedNodeList(tmp); AddLockedNodeList(tmp);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Collect new children // Collect new children
void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes) { void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &nodes) {
nodes_in += nd->mNumChildren; nodes_in += nd->mNumChildren;
// Process children // Process children
std::list<aiNode*> child_nodes; std::list<aiNode *> child_nodes;
for (unsigned int i = 0; i < nd->mNumChildren; ++i) { for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
CollectNewChildren(nd->mChildren[i],child_nodes); CollectNewChildren(nd->mChildren[i], child_nodes);
nd->mChildren[i] = nullptr; nd->mChildren[i] = nullptr;
} }
// Check whether we need this node; if not we can replace it by our own children (warn, danger of incest). // Check whether we need this node; if not we can replace it by our own children (warn, danger of incest).
if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end() ) { if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end()) {
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) { for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) { if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) {
(*it)->mTransformation = nd->mTransformation * (*it)->mTransformation; (*it)->mTransformation = nd->mTransformation * (*it)->mTransformation;
nodes.push_back(*it); nodes.push_back(*it);
it = child_nodes.erase(it); it = child_nodes.erase(it);
continue; continue;
} }
++it; ++it;
} }
if (nd->mNumMeshes || !child_nodes.empty()) { if (nd->mNumMeshes || !child_nodes.empty()) {
nodes.push_back(nd); nodes.push_back(nd);
} else { } else {
delete nd; /* bye, node */ delete nd; /* bye, node */
return; return;
} }
} else { } else {
// Retain our current position in the hierarchy // Retain our current position in the hierarchy
nodes.push_back(nd); nodes.push_back(nd);
// Now check for possible optimizations in our list of child nodes. join as many as possible // Now check for possible optimizations in our list of child nodes. join as many as possible
aiNode* join_master = NULL; aiNode *join_master = nullptr;
aiMatrix4x4 inv; aiMatrix4x4 inv;
const LockedSetType::const_iterator end = locked.end(); const LockedSetType::const_iterator end = locked.end();
std::list<aiNode*> join; std::list<aiNode *> join;
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) { for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
aiNode* child = *it; aiNode *child = *it;
if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) { if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) {
// There may be no instanced meshes // There may be no instanced meshes
unsigned int n = 0; unsigned int n = 0;
for (; n < child->mNumMeshes;++n) { for (; n < child->mNumMeshes; ++n) {
if (meshes[child->mMeshes[n]] > 1) { if (meshes[child->mMeshes[n]] > 1) {
break; break;
} }
} }
if (n == child->mNumMeshes) { if (n == child->mNumMeshes) {
if (!join_master) { if (!join_master) {
join_master = child; join_master = child;
inv = join_master->mTransformation; inv = join_master->mTransformation;
inv.Inverse(); inv.Inverse();
} else { } else {
child->mTransformation = inv * child->mTransformation ; child->mTransformation = inv * child->mTransformation;
join.push_back(child); join.push_back(child);
it = child_nodes.erase(it); it = child_nodes.erase(it);
continue; continue;
} }
} }
} }
++it; ++it;
} }
if (join_master && !join.empty()) { if (join_master && !join.empty()) {
join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i",count_merged++); join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i", count_merged++);
unsigned int out_meshes = 0; unsigned int out_meshes = 0;
for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) { for (std::list<aiNode *>::const_iterator it = join.cbegin(); it != join.cend(); ++it) {
out_meshes += (*it)->mNumMeshes; out_meshes += (*it)->mNumMeshes;
} }
// copy all mesh references in one array // copy all mesh references in one array
if (out_meshes) { if (out_meshes) {
unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes; unsigned int *meshes = new unsigned int[out_meshes + join_master->mNumMeshes], *tmp = meshes;
for (unsigned int n = 0; n < join_master->mNumMeshes;++n) { for (unsigned int n = 0; n < join_master->mNumMeshes; ++n) {
*tmp++ = join_master->mMeshes[n]; *tmp++ = join_master->mMeshes[n];
} }
for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) { for (const aiNode *join_node : join) {
for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) { for (unsigned int n = 0; n < join_node->mNumMeshes; ++n) {
*tmp = (*it)->mMeshes[n]; *tmp = join_node->mMeshes[n];
aiMesh* mesh = mScene->mMeshes[*tmp++]; aiMesh *mesh = mScene->mMeshes[*tmp++];
// manually move the mesh into the right coordinate system // Assume the transformation is affine
const aiMatrix3x3 IT = aiMatrix3x3( (*it)->mTransformation ).Inverse().Transpose(); // manually move the mesh into the right coordinate system
for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
mesh->mVertices[a] *= (*it)->mTransformation; // Check for odd negative scale (mirror)
if (join_node->mTransformation.Determinant() < 0) {
// Reverse the mesh face winding order
FlipWindingOrderProcess::ProcessMesh(mesh);
}
if (mesh->HasNormals()) // Update positions, normals and tangents
mesh->mNormals[a] *= IT; const aiMatrix3x3 IT = aiMatrix3x3(join_node->mTransformation).Inverse().Transpose();
for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
if (mesh->HasTangentsAndBitangents()) { mesh->mVertices[a] *= join_node->mTransformation;
mesh->mTangents[a] *= IT;
mesh->mBitangents[a] *= IT;
}
}
}
delete *it; // bye, node
}
delete[] join_master->mMeshes;
join_master->mMeshes = meshes;
join_master->mNumMeshes += out_meshes;
}
}
}
// reassign children if something changed
if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) {
delete[] nd->mChildren; if (mesh->HasNormals())
mesh->mNormals[a] *= IT;
if (!child_nodes.empty()) { if (mesh->HasTangentsAndBitangents()) {
nd->mChildren = new aiNode*[child_nodes.size()]; mesh->mTangents[a] *= IT;
} mesh->mBitangents[a] *= IT;
else nd->mChildren = nullptr; }
} }
}
delete join_node; // bye, node
}
delete[] join_master->mMeshes;
join_master->mMeshes = meshes;
join_master->mNumMeshes += out_meshes;
}
}
}
// reassign children if something changed
if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) {
nd->mNumChildren = static_cast<unsigned int>(child_nodes.size()); delete[] nd->mChildren;
if (nd->mChildren) { if (!child_nodes.empty()) {
aiNode** tmp = nd->mChildren; nd->mChildren = new aiNode *[child_nodes.size()];
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) { } else
aiNode* node = *tmp++ = *it; nd->mChildren = nullptr;
node->mParent = nd; }
}
}
nodes_out += static_cast<unsigned int>(child_nodes.size()); nd->mNumChildren = static_cast<unsigned int>(child_nodes.size());
if (nd->mChildren) {
aiNode **tmp = nd->mChildren;
for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
aiNode *node = *tmp++ = *it;
node->mParent = nd;
}
}
nodes_out += static_cast<unsigned int>(child_nodes.size());
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Execute the post-processing step on the given scene // Execute the post-processing step on the given scene
void OptimizeGraphProcess::Execute( aiScene* pScene) { void OptimizeGraphProcess::Execute(aiScene *pScene) {
ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin"); ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin");
nodes_in = nodes_out = count_merged = 0; nodes_in = nodes_out = count_merged = 0;
mScene = pScene; mScene = pScene;
meshes.resize(pScene->mNumMeshes,0); meshes.resize(pScene->mNumMeshes, 0);
FindInstancedMeshes(pScene->mRootNode); FindInstancedMeshes(pScene->mRootNode);
// build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it // build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it
locked.clear(); locked.clear();
for (std::list<std::string>::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) { for (std::list<std::string>::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) {
#ifdef AI_OG_USE_HASHING #ifdef AI_OG_USE_HASHING
locked.insert(SuperFastHash((*it).c_str())); locked.insert(SuperFastHash((*it).c_str()));
#else #else
locked.insert(*it); locked.insert(*it);
#endif #endif
} }
for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) { for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {
for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) { for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) {
aiNodeAnim* anim = pScene->mAnimations[i]->mChannels[a]; aiNodeAnim *anim = pScene->mAnimations[i]->mChannels[a];
locked.insert(AI_OG_GETKEY(anim->mNodeName)); locked.insert(AI_OG_GETKEY(anim->mNodeName));
} }
} }
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) { for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) {
aiBone* bone = pScene->mMeshes[i]->mBones[a]; aiBone *bone = pScene->mMeshes[i]->mBones[a];
locked.insert(AI_OG_GETKEY(bone->mName)); locked.insert(AI_OG_GETKEY(bone->mName));
// HACK: Meshes referencing bones may not be transformed; we need to look them. // HACK: Meshes referencing bones may not be transformed; we need to look them.
// The easiest way to do this is to increase their reference counters ... // The easiest way to do this is to increase their reference counters ...
meshes[i] += 2; meshes[i] += 2;
} }
} }
for (unsigned int i = 0; i < pScene->mNumCameras; ++i) { for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {
aiCamera* cam = pScene->mCameras[i]; aiCamera *cam = pScene->mCameras[i];
locked.insert(AI_OG_GETKEY(cam->mName)); locked.insert(AI_OG_GETKEY(cam->mName));
} }
for (unsigned int i = 0; i < pScene->mNumLights; ++i) { for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
aiLight* lgh = pScene->mLights[i]; aiLight *lgh = pScene->mLights[i];
locked.insert(AI_OG_GETKEY(lgh->mName)); locked.insert(AI_OG_GETKEY(lgh->mName));
} }
// Insert a dummy master node and make it read-only // Insert a dummy master node and make it read-only
aiNode* dummy_root = new aiNode(AI_RESERVED_NODE_NAME); aiNode *dummy_root = new aiNode(AI_RESERVED_NODE_NAME);
locked.insert(AI_OG_GETKEY(dummy_root->mName)); locked.insert(AI_OG_GETKEY(dummy_root->mName));
const aiString prev = pScene->mRootNode->mName; const aiString prev = pScene->mRootNode->mName;
pScene->mRootNode->mParent = dummy_root; pScene->mRootNode->mParent = dummy_root;
dummy_root->mChildren = new aiNode*[dummy_root->mNumChildren = 1]; dummy_root->mChildren = new aiNode *[dummy_root->mNumChildren = 1];
dummy_root->mChildren[0] = pScene->mRootNode; dummy_root->mChildren[0] = pScene->mRootNode;
// Do our recursive processing of scenegraph nodes. For each node collect // Do our recursive processing of scenegraph nodes. For each node collect
// a fully new list of children and allow their children to place themselves // a fully new list of children and allow their children to place themselves
// on the same hierarchy layer as their parents. // on the same hierarchy layer as their parents.
std::list<aiNode*> nodes; std::list<aiNode *> nodes;
CollectNewChildren (dummy_root,nodes); CollectNewChildren(dummy_root, nodes);
ai_assert(nodes.size() == 1); ai_assert(nodes.size() == 1);
if (dummy_root->mNumChildren == 0) { if (dummy_root->mNumChildren == 0) {
pScene->mRootNode = NULL; pScene->mRootNode = nullptr;
throw DeadlyImportError("After optimizing the scene graph, no data remains"); throw DeadlyImportError("After optimizing the scene graph, no data remains");
} }
if (dummy_root->mNumChildren > 1) { if (dummy_root->mNumChildren > 1) {
pScene->mRootNode = dummy_root; pScene->mRootNode = dummy_root;
// Keep the dummy node but assign the name of the old root node to it // Keep the dummy node but assign the name of the old root node to it
pScene->mRootNode->mName = prev; pScene->mRootNode->mName = prev;
} } else {
else {
// Remove the dummy root node again. // Remove the dummy root node again.
pScene->mRootNode = dummy_root->mChildren[0]; pScene->mRootNode = dummy_root->mChildren[0];
dummy_root->mChildren[0] = NULL; dummy_root->mChildren[0] = nullptr;
delete dummy_root; delete dummy_root;
} }
pScene->mRootNode->mParent = NULL; pScene->mRootNode->mParent = nullptr;
if (!DefaultLogger::isNullLogger()) { if (!DefaultLogger::isNullLogger()) {
if ( nodes_in != nodes_out) { if (nodes_in != nodes_out) {
ASSIMP_LOG_INFO_F("OptimizeGraphProcess finished; Input nodes: ", nodes_in, ", Output nodes: ", nodes_out); ASSIMP_LOG_INFO_F("OptimizeGraphProcess finished; Input nodes: ", nodes_in, ", Output nodes: ", nodes_out);
} else { } else {
ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished"); ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished");
} }
} }
meshes.clear(); meshes.clear();
locked.clear(); locked.clear();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Build a LUT of all instanced meshes // Build a LUT of all instanced meshes
void OptimizeGraphProcess::FindInstancedMeshes (aiNode* pNode) void OptimizeGraphProcess::FindInstancedMeshes(aiNode *pNode) {
{ for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) {
for (unsigned int i = 0; i < pNode->mNumMeshes;++i) { ++meshes[pNode->mMeshes[i]];
++meshes[pNode->mMeshes[i]]; }
}
for (unsigned int i = 0; i < pNode->mNumChildren; ++i) for (unsigned int i = 0; i < pNode->mNumChildren; ++i)
FindInstancedMeshes(pNode->mChildren[i]); FindInstancedMeshes(pNode->mChildren[i]);
} }
#endif // !! ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS #endif // !! ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS

View File

@ -75,13 +75,13 @@ public:
~OptimizeGraphProcess(); ~OptimizeGraphProcess();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void Execute( aiScene* pScene); void Execute( aiScene* pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** @brief Add a list of node names to be locked and not modified. /** @brief Add a list of node names to be locked and not modified.

File diff suppressed because it is too large Load Diff

View File

@ -59,7 +59,7 @@ struct aiNode;
class PretransformVerticesTest; class PretransformVerticesTest;
namespace Assimp { namespace Assimp {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** The PretransformVertices pre-transforms all vertices in the node tree /** The PretransformVertices pre-transforms all vertices in the node tree
@ -68,97 +68,97 @@ namespace Assimp {
*/ */
class ASSIMP_API PretransformVertices : public BaseProcess { class ASSIMP_API PretransformVertices : public BaseProcess {
public: public:
PretransformVertices (); PretransformVertices();
~PretransformVertices (); ~PretransformVertices();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Check whether step is active // Check whether step is active
bool IsActive( unsigned int pFlags) const; bool IsActive(unsigned int pFlags) const override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Execute step on a given scene // Execute step on a given scene
void Execute( aiScene* pScene); void Execute(aiScene *pScene) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Setup import settings // Setup import settings
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer *pImp) override;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** @brief Toggle the 'keep hierarchy' option /** @brief Toggle the 'keep hierarchy' option
* @param keep true for keep configuration. * @param keep true for keep configuration.
*/ */
void KeepHierarchy(bool keep) { void KeepHierarchy(bool keep) {
configKeepHierarchy = keep; configKeepHierarchy = keep;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** @brief Check whether 'keep hierarchy' is currently enabled. /** @brief Check whether 'keep hierarchy' is currently enabled.
* @return ... * @return ...
*/ */
bool IsHierarchyKept() const { bool IsHierarchyKept() const {
return configKeepHierarchy; return configKeepHierarchy;
} }
private: private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Count the number of nodes // Count the number of nodes
unsigned int CountNodes( aiNode* pcNode ); unsigned int CountNodes(const aiNode *pcNode) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get a bitwise combination identifying the vertex format of a mesh // Get a bitwise combination identifying the vertex format of a mesh
unsigned int GetMeshVFormat(aiMesh* pcMesh); unsigned int GetMeshVFormat(aiMesh *pcMesh) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Count the number of vertices in the whole scene and a given // Count the number of vertices in the whole scene and a given
// material index // material index
void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, void CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode,
unsigned int iMat, unsigned int iMat,
unsigned int iVFormat, unsigned int iVFormat,
unsigned int* piFaces, unsigned int *piFaces,
unsigned int* piVertices); unsigned int *piVertices) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Collect vertex/face data // Collect vertex/face data
void CollectData( aiScene* pcScene, aiNode* pcNode, void CollectData(const aiScene *pcScene, const aiNode *pcNode,
unsigned int iMat, unsigned int iMat,
unsigned int iVFormat, unsigned int iVFormat,
aiMesh* pcMeshOut, aiMesh *pcMeshOut,
unsigned int aiCurrent[2], unsigned int aiCurrent[2],
unsigned int* num_refs); unsigned int *num_refs) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get a list of all vertex formats that occur for a given material // Get a list of all vertex formats that occur for a given material
// The output list contains duplicate elements // The output list contains duplicate elements
void GetVFormatList( aiScene* pcScene, unsigned int iMat, void GetVFormatList(const aiScene *pcScene, unsigned int iMat,
std::list<unsigned int>& aiOut); std::list<unsigned int> &aiOut) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Compute the absolute transformation matrices of each node // Compute the absolute transformation matrices of each node
void ComputeAbsoluteTransform( aiNode* pcNode ); void ComputeAbsoluteTransform(aiNode *pcNode);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Simple routine to build meshes in worldspace, no further optimization // Simple routine to build meshes in worldspace, no further optimization
void BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in, void BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in,
unsigned int numIn, aiNode* node); unsigned int numIn, aiNode *node) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Apply the node transformation to a mesh // Apply the node transformation to a mesh
void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat); void ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Reset transformation matrices to identity // Reset transformation matrices to identity
void MakeIdentityTransform(aiNode* nd); void MakeIdentityTransform(aiNode *nd) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Build reference counters for all meshes // Build reference counters for all meshes
void BuildMeshRefCountArray(aiNode* nd, unsigned int * refs); void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const;
//! Configuration option: keep scene hierarchy as long as possible //! Configuration option: keep scene hierarchy as long as possible
bool configKeepHierarchy; bool configKeepHierarchy;
bool configNormalize; bool configNormalize;
bool configTransform; bool configTransform;
aiMatrix4x4 configTransformation; aiMatrix4x4 configTransformation;
bool mConfigPointCloud; bool mConfigPointCloud;
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/commonMetaData.h>
#include <memory> #include <memory>
@ -697,6 +698,25 @@ void glTFImporter::ImportEmbeddedTextures(glTF::Asset& r)
} }
} }
void glTFImporter::ImportCommonMetadata(glTF::Asset& a)
{
ai_assert(mScene->mMetaData == nullptr);
const bool hasVersion = !a.asset.version.empty();
const bool hasGenerator = !a.asset.generator.empty();
if (hasVersion || hasGenerator)
{
mScene->mMetaData = new aiMetadata;
if (hasVersion)
{
mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT_VERSION, aiString(a.asset.version));
}
if (hasGenerator)
{
mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator));
}
}
}
void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{ {
// clean all member arrays // clean all member arrays
@ -723,7 +743,7 @@ void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOS
ImportLights(asset); ImportLights(asset);
ImportNodes(asset); ImportNodes(asset);
ImportCommonMetadata(asset);
if (pScene->mNumMeshes == 0) { if (pScene->mNumMeshes == 0) {
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;

View File

@ -83,7 +83,7 @@ private:
void ImportCameras(glTF::Asset& a); void ImportCameras(glTF::Asset& a);
void ImportLights(glTF::Asset& a); void ImportLights(glTF::Asset& a);
void ImportNodes(glTF::Asset& a); void ImportNodes(glTF::Asset& a);
void ImportCommonMetadata(glTF::Asset& a);
}; };
} // Namespace assimp } // Namespace assimp

View File

@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/commonMetaData.h>
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
@ -1302,6 +1303,24 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
} }
} }
void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) {
ai_assert(mScene->mMetaData == nullptr);
const bool hasVersion = !a.asset.version.empty();
const bool hasGenerator = !a.asset.generator.empty();
if (hasVersion || hasGenerator)
{
mScene->mMetaData = new aiMetadata;
if (hasVersion)
{
mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT_VERSION, aiString(a.asset.version));
}
if (hasGenerator)
{
mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator));
}
}
}
void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
// clean all member arrays // clean all member arrays
meshOffsets.clear(); meshOffsets.clear();
@ -1329,6 +1348,8 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
ImportAnimations(asset); ImportAnimations(asset);
ImportCommonMetadata(asset);
if (pScene->mNumMeshes == 0) { if (pScene->mNumMeshes == 0) {
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} }

View File

@ -84,6 +84,7 @@ private:
void ImportLights(glTF2::Asset& a); void ImportLights(glTF2::Asset& a);
void ImportNodes(glTF2::Asset& a); void ImportNodes(glTF2::Asset& a);
void ImportAnimations(glTF2::Asset& a); void ImportAnimations(glTF2::Asset& a);
void ImportCommonMetadata(glTF2::Asset& a);
}; };
} // Namespace assimp } // Namespace assimp

View File

@ -72,7 +72,7 @@ for(LineSplitter splitter(stream);splitter;++splitter) {
if (strtol(splitter[2]) > 5) { .. } if (strtol(splitter[2]) > 5) { .. }
} }
std::cout << "Current line is: " << splitter.get_index() << std::endl; ASSIMP_LOG_DEBUG_F("Current line is: ", splitter.get_index());
} }
@endcode @endcode
*/ */

View File

@ -0,0 +1,63 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2019, 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.
---------------------------------------------------------------------------
*/
/** @file commonMetaData.h
* @brief Defines a set of common scene metadata keys.
*/
#pragma once
#ifndef AI_COMMONMETADATA_H_INC
#define AI_COMMONMETADATA_H_INC
/// Scene metadata holding the name of the importer which loaded the source asset.
/// This is always present if the scene was created from an imported asset.
#define AI_METADATA_SOURCE_FORMAT "SourceAsset_Format"
/// Scene metadata holding the version of the source asset as a string, if available.
/// Not all formats add this metadata.
#define AI_METADATA_SOURCE_FORMAT_VERSION "SourceAsset_FormatVersion"
/// Scene metadata holding the name of the software which generated the source asset, if available.
/// Not all formats add this metadata.
#define AI_METADATA_SOURCE_GENERATOR "SourceAsset_Generator"
#endif

View File

@ -286,8 +286,8 @@ struct aiMetadata {
new_values[i] = mValues[i]; new_values[i] = mValues[i];
} }
delete mKeys; delete[] mKeys;
delete mValues; delete[] mValues;
mKeys = new_keys; mKeys = new_keys;
mValues = new_values; mValues = new_values;
@ -377,6 +377,23 @@ struct aiMetadata {
return true; return true;
} }
/// Check whether there is a metadata entry for the given key.
/// \param [in] Key - the key value value to check for.
inline
bool HasKey(const char* key) {
if ( nullptr == key ) {
return false;
}
// Search for the given key
for (unsigned int i = 0; i < mNumProperties; ++i) {
if ( 0 == strncmp(mKeys[i].C_Str(), key, mKeys[i].length ) ) {
return true;
}
}
return false;
}
#endif // __cplusplus #endif // __cplusplus
}; };

View File

@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/types.h> #include <assimp/types.h>
#include <assimp/commonMetaData.h>
using namespace Assimp; using namespace Assimp;
@ -283,3 +284,29 @@ TEST_F(utFBXImporterExporter, importOrphantEmbeddedTextureTest) {
ASSERT_TRUE(scene->mTextures[0]->pcData); ASSERT_TRUE(scene->mTextures[0]->pcData);
ASSERT_EQ(9026u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression used for a texture."; ASSERT_EQ(9026u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression used for a texture.";
} }
TEST_F(utFBXImporterExporter, sceneMetadata) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/global_settings.fbx",
aiProcess_ValidateDataStructure);
ASSERT_NE(scene, nullptr);
ASSERT_NE(scene->mMetaData, nullptr);
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT));
aiString format;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format));
ASSERT_EQ(strcmp(format.C_Str(), "Autodesk FBX Importer"), 0);
}
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION));
aiString version;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version));
ASSERT_EQ(strcmp(version.C_Str(), "7400"), 0);
}
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR));
aiString generator;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator));
ASSERT_EQ(strncmp(generator.C_Str(), "Blender", 7), 0);
}
}

View File

@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/Exporter.hpp> #include <assimp/Exporter.hpp>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/commonMetaData.h>
#include <array> #include <array>
#include <assimp/pbrmaterial.h> #include <assimp/pbrmaterial.h>
@ -439,6 +441,32 @@ TEST_F(utglTF2ImportExport, error_string_preserved) {
#endif // ASSIMP_BUILD_NO_EXPORT #endif // ASSIMP_BUILD_NO_EXPORT
TEST_F(utglTF2ImportExport, sceneMetadata) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf",
aiProcess_ValidateDataStructure);
ASSERT_NE(scene, nullptr);
ASSERT_NE(scene->mMetaData, nullptr);
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT));
aiString format;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format));
ASSERT_EQ(strcmp(format.C_Str(), "glTF2 Importer"), 0);
}
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION));
aiString version;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version));
ASSERT_EQ(strcmp(version.C_Str(), "2.0"), 0);
}
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR));
aiString generator;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator));
ASSERT_EQ(strcmp(generator.C_Str(), "COLLADA2GLTF"), 0);
}
}
TEST_F(utglTF2ImportExport, texcoords) { TEST_F(utglTF2ImportExport, texcoords) {
Assimp::Importer importer; Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf", const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf",

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/commonMetaData.h>
using namespace Assimp; using namespace Assimp;
@ -85,3 +86,28 @@ TEST_F(utglTFImportExport, incorrect_vertex_arrays) {
EXPECT_EQ(scene->mMeshes[7]->mNumVertices, 35u); EXPECT_EQ(scene->mMeshes[7]->mNumVertices, 35u);
EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u); EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u);
} }
TEST_F(utglTFImportExport, sceneMetadata) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF/TwoBoxes/TwoBoxes.gltf", aiProcess_ValidateDataStructure);
ASSERT_TRUE(scene);
ASSERT_TRUE(scene->mMetaData);
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT));
aiString format;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format));
ASSERT_EQ(strcmp(format.C_Str(), "glTF Importer"), 0);
}
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION));
aiString version;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version));
ASSERT_EQ(strcmp(version.C_Str(), "1.0"), 0);
}
{
ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR));
aiString generator;
ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator));
ASSERT_EQ(strncmp(generator.C_Str(), "collada2gltf", 12), 0);
}
}