Merge branch 'master' into issue_567

pull/1782/head
Kim Kulling 2018-02-08 20:29:47 +01:00 committed by GitHub
commit 4e4098f1fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 629 additions and 663 deletions

View File

@ -120,7 +120,7 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak
* [Pascal](port/AssimpPascal/Readme.md) * [Pascal](port/AssimpPascal/Readme.md)
* [Javascript (Alpha)](https://github.com/makc/assimp2json) * [Javascript (Alpha)](https://github.com/makc/assimp2json)
* [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777) * [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (currently supported obj, ply, stl, collada, md2) * [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
### Other tools ### ### Other tools ###
[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities. [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.

View File

@ -113,22 +113,24 @@ Discreet3DSImporter::Discreet3DSImporter()
, mScene() , mScene()
, mMasterScale() , mMasterScale()
, bHasBG() , bHasBG()
, bIsPrj() , bIsPrj() {
{} // empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
Discreet3DSImporter::~Discreet3DSImporter() Discreet3DSImporter::~Discreet3DSImporter() {
{} // empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
{
std::string extension = GetExtension(pFile); std::string extension = GetExtension(pFile);
if(extension == "3ds" || extension == "prj" ) { if(extension == "3ds" || extension == "prj" ) {
return true; return true;
} }
if (!extension.length() || checkSig) { if (!extension.length() || checkSig) {
uint16_t token[3]; uint16_t token[3];
token[0] = 0x4d4d; token[0] = 0x4d4d;
@ -210,7 +212,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
ConvertScene(pScene); ConvertScene(pScene);
// Generate the node graph for the scene. This is a little bit // Generate the node graph for the scene. This is a little bit
// tricky since we'll need to split some meshes into submeshes // tricky since we'll need to split some meshes into sub-meshes
GenerateNodeGraph(pScene); GenerateNodeGraph(pScene);
// Now apply the master scaling factor to the scene // Now apply the master scaling factor to the scene

View File

@ -58,12 +58,11 @@ using namespace Assimp::Formatter;
static bool match4(StreamReaderAny& stream, const char* string) { static bool match4(StreamReaderAny& stream, const char* string) {
ai_assert( nullptr != string ); ai_assert( nullptr != string );
char tmp[] = { char tmp[4];
(const char)(stream).GetI1(), tmp[ 0 ] = ( stream ).GetI1();
(const char)(stream).GetI1(), tmp[ 1 ] = ( stream ).GetI1();
(const char)(stream).GetI1(), tmp[ 2 ] = ( stream ).GetI1();
(const char)(stream).GetI1() tmp[ 3 ] = ( stream ).GetI1();
};
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]); return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
} }

View File

@ -122,9 +122,11 @@ namespace Blender {
# pragma warning(disable:4351) # pragma warning(disable:4351)
#endif #endif
// As counter-intuitive as it may seem, a comparator must return false for equal values.
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
struct ObjectCompare { struct ObjectCompare {
bool operator() (const Object* left, const Object* right) const { bool operator() (const Object* left, const Object* right) const {
return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) == 0; return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
} }
}; };
@ -143,9 +145,11 @@ namespace Blender {
, db(db) , db(db)
{} {}
// As counter-intuitive as it may seem, a comparator must return false for equal values.
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
struct ObjectCompare { struct ObjectCompare {
bool operator() (const Object* left, const Object* right) const { bool operator() (const Object* left, const Object* right) const {
return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) == 0; return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
} }
}; };

View File

@ -154,14 +154,6 @@ void BlenderImporter::SetupProperties(const Importer* /*pImp*/)
// nothing to be done for the moment // nothing to be done for the moment
} }
struct free_it {
free_it(void* free) : free(free) {}
~free_it() {
::free(this->free);
}
void* free;
};
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
@ -169,8 +161,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler) aiScene* pScene, IOSystem* pIOHandler)
{ {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
Bytef* dest = NULL; std::vector<Bytef> uncompressed;
free_it free_it_really(dest);
#endif #endif
@ -218,6 +209,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
size_t total = 0l; size_t total = 0l;
// TODO: be smarter about this, decompress directly into heap buffer
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
#define MYBLOCK 1024 #define MYBLOCK 1024
Bytef block[MYBLOCK]; Bytef block[MYBLOCK];
@ -232,8 +224,8 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
} }
const size_t have = MYBLOCK - zstream.avail_out; const size_t have = MYBLOCK - zstream.avail_out;
total += have; total += have;
dest = reinterpret_cast<Bytef*>( realloc(dest,total) ); uncompressed.resize(total);
memcpy(dest + total - have,block,have); memcpy(uncompressed.data() + total - have,block,have);
} }
while (ret != Z_STREAM_END); while (ret != Z_STREAM_END);
@ -241,7 +233,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
inflateEnd(&zstream); inflateEnd(&zstream);
// replace the input stream with a memory stream // replace the input stream with a memory stream
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total)); stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()),total));
// .. and retry // .. and retry
stream->Read(magic,7,1); stream->Read(magic,7,1);

View File

@ -432,7 +432,6 @@ void LWOImporter::InternReadFile( const std::string& pFile,
unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart); unsigned int num = static_cast<unsigned int>(apcMeshes.size() - meshStart);
if (layer.mName != "<LWODefault>" || num > 0) { if (layer.mName != "<LWODefault>" || num > 0) {
aiNode* pcNode = new aiNode(); aiNode* pcNode = new aiNode();
apcNodes[layer.mIndex] = pcNode;
pcNode->mName.Set(layer.mName); pcNode->mName.Set(layer.mName);
pcNode->mParent = (aiNode*)&layer; pcNode->mParent = (aiNode*)&layer;
pcNode->mNumMeshes = num; pcNode->mNumMeshes = num;
@ -442,6 +441,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
for (unsigned int p = 0; p < pcNode->mNumMeshes;++p) for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
pcNode->mMeshes[p] = p + meshStart; pcNode->mMeshes[p] = p + meshStart;
} }
apcNodes[layer.mIndex] = pcNode;
} }
} }
@ -584,7 +584,7 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
//Set parent of all children, inserting pivots //Set parent of all children, inserting pivots
//std::cout << "Set parent of all children" << std::endl; //std::cout << "Set parent of all children" << std::endl;
std::map<uint16_t, aiNode*> mapPivot; std::map<uint16_t, aiNode*> mapPivot;
for (std::map<uint16_t,aiNode*>::iterator itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
//Get the parent index //Get the parent index
LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent); LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent);
@ -593,7 +593,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
//Create pivot node, store it into the pivot map, and set the parent as the pivot //Create pivot node, store it into the pivot map, and set the parent as the pivot
aiNode* pivotNode = new aiNode(); aiNode* pivotNode = new aiNode();
pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data)); pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data));
mapPivot[-(itapcNodes->first+2)] = pivotNode;
itapcNodes->second->mParent = pivotNode; itapcNodes->second->mParent = pivotNode;
//Look for the parent node to attach the pivot to //Look for the parent node to attach the pivot to
@ -611,18 +610,19 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
pivotNode->mTransformation.a4 = nodeLayer->mPivot.x; pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
pivotNode->mTransformation.b4 = nodeLayer->mPivot.y; pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
pivotNode->mTransformation.c4 = nodeLayer->mPivot.z; pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
mapPivot[-(itapcNodes->first+2)] = pivotNode;
} }
//Merge pivot map into node map //Merge pivot map into node map
//std::cout << "Merge pivot map into node map" << std::endl; //std::cout << "Merge pivot map into node map" << std::endl;
for (std::map<uint16_t, aiNode*>::iterator itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
apcNodes[itMapPivot->first] = itMapPivot->second; apcNodes[itMapPivot->first] = itMapPivot->second;
} }
//Set children of all parents //Set children of all parents
apcNodes[-1] = root; apcNodes[-1] = root;
for (std::map<uint16_t,aiNode*>::iterator itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) { for (auto itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) { for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) { if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
++(itMapParentNodes->second->mNumChildren); ++(itMapParentNodes->second->mNumChildren);
} }
@ -630,7 +630,7 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
if (itMapParentNodes->second->mNumChildren) { if (itMapParentNodes->second->mNumChildren) {
itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ]; itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ];
uint16_t p = 0; uint16_t p = 0;
for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) { for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) { if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second; itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
} }

View File

@ -844,11 +844,11 @@ struct IntGroupInfo_MDL7
struct IntGroupData_MDL7 struct IntGroupData_MDL7
{ {
IntGroupData_MDL7() IntGroupData_MDL7()
: pcFaces(NULL), bNeed2UV(false) : bNeed2UV(false)
{} {}
//! Array of faces that belong to the group //! Array of faces that belong to the group
MDL::IntFace_MDL7* pcFaces; std::vector<MDL::IntFace_MDL7> pcFaces;
//! Array of vertex positions //! Array of vertex positions
std::vector<aiVector3D> vPositions; std::vector<aiVector3D> vPositions;

View File

@ -1502,7 +1502,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
groupData.bNeed2UV = true; groupData.bNeed2UV = true;
} }
} }
groupData.pcFaces = new MDL::IntFace_MDL7[groupInfo.pcGroup->numtris]; groupData.pcFaces.resize(groupInfo.pcGroup->numtris);
// read all faces into the preallocated arrays // read all faces into the preallocated arrays
ReadFaces_3DGS_MDL7(groupInfo, groupData); ReadFaces_3DGS_MDL7(groupInfo, groupData);

View File

