Merge branch 'master' into fixTexcoord
commit
b6553b8a78
|
@ -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}")
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2019, assimp team
|
Copyright (c) 2006-2019, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -78,7 +76,6 @@ static const aiImporterDesc desc = {
|
||||||
"b3d"
|
"b3d"
|
||||||
};
|
};
|
||||||
|
|
||||||
// (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning (disable: 4018)
|
# pragma warning (disable: 4018)
|
||||||
#endif
|
#endif
|
||||||
|
@ -86,10 +83,8 @@ static const aiImporterDesc desc = {
|
||||||
//#define DEBUG_B3D
|
//#define DEBUG_B3D
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void DeleteAllBarePointers(std::vector<T>& x)
|
void DeleteAllBarePointers(std::vector<T>& x) {
|
||||||
{
|
for(auto p : x) {
|
||||||
for(auto p : x)
|
|
||||||
{
|
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,10 +97,14 @@ B3DImporter::~B3DImporter()
|
||||||
bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
|
bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
|
||||||
|
|
||||||
size_t pos=pFile.find_last_of( '.' );
|
size_t pos=pFile.find_last_of( '.' );
|
||||||
if( pos==string::npos ) return false;
|
if( pos==string::npos ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
string ext=pFile.substr( pos+1 );
|
string ext=pFile.substr( pos+1 );
|
||||||
if( ext.size()!=3 ) return false;
|
if( ext.size()!=3 ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
|
return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
|
||||||
}
|
}
|
||||||
|
@ -117,30 +116,21 @@ const aiImporterDesc* B3DImporter::GetInfo () const
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_B3D
|
|
||||||
extern "C"{ void _stdcall AllocConsole(); }
|
|
||||||
#endif
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){
|
void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){
|
||||||
|
|
||||||
#ifdef DEBUG_B3D
|
|
||||||
AllocConsole();
|
|
||||||
freopen( "conin$","r",stdin );
|
|
||||||
freopen( "conout$","w",stdout );
|
|
||||||
freopen( "conout$","w",stderr );
|
|
||||||
cout<<"Hello world from the B3DImporter!"<<endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
|
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
|
||||||
|
|
||||||
// Check whether we can read from the file
|
// Check whether we can read from the file
|
||||||
if( file.get() == NULL)
|
if( file.get() == nullptr) {
|
||||||
throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
|
throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
|
||||||
|
}
|
||||||
|
|
||||||
// check whether the .b3d file is large enough to contain
|
// check whether the .b3d file is large enough to contain
|
||||||
// at least one chunk.
|
// at least one chunk.
|
||||||
size_t fileSize = file->FileSize();
|
size_t fileSize = file->FileSize();
|
||||||
if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small.");
|
if( fileSize<8 ) {
|
||||||
|
throw DeadlyImportError( "B3D File is too small.");
|
||||||
|
}
|
||||||
|
|
||||||
_pos=0;
|
_pos=0;
|
||||||
_buf.resize( fileSize );
|
_buf.resize( fileSize );
|
||||||
|
@ -158,14 +148,17 @@ AI_WONT_RETURN void B3DImporter::Oops(){
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
AI_WONT_RETURN void B3DImporter::Fail( string str ){
|
AI_WONT_RETURN void B3DImporter::Fail( string str ){
|
||||||
#ifdef DEBUG_B3D
|
#ifdef DEBUG_B3D
|
||||||
cout<<"Error in B3D file data: "<<str<<endl;
|
ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
|
||||||
#endif
|
#endif
|
||||||
throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
|
throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
int B3DImporter::ReadByte(){
|
int B3DImporter::ReadByte(){
|
||||||
if( _pos<_buf.size() ) return _buf[_pos++];
|
if( _pos<_buf.size() ) {
|
||||||
|
return _buf[_pos++];
|
||||||
|
}
|
||||||
|
|
||||||
Fail( "EOF" );
|
Fail( "EOF" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -224,7 +217,9 @@ string B3DImporter::ReadString(){
|
||||||
string str;
|
string str;
|
||||||
while( _pos<_buf.size() ){
|
while( _pos<_buf.size() ){
|
||||||
char c=(char)ReadByte();
|
char c=(char)ReadByte();
|
||||||
if( !c ) return str;
|
if( !c ) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
str+=c;
|
str+=c;
|
||||||
}
|
}
|
||||||
Fail( "EOF" );
|
Fail( "EOF" );
|
||||||
|
@ -238,7 +233,7 @@ string B3DImporter::ReadChunk(){
|
||||||
tag+=char( ReadByte() );
|
tag+=char( ReadByte() );
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_B3D
|
#ifdef DEBUG_B3D
|
||||||
// cout<<"ReadChunk:"<<tag<<endl;
|
ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
|
||||||
#endif
|
#endif
|
||||||
unsigned sz=(unsigned)ReadInt();
|
unsigned sz=(unsigned)ReadInt();
|
||||||
_stack.push_back( _pos+sz );
|
_stack.push_back( _pos+sz );
|
||||||
|
@ -269,7 +264,6 @@ T *B3DImporter::to_array( const vector<T> &v ){
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
template<class T>
|
template<class T>
|
||||||
T **unique_to_array( vector<std::unique_ptr<T> > &v ){
|
T **unique_to_array( vector<std::unique_ptr<T> > &v ){
|
||||||
|
@ -283,7 +277,6 @@ T **unique_to_array( vector<std::unique_ptr<T> > &v ){
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void B3DImporter::ReadTEXS(){
|
void B3DImporter::ReadTEXS(){
|
||||||
while( ChunkSize() ){
|
while( ChunkSize() ){
|
||||||
|
@ -376,9 +369,13 @@ void B3DImporter::ReadVRTS(){
|
||||||
|
|
||||||
v.vertex=ReadVec3();
|
v.vertex=ReadVec3();
|
||||||
|
|
||||||
if( _vflags & 1 ) v.normal=ReadVec3();
|
if( _vflags & 1 ) {
|
||||||
|
v.normal=ReadVec3();
|
||||||
|
}
|
||||||
|
|
||||||
if( _vflags & 2 ) ReadQuat(); //skip v 4bytes...
|
if( _vflags & 2 ) {
|
||||||
|
ReadQuat(); //skip v 4bytes...
|
||||||
|
}
|
||||||
|
|
||||||
for( int i=0;i<_tcsets;++i ){
|
for( int i=0;i<_tcsets;++i ){
|
||||||
float t[4]={0,0,0,0};
|
float t[4]={0,0,0,0};
|
||||||
|
@ -386,53 +383,55 @@ void B3DImporter::ReadVRTS(){
|
||||||
t[j]=ReadFloat();
|
t[j]=ReadFloat();
|
||||||
}
|
}
|
||||||
t[1]=1-t[1];
|
t[1]=1-t[1];
|
||||||
if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] );
|
if( !i ) {
|
||||||
|
v.texcoords=aiVector3D( t[0],t[1],t[2] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void B3DImporter::ReadTRIS( int v0 ){
|
void B3DImporter::ReadTRIS(int v0) {
|
||||||
int matid=ReadInt();
|
int matid = ReadInt();
|
||||||
if( matid==-1 ){
|
if (matid == -1) {
|
||||||
matid=0;
|
matid = 0;
|
||||||
}else if( matid<0 || matid>=(int)_materials.size() ){
|
} else if (matid < 0 || matid >= (int)_materials.size()) {
|
||||||
#ifdef DEBUG_B3D
|
#ifdef DEBUG_B3D
|
||||||
cout<<"material id="<<matid<<endl;
|
ASSIMP_LOG_ERROR_F("material id=", matid);
|
||||||
#endif
|
#endif
|
||||||
Fail( "Bad material id" );
|
Fail("Bad material id");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<aiMesh> mesh(new aiMesh);
|
std::unique_ptr<aiMesh> mesh(new aiMesh);
|
||||||
|
|
||||||
mesh->mMaterialIndex=matid;
|
mesh->mMaterialIndex = matid;
|
||||||
mesh->mNumFaces=0;
|
mesh->mNumFaces = 0;
|
||||||
mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE;
|
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||||
|
|
||||||
int n_tris=ChunkSize()/12;
|
int n_tris = ChunkSize() / 12;
|
||||||
aiFace *face=mesh->mFaces=new aiFace[n_tris];
|
aiFace *face = mesh->mFaces = new aiFace[n_tris];
|
||||||
|
|
||||||
for( int i=0;i<n_tris;++i ){
|
for (int i = 0; i < n_tris; ++i) {
|
||||||
int i0=ReadInt()+v0;
|
int i0 = ReadInt() + v0;
|
||||||
int i1=ReadInt()+v0;
|
int i1 = ReadInt() + v0;
|
||||||
int i2=ReadInt()+v0;
|
int i2 = ReadInt() + v0;
|
||||||
if( i0<0 || i0>=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){
|
if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) {
|
||||||
#ifdef DEBUG_B3D
|
#ifdef DEBUG_B3D
|
||||||
cout<<"Bad triangle index: i0="<<i0<<", i1="<<i1<<", i2="<<i2<<endl;
|
ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
|
||||||
#endif
|
#endif
|
||||||
Fail( "Bad triangle index" );
|
Fail("Bad triangle index");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
face->mNumIndices=3;
|
face->mNumIndices = 3;
|
||||||
face->mIndices=new unsigned[3];
|
face->mIndices = new unsigned[3];
|
||||||
face->mIndices[0]=i0;
|
face->mIndices[0] = i0;
|
||||||
face->mIndices[1]=i1;
|
face->mIndices[1] = i1;
|
||||||
face->mIndices[2]=i2;
|
face->mIndices[2] = i2;
|
||||||
++mesh->mNumFaces;
|
++mesh->mNumFaces;
|
||||||
++face;
|
++face;
|
||||||
}
|
}
|
||||||
|
|
||||||
_meshes.emplace_back( std::move(mesh) );
|
_meshes.emplace_back(std::move(mesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -453,28 +452,22 @@ void B3DImporter::ReadMESH(){
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void B3DImporter::ReadBONE( int id ){
|
void B3DImporter::ReadBONE(int id) {
|
||||||
while( ChunkSize() ){
|
while (ChunkSize()) {
|
||||||
int vertex=ReadInt();
|
int vertex = ReadInt();
|
||||||
float weight=ReadFloat();
|
float weight = ReadFloat();
|
||||||
if( vertex<0 || vertex>=(int)_vertices.size() ){
|
if (vertex < 0 || vertex >= (int)_vertices.size()) {
|
||||||
Fail( "Bad vertex index" );
|
Fail("Bad vertex index");
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex &v=_vertices[vertex];
|
Vertex &v = _vertices[vertex];
|
||||||
int i;
|
for (int i = 0; i < 4; ++i) {
|
||||||
for( i=0;i<4;++i ){
|
if (!v.weights[i]) {
|
||||||
if( !v.weights[i] ){
|
v.bones[i] = id;
|
||||||
v.bones[i]=id;
|
v.weights[i] = weight;
|
||||||
v.weights[i]=weight;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_B3D
|
|
||||||
if( i==4 ){
|
|
||||||
cout<<"Too many bone weights"<<endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,11 +626,15 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
|
||||||
}
|
}
|
||||||
ExitChunk();
|
ExitChunk();
|
||||||
|
|
||||||
if( !_nodes.size() ) Fail( "No nodes" );
|
if( !_nodes.size() ) {
|
||||||
|
Fail( "No nodes" );
|
||||||
|
}
|
||||||
|
|
||||||
if( !_meshes.size() ) Fail( "No meshes" );
|
if( !_meshes.size() ) {
|
||||||
|
Fail( "No meshes" );
|
||||||
|
}
|
||||||
|
|
||||||
//Fix nodes/meshes/bones
|
// Fix nodes/meshes/bones
|
||||||
for(size_t i=0;i<_nodes.size();++i ){
|
for(size_t i=0;i<_nodes.size();++i ){
|
||||||
aiNode *node=_nodes[i];
|
aiNode *node=_nodes[i];
|
||||||
|
|
||||||
|
@ -648,8 +645,12 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
|
||||||
int n_verts=mesh->mNumVertices=n_tris * 3;
|
int n_verts=mesh->mNumVertices=n_tris * 3;
|
||||||
|
|
||||||
aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0;
|
aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0;
|
||||||
if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ];
|
if( _vflags & 1 ) {
|
||||||
if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
|
mn=mesh->mNormals=new aiVector3D[ n_verts ];
|
||||||
|
}
|
||||||
|
if( _tcsets ) {
|
||||||
|
mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
|
||||||
|
}
|
||||||
|
|
||||||
aiFace *face=mesh->mFaces;
|
aiFace *face=mesh->mFaces;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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)];
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,105 +82,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation
|
* - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation
|
||||||
* triplets, instead of per bone timestamp + lists)
|
* triplets, instead of per bone timestamp + lists)
|
||||||
*/
|
*/
|
||||||
using namespace Assimp;
|
|
||||||
|
|
||||||
namespace Assimp {
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
// Worker function for exporting a scene to binary M3D.
|
|
||||||
// Prototyped and registered in Exporter.cpp
|
|
||||||
void ExportSceneM3D (
|
|
||||||
const char* pFile,
|
|
||||||
IOSystem* pIOSystem,
|
|
||||||
const aiScene* pScene,
|
|
||||||
const ExportProperties* pProperties
|
|
||||||
){
|
|
||||||
// initialize the exporter
|
|
||||||
M3DExporter exporter(pScene, pProperties);
|
|
||||||
|
|
||||||
// perform binary export
|
|
||||||
exporter.doExport(pFile, pIOSystem, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
// Worker function for exporting a scene to ASCII A3D.
|
|
||||||
// Prototyped and registered in Exporter.cpp
|
|
||||||
void ExportSceneA3D (
|
|
||||||
const char* pFile,
|
|
||||||
IOSystem* pIOSystem,
|
|
||||||
const aiScene* pScene,
|
|
||||||
const ExportProperties* pProperties
|
|
||||||
|
|
||||||
){
|
|
||||||
// initialize the exporter
|
|
||||||
M3DExporter exporter(pScene, pProperties);
|
|
||||||
|
|
||||||
// perform ascii export
|
|
||||||
exporter.doExport(pFile, pIOSystem, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end of namespace Assimp
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
M3DExporter::M3DExporter ( const aiScene* pScene, const ExportProperties* pProperties )
|
// Conversion functions
|
||||||
: mScene(pScene)
|
|
||||||
, mProperties(pProperties)
|
|
||||||
, outfile()
|
|
||||||
, m3d(nullptr) { }
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
void M3DExporter::doExport (
|
|
||||||
const char* pFile,
|
|
||||||
IOSystem* pIOSystem,
|
|
||||||
bool toAscii
|
|
||||||
){
|
|
||||||
// TODO: convert mProperties into M3D_EXP_* flags
|
|
||||||
(void)mProperties;
|
|
||||||
|
|
||||||
// open the indicated file for writing (in binary / ASCII mode)
|
|
||||||
outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb"));
|
|
||||||
if (!outfile) {
|
|
||||||
throw DeadlyExportError( "could not open output .m3d file: " + std::string(pFile) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// use malloc() here because m3d_free() will call free()
|
|
||||||
m3d = (m3d_t*)calloc(1, sizeof(m3d_t));
|
|
||||||
if(!m3d) {
|
|
||||||
throw DeadlyExportError( "memory allocation error" );
|
|
||||||
}
|
|
||||||
m3d->name = _m3d_safestr((char*)&mScene->mRootNode->mName.data, 2);
|
|
||||||
|
|
||||||
// Create a model from assimp structures
|
|
||||||
aiMatrix4x4 m;
|
|
||||||
NodeWalk(mScene->mRootNode, m);
|
|
||||||
|
|
||||||
// serialize the structures
|
|
||||||
unsigned int size;
|
|
||||||
unsigned char *output = m3d_save(m3d, M3D_EXP_FLOAT,
|
|
||||||
M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), &size);
|
|
||||||
m3d_free(m3d);
|
|
||||||
if(!output || size < 8) {
|
|
||||||
throw DeadlyExportError( "unable to serialize into Model 3D" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out serialized model
|
|
||||||
outfile->Write(output, size, 1);
|
|
||||||
|
|
||||||
// explicitly release file pointer,
|
|
||||||
// so we don't have to rely on class destruction.
|
|
||||||
outfile.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// helper to add a vertex (private to NodeWalk)
|
// helper to add a vertex (private to NodeWalk)
|
||||||
m3dv_t *M3DExporter::AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx)
|
m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) {
|
||||||
{
|
if (v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0;
|
||||||
if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0;
|
if (v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0;
|
||||||
if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0;
|
if (v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0;
|
||||||
if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0;
|
if (v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
|
||||||
if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
|
vrtx = (m3dv_t *)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
|
||||||
vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
|
|
||||||
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
|
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
|
||||||
*idx = *numvrtx;
|
*idx = *numvrtx;
|
||||||
(*numvrtx)++;
|
(*numvrtx)++;
|
||||||
|
@ -187,9 +101,8 @@ m3dv_t *M3DExporter::AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// helper to add a tmap (private to NodeWalk)
|
// helper to add a tmap (private to NodeWalk)
|
||||||
m3dti_t *M3DExporter::AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx)
|
m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx) {
|
||||||
{
|
tmap = (m3dti_t *)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
|
||||||
tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
|
|
||||||
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
|
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
|
||||||
*idx = *numtmap;
|
*idx = *numtmap;
|
||||||
(*numtmap)++;
|
(*numtmap)++;
|
||||||
|
@ -197,154 +110,84 @@ m3dti_t *M3DExporter::AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uin
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// recursive node walker
|
// convert aiColor4D into uint32_t
|
||||||
void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
|
uint32_t mkColor(aiColor4D *c) {
|
||||||
{
|
return ((uint8_t)(c->a * 255) << 24L) |
|
||||||
aiMatrix4x4 nm = m * pNode->mTransformation;
|
((uint8_t)(c->b * 255) << 16L) |
|
||||||
|
((uint8_t)(c->g * 255) << 8L) |
|
||||||
for(unsigned int i = 0; i < pNode->mNumMeshes; i++) {
|
((uint8_t)(c->r * 255) << 0L);
|
||||||
const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]];
|
|
||||||
unsigned int mi = (M3D_INDEX)-1U;
|
|
||||||
if(mScene->mMaterials) {
|
|
||||||
// get the material for this mesh
|
|
||||||
mi = addMaterial(mScene->mMaterials[mesh->mMaterialIndex]);
|
|
||||||
}
|
|
||||||
// iterate through the mesh faces
|
|
||||||
for(unsigned int j = 0; j < mesh->mNumFaces; j++) {
|
|
||||||
unsigned int n;
|
|
||||||
const aiFace* face = &(mesh->mFaces[j]);
|
|
||||||
// only triangle meshes supported for now
|
|
||||||
if(face->mNumIndices != 3) {
|
|
||||||
throw DeadlyExportError( "use aiProcess_Triangulate before export" );
|
|
||||||
}
|
|
||||||
// add triangle to the output
|
|
||||||
n = m3d->numface++;
|
|
||||||
m3d->face = (m3df_t*)M3D_REALLOC(m3d->face,
|
|
||||||
m3d->numface * sizeof(m3df_t));
|
|
||||||
if(!m3d->face) {
|
|
||||||
throw DeadlyExportError( "memory allocation error" );
|
|
||||||
}
|
|
||||||
/* set all index to -1 by default */
|
|
||||||
m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] =
|
|
||||||
m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] =
|
|
||||||
m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = -1U;
|
|
||||||
m3d->face[n].materialid = mi;
|
|
||||||
for(unsigned int k = 0; k < face->mNumIndices; k++) {
|
|
||||||
// get the vertex's index
|
|
||||||
unsigned int l = face->mIndices[k];
|
|
||||||
unsigned int idx;
|
|
||||||
m3dv_t vertex;
|
|
||||||
m3dti_t ti;
|
|
||||||
// multiply the position vector by the transformation matrix
|
|
||||||
aiVector3D v = mesh->mVertices[l];
|
|
||||||
v *= nm;
|
|
||||||
vertex.x = v.x;
|
|
||||||
vertex.y = v.y;
|
|
||||||
vertex.z = v.z;
|
|
||||||
vertex.w = 1.0;
|
|
||||||
vertex.color = 0;
|
|
||||||
vertex.skinid = -1U;
|
|
||||||
// add color if defined
|
|
||||||
if(mesh->HasVertexColors(0))
|
|
||||||
vertex.color = mkColor(&mesh->mColors[0][l]);
|
|
||||||
// save the vertex to the output
|
|
||||||
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex,
|
|
||||||
&vertex, &idx);
|
|
||||||
m3d->face[n].vertex[k] = (M3D_INDEX)idx;
|
|
||||||
// do we have texture coordinates?
|
|
||||||
if(mesh->HasTextureCoords(0)) {
|
|
||||||
ti.u = mesh->mTextureCoords[0][l].x;
|
|
||||||
ti.v = mesh->mTextureCoords[0][l].y;
|
|
||||||
m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx);
|
|
||||||
m3d->face[n].texcoord[k] = (M3D_INDEX)idx;
|
|
||||||
}
|
|
||||||
// do we have normal vectors?
|
|
||||||
if(mesh->HasNormals()) {
|
|
||||||
vertex.x = mesh->mNormals[l].x;
|
|
||||||
vertex.y = mesh->mNormals[l].y;
|
|
||||||
vertex.z = mesh->mNormals[l].z;
|
|
||||||
vertex.color = 0;
|
|
||||||
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx);
|
|
||||||
m3d->face[n].normal[k] = (M3D_INDEX)idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// repeat for the children nodes
|
|
||||||
for (unsigned int i = 0; i < pNode->mNumChildren; i++) {
|
|
||||||
NodeWalk(pNode->mChildren[i], nm);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// convert aiColor4D into uint32_t
|
// add a material property to the output
|
||||||
uint32_t M3DExporter::mkColor(aiColor4D* c)
|
void addProp(m3dm_t *m, uint8_t type, uint32_t value) {
|
||||||
{
|
unsigned int i;
|
||||||
return ((uint8_t)(c->a*255) << 24L) |
|
i = m->numprop++;
|
||||||
((uint8_t)(c->b*255) << 16L) |
|
m->prop = (m3dp_t *)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t));
|
||||||
((uint8_t)(c->g*255) << 8L) |
|
if (!m->prop) {
|
||||||
((uint8_t)(c->r*255) << 0L);
|
throw DeadlyExportError("memory allocation error");
|
||||||
|
}
|
||||||
|
m->prop[i].type = type;
|
||||||
|
m->prop[i].value.num = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// add a material to the output
|
// add a material to the output
|
||||||
M3D_INDEX M3DExporter::addMaterial(const aiMaterial *mat)
|
M3D_INDEX addMaterial(const Assimp::M3DWrapper &m3d, const aiMaterial *mat) {
|
||||||
{
|
|
||||||
unsigned int mi = -1U;
|
unsigned int mi = -1U;
|
||||||
aiColor4D c;
|
aiColor4D c;
|
||||||
aiString name;
|
aiString name;
|
||||||
ai_real f;
|
ai_real f;
|
||||||
char *fn;
|
char *fn;
|
||||||
|
|
||||||
if(mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length &&
|
if (mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length &&
|
||||||
strcmp((char*)&name.data, AI_DEFAULT_MATERIAL_NAME)) {
|
strcmp((char *)&name.data, AI_DEFAULT_MATERIAL_NAME)) {
|
||||||
// check if we have saved a material by this name. This has to be done
|
// 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
|
// because only the referenced materials should be added to the output
|
||||||
for(unsigned int i = 0; i < m3d->nummaterial; i++)
|
for (unsigned int i = 0; i < m3d->nummaterial; i++)
|
||||||
if(!strcmp((char*)&name.data, m3d->material[i].name)) {
|
if (!strcmp((char *)&name.data, m3d->material[i].name)) {
|
||||||
mi = i;
|
mi = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// if not found, add the material to the output
|
// if not found, add the material to the output
|
||||||
if(mi == -1U) {
|
if (mi == -1U) {
|
||||||
unsigned int k;
|
unsigned int k;
|
||||||
mi = m3d->nummaterial++;
|
mi = m3d->nummaterial++;
|
||||||
m3d->material = (m3dm_t*)M3D_REALLOC(m3d->material, m3d->nummaterial
|
m3d->material = (m3dm_t *)M3D_REALLOC(m3d->material, m3d->nummaterial * sizeof(m3dm_t));
|
||||||
* sizeof(m3dm_t));
|
if (!m3d->material) {
|
||||||
if(!m3d->material) {
|
throw DeadlyExportError("memory allocation error");
|
||||||
throw DeadlyExportError( "memory allocation error" );
|
|
||||||
}
|
}
|
||||||
m3d->material[mi].name = _m3d_safestr((char*)&name.data, 0);
|
m3d->material[mi].name = _m3d_safestr((char *)&name.data, 0);
|
||||||
m3d->material[mi].numprop = 0;
|
m3d->material[mi].numprop = 0;
|
||||||
m3d->material[mi].prop = NULL;
|
m3d->material[mi].prop = NULL;
|
||||||
// iterate through the material property table and see what we got
|
// iterate through the material property table and see what we got
|
||||||
for(k = 0; k < 15; k++) {
|
for (k = 0; k < 15; k++) {
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
if(m3d_propertytypes[k].format == m3dpf_map)
|
if (m3d_propertytypes[k].format == m3dpf_map)
|
||||||
continue;
|
continue;
|
||||||
if(aiProps[k].pKey) {
|
if (aiProps[k].pKey) {
|
||||||
switch(m3d_propertytypes[k].format) {
|
switch (m3d_propertytypes[k].format) {
|
||||||
case m3dpf_color:
|
case m3dpf_color:
|
||||||
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
|
if (mat->Get(aiProps[k].pKey, aiProps[k].type,
|
||||||
aiProps[k].index, c) == AI_SUCCESS)
|
aiProps[k].index, c) == AI_SUCCESS)
|
||||||
addProp(&m3d->material[mi],
|
addProp(&m3d->material[mi],
|
||||||
m3d_propertytypes[k].id, mkColor(&c));
|
m3d_propertytypes[k].id, mkColor(&c));
|
||||||
break;
|
break;
|
||||||
case m3dpf_float:
|
case m3dpf_float:
|
||||||
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
|
if (mat->Get(aiProps[k].pKey, aiProps[k].type,
|
||||||
aiProps[k].index, f) == AI_SUCCESS)
|
aiProps[k].index, f) == AI_SUCCESS)
|
||||||
addProp(&m3d->material[mi],
|
addProp(&m3d->material[mi],
|
||||||
m3d_propertytypes[k].id,
|
m3d_propertytypes[k].id,
|
||||||
/* not (uint32_t)f, because we don't want to convert
|
/* not (uint32_t)f, because we don't want to convert
|
||||||
* it, we want to see it as 32 bits of memory */
|
* it, we want to see it as 32 bits of memory */
|
||||||
*((uint32_t*)&f));
|
*((uint32_t *)&f));
|
||||||
break;
|
break;
|
||||||
case m3dpf_uint8:
|
case m3dpf_uint8:
|
||||||
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
|
if (mat->Get(aiProps[k].pKey, aiProps[k].type,
|
||||||
aiProps[k].index, j) == AI_SUCCESS) {
|
aiProps[k].index, j) == AI_SUCCESS) {
|
||||||
// special conversion for illumination model property
|
// special conversion for illumination model property
|
||||||
if(m3d_propertytypes[k].id == m3dp_il) {
|
if (m3d_propertytypes[k].id == m3dp_il) {
|
||||||
switch(j) {
|
switch (j) {
|
||||||
case aiShadingMode_NoShading: j = 0; break;
|
case aiShadingMode_NoShading: j = 0; break;
|
||||||
case aiShadingMode_Phong: j = 2; break;
|
case aiShadingMode_Phong: j = 2; break;
|
||||||
default: j = 1; break;
|
default: j = 1; break;
|
||||||
|
@ -355,39 +198,40 @@ M3D_INDEX M3DExporter::addMaterial(const aiMaterial *mat)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
|
if (mat->Get(aiProps[k].pKey, aiProps[k].type,
|
||||||
aiProps[k].index, j) == AI_SUCCESS)
|
aiProps[k].index, j) == AI_SUCCESS)
|
||||||
addProp(&m3d->material[mi],
|
addProp(&m3d->material[mi],
|
||||||
m3d_propertytypes[k].id, j);
|
m3d_propertytypes[k].id, j);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(aiTxProps[k].pKey &&
|
if (aiTxProps[k].pKey &&
|
||||||
mat->GetTexture((aiTextureType)aiTxProps[k].type,
|
mat->GetTexture((aiTextureType)aiTxProps[k].type,
|
||||||
aiTxProps[k].index, &name, NULL, NULL, NULL,
|
aiTxProps[k].index, &name, NULL, NULL, NULL,
|
||||||
NULL, NULL) == AI_SUCCESS) {
|
NULL, NULL) == AI_SUCCESS) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for(j = name.length-1; j > 0 && name.data[j]!='.'; j++);
|
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') &&
|
if (j && name.data[j] == '.' &&
|
||||||
(name.data[j+1]=='n' || name.data[j+1]=='N') &&
|
(name.data[j + 1] == 'p' || name.data[j + 1] == 'P') &&
|
||||||
(name.data[j+1]=='g' || name.data[j+1]=='G'))
|
(name.data[j + 1] == 'n' || name.data[j + 1] == 'N') &&
|
||||||
name.data[j]=0;
|
(name.data[j + 1] == 'g' || name.data[j + 1] == 'G'))
|
||||||
|
name.data[j] = 0;
|
||||||
// do we have this texture saved already?
|
// do we have this texture saved already?
|
||||||
fn = _m3d_safestr((char*)&name.data, 0);
|
fn = _m3d_safestr((char *)&name.data, 0);
|
||||||
for(j = 0, i = -1U; j < m3d->numtexture; j++)
|
for (j = 0, i = -1U; j < m3d->numtexture; j++)
|
||||||
if(!strcmp(fn, m3d->texture[j].name)) {
|
if (!strcmp(fn, m3d->texture[j].name)) {
|
||||||
i = j;
|
i = j;
|
||||||
free(fn);
|
free(fn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(i == -1U) {
|
if (i == -1U) {
|
||||||
i = m3d->numtexture++;
|
i = m3d->numtexture++;
|
||||||
m3d->texture = (m3dtx_t*)M3D_REALLOC(
|
m3d->texture = (m3dtx_t *)M3D_REALLOC(
|
||||||
m3d->texture,
|
m3d->texture,
|
||||||
m3d->numtexture * sizeof(m3dtx_t));
|
m3d->numtexture * sizeof(m3dtx_t));
|
||||||
if(!m3d->texture) {
|
if (!m3d->texture) {
|
||||||
throw DeadlyExportError( "memory allocation error" );
|
throw DeadlyExportError("memory allocation error");
|
||||||
}
|
}
|
||||||
// we don't need the texture itself, only its name
|
// we don't need the texture itself, only its name
|
||||||
m3d->texture[i].name = fn;
|
m3d->texture[i].name = fn;
|
||||||
|
@ -404,17 +248,165 @@ M3D_INDEX M3DExporter::addMaterial(const aiMaterial *mat)
|
||||||
return mi;
|
return mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
namespace Assimp {
|
||||||
// add a material property to the output
|
|
||||||
void M3DExporter::addProp(m3dm_t *m, uint8_t type, uint32_t value)
|
// ---------------------------------------------------------------------
|
||||||
{
|
// Worker function for exporting a scene to binary M3D.
|
||||||
unsigned int i;
|
// Prototyped and registered in Exporter.cpp
|
||||||
i = m->numprop++;
|
void ExportSceneM3D(
|
||||||
m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t));
|
const char *pFile,
|
||||||
if(!m->prop) { throw DeadlyExportError( "memory allocation error" ); }
|
IOSystem *pIOSystem,
|
||||||
m->prop[i].type = type;
|
const aiScene *pScene,
|
||||||
m->prop[i].value.num = value;
|
const ExportProperties *pProperties) {
|
||||||
|
// initialize the exporter
|
||||||
|
M3DExporter exporter(pScene, pProperties);
|
||||||
|
|
||||||
|
// perform binary export
|
||||||
|
exporter.doExport(pFile, pIOSystem, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Worker function for exporting a scene to ASCII A3D.
|
||||||
|
// Prototyped and registered in Exporter.cpp
|
||||||
|
void ExportSceneA3D(
|
||||||
|
const char *pFile,
|
||||||
|
IOSystem *pIOSystem,
|
||||||
|
const aiScene *pScene,
|
||||||
|
const ExportProperties *pProperties
|
||||||
|
|
||||||
|
) {
|
||||||
|
// initialize the exporter
|
||||||
|
M3DExporter exporter(pScene, pProperties);
|
||||||
|
|
||||||
|
// perform ascii export
|
||||||
|
exporter.doExport(pFile, pIOSystem, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
M3DExporter::M3DExporter(const aiScene *pScene, const ExportProperties *pProperties) :
|
||||||
|
mScene(pScene),
|
||||||
|
mProperties(pProperties),
|
||||||
|
outfile() {}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void M3DExporter::doExport(
|
||||||
|
const char *pFile,
|
||||||
|
IOSystem *pIOSystem,
|
||||||
|
bool toAscii) {
|
||||||
|
// TODO: convert mProperties into M3D_EXP_* flags
|
||||||
|
(void)mProperties;
|
||||||
|
|
||||||
|
// open the indicated file for writing (in binary / ASCII mode)
|
||||||
|
outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb"));
|
||||||
|
if (!outfile) {
|
||||||
|
throw DeadlyExportError("could not open output .m3d file: " + std::string(pFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
M3DWrapper m3d;
|
||||||
|
if (!m3d) {
|
||||||
|
throw DeadlyExportError("memory allocation error");
|
||||||
|
}
|
||||||
|
m3d->name = _m3d_safestr((char *)&mScene->mRootNode->mName.data, 2);
|
||||||
|
|
||||||
|
// Create a model from assimp structures
|
||||||
|
aiMatrix4x4 m;
|
||||||
|
NodeWalk(m3d, mScene->mRootNode, m);
|
||||||
|
|
||||||
|
// serialize the structures
|
||||||
|
unsigned int size;
|
||||||
|
unsigned char *output = m3d.Save(M3D_EXP_FLOAT, M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), size);
|
||||||
|
|
||||||
|
if (!output || size < 8) {
|
||||||
|
throw DeadlyExportError("unable to serialize into Model 3D");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write out serialized model
|
||||||
|
outfile->Write(output, size, 1);
|
||||||
|
|
||||||
|
// explicitly release file pointer,
|
||||||
|
// so we don't have to rely on class destruction.
|
||||||
|
outfile.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// recursive node walker
|
||||||
|
void M3DExporter::NodeWalk(const M3DWrapper &m3d, const aiNode *pNode, aiMatrix4x4 m) {
|
||||||
|
aiMatrix4x4 nm = m * pNode->mTransformation;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < pNode->mNumMeshes; i++) {
|
||||||
|
const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]];
|
||||||
|
unsigned int mi = (M3D_INDEX)-1U;
|
||||||
|
if (mScene->mMaterials) {
|
||||||
|
// get the material for this mesh
|
||||||
|
mi = addMaterial(m3d, mScene->mMaterials[mesh->mMaterialIndex]);
|
||||||
|
}
|
||||||
|
// iterate through the mesh faces
|
||||||
|
for (unsigned int j = 0; j < mesh->mNumFaces; j++) {
|
||||||
|
unsigned int n;
|
||||||
|
const aiFace *face = &(mesh->mFaces[j]);
|
||||||
|
// only triangle meshes supported for now
|
||||||
|
if (face->mNumIndices != 3) {
|
||||||
|
throw DeadlyExportError("use aiProcess_Triangulate before export");
|
||||||
|
}
|
||||||
|
// add triangle to the output
|
||||||
|
n = m3d->numface++;
|
||||||
|
m3d->face = (m3df_t *)M3D_REALLOC(m3d->face,
|
||||||
|
m3d->numface * sizeof(m3df_t));
|
||||||
|
if (!m3d->face) {
|
||||||
|
throw DeadlyExportError("memory allocation error");
|
||||||
|
}
|
||||||
|
/* set all index to -1 by default */
|
||||||
|
m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] =
|
||||||
|
m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] =
|
||||||
|
m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = -1U;
|
||||||
|
m3d->face[n].materialid = mi;
|
||||||
|
for (unsigned int k = 0; k < face->mNumIndices; k++) {
|
||||||
|
// get the vertex's index
|
||||||
|
unsigned int l = face->mIndices[k];
|
||||||
|
unsigned int idx;
|
||||||
|
m3dv_t vertex;
|
||||||
|
m3dti_t ti;
|
||||||
|
// multiply the position vector by the transformation matrix
|
||||||
|
aiVector3D v = mesh->mVertices[l];
|
||||||
|
v *= nm;
|
||||||
|
vertex.x = v.x;
|
||||||
|
vertex.y = v.y;
|
||||||
|
vertex.z = v.z;
|
||||||
|
vertex.w = 1.0;
|
||||||
|
vertex.color = 0;
|
||||||
|
vertex.skinid = -1U;
|
||||||
|
// add color if defined
|
||||||
|
if (mesh->HasVertexColors(0))
|
||||||
|
vertex.color = mkColor(&mesh->mColors[0][l]);
|
||||||
|
// save the vertex to the output
|
||||||
|
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex,
|
||||||
|
&vertex, &idx);
|
||||||
|
m3d->face[n].vertex[k] = (M3D_INDEX)idx;
|
||||||
|
// do we have texture coordinates?
|
||||||
|
if (mesh->HasTextureCoords(0)) {
|
||||||
|
ti.u = mesh->mTextureCoords[0][l].x;
|
||||||
|
ti.v = mesh->mTextureCoords[0][l].y;
|
||||||
|
m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx);
|
||||||
|
m3d->face[n].texcoord[k] = (M3D_INDEX)idx;
|
||||||
|
}
|
||||||
|
// do we have normal vectors?
|
||||||
|
if (mesh->HasNormals()) {
|
||||||
|
vertex.x = mesh->mNormals[l].x;
|
||||||
|
vertex.y = mesh->mNormals[l].y;
|
||||||
|
vertex.z = mesh->mNormals[l].z;
|
||||||
|
vertex.color = 0;
|
||||||
|
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx);
|
||||||
|
m3d->face[n].normal[k] = (M3D_INDEX)idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// repeat for the children nodes
|
||||||
|
for (unsigned int i = 0; i < pNode->mNumChildren; i++) {
|
||||||
|
NodeWalk(m3d, pNode->mChildren[i], nm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Assimp
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER
|
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER
|
||||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
||||||
|
|
|
@ -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);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,53 +99,18 @@ 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.
|
||||||
bool M3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler , bool checkSig) const {
|
bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||||
const std::string extension = GetExtension(pFile);
|
const std::string extension = GetExtension(pFile);
|
||||||
|
|
||||||
if (extension == "m3d" || extension == "a3d")
|
if (extension == "m3d" || extension == "a3d")
|
||||||
|
@ -159,9 +126,9 @@ bool M3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler , bool
|
||||||
const char* tokens[] = {"3DMO", "3dmo"};
|
const char* tokens[] = {"3DMO", "3dmo"};
|
||||||
return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
|
return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile, "rb"));
|
std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
|
||||||
unsigned char data[4];
|
unsigned char data[4];
|
||||||
if(4 != pStream->Read(data,1,4)) {
|
if (4 != pStream->Read(data, 1, 4)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !memcmp(data, "3DMO", 4) /* bin */ || !memcmp(data, "3dmo", 4) /* ASCII */;
|
return !memcmp(data, "3DMO", 4) /* bin */ || !memcmp(data, "3dmo", 4) /* ASCII */;
|
||||||
|
@ -170,81 +137,75 @@ bool M3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler , bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const aiImporterDesc* M3DImporter::GetInfo() const {
|
const aiImporterDesc *M3DImporter::GetInfo() const {
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Model 3D import implementation
|
// Model 3D import implementation
|
||||||
void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler) {
|
void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
// Read file into memory
|
// Read file into memory
|
||||||
std::unique_ptr<IOStream> pStream( pIOHandler->Open( file, "rb"));
|
std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb"));
|
||||||
if( !pStream.get() ) {
|
if (!pStream.get()) {
|
||||||
throw DeadlyImportError( "Failed to open file " + file + "." );
|
throw DeadlyImportError("Failed to open file " + file + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the file-size and validate it, throwing an exception when fails
|
// Get the file-size and validate it, throwing an exception when fails
|
||||||
size_t fileSize = pStream->FileSize();
|
size_t fileSize = pStream->FileSize();
|
||||||
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 + "." );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the path for external assets
|
// Get the path for external assets
|
||||||
std::string folderName( "./" );
|
std::string folderName("./");
|
||||||
std::string::size_type pos = file.find_last_of( "\\/" );
|
std::string::size_type pos = file.find_last_of("\\/");
|
||||||
if ( pos != std::string::npos ) {
|
if (pos != std::string::npos) {
|
||||||
folderName = file.substr( 0, pos );
|
folderName = file.substr(0, pos);
|
||||||
if ( !folderName.empty() ) {
|
if (!folderName.empty()) {
|
||||||
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 ) {
|
|
||||||
throw DeadlyImportError( "Unable to parse " + file + " as M3D." );
|
if (!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) {
|
||||||
pIOHandler->PopDirectory();
|
pIOHandler->PopDirectory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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,42 +213,43 @@ 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;
|
||||||
mat->AddProperty( &c, 1, AI_MATKEY_COLOR_DIFFUSE);
|
c.b = c.g = c.r = 0.6f;
|
||||||
|
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);
|
||||||
for(j = 0; j < m->numprop; j++) {
|
for (j = 0; j < m->numprop; j++) {
|
||||||
// look up property type
|
// look up property type
|
||||||
// 0 - 127 scalar values,
|
// 0 - 127 scalar values,
|
||||||
// 128 - 255 the same properties but for texture maps
|
// 128 - 255 the same properties but for texture maps
|
||||||
k = 256;
|
k = 256;
|
||||||
for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++)
|
for (l = 0; l < sizeof(m3d_propertytypes) / sizeof(m3d_propertytypes[0]); l++)
|
||||||
if(m->prop[j].type == m3d_propertytypes[l].id ||
|
if (m->prop[j].type == m3d_propertytypes[l].id ||
|
||||||
m->prop[j].type == m3d_propertytypes[l].id + 128) {
|
m->prop[j].type == m3d_propertytypes[l].id + 128) {
|
||||||
k = l;
|
k = l;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// should never happen, but be safe than sorry
|
// should never happen, but be safe than sorry
|
||||||
if(k == 256) continue;
|
if (k == 256) continue;
|
||||||
|
|
||||||
// scalar properties
|
// scalar properties
|
||||||
if(m->prop[j].type < 128 && aiProps[k].pKey) {
|
if (m->prop[j].type < 128 && aiProps[k].pKey) {
|
||||||
switch(m3d_propertytypes[k].format) {
|
switch (m3d_propertytypes[k].format) {
|
||||||
case m3dpf_color:
|
case m3dpf_color:
|
||||||
c = mkColor(m->prop[j].value.color);
|
c = mkColor(m->prop[j].value.color);
|
||||||
mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
|
mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
|
||||||
|
@ -298,8 +260,8 @@ void M3DImporter::importMaterials()
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
n = m->prop[j].value.num;
|
n = m->prop[j].value.num;
|
||||||
if(m->prop[j].type == m3dp_il) {
|
if (m->prop[j].type == m3dp_il) {
|
||||||
switch(n) {
|
switch (n) {
|
||||||
case 0: n = aiShadingMode_NoShading; break;
|
case 0: n = aiShadingMode_NoShading; break;
|
||||||
case 2: n = aiShadingMode_Phong; break;
|
case 2: n = aiShadingMode_Phong; break;
|
||||||
default: n = aiShadingMode_Gouraud; break;
|
default: n = aiShadingMode_Gouraud; break;
|
||||||
|
@ -310,11 +272,11 @@ 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,43 +288,49 @@ 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);
|
||||||
|
|
||||||
if(!m3d->numtexture)
|
if (!m3d->numtexture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mScene->mTextures = new aiTexture*[m3d->numtexture];
|
mScene->mTextures = new aiTexture *[m3d->numtexture];
|
||||||
for(i = 0; i < m3d->numtexture; i++) {
|
for (i = 0; i < m3d->numtexture; i++) {
|
||||||
unsigned int j, k;
|
unsigned int j, k;
|
||||||
t = &m3d->texture[i];
|
t = &m3d->texture[i];
|
||||||
if(!t->w || !t->h || !t->f || !t->d) continue;
|
if (!t->w || !t->h || !t->f || !t->d) continue;
|
||||||
aiTexture *tx = new aiTexture;
|
aiTexture *tx = new aiTexture;
|
||||||
strcpy(tx->achFormatHint, formatHint[t->f - 1]);
|
strcpy(tx->achFormatHint, formatHint[t->f - 1]);
|
||||||
tx->mFilename = aiString(std::string(t->name) + ".png");
|
tx->mFilename = aiString(std::string(t->name) + ".png");
|
||||||
tx->mWidth = t->w;
|
tx->mWidth = t->w;
|
||||||
tx->mHeight = t->h;
|
tx->mHeight = t->h;
|
||||||
tx->pcData = new aiTexel[ tx->mWidth*tx->mHeight ];
|
tx->pcData = new aiTexel[tx->mWidth * tx->mHeight];
|
||||||
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,10 +342,9 @@ 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;
|
||||||
std::vector<aiVector3D> *vertices = nullptr;
|
std::vector<aiVector3D> *vertices = nullptr;
|
||||||
std::vector<aiVector3D> *normals = nullptr;
|
std::vector<aiVector3D> *normals = nullptr;
|
||||||
|
@ -387,17 +354,17 @@ 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);
|
||||||
|
|
||||||
for(i = 0; i < m3d->numface; i++) {
|
for (i = 0; i < m3d->numface; i++) {
|
||||||
// we must switch mesh if material changes
|
// we must switch mesh if material changes
|
||||||
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;
|
||||||
|
@ -420,9 +387,9 @@ void M3DImporter::importMeshes()
|
||||||
aiFace *pFace = new aiFace;
|
aiFace *pFace = new aiFace;
|
||||||
pFace->mNumIndices = numpoly;
|
pFace->mNumIndices = numpoly;
|
||||||
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;
|
||||||
|
@ -431,20 +398,20 @@ void M3DImporter::importMeshes()
|
||||||
vertices->push_back(pos);
|
vertices->push_back(pos);
|
||||||
colors->push_back(mkColor(m3d->vertex[l].color));
|
colors->push_back(mkColor(m3d->vertex[l].color));
|
||||||
// add a bone to temporary vector
|
// add a bone to temporary vector
|
||||||
if(m3d->vertex[l].skinid != -1U &&m3d->vertex[l].skinid != -2U && m3d->skin && m3d->bone) {
|
if (m3d->vertex[l].skinid != -1U && m3d->vertex[l].skinid != -2U && m3d->skin && m3d->bone) {
|
||||||
// this is complicated, because M3D stores a list of bone id / weight pairs per
|
// this is complicated, because M3D stores a list of bone id / weight pairs per
|
||||||
// vertex but assimp uses lists of local vertex id/weight pairs per local bone list
|
// vertex but assimp uses lists of local vertex id/weight pairs per local bone list
|
||||||
vertexids->push_back(l);
|
vertexids->push_back(l);
|
||||||
}
|
}
|
||||||
l = m3d->face[i].texcoord[j];
|
l = m3d->face[i].texcoord[j];
|
||||||
if(l != -1U) {
|
if (l != -1U) {
|
||||||
uv.x = m3d->tmap[l].u;
|
uv.x = m3d->tmap[l].u;
|
||||||
uv.y = m3d->tmap[l].v;
|
uv.y = m3d->tmap[l].v;
|
||||||
uv.z = 0.0;
|
uv.z = 0.0;
|
||||||
texcoords->push_back(uv);
|
texcoords->push_back(uv);
|
||||||
}
|
}
|
||||||
l = m3d->face[i].normal[j];
|
l = m3d->face[i].normal[j];
|
||||||
if(l != -1U) {
|
if (l != -1U) {
|
||||||
norm.x = m3d->vertex[l].x;
|
norm.x = m3d->vertex[l].x;
|
||||||
norm.y = m3d->vertex[l].y;
|
norm.y = m3d->vertex[l].y;
|
||||||
norm.z = m3d->vertex[l].z;
|
norm.z = m3d->vertex[l].z;
|
||||||
|
@ -455,58 +422,57 @@ void M3DImporter::importMeshes()
|
||||||
delete pFace;
|
delete pFace;
|
||||||
}
|
}
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete meshes;
|
delete meshes;
|
||||||
if(faces) delete faces;
|
if (faces) delete faces;
|
||||||
if(vertices) delete vertices;
|
if (vertices) delete vertices;
|
||||||
if(normals) delete normals;
|
if (normals) delete normals;
|
||||||
if(texcoords) delete texcoords;
|
if (texcoords) delete texcoords;
|
||||||
if(colors) delete colors;
|
if (colors) delete colors;
|
||||||
if(vertexids) delete vertexids;
|
if (vertexids) delete vertexids;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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);
|
||||||
|
|
||||||
for(n = 0, i = parentid + 1; i < m3d->numbone; i++)
|
for (n = 0, i = parentid + 1; i < m3d->numbone; i++)
|
||||||
if(m3d->bone[i].parent == parentid) n++;
|
if (m3d->bone[i].parent == parentid) n++;
|
||||||
pParent->mChildren = new aiNode*[n];
|
pParent->mChildren = new aiNode *[n];
|
||||||
|
|
||||||
for(i = parentid + 1; i < m3d->numbone; i++) {
|
for (i = parentid + 1; i < m3d->numbone; i++) {
|
||||||
if(m3d->bone[i].parent == parentid) {
|
if (m3d->bone[i].parent == parentid) {
|
||||||
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,24 +481,23 @@ 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;
|
||||||
|
|
||||||
ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations);
|
ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations);
|
||||||
|
|
||||||
if(!m3d->numaction || !m3d->numbone)
|
if (!m3d->numaction || !m3d->numbone)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mScene->mAnimations = new aiAnimation*[m3d->numaction];
|
mScene->mAnimations = new aiAnimation *[m3d->numaction];
|
||||||
for(i = 0; i < m3d->numaction; i++) {
|
for (i = 0; i < m3d->numaction; i++) {
|
||||||
a = &m3d->action[i];
|
a = &m3d->action[i];
|
||||||
aiAnimation *pAnim = new aiAnimation;
|
aiAnimation *pAnim = new aiAnimation;
|
||||||
pAnim->mName = aiString(std::string(a->name));
|
pAnim->mName = aiString(std::string(a->name));
|
||||||
|
@ -540,8 +505,8 @@ void M3DImporter::importAnimations()
|
||||||
pAnim->mTicksPerSecond = 100;
|
pAnim->mTicksPerSecond = 100;
|
||||||
// now we know how many bones are referenced in this animation
|
// now we know how many bones are referenced in this animation
|
||||||
pAnim->mNumChannels = m3d->numbone;
|
pAnim->mNumChannels = m3d->numbone;
|
||||||
pAnim->mChannels = new aiNodeAnim*[pAnim->mNumChannels];
|
pAnim->mChannels = new aiNodeAnim *[pAnim->mNumChannels];
|
||||||
for(l = 0; l < m3d->numbone; l++) {
|
for (l = 0; l < m3d->numbone; l++) {
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
pAnim->mChannels[l] = new aiNodeAnim;
|
pAnim->mChannels[l] = new aiNodeAnim;
|
||||||
pAnim->mChannels[l]->mNodeName = aiString(std::string(m3d->bone[l].name));
|
pAnim->mChannels[l]->mNodeName = aiString(std::string(m3d->bone[l].name));
|
||||||
|
@ -551,10 +516,10 @@ void M3DImporter::importAnimations()
|
||||||
pAnim->mChannels[l]->mRotationKeys = new aiQuatKey[a->numframe];
|
pAnim->mChannels[l]->mRotationKeys = new aiQuatKey[a->numframe];
|
||||||
pos = m3d->bone[l].pos;
|
pos = m3d->bone[l].pos;
|
||||||
ori = m3d->bone[l].ori;
|
ori = m3d->bone[l].ori;
|
||||||
for(j = n = 0; j < a->numframe; j++) {
|
for (j = n = 0; j < a->numframe; j++) {
|
||||||
t = ((double)a->frame[j].msec) / 10;
|
t = ((double)a->frame[j].msec) / 10;
|
||||||
for(k = 0; k < a->frame[j].numtransform; k++) {
|
for (k = 0; k < a->frame[j].numtransform; k++) {
|
||||||
if(a->frame[j].transform[k].boneid == l) {
|
if (a->frame[j].transform[k].boneid == l) {
|
||||||
pos = a->frame[j].transform[k].pos;
|
pos = a->frame[j].transform[k].pos;
|
||||||
ori = a->frame[j].transform[k].ori;
|
ori = a->frame[j].transform[k].ori;
|
||||||
}
|
}
|
||||||
|
@ -570,8 +535,8 @@ void M3DImporter::importAnimations()
|
||||||
pAnim->mChannels[l]->mRotationKeys[j].mValue.x = q->x;
|
pAnim->mChannels[l]->mRotationKeys[j].mValue.x = q->x;
|
||||||
pAnim->mChannels[l]->mRotationKeys[j].mValue.y = q->y;
|
pAnim->mChannels[l]->mRotationKeys[j].mValue.y = q->y;
|
||||||
pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z;
|
pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z;
|
||||||
}// foreach frame
|
} // foreach frame
|
||||||
}// foreach bones
|
} // foreach bones
|
||||||
mScene->mAnimations[i] = pAnim;
|
mScene->mAnimations[i] = pAnim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -580,72 +545,83 @@ void M3DImporter::importAnimations()
|
||||||
// convert uint32_t into aiColor4D
|
// convert uint32_t into aiColor4D
|
||||||
aiColor4D M3DImporter::mkColor(uint32_t c) {
|
aiColor4D M3DImporter::mkColor(uint32_t c) {
|
||||||
aiColor4D color;
|
aiColor4D color;
|
||||||
color.a = ((float)((c >> 24)&0xff)) / 255;
|
color.a = ((float)((c >> 24) & 0xff)) / 255;
|
||||||
color.b = ((float)((c >> 16)&0xff)) / 255;
|
color.b = ((float)((c >> 16) & 0xff)) / 255;
|
||||||
color.g = ((float)((c >> 8)&0xff)) / 255;
|
color.g = ((float)((c >> 8) & 0xff)) / 255;
|
||||||
color.r = ((float)((c >> 0)&0xff)) / 255;
|
color.r = ((float)((c >> 0) & 0xff)) / 255;
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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];
|
||||||
m3dv_t *q = &m3d->vertex[orientid];
|
m3dv_t *q = &m3d->vertex[orientid];
|
||||||
|
|
||||||
/* quaternion to matrix. Do NOT use aiQuaternion to aiMatrix3x3, gives bad results */
|
/* quaternion to matrix. Do NOT use aiQuaternion to aiMatrix3x3, gives bad results */
|
||||||
if(q->x == 0.0 && q->y == 0.0 && q->z >= 0.7071065 && q->z <= 0.7071075 && q->w == 0.0) {
|
if (q->x == 0.0 && q->y == 0.0 && q->z >= 0.7071065 && q->z <= 0.7071075 && q->w == 0.0) {
|
||||||
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);
|
||||||
ai_assert(mScene != nullptr);
|
ai_assert(mScene != nullptr);
|
||||||
|
|
||||||
if(pNode->mName == name)
|
if (pNode->mName == name)
|
||||||
return pNode;
|
return pNode;
|
||||||
for(i = 0; i < pNode->mNumChildren; i++) {
|
for (i = 0; i < pNode->mNumChildren; i++) {
|
||||||
aiNode *pChild = findNode(pNode->mChildren[i], name);
|
aiNode *pChild = findNode(pNode->mChildren[i], name);
|
||||||
if(pChild) return pChild;
|
if (pChild) return pChild;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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);
|
||||||
|
|
||||||
if(pNode->mParent) {
|
if (pNode->mParent) {
|
||||||
calculateOffsetMatrix(pNode->mParent, m);
|
calculateOffsetMatrix(pNode->mParent, m);
|
||||||
*m *= pNode->mTransformation;
|
*m *= pNode->mTransformation;
|
||||||
} else {
|
} else {
|
||||||
|
@ -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,28 +644,28 @@ 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()) {
|
||||||
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
||||||
std::copy(normals->begin(), normals->end(), pMesh->mNormals);
|
std::copy(normals->begin(), normals->end(), pMesh->mNormals);
|
||||||
}
|
}
|
||||||
if(texcoords->size() == vertices->size()) {
|
if (texcoords->size() == vertices->size()) {
|
||||||
pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices];
|
pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices];
|
||||||
std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]);
|
std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]);
|
||||||
pMesh->mNumUVComponents[0] = 2;
|
pMesh->mNumUVComponents[0] = 2;
|
||||||
}
|
}
|
||||||
if(colors->size() == vertices->size()) {
|
if (colors->size() == vertices->size()) {
|
||||||
pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
|
pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
|
||||||
std::copy(colors->begin(), colors->end(), pMesh->mColors[0]);
|
std::copy(colors->begin(), colors->end(), pMesh->mColors[0]);
|
||||||
}
|
}
|
||||||
|
@ -697,30 +673,30 @@ void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::v
|
||||||
// vertex but assimp uses lists of local vertex id/weight pairs per local bone list
|
// vertex but assimp uses lists of local vertex id/weight pairs per local bone list
|
||||||
pMesh->mNumBones = m3d->numbone;
|
pMesh->mNumBones = m3d->numbone;
|
||||||
/* we need aiBone with mOffsetMatrix for bones without weights as well */
|
/* we need aiBone with mOffsetMatrix for bones without weights as well */
|
||||||
if(pMesh->mNumBones) {
|
if (pMesh->mNumBones) {
|
||||||
pMesh->mBones = new aiBone*[pMesh->mNumBones];
|
pMesh->mBones = new aiBone *[pMesh->mNumBones];
|
||||||
for(unsigned int i = 0; i < m3d->numbone; i++) {
|
for (unsigned int i = 0; i < m3d->numbone; i++) {
|
||||||
aiNode *pNode;
|
aiNode *pNode;
|
||||||
pMesh->mBones[i] = new aiBone;
|
pMesh->mBones[i] = new aiBone;
|
||||||
pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name));
|
pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name));
|
||||||
pMesh->mBones[i]->mNumWeights = 0;
|
pMesh->mBones[i]->mNumWeights = 0;
|
||||||
pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName);
|
pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName);
|
||||||
if(pNode) {
|
if (pNode) {
|
||||||
calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix);
|
calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix);
|
||||||
pMesh->mBones[i]->mOffsetMatrix.Inverse();
|
pMesh->mBones[i]->mOffsetMatrix.Inverse();
|
||||||
} else
|
} else
|
||||||
pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4();
|
pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4();
|
||||||
}
|
}
|
||||||
if(vertexids->size()) {
|
if (vertexids->size()) {
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
// first count how many vertices we have per bone
|
// first count how many vertices we have per bone
|
||||||
for(i = 0; i < vertexids->size(); i++) {
|
for (i = 0; i < vertexids->size(); i++) {
|
||||||
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
||||||
if(s != -1U && s!= -2U) {
|
if (s != -1U && s != -2U) {
|
||||||
for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
|
for (unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
|
||||||
aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name));
|
aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name));
|
||||||
for(j = 0; j < pMesh->mNumBones; j++) {
|
for (j = 0; j < pMesh->mNumBones; j++) {
|
||||||
if(pMesh->mBones[j]->mName == name) {
|
if (pMesh->mBones[j]->mName == name) {
|
||||||
pMesh->mBones[j]->mNumWeights++;
|
pMesh->mBones[j]->mNumWeights++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -729,21 +705,21 @@ void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// allocate mWeights
|
// allocate mWeights
|
||||||
for(j = 0; j < pMesh->mNumBones; j++) {
|
for (j = 0; j < pMesh->mNumBones; j++) {
|
||||||
aiBone *pBone = pMesh->mBones[j];
|
aiBone *pBone = pMesh->mBones[j];
|
||||||
if(pBone->mNumWeights) {
|
if (pBone->mNumWeights) {
|
||||||
pBone->mWeights = new aiVertexWeight[pBone->mNumWeights];
|
pBone->mWeights = new aiVertexWeight[pBone->mNumWeights];
|
||||||
pBone->mNumWeights = 0;
|
pBone->mNumWeights = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fill up with data
|
// fill up with data
|
||||||
for(i = 0; i < vertexids->size(); i++) {
|
for (i = 0; i < vertexids->size(); i++) {
|
||||||
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
|
||||||
if(s != -1U && s!= -2U) {
|
if (s != -1U && s != -2U) {
|
||||||
for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
|
for (unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
|
||||||
aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name));
|
aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name));
|
||||||
for(j = 0; j < pMesh->mNumBones; j++) {
|
for (j = 0; j < pMesh->mNumBones; j++) {
|
||||||
if(pMesh->mBones[j]->mName == name) {
|
if (pMesh->mBones[j]->mName == name) {
|
||||||
aiBone *pBone = pMesh->mBones[j];
|
aiBone *pBone = pMesh->mBones[j];
|
||||||
pBone->mWeights[pBone->mNumWeights].mVertexId = i;
|
pBone->mWeights[pBone->mNumWeights].mVertexId = i;
|
||||||
pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k];
|
pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k];
|
||||||
|
|
|
@ -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,41 +59,39 @@ struct aiFace;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
class M3DWrapper;
|
||||||
|
|
||||||
class M3DImporter : public BaseImporter {
|
class M3DImporter : public BaseImporter {
|
||||||
public:
|
public:
|
||||||
/// \brief Default constructor
|
/// \brief Default constructor
|
||||||
M3DImporter();
|
M3DImporter();
|
||||||
|
|
||||||
/// \brief Destructor
|
|
||||||
~M3DImporter();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \brief Returns whether the class can handle the format of the given file.
|
/// \brief Returns whether the class can handle the format of the given file.
|
||||||
/// \remark See BaseImporter::CanRead() for details.
|
/// \remark See BaseImporter::CanRead() for details.
|
||||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
aiScene* mScene; // the scene to import to
|
aiScene *mScene = nullptr; // the scene to import to
|
||||||
m3d_t *m3d; // model for the C library to convert from
|
|
||||||
|
|
||||||
//! \brief Appends the supported extension.
|
//! \brief Appends the supported extension.
|
||||||
const aiImporterDesc* GetInfo () const;
|
const aiImporterDesc *GetInfo() const;
|
||||||
|
|
||||||
//! \brief File import implementation.
|
//! \brief File import implementation.
|
||||||
void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
|
||||||
|
|
||||||
void importMaterials();
|
void importMaterials(const M3DWrapper &m3d);
|
||||||
void importTextures();
|
void importTextures(const M3DWrapper &m3d);
|
||||||
void importMeshes();
|
void importMeshes(const M3DWrapper &m3d);
|
||||||
void importBones(unsigned int parentid, aiNode *pParent);
|
void importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent);
|
||||||
void importAnimations();
|
void importAnimations(const M3DWrapper &m3d);
|
||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
aiColor4D mkColor(uint32_t c);
|
aiColor4D mkColor(uint32_t c);
|
||||||
void convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid);
|
void convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid);
|
||||||
aiNode *findNode(aiNode *pNode, aiString name);
|
aiNode *findNode(aiNode *pNode, aiString name);
|
||||||
void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m);
|
void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m);
|
||||||
void populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces,
|
void populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces,
|
||||||
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
|
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
|
||||||
std::vector<unsigned int> *vertexids);
|
std::vector<unsigned int> *vertexids);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -43,13 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Implementation of the aiProcess_OptimizGraph step
|
* @brief Implementation of the aiProcess_OptimizGraph step
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
|
#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
|
||||||
|
|
||||||
#include "OptimizeGraph.h"
|
#include "OptimizeGraph.h"
|
||||||
#include "ProcessHelper.h"
|
#include "ProcessHelper.h"
|
||||||
#include <assimp/SceneCombiner.h>
|
#include "ConvertToLHProcess.h"
|
||||||
#include <assimp/Exceptional.h>
|
#include <assimp/Exceptional.h>
|
||||||
|
#include <assimp/SceneCombiner.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
@ -60,21 +60,21 @@ using namespace Assimp;
|
||||||
* The unhashed variant should be faster, except for *very* large data sets
|
* The unhashed variant should be faster, except for *very* large data sets
|
||||||
*/
|
*/
|
||||||
#ifdef AI_OG_USE_HASHING
|
#ifdef AI_OG_USE_HASHING
|
||||||
// Use our standard hashing function to compute the hash
|
// Use our standard hashing function to compute the hash
|
||||||
# define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length)
|
#define AI_OG_GETKEY(str) SuperFastHash(str.data, str.length)
|
||||||
#else
|
#else
|
||||||
// Otherwise hope that std::string will utilize a static buffer
|
// Otherwise hope that std::string will utilize a static buffer
|
||||||
// for shorter node names. This would avoid endless heap copying.
|
// for shorter node names. This would avoid endless heap copying.
|
||||||
# define AI_OG_GETKEY(str) std::string(str.data)
|
#define AI_OG_GETKEY(str) std::string(str.data)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
OptimizeGraphProcess::OptimizeGraphProcess()
|
OptimizeGraphProcess::OptimizeGraphProcess() :
|
||||||
: mScene()
|
mScene(),
|
||||||
, nodes_in()
|
nodes_in(),
|
||||||
, nodes_out()
|
nodes_out(),
|
||||||
, count_merged() {
|
count_merged() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,33 +86,33 @@ OptimizeGraphProcess::~OptimizeGraphProcess() {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the processing step is present in the given flag field.
|
// Returns whether the processing step is present in the given flag field.
|
||||||
bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const {
|
bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const {
|
||||||
return (0 != (pFlags & aiProcess_OptimizeGraph));
|
return (0 != (pFlags & aiProcess_OptimizeGraph));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Setup properties for the post-processing step
|
// Setup properties for the post-processing step
|
||||||
void OptimizeGraphProcess::SetupProperties(const Importer* pImp) {
|
void OptimizeGraphProcess::SetupProperties(const Importer *pImp) {
|
||||||
// Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST
|
// Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST
|
||||||
std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,"");
|
std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST, "");
|
||||||
AddLockedNodeList(tmp);
|
AddLockedNodeList(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Collect new children
|
// Collect new children
|
||||||
void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes) {
|
void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &nodes) {
|
||||||
nodes_in += nd->mNumChildren;
|
nodes_in += nd->mNumChildren;
|
||||||
|
|
||||||
// Process children
|
// Process children
|
||||||
std::list<aiNode*> child_nodes;
|
std::list<aiNode *> child_nodes;
|
||||||
for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
|
for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
|
||||||
CollectNewChildren(nd->mChildren[i],child_nodes);
|
CollectNewChildren(nd->mChildren[i], child_nodes);
|
||||||
nd->mChildren[i] = nullptr;
|
nd->mChildren[i] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether we need this node; if not we can replace it by our own children (warn, danger of incest).
|
// Check whether we need this node; if not we can replace it by our own children (warn, danger of incest).
|
||||||
if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end() ) {
|
if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end()) {
|
||||||
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
|
for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
|
||||||
|
|
||||||
if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) {
|
if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) {
|
||||||
(*it)->mTransformation = nd->mTransformation * (*it)->mTransformation;
|
(*it)->mTransformation = nd->mTransformation * (*it)->mTransformation;
|
||||||
|
@ -136,19 +136,19 @@ 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();
|
||||||
|
|
||||||
std::list<aiNode*> join;
|
std::list<aiNode *> join;
|
||||||
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
|
for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
|
||||||
aiNode* child = *it;
|
aiNode *child = *it;
|
||||||
if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) {
|
if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) {
|
||||||
|
|
||||||
// There may be no instanced meshes
|
// There may be no instanced meshes
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
for (; n < child->mNumMeshes;++n) {
|
for (; n < child->mNumMeshes; ++n) {
|
||||||
if (meshes[child->mMeshes[n]] > 1) {
|
if (meshes[child->mMeshes[n]] > 1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
|
||||||
inv = join_master->mTransformation;
|
inv = join_master->mTransformation;
|
||||||
inv.Inverse();
|
inv.Inverse();
|
||||||
} else {
|
} else {
|
||||||
child->mTransformation = inv * child->mTransformation ;
|
child->mTransformation = inv * child->mTransformation;
|
||||||
|
|
||||||
join.push_back(child);
|
join.push_back(child);
|
||||||
it = child_nodes.erase(it);
|
it = child_nodes.erase(it);
|
||||||
|
@ -170,31 +170,40 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
if (join_master && !join.empty()) {
|
if (join_master && !join.empty()) {
|
||||||
join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i",count_merged++);
|
join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i", count_merged++);
|
||||||
|
|
||||||
unsigned int out_meshes = 0;
|
unsigned int out_meshes = 0;
|
||||||
for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
|
for (std::list<aiNode *>::const_iterator it = join.cbegin(); it != join.cend(); ++it) {
|
||||||
out_meshes += (*it)->mNumMeshes;
|
out_meshes += (*it)->mNumMeshes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy all mesh references in one array
|
// copy all mesh references in one array
|
||||||
if (out_meshes) {
|
if (out_meshes) {
|
||||||
unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes;
|
unsigned int *meshes = new unsigned int[out_meshes + join_master->mNumMeshes], *tmp = meshes;
|
||||||
for (unsigned int n = 0; n < join_master->mNumMeshes;++n) {
|
for (unsigned int n = 0; n < join_master->mNumMeshes; ++n) {
|
||||||
*tmp++ = join_master->mMeshes[n];
|
*tmp++ = join_master->mMeshes[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
|
for (const aiNode *join_node : join) {
|
||||||
for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) {
|
for (unsigned int n = 0; n < join_node->mNumMeshes; ++n) {
|
||||||
|
|
||||||
*tmp = (*it)->mMeshes[n];
|
*tmp = join_node->mMeshes[n];
|
||||||
aiMesh* mesh = mScene->mMeshes[*tmp++];
|
aiMesh *mesh = mScene->mMeshes[*tmp++];
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
@ -219,17 +228,17 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
|
||||||
delete[] nd->mChildren;
|
delete[] nd->mChildren;
|
||||||
|
|
||||||
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());
|
||||||
|
|
||||||
if (nd->mChildren) {
|
if (nd->mChildren) {
|
||||||
aiNode** tmp = nd->mChildren;
|
aiNode **tmp = nd->mChildren;
|
||||||
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
|
for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
|
||||||
aiNode* node = *tmp++ = *it;
|
aiNode *node = *tmp++ = *it;
|
||||||
node->mParent = nd;
|
node->mParent = nd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,12 +248,12 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Execute the post-processing step on the given scene
|
// Execute the post-processing step on the given scene
|
||||||
void OptimizeGraphProcess::Execute( aiScene* pScene) {
|
void OptimizeGraphProcess::Execute(aiScene *pScene) {
|
||||||
ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin");
|
ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin");
|
||||||
nodes_in = nodes_out = count_merged = 0;
|
nodes_in = nodes_out = count_merged = 0;
|
||||||
mScene = pScene;
|
mScene = pScene;
|
||||||
|
|
||||||
meshes.resize(pScene->mNumMeshes,0);
|
meshes.resize(pScene->mNumMeshes, 0);
|
||||||
FindInstancedMeshes(pScene->mRootNode);
|
FindInstancedMeshes(pScene->mRootNode);
|
||||||
|
|
||||||
// build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it
|
// build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it
|
||||||
|
@ -259,7 +268,7 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) {
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {
|
for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {
|
||||||
for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) {
|
for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) {
|
||||||
aiNodeAnim* anim = pScene->mAnimations[i]->mChannels[a];
|
aiNodeAnim *anim = pScene->mAnimations[i]->mChannels[a];
|
||||||
locked.insert(AI_OG_GETKEY(anim->mNodeName));
|
locked.insert(AI_OG_GETKEY(anim->mNodeName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +276,7 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) {
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||||
for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) {
|
for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) {
|
||||||
|
|
||||||
aiBone* bone = pScene->mMeshes[i]->mBones[a];
|
aiBone *bone = pScene->mMeshes[i]->mBones[a];
|
||||||
locked.insert(AI_OG_GETKEY(bone->mName));
|
locked.insert(AI_OG_GETKEY(bone->mName));
|
||||||
|
|
||||||
// HACK: Meshes referencing bones may not be transformed; we need to look them.
|
// HACK: Meshes referencing bones may not be transformed; we need to look them.
|
||||||
|
@ -277,35 +286,35 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {
|
for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {
|
||||||
aiCamera* cam = pScene->mCameras[i];
|
aiCamera *cam = pScene->mCameras[i];
|
||||||
locked.insert(AI_OG_GETKEY(cam->mName));
|
locked.insert(AI_OG_GETKEY(cam->mName));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
|
for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
|
||||||
aiLight* lgh = pScene->mLights[i];
|
aiLight *lgh = pScene->mLights[i];
|
||||||
locked.insert(AI_OG_GETKEY(lgh->mName));
|
locked.insert(AI_OG_GETKEY(lgh->mName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert a dummy master node and make it read-only
|
// Insert a dummy master node and make it read-only
|
||||||
aiNode* dummy_root = new aiNode(AI_RESERVED_NODE_NAME);
|
aiNode *dummy_root = new aiNode(AI_RESERVED_NODE_NAME);
|
||||||
locked.insert(AI_OG_GETKEY(dummy_root->mName));
|
locked.insert(AI_OG_GETKEY(dummy_root->mName));
|
||||||
|
|
||||||
const aiString prev = pScene->mRootNode->mName;
|
const aiString prev = pScene->mRootNode->mName;
|
||||||
pScene->mRootNode->mParent = dummy_root;
|
pScene->mRootNode->mParent = dummy_root;
|
||||||
|
|
||||||
dummy_root->mChildren = new aiNode*[dummy_root->mNumChildren = 1];
|
dummy_root->mChildren = new aiNode *[dummy_root->mNumChildren = 1];
|
||||||
dummy_root->mChildren[0] = pScene->mRootNode;
|
dummy_root->mChildren[0] = pScene->mRootNode;
|
||||||
|
|
||||||
// Do our recursive processing of scenegraph nodes. For each node collect
|
// Do our recursive processing of scenegraph nodes. For each node collect
|
||||||
// a fully new list of children and allow their children to place themselves
|
// a fully new list of children and allow their children to place themselves
|
||||||
// on the same hierarchy layer as their parents.
|
// on the same hierarchy layer as their parents.
|
||||||
std::list<aiNode*> nodes;
|
std::list<aiNode *> nodes;
|
||||||
CollectNewChildren (dummy_root,nodes);
|
CollectNewChildren(dummy_root, nodes);
|
||||||
|
|
||||||
ai_assert(nodes.size() == 1);
|
ai_assert(nodes.size() == 1);
|
||||||
|
|
||||||
if (dummy_root->mNumChildren == 0) {
|
if (dummy_root->mNumChildren == 0) {
|
||||||
pScene->mRootNode = NULL;
|
pScene->mRootNode = nullptr;
|
||||||
throw DeadlyImportError("After optimizing the scene graph, no data remains");
|
throw DeadlyImportError("After optimizing the scene graph, no data remains");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,19 +323,18 @@ 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);
|
||||||
} else {
|
} else {
|
||||||
ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished");
|
ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished");
|
||||||
|
@ -338,9 +346,8 @@ 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]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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,20 +76,18 @@ 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));
|
||||||
configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0));
|
configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0));
|
||||||
configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0));
|
configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0));
|
||||||
|
|
||||||
configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
|
configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
|
||||||
|
|
||||||
|
@ -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,56 +114,47 @@ 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
|
||||||
pcMesh->mBones = (aiBone**)(uint64_t)iRet;
|
pcMesh->mBones = (aiBone **)(uint64_t)iRet;
|
||||||
return iRet;
|
return iRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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]];
|
||||||
{
|
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) {
|
||||||
aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ];
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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,12 +180,10 @@ 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];
|
||||||
}
|
}
|
||||||
aiMatrix4x4 mWorldIT = pcNode->mTransformation;
|
aiMatrix4x4 mWorldIT = pcNode->mTransformation;
|
||||||
mWorldIT.Inverse().Transpose();
|
mWorldIT.Inverse().Transpose();
|
||||||
|
@ -208,26 +191,23 @@ 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();
|
||||||
pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mBitangents[n]).Normalize();
|
pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mBitangents[n]).Normalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,36 +225,33 @@ 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];
|
|
||||||
|
|
||||||
const unsigned int num_idx = f_src.mNumIndices;
|
const unsigned int num_idx = f_src.mNumIndices;
|
||||||
|
|
||||||
f_dst.mNumIndices = num_idx;
|
f_dst.mNumIndices = num_idx;
|
||||||
|
|
||||||
unsigned int* pi;
|
unsigned int *pi;
|
||||||
if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */
|
if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */
|
||||||
pi = f_dst.mIndices = f_src.mIndices;
|
pi = f_dst.mIndices = f_src.mIndices;
|
||||||
|
|
||||||
// offset all vertex indices
|
// offset all vertex indices
|
||||||
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
|
||||||
for (unsigned int hahn = 0; hahn < num_idx;++hahn){
|
for (unsigned int hahn = 0; hahn < num_idx; ++hahn) {
|
||||||
pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX];
|
pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -296,21 +272,19 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
|
||||||
}
|
}
|
||||||
|
|
||||||
// append all children of us
|
// append all children of us
|
||||||
for (unsigned int i = 0;i < pcNode->mNumChildren;++i) {
|
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
|
||||||
CollectData(pcScene,pcNode->mChildren[i],iMat,
|
CollectData(pcScene, pcNode->mChildren[i], iMat,
|
||||||
iVFormat,pcMeshOut,aiCurrent,num_refs);
|
iVFormat, pcMeshOut, aiCurrent, num_refs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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,35 +293,38 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0;i < pcNode->mNumChildren;++i) {
|
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
|
||||||
ComputeAbsoluteTransform(pcNode->mChildren[i]);
|
ComputeAbsoluteTransform(pcNode->mChildren[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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) {
|
||||||
|
@ -366,29 +343,27 @@ 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
|
||||||
|
|
||||||
// process meshes
|
// process meshes
|
||||||
for (unsigned int i = 0; i < node->mNumMeshes;++i) {
|
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
|
||||||
aiMesh* mesh = in[node->mMeshes[i]];
|
aiMesh *mesh = in[node->mMeshes[i]];
|
||||||
|
|
||||||
// check whether we can operate on this mesh
|
// check whether we can operate on this mesh
|
||||||
if (!mesh->mBones || *reinterpret_cast<aiMatrix4x4*>(mesh->mBones) == node->mTransformation) {
|
if (!mesh->mBones || *reinterpret_cast<aiMatrix4x4 *>(mesh->mBones) == node->mTransformation) {
|
||||||
// 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) {
|
||||||
aiMesh* ctz = out[n];
|
aiMesh *ctz = out[n];
|
||||||
if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4*>(ctz->mBones) == node->mTransformation) {
|
if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4 *>(ctz->mBones) == node->mTransformation) {
|
||||||
|
|
||||||
// ok, use this one. Update node mesh index
|
// ok, use this one. Update node mesh index
|
||||||
node->mMeshes[i] = numIn + n;
|
node->mMeshes[i] = numIn + n;
|
||||||
|
@ -397,15 +372,15 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in
|
||||||
if (node->mMeshes[i] < numIn) {
|
if (node->mMeshes[i] < numIn) {
|
||||||
// Worst case. Need to operate on a full copy of the mesh
|
// Worst case. Need to operate on a full copy of the mesh
|
||||||
ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms");
|
ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms");
|
||||||
aiMesh* ntz;
|
aiMesh *ntz;
|
||||||
|
|
||||||
const unsigned int tmp = mesh->mNumBones; //
|
const unsigned int tmp = mesh->mNumBones; //
|
||||||
mesh->mNumBones = 0;
|
mesh->mNumBones = 0;
|
||||||
SceneCombiner::Copy(&ntz,mesh);
|
SceneCombiner::Copy(&ntz, mesh);
|
||||||
mesh->mNumBones = tmp;
|
mesh->mNumBones = tmp;
|
||||||
|
|
||||||
ntz->mNumBones = node->mMeshes[i];
|
ntz->mNumBones = node->mMeshes[i];
|
||||||
ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
|
ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
|
||||||
|
|
||||||
out.push_back(ntz);
|
out.push_back(ntz);
|
||||||
|
|
||||||
|
@ -415,37 +390,34 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in
|
||||||
}
|
}
|
||||||
|
|
||||||
// call children
|
// call children
|
||||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
for (unsigned int i = 0; i < node->mNumChildren; ++i)
|
||||||
BuildWCSMeshes(out,in,numIn,node->mChildren[i]);
|
BuildWCSMeshes(out, in, numIn, node->mChildren[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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
|
||||||
for (unsigned int i = 0; i < nd->mNumChildren;++i)
|
for (unsigned int i = 0; i < nd->mNumChildren; ++i)
|
||||||
MakeIdentityTransform(nd->mChildren[i]);
|
MakeIdentityTransform(nd->mChildren[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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]]++;
|
||||||
|
|
||||||
// call children
|
// call children
|
||||||
for (unsigned int i = 0; i < nd->mNumChildren;++i)
|
for (unsigned int i = 0; i < nd->mNumChildren; ++i)
|
||||||
BuildMeshRefCountArray(nd->mChildren[i],refs);
|
BuildMeshRefCountArray(nd->mChildren[i], refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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
|
||||||
|
@ -456,7 +428,7 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
|
const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
|
||||||
const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
|
const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
|
||||||
|
|
||||||
if(configTransform) {
|
if (configTransform) {
|
||||||
pScene->mRootNode->mTransformation = configTransformation;
|
pScene->mRootNode->mTransformation = configTransformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,10 +438,10 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
// Delete aiMesh::mBones for all meshes. The bones are
|
// Delete aiMesh::mBones for all meshes. The bones are
|
||||||
// removed during this step and we need the pointer as
|
// removed during this step and we need the pointer as
|
||||||
// temporary storage
|
// temporary storage
|
||||||
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];
|
||||||
|
|
||||||
for (unsigned int a = 0; a < mesh->mNumBones;++a)
|
for (unsigned int a = 0; a < mesh->mNumBones; ++a)
|
||||||
delete mesh->mBones[a];
|
delete mesh->mBones[a];
|
||||||
|
|
||||||
delete[] mesh->mBones;
|
delete[] mesh->mBones;
|
||||||
|
@ -477,74 +449,74 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
}
|
}
|
||||||
|
|
||||||
// now build a list of output meshes
|
// now build a list of output meshes
|
||||||
std::vector<aiMesh*> apcOutMeshes;
|
std::vector<aiMesh *> apcOutMeshes;
|
||||||
|
|
||||||
// Keep scene hierarchy? It's an easy job in this case ...
|
// Keep scene hierarchy? It's an easy job in this case ...
|
||||||
// we go on and transform all meshes, if one is referenced by nodes
|
// we go on and transform all meshes, if one is referenced by nodes
|
||||||
// with different absolute transformations a depth copy of the mesh
|
// with different absolute transformations a depth copy of the mesh
|
||||||
// is required.
|
// is required.
|
||||||
if( configKeepHierarchy ) {
|
if (configKeepHierarchy) {
|
||||||
|
|
||||||
// Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
|
// Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
|
||||||
BuildWCSMeshes(apcOutMeshes,pScene->mMeshes,pScene->mNumMeshes, pScene->mRootNode);
|
BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode);
|
||||||
|
|
||||||
// ... if new meshes have been generated, append them to the end of the scene
|
// ... if new meshes have been generated, append them to the end of the scene
|
||||||
if (apcOutMeshes.size() > 0) {
|
if (apcOutMeshes.size() > 0) {
|
||||||
aiMesh** npp = new aiMesh*[pScene->mNumMeshes + apcOutMeshes.size()];
|
aiMesh **npp = new aiMesh *[pScene->mNumMeshes + apcOutMeshes.size()];
|
||||||
|
|
||||||
memcpy(npp,pScene->mMeshes,sizeof(aiMesh*)*pScene->mNumMeshes);
|
memcpy(npp, pScene->mMeshes, sizeof(aiMesh *) * pScene->mNumMeshes);
|
||||||
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
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||||
ApplyTransform(pScene->mMeshes[i],*reinterpret_cast<aiMatrix4x4*>( pScene->mMeshes[i]->mBones ));
|
ApplyTransform(pScene->mMeshes[i], *reinterpret_cast<aiMatrix4x4 *>(pScene->mMeshes[i]->mBones));
|
||||||
|
|
||||||
// prevent improper destruction
|
// prevent improper destruction
|
||||||
pScene->mMeshes[i]->mBones = NULL;
|
pScene->mMeshes[i]->mBones = NULL;
|
||||||
pScene->mMeshes[i]->mNumBones = 0;
|
pScene->mMeshes[i]->mNumBones = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
apcOutMeshes.reserve(pScene->mNumMaterials<<1u);
|
apcOutMeshes.reserve(pScene->mNumMaterials << 1u);
|
||||||
std::list<unsigned int> aiVFormats;
|
std::list<unsigned int> aiVFormats;
|
||||||
|
|
||||||
std::vector<unsigned int> s(pScene->mNumMeshes,0);
|
std::vector<unsigned int> s(pScene->mNumMeshes, 0);
|
||||||
BuildMeshRefCountArray(pScene->mRootNode,&s[0]);
|
BuildMeshRefCountArray(pScene->mRootNode, &s[0]);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
|
for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
||||||
// get the list of all vertex formats for this material
|
// get the list of all vertex formats for this material
|
||||||
aiVFormats.clear();
|
aiVFormats.clear();
|
||||||
GetVFormatList(pScene,i,aiVFormats);
|
GetVFormatList(pScene, i, aiVFormats);
|
||||||
aiVFormats.sort();
|
aiVFormats.sort();
|
||||||
aiVFormats.unique();
|
aiVFormats.unique();
|
||||||
for (std::list<unsigned int>::const_iterator j = aiVFormats.begin();j != aiVFormats.end();++j) {
|
for (std::list<unsigned int>::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) {
|
||||||
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;
|
||||||
pcMesh->mNumVertices = iVertices;
|
pcMesh->mNumVertices = iVertices;
|
||||||
pcMesh->mFaces = new aiFace[iFaces];
|
pcMesh->mFaces = new aiFace[iFaces];
|
||||||
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;
|
||||||
|
@ -552,8 +524,8 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
pcMesh->mColors[iFaces++] = new aiColor4D[iVertices];
|
pcMesh->mColors[iFaces++] = new aiColor4D[iVertices];
|
||||||
|
|
||||||
// fill the mesh ...
|
// fill the mesh ...
|
||||||
unsigned int aiTemp[2] = {0,0};
|
unsigned int aiTemp[2] = { 0, 0 };
|
||||||
CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]);
|
CollectData(pScene, pScene->mRootNode, i, *j, pcMesh, aiTemp, &s[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -562,13 +534,10 @@ 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;
|
||||||
|
|
||||||
|
@ -591,14 +560,14 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
// It is impossible that we have more output meshes than
|
// It is impossible that we have more output meshes than
|
||||||
// input meshes, so we can easily reuse the old mesh array
|
// input meshes, so we can easily reuse the old mesh array
|
||||||
pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
|
pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||||
pScene->mMeshes[i] = apcOutMeshes[i];
|
pScene->mMeshes[i] = apcOutMeshes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all animations from the scene
|
// remove all animations from the scene
|
||||||
for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
|
for (unsigned int i = 0; i < pScene->mNumAnimations; ++i)
|
||||||
delete pScene->mAnimations[i];
|
delete pScene->mAnimations[i];
|
||||||
delete[] pScene->mAnimations;
|
delete[] pScene->mAnimations;
|
||||||
|
|
||||||
|
@ -606,56 +575,50 @@ 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);
|
||||||
|
|
||||||
// multiply all properties of the camera with the absolute
|
// multiply all properties of the camera with the absolute
|
||||||
// transformation of the corresponding node
|
// transformation of the corresponding node
|
||||||
cam->mPosition = nd->mTransformation * cam->mPosition;
|
cam->mPosition = nd->mTransformation * cam->mPosition;
|
||||||
cam->mLookAt = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt;
|
cam->mLookAt = aiMatrix3x3(nd->mTransformation) * cam->mLookAt;
|
||||||
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);
|
||||||
|
|
||||||
// multiply all properties of the camera with the absolute
|
// multiply all properties of the camera with the absolute
|
||||||
// transformation of the corresponding node
|
// transformation of the corresponding node
|
||||||
l->mPosition = nd->mTransformation * l->mPosition;
|
l->mPosition = nd->mTransformation * l->mPosition;
|
||||||
l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection;
|
l->mDirection = aiMatrix3x3(nd->mTransformation) * l->mDirection;
|
||||||
l->mUp = aiMatrix3x3( nd->mTransformation ) * l->mUp;
|
l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !configKeepHierarchy ) {
|
if (!configKeepHierarchy) {
|
||||||
|
|
||||||
// now delete all nodes in the scene and build a new
|
// now delete all nodes in the scene and build a new
|
||||||
// flat node graph with a root node and some level 1 children
|
// flat node graph with a root node and some level 1 children
|
||||||
aiNode* newRoot = new aiNode();
|
aiNode *newRoot = new aiNode();
|
||||||
newRoot->mName = pScene->mRootNode->mName;
|
newRoot->mName = pScene->mRootNode->mName;
|
||||||
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;
|
||||||
{
|
aiNode **nodes = pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
|
||||||
pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras;
|
|
||||||
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;
|
||||||
pcNode->mName = pScene->mMeshes[i]->mName;
|
pcNode->mName = pScene->mMeshes[i]->mName;
|
||||||
|
@ -666,52 +629,49 @@ 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;
|
||||||
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i);
|
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u", i);
|
||||||
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;
|
||||||
pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i);
|
pcNode->mName.length = ::ai_snprintf(pcNode->mName.data, MAXLEN, "cam_%u", i);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configNormalize) {
|
if (configNormalize) {
|
||||||
// compute the boundary of all meshes
|
// compute the boundary of all meshes
|
||||||
aiVector3D min,max;
|
aiVector3D min, max;
|
||||||
MinMaxChooser<aiVector3D> ()(min,max);
|
MinMaxChooser<aiVector3D>()(min, max);
|
||||||
|
|
||||||
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
||||||
aiMesh* m = pScene->mMeshes[a];
|
aiMesh *m = pScene->mMeshes[a];
|
||||||
for (unsigned int i = 0; i < m->mNumVertices;++i) {
|
for (unsigned int i = 0; i < m->mNumVertices; ++i) {
|
||||||
min = std::min(m->mVertices[i],min);
|
min = std::min(m->mVertices[i], min);
|
||||||
max = std::max(m->mVertices[i],max);
|
max = std::max(m->mVertices[i], max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the dominant axis
|
// find the dominant axis
|
||||||
aiVector3D d = max-min;
|
aiVector3D d = max - min;
|
||||||
const ai_real div = std::max(d.x,std::max(d.y,d.z))*ai_real( 0.5);
|
const ai_real div = std::max(d.x, std::max(d.y, d.z)) * ai_real(0.5);
|
||||||
|
|
||||||
d = min + d * (ai_real)0.5;
|
d = min + d * (ai_real)0.5;
|
||||||
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
||||||
aiMesh* m = pScene->mMeshes[a];
|
aiMesh *m = pScene->mMeshes[a];
|
||||||
for (unsigned int i = 0; i < m->mNumVertices;++i) {
|
for (unsigned int i = 0; i < m->mNumVertices; ++i) {
|
||||||
m->mVertices[i] = (m->mVertices[i]-d)/div;
|
m->mVertices[i] = (m->mVertices[i] - d) / div;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -721,8 +681,8 @@ void PretransformVertices::Execute( aiScene* pScene)
|
||||||
ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished");
|
ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished");
|
||||||
|
|
||||||
ASSIMP_LOG_INFO_F("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (",
|
ASSIMP_LOG_INFO_F("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (",
|
||||||
CountNodes(pScene->mRootNode) ," output nodes)" );
|
CountNodes(pScene->mRootNode), " output nodes)");
|
||||||
ASSIMP_LOG_INFO_F("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras." );
|
ASSIMP_LOG_INFO_F("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras.");
|
||||||
ASSIMP_LOG_INFO_F("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")");
|
ASSIMP_LOG_INFO_F("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,20 +68,20 @@ namespace Assimp {
|
||||||
*/
|
*/
|
||||||
class ASSIMP_API PretransformVertices : public BaseProcess {
|
class ASSIMP_API PretransformVertices : public BaseProcess {
|
||||||
public:
|
public:
|
||||||
PretransformVertices ();
|
PretransformVertices();
|
||||||
~PretransformVertices ();
|
~PretransformVertices();
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Check whether step is active
|
// Check whether step is active
|
||||||
bool IsActive( unsigned int pFlags) const;
|
bool IsActive(unsigned int pFlags) const override;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Execute step on a given scene
|
// Execute step on a given scene
|
||||||
void Execute( aiScene* pScene);
|
void Execute(aiScene *pScene) override;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Setup import settings
|
// Setup import settings
|
||||||
void SetupProperties(const Importer* pImp);
|
void SetupProperties(const Importer *pImp) override;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** @brief Toggle the 'keep hierarchy' option
|
/** @brief Toggle the 'keep hierarchy' option
|
||||||
|
@ -102,56 +102,56 @@ 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
|
||||||
void ComputeAbsoluteTransform( aiNode* pcNode );
|
void ComputeAbsoluteTransform(aiNode *pcNode);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Simple routine to build meshes in worldspace, no further optimization
|
// Simple routine to build meshes in worldspace, no further optimization
|
||||||
void BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in,
|
void BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in,
|
||||||
unsigned int numIn, aiNode* node);
|
unsigned int numIn, aiNode *node) const;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Apply the node transformation to a mesh
|
// Apply the node transformation to a mesh
|
||||||
void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat);
|
void ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Reset transformation matrices to identity
|
// Reset transformation matrices to identity
|
||||||
void MakeIdentityTransform(aiNode* nd);
|
void MakeIdentityTransform(aiNode *nd) const;
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Build reference counters for all meshes
|
// Build reference counters for all meshes
|
||||||
void BuildMeshRefCountArray(aiNode* nd, unsigned int * refs);
|
void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const;
|
||||||
|
|
||||||
//! Configuration option: keep scene hierarchy as long as possible
|
//! Configuration option: keep scene hierarchy as long as possible
|
||||||
bool configKeepHierarchy;
|
bool configKeepHierarchy;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue