Merge branch 'master' into warning-level-max

pull/2776/head
Kim Kulling 2019-12-11 19:16:30 +01:00 committed by GitHub
commit 13427c8d2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 2570 additions and 2055 deletions

View File

@ -257,7 +257,7 @@ ELSEIF(MSVC)
IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351)
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" )
IF(NOT HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")

View File

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

View File

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

View File

@ -5,8 +5,6 @@ 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,
@ -78,6 +76,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/TinyFormatter.h>
#include <assimp/Exceptional.h>
#include <assimp/Profiler.h>
#include <assimp/commonMetaData.h>
#include <set>
#include <memory>
#include <cctype>
@ -119,7 +119,7 @@ void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothro
return AllocateFromAssimpHeap::operator new( num_bytes );
}
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() {
try {
return AllocateFromAssimpHeap::operator new[]( num_bytes );
}
catch( ... ) {
return NULL;
} catch( ... ) {
return nullptr;
}
}
@ -148,7 +147,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) {
// Importer constructor.
Importer::Importer()
: pimpl( new ImporterPimpl ) {
pimpl->mScene = NULL;
pimpl->mScene = nullptr;
pimpl->mErrorString = "";
// Allocate a default IO handler
@ -174,14 +173,14 @@ Importer::Importer()
// ------------------------------------------------------------------------------------------------
// Destructor of Importer
Importer::~Importer()
{
Importer::~Importer() {
// Delete all import plugins
DeleteImporterInstanceList(pimpl->mImporter);
// 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 the assigned IO and progress handler
delete pimpl->mIOHandler;
@ -199,9 +198,9 @@ Importer::~Importer()
// ------------------------------------------------------------------------------------------------
// Register a custom post-processing step
aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
{
ai_assert(NULL != pImp);
aiReturn Importer::RegisterPPStep(BaseProcess* pImp) {
ai_assert( nullptr != pImp );
ASSIMP_BEGIN_EXCEPTION_REGION();
pimpl->mPostProcessingSteps.push_back(pImp);
@ -213,9 +212,9 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
// ------------------------------------------------------------------------------------------------
// Register a custom loader plugin
aiReturn Importer::RegisterLoader(BaseImporter* pImp)
{
ai_assert(NULL != pImp);
aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
ai_assert(nullptr != pImp);
ASSIMP_BEGIN_EXCEPTION_REGION();
// --------------------------------------------------------------------
@ -242,13 +241,13 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
pimpl->mImporter.push_back(pImp);
ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked);
ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_SUCCESS;
}
// ------------------------------------------------------------------------------------------------
// Unregister a custom loader plugin
aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
{
aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
if(!pImp) {
// unregistering a NULL importer is no problem for us ... really!
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_END_EXCEPTION_REGION(aiReturn);
return AI_FAILURE;
}
// ------------------------------------------------------------------------------------------------
// Unregister a custom loader plugin
aiReturn Importer::UnregisterPPStep(BaseProcess* pImp)
{
aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) {
if(!pImp) {
// unregistering a NULL ppstep is no problem for us ... really!
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_END_EXCEPTION_REGION(aiReturn);
return AI_FAILURE;
}
// ------------------------------------------------------------------------------------------------
// 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();
// If the new handler is zero, allocate a default IO implementation.
if (!pIOHandler)
{
if (!pIOHandler) {
// Release pointer in the possession of the caller
pimpl->mIOHandler = new DefaultIOSystem();
pimpl->mIsDefaultHandler = true;
}
// Otherwise register the custom handler
else if (pimpl->mIOHandler != pIOHandler)
{
} else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
delete pimpl->mIOHandler;
pimpl->mIOHandler = pIOHandler;
pimpl->mIsDefaultHandler = false;
@ -316,29 +313,32 @@ void Importer::SetIOHandler( IOSystem* pIOHandler)
// ------------------------------------------------------------------------------------------------
// Get the currently set IO handler
IOSystem* Importer::GetIOHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIOHandler;
}
// ------------------------------------------------------------------------------------------------
// Check whether a custom IO handler is currently set
bool Importer::IsDefaultIOHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIsDefaultHandler;
}
// ------------------------------------------------------------------------------------------------
// Supplies a custom progress handler to get regular callbacks during importing
void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
// If the new handler is zero, allocate a default implementation.
if (!pHandler)
{
if (!pHandler) {
// Release pointer in the possession of the caller
pimpl->mProgressHandler = new DefaultProgressHandler();
pimpl->mIsDefaultProgressHandler = true;
}
// Otherwise register the custom handler
else if (pimpl->mProgressHandler != pHandler)
{
} else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler
delete pimpl->mProgressHandler;
pimpl->mProgressHandler = pHandler;
pimpl->mIsDefaultProgressHandler = false;
@ -349,19 +349,22 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
// ------------------------------------------------------------------------------------------------
// Get the currently set progress handler
ProgressHandler* Importer::GetProgressHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mProgressHandler;
}
// ------------------------------------------------------------------------------------------------
// Check whether a custom progress handler is currently set
bool Importer::IsDefaultProgressHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIsDefaultProgressHandler;
}
// ------------------------------------------------------------------------------------------------
// Validate post process step flags
bool _ValidateFlags(unsigned int pFlags)
{
bool _ValidateFlags(unsigned int pFlags) {
if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) {
ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
return false;
@ -375,12 +378,13 @@ bool _ValidateFlags(unsigned int pFlags)
// ------------------------------------------------------------------------------------------------
// Free the current scene
void Importer::FreeScene( )
{
void Importer::FreeScene( ) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
delete pimpl->mScene;
pimpl->mScene = NULL;
pimpl->mScene = nullptr;
pimpl->mErrorString = "";
ASSIMP_END_EXCEPTION_REGION(void);
@ -388,44 +392,48 @@ void Importer::FreeScene( )
// ------------------------------------------------------------------------------------------------
// Get the current error string, if any
const char* Importer::GetErrorString() const
{
/* Must remain valid as long as ReadFile() or FreeFile() are not called */
const char* Importer::GetErrorString() const {
ai_assert(nullptr != pimpl);
// Must remain valid as long as ReadFile() or FreeFile() are not called
return pimpl->mErrorString.c_str();
}
// ------------------------------------------------------------------------------------------------
// Enable extra-verbose mode
void Importer::SetExtraVerbose(bool bDo)
{
void Importer::SetExtraVerbose(bool bDo) {
ai_assert(nullptr != pimpl);
pimpl->bExtraVerbose = bDo;
}
// ------------------------------------------------------------------------------------------------
// Get the current scene
const aiScene* Importer::GetScene() const
{
const aiScene* Importer::GetScene() const {
ai_assert(nullptr != pimpl);
return pimpl->mScene;
}
// ------------------------------------------------------------------------------------------------
// Orphan the current scene and return it.
aiScene* Importer::GetOrphanedScene()
{
aiScene* Importer::GetOrphanedScene() {
ai_assert(nullptr != pimpl);
aiScene* s = pimpl->mScene;
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*);
return s;
}
// ------------------------------------------------------------------------------------------------
// Validate post-processing flags
bool Importer::ValidateFlags(unsigned int pFlags) const
{
bool Importer::ValidateFlags(unsigned int pFlags) const {
ASSIMP_BEGIN_EXCEPTION_REGION();
// run basic checks for mutually exclusive flags
if(!_ValidateFlags(pFlags)) {
@ -467,8 +475,9 @@ bool Importer::ValidateFlags(unsigned int pFlags) const
const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
size_t pLength,
unsigned int pFlags,
const char* pHint /*= ""*/)
{
const char* pHint /*= ""*/) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
if (!pHint) {
pHint = "";
@ -476,12 +485,12 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
return NULL;
return nullptr;
}
// prevent deletion of the previous IOHandler
IOSystem* io = pimpl->mIOHandler;
pimpl->mIOHandler = NULL;
pimpl->mIOHandler = nullptr;
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);
// 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.
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();
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 + "\".";
ASSIMP_LOG_ERROR(pimpl->mErrorString);
return NULL;
return nullptr;
}
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
BaseImporter* imp = NULL;
BaseImporter* imp = nullptr;
SetPropertyInteger("importerIndex", -1);
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) {
pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
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
const aiImporterDesc *desc( imp->GetInfo() );
std::string ext( "unknown" );
if ( NULL != desc ) {
if ( nullptr != desc ) {
ext = desc->mName;
}
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( 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
// 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;
ds.ExecuteOnScene (this);
if (!pimpl->mScene) {
return NULL;
return nullptr;
}
}
#endif // no validation
@ -695,8 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
}
}
#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
catch (std::exception &e)
{
catch (std::exception &e) {
#if (defined _MSC_VER) && (defined _CPPRTTI)
// if we have RTTI get the full name of the exception that occurred
pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
@ -705,24 +719,26 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
#endif
ASSIMP_LOG_ERROR(pimpl->mErrorString);
delete pimpl->mScene; pimpl->mScene = NULL;
delete pimpl->mScene; pimpl->mScene = nullptr;
}
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
// either successful or failure - the pointer expresses it anyways
ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
return pimpl->mScene;
}
// ------------------------------------------------------------------------------------------------
// 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();
// Return immediately if no scene is active
if (!pimpl->mScene) {
return NULL;
return nullptr;
}
// 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
// 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.
if (pFlags & aiProcess_ValidateDataStructure)
{
if (pFlags & aiProcess_ValidateDataStructure) {
ValidateDSProcess ds;
ds.ExecuteOnScene (this);
if (!pimpl->mScene) {
return NULL;
return nullptr;
}
}
#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);
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
BaseProcess* process = pimpl->mPostProcessingSteps[a];
pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
if( process->IsActive( pFlags)) {
if (profiler) {
profiler->BeginRegion("postprocess");
}
@ -803,24 +816,28 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
static_cast<int>(pimpl->mPostProcessingSteps.size()) );
// update private scene flags
if( pimpl->mScene )
if( pimpl->mScene ) {
ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
}
// clear any data allocated by post-process steps
pimpl->mPPShared->Clean();
ASSIMP_LOG_INFO("Leaving post processing pipeline");
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
return pimpl->mScene;
}
// ------------------------------------------------------------------------------------------------
const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
// Return immediately if no scene is active
if ( NULL == pimpl->mScene ) {
return NULL;
if ( nullptr == pimpl->mScene ) {
return nullptr;
}
// 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;
ds.ExecuteOnScene( this );
if ( !pimpl->mScene ) {
return NULL;
return nullptr;
}
}
#endif // no validation
@ -890,46 +907,50 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
// ------------------------------------------------------------------------------------------------
// 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);
}
// ------------------------------------------------------------------------------------------------
size_t Importer::GetImporterCount() const
{
size_t Importer::GetImporterCount() const {
ai_assert(nullptr != pimpl);
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()) {
return NULL;
return nullptr;
}
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()) {
return NULL;
return nullptr;
}
return pimpl->mImporter[index];
}
// ------------------------------------------------------------------------------------------------
// 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));
}
// ------------------------------------------------------------------------------------------------
// Find a loader plugin for a given file extension
size_t Importer::GetImporterIndex (const char* szExtension) const {
ai_assert(nullptr != pimpl);
ai_assert(nullptr != szExtension);
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
void Importer::GetExtensionList(aiString& szOut) const
{
void Importer::GetExtensionList(aiString& szOut) const {
ai_assert(nullptr != pimpl);
ASSIMP_BEGIN_EXCEPTION_REGION();
std::set<std::string> str;
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
bool Importer::SetPropertyInteger(const char* szName, int iValue)
{
bool Importer::SetPropertyInteger(const char* szName, int iValue) {
ai_assert(nullptr != pimpl);
bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
@ -996,8 +1019,9 @@ bool Importer::SetPropertyInteger(const char* szName, int iValue)
// ------------------------------------------------------------------------------------------------
// 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;
ASSIMP_BEGIN_EXCEPTION_REGION();
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
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;
ASSIMP_BEGIN_EXCEPTION_REGION();
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
bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
{
bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
ai_assert(nullptr != pimpl);
bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION();
existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
@ -1029,40 +1055,43 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
// ------------------------------------------------------------------------------------------------
// Get a configuration property
int Importer::GetPropertyInteger(const char* szName,
int iErrorReturn /*= 0xffffffff*/) const
{
int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
ai_real Importer::GetPropertyFloat(const char* szName,
ai_real iErrorReturn /*= 10e10*/) const
{
ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
const std::string Importer::GetPropertyString(const char* szName,
const std::string& iErrorReturn /*= ""*/) const
{
const std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName,
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
{
const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
ai_assert(nullptr != pimpl);
return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
// 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(unsigned int) * pcNode->mNumMeshes;
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
void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
{
void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
ai_assert(nullptr != pimpl);
in = aiMemoryInfo();
aiScene* mScene = pimpl->mScene;
@ -1087,8 +1117,7 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
in.total = sizeof(aiScene);
// 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);
if (mScene->mMeshes[i]->HasPositions()) {
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) {
if (mScene->mMeshes[i]->HasVertexColors(a)) {
in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
} else {
break;
}
else break;
}
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
if (mScene->mMeshes[i]->HasTextureCoords(a)) {
in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
} else {
break;
}
else break;
}
if (mScene->mMeshes[i]->HasBones()) {
in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
@ -1131,8 +1162,9 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
in.textures += sizeof(aiTexture);
if (pc->mHeight) {
in.textures += 4 * pc->mHeight * pc->mWidth;
} else {
in.textures += pc->mWidth;
}
else in.textures += pc->mWidth;
}
in.total += in.textures;

View File

@ -60,6 +60,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h>
#include <assimp/CreateAnimMesh.h>
#include <assimp/commonMetaData.h>
#include <assimp/StringUtils.h>
#include <tuple>
#include <memory>
@ -1597,11 +1599,10 @@ namespace Assimp {
aiBone *bone = nullptr;
if (bone_map.count(deformer_name)) {
std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name
<< std::endl;
ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name);
bone = bone_map[deformer_name];
} 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->mName = bone_name;
@ -1648,7 +1649,7 @@ namespace Assimp {
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
// 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_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, 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)
@ -3604,7 +3612,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
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(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign());
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(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop());
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()

View File

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

View File

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

View File

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

View File

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

View File

@ -48,8 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
#include "m3d.h"
#include <assimp/types.h>
//#include <assimp/material.h>
#include <assimp/StreamWriter.h> // StreamWriterLE
@ -68,6 +66,8 @@ namespace Assimp
class IOStream;
class ExportProperties;
class M3DWrapper;
// ---------------------------------------------------------------------
/** 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 ExportProperties* mProperties; // currently unused
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
void NodeWalk(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);
void NodeWalk(const M3DWrapper &m3d, const aiNode* pNode, aiMatrix4x4 m);
};
}

View File

@ -48,16 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define M3D_NOWEIGHTS
#define M3D_NOANIMATION
#include <assimp/IOStreamBuffer.h>
#include <memory>
#include <assimp/DefaultIOSystem.h>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/IOStreamBuffer.h>
#include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <memory>
#include "M3DImporter.h"
#include "M3DMaterials.h"
#include "M3DWrapper.h"
// RESOURCES:
// 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,
@ -97,53 +99,18 @@ static const aiImporterDesc desc = {
"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 {
using namespace std;
// ------------------------------------------------------------------------------------------------
// Default constructor
M3DImporter::M3DImporter()
: mScene(nullptr)
, m3d(nullptr) { }
// ------------------------------------------------------------------------------------------------
// Destructor.
M3DImporter::~M3DImporter() {}
M3DImporter::M3DImporter() :
mScene(nullptr) {}
// ------------------------------------------------------------------------------------------------
// 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);
if (extension == "m3d" || extension == "a3d")
@ -159,9 +126,9 @@ bool M3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler , bool
const char* tokens[] = {"3DMO", "3dmo"};
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];
if(4 != pStream->Read(data,1,4)) {
if (4 != pStream->Read(data, 1, 4)) {
return false;
}
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;
}
// ------------------------------------------------------------------------------------------------
// 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
std::unique_ptr<IOStream> pStream( pIOHandler->Open( file, "rb"));
if( !pStream.get() ) {
throw DeadlyImportError( "Failed to open file " + file + "." );
std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb"));
if (!pStream.get()) {
throw DeadlyImportError("Failed to open file " + file + ".");
}
// Get the file-size and validate it, throwing an exception when fails
size_t fileSize = pStream->FileSize();
if( fileSize < 8 ) {
throw DeadlyImportError( "M3D-file " + file + " is too small." );
if (fileSize < 8) {
throw DeadlyImportError("M3D-file " + file + " is too small.");
}
std::unique_ptr<unsigned char[]> _buffer (new unsigned char[fileSize]);
unsigned char *data( _buffer.get() );
if(fileSize != pStream->Read(data,1,fileSize)) {
throw DeadlyImportError( "Failed to read the file " + file + "." );
std::vector<unsigned char> buffer(fileSize);
if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) {
throw DeadlyImportError("Failed to read the file " + file + ".");
}
// Get the path for external assets
std::string folderName( "./" );
std::string::size_type pos = file.find_last_of( "\\/" );
if ( pos != std::string::npos ) {
folderName = file.substr( 0, pos );
if ( !folderName.empty() ) {
pIOHandler->PushDirectory( folderName );
std::string folderName("./");
std::string::size_type pos = file.find_last_of("\\/");
if (pos != std::string::npos) {
folderName = file.substr(0, pos);
if (!folderName.empty()) {
pIOHandler->PushDirectory(folderName);
}
}
// pass this IOHandler to the C callback
m3dimporter_pIOHandler = pIOHandler;
//DefaultLogger::create("/dev/stderr", Logger::VERBOSE);
ASSIMP_LOG_DEBUG_F("M3D: loading ", file);
// let the C SDK do the hard work for us
m3d = m3d_load(&data[0], m3dimporter_readfile, free, nullptr);
m3dimporter_pIOHandler = nullptr;
if( !m3d ) {
throw DeadlyImportError( "Unable to parse " + file + " as M3D." );
M3DWrapper m3d(pIOHandler, buffer);
if (!m3d) {
throw DeadlyImportError("Unable to parse " + file + " as M3D.");
}
// create the root node
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->mNumChildren = 0;
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
importMaterials();
importTextures();
importBones(-1U, pScene->mRootNode);
importMeshes();
importAnimations();
// we don't need the SDK's version any more
m3d_free(m3d);
importMaterials(m3d);
importTextures(m3d);
importBones(m3d, -1U, pScene->mRootNode);
importMeshes(m3d);
importAnimations(m3d);
// Pop directory stack
if ( pIOHandler->StackSize() > 0 ) {
if (pIOHandler->StackSize() > 0) {
pIOHandler->PopDirectory();
}
}
// ------------------------------------------------------------------------------------------------
// 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;
m3dm_t *m;
aiString name = aiString(AI_DEFAULT_MATERIAL_NAME);
@ -252,42 +213,43 @@ void M3DImporter::importMaterials()
ai_real f;
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
ai_assert(m3d_wrap);
mScene->mNumMaterials = m3d->nummaterial + 1;
mScene->mMaterials = new aiMaterial*[ m3d->nummaterial + 1 ];
mScene->mNumMaterials = m3d_wrap->nummaterial + 1;
mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials);
// add a default material as first
aiMaterial* mat = new aiMaterial;
mat->AddProperty( &name, AI_MATKEY_NAME );
c.a = 1.0; c.b = c.g = c.r = 0.6;
mat->AddProperty( &c, 1, AI_MATKEY_COLOR_DIFFUSE);
aiMaterial *mat = new aiMaterial;
mat->AddProperty(&name, AI_MATKEY_NAME);
c.a = 1.0f;
c.b = c.g = c.r = 0.6f;
mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE);
mScene->mMaterials[0] = mat;
for(i = 0; i < m3d->nummaterial; i++) {
m = &m3d->material[i];
aiMaterial* mat = new aiMaterial;
for (i = 0; i < m3d_wrap->nummaterial; i++) {
m = &m3d_wrap->material[i];
aiMaterial *mat = new aiMaterial;
name.Set(std::string(m->name));
mat->AddProperty( &name, AI_MATKEY_NAME );
for(j = 0; j < m->numprop; j++) {
mat->AddProperty(&name, AI_MATKEY_NAME);
for (j = 0; j < m->numprop; j++) {
// look up property type
// 0 - 127 scalar values,
// 128 - 255 the same properties but for texture maps
k = 256;
for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++)
if(m->prop[j].type == m3d_propertytypes[l].id ||
for (l = 0; l < sizeof(m3d_propertytypes) / sizeof(m3d_propertytypes[0]); l++)
if (m->prop[j].type == m3d_propertytypes[l].id ||
m->prop[j].type == m3d_propertytypes[l].id + 128) {
k = l;
break;
}
// should never happen, but be safe than sorry
if(k == 256) continue;
if (k == 256) continue;
// scalar properties
if(m->prop[j].type < 128 && aiProps[k].pKey) {
switch(m3d_propertytypes[k].format) {
if (m->prop[j].type < 128 && aiProps[k].pKey) {
switch (m3d_propertytypes[k].format) {
case m3dpf_color:
c = mkColor(m->prop[j].value.color);
mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
@ -298,8 +260,8 @@ void M3DImporter::importMaterials()
break;
default:
n = m->prop[j].value.num;
if(m->prop[j].type == m3dp_il) {
switch(n) {
if (m->prop[j].type == m3dp_il) {
switch (n) {
case 0: n = aiShadingMode_NoShading; break;
case 2: n = aiShadingMode_Phong; break;
default: n = aiShadingMode_Gouraud; break;
@ -310,11 +272,11 @@ void M3DImporter::importMaterials()
}
}
// 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?
m->prop[j].value.textureid < m3d->numtexture &&
m3d->texture[m->prop[j].value.textureid].name) {
name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png"));
m->prop[j].value.textureid < m3d_wrap->numtexture &&
m3d_wrap->texture[m->prop[j].value.textureid].name) {
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);
n = 0;
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
void M3DImporter::importTextures()
{
void M3DImporter::importTextures(const M3DWrapper &m3d) {
unsigned int i;
const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
m3dtx_t *t;
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
ai_assert(m3d);
mScene->mNumTextures = m3d->numtexture;
ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures);
if(!m3d->numtexture)
if (!m3d->numtexture)
return;
mScene->mTextures = new aiTexture*[m3d->numtexture];
for(i = 0; i < m3d->numtexture; i++) {
mScene->mTextures = new aiTexture *[m3d->numtexture];
for (i = 0; i < m3d->numtexture; i++) {
unsigned int j, k;
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;
strcpy(tx->achFormatHint, formatHint[t->f - 1]);
tx->mFilename = aiString(std::string(t->name) + ".png");
tx->mWidth = t->w;
tx->mHeight = t->h;
tx->pcData = new aiTexel[ tx->mWidth*tx->mHeight ];
for(j = k = 0; j < tx->mWidth*tx->mHeight; j++) {
switch(t->f) {
tx->pcData = new aiTexel[tx->mWidth * tx->mHeight];
for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) {
switch (t->f) {
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:
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = 255;
tx->pcData[j].r = t->d[k++];
tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++];
tx->pcData[j].a = 255;
break;
case 4:
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = t->d[k++];
tx->pcData[j].r = 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;
}
}
@ -374,10 +342,9 @@ void M3DImporter::importTextures()
// 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
// indexed simultaneously.
void M3DImporter::importMeshes()
{
void M3DImporter::importMeshes(const M3DWrapper &m3d) {
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<aiVector3D> *vertices = nullptr;
std::vector<aiVector3D> *normals = nullptr;
@ -387,17 +354,17 @@ void M3DImporter::importMeshes()
aiMesh *pMesh = nullptr;
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
ai_assert(m3d);
ai_assert(mScene->mRootNode != nullptr);
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
if(lastMat != m3d->face[i].materialid) {
if (lastMat != m3d->face[i].materialid) {
lastMat = m3d->face[i].materialid;
if(pMesh && vertices && vertices->size() && faces && faces->size()) {
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids);
if (pMesh && vertices && vertices->size() && faces && faces->size()) {
populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids);
meshes->push_back(pMesh);
delete faces;
delete vertices;
@ -420,9 +387,9 @@ void M3DImporter::importMeshes()
aiFace *pFace = new aiFace;
pFace->mNumIndices = numpoly;
pFace->mIndices = new unsigned int[numpoly];
for(j = 0; j < numpoly; j++) {
for (j = 0; j < numpoly; j++) {
aiVector3D pos, uv, norm;
k = vertices->size();
k = static_cast<unsigned int>(vertices->size());
pFace->mIndices[j] = k;
l = m3d->face[i].vertex[j];
pos.x = m3d->vertex[l].x;
@ -431,20 +398,20 @@ void M3DImporter::importMeshes()
vertices->push_back(pos);
colors->push_back(mkColor(m3d->vertex[l].color));
// 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
// vertex but assimp uses lists of local vertex id/weight pairs per local bone list
vertexids->push_back(l);
}
l = m3d->face[i].texcoord[j];
if(l != -1U) {
if (l != -1U) {
uv.x = m3d->tmap[l].u;
uv.y = m3d->tmap[l].v;
uv.z = 0.0;
texcoords->push_back(uv);
}
l = m3d->face[i].normal[j];
if(l != -1U) {
if (l != -1U) {
norm.x = m3d->vertex[l].x;
norm.y = m3d->vertex[l].y;
norm.z = m3d->vertex[l].z;
@ -455,58 +422,57 @@ void M3DImporter::importMeshes()
delete pFace;
}
// if there's data left in the temporary vectors, flush them
if(pMesh && vertices->size() && faces->size()) {
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids);
if (pMesh && vertices->size() && faces->size()) {
populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids);
meshes->push_back(pMesh);
}
// create global mesh list in scene
mScene->mNumMeshes = meshes->size();
mScene->mMeshes = new aiMesh*[mScene->mNumMeshes];
mScene->mNumMeshes = static_cast<unsigned int>(meshes->size());
mScene->mMeshes = new aiMesh *[mScene->mNumMeshes];
std::copy(meshes->begin(), meshes->end(), mScene->mMeshes);
// 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()];
for(i = 0; i < meshes->size(); i++) {
for (i = 0; i < meshes->size(); i++) {
mScene->mRootNode->mMeshes[i] = i;
}
delete meshes;
if(faces) delete faces;
if(vertices) delete vertices;
if(normals) delete normals;
if(texcoords) delete texcoords;
if(colors) delete colors;
if(vertexids) delete vertexids;
if (faces) delete faces;
if (vertices) delete vertices;
if (normals) delete normals;
if (texcoords) delete texcoords;
if (colors) delete colors;
if (vertexids) delete vertexids;
}
// ------------------------------------------------------------------------------------------------
// 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;
ai_assert(pParent != nullptr);
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
ai_assert(m3d);
ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid);
for(n = 0, i = parentid + 1; i < m3d->numbone; i++)
if(m3d->bone[i].parent == parentid) n++;
pParent->mChildren = new aiNode*[n];
for (n = 0, i = parentid + 1; i < m3d->numbone; i++)
if (m3d->bone[i].parent == parentid) n++;
pParent->mChildren = new aiNode *[n];
for(i = parentid + 1; i < m3d->numbone; i++) {
if(m3d->bone[i].parent == parentid) {
for (i = parentid + 1; i < m3d->numbone; i++) {
if (m3d->bone[i].parent == parentid) {
aiNode *pChild = new aiNode;
pChild->mParent = pParent;
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;
pParent->mChildren[pParent->mNumChildren] = pChild;
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
// 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
void M3DImporter::importAnimations()
{
void M3DImporter::importAnimations(const M3DWrapper &m3d) {
unsigned int i, j, k, l, pos, ori;
double t;
m3da_t *a;
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
ai_assert(m3d);
mScene->mNumAnimations = m3d->numaction;
ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations);
if(!m3d->numaction || !m3d->numbone)
if (!m3d->numaction || !m3d->numbone)
return;
mScene->mAnimations = new aiAnimation*[m3d->numaction];
for(i = 0; i < m3d->numaction; i++) {
mScene->mAnimations = new aiAnimation *[m3d->numaction];
for (i = 0; i < m3d->numaction; i++) {
a = &m3d->action[i];
aiAnimation *pAnim = new aiAnimation;
pAnim->mName = aiString(std::string(a->name));
@ -540,8 +505,8 @@ void M3DImporter::importAnimations()
pAnim->mTicksPerSecond = 100;
// now we know how many bones are referenced in this animation
pAnim->mNumChannels = m3d->numbone;
pAnim->mChannels = new aiNodeAnim*[pAnim->mNumChannels];
for(l = 0; l < m3d->numbone; l++) {
pAnim->mChannels = new aiNodeAnim *[pAnim->mNumChannels];
for (l = 0; l < m3d->numbone; l++) {
unsigned int n;
pAnim->mChannels[l] = new aiNodeAnim;
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];
pos = m3d->bone[l].pos;
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;
for(k = 0; k < a->frame[j].numtransform; k++) {
if(a->frame[j].transform[k].boneid == l) {
for (k = 0; k < a->frame[j].numtransform; k++) {
if (a->frame[j].transform[k].boneid == l) {
pos = a->frame[j].transform[k].pos;
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.y = q->y;
pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z;
}// foreach frame
}// foreach bones
} // foreach frame
} // foreach bones
mScene->mAnimations[i] = pAnim;
}
}
@ -580,72 +545,83 @@ void M3DImporter::importAnimations()
// convert uint32_t into aiColor4D
aiColor4D M3DImporter::mkColor(uint32_t c) {
aiColor4D color;
color.a = ((float)((c >> 24)&0xff)) / 255;
color.b = ((float)((c >> 16)&0xff)) / 255;
color.g = ((float)((c >> 8)&0xff)) / 255;
color.r = ((float)((c >> 0)&0xff)) / 255;
color.a = ((float)((c >> 24) & 0xff)) / 255;
color.b = ((float)((c >> 16) & 0xff)) / 255;
color.g = ((float)((c >> 8) & 0xff)) / 255;
color.r = ((float)((c >> 0) & 0xff)) / 255;
return color;
}
// ------------------------------------------------------------------------------------------------
// 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(m3d != nullptr);
ai_assert(m3d);
ai_assert(posid != -1U && posid < m3d->numvertex);
ai_assert(orientid != -1U && orientid < m3d->numvertex);
m3dv_t *p = &m3d->vertex[posid];
m3dv_t *q = &m3d->vertex[orientid];
/* 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->a1 = m->b2 = m->c3 = -1.0;
} 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->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 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->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 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;
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->a2 = 2 * (q->x * q->y - q->z * q->w);
if (m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 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->b1 = 2 * (q->x * q->y + q->z * q->w);
if (m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 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 */
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
aiNode *M3DImporter::findNode(aiNode *pNode, aiString name)
{
aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) {
unsigned int i;
ai_assert(pNode != nullptr);
ai_assert(mScene != nullptr);
if(pNode->mName == name)
if (pNode->mName == name)
return pNode;
for(i = 0; i < pNode->mNumChildren; i++) {
for (i = 0; i < pNode->mNumChildren; i++) {
aiNode *pChild = findNode(pNode->mChildren[i], name);
if(pChild) return pChild;
if (pChild) return pChild;
}
return nullptr;
}
// ------------------------------------------------------------------------------------------------
// 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(mScene != nullptr);
if(pNode->mParent) {
if (pNode->mParent) {
calculateOffsetMatrix(pNode->mParent, m);
*m *= pNode->mTransformation;
} 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
// 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
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<unsigned int> *vertexids) {
@ -668,28 +644,28 @@ void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::v
ai_assert(texcoords != nullptr);
ai_assert(colors != nullptr);
ai_assert(vertexids != nullptr);
ai_assert(m3d != nullptr);
ai_assert(m3d);
ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(),
" numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone);
if(vertices->size() && faces->size()) {
pMesh->mNumFaces = faces->size();
if (vertices->size() && faces->size()) {
pMesh->mNumFaces = static_cast<unsigned int>(faces->size());
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
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];
std::copy(vertices->begin(), vertices->end(), pMesh->mVertices);
if(normals->size() == vertices->size()) {
if (normals->size() == vertices->size()) {
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
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];
std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]);
pMesh->mNumUVComponents[0] = 2;
}
if(colors->size() == vertices->size()) {
if (colors->size() == vertices->size()) {
pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
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
pMesh->mNumBones = m3d->numbone;
/* we need aiBone with mOffsetMatrix for bones without weights as well */
if(pMesh->mNumBones) {
pMesh->mBones = new aiBone*[pMesh->mNumBones];
for(unsigned int i = 0; i < m3d->numbone; i++) {
if (pMesh->mNumBones) {
pMesh->mBones = new aiBone *[pMesh->mNumBones];
for (unsigned int i = 0; i < m3d->numbone; i++) {
aiNode *pNode;
pMesh->mBones[i] = new aiBone;
pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name));
pMesh->mBones[i]->mNumWeights = 0;
pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName);
if(pNode) {
if (pNode) {
calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix);
pMesh->mBones[i]->mOffsetMatrix.Inverse();
} else
pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4();
}
if(vertexids->size()) {
if (vertexids->size()) {
unsigned int i, j;
// 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;
if(s != -1U && s!= -2U) {
for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
if (s != -1U && s != -2U) {
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));
for(j = 0; j < pMesh->mNumBones; j++) {
if(pMesh->mBones[j]->mName == name) {
for (j = 0; j < pMesh->mNumBones; j++) {
if (pMesh->mBones[j]->mName == name) {
pMesh->mBones[j]->mNumWeights++;
break;
}
@ -729,21 +705,21 @@ void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::v
}
}
// allocate mWeights
for(j = 0; j < pMesh->mNumBones; j++) {
for (j = 0; j < pMesh->mNumBones; j++) {
aiBone *pBone = pMesh->mBones[j];
if(pBone->mNumWeights) {
if (pBone->mNumWeights) {
pBone->mWeights = new aiVertexWeight[pBone->mNumWeights];
pBone->mNumWeights = 0;
}
}
// 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;
if(s != -1U && s!= -2U) {
for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
if (s != -1U && s != -2U) {
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));
for(j = 0; j < pMesh->mNumBones; j++) {
if(pMesh->mBones[j]->mName == name) {
for (j = 0; j < pMesh->mNumBones; j++) {
if (pMesh->mBones[j]->mName == name) {
aiBone *pBone = pMesh->mBones[j];
pBone->mWeights[pBone->mNumWeights].mVertexId = i;
pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k];

View File

@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#include "m3d.h"
#include <assimp/BaseImporter.h>
#include <assimp/material.h>
#include <vector>
@ -60,41 +59,39 @@ struct aiFace;
namespace Assimp {
class M3DWrapper;
class M3DImporter : public BaseImporter {
public:
/// \brief Default constructor
M3DImporter();
/// \brief Destructor
~M3DImporter();
public:
/// \brief Returns whether the class can handle the format of the given file.
/// \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:
aiScene* mScene; // the scene to import to
m3d_t *m3d; // model for the C library to convert from
aiScene *mScene = nullptr; // the scene to import to
//! \brief Appends the supported extension.
const aiImporterDesc* GetInfo () const;
const aiImporterDesc *GetInfo() const;
//! \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 importTextures();
void importMeshes();
void importBones(unsigned int parentid, aiNode *pParent);
void importAnimations();
void importMaterials(const M3DWrapper &m3d);
void importTextures(const M3DWrapper &m3d);
void importMeshes(const M3DWrapper &m3d);
void importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent);
void importAnimations(const M3DWrapper &m3d);
// helper functions
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);
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<unsigned int> *vertexids);
};

View File

@ -0,0 +1,142 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
#include "M3DWrapper.h"
#include <assimp/DefaultIOSystem.h>
#include <assimp/IOStreamBuffer.h>
#include <assimp/ai_assert.h>
#ifndef AI_M3D_USE_STDMUTEX
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900) // C++11 and MSVC 2015 onwards
#define AI_M3D_USE_STDMUTEX 1
#else
#define AI_M3D_USE_STDMUTEX 0
#endif
#endif
#if AI_M3D_USE_STDMUTEX
#include <mutex>
std::mutex file_mutex;
#endif
// workaround: the M3D SDK expects a C callback, but we want to use Assimp::IOSystem to implement that
// This makes it non-rentrant so lock a mutex (requires C++11)
extern "C" {
void *m3dimporter_pIOHandler;
unsigned char *m3dimporter_readfile(char *fn, unsigned int *size) {
ai_assert(nullptr != fn);
ai_assert(nullptr != size);
std::string file(fn);
std::unique_ptr<Assimp::IOStream> pStream(
(reinterpret_cast<Assimp::IOSystem *>(m3dimporter_pIOHandler))->Open(file, "rb"));
size_t fileSize = 0;
unsigned char *data = NULL;
// sometimes pStream is nullptr for some reason (should be an empty object returning nothing I guess)
if (pStream) {
fileSize = pStream->FileSize();
// should be allocated with malloc(), because the library will call free() to deallocate
data = (unsigned char *)malloc(fileSize);
if (!data || !pStream.get() || !fileSize || fileSize != pStream->Read(data, 1, fileSize)) {
pStream.reset();
*size = 0;
// don't throw a deadly exception, it's not fatal if we can't read an external asset
return nullptr;
}
pStream.reset();
}
*size = (int)fileSize;
return data;
}
}
namespace Assimp {
M3DWrapper::M3DWrapper() {
// use malloc() here because m3d_free() will call free()
m3d_ = (m3d_t *)calloc(1, sizeof(m3d_t));
}
M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer) {
#if AI_M3D_USE_STDMUTEX
// M3D is NOT thread-safe, so lock the global mutex
const std::lock_guard<std::mutex> lock(file_mutex);
#endif
// pass this IOHandler to the C callback
m3dimporter_pIOHandler = pIOHandler;
m3d_ = m3d_load(const_cast<unsigned char *>(buffer.data()), m3dimporter_readfile, free, nullptr);
// Clear the C callback
m3dimporter_pIOHandler = nullptr;
}
M3DWrapper::~M3DWrapper() {
reset();
}
void M3DWrapper::reset() {
ClearSave();
if (m3d_)
m3d_free(m3d_);
m3d_ = nullptr;
}
unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) {
#if (!(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER))
ClearSave();
saved_output_ = m3d_save(m3d_, quality, flags, &size);
return saved_output_;
#else
return nullptr;
#endif
}
void M3DWrapper::ClearSave() {
if (saved_output_)
M3D_FREE(saved_output_);
saved_output_ = nullptr;
}
} // namespace Assimp
#endif

View File

@ -0,0 +1,97 @@
#pragma once
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file M3DWrapper.h
* @brief Declares a class to wrap the C m3d SDK
*/
#ifndef AI_M3DWRAPPER_H_INC
#define AI_M3DWRAPPER_H_INC
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
#include <memory>
#include <vector>
#include <string>
#include "m3d.h"
namespace Assimp {
class IOSystem;
class M3DWrapper {
m3d_t *m3d_ = nullptr;
unsigned char *saved_output_ = nullptr;
public:
// Construct an empty M3D model
explicit M3DWrapper();
// Construct an M3D model from provided buffer
// NOTE: The m3d.h SDK function does not mark the data as const. Have assumed it does not write.
// BUG: SECURITY: The m3d.h SDK cannot be informed of the buffer size. BUFFER OVERFLOW IS CERTAIN
explicit M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer);
~M3DWrapper();
void reset();
// Name
inline std::string Name() const {
if (m3d_) return std::string(m3d_->name);
return std::string();
}
// Execute a save
unsigned char *Save(int quality, int flags, unsigned int &size);
void ClearSave();
inline explicit operator bool() const { return m3d_ != nullptr; }
// Allow direct access to M3D API
inline m3d_t *operator->() const { return m3d_; }
inline m3d_t *M3D() const { return m3d_; }
};
} // namespace Assimp
#endif
#endif // AI_M3DWRAPPER_H_INC

View File

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

View File

@ -43,13 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the aiProcess_OptimizGraph step
*/
#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
#include "OptimizeGraph.h"
#include "ProcessHelper.h"
#include <assimp/SceneCombiner.h>
#include "ConvertToLHProcess.h"
#include <assimp/Exceptional.h>
#include <assimp/SceneCombiner.h>
#include <stdio.h>
using namespace Assimp;
@ -60,21 +60,21 @@ using namespace Assimp;
* The unhashed variant should be faster, except for *very* large data sets
*/
#ifdef AI_OG_USE_HASHING
// Use our standard hashing function to compute the hash
# define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length)
// Use our standard hashing function to compute the hash
#define AI_OG_GETKEY(str) SuperFastHash(str.data, str.length)
#else
// Otherwise hope that std::string will utilize a static buffer
// for shorter node names. This would avoid endless heap copying.
# define AI_OG_GETKEY(str) std::string(str.data)
// Otherwise hope that std::string will utilize a static buffer
// for shorter node names. This would avoid endless heap copying.
#define AI_OG_GETKEY(str) std::string(str.data)
#endif
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
OptimizeGraphProcess::OptimizeGraphProcess()
: mScene()
, nodes_in()
, nodes_out()
, count_merged() {
OptimizeGraphProcess::OptimizeGraphProcess() :
mScene(),
nodes_in(),
nodes_out(),
count_merged() {
// empty
}
@ -86,33 +86,33 @@ OptimizeGraphProcess::~OptimizeGraphProcess() {
// ------------------------------------------------------------------------------------------------
// 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));
}
// ------------------------------------------------------------------------------------------------
// 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
std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,"");
std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST, "");
AddLockedNodeList(tmp);
}
// ------------------------------------------------------------------------------------------------
// 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;
// Process children
std::list<aiNode*> child_nodes;
std::list<aiNode *> child_nodes;
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;
}
// 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() ) {
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end()) {
for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) {
(*it)->mTransformation = nd->mTransformation * (*it)->mTransformation;
@ -136,19 +136,19 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
nodes.push_back(nd);
// 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;
const LockedSetType::const_iterator end = locked.end();
std::list<aiNode*> join;
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
aiNode* child = *it;
std::list<aiNode *> join;
for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end();) {
aiNode *child = *it;
if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) {
// There may be no instanced meshes
unsigned int n = 0;
for (; n < child->mNumMeshes;++n) {
for (; n < child->mNumMeshes; ++n) {
if (meshes[child->mMeshes[n]] > 1) {
break;
}
@ -159,7 +159,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
inv = join_master->mTransformation;
inv.Inverse();
} else {
child->mTransformation = inv * child->mTransformation ;
child->mTransformation = inv * child->mTransformation;
join.push_back(child);
it = child_nodes.erase(it);
@ -170,31 +170,40 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
++it;
}
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;
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;
}
// copy all mesh references in one array
if (out_meshes) {
unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes;
for (unsigned int n = 0; n < join_master->mNumMeshes;++n) {
unsigned int *meshes = new unsigned int[out_meshes + join_master->mNumMeshes], *tmp = meshes;
for (unsigned int n = 0; n < join_master->mNumMeshes; ++n) {
*tmp++ = join_master->mMeshes[n];
}
for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) {
for (const aiNode *join_node : join) {
for (unsigned int n = 0; n < join_node->mNumMeshes; ++n) {
*tmp = (*it)->mMeshes[n];
aiMesh* mesh = mScene->mMeshes[*tmp++];
*tmp = join_node->mMeshes[n];
aiMesh *mesh = mScene->mMeshes[*tmp++];
// Assume the transformation is affine
// 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) {
mesh->mVertices[a] *= (*it)->mTransformation;
mesh->mVertices[a] *= join_node->mTransformation;
if (mesh->HasNormals())
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;
join_master->mMeshes = meshes;
@ -219,17 +228,17 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
delete[] nd->mChildren;
if (!child_nodes.empty()) {
nd->mChildren = new aiNode*[child_nodes.size()];
}
else nd->mChildren = nullptr;
nd->mChildren = new aiNode *[child_nodes.size()];
} else
nd->mChildren = nullptr;
}
nd->mNumChildren = static_cast<unsigned int>(child_nodes.size());
if (nd->mChildren) {
aiNode** tmp = nd->mChildren;
for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
aiNode* node = *tmp++ = *it;
aiNode **tmp = nd->mChildren;
for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
aiNode *node = *tmp++ = *it;
node->mParent = nd;
}
}
@ -239,12 +248,12 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
// ------------------------------------------------------------------------------------------------
// Execute the post-processing step on the given scene
void OptimizeGraphProcess::Execute( aiScene* pScene) {
void OptimizeGraphProcess::Execute(aiScene *pScene) {
ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin");
nodes_in = nodes_out = count_merged = 0;
mScene = pScene;
meshes.resize(pScene->mNumMeshes,0);
meshes.resize(pScene->mNumMeshes, 0);
FindInstancedMeshes(pScene->mRootNode);
// 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 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));
}
}
@ -267,7 +276,7 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) {
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
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));
// 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) {
aiCamera* cam = pScene->mCameras[i];
aiCamera *cam = pScene->mCameras[i];
locked.insert(AI_OG_GETKEY(cam->mName));
}
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));
}
// 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));
const aiString prev = pScene->mRootNode->mName;
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;
// Do our recursive processing of scenegraph nodes. For each node collect
// a fully new list of children and allow their children to place themselves
// on the same hierarchy layer as their parents.
std::list<aiNode*> nodes;
CollectNewChildren (dummy_root,nodes);
std::list<aiNode *> nodes;
CollectNewChildren(dummy_root, nodes);
ai_assert(nodes.size() == 1);
if (dummy_root->mNumChildren == 0) {
pScene->mRootNode = NULL;
pScene->mRootNode = nullptr;
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
pScene->mRootNode->mName = prev;
}
else {
} else {
// Remove the dummy root node again.
pScene->mRootNode = dummy_root->mChildren[0];
dummy_root->mChildren[0] = NULL;
dummy_root->mChildren[0] = nullptr;
delete dummy_root;
}
pScene->mRootNode->mParent = NULL;
pScene->mRootNode->mParent = nullptr;
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);
} else {
ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished");
@ -338,9 +346,8 @@ void OptimizeGraphProcess::Execute( aiScene* pScene) {
// ------------------------------------------------------------------------------------------------
// Build a LUT of all instanced meshes
void OptimizeGraphProcess::FindInstancedMeshes (aiNode* pNode)
{
for (unsigned int i = 0; i < pNode->mNumMeshes;++i) {
void OptimizeGraphProcess::FindInstancedMeshes(aiNode *pNode) {
for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) {
++meshes[pNode->mMeshes[i]];
}

View File

@ -75,13 +75,13 @@ public:
~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.

View File

@ -45,11 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the "PretransformVertices" post processing step
*/
#include "PretransformVertices.h"
#include "ConvertToLHProcess.h"
#include "ProcessHelper.h"
#include <assimp/SceneCombiner.h>
#include <assimp/Exceptional.h>
#include <assimp/SceneCombiner.h>
using namespace Assimp;
@ -59,12 +59,12 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
PretransformVertices::PretransformVertices()
: configKeepHierarchy (false)
, configNormalize(false)
, configTransform(false)
, configTransformation()
, mConfigPointCloud( false ) {
PretransformVertices::PretransformVertices() :
configKeepHierarchy(false),
configNormalize(false),
configTransform(false),
configTransformation(),
mConfigPointCloud(false) {
// empty
}
@ -76,20 +76,18 @@ PretransformVertices::~PretransformVertices() {
// ------------------------------------------------------------------------------------------------
// 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;
}
// ------------------------------------------------------------------------------------------------
// 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,
// 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));
configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0));
configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0));
configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0));
configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0));
configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0));
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
unsigned int PretransformVertices::CountNodes( aiNode* pcNode )
{
unsigned int PretransformVertices::CountNodes(const aiNode *pcNode) const {
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]);
}
return iRet;
@ -110,8 +106,7 @@ unsigned int PretransformVertices::CountNodes( aiNode* pcNode )
// ------------------------------------------------------------------------------------------------
// 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.
// there isn't a good reason to compute it a few hundred times
// from scratch. The pointer is unused as animations are lost
@ -119,56 +114,47 @@ unsigned int PretransformVertices::GetMeshVFormat( aiMesh* pcMesh )
if (pcMesh->mBones)
return (unsigned int)(uint64_t)pcMesh->mBones;
const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
// store the value for later use
pcMesh->mBones = (aiBone**)(uint64_t)iRet;
pcMesh->mBones = (aiBone **)(uint64_t)iRet;
return iRet;
}
// ------------------------------------------------------------------------------------------------
// Count the number of vertices in the whole scene and a given
// material index
void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices)
{
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
{
aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ];
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh))
{
void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const {
for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) {
aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]];
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) {
*piVertices += pcMesh->mNumVertices;
*piFaces += pcMesh->mNumFaces;
}
}
for (unsigned int i = 0;i < pcNode->mNumChildren;++i)
{
CountVerticesAndFaces(pcScene,pcNode->mChildren[i],iMat,
iVFormat,piFaces,piVertices);
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat,
iVFormat, piFaces, piVertices);
}
}
// ------------------------------------------------------------------------------------------------
// Collect vertex/face data
void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
unsigned int iVFormat, aiMesh* pcMeshOut,
unsigned int aiCurrent[2], unsigned int* num_refs)
{
void PretransformVertices::CollectData(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
unsigned int iVFormat, aiMesh *pcMeshOut,
unsigned int aiCurrent[2], unsigned int *num_refs) const {
// No need to multiply if there's no transformation
const bool identity = pcNode->mTransformation.IsIdentity();
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
{
aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ];
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh))
{
for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) {
aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]];
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) {
// 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);
--num_ref;
// Save the name of the last mesh
if (num_ref==0)
{
if (num_ref == 0) {
pcMeshOut->mName = pcMesh->mName;
}
@ -184,8 +170,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
pcMesh->mNormals,
pcMesh->mNumVertices * sizeof(aiVector3D));
}
if (iVFormat & 0x4)
{
if (iVFormat & 0x4) {
// copy tangents without modifying them
::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX],
pcMesh->mTangents,
@ -195,12 +180,10 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
pcMesh->mBitangents,
pcMesh->mNumVertices * sizeof(aiVector3D));
}
}
else
{
} else {
// copy positions, transform them to worldspace
for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n];
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX] + n] = pcNode->mTransformation * pcMesh->mVertices[n];
}
aiMatrix4x4 mWorldIT = pcNode->mTransformation;
mWorldIT.Inverse().Transpose();
@ -208,26 +191,23 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
// TODO: implement Inverse() for aiMatrix3x3
aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
if (iVFormat & 0x2)
{
if (iVFormat & 0x2) {
// copy normals, transform them to worldspace
for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] =
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX] + n] =
(m * pcMesh->mNormals[n]).Normalize();
}
}
if (iVFormat & 0x4)
{
if (iVFormat & 0x4) {
// copy tangents and bitangents, transform them to worldspace
for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
pcMeshOut->mTangents [aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mTangents[n]).Normalize();
pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mBitangents[n]).Normalize();
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
pcMeshOut->mTangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mTangents[n]).Normalize();
pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mBitangents[n]).Normalize();
}
}
}
unsigned int p = 0;
while (iVFormat & (0x100 << p))
{
while (iVFormat & (0x100 << p)) {
// copy texture coordinates
memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX],
pcMesh->mTextureCoords[p],
@ -235,8 +215,7 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
++p;
}
p = 0;
while (iVFormat & (0x1000000 << p))
{
while (iVFormat & (0x1000000 << p)) {
// copy vertex colors
memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX],
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,
// we don't need to reallocate the array of indices except if this mesh is
// referenced multiple times.
for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck)
{
aiFace& f_src = pcMesh->mFaces[planck];
aiFace& f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck];
for (unsigned int planck = 0; planck < pcMesh->mNumFaces; ++planck) {
aiFace &f_src = pcMesh->mFaces[planck];
aiFace &f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE] + planck];
const unsigned int num_idx = f_src.mNumIndices;
f_dst.mNumIndices = num_idx;
unsigned int* pi;
unsigned int *pi;
if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */
pi = f_dst.mIndices = f_src.mIndices;
// 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];
}
}
else {
} else {
pi = f_dst.mIndices = new unsigned int[num_idx];
// 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];
}
}
// Update the mPrimitiveTypes member of the mesh
switch (pcMesh->mFaces[planck].mNumIndices)
{
switch (pcMesh->mFaces[planck].mNumIndices) {
case 0x1:
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT;
break;
@ -296,21 +272,19 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
}
// append all children of us
for (unsigned int i = 0;i < pcNode->mNumChildren;++i) {
CollectData(pcScene,pcNode->mChildren[i],iMat,
iVFormat,pcMeshOut,aiCurrent,num_refs);
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
CollectData(pcScene, pcNode->mChildren[i], iMat,
iVFormat, pcMeshOut, aiCurrent, num_refs);
}
}
// ------------------------------------------------------------------------------------------------
// Get a list of all vertex formats that occur for a given material index
// The output list contains duplicate elements
void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat,
std::list<unsigned int>& aiOut)
{
for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
{
aiMesh* pcMesh = pcScene->mMeshes[ i ];
void PretransformVertices::GetVFormatList(const aiScene *pcScene, unsigned int iMat,
std::list<unsigned int> &aiOut) const {
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
aiMesh *pcMesh = pcScene->mMeshes[i];
if (iMat == pcMesh->mMaterialIndex) {
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
void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode )
{
void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
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]);
}
}
// ------------------------------------------------------------------------------------------------
// 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
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()) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
mesh->mVertices[i] = mat * mesh->mVertices[i];
}
}
if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
aiMatrix4x4 mWorldIT = mat;
mWorldIT.Inverse().Transpose();
// TODO: implement Inverse() for aiMatrix3x3
aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
// Update normals and tangents
if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose();
if (mesh->HasNormals()) {
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
void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in,
unsigned int numIn, aiNode* node)
{
void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in,
unsigned int numIn, aiNode *node) const {
// NOTE:
// aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy
// aiMesh::mBones store reference to abs. transform we multiplied with
// process meshes
for (unsigned int i = 0; i < node->mNumMeshes;++i) {
aiMesh* mesh = in[node->mMeshes[i]];
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
aiMesh *mesh = in[node->mMeshes[i]];
// 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.
mesh->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
mesh->mNumBones = UINT_MAX;
}
else {
} else {
// try to find us in the list of newly created meshes
for (unsigned int n = 0; n < out.size(); ++n) {
aiMesh* ctz = out[n];
if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4*>(ctz->mBones) == node->mTransformation) {
aiMesh *ctz = out[n];
if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4 *>(ctz->mBones) == node->mTransformation) {
// ok, use this one. Update node mesh index
node->mMeshes[i] = numIn + n;
@ -397,15 +372,15 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in
if (node->mMeshes[i] < numIn) {
// Worst case. Need to operate on a full copy of the mesh
ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms");
aiMesh* ntz;
aiMesh *ntz;
const unsigned int tmp = mesh->mNumBones; //
mesh->mNumBones = 0;
SceneCombiner::Copy(&ntz,mesh);
SceneCombiner::Copy(&ntz, mesh);
mesh->mNumBones = tmp;
ntz->mNumBones = node->mMeshes[i];
ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
out.push_back(ntz);
@ -415,37 +390,34 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in
}
// call children
for (unsigned int i = 0; i < node->mNumChildren;++i)
BuildWCSMeshes(out,in,numIn,node->mChildren[i]);
for (unsigned int i = 0; i < node->mNumChildren; ++i)
BuildWCSMeshes(out, in, numIn, node->mChildren[i]);
}
// ------------------------------------------------------------------------------------------------
// Reset transformation matrices to identity
void PretransformVertices::MakeIdentityTransform(aiNode* nd)
{
void PretransformVertices::MakeIdentityTransform(aiNode *nd) const {
nd->mTransformation = aiMatrix4x4();
// call children
for (unsigned int i = 0; i < nd->mNumChildren;++i)
for (unsigned int i = 0; i < nd->mNumChildren; ++i)
MakeIdentityTransform(nd->mChildren[i]);
}
// ------------------------------------------------------------------------------------------------
// Build reference counters for all meshes
void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs)
{
for (unsigned int i = 0; i< nd->mNumMeshes;++i)
void PretransformVertices::BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const {
for (unsigned int i = 0; i < nd->mNumMeshes; ++i)
refs[nd->mMeshes[i]]++;
// call children
for (unsigned int i = 0; i < nd->mNumChildren;++i)
BuildMeshRefCountArray(nd->mChildren[i],refs);
for (unsigned int i = 0; i < nd->mNumChildren; ++i)
BuildMeshRefCountArray(nd->mChildren[i], refs);
}
// ------------------------------------------------------------------------------------------------
// 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");
// 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 iOldNodes = CountNodes(pScene->mRootNode);
if(configTransform) {
if (configTransform) {
pScene->mRootNode->mTransformation = configTransformation;
}
@ -466,10 +438,10 @@ void PretransformVertices::Execute( aiScene* pScene)
// Delete aiMesh::mBones for all meshes. The bones are
// removed during this step and we need the pointer as
// temporary storage
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
aiMesh* mesh = pScene->mMeshes[i];
for (unsigned int i = 0; i < pScene->mNumMeshes; ++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;
@ -477,74 +449,74 @@ void PretransformVertices::Execute( aiScene* pScene)
}
// 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 ...
// we go on and transform all meshes, if one is referenced by nodes
// with different absolute transformations a depth copy of the mesh
// is required.
if( configKeepHierarchy ) {
if (configKeepHierarchy) {
// 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 (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->mNumMeshes,&apcOutMeshes[0],sizeof(aiMesh*)*apcOutMeshes.size());
memcpy(npp, pScene->mMeshes, sizeof(aiMesh *) * pScene->mNumMeshes);
memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * 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
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
pScene->mMeshes[i]->mBones = NULL;
pScene->mMeshes[i]->mNumBones = 0;
}
} else {
apcOutMeshes.reserve(pScene->mNumMaterials<<1u);
apcOutMeshes.reserve(pScene->mNumMaterials << 1u);
std::list<unsigned int> aiVFormats;
std::vector<unsigned int> s(pScene->mNumMeshes,0);
BuildMeshRefCountArray(pScene->mRootNode,&s[0]);
std::vector<unsigned int> s(pScene->mNumMeshes, 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
aiVFormats.clear();
GetVFormatList(pScene,i,aiVFormats);
GetVFormatList(pScene, i, aiVFormats);
aiVFormats.sort();
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 iFaces = 0;
CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices);
if (0 != iFaces && 0 != iVertices)
{
CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices);
if (0 != iFaces && 0 != iVertices) {
apcOutMeshes.push_back(new aiMesh());
aiMesh* pcMesh = apcOutMeshes.back();
aiMesh *pcMesh = apcOutMeshes.back();
pcMesh->mNumFaces = iFaces;
pcMesh->mNumVertices = iVertices;
pcMesh->mFaces = new aiFace[iFaces];
pcMesh->mVertices = new aiVector3D[iVertices];
pcMesh->mMaterialIndex = i;
if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices];
if ((*j) & 0x4)
{
if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices];
if ((*j) & 0x4) {
pcMesh->mTangents = new aiVector3D[iVertices];
pcMesh->mBitangents = new aiVector3D[iVertices];
}
iFaces = 0;
while ((*j) & (0x100 << iFaces))
{
while ((*j) & (0x100 << iFaces)) {
pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices];
if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3;
else pcMesh->mNumUVComponents[iFaces] = 2;
if ((*j) & (0x10000 << iFaces))
pcMesh->mNumUVComponents[iFaces] = 3;
else
pcMesh->mNumUVComponents[iFaces] = 2;
iFaces++;
}
iFaces = 0;
@ -552,8 +524,8 @@ void PretransformVertices::Execute( aiScene* pScene)
pcMesh->mColors[iFaces++] = new aiColor4D[iVertices];
// fill the mesh ...
unsigned int aiTemp[2] = {0,0};
CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]);
unsigned int aiTemp[2] = { 0, 0 };
CollectData(pScene, pScene->mRootNode, i, *j, pcMesh, aiTemp, &s[0]);
}
}
}
@ -562,13 +534,10 @@ void PretransformVertices::Execute( aiScene* pScene)
if (apcOutMeshes.empty()) {
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
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
aiMesh* mesh = pScene->mMeshes[i];
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
aiMesh *mesh = pScene->mMeshes[i];
mesh->mNumBones = 0;
mesh->mBones = NULL;
@ -591,14 +560,14 @@ void PretransformVertices::Execute( aiScene* pScene)
// It is impossible that we have more output meshes than
// input meshes, so we can easily reuse the old mesh array
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];
}
}
}
// 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;
@ -606,56 +575,50 @@ void PretransformVertices::Execute( aiScene* pScene)
pScene->mNumAnimations = 0;
// --- we need to keep all cameras and lights
for (unsigned int i = 0; i < pScene->mNumCameras;++i)
{
aiCamera* cam = pScene->mCameras[i];
const aiNode* nd = pScene->mRootNode->FindNode(cam->mName);
for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {
aiCamera *cam = pScene->mCameras[i];
const aiNode *nd = pScene->mRootNode->FindNode(cam->mName);
ai_assert(NULL != nd);
// multiply all properties of the camera with the absolute
// transformation of the corresponding node
cam->mPosition = nd->mTransformation * cam->mPosition;
cam->mLookAt = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt;
cam->mUp = aiMatrix3x3( nd->mTransformation ) * cam->mUp;
cam->mLookAt = aiMatrix3x3(nd->mTransformation) * cam->mLookAt;
cam->mUp = aiMatrix3x3(nd->mTransformation) * cam->mUp;
}
for (unsigned int i = 0; i < pScene->mNumLights;++i)
{
aiLight* l = pScene->mLights[i];
const aiNode* nd = pScene->mRootNode->FindNode(l->mName);
for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
aiLight *l = pScene->mLights[i];
const aiNode *nd = pScene->mRootNode->FindNode(l->mName);
ai_assert(NULL != nd);
// multiply all properties of the camera with the absolute
// transformation of the corresponding node
l->mPosition = nd->mTransformation * l->mPosition;
l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection;
l->mUp = aiMatrix3x3( nd->mTransformation ) * l->mUp;
l->mDirection = aiMatrix3x3(nd->mTransformation) * l->mDirection;
l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp;
}
if( !configKeepHierarchy ) {
if (!configKeepHierarchy) {
// now delete all nodes in the scene and build a new
// 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;
delete pScene->mRootNode;
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->mMeshes = new unsigned int[1];
pScene->mRootNode->mMeshes[0] = 0;
}
else
{
pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras;
aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
} else {
pScene->mRootNode->mNumChildren = pScene->mNumMeshes + pScene->mNumLights + pScene->mNumCameras;
aiNode **nodes = pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
// generate mesh nodes
for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes)
{
aiNode* pcNode = new aiNode();
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++nodes) {
aiNode *pcNode = new aiNode();
*nodes = pcNode;
pcNode->mParent = pScene->mRootNode;
pcNode->mName = pScene->mMeshes[i]->mName;
@ -666,52 +629,49 @@ void PretransformVertices::Execute( aiScene* pScene)
pcNode->mMeshes[0] = i;
}
// generate light nodes
for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes)
{
aiNode* pcNode = new aiNode();
for (unsigned int i = 0; i < pScene->mNumLights; ++i, ++nodes) {
aiNode *pcNode = new aiNode();
*nodes = pcNode;
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;
}
// generate camera nodes
for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes)
{
aiNode* pcNode = new aiNode();
for (unsigned int i = 0; i < pScene->mNumCameras; ++i, ++nodes) {
aiNode *pcNode = new aiNode();
*nodes = pcNode;
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;
}
}
}
else {
} else {
// ... and finally set the transformation matrix of all nodes to identity
MakeIdentityTransform(pScene->mRootNode);
}
if (configNormalize) {
// compute the boundary of all meshes
aiVector3D min,max;
MinMaxChooser<aiVector3D> ()(min,max);
aiVector3D min, max;
MinMaxChooser<aiVector3D>()(min, max);
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
aiMesh* m = pScene->mMeshes[a];
for (unsigned int i = 0; i < m->mNumVertices;++i) {
min = std::min(m->mVertices[i],min);
max = std::max(m->mVertices[i],max);
aiMesh *m = pScene->mMeshes[a];
for (unsigned int i = 0; i < m->mNumVertices; ++i) {
min = std::min(m->mVertices[i], min);
max = std::max(m->mVertices[i], max);
}
}
// find the dominant axis
aiVector3D d = max-min;
const ai_real div = std::max(d.x,std::max(d.y,d.z))*ai_real( 0.5);
aiVector3D d = max - min;
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;
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
aiMesh* m = pScene->mMeshes[a];
for (unsigned int i = 0; i < m->mNumVertices;++i) {
m->mVertices[i] = (m->mVertices[i]-d)/div;
aiMesh *m = pScene->mMeshes[a];
for (unsigned int i = 0; i < m->mNumVertices; ++i) {
m->mVertices[i] = (m->mVertices[i] - d) / div;
}
}
}
@ -721,8 +681,8 @@ void PretransformVertices::Execute( aiScene* pScene)
ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished");
ASSIMP_LOG_INFO_F("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (",
CountNodes(pScene->mRootNode) ," output nodes)" );
ASSIMP_LOG_INFO_F("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras." );
CountNodes(pScene->mRootNode), " output nodes)");
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, ")");
}
}