@ -221,12 +221,8 @@ static void propId2StdString( Property *prop, std::string &name, std::string &ke
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
OpenGEXImporter::VertexContainer::VertexContainer() OpenGEXImporter::VertexContainer::VertexContainer()
: m_numVerts( 0 ) : m_numColors( 0 )
, m_vertices( nullptr )
, m_numColors( 0 )
, m_colors( nullptr ) , m_colors( nullptr )
, m_numNormals( 0 )
, m_normals( nullptr )
, m_numUVComps() , m_numUVComps()
, m_textureCoords() { , m_textureCoords() {
// empty // empty
@ -234,9 +230,7 @@ OpenGEXImporter::VertexContainer::VertexContainer()
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
OpenGEXImporter::VertexContainer::~VertexContainer() { OpenGEXImporter::VertexContainer::~VertexContainer() {
delete[] m_vertices;
delete[] m_colors; delete[] m_colors;
delete[] m_normals;
for(auto &texcoords : m_textureCoords) { for(auto &texcoords : m_textureCoords) {
delete [] texcoords; delete [] texcoords;
@ -697,7 +691,8 @@ void OpenGEXImporter::handleTransformNode( ODDLParser::DDLNode *node, aiScene *
void OpenGEXImporter::handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene ) { void OpenGEXImporter::handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
m_currentMesh = new aiMesh; m_currentMesh = new aiMesh;
const size_t meshidx( m_meshCache.size() ); const size_t meshidx( m_meshCache.size() );
m_meshCache.push_back( m_currentMesh ); // ownership is transfered but a reference remains in m_currentMesh
m_meshCache.emplace_back( m_currentMesh );
Property *prop = node->getProperties(); Property *prop = node->getProperties();
if( nullptr != prop ) { if( nullptr != prop ) {
@ -857,17 +852,15 @@ void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene
const size_t numItems( countDataArrayListItems( vaList ) ); const size_t numItems( countDataArrayListItems( vaList ) );
if( Position == attribType ) { if( Position == attribType ) {
m_currentVertices.m_numVerts = numItems; m_currentVertices.m_vertices.resize( numItems );
m_currentVertices.m_vertices = new aiVector3D[ numItems ]; copyVectorArray( numItems, vaList, m_currentVertices.m_vertices.data() );
copyVectorArray( numItems, vaList, m_currentVertices.m_vertices );
} else if ( Color == attribType ) { } else if ( Color == attribType ) {
m_currentVertices.m_numColors = numItems; m_currentVertices.m_numColors = numItems;
m_currentVertices.m_colors = new aiColor4D[ numItems ]; m_currentVertices.m_colors = new aiColor4D[ numItems ];
copyColor4DArray( numItems, vaList, m_currentVertices.m_colors ); copyColor4DArray( numItems, vaList, m_currentVertices.m_colors );
} else if( Normal == attribType ) { } else if( Normal == attribType ) {
m_currentVertices.m_numNormals = numItems; m_currentVertices.m_normals.resize( numItems );
m_currentVertices.m_normals = new aiVector3D[ numItems ]; copyVectorArray( numItems, vaList, m_currentVertices.m_normals.data() );
copyVectorArray( numItems, vaList, m_currentVertices.m_normals );
} else if( TexCoord == attribType ) { } else if( TexCoord == attribType ) {
m_currentVertices.m_numUVComps[ 0 ] = numItems; m_currentVertices.m_numUVComps[ 0 ] = numItems;
m_currentVertices.m_textureCoords[ 0 ] = new aiVector3D[ numItems ]; m_currentVertices.m_textureCoords[ 0 ] = new aiVector3D[ numItems ];
@ -904,7 +897,7 @@ void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *
hasColors = true; hasColors = true;
} }
bool hasNormalCoords( false ); bool hasNormalCoords( false );
if ( m_currentVertices.m_numNormals > 0 ) { if ( !m_currentVertices.m_normals.empty() ) {
m_currentMesh->mNormals = new aiVector3D[ m_currentMesh->mNumVertices ]; m_currentMesh->mNormals = new aiVector3D[ m_currentMesh->mNumVertices ];
hasNormalCoords = true; hasNormalCoords = true;
} }
@ -922,7 +915,7 @@ void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *
Value *next( vaList->m_dataList ); Value *next( vaList->m_dataList );
for( size_t indices = 0; indices < current.mNumIndices; indices++ ) { for( size_t indices = 0; indices < current.mNumIndices; indices++ ) {
const int idx( next->getUnsignedInt32() ); const int idx( next->getUnsignedInt32() );
ai_assert( static_cast<size_t>( idx ) <= m_currentVertices.m_numVerts ); ai_assert( static_cast<size_t>( idx ) <= m_currentVertices.m_vertices.size() );
ai_assert( index < m_currentMesh->mNumVertices ); ai_assert( index < m_currentMesh->mNumVertices );
aiVector3D &pos = ( m_currentVertices.m_vertices[ idx ] ); aiVector3D &pos = ( m_currentVertices.m_vertices[ idx ] );
m_currentMesh->mVertices[ index ].Set( pos.x, pos.y, pos.z ); m_currentMesh->mVertices[ index ].Set( pos.x, pos.y, pos.z );
@ -1145,7 +1138,9 @@ void OpenGEXImporter::copyMeshes( aiScene *pScene ) {
pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size()); pScene->mNumMeshes = static_cast<unsigned int>(m_meshCache.size());
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ]; pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
std::copy( m_meshCache.begin(), m_meshCache.end(), pScene->mMeshes ); for (unsigned int i = 0; i < pScene->mNumMeshes; i++) {
pScene->mMeshes[i] = m_meshCache[i].release();
}
} }
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------

View File

@ -144,12 +144,10 @@ protected:
private: private:
struct VertexContainer { struct VertexContainer {
size_t m_numVerts; std::vector<aiVector3D> m_vertices;
aiVector3D *m_vertices;
size_t m_numColors; size_t m_numColors;
aiColor4D *m_colors; aiColor4D *m_colors;
size_t m_numNormals; std::vector<aiVector3D> m_normals;
aiVector3D *m_normals;
size_t m_numUVComps[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; size_t m_numUVComps[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
aiVector3D *m_textureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; aiVector3D *m_textureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
@ -185,7 +183,7 @@ private:
typedef std::map<aiNode*, std::unique_ptr<ChildInfo> > NodeChildMap; typedef std::map<aiNode*, std::unique_ptr<ChildInfo> > NodeChildMap;
NodeChildMap m_nodeChildMap; NodeChildMap m_nodeChildMap;
std::vector<aiMesh*> m_meshCache; std::vector<std::unique_ptr<aiMesh> > m_meshCache;
typedef std::map<std::string, size_t> ReferenceMap; typedef std::map<std::string, size_t> ReferenceMap;
std::map<std::string, size_t> m_mesh2refMap; std::map<std::string, size_t> m_mesh2refMap;
std::map<std::string, size_t> m_material2refMap; std::map<std::string, size_t> m_material2refMap;
@ -194,7 +192,7 @@ private:
MetricInfo m_metrics[ MetricInfo::Max ]; MetricInfo m_metrics[ MetricInfo::Max ];
aiNode *m_currentNode; aiNode *m_currentNode;
VertexContainer m_currentVertices; VertexContainer m_currentVertices;
aiMesh *m_currentMesh; aiMesh *m_currentMesh; // not owned, target is owned by m_meshCache
aiMaterial *m_currentMaterial; aiMaterial *m_currentMaterial;
aiLight *m_currentLight; aiLight *m_currentLight;
aiCamera *m_currentCamera; aiCamera *m_currentCamera;

View File

@ -92,9 +92,9 @@ namespace
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
PLYImporter::PLYImporter() PLYImporter::PLYImporter()
: mBuffer(nullptr) : mBuffer(nullptr)
, pcDOM(nullptr) , pcDOM(nullptr)
, mGeneratedMesh(nullptr){ , mGeneratedMesh(nullptr) {
// empty // empty
} }
@ -106,24 +106,24 @@ PLYImporter::~PLYImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
{
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
if (extension == "ply") if ( extension == "ply" ) {
return true; return true;
else if (!extension.length() || checkSig) } else if (!extension.length() || checkSig) {
{ if ( !pIOHandler ) {
if (!pIOHandler)return true; return true;
const char* tokens[] = { "ply" }; }
static const char* tokens[] = { "ply" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
} }
return false; return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiImporterDesc* PLYImporter::GetInfo() const const aiImporterDesc* PLYImporter::GetInfo() const {
{
return &desc; return &desc;
} }
@ -149,9 +149,7 @@ static bool isBigEndian(const char* szMe) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void PLYImporter::InternReadFile(const std::string& pFile, void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
aiScene* pScene, IOSystem* pIOHandler)
{
static const std::string mode = "rb"; static const std::string mode = "rb";
std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode)); std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
if (!fileStream.get()) { if (!fileStream.get()) {
@ -159,7 +157,7 @@ void PLYImporter::InternReadFile(const std::string& pFile,
} }
// Get the file-size // Get the file-size
size_t fileSize = fileStream->FileSize(); const size_t fileSize( fileStream->FileSize() );
if ( 0 == fileSize ) { if ( 0 == fileSize ) {
throw DeadlyImportError("File " + pFile + " is empty."); throw DeadlyImportError("File " + pFile + " is empty.");
} }
@ -174,8 +172,7 @@ void PLYImporter::InternReadFile(const std::string& pFile,
if ((headerCheck.size() < 3) || if ((headerCheck.size() < 3) ||
(headerCheck[0] != 'P' && headerCheck[0] != 'p') || (headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
(headerCheck[1] != 'L' && headerCheck[1] != 'l') || (headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
(headerCheck[2] != 'Y' && headerCheck[2] != 'y') ) (headerCheck[2] != 'Y' && headerCheck[2] != 'y') ) {
{
streamedBuffer.close(); streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there"); throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
} }
@ -194,10 +191,8 @@ void PLYImporter::InternReadFile(const std::string& pFile,
if (TokenMatch(szMe, "format", 6)) { if (TokenMatch(szMe, "format", 6)) {
if (TokenMatch(szMe, "ascii", 5)) { if (TokenMatch(szMe, "ascii", 5)) {
SkipLine(szMe, (const char**)&szMe); SkipLine(szMe, (const char**)&szMe);
if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
{ if (mGeneratedMesh != NULL) {
if (mGeneratedMesh != NULL)
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -205,17 +200,13 @@ void PLYImporter::InternReadFile(const std::string& pFile,
streamedBuffer.close(); streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)"); throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)");
} }
} } else if (!::strncmp(szMe, "binary_", 7)) {
else if (!::strncmp(szMe, "binary_", 7))
{
szMe += 7; szMe += 7;
const bool bIsBE(isBigEndian(szMe)); const bool bIsBE(isBigEndian(szMe));
// skip the line, parse the rest of the header and build the DOM // skip the line, parse the rest of the header and build the DOM
if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) {
{ if (mGeneratedMesh != NULL) {
if (mGeneratedMesh != NULL)
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -223,11 +214,8 @@ void PLYImporter::InternReadFile(const std::string& pFile,
streamedBuffer.close(); streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)"); throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
} }
} } else {
else if (mGeneratedMesh != NULL) {
{
if (mGeneratedMesh != NULL)
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -235,12 +223,9 @@ void PLYImporter::InternReadFile(const std::string& pFile,
streamedBuffer.close(); streamedBuffer.close();
throw DeadlyImportError("Invalid .ply file: Unknown file format"); throw DeadlyImportError("Invalid .ply file: Unknown file format");
} }
} } else {
else
{
AI_DEBUG_INVALIDATE_PTR(this->mBuffer); AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
if (mGeneratedMesh != NULL) if (mGeneratedMesh != NULL) {
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -252,20 +237,16 @@ void PLYImporter::InternReadFile(const std::string& pFile,
//free the file buffer //free the file buffer
streamedBuffer.close(); streamedBuffer.close();
if (mGeneratedMesh == NULL) if (mGeneratedMesh == NULL) {
{
throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data "); throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
} }
// if no face list is existing we assume that the vertex // if no face list is existing we assume that the vertex
// list is containing a list of points // list is containing a list of points
bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false; bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false;
if (pointsOnly) if (pointsOnly) {
{ if (mGeneratedMesh->mNumVertices < 3) {
if (mGeneratedMesh->mNumVertices < 3) if (mGeneratedMesh != NULL) {
{
if (mGeneratedMesh != NULL)
{
delete(mGeneratedMesh); delete(mGeneratedMesh);
mGeneratedMesh = nullptr; mGeneratedMesh = nullptr;
} }
@ -279,8 +260,7 @@ void PLYImporter::InternReadFile(const std::string& pFile,
mGeneratedMesh->mNumFaces = iNum; mGeneratedMesh->mNumFaces = iNum;
mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
for (unsigned int i = 0; i < iNum; ++i) for (unsigned int i = 0; i < iNum; ++i) {
{
mGeneratedMesh->mFaces[i].mNumIndices = 3; mGeneratedMesh->mFaces[i].mNumIndices = 3;
mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3]; mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3];
mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3); mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3);
@ -521,9 +501,7 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Convert a color component to [0...1] // Convert a color component to [0...1]
ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, PLY::EDataType eType) {
PLY::EDataType eType)
{
switch (eType) switch (eType)
{ {
case EDT_Float: case EDT_Float:

View File

@ -57,7 +57,6 @@ struct aiMesh;
namespace Assimp { namespace Assimp {
using namespace PLY; using namespace PLY;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -39,12 +39,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file Defines the helper data structures for importing PLY files */ /** @file Defines the helper data structures for importing PLY files */
#pragma once
#ifndef AI_PLYFILEHELPER_H_INC #ifndef AI_PLYFILEHELPER_H_INC
#define AI_PLYFILEHELPER_H_INC #define AI_PLYFILEHELPER_H_INC
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/IOStreamBuffer.h> #include <assimp/IOStreamBuffer.h>
#include <vector> #include <vector>
@ -58,8 +57,7 @@ class PLYImporter;
// http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/
// http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf // http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf
// http://www.okino.com/conv/exp_ply.htm // http://www.okino.com/conv/exp_ply.htm
namespace PLY namespace PLY {
{
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
/* /*
@ -78,8 +76,7 @@ int8
int16 int16
uint8 ... forms are also used uint8 ... forms are also used
*/ */
enum EDataType enum EDataType {
{
EDT_Char = 0x0u, EDT_Char = 0x0u,
EDT_UChar, EDT_UChar,
EDT_Short, EDT_Short,
@ -98,8 +95,7 @@ enum EDataType
* *
* Semantics define the usage of a property, e.g. x coordinate * Semantics define the usage of a property, e.g. x coordinate
*/ */
enum ESemantic enum ESemantic {
{
//! vertex position x coordinate //! vertex position x coordinate
EST_XCoord = 0x0u, EST_XCoord = 0x0u,
//! vertex position x coordinate //! vertex position x coordinate
@ -182,15 +178,14 @@ enum ESemantic
* *
* Semantics define the usage of an element, e.g. vertex or material * Semantics define the usage of an element, e.g. vertex or material
*/ */
enum EElementSemantic enum EElementSemantic {
{
//! The element is a vertex //! The element is a vertex
EEST_Vertex = 0x0u, EEST_Vertex = 0x0u,
//! The element is a face description (index table) //! The element is a face description (index table)
EEST_Face, EEST_Face,
//! The element is a tristrip description (index table) //! The element is a triangle-strip description (index table)
EEST_TriStrip, EEST_TriStrip,
//! The element is an edge description (ignored) //! The element is an edge description (ignored)
@ -211,17 +206,16 @@ enum EElementSemantic
* *
* This can e.g. be a part of the vertex declaration * This can e.g. be a part of the vertex declaration
*/ */
class Property class Property {
{
public: public:
//! Default constructor //! Default constructor
Property() Property()
: eType (EDT_Int), : eType (EDT_Int)
Semantic(), , Semantic()
bIsList(false), , bIsList(false)
eFirstType(EDT_UChar) , eFirstType(EDT_UChar) {
{} // empty
}
//! Data type of the property //! Data type of the property
EDataType eType; EDataType eType;
@ -260,15 +254,14 @@ public:
* This can e.g. be the vertex declaration. Elements contain a * This can e.g. be the vertex declaration. Elements contain a
* well-defined number of properties. * well-defined number of properties.
*/ */
class Element class Element {
{
public: public:
//! Default constructor //! Default constructor
Element() Element()
: eSemantic (EEST_INVALID) : eSemantic (EEST_INVALID)
, NumOccur(0) , NumOccur(0) {
{} // empty
}
//! List of properties assigned to the element //! List of properties assigned to the element
//! std::vector to support operator[] //! std::vector to support operator[]

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2018, assimp team Copyright (c) 2006-2018, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -44,7 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the XFile importer class * @brief Implementation of the XFile importer class
*/ */
#ifndef ASSIMP_BUILD_NO_X_IMPORTER #ifndef ASSIMP_BUILD_NO_X_IMPORTER
#include "XFileImporter.h" #include "XFileImporter.h"
@ -79,17 +76,19 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
XFileImporter::XFileImporter() XFileImporter::XFileImporter()
{} : mBuffer() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
XFileImporter::~XFileImporter() XFileImporter::~XFileImporter() {
{} // empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
{
std::string extension = GetExtension(pFile); std::string extension = GetExtension(pFile);
if(extension == "x") { if(extension == "x") {
return true; return true;
@ -104,23 +103,24 @@ bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get file extension list // Get file extension list
const aiImporterDesc* XFileImporter::GetInfo () const const aiImporterDesc* XFileImporter::GetInfo () const {
{
return &desc; return &desc;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
{
// read file into memory // read file into memory
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile)); std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
if( file.get() == NULL) if ( file.get() == NULL ) {
throw DeadlyImportError( "Failed to open file " + pFile + "."); throw DeadlyImportError( "Failed to open file " + pFile + "." );
}
static const size_t MinSize = 16;
size_t fileSize = file->FileSize(); size_t fileSize = file->FileSize();
if( fileSize < 16) if ( fileSize < MinSize ) {
throw DeadlyImportError( "XFile is too small."); throw DeadlyImportError( "XFile is too small." );
}
// in the hope that binary files will never start with a BOM ... // in the hope that binary files will never start with a BOM ...
mBuffer.resize( fileSize + 1); mBuffer.resize( fileSize + 1);
@ -134,8 +134,9 @@ void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, I
CreateDataRepresentationFromImport( pScene, parser.GetImportedData()); CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
// if nothing came from it, report it as error // if nothing came from it, report it as error
if( !pScene->mRootNode) if ( !pScene->mRootNode ) {
throw DeadlyImportError( "XFile is ill-formatted - no content imported."); throw DeadlyImportError( "XFile is ill-formatted - no content imported." );
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -146,17 +147,15 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
ConvertMaterials( pScene, pData->mGlobalMaterials); ConvertMaterials( pScene, pData->mGlobalMaterials);
// copy nodes, extracting meshes and materials on the way // copy nodes, extracting meshes and materials on the way
pScene->mRootNode = CreateNodes( pScene, NULL, pData->mRootNode); pScene->mRootNode = CreateNodes( pScene, nullptr, pData->mRootNode);
// extract animations // extract animations
CreateAnimations( pScene, pData); CreateAnimations( pScene, pData);
// read the global meshes that were stored outside of any node // read the global meshes that were stored outside of any node
if( pData->mGlobalMeshes.size() > 0) if( !pData->mGlobalMeshes.empty() ) {
{
// create a root node to hold them if there isn't any, yet // create a root node to hold them if there isn't any, yet
if( pScene->mRootNode == NULL) if( pScene->mRootNode == nullptr ) {
{
pScene->mRootNode = new aiNode; pScene->mRootNode = new aiNode;
pScene->mRootNode->mName.Set( "$dummy_node"); pScene->mRootNode->mName.Set( "$dummy_node");
} }
@ -180,8 +179,7 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
flipper.Execute(pScene); flipper.Execute(pScene);
// finally: create a dummy material if not material was imported // finally: create a dummy material if not material was imported
if( pScene->mNumMaterials == 0) if( pScene->mNumMaterials == 0) {
{
pScene->mNumMaterials = 1; pScene->mNumMaterials = 1;
// create the Material // create the Material
aiMaterial* mat = new aiMaterial; aiMaterial* mat = new aiMaterial;
@ -205,10 +203,10 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, XFile::
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Recursively creates scene nodes from the imported hierarchy. // Recursively creates scene nodes from the imported hierarchy.
aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode) aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFile::Node* pNode) {
{ if ( !pNode ) {
if( !pNode) return nullptr;
return NULL; }
// create node // create node
aiNode* node = new aiNode; aiNode* node = new aiNode;
@ -222,13 +220,13 @@ aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFil
CreateMeshes( pScene, node, pNode->mMeshes); CreateMeshes( pScene, node, pNode->mMeshes);
// handle childs // handle childs
if( pNode->mChildren.size() > 0) if( !pNode->mChildren.empty() ) {
{
node->mNumChildren = (unsigned int)pNode->mChildren.size(); node->mNumChildren = (unsigned int)pNode->mChildren.size();
node->mChildren = new aiNode* [node->mNumChildren]; node->mChildren = new aiNode* [node->mNumChildren];
for( unsigned int a = 0; a < pNode->mChildren.size(); a++) for ( unsigned int a = 0; a < pNode->mChildren.size(); ++a ) {
node->mChildren[a] = CreateNodes( pScene, node, pNode->mChildren[a]); node->mChildren[ a ] = CreateNodes( pScene, node, pNode->mChildren[ a ] );
}
} }
return node; return node;
@ -236,16 +234,14 @@ aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFil
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates the meshes for the given node. // Creates the meshes for the given node.
void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes) void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector<XFile::Mesh*>& pMeshes) {
{
if (pMeshes.empty()) { if (pMeshes.empty()) {
return; return;
} }
// create a mesh for each mesh-material combination in the source node // create a mesh for each mesh-material combination in the source node
std::vector<aiMesh*> meshes; std::vector<aiMesh*> meshes;
for( unsigned int a = 0; a < pMeshes.size(); a++) for( unsigned int a = 0; a < pMeshes.size(); ++a ) {
{
XFile::Mesh* sourceMesh = pMeshes[a]; XFile::Mesh* sourceMesh = pMeshes[a];
if ( nullptr == sourceMesh ) { if ( nullptr == sourceMesh ) {
continue; continue;
@ -255,35 +251,30 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
ConvertMaterials( pScene, sourceMesh->mMaterials); ConvertMaterials( pScene, sourceMesh->mMaterials);
unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u); unsigned int numMaterials = std::max( (unsigned int)sourceMesh->mMaterials.size(), 1u);
for( unsigned int b = 0; b < numMaterials; b++) for( unsigned int b = 0; b < numMaterials; ++b ) {
{
// collect the faces belonging to this material // collect the faces belonging to this material
std::vector<unsigned int> faces; std::vector<unsigned int> faces;
unsigned int numVertices = 0; unsigned int numVertices = 0;
if( sourceMesh->mFaceMaterials.size() > 0) if( !sourceMesh->mFaceMaterials.empty() ) {
{
// if there is a per-face material defined, select the faces with the corresponding material // if there is a per-face material defined, select the faces with the corresponding material
for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); c++) for( unsigned int c = 0; c < sourceMesh->mFaceMaterials.size(); ++c ) {
{ if( sourceMesh->mFaceMaterials[c] == b) {
if( sourceMesh->mFaceMaterials[c] == b)
{
faces.push_back( c); faces.push_back( c);
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size(); numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
} }
} }
} else } else {
{
// if there is no per-face material, place everything into one mesh // if there is no per-face material, place everything into one mesh
for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); c++) for( unsigned int c = 0; c < sourceMesh->mPosFaces.size(); ++c ) {
{
faces.push_back( c); faces.push_back( c);
numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size(); numVertices += (unsigned int)sourceMesh->mPosFaces[c].mIndices.size();
} }
} }
// no faces/vertices using this material? strange... // no faces/vertices using this material? strange...
if( numVertices == 0) if ( numVertices == 0 ) {
continue; continue;
}
// create a submesh using this material // create a submesh using this material
aiMesh* mesh = new aiMesh; aiMesh* mesh = new aiMesh;
@ -291,11 +282,9 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// find the material in the scene's material list. Either own material // find the material in the scene's material list. Either own material
// or referenced material, it should already have a valid index // or referenced material, it should already have a valid index
if( sourceMesh->mFaceMaterials.size() > 0) if( !sourceMesh->mFaceMaterials.empty() ) {
{
mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex); mesh->mMaterialIndex = static_cast<unsigned int>(sourceMesh->mMaterials[b].sceneIndex);
} else } else {
{
mesh->mMaterialIndex = 0; mesh->mMaterialIndex = 0;
} }
@ -310,28 +299,28 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
mesh->mName.Set(sourceMesh->mName); mesh->mName.Set(sourceMesh->mName);
// normals? // normals?
if( sourceMesh->mNormals.size() > 0) if ( sourceMesh->mNormals.size() > 0 ) {
mesh->mNormals = new aiVector3D[numVertices]; mesh->mNormals = new aiVector3D[ numVertices ];
}
// texture coords // texture coords
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++) for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) {
{ if ( !sourceMesh->mTexCoords[ c ].empty() ) {
if( sourceMesh->mTexCoords[c].size() > 0) mesh->mTextureCoords[ c ] = new aiVector3D[ numVertices ];
mesh->mTextureCoords[c] = new aiVector3D[numVertices]; }
} }
// vertex colors // vertex colors
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++) for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) {
{ if ( !sourceMesh->mColors[ c ].empty() ) {
if( sourceMesh->mColors[c].size() > 0) mesh->mColors[ c ] = new aiColor4D[ numVertices ];
mesh->mColors[c] = new aiColor4D[numVertices]; }
} }
// now collect the vertex data of all data streams present in the imported mesh // now collect the vertex data of all data streams present in the imported mesh
unsigned int newIndex = 0; unsigned int newIndex( 0 );
std::vector<unsigned int> orgPoints; // from which original point each new vertex stems std::vector<unsigned int> orgPoints; // from which original point each new vertex stems
orgPoints.resize( numVertices, 0); orgPoints.resize( numVertices, 0);
for( unsigned int c = 0; c < faces.size(); c++) for( unsigned int c = 0; c < faces.size(); ++c ) {
{
unsigned int f = faces[c]; // index of the source face unsigned int f = faces[c]; // index of the source face
const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face const XFile::Face& pf = sourceMesh->mPosFaces[f]; // position source face
@ -341,30 +330,30 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
df.mIndices = new unsigned int[ df.mNumIndices]; df.mIndices = new unsigned int[ df.mNumIndices];
// collect vertex data for indices of this face // collect vertex data for indices of this face
for( unsigned int d = 0; d < df.mNumIndices; d++) for( unsigned int d = 0; d < df.mNumIndices; ++d ) {
{
df.mIndices[d] = newIndex; df.mIndices[d] = newIndex;
orgPoints[newIndex] = pf.mIndices[d]; orgPoints[newIndex] = pf.mIndices[d];
// Position // Position
mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]]; mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]];
// Normal, if present // Normal, if present
if( mesh->HasNormals()) if ( mesh->HasNormals() ) {
mesh->mNormals[newIndex] = sourceMesh->mNormals[sourceMesh->mNormFaces[f].mIndices[d]]; mesh->mNormals[ newIndex ] = sourceMesh->mNormals[ sourceMesh->mNormFaces[ f ].mIndices[ d ] ];
}
// texture coord sets // texture coord sets
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; e++) for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++e ) {
{ if( mesh->HasTextureCoords( e)) {
if( mesh->HasTextureCoords( e))
{
aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]]; aiVector2D tex = sourceMesh->mTexCoords[e][pf.mIndices[d]];
mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f); mesh->mTextureCoords[e][newIndex] = aiVector3D( tex.x, 1.0f - tex.y, 0.0f);
} }
} }
// vertex color sets // vertex color sets
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++) for ( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; ++e ) {
if( mesh->HasVertexColors( e)) if ( mesh->HasVertexColors( e ) ) {
mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]]; mesh->mColors[ e ][ newIndex ] = sourceMesh->mColors[ e ][ pf.mIndices[ d ] ];
}
}
newIndex++; newIndex++;
} }
@ -376,28 +365,29 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// convert all bones of the source mesh which influence vertices in this newly created mesh // convert all bones of the source mesh which influence vertices in this newly created mesh
const std::vector<XFile::Bone>& bones = sourceMesh->mBones; const std::vector<XFile::Bone>& bones = sourceMesh->mBones;
std::vector<aiBone*> newBones; std::vector<aiBone*> newBones;
for( unsigned int c = 0; c < bones.size(); c++) for( unsigned int c = 0; c < bones.size(); ++c ) {
{
const XFile::Bone& obone = bones[c]; const XFile::Bone& obone = bones[c];
// set up a vertex-linear array of the weights for quick searching if a bone influences a vertex // set up a vertex-linear array of the weights for quick searching if a bone influences a vertex
std::vector<ai_real> oldWeights( sourceMesh->mPositions.size(), 0.0); std::vector<ai_real> oldWeights( sourceMesh->mPositions.size(), 0.0);
for( unsigned int d = 0; d < obone.mWeights.size(); d++) for ( unsigned int d = 0; d < obone.mWeights.size(); ++d ) {
oldWeights[obone.mWeights[d].mVertex] = obone.mWeights[d].mWeight; oldWeights[ obone.mWeights[ d ].mVertex ] = obone.mWeights[ d ].mWeight;
}
// collect all vertex weights that influence a vertex in the new mesh // collect all vertex weights that influence a vertex in the new mesh
std::vector<aiVertexWeight> newWeights; std::vector<aiVertexWeight> newWeights;
newWeights.reserve( numVertices); newWeights.reserve( numVertices);
for( unsigned int d = 0; d < orgPoints.size(); d++) for( unsigned int d = 0; d < orgPoints.size(); ++d ) {
{
// does the new vertex stem from an old vertex which was influenced by this bone? // does the new vertex stem from an old vertex which was influenced by this bone?
ai_real w = oldWeights[orgPoints[d]]; ai_real w = oldWeights[orgPoints[d]];
if( w > 0.0) if ( w > 0.0 ) {
newWeights.push_back( aiVertexWeight( d, w)); newWeights.push_back( aiVertexWeight( d, w ) );
}
} }
// if the bone has no weights in the newly created mesh, ignore it // if the bone has no weights in the newly created mesh, ignore it
if( newWeights.size() == 0) if ( newWeights.empty() ) {
continue; continue;
}
// create // create
aiBone* nbone = new aiBone; aiBone* nbone = new aiBone;
@ -407,14 +397,14 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
nbone->mOffsetMatrix = obone.mOffsetMatrix; nbone->mOffsetMatrix = obone.mOffsetMatrix;
nbone->mNumWeights = (unsigned int)newWeights.size(); nbone->mNumWeights = (unsigned int)newWeights.size();
nbone->mWeights = new aiVertexWeight[nbone->mNumWeights]; nbone->mWeights = new aiVertexWeight[nbone->mNumWeights];
for( unsigned int d = 0; d < newWeights.size(); d++) for ( unsigned int d = 0; d < newWeights.size(); ++d ) {
nbone->mWeights[d] = newWeights[d]; nbone->mWeights[ d ] = newWeights[ d ];
}
} }
// store the bones in the mesh // store the bones in the mesh
mesh->mNumBones = (unsigned int)newBones.size(); mesh->mNumBones = (unsigned int)newBones.size();
if( newBones.size() > 0) if( !newBones.empty()) {
{
mesh->mBones = new aiBone*[mesh->mNumBones]; mesh->mBones = new aiBone*[mesh->mNumBones];
std::copy( newBones.begin(), newBones.end(), mesh->mBones); std::copy( newBones.begin(), newBones.end(), mesh->mBones);
} }
@ -424,8 +414,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// reallocate scene mesh array to be large enough // reallocate scene mesh array to be large enough
aiMesh** prevArray = pScene->mMeshes; aiMesh** prevArray = pScene->mMeshes;
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()]; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes + meshes.size()];
if( prevArray) if( prevArray) {
{
memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*)); memcpy( pScene->mMeshes, prevArray, pScene->mNumMeshes * sizeof( aiMesh*));
delete [] prevArray; delete [] prevArray;
} }
@ -435,8 +424,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
// store all meshes in the mesh library of the scene and store their indices in the node // store all meshes in the mesh library of the scene and store their indices in the node
for( unsigned int a = 0; a < meshes.size(); a++) for( unsigned int a = 0; a < meshes.size(); a++) {
{
pScene->mMeshes[pScene->mNumMeshes] = meshes[a]; pScene->mMeshes[pScene->mNumMeshes] = meshes[a];
pNode->mMeshes[a] = pScene->mNumMeshes; pNode->mMeshes[a] = pScene->mNumMeshes;
pScene->mNumMeshes++; pScene->mNumMeshes++;
@ -445,16 +433,15 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Converts the animations from the given imported data and creates them in the scene. // Converts the animations from the given imported data and creates them in the scene.
void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData) void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData) {
{
std::vector<aiAnimation*> newAnims; std::vector<aiAnimation*> newAnims;
for( unsigned int a = 0; a < pData->mAnims.size(); a++) for( unsigned int a = 0; a < pData->mAnims.size(); ++a ) {
{
const XFile::Animation* anim = pData->mAnims[a]; const XFile::Animation* anim = pData->mAnims[a];
// some exporters mock me with empty animation tags. // some exporters mock me with empty animation tags.
if( anim->mAnims.size() == 0) if ( anim->mAnims.empty() ) {
continue; continue;
}
// create a new animation to hold the data // create a new animation to hold the data
aiAnimation* nanim = new aiAnimation; aiAnimation* nanim = new aiAnimation;
@ -466,15 +453,14 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
nanim->mNumChannels = (unsigned int)anim->mAnims.size(); nanim->mNumChannels = (unsigned int)anim->mAnims.size();
nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels]; nanim->mChannels = new aiNodeAnim*[nanim->mNumChannels];
for( unsigned int b = 0; b < anim->mAnims.size(); b++) for( unsigned int b = 0; b < anim->mAnims.size(); ++b ) {
{
const XFile::AnimBone* bone = anim->mAnims[b]; const XFile::AnimBone* bone = anim->mAnims[b];
aiNodeAnim* nbone = new aiNodeAnim; aiNodeAnim* nbone = new aiNodeAnim;
nbone->mNodeName.Set( bone->mBoneName); nbone->mNodeName.Set( bone->mBoneName);
nanim->mChannels[b] = nbone; nanim->mChannels[b] = nbone;
// keyframes are given as combined transformation matrix keys // keyframes are given as combined transformation matrix keys
if( bone->mTrafoKeys.size() > 0) if( !bone->mTrafoKeys.empty() )
{ {
nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size(); nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys]; nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
@ -483,8 +469,7 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size(); nbone->mNumScalingKeys = (unsigned int)bone->mTrafoKeys.size();
nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys]; nbone->mScalingKeys = new aiVectorKey[nbone->mNumScalingKeys];
for( unsigned int c = 0; c < bone->mTrafoKeys.size(); c++) for( unsigned int c = 0; c < bone->mTrafoKeys.size(); ++c) {
{
// deconstruct each matrix into separate position, rotation and scaling // deconstruct each matrix into separate position, rotation and scaling
double time = bone->mTrafoKeys[c].mTime; double time = bone->mTrafoKeys[c].mTime;
aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix; aiMatrix4x4 trafo = bone->mTrafoKeys[c].mMatrix;
@ -516,13 +501,11 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
// longest lasting key sequence determines duration // longest lasting key sequence determines duration
nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime); nanim->mDuration = std::max( nanim->mDuration, bone->mTrafoKeys.back().mTime);
} else } else {
{
// separate key sequences for position, rotation, scaling // separate key sequences for position, rotation, scaling
nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size(); nbone->mNumPositionKeys = (unsigned int)bone->mPosKeys.size();
nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys]; nbone->mPositionKeys = new aiVectorKey[nbone->mNumPositionKeys];
for( unsigned int c = 0; c < nbone->mNumPositionKeys; c++) for( unsigned int c = 0; c < nbone->mNumPositionKeys; ++c ) {
{
aiVector3D pos = bone->mPosKeys[c].mValue; aiVector3D pos = bone->mPosKeys[c].mValue;
nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime; nbone->mPositionKeys[c].mTime = bone->mPosKeys[c].mTime;
@ -532,8 +515,7 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
// rotation // rotation
nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size(); nbone->mNumRotationKeys = (unsigned int)bone->mRotKeys.size();
nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys]; nbone->mRotationKeys = new aiQuatKey[nbone->mNumRotationKeys];
for( unsigned int c = 0; c < nbone->mNumRotationKeys; c++) for( unsigned int c = 0; c < nbone->mNumRotationKeys; ++c ) {
{
aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix(); aiMatrix3x3 rotmat = bone->mRotKeys[c].mValue.GetMatrix();
nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime; nbone->mRotationKeys[c].mTime = bone->mRotKeys[c].mTime;
@ -573,43 +555,38 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials) void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Material>& pMaterials)
{ {
// count the non-referrer materials in the array // count the non-referrer materials in the array
unsigned int numNewMaterials = 0; unsigned int numNewMaterials( 0 );
for( unsigned int a = 0; a < pMaterials.size(); a++) for ( unsigned int a = 0; a < pMaterials.size(); ++a ) {
if( !pMaterials[a].mIsReference) if ( !pMaterials[ a ].mIsReference ) {
numNewMaterials++; ++numNewMaterials;
}
}
// resize the scene's material list to offer enough space for the new materials // resize the scene's material list to offer enough space for the new materials
if( numNewMaterials > 0 ) if( numNewMaterials > 0 ) {
{
aiMaterial** prevMats = pScene->mMaterials; aiMaterial** prevMats = pScene->mMaterials;
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials]; pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials + numNewMaterials];
if( prevMats) if( nullptr != prevMats) {
{ ::memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
memcpy( pScene->mMaterials, prevMats, pScene->mNumMaterials * sizeof( aiMaterial*));
delete [] prevMats; delete [] prevMats;
} }
} }
// convert all the materials given in the array // convert all the materials given in the array
for( unsigned int a = 0; a < pMaterials.size(); a++) for( unsigned int a = 0; a < pMaterials.size(); ++a ) {
{
XFile::Material& oldMat = pMaterials[a]; XFile::Material& oldMat = pMaterials[a];
if( oldMat.mIsReference) if( oldMat.mIsReference) {
{
// find the material it refers to by name, and store its index // find the material it refers to by name, and store its index
for( size_t a = 0; a < pScene->mNumMaterials; ++a ) for( size_t a = 0; a < pScene->mNumMaterials; ++a ) {
{
aiString name; aiString name;
pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name); pScene->mMaterials[a]->Get( AI_MATKEY_NAME, name);
if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) if( strcmp( name.C_Str(), oldMat.mName.data()) == 0 ) {
{
oldMat.sceneIndex = a; oldMat.sceneIndex = a;
break; break;
} }
} }
if( oldMat.sceneIndex == SIZE_MAX ) if( oldMat.sceneIndex == SIZE_MAX ) {
{
DefaultLogger::get()->warn( format() << "Could not resolve global material reference \"" << oldMat.mName << "\"" ); DefaultLogger::get()->warn( format() << "Could not resolve global material reference \"" << oldMat.mName << "\"" );
oldMat.sceneIndex = 0; oldMat.sceneIndex = 0;
} }
@ -622,7 +599,7 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
name.Set( oldMat.mName); name.Set( oldMat.mName);
mat->AddProperty( &name, AI_MATKEY_NAME); mat->AddProperty( &name, AI_MATKEY_NAME);
// Shading model: hardcoded to PHONG, there is no such information in an XFile // Shading model: hard-coded to PHONG, there is no such information in an XFile
// FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix // FIX (aramis): If the specular exponent is 0, use gouraud shading. This is a bugfix
// for some models in the SDK (e.g. good old tiny.x) // for some models in the SDK (e.g. good old tiny.x)
int shadeMode = (int)oldMat.mSpecularExponent == 0.0f int shadeMode = (int)oldMat.mSpecularExponent == 0.0f
@ -639,36 +616,33 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
// texture, if there is one // texture, if there is one
if (1 == oldMat.mTextures.size()) if (1 == oldMat.mTextures.size() ) {
{
const XFile::TexEntry& otex = oldMat.mTextures.back(); const XFile::TexEntry& otex = oldMat.mTextures.back();
if (otex.mName.length()) if (otex.mName.length()) {
{
// if there is only one texture assume it contains the diffuse color // if there is only one texture assume it contains the diffuse color
aiString tex( otex.mName); aiString tex( otex.mName);
if( otex.mIsNormalMap) if ( otex.mIsNormalMap ) {
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(0)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS( 0 ) );
else } else {
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(0)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
} }
} }
else } else {
{
// Otherwise ... try to search for typical strings in the // Otherwise ... try to search for typical strings in the
// texture's file name like 'bump' or 'diffuse' // texture's file name like 'bump' or 'diffuse'
unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0; unsigned int iHM = 0,iNM = 0,iDM = 0,iSM = 0,iAM = 0,iEM = 0;
for( unsigned int b = 0; b < oldMat.mTextures.size(); b++) for( unsigned int b = 0; b < oldMat.mTextures.size(); ++b ) {
{
const XFile::TexEntry& otex = oldMat.mTextures[b]; const XFile::TexEntry& otex = oldMat.mTextures[b];
std::string sz = otex.mName; std::string sz = otex.mName;
if (!sz.length())continue; if ( !sz.length() ) {
continue;
}
// find the file name // find the file name
//const size_t iLen = sz.length();
std::string::size_type s = sz.find_last_of("\\/"); std::string::size_type s = sz.find_last_of("\\/");
if (std::string::npos == s) if ( std::string::npos == s ) {
s = 0; s = 0;
}
// cut off the file extension // cut off the file extension
std::string::size_type sExt = sz.find_last_of('.'); std::string::size_type sExt = sz.find_last_of('.');
@ -677,36 +651,27 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
} }
// convert to lower case for easier comparison // convert to lower case for easier comparison
for( unsigned int c = 0; c < sz.length(); c++) for ( unsigned int c = 0; c < sz.length(); ++c ) {
if( isalpha( sz[c])) if ( isalpha( sz[ c ] ) ) {
sz[c] = tolower( sz[c]); sz[ c ] = tolower( sz[ c ] );
}
}
// Place texture filename property under the corresponding name // Place texture filename property under the corresponding name
aiString tex( oldMat.mTextures[b].mName); aiString tex( oldMat.mTextures[b].mName);
// bump map // bump map
if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) if (std::string::npos != sz.find("bump", s) || std::string::npos != sz.find("height", s)) {
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_HEIGHT(iHM++));
} else } else if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s)) {
if (otex.mIsNormalMap || std::string::npos != sz.find( "normal", s) || std::string::npos != sz.find("nm", s))
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_NORMALS(iNM++));
} else } else if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s)) {
if (std::string::npos != sz.find( "spec", s) || std::string::npos != sz.find( "glanz", s))
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR(iSM++));
} else } else if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s)) {
if (std::string::npos != sz.find( "ambi", s) || std::string::npos != sz.find( "env", s))
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_AMBIENT(iAM++));
} else } else if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s)) {
if (std::string::npos != sz.find( "emissive", s) || std::string::npos != sz.find( "self", s))
{
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE(iEM++));
} else } else {
{
// Assume it is a diffuse texture // Assume it is a diffuse texture
mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++)); mat->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE(iDM++));
} }

View File

@ -87,59 +87,60 @@ static void dummy_free (void* /*opaque*/, void* address) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor. Creates a data structure out of the XFile given in the memory block. // Constructor. Creates a data structure out of the XFile given in the memory block.
XFileParser::XFileParser( const std::vector<char>& pBuffer) XFileParser::XFileParser( const std::vector<char>& pBuffer)
{ : mMajorVersion( 0 )
mMajorVersion = mMinorVersion = 0; , mMinorVersion( 0 )
mIsBinaryFormat = false; , mIsBinaryFormat( false )
mBinaryNumCount = 0; , mBinaryNumCount( 0 )
P = End = NULL; , mP( nullptr )
mLineNumber = 0; , mEnd( nullptr )
mScene = NULL; , mLineNumber( 0 )
, mScene( nullptr ) {
// vector to store uncompressed file for INFLATE'd X files // vector to store uncompressed file for INFLATE'd X files
std::vector<char> uncompressed; std::vector<char> uncompressed;
// set up memory pointers // set up memory pointers
P = &pBuffer.front(); mP = &pBuffer.front();
End = P + pBuffer.size() - 1; mEnd = mP + pBuffer.size() - 1;
// check header // check header
if( strncmp( P, "xof ", 4) != 0) if ( 0 != strncmp( mP, "xof ", 4 ) ) {
throw DeadlyImportError( "Header mismatch, file is not an XFile."); throw DeadlyImportError( "Header mismatch, file is not an XFile." );
}
// read version. It comes in a four byte format such as "0302" // read version. It comes in a four byte format such as "0302"
mMajorVersion = (unsigned int)(P[4] - 48) * 10 + (unsigned int)(P[5] - 48); mMajorVersion = (unsigned int)(mP[4] - 48) * 10 + (unsigned int)(mP[5] - 48);
mMinorVersion = (unsigned int)(P[6] - 48) * 10 + (unsigned int)(P[7] - 48); mMinorVersion = (unsigned int)(mP[6] - 48) * 10 + (unsigned int)(mP[7] - 48);
bool compressed = false; bool compressed = false;
// txt - pure ASCII text format // txt - pure ASCII text format
if( strncmp( P + 8, "txt ", 4) == 0) if( strncmp( mP + 8, "txt ", 4) == 0)
mIsBinaryFormat = false; mIsBinaryFormat = false;
// bin - Binary format // bin - Binary format
else if( strncmp( P + 8, "bin ", 4) == 0) else if( strncmp( mP + 8, "bin ", 4) == 0)
mIsBinaryFormat = true; mIsBinaryFormat = true;
// tzip - Inflate compressed text format // tzip - Inflate compressed text format
else if( strncmp( P + 8, "tzip", 4) == 0) else if( strncmp( mP + 8, "tzip", 4) == 0)
{ {
mIsBinaryFormat = false; mIsBinaryFormat = false;
compressed = true; compressed = true;
} }
// bzip - Inflate compressed binary format // bzip - Inflate compressed binary format
else if( strncmp( P + 8, "bzip", 4) == 0) else if( strncmp( mP + 8, "bzip", 4) == 0)
{ {
mIsBinaryFormat = true; mIsBinaryFormat = true;
compressed = true; compressed = true;
} }
else ThrowException( format() << "Unsupported xfile format '" << else ThrowException( format() << "Unsupported xfile format '" <<
P[8] << P[9] << P[10] << P[11] << "'"); mP[8] << mP[9] << mP[10] << mP[11] << "'");
// float size // float size
mBinaryFloatSize = (unsigned int)(P[12] - 48) * 1000 mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000
+ (unsigned int)(P[13] - 48) * 100 + (unsigned int)(mP[13] - 48) * 100
+ (unsigned int)(P[14] - 48) * 10 + (unsigned int)(mP[14] - 48) * 10
+ (unsigned int)(P[15] - 48); + (unsigned int)(mP[15] - 48);
if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64) if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
ThrowException( format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header." ); ThrowException( format() << "Unknown float size " << mBinaryFloatSize << " specified in xfile header." );
@ -147,7 +148,7 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
// The x format specifies size in bits, but we work in bytes // The x format specifies size in bits, but we work in bytes
mBinaryFloatSize /= 8; mBinaryFloatSize /= 8;
P += 16; mP += 16;
// If this is a compressed X file, apply the inflate algorithm to it // If this is a compressed X file, apply the inflate algorithm to it
if (compressed) if (compressed)
@ -186,13 +187,13 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
::inflateInit2(&stream, -MAX_WBITS); ::inflateInit2(&stream, -MAX_WBITS);
// skip unknown data (checksum, flags?) // skip unknown data (checksum, flags?)
P += 6; mP += 6;
// First find out how much storage we'll need. Count sections. // First find out how much storage we'll need. Count sections.
const char* P1 = P; const char* P1 = mP;
unsigned int est_out = 0; unsigned int est_out = 0;
while (P1 + 3 < End) while (P1 + 3 < mEnd)
{ {
// read next offset // read next offset
uint16_t ofs = *((uint16_t*)P1); uint16_t ofs = *((uint16_t*)P1);
@ -216,18 +217,18 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
// Allocate storage and terminating zero and do the actual uncompressing // Allocate storage and terminating zero and do the actual uncompressing
uncompressed.resize(est_out + 1); uncompressed.resize(est_out + 1);
char* out = &uncompressed.front(); char* out = &uncompressed.front();
while (P + 3 < End) while (mP + 3 < mEnd)
{ {
uint16_t ofs = *((uint16_t*)P); uint16_t ofs = *((uint16_t*)mP);
AI_SWAP2(ofs); AI_SWAP2(ofs);
P += 4; mP += 4;
if (P + ofs > End + 2) { if (mP + ofs > mEnd + 2) {
throw DeadlyImportError("X: Unexpected EOF in compressed chunk"); throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
} }
// push data to the stream // push data to the stream
stream.next_in = (Bytef*)P; stream.next_in = (Bytef*)mP;
stream.avail_in = ofs; stream.avail_in = ofs;
stream.next_out = (Bytef*)out; stream.next_out = (Bytef*)out;
stream.avail_out = MSZIP_BLOCK; stream.avail_out = MSZIP_BLOCK;
@ -242,15 +243,15 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
// and advance to the next offset // and advance to the next offset
out += MSZIP_BLOCK - stream.avail_out; out += MSZIP_BLOCK - stream.avail_out;
P += ofs; mP += ofs;
} }
// terminate zlib // terminate zlib
::inflateEnd(&stream); ::inflateEnd(&stream);
// ok, update pointers to point to the uncompressed file data // ok, update pointers to point to the uncompressed file data
P = &uncompressed[0]; mP = &uncompressed[0];
End = out; mEnd = out;
// FIXME: we don't need the compressed data anymore, could release // FIXME: we don't need the compressed data anymore, could release
// it already for better memory usage. Consider breaking const-co. // it already for better memory usage. Consider breaking const-co.
@ -465,12 +466,11 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
// read position faces // read position faces
unsigned int numPosFaces = ReadInt(); unsigned int numPosFaces = ReadInt();
pMesh->mPosFaces.resize( numPosFaces); pMesh->mPosFaces.resize( numPosFaces);
for( unsigned int a = 0; a < numPosFaces; a++) for( unsigned int a = 0; a < numPosFaces; ++a) {
{
// read indices // read indices
unsigned int numIndices = ReadInt(); unsigned int numIndices = ReadInt();
Face& face = pMesh->mPosFaces[a]; Face& face = pMesh->mPosFaces[a];
for (unsigned int b = 0; b < numIndices; b++) { for (unsigned int b = 0; b < numIndices; ++b) {
face.mIndices.push_back( ReadInt() ); face.mIndices.push_back( ReadInt() );
} }
TestForSeparator(); TestForSeparator();
@ -478,11 +478,10 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
// here, other data objects may follow // here, other data objects may follow
bool running = true; bool running = true;
while ( running ) while ( running ) {
{
std::string objectName = GetNextToken(); std::string objectName = GetNextToken();
if( objectName.size() == 0) if( objectName.empty() )
ThrowException( "Unexpected end of file while parsing mesh structure"); ThrowException( "Unexpected end of file while parsing mesh structure");
else else
if( objectName == "}") if( objectName == "}")
@ -517,8 +516,10 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh) void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh) {
{ if ( nullptr == pMesh ) {
return;
}
readHeadOfDataObject(); readHeadOfDataObject();
std::string transformNodeName; std::string transformNodeName;
@ -647,8 +648,8 @@ void XFileParser::ParseDataObjectMeshVertexColors( Mesh* pMesh)
if( !mIsBinaryFormat) if( !mIsBinaryFormat)
{ {
FindNextNoneWhiteSpace(); FindNextNoneWhiteSpace();
if( *P == ';' || *P == ',') if( *mP == ';' || *mP == ',')
P++; mP++;
} }
} }
@ -678,8 +679,8 @@ void XFileParser::ParseDataObjectMeshMaterialList( Mesh* pMesh)
// commented out version check, as version 03.03 exported from blender also has 2 semicolons // commented out version check, as version 03.03 exported from blender also has 2 semicolons
if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2) if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
{ {
if(P < End && *P == ';') if(mP < mEnd && *mP == ';')
++P; ++mP;
} }
// if there was only a single material index, replicate it on all faces // if there was only a single material index, replicate it on all faces
@ -1029,12 +1030,12 @@ void XFileParser::TestForSeparator()
return; return;
FindNextNoneWhiteSpace(); FindNextNoneWhiteSpace();
if( P >= End) if( mP >= mEnd)
return; return;
// test and skip // test and skip
if( *P == ';' || *P == ',') if( *mP == ';' || *mP == ',')
P++; mP++;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1046,62 +1047,73 @@ void XFileParser::readHeadOfDataObject( std::string* poName)
if( poName) if( poName)
*poName = nameOrBrace; *poName = nameOrBrace;
if( GetNextToken() != "{") if ( GetNextToken() != "{" ) {
ThrowException( "Opening brace expected."); delete mScene;
ThrowException( "Opening brace expected." );
}
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string XFileParser::GetNextToken() std::string XFileParser::GetNextToken() {
{
std::string s; std::string s;
// process binary-formatted file // process binary-formatted file
if( mIsBinaryFormat) if( mIsBinaryFormat) {
{
// in binary mode it will only return NAME and STRING token // in binary mode it will only return NAME and STRING token
// and (correctly) skip over other tokens. // and (correctly) skip over other tokens.
if ( mEnd - mP < 2 ) {
if( End - P < 2) return s; return s;
}
unsigned int tok = ReadBinWord(); unsigned int tok = ReadBinWord();
unsigned int len; unsigned int len;
// standalone tokens // standalone tokens
switch( tok) switch( tok ) {
{ case 1: {
case 1:
// name token // name token
if( End - P < 4) return s; if ( mEnd - mP < 4 ) {
len = ReadBinDWord();
if( End - P < int(len)) return s;
s = std::string(P, len);
P += len;
return s; return s;
}
len = ReadBinDWord();
const int bounds( mEnd - mP );
const int iLen( len );
if ( iLen < 0 ) {
return s;
}
if ( bounds < iLen ) {
return s;
}
s = std::string( mP, len );
mP += len;
}
return s;
case 2: case 2:
// string token // string token
if( End - P < 4) return s; if( mEnd - mP < 4) return s;
len = ReadBinDWord(); len = ReadBinDWord();
if( End - P < int(len)) return s; if( mEnd - mP < int(len)) return s;
s = std::string(P, len); s = std::string(mP, len);
P += (len + 2); mP += (len + 2);
return s; return s;
case 3: case 3:
// integer token // integer token
P += 4; mP += 4;
return "<integer>"; return "<integer>";
case 5: case 5:
// GUID token // GUID token
P += 16; mP += 16;
return "<guid>"; return "<guid>";
case 6: case 6:
if( End - P < 4) return s; if( mEnd - mP < 4) return s;
len = ReadBinDWord(); len = ReadBinDWord();
P += (len * 4); mP += (len * 4);
return "<int_list>"; return "<int_list>";
case 7: case 7:
if( End - P < 4) return s; if( mEnd - mP < 4) return s;
len = ReadBinDWord(); len = ReadBinDWord();
P += (len * mBinaryFloatSize); mP += (len * mBinaryFloatSize);
return "<flt_list>"; return "<flt_list>";
case 0x0a: case 0x0a:
return "{"; return "{";
@ -1159,19 +1171,19 @@ std::string XFileParser::GetNextToken()
else else
{ {
FindNextNoneWhiteSpace(); FindNextNoneWhiteSpace();
if( P >= End) if( mP >= mEnd)
return s; return s;
while( (P < End) && !isspace( (unsigned char) *P)) while( (mP < mEnd) && !isspace( (unsigned char) *mP))
{ {
// either keep token delimiters when already holding a token, or return if first valid char // either keep token delimiters when already holding a token, or return if first valid char
if( *P == ';' || *P == '}' || *P == '{' || *P == ',') if( *mP == ';' || *mP == '}' || *mP == '{' || *mP == ',')
{ {
if( !s.size()) if( !s.size())
s.append( P++, 1); s.append( mP++, 1);
break; // stop for delimiter break; // stop for delimiter
} }
s.append( P++, 1); s.append( mP++, 1);
} }
} }
return s; return s;
@ -1186,18 +1198,18 @@ void XFileParser::FindNextNoneWhiteSpace()
bool running = true; bool running = true;
while( running ) while( running )
{ {
while( P < End && isspace( (unsigned char) *P)) while( mP < mEnd && isspace( (unsigned char) *mP))
{ {
if( *P == '\n') if( *mP == '\n')
mLineNumber++; mLineNumber++;
++P; ++mP;
} }
if( P >= End) if( mP >= mEnd)
return; return;
// check if this is a comment // check if this is a comment
if( (P[0] == '/' && P[1] == '/') || P[0] == '#') if( (mP[0] == '/' && mP[1] == '/') || mP[0] == '#')
ReadUntilEndOfLine(); ReadUntilEndOfLine();
else else
break; break;
@ -1214,22 +1226,30 @@ void XFileParser::GetNextTokenAsString( std::string& poString)
} }
FindNextNoneWhiteSpace(); FindNextNoneWhiteSpace();
if( P >= End) if ( mP >= mEnd ) {
ThrowException( "Unexpected end of file while parsing string"); delete mScene;
ThrowException( "Unexpected end of file while parsing string" );
}
if( *P != '"') if ( *mP != '"' ) {
ThrowException( "Expected quotation mark."); delete mScene;
++P; ThrowException( "Expected quotation mark." );
}
++mP;
while( P < End && *P != '"') while( mP < mEnd && *mP != '"')
poString.append( P++, 1); poString.append( mP++, 1);
if( P >= End-1) if ( mP >= mEnd - 1 ) {
ThrowException( "Unexpected end of file while parsing string"); delete mScene;
ThrowException( "Unexpected end of file while parsing string" );
}
if( P[1] != ';' || P[0] != '"') if ( mP[ 1 ] != ';' || mP[ 0 ] != '"' ) {
ThrowException( "Expected quotation mark and semicolon at the end of a string."); delete mScene;
P+=2; ThrowException( "Expected quotation mark and semicolon at the end of a string." );
}
mP+=2;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1238,35 +1258,35 @@ void XFileParser::ReadUntilEndOfLine()
if( mIsBinaryFormat) if( mIsBinaryFormat)
return; return;
while( P < End) while( mP < mEnd)
{ {
if( *P == '\n' || *P == '\r') if( *mP == '\n' || *mP == '\r')
{ {
++P; mLineNumber++; ++mP; mLineNumber++;
return; return;
} }
++P; ++mP;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned short XFileParser::ReadBinWord() unsigned short XFileParser::ReadBinWord()
{ {
ai_assert(End - P >= 2); ai_assert(mEnd - mP >= 2);
const unsigned char* q = (const unsigned char*) P; const unsigned char* q = (const unsigned char*) mP;
unsigned short tmp = q[0] | (q[1] << 8); unsigned short tmp = q[0] | (q[1] << 8);
P += 2; mP += 2;
return tmp; return tmp;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int XFileParser::ReadBinDWord() unsigned int XFileParser::ReadBinDWord() {
{ ai_assert(mEnd - mP >= 4);
ai_assert(End - P >= 4);
const unsigned char* q = (const unsigned char*) P; const unsigned char* q = (const unsigned char*) mP;
unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24); unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24);
P += 4; mP += 4;
return tmp; return tmp;
} }
@ -1275,20 +1295,20 @@ unsigned int XFileParser::ReadInt()
{ {
if( mIsBinaryFormat) if( mIsBinaryFormat)
{ {
if( mBinaryNumCount == 0 && End - P >= 2) if( mBinaryNumCount == 0 && mEnd - mP >= 2)
{ {
unsigned short tmp = ReadBinWord(); // 0x06 or 0x03 unsigned short tmp = ReadBinWord(); // 0x06 or 0x03
if( tmp == 0x06 && End - P >= 4) // array of ints follows if( tmp == 0x06 && mEnd - mP >= 4) // array of ints follows
mBinaryNumCount = ReadBinDWord(); mBinaryNumCount = ReadBinDWord();
else // single int follows else // single int follows
mBinaryNumCount = 1; mBinaryNumCount = 1;
} }
--mBinaryNumCount; --mBinaryNumCount;
if ( End - P >= 4) { if ( mEnd - mP >= 4) {
return ReadBinDWord(); return ReadBinDWord();
} else { } else {
P = End; mP = mEnd;
return 0; return 0;
} }
} else } else
@ -1299,24 +1319,24 @@ unsigned int XFileParser::ReadInt()
// check preceding minus sign // check preceding minus sign
bool isNegative = false; bool isNegative = false;
if( *P == '-') if( *mP == '-')
{ {
isNegative = true; isNegative = true;
P++; mP++;
} }
// at least one digit expected // at least one digit expected
if( !isdigit( *P)) if( !isdigit( *mP))
ThrowException( "Number expected."); ThrowException( "Number expected.");
// read digits // read digits
unsigned int number = 0; unsigned int number = 0;
while( P < End) while( mP < mEnd)
{ {
if( !isdigit( *P)) if( !isdigit( *mP))
break; break;
number = number * 10 + (*P - 48); number = number * 10 + (*mP - 48);
P++; mP++;
} }
CheckForSeparator(); CheckForSeparator();
@ -1329,34 +1349,35 @@ ai_real XFileParser::ReadFloat()
{ {
if( mIsBinaryFormat) if( mIsBinaryFormat)
{ {
if( mBinaryNumCount == 0 && End - P >= 2) if( mBinaryNumCount == 0 && mEnd - mP >= 2)
{ {
unsigned short tmp = ReadBinWord(); // 0x07 or 0x42 unsigned short tmp = ReadBinWord(); // 0x07 or 0x42
if( tmp == 0x07 && End - P >= 4) // array of floats following if( tmp == 0x07 && mEnd - mP >= 4) // array of floats following
mBinaryNumCount = ReadBinDWord(); mBinaryNumCount = ReadBinDWord();
else // single float following else // single float following
mBinaryNumCount = 1; mBinaryNumCount = 1;
} }
--mBinaryNumCount; --mBinaryNumCount;
if( mBinaryFloatSize == 8) if( mBinaryFloatSize == 8) {
{ if( mEnd - mP >= 8) {
if( End - P >= 8) { double res;
ai_real result = (ai_real) (*(double*) P); ::memcpy( &res, mP, 8 );
P += 8; mP += 8;
const ai_real result( static_cast<ai_real>( res ) );
return result; return result;
} else { } else {
P = End; mP = mEnd;
return 0; return 0;
} }
} else } else {
{ if( mEnd - mP >= 4) {
if( End - P >= 4) { ai_real result;
ai_real result = *(ai_real*) P; ::memcpy( &result, mP, 4 );
P += 4; mP += 4;
return result; return result;
} else { } else {
P = End; mP = mEnd;
return 0; return 0;
} }
} }
@ -1367,21 +1388,21 @@ ai_real XFileParser::ReadFloat()
// check for various special strings to allow reading files from faulty exporters // check for various special strings to allow reading files from faulty exporters
// I mean you, Blender! // I mean you, Blender!
// Reading is safe because of the terminating zero // Reading is safe because of the terminating zero
if( strncmp( P, "-1.#IND00", 9) == 0 || strncmp( P, "1.#IND00", 8) == 0) if( strncmp( mP, "-1.#IND00", 9) == 0 || strncmp( mP, "1.#IND00", 8) == 0)
{ {
P += 9; mP += 9;
CheckForSeparator(); CheckForSeparator();
return 0.0; return 0.0;
} else } else
if( strncmp( P, "1.#QNAN0", 8) == 0) if( strncmp( mP, "1.#QNAN0", 8) == 0)
{ {
P += 8; mP += 8;
CheckForSeparator(); CheckForSeparator();
return 0.0; return 0.0;
} }
ai_real result = 0.0; ai_real result = 0.0;
P = fast_atoreal_move<ai_real>( P, result); mP = fast_atoreal_move<ai_real>( mP, result);
CheckForSeparator(); CheckForSeparator();
@ -1438,15 +1459,14 @@ aiColor3D XFileParser::ReadRGB()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Throws an exception with a line number and the given text. // Throws an exception with a line number and the given text.
AI_WONT_RETURN void XFileParser::ThrowException( const std::string& pText) AI_WONT_RETURN void XFileParser::ThrowException( const std::string& pText) {
{ if ( mIsBinaryFormat ) {
if( mIsBinaryFormat) throw DeadlyImportError( pText );
throw DeadlyImportError( pText); } else {
else
throw DeadlyImportError( format() << "Line " << mLineNumber << ": " << pText ); throw DeadlyImportError( format() << "Line " << mLineNumber << ": " << pText );
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Filters the imported hierarchy for some degenerated cases that some exporters produce. // Filters the imported hierarchy for some degenerated cases that some exporters produce.
void XFileParser::FilterHierarchy( XFile::Node* pNode) void XFileParser::FilterHierarchy( XFile::Node* pNode)

View File

@ -49,10 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/types.h> #include <assimp/types.h>
namespace Assimp namespace Assimp {
{ namespace XFile {
namespace XFile
{
struct Node; struct Node;
struct Mesh; struct Mesh;
struct Scene; struct Scene;
@ -61,21 +59,20 @@ namespace Assimp
struct AnimBone; struct AnimBone;
} }
/** The XFileParser reads a XFile either in text or binary form and builds a temporary /**
* @brief The XFileParser reads a XFile either in text or binary form and builds a temporary
* data structure out of it. * data structure out of it.
*/ */
class XFileParser class XFileParser {
{
public: public:
/** Constructor. Creates a data structure out of the XFile given in the memory block. /// Constructor. Creates a data structure out of the XFile given in the memory block.
* @param pBuffer Null-terminated memory buffer containing the XFile /// @param pBuffer Null-terminated memory buffer containing the XFile
*/
explicit XFileParser( const std::vector<char>& pBuffer); explicit XFileParser( const std::vector<char>& pBuffer);
/** Destructor. Destroys all imported data along with it */ /// Destructor. Destroys all imported data along with it
~XFileParser(); ~XFileParser();
/** Returns the temporary representation of the imported data */ /// Returns the temporary representation of the imported data.
XFile::Scene* GetImportedData() const { return mScene; } XFile::Scene* GetImportedData() const { return mScene; }
protected: protected:
@ -101,10 +98,10 @@ protected:
//! places pointer to next begin of a token, and ignores comments //! places pointer to next begin of a token, and ignores comments
void FindNextNoneWhiteSpace(); void FindNextNoneWhiteSpace();
//! returns next parseable token. Returns empty string if no token there //! returns next valid token. Returns empty string if no token there
std::string GetNextToken(); std::string GetNextToken();
//! reads header of dataobject including the opening brace. //! reads header of data object including the opening brace.
//! returns false if error happened, and writes name of object //! returns false if error happened, and writes name of object
//! if there is one //! if there is one
void readHeadOfDataObject( std::string* poName = NULL); void readHeadOfDataObject( std::string* poName = NULL);
@ -138,7 +135,8 @@ protected:
/** Throws an exception with a line number and the given text. */ /** Throws an exception with a line number and the given text. */
AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX;
/** Filters the imported hierarchy for some degenerated cases that some exporters produce. /**
* @brief Filters the imported hierarchy for some degenerated cases that some exporters produce.
* @param pData The sub-hierarchy to filter * @param pData The sub-hierarchy to filter
*/ */
void FilterHierarchy( XFile::Node* pNode); void FilterHierarchy( XFile::Node* pNode);
@ -147,18 +145,13 @@ protected:
unsigned int mMajorVersion, mMinorVersion; ///< version numbers unsigned int mMajorVersion, mMinorVersion; ///< version numbers
bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form
unsigned int mBinaryFloatSize; ///< float size in bytes, either 4 or 8 unsigned int mBinaryFloatSize; ///< float size in bytes, either 4 or 8
// counter for number arrays in binary format unsigned int mBinaryNumCount; /// < counter for number arrays in binary format
unsigned int mBinaryNumCount; const char* mP;
const char* mEnd;
const char* P; unsigned int mLineNumber; ///< Line number when reading in text format
const char* End; XFile::Scene* mScene; ///< Imported data
/// Line number when reading in text format
unsigned int mLineNumber;
/// Imported data
XFile::Scene* mScene;
}; };
} } //! ns Assimp
#endif // AI_XFILEPARSER_H_INC #endif // AI_XFILEPARSER_H_INC

View File

@ -72,17 +72,6 @@ using namespace irr::io;
#endif #endif
// scopeguard for a malloc'ed buffer
struct free_it
{
free_it(void* free) : free(free) {}
~free_it() {
::free(this->free);
}
void* free;
};
namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp
template<> const char* LogFunctions<XGLImporter>::Prefix() template<> const char* LogFunctions<XGLImporter>::Prefix()
{ {
@ -155,8 +144,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler) aiScene* pScene, IOSystem* pIOHandler)
{ {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
Bytef* dest = NULL; std::vector<Bytef> uncompressed;
free_it free_it_really(dest);
#endif #endif
m_scene = pScene; m_scene = pScene;
@ -192,6 +180,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
size_t total = 0l; size_t total = 0l;
// TODO: be smarter about this, decompress directly into heap buffer
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
#define MYBLOCK 1024 #define MYBLOCK 1024
Bytef block[MYBLOCK]; Bytef block[MYBLOCK];
@ -206,8 +195,8 @@ void XGLImporter::InternReadFile( const std::string& pFile,
} }
const size_t have = MYBLOCK - zstream.avail_out; const size_t have = MYBLOCK - zstream.avail_out;
total += have; total += have;
dest = reinterpret_cast<Bytef*>( realloc(dest,total) ); uncompressed.resize(total);
memcpy(dest + total - have,block,have); memcpy(uncompressed.data() + total - have,block,have);
} }
while (ret != Z_STREAM_END); while (ret != Z_STREAM_END);
@ -215,7 +204,7 @@ void XGLImporter::InternReadFile( const std::string& pFile,
inflateEnd(&zstream); inflateEnd(&zstream);
// replace the input stream with a memory stream // replace the input stream with a memory stream
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total)); stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()),total));
#endif #endif
} }

Binary file not shown.

View File

@ -57,17 +57,26 @@ class BlenderIntermediateTest : public ::testing::Test {
#define NAME_1 "name1" #define NAME_1 "name1"
#define NAME_2 "name2" #define NAME_2 "name2"
// Updated this test after fixing #1776:
// A comparator in C++ is used for ordering and must implement strict weak ordering,
// which means it must return false for equal values.
// The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
TEST_F( BlenderIntermediateTest,ConversionData_ObjectCompareTest ) { TEST_F( BlenderIntermediateTest,ConversionData_ObjectCompareTest ) {
Object obj1, obj2; Object obj1, obj2;
strncpy( obj1.id.name, NAME_1, sizeof(NAME_1) ); strncpy( obj1.id.name, NAME_1, sizeof(NAME_1) );
strncpy( obj2.id.name, NAME_2, sizeof(NAME_2) ); strncpy( obj2.id.name, NAME_2, sizeof(NAME_2) );
Blender::ObjectCompare cmp_false;
bool res( cmp_false( &obj1, &obj2 ) ); Blender::ObjectCompare cmp_true_because_first_is_smaller_than_second;
bool res( cmp_true_because_first_is_smaller_than_second( &obj1, &obj2 ) );
EXPECT_TRUE( res );
Blender::ObjectCompare cmp_false_because_equal;
res = cmp_false_because_equal( &obj1, &obj1 );
EXPECT_FALSE( res ); EXPECT_FALSE( res );
Blender::ObjectCompare cmp_true; Blender::ObjectCompare cmp_false_because_first_is_greater_than_second;
res = cmp_true( &obj1, &obj1 ); res = cmp_false_because_first_is_greater_than_second( &obj2, &obj1 );
EXPECT_TRUE( res ); EXPECT_FALSE( res );
} }

View File

@ -103,3 +103,28 @@ TEST_F( utPLYImportExport, vertexColorTest ) {
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/float-color.ply", 0 ); const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/float-color.ply", 0 );
EXPECT_NE( nullptr, scene ); EXPECT_NE( nullptr, scene );
} }
static const char *test_file =
"ply\n"
"format ascii 1.0\n"
"element vertex 4\n"
"property float x\n"
"property float y\n"
"property float z\n"
"property uchar red\n"
"property uchar green\n"
"property uchar blue\n"
"property float nx\n"
"property float ny\n"
"property float nz\n"
"end_header\n"
"0.0 0.0 0.0 255 255 255 0.0 1.0 0.0\n"
"0.0 0.0 1.0 255 0 255 0.0 0.0 1.0\n"
"0.0 1.0 0.0 255 255 0 1.0 0.0 0.0\n"
"0.0 1.0 1.0 0 255 255 1.0 1.0 0.0\n";
TEST_F( utPLYImportExport, parseErrorTest ) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFileFromMemory( test_file, strlen( test_file ), 0 );
EXPECT_NE( nullptr, scene );
}

View File

@ -62,3 +62,8 @@ public:
TEST_F( utXImporterExporter, importXFromFileTest ) { TEST_F( utXImporterExporter, importXFromFileTest ) {
EXPECT_TRUE( importerTest() ); EXPECT_TRUE( importerTest() );
} }
TEST_F( utXImporterExporter, heap_overflow_in_tokenizer ) {
Assimp::Importer importer;
EXPECT_NO_THROW( importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/X/OV_GetNextToken", 0 ) );
}