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,7 +383,9 @@ 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] );
}
} }
} }
} }
@ -398,7 +397,7 @@ void B3DImporter::ReadTRIS( int v0 ){
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");
} }
@ -418,7 +417,7 @@ void B3DImporter::ReadTRIS( int 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;
@ -462,19 +461,13 @@ void B3DImporter::ReadBONE( int id ){
} }
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,9 +626,13 @@ 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 ){
@ -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,11 +1599,10 @@ 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 {
std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl; ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
bone = new aiBone(); bone = new aiBone();
bone->mName = bone_name; bone->mName = bone_name;
@ -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,7 +82,171 @@ 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;
// ------------------------------------------------------------------------------------------------
// Conversion functions
// ------------------------------------------------------------------------------------------------
// helper to add a vertex (private to NodeWalk)
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->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->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
vrtx = (m3dv_t *)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
*idx = *numvrtx;
(*numvrtx)++;
return vrtx;
}
// ------------------------------------------------------------------------------------------------
// helper to add a tmap (private to NodeWalk)
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));
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
*idx = *numtmap;
(*numtmap)++;
return tmap;
}
// ------------------------------------------------------------------------------------------------
// convert aiColor4D into uint32_t
uint32_t mkColor(aiColor4D *c) {
return ((uint8_t)(c->a * 255) << 24L) |
((uint8_t)(c->b * 255) << 16L) |
((uint8_t)(c->g * 255) << 8L) |
((uint8_t)(c->r * 255) << 0L);
}
// ------------------------------------------------------------------------------------------------
// add a material property to the output
void addProp(m3dm_t *m, uint8_t type, uint32_t value) {
unsigned int i;
i = m->numprop++;
m->prop = (m3dp_t *)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t));
if (!m->prop) {
throw DeadlyExportError("memory allocation error");
}
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 { namespace Assimp {
@ -91,8 +257,7 @@ namespace Assimp {
const char *pFile, const char *pFile,
IOSystem *pIOSystem, IOSystem *pIOSystem,
const aiScene *pScene, const aiScene *pScene,
const ExportProperties* pProperties const ExportProperties *pProperties) {
){
// initialize the exporter // initialize the exporter
M3DExporter exporter(pScene, pProperties); M3DExporter exporter(pScene, pProperties);
@ -117,21 +282,17 @@ namespace Assimp {
exporter.doExport(pFile, pIOSystem, true); exporter.doExport(pFile, pIOSystem, true);
} }
} // end of namespace Assimp
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
M3DExporter::M3DExporter ( const aiScene* pScene, const ExportProperties* pProperties ) M3DExporter::M3DExporter(const aiScene *pScene, const ExportProperties *pProperties) :
: mScene(pScene) mScene(pScene),
, mProperties(pProperties) mProperties(pProperties),
, outfile() outfile() {}
, m3d(nullptr) { }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void M3DExporter::doExport( void M3DExporter::doExport(
const char *pFile, const char *pFile,
IOSystem *pIOSystem, IOSystem *pIOSystem,
bool toAscii bool toAscii) {
){
// TODO: convert mProperties into M3D_EXP_* flags // TODO: convert mProperties into M3D_EXP_* flags
(void)mProperties; (void)mProperties;
@ -141,8 +302,7 @@ void M3DExporter::doExport (
throw DeadlyExportError("could not open output .m3d file: " + std::string(pFile)); throw DeadlyExportError("could not open output .m3d file: " + std::string(pFile));
} }
// use malloc() here because m3d_free() will call free() M3DWrapper m3d;
m3d = (m3d_t*)calloc(1, sizeof(m3d_t));
if (!m3d) { if (!m3d) {
throw DeadlyExportError("memory allocation error"); throw DeadlyExportError("memory allocation error");
} }
@ -150,13 +310,12 @@ void M3DExporter::doExport (
// Create a model from assimp structures // Create a model from assimp structures
aiMatrix4x4 m; aiMatrix4x4 m;
NodeWalk(mScene->mRootNode, m); NodeWalk(m3d, mScene->mRootNode, m);
// serialize the structures // serialize the structures
unsigned int size; unsigned int size;
unsigned char *output = m3d_save(m3d, M3D_EXP_FLOAT, unsigned char *output = m3d.Save(M3D_EXP_FLOAT, M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), size);
M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), &size);
m3d_free(m3d);
if (!output || size < 8) { if (!output || size < 8) {
throw DeadlyExportError("unable to serialize into Model 3D"); throw DeadlyExportError("unable to serialize into Model 3D");
} }
@ -169,37 +328,9 @@ void M3DExporter::doExport (
outfile.reset(); outfile.reset();
} }
// ------------------------------------------------------------------------------------------------
// helper to add a vertex (private to NodeWalk)
m3dv_t *M3DExporter::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->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->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
*idx = *numvrtx;
(*numvrtx)++;
return vrtx;
}
// ------------------------------------------------------------------------------------------------
// helper to add a tmap (private to NodeWalk)
m3dti_t *M3DExporter::AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx)
{
tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
*idx = *numtmap;
(*numtmap)++;
return tmap;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// recursive node walker // recursive node walker
void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m) void M3DExporter::NodeWalk(const M3DWrapper &m3d, const aiNode *pNode, aiMatrix4x4 m) {
{
aiMatrix4x4 nm = m * pNode->mTransformation; aiMatrix4x4 nm = m * pNode->mTransformation;
for (unsigned int i = 0; i < pNode->mNumMeshes; i++) { for (unsigned int i = 0; i < pNode->mNumMeshes; i++) {
@ -207,7 +338,7 @@ void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
unsigned int mi = (M3D_INDEX)-1U; unsigned int mi = (M3D_INDEX)-1U;
if (mScene->mMaterials) { if (mScene->mMaterials) {
// get the material for this mesh // get the material for this mesh
mi = addMaterial(mScene->mMaterials[mesh->mMaterialIndex]); mi = addMaterial(m3d, mScene->mMaterials[mesh->mMaterialIndex]);
} }
// iterate through the mesh faces // iterate through the mesh faces
for (unsigned int j = 0; j < mesh->mNumFaces; j++) { for (unsigned int j = 0; j < mesh->mNumFaces; j++) {
@ -272,149 +403,10 @@ void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
} }
// repeat for the children nodes // repeat for the children nodes
for (unsigned int i = 0; i < pNode->mNumChildren; i++) { for (unsigned int i = 0; i < pNode->mNumChildren; i++) {
NodeWalk(pNode->mChildren[i], nm); NodeWalk(m3d, pNode->mChildren[i], nm);
} }
} }
} // namespace Assimp
// ------------------------------------------------------------------------------------------------
// convert aiColor4D into uint32_t
uint32_t M3DExporter::mkColor(aiColor4D* c)
{
return ((uint8_t)(c->a*255) << 24L) |
((uint8_t)(c->b*255) << 16L) |
((uint8_t)(c->g*255) << 8L) |
((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
void M3DExporter::addProp(m3dm_t *m, uint8_t type, uint32_t value)
{
unsigned int i;
i = m->numprop++;
m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t));
if(!m->prop) { throw DeadlyExportError( "memory allocation error" ); }
m->prop[i].type = type;
m->prop[i].value.num = value;
}
#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);
}; };
} }