View File

@ -68,20 +68,20 @@ namespace Assimp {
*/
class ASSIMP_API PretransformVertices : public BaseProcess {
public:
PretransformVertices ();
~PretransformVertices ();
PretransformVertices();
~PretransformVertices();
// -------------------------------------------------------------------
// Check whether step is active
bool IsActive( unsigned int pFlags) const;
bool IsActive(unsigned int pFlags) const override;
// -------------------------------------------------------------------
// Execute step on a given scene
void Execute( aiScene* pScene);
void Execute(aiScene *pScene) override;
// -------------------------------------------------------------------
// Setup import settings
void SetupProperties(const Importer* pImp);
void SetupProperties(const Importer *pImp) override;
// -------------------------------------------------------------------
/** @brief Toggle the 'keep hierarchy' option
@ -102,56 +102,56 @@ public:
private:
// -------------------------------------------------------------------
// 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
unsigned int GetMeshVFormat(aiMesh* pcMesh);
unsigned int GetMeshVFormat(aiMesh *pcMesh) const;
// -------------------------------------------------------------------
// Count the number of vertices in the whole scene and a given
// material index
void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode,
void CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode,
unsigned int iMat,
unsigned int iVFormat,
unsigned int* piFaces,
unsigned int* piVertices);
unsigned int *piFaces,
unsigned int *piVertices) const;
// -------------------------------------------------------------------
// Collect vertex/face data
void CollectData( aiScene* pcScene, aiNode* pcNode,
void CollectData(const aiScene *pcScene, const aiNode *pcNode,
unsigned int iMat,
unsigned int iVFormat,
aiMesh* pcMeshOut,
aiMesh *pcMeshOut,
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
// The output list contains duplicate elements
void GetVFormatList( aiScene* pcScene, unsigned int iMat,
std::list<unsigned int>& aiOut);
void GetVFormatList(const aiScene *pcScene, unsigned int iMat,
std::list<unsigned int> &aiOut) const;
// -------------------------------------------------------------------
// 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
void BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in,
unsigned int numIn, aiNode* node);
void BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in,
unsigned int numIn, aiNode *node) const;
// -------------------------------------------------------------------
// 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
void MakeIdentityTransform(aiNode* nd);
void MakeIdentityTransform(aiNode *nd) const;
// -------------------------------------------------------------------
// 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
bool configKeepHierarchy;

View File

@ -362,8 +362,8 @@ namespace glTF
ComponentType componentType; //!< The datatype of components in the attribute. (required)
unsigned int count; //!< The number of attributes referenced by this accessor. (required)
AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required)
std::vector<float> max; //!< Maximum value of each component in this attribute.
std::vector<float> min; //!< Minimum value of each component in this attribute.
std::vector<double> max; //!< Maximum value of each component in this attribute.
std::vector<double> min; //!< Minimum value of each component in this attribute.
unsigned int GetNumComponents();
unsigned int GetBytesPerComponent();

View File

@ -54,9 +54,9 @@ namespace glTF {
namespace {
template<size_t N>
template<typename T, size_t N>
inline
Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
Value& MakeValue(Value& val, T(&r)[N], MemoryPoolAllocator<>& al) {
val.SetArray();
val.Reserve(N, al);
for (decltype(N) i = 0; i < N; ++i) {
@ -65,8 +65,9 @@ namespace glTF {
return val;
}
template<typename T>
inline
Value& MakeValue(Value& val, const std::vector<float> & r, MemoryPoolAllocator<>& al) {
Value& MakeValue(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) {
val.SetArray();
val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
for (unsigned int i = 0; i < r.size(); ++i) {
@ -75,6 +76,16 @@ namespace glTF {
return val;
}
template<typename C, typename T>
inline Value& MakeValueCast(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) {
val.SetArray();
val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
for (unsigned int i = 0; i < r.size(); ++i) {
val.PushBack(static_cast<C>(r[i]), al);
}
return val;
}
template<class T>
inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
if (v.empty()) return;
@ -100,8 +111,13 @@ namespace glTF {
obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
Value vTmpMax, vTmpMin;
if (a.componentType == ComponentType_FLOAT) {
obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
} else {
obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl);
}
}
inline void Write(Value& obj, Animation& a, AssetWriter& w)

View File

@ -58,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files, standard library.
#include <memory>
#include <limits>
#include <inttypes.h>
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
@ -173,6 +174,62 @@ static void IdentityMatrix4(glTF::mat4& o)
o[12] = 0; o[13] = 0; o[14] = 0; o[15] = 1;
}
template<typename T>
void SetAccessorRange(Ref<Accessor> acc, void* data, unsigned int count,
unsigned int numCompsIn, unsigned int numCompsOut)
{
ai_assert(numCompsOut <= numCompsIn);
// Allocate and initialize with large values.
for (unsigned int i = 0 ; i < numCompsOut ; i++) {
acc->min.push_back( std::numeric_limits<double>::max());
acc->max.push_back(-std::numeric_limits<double>::max());
}
size_t totalComps = count * numCompsIn;
T* buffer_ptr = static_cast<T*>(data);
T* buffer_end = buffer_ptr + totalComps;
// Search and set extreme values.
for (; buffer_ptr < buffer_end ; buffer_ptr += numCompsIn) {
for (unsigned int j = 0 ; j < numCompsOut ; j++) {
double valueTmp = buffer_ptr[j];
if (valueTmp < acc->min[j]) {
acc->min[j] = valueTmp;
}
if (valueTmp > acc->max[j]) {
acc->max[j] = valueTmp;
}
}
}
}
inline void SetAccessorRange(ComponentType compType, Ref<Accessor> acc, void* data,
unsigned int count, unsigned int numCompsIn, unsigned int numCompsOut)
{
switch (compType) {
case ComponentType_SHORT:
SetAccessorRange<short>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_UNSIGNED_SHORT:
SetAccessorRange<unsigned short>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_UNSIGNED_INT:
SetAccessorRange<unsigned int>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_FLOAT:
SetAccessorRange<float>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_BYTE:
SetAccessorRange<int8_t>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_UNSIGNED_BYTE:
SetAccessorRange<uint8_t>(acc, data, count, numCompsIn, numCompsOut);
return;
}
}
inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& buffer,
unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false)
{
@ -206,33 +263,7 @@ inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& bu
acc->type = typeOut;
// calculate min and max values
{
// Allocate and initialize with large values.
float float_MAX = 10000000000000.0f;
for (unsigned int i = 0 ; i < numCompsOut ; i++) {
acc->min.push_back( float_MAX);
acc->max.push_back(-float_MAX);
}
// Search and set extreme values.
float valueTmp;
for (unsigned int i = 0 ; i < count ; i++) {
for (unsigned int j = 0 ; j < numCompsOut ; j++) {
if (numCompsOut == 1) {
valueTmp = static_cast<unsigned short*>(data)[i];
} else {
valueTmp = static_cast<aiVector3D*>(data)[i][j];
}
if (valueTmp < acc->min[j]) {
acc->min[j] = valueTmp;
}
if (valueTmp > acc->max[j]) {
acc->max[j] = valueTmp;
}
}
}
}
SetAccessorRange(compType, acc, data, count, numCompsIn, numCompsOut);
// copy the data
acc->WriteData(count, data, numCompsIn*bytesPerComp);

View File

@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include <assimp/commonMetaData.h>
#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)
{
// clean all member arrays
@ -723,7 +743,7 @@ void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOS
ImportLights(asset);
ImportNodes(asset);
ImportCommonMetadata(asset);
if (pScene->mNumMeshes == 0) {
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;

View File

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

View File

@ -387,8 +387,8 @@ namespace glTF2
ComponentType componentType; //!< The datatype of components in the attribute. (required)
size_t count; //!< The number of attributes referenced by this accessor. (required)
AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required)
std::vector<float> max; //!< Maximum value of each component in this attribute.
std::vector<float> min; //!< Minimum value of each component in this attribute.
std::vector<double> max; //!< Maximum value of each component in this attribute.
std::vector<double> min; //!< Minimum value of each component in this attribute.
unsigned int GetNumComponents();
unsigned int GetBytesPerComponent();

View File

@ -54,8 +54,8 @@ namespace glTF2 {
namespace {
template<size_t N>
inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
template<typename T, size_t N>
inline Value& MakeValue(Value& val, T(&r)[N], MemoryPoolAllocator<>& al) {
val.SetArray();
val.Reserve(N, al);
for (decltype(N) i = 0; i < N; ++i) {
@ -64,7 +64,8 @@ namespace glTF2 {
return val;
}
inline Value& MakeValue(Value& val, const std::vector<float> & r, MemoryPoolAllocator<>& al) {
template<typename T>
inline Value& MakeValue(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) {
val.SetArray();
val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
for (unsigned int i = 0; i < r.size(); ++i) {
@ -73,8 +74,19 @@ namespace glTF2 {
return val;
}
inline Value& MakeValue(Value& val, float r, MemoryPoolAllocator<>& /*al*/) {
val.SetDouble(r);
template<typename C, typename T>
inline Value& MakeValueCast(Value& val, const std::vector<T> & r, MemoryPoolAllocator<>& al) {
val.SetArray();
val.Reserve(static_cast<rapidjson::SizeType>(r.size()), al);
for (unsigned int i = 0; i < r.size(); ++i) {
val.PushBack(static_cast<C>(r[i]), al);
}
return val;
}
template<typename T>
inline Value& MakeValue(Value& val, T r, MemoryPoolAllocator<>& /*al*/) {
val.Set(r);
return val;
}
@ -104,8 +116,13 @@ namespace glTF2 {
obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
Value vTmpMax, vTmpMin;
if (a.componentType == ComponentType_FLOAT) {
obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl);
} else {
obj.AddMember("max", MakeValueCast<int64_t>(vTmpMax, a.max, w.mAl), w.mAl);
obj.AddMember("min", MakeValueCast<int64_t>(vTmpMin, a.min, w.mAl), w.mAl);
}
}
inline void Write(Value& obj, Animation& a, AssetWriter& w)

View File

@ -58,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Header files, standard library.
#include <memory>
#include <limits>
#include <inttypes.h>
using namespace rapidjson;
@ -152,6 +153,62 @@ static void IdentityMatrix4(mat4& o) {
o[12] = 0; o[13] = 0; o[14] = 0; o[15] = 1;
}
template<typename T>
void SetAccessorRange(Ref<Accessor> acc, void* data, size_t count,
unsigned int numCompsIn, unsigned int numCompsOut)
{
ai_assert(numCompsOut <= numCompsIn);
// Allocate and initialize with large values.
for (unsigned int i = 0 ; i < numCompsOut ; i++) {
acc->min.push_back( std::numeric_limits<double>::max());
acc->max.push_back(-std::numeric_limits<double>::max());
}
size_t totalComps = count * numCompsIn;
T* buffer_ptr = static_cast<T*>(data);
T* buffer_end = buffer_ptr + totalComps;
// Search and set extreme values.
for (; buffer_ptr < buffer_end ; buffer_ptr += numCompsIn) {
for (unsigned int j = 0 ; j < numCompsOut ; j++) {
double valueTmp = buffer_ptr[j];
if (valueTmp < acc->min[j]) {
acc->min[j] = valueTmp;
}
if (valueTmp > acc->max[j]) {
acc->max[j] = valueTmp;
}
}
}
}
inline void SetAccessorRange(ComponentType compType, Ref<Accessor> acc, void* data,
size_t count, unsigned int numCompsIn, unsigned int numCompsOut)
{
switch (compType) {
case ComponentType_SHORT:
SetAccessorRange<short>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_UNSIGNED_SHORT:
SetAccessorRange<unsigned short>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_UNSIGNED_INT:
SetAccessorRange<unsigned int>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_FLOAT:
SetAccessorRange<float>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_BYTE:
SetAccessorRange<int8_t>(acc, data, count, numCompsIn, numCompsOut);
return;
case ComponentType_UNSIGNED_BYTE:
SetAccessorRange<uint8_t>(acc, data, count, numCompsIn, numCompsOut);
return;
}
}
inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& buffer,
size_t count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false)
{
@ -187,33 +244,7 @@ inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& bu
acc->type = typeOut;
// calculate min and max values
{
// Allocate and initialize with large values.
float float_MAX = 10000000000000.0f;
for (unsigned int i = 0 ; i < numCompsOut ; i++) {
acc->min.push_back( float_MAX);
acc->max.push_back(-float_MAX);
}
// Search and set extreme values.
float valueTmp;
for (unsigned int i = 0 ; i < count ; i++) {
for (unsigned int j = 0 ; j < numCompsOut ; j++) {
if (numCompsOut == 1) {
valueTmp = static_cast<unsigned short*>(data)[i];
} else {
valueTmp = static_cast<aiVector3D*>(data)[i][j];
}
if (valueTmp < acc->min[j]) {
acc->min[j] = valueTmp;
}
if (valueTmp > acc->max[j]) {
acc->max[j] = valueTmp;
}
}
}
}
SetAccessorRange(compType, acc, data, count, numCompsIn, numCompsOut);
// copy the data
acc->WriteData(count, data, numCompsIn*bytesPerComp);

View File

@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/commonMetaData.h>
#include <memory>
#include <unordered_map>
@ -1301,6 +1302,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) {
// clean all member arrays
meshOffsets.clear();
@ -1328,6 +1347,8 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
ImportAnimations(asset);
ImportCommonMetadata(asset);
if (pScene->mNumMeshes == 0) {
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
}

View File

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

View File

@ -72,7 +72,7 @@ for(LineSplitter splitter(stream);splitter;++splitter) {
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
*/

View File

@ -0,0 +1,63 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file commonMetaData.h
* @brief Defines a set of common scene metadata keys.
*/
#pragma once
#ifndef AI_COMMONMETADATA_H_INC
#define AI_COMMONMETADATA_H_INC
/// Scene metadata holding the name of the importer which loaded the source asset.
/// This is always present if the scene was created from an imported asset.
#define AI_METADATA_SOURCE_FORMAT "SourceAsset_Format"
/// Scene metadata holding the version of the source asset as a string, if available.
/// Not all formats add this metadata.
#define AI_METADATA_SOURCE_FORMAT_VERSION "SourceAsset_FormatVersion"
/// Scene metadata holding the name of the software which generated the source asset, if available.
/// Not all formats add this metadata.
#define AI_METADATA_SOURCE_GENERATOR "SourceAsset_Generator"
#endif

View File

@ -286,8 +286,8 @@ struct aiMetadata {
new_values[i] = mValues[i];
}
delete mKeys;
delete mValues;
delete[] mKeys;
delete[] mValues;
mKeys = new_keys;
mValues = new_values;
@ -377,6 +377,23 @@ struct aiMetadata {
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
};

View File

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

View File

@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/Exporter.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <assimp/commonMetaData.h>
#include <array>
using namespace Assimp;
@ -436,3 +438,29 @@ TEST_F(utglTF2ImportExport, error_string_preserved) {
}
#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);
}
}

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <assimp/commonMetaData.h>
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]->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);
}
}