View File

@ -48,16 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define M3D_NOWEIGHTS #define M3D_NOWEIGHTS
#define M3D_NOANIMATION #define M3D_NOANIMATION
#include <assimp/IOStreamBuffer.h>
#include <memory>
#include <assimp/DefaultIOSystem.h> #include <assimp/DefaultIOSystem.h>
#include <assimp/Importer.hpp> #include <assimp/IOStreamBuffer.h>
#include <assimp/scene.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <memory>
#include "M3DImporter.h" #include "M3DImporter.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
@ -89,7 +91,7 @@ static const aiImporterDesc desc = {
"", "",
"", "",
"", "",
aiImporterFlags_SupportBinaryFlavour, aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
0, 0,
0, 0,
0, 0,
@ -97,49 +99,14 @@ static const aiImporterDesc desc = {
"m3d a3d" "m3d a3d"
}; };
// workaround: the SDK expects a C callback, but we want to use Assimp::IOSystem to implement that
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 { namespace Assimp {
using namespace std; using namespace std;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Default constructor // Default constructor
M3DImporter::M3DImporter() M3DImporter::M3DImporter() :
: mScene(nullptr) mScene(nullptr) {}
, m3d(nullptr) { }
// ------------------------------------------------------------------------------------------------
// Destructor.
M3DImporter::~M3DImporter() {}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if file is a binary or ASCII Model 3D file. // Returns true, if file is a binary or ASCII Model 3D file.
@ -188,9 +155,8 @@ void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSy
if (fileSize < 8) { if (fileSize < 8) {
throw DeadlyImportError("M3D-file " + file + " is too small."); throw DeadlyImportError("M3D-file " + file + " is too small.");
} }
std::unique_ptr<unsigned char[]> _buffer (new unsigned char[fileSize]); std::vector<unsigned char> buffer(fileSize);
unsigned char *data( _buffer.get() ); if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) {
if(fileSize != pStream->Read(data,1,fileSize)) {
throw DeadlyImportError("Failed to read the file " + file + "."); throw DeadlyImportError("Failed to read the file " + file + ".");
} }
@ -203,37 +169,33 @@ void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSy
pIOHandler->PushDirectory(folderName); pIOHandler->PushDirectory(folderName);
} }
} }
// pass this IOHandler to the C callback
m3dimporter_pIOHandler = pIOHandler;
//DefaultLogger::create("/dev/stderr", Logger::VERBOSE); //DefaultLogger::create("/dev/stderr", Logger::VERBOSE);
ASSIMP_LOG_DEBUG_F("M3D: loading ", file); ASSIMP_LOG_DEBUG_F("M3D: loading ", file);
// let the C SDK do the hard work for us // let the C SDK do the hard work for us
m3d = m3d_load(&data[0], m3dimporter_readfile, free, nullptr); M3DWrapper m3d(pIOHandler, buffer);
m3dimporter_pIOHandler = nullptr;
if (!m3d) { if (!m3d) {
throw DeadlyImportError("Unable to parse " + file + " as M3D."); throw DeadlyImportError("Unable to parse " + file + " as M3D.");
} }
// create the root node // create the root node
pScene->mRootNode = new aiNode; pScene->mRootNode = new aiNode;
pScene->mRootNode->mName = aiString(std::string(std::string(m3d->name))); pScene->mRootNode->mName = aiString(m3d.Name());
pScene->mRootNode->mTransformation = aiMatrix4x4(); pScene->mRootNode->mTransformation = aiMatrix4x4();
pScene->mRootNode->mNumChildren = 0; pScene->mRootNode->mNumChildren = 0;
mScene = pScene; mScene = pScene;
ASSIMP_LOG_DEBUG("M3D: root node " + std::string(m3d->name)); ASSIMP_LOG_DEBUG("M3D: root node " + m3d.Name());
// now we just have to fill up the Assimp structures in pScene // now we just have to fill up the Assimp structures in pScene
importMaterials(); importMaterials(m3d);
importTextures(); importTextures(m3d);
importBones(-1U, pScene->mRootNode); importBones(m3d, -1U, pScene->mRootNode);
importMeshes(); importMeshes(m3d);
importAnimations(); importAnimations(m3d);
// we don't need the SDK's version any more
m3d_free(m3d);
// Pop directory stack // Pop directory stack
if (pIOHandler->StackSize() > 0) { if (pIOHandler->StackSize() > 0) {
@ -243,8 +205,7 @@ void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSy
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// convert materials. properties are converted using a static table in M3DMaterials.h // convert materials. properties are converted using a static table in M3DMaterials.h
void M3DImporter::importMaterials() void M3DImporter::importMaterials(const M3DWrapper &m3d_wrap) {
{
unsigned int i, j, k, l, n; unsigned int i, j, k, l, n;
m3dm_t *m; m3dm_t *m;
aiString name = aiString(AI_DEFAULT_MATERIAL_NAME); aiString name = aiString(AI_DEFAULT_MATERIAL_NAME);
@ -252,22 +213,23 @@ void M3DImporter::importMaterials()
ai_real f; ai_real f;
ai_assert(mScene != nullptr); ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr); ai_assert(m3d_wrap);
mScene->mNumMaterials = m3d->nummaterial + 1; mScene->mNumMaterials = m3d_wrap->nummaterial + 1;
mScene->mMaterials = new aiMaterial*[ m3d->nummaterial + 1 ]; mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials); ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials);
// add a default material as first // add a default material as first
aiMaterial *mat = new aiMaterial; aiMaterial *mat = new aiMaterial;
mat->AddProperty(&name, AI_MATKEY_NAME); mat->AddProperty(&name, AI_MATKEY_NAME);
c.a = 1.0; c.b = c.g = c.r = 0.6; c.a = 1.0f;
c.b = c.g = c.r = 0.6f;
mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE); mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE);
mScene->mMaterials[0] = mat; mScene->mMaterials[0] = mat;
for(i = 0; i < m3d->nummaterial; i++) { for (i = 0; i < m3d_wrap->nummaterial; i++) {
m = &m3d->material[i]; m = &m3d_wrap->material[i];
aiMaterial *mat = new aiMaterial; aiMaterial *mat = new aiMaterial;
name.Set(std::string(m->name)); name.Set(std::string(m->name));
mat->AddProperty(&name, AI_MATKEY_NAME); mat->AddProperty(&name, AI_MATKEY_NAME);
@ -312,9 +274,9 @@ void M3DImporter::importMaterials()
// texture map properties // texture map properties
if (m->prop[j].type >= 128 && aiTxProps[k].pKey && if (m->prop[j].type >= 128 && aiTxProps[k].pKey &&
// extra check, should never happen, do we have the refered texture? // extra check, should never happen, do we have the refered texture?
m->prop[j].value.textureid < m3d->numtexture && m->prop[j].value.textureid < m3d_wrap->numtexture &&
m3d->texture[m->prop[j].value.textureid].name) { m3d_wrap->texture[m->prop[j].value.textureid].name) {
name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png")); name.Set(std::string(std::string(m3d_wrap->texture[m->prop[j].value.textureid].name) + ".png"));
mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index); mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index);
n = 0; n = 0;
mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index); mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index);
@ -326,14 +288,13 @@ void M3DImporter::importMaterials()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// import textures, this is the simplest of all // import textures, this is the simplest of all
void M3DImporter::importTextures() void M3DImporter::importTextures(const M3DWrapper &m3d) {
{
unsigned int i; unsigned int i;
const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" }; const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
m3dtx_t *t; m3dtx_t *t;
ai_assert(mScene != nullptr); ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr); ai_assert(m3d);
mScene->mNumTextures = m3d->numtexture; mScene->mNumTextures = m3d->numtexture;
ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures); ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures);
@ -355,14 +316,21 @@ void M3DImporter::importTextures()
for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) { for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) {
switch (t->f) { switch (t->f) {
case 1: tx->pcData[j].g = t->d[k++]; break; case 1: tx->pcData[j].g = t->d[k++]; break;
case 2: tx->pcData[j].g = t->d[k++]; tx->pcData[j].a = t->d[k++]; break; case 2:
tx->pcData[j].g = t->d[k++];
tx->pcData[j].a = t->d[k++];
break;
case 3: case 3:
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++]; tx->pcData[j].r = t->d[k++];
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = 255; tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++];
tx->pcData[j].a = 255;
break; break;
case 4: case 4:
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++]; tx->pcData[j].r = t->d[k++];
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = t->d[k++]; tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++];
tx->pcData[j].a = t->d[k++];
break; break;
} }
} }
@ -374,8 +342,7 @@ void M3DImporter::importTextures()
// this is tricky. M3D has a global vertex and UV list, and faces are indexing them // this is tricky. M3D has a global vertex and UV list, and faces are indexing them
// individually. In assimp there're per mesh vertex and UV lists, and they must be // individually. In assimp there're per mesh vertex and UV lists, and they must be
// indexed simultaneously. // indexed simultaneously.
void M3DImporter::importMeshes() void M3DImporter::importMeshes(const M3DWrapper &m3d) {
{
unsigned int i, j, k, l, numpoly = 3, lastMat = -2U; unsigned int i, j, k, l, numpoly = 3, lastMat = -2U;
std::vector<aiMesh *> *meshes = new std::vector<aiMesh *>(); std::vector<aiMesh *> *meshes = new std::vector<aiMesh *>();
std::vector<aiFace> *faces = nullptr; std::vector<aiFace> *faces = nullptr;
@ -387,7 +354,7 @@ void M3DImporter::importMeshes()
aiMesh *pMesh = nullptr; aiMesh *pMesh = nullptr;
ai_assert(mScene != nullptr); ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr); ai_assert(m3d);
ai_assert(mScene->mRootNode != nullptr); ai_assert(mScene->mRootNode != nullptr);
ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface); ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface);
@ -397,7 +364,7 @@ void M3DImporter::importMeshes()
if (lastMat != m3d->face[i].materialid) { if (lastMat != m3d->face[i].materialid) {
lastMat = m3d->face[i].materialid; lastMat = m3d->face[i].materialid;
if (pMesh && vertices && vertices->size() && faces && faces->size()) { if (pMesh && vertices && vertices->size() && faces && faces->size()) {
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids);
meshes->push_back(pMesh); meshes->push_back(pMesh);
delete faces; delete faces;
delete vertices; delete vertices;
@ -422,7 +389,7 @@ void M3DImporter::importMeshes()
pFace->mIndices = new unsigned int[numpoly]; pFace->mIndices = new unsigned int[numpoly];
for (j = 0; j < numpoly; j++) { for (j = 0; j < numpoly; j++) {
aiVector3D pos, uv, norm; aiVector3D pos, uv, norm;
k = vertices->size(); k = static_cast<unsigned int>(vertices->size());
pFace->mIndices[j] = k; pFace->mIndices[j] = k;
l = m3d->face[i].vertex[j]; l = m3d->face[i].vertex[j];
pos.x = m3d->vertex[l].x; pos.x = m3d->vertex[l].x;
@ -456,17 +423,17 @@ void M3DImporter::importMeshes()
} }
// if there's data left in the temporary vectors, flush them // if there's data left in the temporary vectors, flush them
if (pMesh && vertices->size() && faces->size()) { if (pMesh && vertices->size() && faces->size()) {
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids);
meshes->push_back(pMesh); meshes->push_back(pMesh);
} }
// create global mesh list in scene // create global mesh list in scene
mScene->mNumMeshes = meshes->size(); mScene->mNumMeshes = static_cast<unsigned int>(meshes->size());
mScene->mMeshes = new aiMesh *[mScene->mNumMeshes]; mScene->mMeshes = new aiMesh *[mScene->mNumMeshes];
std::copy(meshes->begin(), meshes->end(), mScene->mMeshes); std::copy(meshes->begin(), meshes->end(), mScene->mMeshes);
// create mesh indeces in root node // create mesh indeces in root node
mScene->mRootNode->mNumMeshes = meshes->size(); mScene->mRootNode->mNumMeshes = static_cast<unsigned int>(meshes->size());
mScene->mRootNode->mMeshes = new unsigned int[meshes->size()]; mScene->mRootNode->mMeshes = new unsigned int[meshes->size()];
for (i = 0; i < meshes->size(); i++) { for (i = 0; i < meshes->size(); i++) {
mScene->mRootNode->mMeshes[i] = i; mScene->mRootNode->mMeshes[i] = i;
@ -483,13 +450,12 @@ void M3DImporter::importMeshes()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// a reentrant node parser. Otherwise this is simple // a reentrant node parser. Otherwise this is simple
void M3DImporter::importBones(unsigned int parentid, aiNode *pParent) void M3DImporter::importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent) {
{
unsigned int i, n; unsigned int i, n;
ai_assert(pParent != nullptr); ai_assert(pParent != nullptr);
ai_assert(mScene != nullptr); ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr); ai_assert(m3d);
ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid); ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid);
@ -502,11 +468,11 @@ void M3DImporter::importBones(unsigned int parentid, aiNode *pParent)
aiNode *pChild = new aiNode; aiNode *pChild = new aiNode;
pChild->mParent = pParent; pChild->mParent = pParent;
pChild->mName = aiString(std::string(m3d->bone[i].name)); pChild->mName = aiString(std::string(m3d->bone[i].name));
convertPose(&pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori); convertPose(m3d, &pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori);
pChild->mNumChildren = 0; pChild->mNumChildren = 0;
pParent->mChildren[pParent->mNumChildren] = pChild; pParent->mChildren[pParent->mNumChildren] = pChild;
pParent->mNumChildren++; pParent->mNumChildren++;
importBones(i, pChild); importBones(m3d, i, pChild);
} }
} }
} }
@ -515,14 +481,13 @@ void M3DImporter::importBones(unsigned int parentid, aiNode *pParent)
// this is another headache. M3D stores list of changed bone id/position/orientation triplets and // this is another headache. M3D stores list of changed bone id/position/orientation triplets and
// a timestamp per frame, but assimp needs timestamp and lists of position, orientation lists per // a timestamp per frame, but assimp needs timestamp and lists of position, orientation lists per
// bone, so we have to convert between the two conceptually different representation forms // bone, so we have to convert between the two conceptually different representation forms
void M3DImporter::importAnimations() void M3DImporter::importAnimations(const M3DWrapper &m3d) {
{
unsigned int i, j, k, l, pos, ori; unsigned int i, j, k, l, pos, ori;
double t; double t;
m3da_t *a; m3da_t *a;
ai_assert(mScene != nullptr); ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr); ai_assert(m3d);
mScene->mNumAnimations = m3d->numaction; mScene->mNumAnimations = m3d->numaction;
@ -589,10 +554,9 @@ aiColor4D M3DImporter::mkColor(uint32_t c) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// convert a position id and orientation id into a 4 x 4 transformation matrix // convert a position id and orientation id into a 4 x 4 transformation matrix
void M3DImporter::convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) void M3DImporter::convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) {
{
ai_assert(m != nullptr); ai_assert(m != nullptr);
ai_assert(m3d != nullptr); ai_assert(m3d);
ai_assert(posid != -1U && posid < m3d->numvertex); ai_assert(posid != -1U && posid < m3d->numvertex);
ai_assert(orientid != -1U && orientid < m3d->numvertex); ai_assert(orientid != -1U && orientid < m3d->numvertex);
m3dv_t *p = &m3d->vertex[posid]; m3dv_t *p = &m3d->vertex[posid];
@ -603,27 +567,40 @@ void M3DImporter::convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int o
m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0; m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0;
m->a1 = m->b2 = m->c3 = -1.0; m->a1 = m->b2 = m->c3 = -1.0;
} else { } else {
m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); if(m->a1 > -M3D_EPSILON && m->a1 < M3D_EPSILON) m->a1 = 0.0; m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z);
m->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 0.0; if (m->a1 > -M3D_EPSILON && m->a1 < M3D_EPSILON) m->a1 = 0.0;
m->a3 = 2 * (q->x * q->z + q->y * q->w); if(m->a3 > -M3D_EPSILON && m->a3 < M3D_EPSILON) m->a3 = 0.0; m->a2 = 2 * (q->x * q->y - q->z * q->w);
m->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 0.0; if (m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 0.0;
m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); if(m->b2 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 0.0; m->a3 = 2 * (q->x * q->z + q->y * q->w);
m->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -M3D_EPSILON && m->b3 < M3D_EPSILON) m->b3 = 0.0; if (m->a3 > -M3D_EPSILON && m->a3 < M3D_EPSILON) m->a3 = 0.0;
m->c1 = 2 * (q->x * q->z - q->y * q->w); if(m->c1 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 0.0; m->b1 = 2 * (q->x * q->y + q->z * q->w);
m->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -M3D_EPSILON && m->c2 < M3D_EPSILON) m->c2 = 0.0; if (m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 0.0;
m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); if(m->c3 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0; m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z);
if (m->b2 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 0.0;
m->b3 = 2 * (q->y * q->z - q->x * q->w);
if (m->b3 > -M3D_EPSILON && m->b3 < M3D_EPSILON) m->b3 = 0.0;
m->c1 = 2 * (q->x * q->z - q->y * q->w);
if (m->c1 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 0.0;
m->c2 = 2 * (q->y * q->z + q->x * q->w);
if (m->c2 > -M3D_EPSILON && m->c2 < M3D_EPSILON) m->c2 = 0.0;
m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y);
if (m->c3 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0;
} }
/* set translation */ /* set translation */
m->a4 = p->x; m->b4 = p->y; m->c4 = p->z; m->a4 = p->x;
m->b4 = p->y;
m->c4 = p->z;
m->d1 = 0; m->d2 = 0; m->d3 = 0; m->d4 = 1; m->d1 = 0;
m->d2 = 0;
m->d3 = 0;
m->d4 = 1;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// find a node by name // find a node by name
aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) {
{
unsigned int i; unsigned int i;
ai_assert(pNode != nullptr); ai_assert(pNode != nullptr);
@ -640,8 +617,7 @@ aiNode *M3DImporter::findNode(aiNode *pNode, aiString name)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// fills up offsetmatrix in mBones // fills up offsetmatrix in mBones
void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m) void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m) {
{
ai_assert(pNode != nullptr); ai_assert(pNode != nullptr);
ai_assert(mScene != nullptr); ai_assert(mScene != nullptr);
@ -657,7 +633,7 @@ void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m)
// because M3D has a global mesh, global vertex ids and stores materialid on the face, we need // because M3D has a global mesh, global vertex ids and stores materialid on the face, we need
// temporary lists to collect data for an aiMesh, which requires local arrays and local indeces // temporary lists to collect data for an aiMesh, which requires local arrays and local indeces
// this function fills up an aiMesh with those temporary lists // this function fills up an aiMesh with those temporary lists
void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *vertices, void M3DImporter::populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *vertices,
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) {
@ -668,16 +644,16 @@ void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::v
ai_assert(texcoords != nullptr); ai_assert(texcoords != nullptr);
ai_assert(colors != nullptr); ai_assert(colors != nullptr);
ai_assert(vertexids != nullptr); ai_assert(vertexids != nullptr);
ai_assert(m3d != nullptr); ai_assert(m3d);
ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(), ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(),
" numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone); " numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone);
if (vertices->size() && faces->size()) { if (vertices->size() && faces->size()) {
pMesh->mNumFaces = faces->size(); pMesh->mNumFaces = static_cast<unsigned int>(faces->size());
pMesh->mFaces = new aiFace[pMesh->mNumFaces]; pMesh->mFaces = new aiFace[pMesh->mNumFaces];
std::copy(faces->begin(), faces->end(), pMesh->mFaces); std::copy(faces->begin(), faces->end(), pMesh->mFaces);
pMesh->mNumVertices = vertices->size(); pMesh->mNumVertices = static_cast<unsigned int>(vertices->size());
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
std::copy(vertices->begin(), vertices->end(), pMesh->mVertices); std::copy(vertices->begin(), vertices->end(), pMesh->mVertices);
if (normals->size() == vertices->size()) { if (normals->size() == vertices->size()) {

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,22 +59,20 @@ 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;
@ -83,18 +80,18 @@ private:
//! \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);
}; };

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;
@ -70,11 +70,11 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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
} }
@ -136,7 +136,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
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();
@ -173,7 +173,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
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;
} }
@ -184,17 +184,26 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
*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++];
// Assume the transformation is affine
// manually move the mesh into the right coordinate system // manually move the mesh into the right coordinate system
const aiMatrix3x3 IT = aiMatrix3x3( (*it)->mTransformation ).Inverse().Transpose();
// Check for odd negative scale (mirror)
if (join_node->mTransformation.Determinant() < 0) {
// Reverse the mesh face winding order
FlipWindingOrderProcess::ProcessMesh(mesh);
}
// Update positions, normals and tangents
const aiMatrix3x3 IT = aiMatrix3x3(join_node->mTransformation).Inverse().Transpose();
for (unsigned int a = 0; a < mesh->mNumVertices; ++a) { for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
mesh->mVertices[a] *= (*it)->mTransformation; mesh->mVertices[a] *= join_node->mTransformation;
if (mesh->HasNormals()) if (mesh->HasNormals())
mesh->mNormals[a] *= IT; mesh->mNormals[a] *= IT;
@ -205,7 +214,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
} }
} }
} }
delete *it; // bye, node delete join_node; // bye, node
} }
delete[] join_master->mMeshes; delete[] join_master->mMeshes;
join_master->mMeshes = meshes; join_master->mMeshes = meshes;
@ -220,8 +229,8 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
if (!child_nodes.empty()) { if (!child_nodes.empty()) {
nd->mChildren = new aiNode *[child_nodes.size()]; nd->mChildren = new aiNode *[child_nodes.size()];
} } else
else nd->mChildren = nullptr; nd->mChildren = nullptr;
} }
nd->mNumChildren = static_cast<unsigned int>(child_nodes.size()); nd->mNumChildren = static_cast<unsigned int>(child_nodes.size());
@ -305,7 +314,7 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) {
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");
} }
@ -314,17 +323,16 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) {
// 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);
@ -338,8 +346,7 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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]];
} }

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.

View File

@ -45,11 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the "PretransformVertices" post processing step * @brief Implementation of the "PretransformVertices" post processing step
*/ */
#include "PretransformVertices.h" #include "PretransformVertices.h"
#include "ConvertToLHProcess.h"
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include <assimp/SceneCombiner.h>
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/SceneCombiner.h>
using namespace Assimp; using namespace Assimp;
@ -59,12 +59,12 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
PretransformVertices::PretransformVertices() PretransformVertices::PretransformVertices() :
: configKeepHierarchy (false) configKeepHierarchy(false),
, configNormalize(false) configNormalize(false),
, configTransform(false) configTransform(false),
, configTransformation() configTransformation(),
, mConfigPointCloud( false ) { mConfigPointCloud(false) {
// empty // empty
} }
@ -76,15 +76,13 @@ PretransformVertices::~PretransformVertices() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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 PretransformVertices::IsActive( unsigned int pFlags) const bool PretransformVertices::IsActive(unsigned int pFlags) const {
{
return (pFlags & aiProcess_PreTransformVertices) != 0; return (pFlags & aiProcess_PreTransformVertices) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup import configuration // Setup import configuration
void PretransformVertices::SetupProperties(const Importer* pImp) void PretransformVertices::SetupProperties(const Importer *pImp) {
{
// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE, // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE,
// AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION // AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION
configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0)); configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0));
@ -98,11 +96,9 @@ void PretransformVertices::SetupProperties(const Importer* pImp)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Count the number of nodes // Count the number of nodes
unsigned int PretransformVertices::CountNodes( aiNode* pcNode ) unsigned int PretransformVertices::CountNodes(const aiNode *pcNode) const {
{
unsigned int iRet = 1; unsigned int iRet = 1;
for (unsigned int i = 0;i < pcNode->mNumChildren;++i) for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
{
iRet += CountNodes(pcNode->mChildren[i]); iRet += CountNodes(pcNode->mChildren[i]);
} }
return iRet; return iRet;
@ -110,8 +106,7 @@ unsigned int PretransformVertices::CountNodes( aiNode* pcNode )
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a bitwise combination identifying the vertex format of a mesh // Get a bitwise combination identifying the vertex format of a mesh
unsigned int PretransformVertices::GetMeshVFormat( aiMesh* pcMesh ) unsigned int PretransformVertices::GetMeshVFormat(aiMesh *pcMesh) const {
{
// the vertex format is stored in aiMesh::mBones for later retrieval. // the vertex format is stored in aiMesh::mBones for later retrieval.
// there isn't a good reason to compute it a few hundred times // there isn't a good reason to compute it a few hundred times
// from scratch. The pointer is unused as animations are lost // from scratch. The pointer is unused as animations are lost
@ -119,7 +114,6 @@ unsigned int PretransformVertices::GetMeshVFormat( aiMesh* pcMesh )
if (pcMesh->mBones) if (pcMesh->mBones)
return (unsigned int)(uint64_t)pcMesh->mBones; return (unsigned int)(uint64_t)pcMesh->mBones;
const unsigned int iRet = GetMeshVFormatUnique(pcMesh); const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
// store the value for later use // store the value for later use
@ -130,20 +124,16 @@ unsigned int PretransformVertices::GetMeshVFormat( aiMesh* pcMesh )
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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 PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices) unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const {
{ for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) {
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
{
aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]]; aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]];
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) {
{
*piVertices += pcMesh->mNumVertices; *piVertices += pcMesh->mNumVertices;
*piFaces += pcMesh->mNumFaces; *piFaces += pcMesh->mNumFaces;
} }
} }
for (unsigned int i = 0;i < pcNode->mNumChildren;++i) for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
{
CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat,
iVFormat, piFaces, piVertices); iVFormat, piFaces, piVertices);
} }
@ -151,24 +141,20 @@ void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNo
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Collect vertex/face data // Collect vertex/face data
void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, void PretransformVertices::CollectData(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
unsigned int iVFormat, aiMesh *pcMeshOut, unsigned int iVFormat, aiMesh *pcMeshOut,
unsigned int aiCurrent[2], unsigned int* num_refs) unsigned int aiCurrent[2], unsigned int *num_refs) const {
{
// No need to multiply if there's no transformation // No need to multiply if there's no transformation
const bool identity = pcNode->mTransformation.IsIdentity(); const bool identity = pcNode->mTransformation.IsIdentity();
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) {
{
aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]]; aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]];
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) {
{
// Decrement mesh reference counter // Decrement mesh reference counter
unsigned int &num_ref = num_refs[pcNode->mMeshes[i]]; unsigned int &num_ref = num_refs[pcNode->mMeshes[i]];
ai_assert(0 != num_ref); ai_assert(0 != num_ref);
--num_ref; --num_ref;
// Save the name of the last mesh // Save the name of the last mesh
if (num_ref==0) if (num_ref == 0) {
{
pcMeshOut->mName = pcMesh->mName; pcMeshOut->mName = pcMesh->mName;
} }
@ -184,8 +170,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
pcMesh->mNormals, pcMesh->mNormals,
pcMesh->mNumVertices * sizeof(aiVector3D)); pcMesh->mNumVertices * sizeof(aiVector3D));
} }
if (iVFormat & 0x4) if (iVFormat & 0x4) {
{
// copy tangents without modifying them // copy tangents without modifying them
::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX], ::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX],
pcMesh->mTangents, pcMesh->mTangents,
@ -195,9 +180,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
pcMesh->mBitangents, pcMesh->mBitangents,
pcMesh->mNumVertices * sizeof(aiVector3D)); pcMesh->mNumVertices * sizeof(aiVector3D));
} }
} } else {
else
{
// copy positions, transform them to worldspace // copy positions, transform them to worldspace
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) { for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX] + n] = pcNode->mTransformation * pcMesh->mVertices[n]; pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX] + n] = pcNode->mTransformation * pcMesh->mVertices[n];
@ -208,16 +191,14 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
// TODO: implement Inverse() for aiMatrix3x3 // TODO: implement Inverse() for aiMatrix3x3
aiMatrix3x3 m = aiMatrix3x3(mWorldIT); aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
if (iVFormat & 0x2) if (iVFormat & 0x2) {
{
// copy normals, transform them to worldspace // copy normals, transform them to worldspace
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) { for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX] + n] = pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX] + n] =
(m * pcMesh->mNormals[n]).Normalize(); (m * pcMesh->mNormals[n]).Normalize();
} }
} }
if (iVFormat & 0x4) if (iVFormat & 0x4) {
{
// copy tangents and bitangents, transform them to worldspace // copy tangents and bitangents, transform them to worldspace
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) { for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
pcMeshOut->mTangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mTangents[n]).Normalize(); pcMeshOut->mTangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mTangents[n]).Normalize();
@ -226,8 +207,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
} }
} }
unsigned int p = 0; unsigned int p = 0;
while (iVFormat & (0x100 << p)) while (iVFormat & (0x100 << p)) {
{
// copy texture coordinates // copy texture coordinates
memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX], memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX],
pcMesh->mTextureCoords[p], pcMesh->mTextureCoords[p],
@ -235,8 +215,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
++p; ++p;
} }
p = 0; p = 0;
while (iVFormat & (0x1000000 << p)) while (iVFormat & (0x1000000 << p)) {
{
// copy vertex colors // copy vertex colors
memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX], memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX],
pcMesh->mColors[p], pcMesh->mColors[p],
@ -246,8 +225,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
// now we need to copy all faces. since we will delete the source mesh afterwards, // now we need to copy all faces. since we will delete the source mesh afterwards,
// we don't need to reallocate the array of indices except if this mesh is // we don't need to reallocate the array of indices except if this mesh is
// referenced multiple times. // referenced multiple times.
for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck) for (unsigned int planck = 0; planck < pcMesh->mNumFaces; ++planck) {
{
aiFace &f_src = pcMesh->mFaces[planck]; aiFace &f_src = pcMesh->mFaces[planck];
aiFace &f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE] + planck]; aiFace &f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE] + planck];
@ -263,8 +241,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
for (unsigned int hahn = 0; hahn < num_idx; ++hahn) { for (unsigned int hahn = 0; hahn < num_idx; ++hahn) {
pi[hahn] += aiCurrent[AI_PTVS_VERTEX]; pi[hahn] += aiCurrent[AI_PTVS_VERTEX];
} }
} } else {
else {
pi = f_dst.mIndices = new unsigned int[num_idx]; pi = f_dst.mIndices = new unsigned int[num_idx];
// copy and offset all vertex indices // copy and offset all vertex indices
@ -274,8 +251,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
} }
// Update the mPrimitiveTypes member of the mesh // Update the mPrimitiveTypes member of the mesh
switch (pcMesh->mFaces[planck].mNumIndices) switch (pcMesh->mFaces[planck].mNumIndices) {
{
case 0x1: case 0x1:
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT; pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT;
break; break;
@ -305,11 +281,9 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a list of all vertex formats that occur for a given material index // Get a list of all vertex formats that occur for a given material index
// The output list contains duplicate elements // The output list contains duplicate elements
void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat, void PretransformVertices::GetVFormatList(const aiScene *pcScene, unsigned int iMat,
std::list<unsigned int>& aiOut) std::list<unsigned int> &aiOut) const {
{ for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
{
aiMesh *pcMesh = pcScene->mMeshes[i]; aiMesh *pcMesh = pcScene->mMeshes[i];
if (iMat == pcMesh->mMaterialIndex) { if (iMat == pcMesh->mMaterialIndex) {
aiOut.push_back(GetMeshVFormat(pcMesh)); aiOut.push_back(GetMeshVFormat(pcMesh));
@ -319,8 +293,7 @@ void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Compute the absolute transformation matrices of each node // Compute the absolute transformation matrices of each node
void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode ) void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
{
if (pcNode->mParent) { if (pcNode->mParent) {
pcNode->mTransformation = pcNode->mParent->mTransformation * pcNode->mTransformation; pcNode->mTransformation = pcNode->mParent->mTransformation * pcNode->mTransformation;
} }
@ -332,22 +305,26 @@ void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode )
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Apply the node transformation to a mesh // Apply the node transformation to a mesh
void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat) void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const {
{
// Check whether we need to transform the coordinates at all // Check whether we need to transform the coordinates at all
if (!mat.IsIdentity()) { if (!mat.IsIdentity()) {
// Check for odd negative scale (mirror)
if (mesh->HasFaces() && mat.Determinant() < 0) {
// Reverse the mesh face winding order
FlipWindingOrderProcess::ProcessMesh(mesh);
}
// Update positions
if (mesh->HasPositions()) { if (mesh->HasPositions()) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
mesh->mVertices[i] = mat * mesh->mVertices[i]; mesh->mVertices[i] = mat * mesh->mVertices[i];
} }
} }
if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
aiMatrix4x4 mWorldIT = mat;
mWorldIT.Inverse().Transpose();
// TODO: implement Inverse() for aiMatrix3x3 // Update normals and tangents
aiMatrix3x3 m = aiMatrix3x3(mWorldIT); if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose();
if (mesh->HasNormals()) { if (mesh->HasNormals()) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
@ -367,8 +344,7 @@ void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Simple routine to build meshes in worldspace, no further optimization // Simple routine to build meshes in worldspace, no further optimization
void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in, void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in,
unsigned int numIn, aiNode* node) unsigned int numIn, aiNode *node) const {
{
// NOTE: // NOTE:
// aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy // aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy
// aiMesh::mBones store reference to abs. transform we multiplied with // aiMesh::mBones store reference to abs. transform we multiplied with
@ -382,8 +358,7 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in
// yes, we can. // yes, we can.
mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation); mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
mesh->mNumBones = UINT_MAX; mesh->mNumBones = UINT_MAX;
} } else {
else {
// try to find us in the list of newly created meshes // try to find us in the list of newly created meshes
for (unsigned int n = 0; n < out.size(); ++n) { for (unsigned int n = 0; n < out.size(); ++n) {
@ -421,8 +396,7 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reset transformation matrices to identity // Reset transformation matrices to identity
void PretransformVertices::MakeIdentityTransform(aiNode* nd) void PretransformVertices::MakeIdentityTransform(aiNode *nd) const {
{
nd->mTransformation = aiMatrix4x4(); nd->mTransformation = aiMatrix4x4();
// call children // call children
@ -432,8 +406,7 @@ void PretransformVertices::MakeIdentityTransform(aiNode* nd)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Build reference counters for all meshes // Build reference counters for all meshes
void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs) void PretransformVertices::BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const {
{
for (unsigned int i = 0; i < nd->mNumMeshes; ++i) for (unsigned int i = 0; i < nd->mNumMeshes; ++i)
refs[nd->mMeshes[i]]++; refs[nd->mMeshes[i]]++;
@ -444,8 +417,7 @@ void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * ref
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void PretransformVertices::Execute( aiScene* pScene) void PretransformVertices::Execute(aiScene *pScene) {
{
ASSIMP_LOG_DEBUG("PretransformVerticesProcess begin"); ASSIMP_LOG_DEBUG("PretransformVerticesProcess begin");
// Return immediately if we have no meshes // Return immediately if we have no meshes
@ -496,7 +468,8 @@ void PretransformVertices::Execute( aiScene* pScene)
memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * apcOutMeshes.size()); memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * apcOutMeshes.size());
pScene->mNumMeshes += static_cast<unsigned int>(apcOutMeshes.size()); pScene->mNumMeshes += static_cast<unsigned int>(apcOutMeshes.size());
delete[] pScene->mMeshes; pScene->mMeshes = npp; delete[] pScene->mMeshes;
pScene->mMeshes = npp;
} }
// now iterate through all meshes and transform them to worldspace // now iterate through all meshes and transform them to worldspace
@ -524,8 +497,7 @@ void PretransformVertices::Execute( aiScene* pScene)
unsigned int iVertices = 0; unsigned int iVertices = 0;
unsigned int iFaces = 0; unsigned int iFaces = 0;
CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices); CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices);
if (0 != iFaces && 0 != iVertices) if (0 != iFaces && 0 != iVertices) {
{
apcOutMeshes.push_back(new aiMesh()); apcOutMeshes.push_back(new aiMesh());
aiMesh *pcMesh = apcOutMeshes.back(); aiMesh *pcMesh = apcOutMeshes.back();
pcMesh->mNumFaces = iFaces; pcMesh->mNumFaces = iFaces;
@ -534,17 +506,17 @@ void PretransformVertices::Execute( aiScene* pScene)
pcMesh->mVertices = new aiVector3D[iVertices]; pcMesh->mVertices = new aiVector3D[iVertices];
pcMesh->mMaterialIndex = i; pcMesh->mMaterialIndex = i;
if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices]; if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices];
if ((*j) & 0x4) if ((*j) & 0x4) {
{
pcMesh->mTangents = new aiVector3D[iVertices]; pcMesh->mTangents = new aiVector3D[iVertices];
pcMesh->mBitangents = new aiVector3D[iVertices]; pcMesh->mBitangents = new aiVector3D[iVertices];
} }
iFaces = 0; iFaces = 0;
while ((*j) & (0x100 << iFaces)) while ((*j) & (0x100 << iFaces)) {
{
pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices];
if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3; if ((*j) & (0x10000 << iFaces))
else pcMesh->mNumUVComponents[iFaces] = 2; pcMesh->mNumUVComponents[iFaces] = 3;
else
pcMesh->mNumUVComponents[iFaces] = 2;
iFaces++; iFaces++;
} }
iFaces = 0; iFaces = 0;
@ -562,12 +534,9 @@ void PretransformVertices::Execute( aiScene* pScene)
if (apcOutMeshes.empty()) { if (apcOutMeshes.empty()) {
throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes"); throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes");
} } else {
else
{
// now delete all meshes in the scene and build a new mesh list // now delete all meshes in the scene and build a new mesh list
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
{
aiMesh *mesh = pScene->mMeshes[i]; aiMesh *mesh = pScene->mMeshes[i];
mesh->mNumBones = 0; mesh->mNumBones = 0;
mesh->mBones = NULL; mesh->mBones = NULL;
@ -606,8 +575,7 @@ void PretransformVertices::Execute( aiScene* pScene)
pScene->mNumAnimations = 0; pScene->mNumAnimations = 0;
// --- we need to keep all cameras and lights // --- we need to keep all cameras and lights
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];
const aiNode *nd = pScene->mRootNode->FindNode(cam->mName); const aiNode *nd = pScene->mRootNode->FindNode(cam->mName);
ai_assert(NULL != nd); ai_assert(NULL != nd);
@ -619,8 +587,7 @@ void PretransformVertices::Execute( aiScene* pScene)
cam->mUp = aiMatrix3x3(nd->mTransformation) * cam->mUp; cam->mUp = aiMatrix3x3(nd->mTransformation) * cam->mUp;
} }
for (unsigned int i = 0; i < pScene->mNumLights;++i) for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
{
aiLight *l = pScene->mLights[i]; aiLight *l = pScene->mLights[i];
const aiNode *nd = pScene->mRootNode->FindNode(l->mName); const aiNode *nd = pScene->mRootNode->FindNode(l->mName);
ai_assert(NULL != nd); ai_assert(NULL != nd);
@ -641,20 +608,16 @@ void PretransformVertices::Execute( aiScene* pScene)
delete pScene->mRootNode; delete pScene->mRootNode;
pScene->mRootNode = newRoot; pScene->mRootNode = newRoot;
if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) {
{
pScene->mRootNode->mNumMeshes = 1; pScene->mRootNode->mNumMeshes = 1;
pScene->mRootNode->mMeshes = new unsigned int[1]; pScene->mRootNode->mMeshes = new unsigned int[1];
pScene->mRootNode->mMeshes[0] = 0; pScene->mRootNode->mMeshes[0] = 0;
} } else {
else
{
pScene->mRootNode->mNumChildren = pScene->mNumMeshes + pScene->mNumLights + pScene->mNumCameras; pScene->mRootNode->mNumChildren = pScene->mNumMeshes + pScene->mNumLights + pScene->mNumCameras;
aiNode **nodes = pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren]; aiNode **nodes = pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
// generate mesh nodes // generate mesh nodes
for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes) for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++nodes) {
{
aiNode *pcNode = new aiNode(); aiNode *pcNode = new aiNode();
*nodes = pcNode; *nodes = pcNode;
pcNode->mParent = pScene->mRootNode; pcNode->mParent = pScene->mRootNode;
@ -666,8 +629,7 @@ void PretransformVertices::Execute( aiScene* pScene)
pcNode->mMeshes[0] = i; pcNode->mMeshes[0] = i;
} }
// generate light nodes // generate light nodes
for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes) for (unsigned int i = 0; i < pScene->mNumLights; ++i, ++nodes) {
{
aiNode *pcNode = new aiNode(); aiNode *pcNode = new aiNode();
*nodes = pcNode; *nodes = pcNode;
pcNode->mParent = pScene->mRootNode; pcNode->mParent = pScene->mRootNode;
@ -675,8 +637,7 @@ void PretransformVertices::Execute( aiScene* pScene)
pScene->mLights[i]->mName = pcNode->mName; pScene->mLights[i]->mName = pcNode->mName;
} }
// generate camera nodes // generate camera nodes
for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes) for (unsigned int i = 0; i < pScene->mNumCameras; ++i, ++nodes) {
{
aiNode *pcNode = new aiNode(); aiNode *pcNode = new aiNode();
*nodes = pcNode; *nodes = pcNode;
pcNode->mParent = pScene->mRootNode; pcNode->mParent = pScene->mRootNode;
@ -684,8 +645,7 @@ void PretransformVertices::Execute( aiScene* pScene)
pScene->mCameras[i]->mName = pcNode->mName; pScene->mCameras[i]->mName = pcNode->mName;
} }
} }
} } else {
else {
// ... and finally set the transformation matrix of all nodes to identity // ... and finally set the transformation matrix of all nodes to identity
MakeIdentityTransform(pScene->mRootNode); MakeIdentityTransform(pScene->mRootNode);
} }

View File

@ -73,15 +73,15 @@ public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// 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
@ -102,35 +102,35 @@ public:
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
@ -139,19 +139,19 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// 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;

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