MD5 bugfix.

WIP version of the OptimizeGraph-Step.
Added hashes to some string routines (speedup).
Improved property system for float and strings.
Refactoring code for computing normals from smoothinggroups.
Implemented C-ASSIMP.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@116 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
This commit is contained in:
aramis_acg
2008-08-28 17:35:36 +00:00
parent 51bfc46c1d
commit 38d04b6796
62 changed files with 3399 additions and 1226 deletions
+38 -66
View File
@@ -59,10 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
#ifdef _MSC_VER
# define sprintf sprintf_s
#endif
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ReplaceDefaultMaterial()
{
@@ -130,70 +126,66 @@ void Dot3DSImporter::ReplaceDefaultMaterial()
}
return;
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::CheckIndices(Dot3DS::Mesh* sMesh)
void Dot3DSImporter::CheckIndices(Dot3DS::Mesh& sMesh)
{
for (std::vector< Dot3DS::Face >::iterator
i = sMesh->mFaces.begin();
i != sMesh->mFaces.end();++i)
i = sMesh.mFaces.begin();
i != sMesh.mFaces.end();++i)
{
// check whether all indices are in range
if ((*i).mIndices[0] >= sMesh->mPositions.size())
for (unsigned int a = 0; a < 3;++a)
{
DefaultLogger::get()->warn("Face index overflow in 3DS file (#1)");
(*i).mIndices[0] = (uint32_t)sMesh->mPositions.size()-1;
}
if ((*i).mIndices[1] >= sMesh->mPositions.size())
{
DefaultLogger::get()->warn("Face index overflow in 3DS file (#2)");
(*i).mIndices[1] = (uint32_t)sMesh->mPositions.size()-1;
}
if ((*i).mIndices[2] >= sMesh->mPositions.size())
{
DefaultLogger::get()->warn("Face index overflow in 3DS file (#3)");
(*i).mIndices[2] = (uint32_t)sMesh->mPositions.size()-1;
if ((*i).mIndices[a] >= sMesh.mPositions.size())
{
DefaultLogger::get()->warn("3DS: Face index overflow)");
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
}
}
}
return;
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
void Dot3DSImporter::MakeUnique(Dot3DS::Mesh& sMesh)
{
unsigned int iBase = 0;
std::vector<aiVector3D> vNew;
std::vector<aiVector2D> vNew2;
vNew.resize(sMesh->mFaces.size() * 3);
if (sMesh->mTexCoords.size())vNew2.resize(sMesh->mFaces.size() * 3);
vNew.resize(sMesh.mFaces.size() * 3);
if (sMesh.mTexCoords.size())vNew2.resize(sMesh.mFaces.size() * 3);
for (unsigned int i = 0; i < sMesh->mFaces.size();++i)
for (unsigned int i = 0; i < sMesh.mFaces.size();++i)
{
uint32_t iTemp1,iTemp2;
// positions
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]];
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[2]];
iTemp1 = iBase++;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]];
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[1]];
iTemp2 = iBase++;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]];
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[0]];
// texture coordinates
if (sMesh->mTexCoords.size())
if (sMesh.mTexCoords.size())
{
vNew2[iTemp1] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[2]];
vNew2[iTemp2] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[1]];
vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[0]];
vNew2[iTemp1] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[2]];
vNew2[iTemp2] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[1]];
vNew2[iBase] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[0]];
}
sMesh->mFaces[i].mIndices[2] = iBase++;
sMesh->mFaces[i].mIndices[0] = iTemp1;
sMesh->mFaces[i].mIndices[1] = iTemp2;
sMesh.mFaces[i].mIndices[2] = iBase++;
sMesh.mFaces[i].mIndices[0] = iTemp1;
sMesh.mFaces[i].mIndices[1] = iTemp2;
}
sMesh->mPositions = vNew;
sMesh->mTexCoords = vNew2;
sMesh.mPositions = vNew;
sMesh.mTexCoords = vNew2;
return;
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
MaterialHelper& mat)
@@ -201,14 +193,14 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
// NOTE: Pass the background image to the viewer by bypassing the
// material system. This is an evil hack, never do it again!
if (0 != this->mBackgroundImage.length() && this->bHasBG)
{
{
aiString tex;
tex.Set( this->mBackgroundImage);
mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
// be sure this is only done for the first material
this->mBackgroundImage = std::string("");
}
}
// At first add the base ambient color of the
// scene to the material
@@ -250,7 +242,7 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
// two sided rendering?
if (oldMat.mTwoSided)
{
int i = 0;
int i = 1;
mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
}
@@ -268,8 +260,6 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
eShading = aiShadingMode_Gouraud; break;
// assume cook-torrance shading for metals.
// NOTE: I assume the real shader inside 3ds max is an anisotropic
// Phong-Blinn shader, but this is a good approximation too
case Dot3DS::Dot3DSFile::Phong :
eShading = aiShadingMode_Phong; break;
@@ -409,20 +399,7 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
a = (*i).mFaceMaterials.begin();
a != (*i).mFaceMaterials.end();++a,++iNum)
{
// check range
// FIX: shouldn't be necessary anymore, has been moved to ReplaceDefaultMaterial()
#if 0
if ((*a) >= this->mScene->mMaterials.size())
{
DefaultLogger::get()->error("3DS face material index is out of range");
// use the last material instead
// TODO: assign the default material index
aiSplit[this->mScene->mMaterials.size()-1].push_back(iNum);
}
else
#endif
aiSplit[*a].push_back(iNum);
aiSplit[*a].push_back(iNum);
}
// now generate submeshes
bool bFirst = true;
@@ -506,12 +483,9 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
{
pcOut->mMeshes[a] = avOutMeshes[a];
}
if (!iFaceCnt)
throw new ImportErrorException("No faces loaded. The mesh is empty");
if (!iFaceCnt)throw new ImportErrorException("No faces loaded. The mesh is empty");
// for each material in the scene we need to setup the UV source
// set for each texture
@@ -519,6 +493,7 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &this->mScene->mMaterials[a] );
return;
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node* pcIn)
{
@@ -533,11 +508,8 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
ai_assert(NULL != pcMesh);
// do case independent comparisons here, just for safety
if (pcIn->mName.length() == pcMesh->mName.length() &&
!ASSIMP_stricmp(pcIn->mName.c_str(),pcMesh->mName.c_str()))
{
if (!ASSIMP_stricmp(pcIn->mName,pcMesh->mName))
iArray.push_back(a);
}
}
if (!iArray.empty())
{
@@ -568,10 +540,11 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
pvCurrent->y -= pivot.y;
pvCurrent->z -= pivot.z;
*pvCurrent = mTrafo * (*pvCurrent);
std::swap( pvCurrent->y, pvCurrent->z );
//std::swap( pvCurrent->y, pvCurrent->z );
++pvCurrent;
}
}
#if 0
else
{
while (pvCurrent != pvEnd)
@@ -580,6 +553,7 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
++pvCurrent;
}
}
#endif
pcOut->mMeshes[i] = iIndex;
}
}
@@ -658,9 +632,7 @@ void Dot3DSImporter::GenerateNodeGraph(aiScene* pcOut)
// if the root node is a default node setup a name for it
if (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')
{
pcOut->mRootNode->mName.Set("<root>");
}
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ConvertScene(aiScene* pcOut)
+13 -45
View File
@@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file Defines the helper data structures for importing 3DS files.
/** @file Defines helper data structures for the import of 3DS files.
http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
#ifndef AI_3DSFILEHELPER_H_INC
@@ -55,20 +55,18 @@ http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
#include "../include/aiMaterial.h"
#include "SpatialSort.h"
#include "SmoothingGroups.h"
namespace Assimp {
namespace Dot3DS {
#include "./Compiler/pushpack1.h"
#ifdef _MSC_VER
# define sprintf sprintf_s
#endif
// ---------------------------------------------------------------------------
/** Dot3DSFile class: Helper class for loading 3ds files. Defines chunks
* and data structures.
*/
// ---------------------------------------------------------------------------
class Dot3DSFile
{
public:
@@ -91,32 +89,27 @@ public:
typedef enum
{
// translated to gouraud shading with wireframe active
Wire = 0,
Wire = 0x0,
// if this material is set, no vertex normals will
// be calculated for the model. Face normals + gouraud
Flat = 1,
Flat = 0x1,
// standard gouraud shading
Gouraud = 2,
Gouraud = 0x2,
// phong shading
Phong = 3,
Phong = 0x3,
// cooktorrance or anistropic phong shading ...
// the exact meaning is unknown, if you know it
// feel free to tell me ;-)
Metal = 4,
Metal = 0x4,
// required by the ASE loader
Blinn = 5
Blinn = 0x5
} shadetype3ds;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// enum for all chunks in 3ds files. Unused
// ones are commented, list is not complete since
// there are many undocumented chunks
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum
{
@@ -316,26 +309,10 @@ public:
// ---------------------------------------------------------------------------
/** Helper structure representing a 3ds mesh face */
struct Face
struct Face : public FaceWithSmoothingGroup
{
Face() : iSmoothGroup(0), bFlipped(false)
{
// let the rest uninitialized for performance
this->mIndices[0] = 0;
this->mIndices[1] = 0;
this->mIndices[2] = 0;
}
//! Indices. .3ds is using uint16. However, after
//! an unique vrtex set has been geneerated it might
//! be an index becomes > 2^16
uint32_t mIndices[3];
//! specifies to which smoothing group the face belongs to
uint32_t iSmoothGroup;
//! Specifies that the face normal must be flipped
//! Specifies that the face normal must be flipped.
//! todo: do we really need this?
bool bFlipped;
};
// ---------------------------------------------------------------------------
@@ -442,7 +419,7 @@ struct Material
};
// ---------------------------------------------------------------------------
/** Helper structure to represent a 3ds file mesh */
struct Mesh
struct Mesh : public MeshWithSmoothingGroups<Dot3DS::Face>
{
//! Default constructor
Mesh()
@@ -457,21 +434,12 @@ struct Mesh
//! Name of the mesh
std::string mName;
//! Vertex positions
std::vector<aiVector3D> mPositions;
//! Face lists
std::vector<Face> mFaces;
//! Texture coordinates
std::vector<aiVector2D> mTexCoords;
//! Face materials
std::vector<unsigned int> mFaceMaterials;
//! Normal vectors
std::vector<aiVector3D> mNormals;
//! Local transformation matrix
aiMatrix4x4 mMat;
};
+93 -221
View File
@@ -50,23 +50,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// public ASSIMP headers
#include "../include/DefaultLogger.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/aiMesh.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/assimp.hpp"
// boost headers
#include <boost/scoped_ptr.hpp>
using namespace Assimp;
#if (!defined ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG)
# define ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG \
"WARNING: Size of chunk data plus size of " \
"subordinate chunks is larger than the size " \
"specified in the top-level chunk header."
// begin a chunk: parse it, validate its length, get a pointer to its end
#define ASSIMP_3DS_BEGIN_CHUNK() \
const Dot3DSFile::Chunk* psChunk; \
this->ReadChunk(&psChunk); \
const unsigned char* pcCur = this->mCurrent; \
const unsigned char* pcCurNext = pcCur + (psChunk->Size \
- sizeof(Dot3DSFile::Chunk));
// process the end of a chunk and return if the end of the file is reached
#define ASSIMP_3DS_END_CHUNK() \
this->mCurrent = pcCurNext; \
piRemaining -= psChunk->Size; \
if (0 >= piRemaining)return;
// check whether the size of all subordinate chunks of a chunks is
// not larger than the size of the chunk itself
#ifdef _DEBUG
# define ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG \
"Size of chunk data plus size of subordinate chunks is " \
"larger than the size specified in the top-level chunk header."
# define ASSIMP_3DS_VALIDATE_CHUNK_SIZE() \
if (pcCurNext < this->mCurrent) \
{ \
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG); \
pcCurNext = this->mCurrent; \
}
#else
# define ASSIMP_3DS_VALIDATE_CHUNK_SIZE()
#endif
// ------------------------------------------------------------------------------------------------
@@ -92,7 +117,7 @@ bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) co
return false;
std::string extension = pFile.substr( pos);
// not brilliant but working ;-)
// not brillant but working ;-)
if( extension == ".3ds" || extension == ".3DS" ||
extension == ".3Ds" || extension == ".3dS")
return true;
@@ -103,7 +128,7 @@ bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) co
// Setup configuration properties
void Dot3DSImporter::SetupProperties(const Importer* pImp)
{
this->configSkipPivot = pImp->GetProperty(AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT,0) ? true : false;
this->configSkipPivot = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT,0) ? true : false;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
@@ -151,11 +176,11 @@ void Dot3DSImporter::InternReadFile(
i != this->mScene->mMeshes.end();++i)
{
// TODO: see function body
this->CheckIndices(&(*i));
this->MakeUnique(&(*i));
this->CheckIndices(*i);
this->MakeUnique(*i);
// first generate normals for the mesh
this->GenNormals(&(*i));
ComputeNormalsWithSmoothingsGroups<Dot3DS::Face>(*i);
}
// Apply scaling and offsets to all texture coordinates
@@ -179,11 +204,7 @@ void Dot3DSImporter::InternReadFile(
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ApplyMasterScale(aiScene* pScene)
{
// NOTE: Some invalid files have masterscale set to 0.0
if (0.0f == this->mMasterScale)
{
this->mMasterScale = 1.0f;
}
if (!this->mMasterScale)this->mMasterScale = 1.0f;
else this->mMasterScale = 1.0f / this->mMasterScale;
// construct an uniform scaling matrix and multiply with it
@@ -200,9 +221,8 @@ void Dot3DSImporter::ReadChunk(const Dot3DSFile::Chunk** p_ppcOut)
// read chunk
if (this->mCurrent >= this->mLast)
{
throw new ImportErrorException("Unexpected end of file, can't read chunk header");
}
const uintptr_t iDiff = this->mLast - this->mCurrent;
if (iDiff < sizeof(Dot3DSFile::Chunk))
{
@@ -211,23 +231,15 @@ void Dot3DSImporter::ReadChunk(const Dot3DSFile::Chunk** p_ppcOut)
}
*p_ppcOut = (const Dot3DSFile::Chunk*) this->mCurrent;
if ((**p_ppcOut).Size + this->mCurrent > this->mLast)
{
throw new ImportErrorException("Unexpected end of file, can't read chunk footer");
}
this->mCurrent += sizeof(Dot3DSFile::Chunk);
return;
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseMainChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size
- sizeof(Dot3DSFile::Chunk));
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
@@ -237,27 +249,14 @@ void Dot3DSImporter::ParseMainChunk(int& piRemaining)
this->ParseEditorChunk(iRemaining);
break;
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next top-level chunk
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return this->ParseMainChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseEditorChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
@@ -291,27 +290,14 @@ void Dot3DSImporter::ParseEditorChunk(int& piRemaining)
}
break;
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next top-level chunk
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return this->ParseEditorChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseObjectChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
ASSIMP_3DS_BEGIN_CHUNK();
const unsigned char* sz = this->mCurrent;
unsigned int iCnt = 0;
@@ -384,17 +370,8 @@ void Dot3DSImporter::ParseObjectChunk(int& piRemaining)
break;
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next top-level chunk
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return this->ParseObjectChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
@@ -409,11 +386,7 @@ void Dot3DSImporter::SkipChunk()
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
@@ -424,28 +397,14 @@ void Dot3DSImporter::ParseChunk(int& piRemaining)
this->ParseMeshChunk(iRemaining);
break;
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next top-level chunk
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return this->ParseChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseKeyframeChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
@@ -456,18 +415,8 @@ void Dot3DSImporter::ParseKeyframeChunk(int& piRemaining)
this->ParseHierarchyChunk(iRemaining);
break;
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next top-level chunk
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return this->ParseKeyframeChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
@@ -489,14 +438,7 @@ void Dot3DSImporter::InverseNodeSearch(Dot3DS::Node* pcNode,Dot3DS::Node* pcCurr
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size
- sizeof(Dot3DSFile::Chunk));
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
const unsigned char* sz = (unsigned char*)this->mCurrent;
@@ -548,6 +490,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
// pivot = origin of rotation and scaling
this->mCurrentNode->vPivot = *((const aiVector3D*)this->mCurrent);
std::swap(this->mCurrentNode->vPivot.y,this->mCurrentNode->vPivot.z);
this->mCurrent += sizeof(aiVector3D);
break;
@@ -576,8 +519,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
uint16_t sNum = *((const uint16_t*)mCurrent);
this->mCurrent += sizeof(uint16_t);
aiVectorKey v;
v.mTime = (double)sNum;
aiVectorKey v;v.mTime = (double)sNum;
this->mCurrent += sizeof(uint32_t);
v.mValue = *((const aiVector3D*)this->mCurrent);
@@ -591,7 +533,8 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
}
// add the new keyframe
if (v.mTime != -10e10f)this->mCurrentNode->aPositionKeys.push_back(v);
if (v.mTime != -10e10f)
this->mCurrentNode->aPositionKeys.push_back(v);
}
break;
@@ -618,9 +561,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
uint16_t sNum = *((const uint16_t*)mCurrent);
this->mCurrent += sizeof(uint16_t);
aiQuatKey v;
v.mTime = (double)sNum;
aiQuatKey v;v.mTime = (double)sNum;
this->mCurrent += sizeof(uint32_t);
float fRadians = *((const float*)this->mCurrent);
@@ -640,7 +581,8 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
}
// add the new keyframe
if (v.mTime != -10e10f)this->mCurrentNode->aRotationKeys.push_back(v);
if (v.mTime != -10e10f)
this->mCurrentNode->aRotationKeys.push_back(v);
}
break;
@@ -698,31 +640,16 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
break;
#endif
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next top-level chunk
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return this->ParseHierarchyChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseFaceChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
ASSIMP_3DS_BEGIN_CHUNK();
Dot3DS::Mesh& mMesh = this->mScene->mMeshes.back();
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
// get chunk type
const unsigned char* sz = this->mCurrent;
uint32_t iCnt = 0,iTemp;
@@ -796,31 +723,16 @@ void Dot3DSImporter::ParseFaceChunk(int& piRemaining)
break;
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next chunk on this level
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return ParseFaceChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
ASSIMP_3DS_BEGIN_CHUNK();
Dot3DS::Mesh& mMesh = this->mScene->mMeshes.back();
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
// get chunk type
const unsigned char* sz = this->mCurrent;
unsigned int iCnt = 0;
@@ -837,7 +749,7 @@ void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
{
mMesh.mPositions.push_back(*((aiVector3D*)this->mCurrent));
aiVector3D& v = mMesh.mPositions.back();
//std::swap( v.y, v.z);
std::swap( v.y, v.z);
//v.y *= -1.0f;
this->mCurrent += sizeof(aiVector3D);
}
@@ -924,28 +836,14 @@ void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
break;
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next chunk on this level
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return ParseMeshChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
{
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
const unsigned char* sz = this->mCurrent;
@@ -958,9 +856,8 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
case Dot3DSFile::CHUNK_MAT_MATNAME:
// string in file is zero-terminated,
// this should be no problem. However, validate whether
// it overlaps the end of the chunk, if yes we should
// truncate it.
// this should be no problem. However, validate whether it overlaps
// the end of the chunk, if yes we should truncate it.
while (*sz++ != '\0')
{
if (sz > pcCurNext-1)
@@ -1017,8 +914,7 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
pcf = &this->mScene->mMaterials.back().mTransparency;
*pcf = this->ParsePercentageChunk();
// NOTE: transparency, not opacity
if (is_qnan(*pcf))
*pcf = 1.0f;
if (is_qnan(*pcf))*pcf = 1.0f;
else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
break;
@@ -1037,16 +933,14 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
case Dot3DSFile::CHUNK_MAT_SHININESS:
pcf = &this->mScene->mMaterials.back().mSpecularExponent;
*pcf = this->ParsePercentageChunk();
if (is_qnan(*pcf))
*pcf = 0.0f;
if (is_qnan(*pcf))*pcf = 0.0f;
else *pcf *= (float)0xFFFF;
break;
case Dot3DSFile::CHUNK_MAT_SHININESS_PERCENT:
pcf = &this->mScene->mMaterials.back().mShininessStrength;
*pcf = this->ParsePercentageChunk();
if (is_qnan(*pcf))
*pcf = 0.0f;
if (is_qnan(*pcf))*pcf = 0.0f;
else *pcf *= (float)0xffff / 100.0f;
break;
@@ -1054,8 +948,7 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
// TODO: need to multiply with emissive base color?
pcf = &this->mScene->mMaterials.back().sTexEmissive.mTextureBlend;
*pcf = this->ParsePercentageChunk();
if (is_qnan(*pcf))
*pcf = 0.0f;
if (is_qnan(*pcf))*pcf = 0.0f;
else *pcf = *pcf * (float)0xFFFF / 100.0f;
break;
@@ -1085,31 +978,14 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexEmissive);
break;
};
if (pcCurNext < this->mCurrent)
{
// place an error message. If we crash the programmer
// will be able to find it
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
pcCurNext = this->mCurrent;
}
// Go to the starting position of the next chunk on this level
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return ParseMaterialChunk(piRemaining);
}
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ParseTextureChunk(int& piRemaining,Dot3DS::Texture* pcOut)
{
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
const unsigned char* pcCur = this->mCurrent;
const unsigned char* pcCurNext = pcCur + (psChunk->Size
- sizeof(Dot3DSFile::Chunk));
ASSIMP_3DS_BEGIN_CHUNK();
// get chunk type
const unsigned char* sz = this->mCurrent;
@@ -1184,11 +1060,8 @@ void Dot3DSImporter::ParseTextureChunk(int& piRemaining,Dot3DS::Texture* pcOut)
break;
};
// Go to the starting position of the next chunk on this level
this->mCurrent = pcCurNext;
piRemaining -= psChunk->Size;
if (0 >= piRemaining)return;
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
ASSIMP_3DS_END_CHUNK();
return ParseTextureChunk(piRemaining,pcOut);
}
// ------------------------------------------------------------------------------------------------
@@ -1226,20 +1099,22 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
const Dot3DSFile::Chunk* psChunk;
this->ReadChunk(&psChunk);
if (NULL == psChunk)
if (!psChunk)
{
*p_pcOut = clrError;
return;
}
const unsigned int diff = psChunk->Size - sizeof(Dot3DSFile::Chunk);
const unsigned char* pcCur = this->mCurrent;
this->mCurrent += psChunk->Size - sizeof(Dot3DSFile::Chunk);
this->mCurrent += diff;
bool bGamma = false;
switch(psChunk->Flag)
{
case Dot3DSFile::CHUNK_LINRGBF:
bGamma = true;
case Dot3DSFile::CHUNK_RGBF:
if (sizeof(float) * 3 > psChunk->Size - sizeof(Dot3DSFile::Chunk))
if (sizeof(float) * 3 > diff)
{
*p_pcOut = clrError;
return;
@@ -1252,7 +1127,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
case Dot3DSFile::CHUNK_LINRGBB:
bGamma = true;
case Dot3DSFile::CHUNK_RGBB:
if (sizeof(char) * 3 > psChunk->Size - sizeof(Dot3DSFile::Chunk))
if (sizeof(char) * 3 > diff)
{
*p_pcOut = clrError;
return;
@@ -1265,7 +1140,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
// percentage chunks: accepted to be compatible with various
// .3ds files with very curious content
case Dot3DSFile::CHUNK_PERCENTF:
if (p_bAcceptPercent && 4 <= psChunk->Size - sizeof(Dot3DSFile::Chunk))
if (p_bAcceptPercent && 4 <= diff)
{
p_pcOut->r = *((float*)pcCur);
p_pcOut->g = *((float*)pcCur);
@@ -1275,7 +1150,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
*p_pcOut = clrError;
return;
case Dot3DSFile::CHUNK_PERCENTW:
if (p_bAcceptPercent && 1 <= psChunk->Size - sizeof(Dot3DSFile::Chunk))
if (p_bAcceptPercent && 1 <= diff)
{
p_pcOut->r = (float)pcCur[0] / 255.0f;
p_pcOut->g = (float)pcCur[0] / 255.0f;
@@ -1289,9 +1164,6 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
// skip unknown chunks, hope this won't cause any problems.
return this->ParseColorChunk(p_pcOut,p_bAcceptPercent);
};
// assume input gamma = 1.0, output gamma = 2.2
// Not sure whether this is correct, too tired to
// think about it ;-)
if (bGamma)
{
p_pcOut->r = powf(p_pcOut->r, 1.0f / 2.2f);
+2 -7
View File
@@ -206,15 +206,10 @@ protected:
*/
void ConvertScene(aiScene* pcOut);
// -------------------------------------------------------------------
/** generate normal vectors for a given mesh
*/
void GenNormals(Dot3DS::Mesh* sMesh);
// -------------------------------------------------------------------
/** generate unique vertices for a mesh
*/
void MakeUnique(Dot3DS::Mesh* sMesh);
void MakeUnique(Dot3DS::Mesh& sMesh);
// -------------------------------------------------------------------
/** Add a node to the node graph
@@ -235,7 +230,7 @@ protected:
// -------------------------------------------------------------------
/** Clamp all indices in the file to a valid range
*/
void CheckIndices(Dot3DS::Mesh* sMesh);
void CheckIndices(Dot3DS::Mesh& sMesh);
protected:
+2 -73
View File
@@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// internal headers
#include "ASELoader.h"
#include "3DSSpatialSort.h"
#include "MaterialSystem.h"
#include "StringComparison.h"
#include "TextureTransform.h"
@@ -142,6 +141,7 @@ void ASEImporter::InternReadFile(
if ((*i).bSkip)continue;
this->TransformVertices(*i);
// now we need to create proper meshes from the import we need to
// split them by materials, build valid vertex/face lists ...
this->BuildUniqueRepresentation(*i);
@@ -1135,9 +1135,7 @@ void ASEImporter::BuildMaterialIndices()
}
// prepare for the next step
for (unsigned int hans = 0; hans < this->mParser->m_vMaterials.size();++hans)
{
TextureTransform::ApplyScaleNOffset(this->mParser->m_vMaterials[hans]);
}
// now we need to iterate through all meshes,
// generating correct texture coordinates and material uv indices
@@ -1182,75 +1180,6 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh)
}
}
if (mesh.mNormals.empty())
{
// need to calculate normals ...
// TODO: Find a way to merge this with the code in 3DSGenNormals.cpp
mesh.mNormals.resize(mesh.mPositions.size(),aiVector3D());
for( unsigned int a = 0; a < mesh.mFaces.size(); a++)
{
const ASE::Face& face = mesh.mFaces[a];
// assume it is a triangle
aiVector3D* pV1 = &mesh.mPositions[face.mIndices[2]];
aiVector3D* pV2 = &mesh.mPositions[face.mIndices[1]];
aiVector3D* pV3 = &mesh.mPositions[face.mIndices[0]];
aiVector3D pDelta1 = *pV2 - *pV1;
aiVector3D pDelta2 = *pV3 - *pV1;
aiVector3D vNor = pDelta1 ^ pDelta2;
for (unsigned int i = 0; i < 3;++i)
mesh.mNormals[face.mIndices[i]] = vNor;
}
// calculate the position bounds so we have a reliable epsilon to
// check position differences against
// @Schrompf: This is the 7th time this snippet is repeated!
aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
for( unsigned int a = 0; a < mesh.mPositions.size(); a++)
{
minVec.x = std::min( minVec.x, mesh.mPositions[a].x);
minVec.y = std::min( minVec.y, mesh.mPositions[a].y);
minVec.z = std::min( minVec.z, mesh.mPositions[a].z);
maxVec.x = std::max( maxVec.x, mesh.mPositions[a].x);
maxVec.y = std::max( maxVec.y, mesh.mPositions[a].y);
maxVec.z = std::max( maxVec.z, mesh.mPositions[a].z);
}
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
std::vector<aiVector3D> avNormals;
avNormals.resize(mesh.mNormals.size());
// now generate the spatial sort tree
D3DSSpatialSorter sSort;
for( std::vector<ASE::Face>::iterator
i = mesh.mFaces.begin();
i != mesh.mFaces.end();++i){sSort.AddFace(&(*i),mesh.mPositions);}
sSort.Prepare();
for( std::vector<ASE::Face>::iterator
i = mesh.mFaces.begin();
i != mesh.mFaces.end();++i)
{
std::vector<unsigned int> poResult;
for (unsigned int c = 0; c < 3;++c)
{
sSort.FindPositions(mesh.mPositions[(*i).mIndices[c]],(*i).iSmoothGroup,
posEpsilon,poResult);
aiVector3D vNormals;
for (std::vector<unsigned int>::const_iterator
a = poResult.begin();
a != poResult.end();++a)
{
vNormals += mesh.mNormals[(*a)];
}
vNormals.Normalize();
avNormals[(*i).mIndices[c]] = vNormals;
poResult.clear();
}
}
mesh.mNormals = avNormals;
}
ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
return;
}
+6 -57
View File
@@ -64,7 +64,7 @@ using namespace Assimp::ASE;
#define BLUBB(_message_) \
{this->LogError(_message_);return;}
// ------------------------------------------------------------------------------------------------
#define AI_ASE_HANDLE_TOP_LEVEL_SECTION(iDepth) \
else if ('{' == *this->m_szFile)iDepth++; \
else if ('}' == *this->m_szFile) \
@@ -87,6 +87,7 @@ using namespace Assimp::ASE;
} else bLastWasEndLine = false; \
++this->m_szFile;
// ------------------------------------------------------------------------------------------------
#define AI_ASE_HANDLE_SECTION(iDepth, level, msg) \
else if ('{' == *this->m_szFile)iDepth++; \
else if ('}' == *this->m_szFile) \
@@ -1723,62 +1724,29 @@ void Parser::ParseLV4MeshLongTriple(unsigned int* apOut)
ai_assert(NULL != apOut);
for (unsigned int i = 0; i < 3;++i)
{
// skip spaces and tabs
if(!SkipSpaces(this->m_szFile,&this->m_szFile))
{
// LOG
this->LogWarning("Unable to parse indexable long triple: unexpected EOL [#1]");
++this->iLineNumber;
apOut[0] = apOut[1] = apOut[2] = 0;
return;
}
apOut[i] = strtol10(this->m_szFile,&this->m_szFile);
}
ParseLV4MeshLong(apOut[i]);
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut)
{
ai_assert(NULL != apOut);
// skip spaces and tabs
if(!SkipSpaces(this->m_szFile,&this->m_szFile))
{
// LOG
this->LogWarning("Unable to parse indexed long triple: unexpected EOL [#4]");
rIndexOut = 0;
apOut[0] = apOut[1] = apOut[2] = 0;
++this->iLineNumber;
return;
}
// parse the index
rIndexOut = strtol10(this->m_szFile,&this->m_szFile);
ParseLV4MeshLong(rIndexOut);
// parse the three others
this->ParseLV4MeshLongTriple(apOut);
return;
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut)
{
ai_assert(NULL != apOut);
// skip spaces and tabs
if(!SkipSpaces(this->m_szFile,&this->m_szFile))
{
// LOG
this->LogWarning("Unable to parse indexed float triple: unexpected EOL [#1]");
rIndexOut = 0;
apOut[0] = apOut[1] = apOut[2] = 0.0f;
++this->iLineNumber;
return;
}
// parse the index
rIndexOut = strtol10(this->m_szFile,&this->m_szFile);
ParseLV4MeshLong(rIndexOut);
// parse the three others
this->ParseLV4MeshFloatTriple(apOut);
return;
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloatTriple(float* apOut)
@@ -1786,20 +1754,7 @@ void Parser::ParseLV4MeshFloatTriple(float* apOut)
ai_assert(NULL != apOut);
for (unsigned int i = 0; i < 3;++i)
{
// skip spaces and tabs
if(!SkipSpaces(this->m_szFile,&this->m_szFile))
{
// LOG
this->LogWarning("Unable to parse float triple: unexpected EOL [#5]");
apOut[0] = apOut[1] = apOut[2] = 0.0f;
++this->iLineNumber;
return;
}
// parse the float
this->m_szFile = fast_atof_move(this->m_szFile,apOut[i]);
}
return;
ParseLV4MeshFloat(apOut[i]);
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloat(float& fOut)
@@ -1815,9 +1770,6 @@ void Parser::ParseLV4MeshFloat(float& fOut)
}
// parse the first float
this->m_szFile = fast_atof_move(this->m_szFile,fOut);
// go to the next valid sequence
//this->SkipToNextToken();
return;
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshLong(unsigned int& iOut)
@@ -1833,7 +1785,4 @@ void Parser::ParseLV4MeshLong(unsigned int& iOut)
}
// parse the value
iOut = strtol10(this->m_szFile,&this->m_szFile);
// go to the next valid sequence
//this->SkipToNextToken();
return;
}
+4 -13
View File
@@ -54,7 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/aiAnim.h"
// for some helper routines like IsSpace()
#include "PlyParser.h"
#include "ParsingUtils.h"
#include "qnan.h"
// ASE is quite similar to 3ds. We can reuse some structures
@@ -87,7 +87,7 @@ struct Material : public Dot3DS::Material
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file face */
struct Face : public Dot3DS::Face
struct Face : public FaceWithSmoothingGroup
{
//! Default constructor. Initializes everything with 0
Face()
@@ -224,13 +224,13 @@ struct DecompTransform
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file mesh */
struct Mesh
struct Mesh : public MeshWithSmoothingGroups<ASE::Face>
{
//! Constructor. Creates a default name for the mesh
Mesh() : bSkip(false)
{
static int iCnt = 0;
char szTemp[128];
char szTemp[128]; // should be sufficiently large
::sprintf(szTemp,"UNNAMED_%i",iCnt++);
mName = szTemp;
@@ -249,21 +249,12 @@ struct Mesh
//! "" if there is no parent ...
std::string mParent;
//! vertex positions
std::vector<aiVector3D> mPositions;
//! List of all faces loaded
std::vector<ASE::Face> mFaces;
//! List of all texture coordinate sets
std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
//! List of all vertex color sets.
std::vector<aiColor4D> mVertexColors;
//! List of normal vectors
std::vector<aiVector3D> mNormals;
//! List of all bone vertices
std::vector<BoneVertex> mBoneVertices;
+167 -6
View File
@@ -40,14 +40,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @file Implementation of the Plain-C API */
// CRT headers
#include <map>
// public ASSIMP headers
#include "../include/assimp.h"
#include "../include/aiFileIO.h"
#include "../include/assimp.hpp"
#include "../include/DefaultLogger.h"
#include "../include/aiAssert.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "GenericProperty.h"
// boost headers
#define AI_C_THREADSAFE
@@ -67,19 +70,158 @@ static ImporterMap gActiveImports;
/** Error message of the last failed import process */
static std::string gLastErrorString;
/** Configuration properties */
static Importer::IntPropertyMap gIntProperties;
static Importer::FloatPropertyMap gFloatProperties;
static Importer::StringPropertyMap gStringProperties;
#if (defined AI_C_THREADSAFE)
/** Global mutex to manage the access to the importer map */
static boost::mutex gMutex;
#endif
class CIOSystemWrapper;
class CIOStreamWrapper;
// ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API
class CIOStreamWrapper : public IOStream
{
friend class CIOSystemWrapper;
public:
CIOStreamWrapper(aiFile* pFile)
: mFile(pFile)
{}
// -------------------------------------------------------------------
size_t Read(void* pvBuffer,
size_t pSize,
size_t pCount)
{
// need to typecast here as C has no void*
return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
}
// -------------------------------------------------------------------
size_t Write(const void* pvBuffer,
size_t pSize,
size_t pCount)
{
// need to typecast here as C has no void*
return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
}
// -------------------------------------------------------------------
aiReturn Seek(size_t pOffset,
aiOrigin pOrigin)
{
return mFile->SeekProc(mFile,pOffset,pOrigin);
}
// -------------------------------------------------------------------
size_t Tell(void) const
{
return mFile->TellProc(mFile);
}
// -------------------------------------------------------------------
size_t FileSize() const
{
return mFile->FileSizeProc(mFile);
}
private:
aiFile* mFile;
};
// ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API
class CIOSystemWrapper : public IOSystem
{
public:
CIOSystemWrapper(aiFileIO* pFile)
: mFileSystem(pFile)
{}
// -------------------------------------------------------------------
bool Exists( const std::string& pFile) const
{
CIOSystemWrapper* pip = const_cast<CIOSystemWrapper*>(this);
IOStream* p = pip->Open(pFile);
if (p){pip->Close(p);return true;}
return false;
}
// -------------------------------------------------------------------
std::string getOsSeparator() const
{
return "/";
}
// -------------------------------------------------------------------
IOStream* Open(const std::string& pFile,
const std::string& pMode = std::string("rb"))
{
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile.c_str(),pMode.c_str());
if (!p)return NULL;
return new CIOStreamWrapper(p);
}
// -------------------------------------------------------------------
void Close( IOStream* pFile)
{
if (!pFile)return;
mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
delete pFile;
}
private:
aiFileIO* mFileSystem;
};
// ------------------------------------------------------------------------------------------------
void ReportSceneNotFoundError()
{
DefaultLogger::get()->error("Unable to find the Importer instance for this scene. "
"Are you sure it has been created by aiImportFile(ex)(...)?");
}
// ------------------------------------------------------------------------------------------------
// Reads the given file and returns its content.
const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
{
return aiImportFileEx(pFile,pFlags,NULL);
}
// ------------------------------------------------------------------------------------------------
const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,
aiFileIO* pFS)
{
ai_assert(NULL != pFile);
// create an Importer for this file
Assimp::Importer* imp = new Assimp::Importer;
// copy the global property lists to the Importer instance
// (we are a friend of Importer)
imp->mIntProperties = gIntProperties;
imp->mFloatProperties = gFloatProperties;
imp->mStringProperties = gStringProperties;
// setup a custom IO system if necessary
if (pFS)
{
imp->SetIOHandler( new CIOSystemWrapper (pFS) );
}
// and have it read the file
const aiScene* scene = imp->ReadFile( pFile, pFlags);
@@ -118,8 +260,7 @@ void aiReleaseImport( const aiScene* pScene)
// it should be there... else the user is playing fools with us
if( it == gActiveImports.end())
{
DefaultLogger::get()->error("Unable to find the Importer instance for this scene. "
"Are you sure it has been created by aiImportFile(ex)(...)?");
ReportSceneNotFoundError();
return;
}
@@ -196,11 +337,31 @@ void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
// it should be there... else the user is playing fools with us
if( it == gActiveImports.end())
{
DefaultLogger::get()->error("Unable to find the Importer instance for this scene. "
"Are you sure it has been created by aiImportFile(ex)(...)?");
ReportSceneNotFoundError();
return;
}
// get memory statistics
it->second->GetMemoryRequirements(*in);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiSetImportPropertyInteger(const char* szName, int value)
{
SetGenericProperty<int>(gIntProperties,szName,value,NULL);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiSetImportPropertyFloat(const char* szName, float value)
{
SetGenericProperty<float>(gFloatProperties,szName,value,NULL);
}
// ------------------------------------------------------------------------------------------------
ASSIMP_API void aiSetImportPropertyString(const char* szName,
const C_STRUCT aiString* st)
{
if (!st)return;
SetGenericProperty<std::string>(gStringProperties,szName,
std::string( st->data ),NULL);
}
+1 -1
View File
@@ -86,7 +86,7 @@ bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
void CalcTangentsProcess::SetupProperties(const Importer* pImp)
{
// get the current value of the property
this->configMaxAngle = pImp->GetProperty(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45000) / 1000.0f;
this->configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
this->configMaxAngle = std::max(std::min(this->configMaxAngle,180.0f),0.0f);
this->configMaxAngle = AI_DEG_TO_RAD(this->configMaxAngle);
}
+100
View File
@@ -0,0 +1,100 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (ASSIMP)
---------------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Implementation of the DXF importer class */
#include "DXFLoader.h"
// public ASSIMP headers
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/DefaultLogger.h"
// boost headers
#include <boost/scoped_ptr.hpp>
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
DXFImporter::DXFImporter()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
DXFImporter::~DXFImporter()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool DXFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
{
// simple check of file extension is enough for the moment
std::string::size_type pos = pFile.find_last_of('.');
// no file extension - can't read
if( pos == std::string::npos)
return false;
std::string extension = pFile.substr( pos);
return !(extension.length() != 4 || extension[0] != '.' ||
extension[1] != 'd' && extension[1] != 'D' ||
extension[2] != 'x' && extension[2] != 'X' ||
extension[3] != 'f' && extension[3] != 'F');
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void DXFImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler)
{
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
// Check whether we can read from the file
if( file.get() == NULL)
throw new ImportErrorException( "Failed to open DXF file " + pFile + "");
throw new ImportErrorException("DXF: not yet implemented");
}
+93
View File
@@ -0,0 +1,93 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file Declaration of the .dxf importer class. */
#ifndef AI_DXFLOADER_H_INCLUDED
#define AI_DXFLOADER_H_INCLUDED
#include "BaseImporter.h"
#include "../include/aiTypes.h"
namespace Assimp {
// ---------------------------------------------------------------------------
/** DXF importer class
*/
class DXFImporter : public BaseImporter
{
friend class Importer;
protected:
/** Constructor to be privately used by Importer */
DXFImporter();
/** Destructor, private as well */
~DXFImporter();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const;
protected:
// -------------------------------------------------------------------
/** Called by Importer::GetExtensionList() for each loaded importer.
* See BaseImporter::GetExtensionList() for details
*/
void GetExtensionList(std::string& append)
{
append.append("*.dxf");
}
// -------------------------------------------------------------------
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
};
} // end of namespace Assimp
#endif // AI_3DSIMPORTER_H_INC
+2 -3
View File
@@ -76,7 +76,7 @@ bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const
void GenVertexNormalsProcess::SetupProperties(const Importer* pImp)
{
// get the current value of the property
this->configMaxAngle = pImp->GetProperty(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,180000) / 1000.0f;
this->configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,180.f);
this->configMaxAngle = std::max(std::min(this->configMaxAngle,180.0f),0.0f);
this->configMaxAngle = AI_DEG_TO_RAD(this->configMaxAngle);
}
@@ -145,8 +145,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
std::vector<unsigned int> verticesFound;
const float fLimit = (AI_MESH_SMOOTHING_ANGLE_NOT_SET == pMesh->mMaxSmoothingAngle
? this->configMaxAngle : pMesh->mMaxSmoothingAngle);
const float fLimit = this->configMaxAngle;
aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
+88
View File
@@ -0,0 +1,88 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef AI_GENERIC_PROPERTY_H_INCLUDED
#define AI_GENERIC_PROPERTY_H_INCLUDED
#include "./../include/assimp.hpp"
#include "Hash.h"
// ------------------------------------------------------------------------------------------------
template <class T>
inline void SetGenericProperty(std::map< uint32_t, T >& list,
const char* szName, const T& value, bool* bWasExisting)
{
ai_assert(NULL != szName);
typedef std::map< uint32_t, T > GenericPropertyMap;
typedef std::pair< uint32_t, T > GenericPair;
uint32_t hash = SuperFastHash(szName);
GenericPropertyMap::iterator it = list.find(hash);
if (it == list.end())
{
if (bWasExisting)*bWasExisting = false;
list.insert(GenericPair( hash, value ));
return;
}
(*it).second = value;
if (bWasExisting)*bWasExisting = true;
}
// ------------------------------------------------------------------------------------------------
template <class T>
inline T GetGenericProperty(const std::map< uint32_t, T >& list,
const char* szName, const T& errorReturn)
{
ai_assert(NULL != szName);
typedef std::map< uint32_t, T > GenericPropertyMap;
typedef std::pair< uint32_t, T > GenericPair;
uint32_t hash = SuperFastHash(szName);
GenericPropertyMap::const_iterator it = list.find(hash);
if (it == list.end())return errorReturn;
return (*it).second;
}
#endif // !! AI_GENERIC_PROPERTY_H_INCLUDED
+42 -2
View File
@@ -1,3 +1,42 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef AI_HASH_H_INCLUDED
#define AI_HASH_H_INCLUDED
@@ -19,11 +58,12 @@
#endif
// ------------------------------------------------------------------------------------------------
inline uint32_t SuperFastHash (const char * data, int len, uint32_t hash = 0) {
inline uint32_t SuperFastHash (const char * data, unsigned int len = 0, uint32_t hash = 0) {
uint32_t tmp;
int rem;
if (len <= 0 || data == NULL) return 0;
if (!data) return 0;
if (!len)len = (unsigned int)::strlen(data);
rem = len & 3;
len >>= 2;
+64 -39
View File
@@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BaseProcess.h"
#include "DefaultIOStream.h"
#include "DefaultIOSystem.h"
#include "GenericProperty.h"
// Importers
#if (!defined AI_BUILD_NO_X_IMPORTER)
@@ -151,6 +152,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
# include "RemoveRedundantMaterials.h"
#endif
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
# include "OptimizeGraphProcess.h"
#endif
using namespace Assimp;
@@ -168,6 +172,9 @@ Importer::Importer() :
bExtraVerbose = false; // disable extra verbose mode by default
// add an instance of each worker class here
// the order doesn't really care, however file formats that are
// used more frequently than others should be at the beginning.
#if (!defined AI_BUILD_NO_X_IMPORTER)
mImporter.push_back( new XFileImporter());
#endif
@@ -217,13 +224,18 @@ Importer::Importer() :
#endif
// add an instance of each post processing step here in the order
// of sequence it is executed
// of sequence it is executed. steps that are added here are not validated -
// as RegisterPPStep() does - all dependencies must be there.
#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS)
mPostProcessingSteps.push_back( new ValidateDSProcess()); // must be first
#endif
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
#endif
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
mPostProcessingSteps.push_back( new OptimizeGraphProcess());
#endif
#if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
mPostProcessingSteps.push_back( new TriangulateProcess());
#endif
@@ -379,8 +391,16 @@ bool ValidateFlags(unsigned int pFlags)
if (pFlags & aiProcess_GenSmoothNormals &&
pFlags & aiProcess_GenNormals)
{
DefaultLogger::get()->error("aiProcess_GenSmoothNormals and aiProcess_GenNormals "
"may not be specified together");
DefaultLogger::get()->error("aiProcess_GenSmoothNormals and "
"aiProcess_GenNormals may not be specified together");
return false;
}
if (pFlags & aiProcess_PreTransformVertices &&
pFlags & aiProcess_OptimizeGraph)
{
DefaultLogger::get()->error("aiProcess_PreTransformVertives and "
"aiProcess_OptimizeGraph may not be specified together");
return false;
}
@@ -488,15 +508,21 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
// ------------------------------------------------------------------------------------------------
// Helper function to check whether an extension is supported by ASSIMP
bool Importer::IsExtensionSupported(const std::string& szExtension)
{
return NULL != FindLoader(szExtension);
}
// ------------------------------------------------------------------------------------------------
BaseImporter* Importer::FindLoader (const std::string& szExtension)
{
for (std::vector<BaseImporter*>::const_iterator
i = this->mImporter.begin();
i != this->mImporter.end();++i)
{
// pass the file extension to the CanRead(..,NULL)-method
if ((*i)->CanRead(szExtension,NULL))return true;
if ((*i)->CanRead(szExtension,NULL))return *i;
}
return false;
return NULL;
}
// ------------------------------------------------------------------------------------------------
@@ -519,49 +545,48 @@ void Importer::GetExtensionList(std::string& szOut)
// ------------------------------------------------------------------------------------------------
// Set a configuration property
int Importer::SetProperty(const char* szName, int iValue)
void Importer::SetPropertyInteger(const char* szName, int iValue,
bool* bWasExisting /*= NULL*/)
{
ai_assert(NULL != szName);
SetGenericProperty<int>(mIntProperties, szName,iValue,bWasExisting);
}
// search in the list ...
for (std::vector<IntPropertyInfo>::iterator
i = this->mIntProperties.begin();
i != this->mIntProperties.end();++i)
{
if (0 == ::strcmp( (*i).name.c_str(), szName ))
{
int iOld = (*i).value;
(*i).value = iValue;
return iOld;
}
}
// the property is not yet in the list ...
this->mIntProperties.push_back( IntPropertyInfo() );
IntPropertyInfo& me = this->mIntProperties.back();
me.name = std::string(szName);
me.value = iValue;
return AI_PROPERTY_WAS_NOT_EXISTING;
// ------------------------------------------------------------------------------------------------
void Importer::SetPropertyFloat(const char* szName, float iValue,
bool* bWasExisting /*= NULL*/)
{
SetGenericProperty<float>(mFloatProperties, szName,iValue,bWasExisting);
}
// ------------------------------------------------------------------------------------------------
void Importer::SetPropertyString(const char* szName, const std::string& value,
bool* bWasExisting /*= NULL*/)
{
SetGenericProperty<std::string>(mStringProperties, szName,value,bWasExisting);
}
// ------------------------------------------------------------------------------------------------
// Get a configuration property
int Importer::GetProperty(const char* szName,
int Importer::GetPropertyInteger(const char* szName,
int iErrorReturn /*= 0xffffffff*/) const
{
ai_assert(NULL != szName);
// search in the list ...
for (std::vector<IntPropertyInfo>::const_iterator
i = this->mIntProperties.begin();
i != this->mIntProperties.end();++i)
{
if (0 == ::strcmp( (*i).name.c_str(), szName ))
{
return (*i).value;
}
}
return iErrorReturn;
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
float Importer::GetPropertyFloat(const char* szName,
float iErrorReturn /*= 10e10*/) const
{
return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
std::string Importer::GetPropertyString(const char* szName,
const std::string& iErrorReturn /*= ""*/) const
{
return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
}
// ------------------------------------------------------------------------------------------------
void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
{
+2
View File
@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/aiTypes.h"
struct aiMesh;
class JoinVerticesTest;
namespace Assimp
{
@@ -62,6 +63,7 @@ namespace Assimp
class ASSIMP_API JoinVerticesProcess : public BaseProcess
{
friend class Importer;
friend class ::JoinVerticesTest;
protected:
/** Constructor to be privately used by Importer */
+11 -11
View File
@@ -95,8 +95,8 @@ bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
// Setup configuration properties
void LWOImporter::SetupProperties(const Importer* pImp)
{
this->configGradientResX = pImp->GetProperty(AI_CONFIG_IMPORT_LWO_GRADIENT_RESX,512);
this->configGradientResY = pImp->GetProperty(AI_CONFIG_IMPORT_LWO_GRADIENT_RESY,512);
this->configGradientResX = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWO_GRADIENT_RESX,512);
this->configGradientResY = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWO_GRADIENT_RESY,512);
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
@@ -174,10 +174,10 @@ void LWOImporter::InternReadFile( const std::string& pFile,
std::vector<aiMesh*> apcMeshes;
std::vector<aiNode*> apcNodes;
apcNodes.reserve(mLayers->size());
apcMeshes.reserve(mLayers->size()*std::min((mSurfaces->size()/2u), 1u));
apcMeshes.reserve(mLayers->size()*std::min(((unsigned int)mSurfaces->size()/2u), 1u));
// the RemoveRedundantMaterials step will clean this up later
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = mSurfaces->size()];
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat)
{
MaterialHelper* pcMat = new MaterialHelper();
@@ -192,7 +192,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
const LWO::Layer& layer = *lit;
// I don't know whether there could be dummy layers, but it would be possible
const unsigned int meshStart = apcMeshes.size();
const unsigned int meshStart = (unsigned int)apcMeshes.size();
if (!layer.mFaces.empty() && !layer.mTempPoints.empty())
{
// now sort all faces by the surfaces assigned to them
@@ -207,13 +207,13 @@ void LWOImporter::InternReadFile( const std::string& pFile,
if (idx >= mTags->size())
{
DefaultLogger::get()->warn("LWO: Invalid face surface index");
idx = mTags->size()-1;
idx = (unsigned int)mTags->size()-1;
}
if(0xffffffff == (idx = _mMapping[idx]))
{
if (0xffffffff == iDefaultSurface)
{
iDefaultSurface = mSurfaces->size();
iDefaultSurface = (unsigned int)mSurfaces->size();
mSurfaces->push_back(LWO::Surface());
LWO::Surface& surf = mSurfaces->back();
surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f;
@@ -240,7 +240,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
// generate the mesh
aiMesh* mesh = new aiMesh();
apcMeshes.push_back(mesh);
mesh->mNumFaces = sorted.size();
mesh->mNumFaces = (unsigned int)sorted.size();
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
it != end;++it)
@@ -281,7 +281,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
apcNodes.push_back(pcNode);
pcNode->mName.Set(layer.mName);
pcNode->mParent = reinterpret_cast<aiNode*>(layer.mParent);
pcNode->mNumMeshes = apcMeshes.size() - meshStart;
pcNode->mNumMeshes = (unsigned int)apcMeshes.size() - meshStart;
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
pcNode->mMeshes[p] = p + meshStart;
@@ -292,7 +292,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
// copy the meshes to the output structure
if (apcMeshes.size()) // shouldn't occur, just to be sure we don't crash
{
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = apcMeshes.size() ];
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = (unsigned int)apcMeshes.size() ];
::memcpy(pScene->mMeshes,&apcMeshes[0],pScene->mNumMeshes*sizeof(void*));
}
}
@@ -414,7 +414,7 @@ void LWOImporter::CopyFaceIndices(FaceList::iterator& it,
if (mi > mCurLayer->mTempPoints.size())
{
DefaultLogger::get()->warn("LWO: face index is out of range");
mi = mCurLayer->mTempPoints.size()-1;
mi = (unsigned int)mCurLayer->mTempPoints.size()-1;
}
}
}
+1 -1
View File
@@ -89,7 +89,7 @@ void LimitBoneWeightsProcess::Execute( aiScene* pScene)
void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp)
{
// get the current value of the property
this->mMaxWeights = pImp->GetProperty(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
}
// ------------------------------------------------------------------------------------------------
+232 -239
View File
@@ -45,14 +45,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ByteSwap.h"
#include "MD2NormalTable.h" // shouldn't be included by other units
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/aiMesh.h"
// public ASSIMP headers
#include "../include/assimp.hpp"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/DefaultLogger.h"
#include "../include/assimp.hpp"
// boost headers
#include <boost/scoped_ptr.hpp>
using namespace Assimp;
@@ -117,10 +118,10 @@ void MD2Importer::SetupProperties(const Importer* pImp)
{
// The AI_CONFIG_IMPORT_MD2_KEYFRAME option overrides the
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
AI_CONFIG_IMPORT_MD2_KEYFRAME,0xffffffff)))
{
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
}
// ------------------------------------------------------------------------------------------------
@@ -190,255 +191,247 @@ void MD2Importer::InternReadFile( const std::string& pFile,
if( fileSize < sizeof(MD2::Header))
throw new ImportErrorException( "MD2 File is too small");
try
std::vector<unsigned char> mBuffer2(fileSize);
file->Read(&mBuffer2[0], 1, fileSize);
this->mBuffer = &mBuffer2[0];
this->m_pcHeader = (const MD2::Header*)this->mBuffer;
#ifdef AI_BUILD_BIG_ENDIAN
ByteSwap::Swap4(&m_pcHeader->frameSize);
ByteSwap::Swap4(&m_pcHeader->magic);
ByteSwap::Swap4(&m_pcHeader->numFrames);
ByteSwap::Swap4(&m_pcHeader->numGlCommands);
ByteSwap::Swap4(&m_pcHeader->numSkins);
ByteSwap::Swap4(&m_pcHeader->numTexCoords);
ByteSwap::Swap4(&m_pcHeader->numTriangles);
ByteSwap::Swap4(&m_pcHeader->numVertices);
ByteSwap::Swap4(&m_pcHeader->offsetEnd);
ByteSwap::Swap4(&m_pcHeader->offsetFrames);
ByteSwap::Swap4(&m_pcHeader->offsetGlCommands);
ByteSwap::Swap4(&m_pcHeader->offsetSkins);
ByteSwap::Swap4(&m_pcHeader->offsetTexCoords);
ByteSwap::Swap4(&m_pcHeader->offsetTriangles);
ByteSwap::Swap4(&m_pcHeader->skinHeight);
ByteSwap::Swap4(&m_pcHeader->skinWidth);
ByteSwap::Swap4(&m_pcHeader->version);
#endif
this->ValidateHeader();
// there won't be more than one mesh inside the file
pScene->mNumMaterials = 1;
pScene->mRootNode = new aiNode();
pScene->mRootNode->mNumMeshes = 1;
pScene->mRootNode->mMeshes = new unsigned int[1];
pScene->mRootNode->mMeshes[0] = 0;
pScene->mMaterials = new aiMaterial*[1];
pScene->mMaterials[0] = new MaterialHelper();
pScene->mNumMeshes = 1;
pScene->mMeshes = new aiMesh*[1];
aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
// navigate to the begin of the frame data
const MD2::Frame* pcFrame = (const MD2::Frame*) ((uint8_t*)
this->m_pcHeader + this->m_pcHeader->offsetFrames);
pcFrame += this->configFrameID;
// navigate to the begin of the triangle data
MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)
this->m_pcHeader + this->m_pcHeader->offsetTriangles);
// navigate to the begin of the tex coords data
const MD2::TexCoord* pcTexCoords = (const MD2::TexCoord*) ((uint8_t*)
this->m_pcHeader + this->m_pcHeader->offsetTexCoords);
// navigate to the begin of the vertex data
const MD2::Vertex* pcVerts = (const MD2::Vertex*) (pcFrame->vertices);
#ifdef AI_BUILD_BIG_ENDIAN
for (uint32_t i = 0; i< m_pcHeader->numTriangles)
{
// allocate storage and copy the contents of the file to a memory buffer
this->mBuffer = new unsigned char[fileSize];
file->Read( (void*)mBuffer, 1, fileSize);
this->m_pcHeader = (const MD2::Header*)this->mBuffer;
#ifdef AI_BUILD_BIG_ENDIAN
ByteSwap::Swap4(&m_pcHeader->frameSize);
ByteSwap::Swap4(&m_pcHeader->magic);
ByteSwap::Swap4(&m_pcHeader->numFrames);
ByteSwap::Swap4(&m_pcHeader->numGlCommands);
ByteSwap::Swap4(&m_pcHeader->numSkins);
ByteSwap::Swap4(&m_pcHeader->numTexCoords);
ByteSwap::Swap4(&m_pcHeader->numTriangles);
ByteSwap::Swap4(&m_pcHeader->numVertices);
ByteSwap::Swap4(&m_pcHeader->offsetEnd);
ByteSwap::Swap4(&m_pcHeader->offsetFrames);
ByteSwap::Swap4(&m_pcHeader->offsetGlCommands);
ByteSwap::Swap4(&m_pcHeader->offsetSkins);
ByteSwap::Swap4(&m_pcHeader->offsetTexCoords);
ByteSwap::Swap4(&m_pcHeader->offsetTriangles);
ByteSwap::Swap4(&m_pcHeader->skinHeight);
ByteSwap::Swap4(&m_pcHeader->skinWidth);
ByteSwap::Swap4(&m_pcHeader->version);
for (unsigned int p = 0; p < 3;++p)
{
ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]);
ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]);
}
}
for (uint32_t i = 0; i < m_pcHeader->offsetTexCoords;++i)
{
ByteSwap::Swap2(& pcTexCoords[i].s);
ByteSwap::Swap2(& pcTexCoords[i].t);
}
ByteSwap::Swap4( & pcFrame->scale[0] );
ByteSwap::Swap4( & pcFrame->scale[1] );
ByteSwap::Swap4( & pcFrame->scale[2] );
ByteSwap::Swap4( & pcFrame->translate[0] );
ByteSwap::Swap4( & pcFrame->translate[1] );
ByteSwap::Swap4( & pcFrame->translate[2] );
#endif
this->ValidateHeader();
pcMesh->mNumFaces = this->m_pcHeader->numTriangles;
pcMesh->mFaces = new aiFace[this->m_pcHeader->numTriangles];
// there won't be more than one mesh inside the file
pScene->mNumMaterials = 1;
pScene->mRootNode = new aiNode();
pScene->mRootNode->mNumMeshes = 1;
pScene->mRootNode->mMeshes = new unsigned int[1];
pScene->mRootNode->mMeshes[0] = 0;
pScene->mMaterials = new aiMaterial*[1];
pScene->mMaterials[0] = new MaterialHelper();
pScene->mNumMeshes = 1;
pScene->mMeshes = new aiMesh*[1];
aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
// allocate output storage
pcMesh->mNumVertices = (unsigned int)pcMesh->mNumFaces*3;
pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
// navigate to the begin of the frame data
const MD2::Frame* pcFrame = (const MD2::Frame*) ((uint8_t*)
this->m_pcHeader + this->m_pcHeader->offsetFrames);
pcFrame += this->configFrameID;
// not sure whether there are MD2 files without texture coordinates
// NOTE: texture coordinates can be there without a texture,
// but a texture can't be there without a valid UV channel
if (this->m_pcHeader->numTexCoords && this->m_pcHeader->numSkins)
{
// navigate to the first texture associated with the mesh
const MD2::Skin* pcSkins = (const MD2::Skin*) ((unsigned char*)this->m_pcHeader +
this->m_pcHeader->offsetSkins);
// navigate to the begin of the triangle data
MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)
this->m_pcHeader + this->m_pcHeader->offsetTriangles);
const int iMode = (int)aiShadingMode_Gouraud;
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
// navigate to the begin of the tex coords data
const MD2::TexCoord* pcTexCoords = (const MD2::TexCoord*) ((uint8_t*)
this->m_pcHeader + this->m_pcHeader->offsetTexCoords);
aiColor3D clr;
clr.b = clr.g = clr.r = 1.0f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
// navigate to the begin of the vertex data
const MD2::Vertex* pcVerts = (const MD2::Vertex*) (pcFrame->vertices);
clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
#ifdef AI_BUILD_BIG_ENDIAN
for (uint32_t i = 0; i< m_pcHeader->numTriangles)
if (pcSkins->name[0])
{
for (unsigned int p = 0; p < 3;++p)
{
ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]);
ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]);
}
}
for (uint32_t i = 0; i < m_pcHeader->offsetTexCoords;++i)
{
ByteSwap::Swap2(& pcTexCoords[i].s);
ByteSwap::Swap2(& pcTexCoords[i].t);
}
ByteSwap::Swap4( & pcFrame->scale[0] );
ByteSwap::Swap4( & pcFrame->scale[1] );
ByteSwap::Swap4( & pcFrame->scale[2] );
ByteSwap::Swap4( & pcFrame->translate[0] );
ByteSwap::Swap4( & pcFrame->translate[1] );
ByteSwap::Swap4( & pcFrame->translate[2] );
#endif
aiString szString;
const size_t iLen = ::strlen(pcSkins->name);
::memcpy(szString.data,pcSkins->name,iLen);
szString.data[iLen] = '\0';
szString.length = iLen;
pcMesh->mNumFaces = this->m_pcHeader->numTriangles;
pcMesh->mFaces = new aiFace[this->m_pcHeader->numTriangles];
// allocate output storage
pcMesh->mNumVertices = (unsigned int)pcMesh->mNumFaces*3;
pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
// not sure whether there are MD2 files without texture coordinates
// NOTE: texture coordinates can be there without a texture,
// but a texture can't be there without a valid UV channel
if (this->m_pcHeader->numTexCoords && this->m_pcHeader->numSkins)
{
// navigate to the first texture associated with the mesh
const MD2::Skin* pcSkins = (const MD2::Skin*) ((unsigned char*)this->m_pcHeader +
this->m_pcHeader->offsetSkins);
const int iMode = (int)aiShadingMode_Gouraud;
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
aiColor3D clr;
clr.b = clr.g = clr.r = 1.0f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
if (pcSkins->name[0])
{
aiString szString;
const size_t iLen = ::strlen(pcSkins->name);
::memcpy(szString.data,pcSkins->name,iLen);
szString.data[iLen] = '\0';
szString.length = iLen;
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
}
else
{
DefaultLogger::get()->warn("Texture file name has zero length. It will be skipped.");
}
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
}
else
{
// apply a default material
const int iMode = (int)aiShadingMode_Gouraud;
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
aiColor3D clr;
clr.b = clr.g = clr.r = 0.6f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
aiString szName;
szName.Set(AI_DEFAULT_MATERIAL_NAME);
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
}
// now read all triangles of the first frame, apply scaling and translation
unsigned int iCurrent = 0;
float fDivisorU,fDivisorV;
if (this->m_pcHeader->numTexCoords)
{
// allocate storage for texture coordinates, too
pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
pcMesh->mNumUVComponents[0] = 2;
// check whether the skin width or height are zero (this would
// cause a division through zero)
if (!this->m_pcHeader->skinWidth)
{
DefaultLogger::get()->error("Skin width is zero but there are "
"valid absolute texture coordinates. Unable to compute "
"relative texture coordinates ranging from 0 to 1");
fDivisorU = 1.0f;
}
else fDivisorU = (float)this->m_pcHeader->skinWidth;
if (!this->m_pcHeader->skinHeight)
{
DefaultLogger::get()->error("Skin height is zero but there are "
"valid absolute texture coordinates. Unable to compute "
"relative texture coordinates ranging from 0 to 1");
fDivisorV = 1.0f;
}
else fDivisorV = (float)this->m_pcHeader->skinHeight;
}
for (unsigned int i = 0; i < (unsigned int)this->m_pcHeader->numTriangles;++i)
{
// allocate the face
pScene->mMeshes[0]->mFaces[i].mIndices = new unsigned int[3];
pScene->mMeshes[0]->mFaces[i].mNumIndices = 3;
// copy texture coordinates
// check whether they are different from the previous value at this index.
// In this case, create a full separate set of vertices/normals/texcoords
unsigned int iTemp = iCurrent;
for (unsigned int c = 0; c < 3;++c,++iCurrent)
{
// validate vertex indices
if (pcTriangles[i].vertexIndices[c] >= this->m_pcHeader->numVertices)
{
DefaultLogger::get()->error("Vertex index is outside the allowed range");
pcTriangles[i].vertexIndices[c] = this->m_pcHeader->numVertices-1;
}
// copy face indices
unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c];
// read x,y, and z component of the vertex
aiVector3D& vec = pcMesh->mVertices[iCurrent];
vec.x = (float)pcVerts[iIndex].vertex[0] * pcFrame->scale[0];
vec.x += pcFrame->translate[0];
// (flip z and y component)
// FIX: no .... invert y instead
vec.y = (float)pcVerts[iIndex].vertex[1] * pcFrame->scale[1];
vec.y += pcFrame->translate[1];
vec.y *= -1.0f;
vec.z = (float)pcVerts[iIndex].vertex[2] * pcFrame->scale[2];
vec.z += pcFrame->translate[2];
// read the normal vector from the precalculated normal table
aiVector3D& vNormal = pcMesh->mNormals[iCurrent];
LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal);
vNormal.y *= -1.0f;
if (this->m_pcHeader->numTexCoords)
{
// validate texture coordinates
if (pcTriangles[iIndex].textureIndices[c] >= this->m_pcHeader->numTexCoords)
{
DefaultLogger::get()->error("UV index is outside the allowed range");
pcTriangles[iIndex].textureIndices[c] = this->m_pcHeader->numTexCoords-1;
}
aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent];
float u,v;
// the texture coordinates are absolute values but we
// need relative values between 0 and 1
u = (float)pcTexCoords[pcTriangles[i].textureIndices[c]].s / fDivisorU;
v = (float)pcTexCoords[pcTriangles[i].textureIndices[c]].t / fDivisorV;
pcOut.x = u;
pcOut.y = 1.0f - v; // FIXME: Is this correct for MD2?
}
}
// FIX: flip the face order for use with OpenGL
pScene->mMeshes[0]->mFaces[i].mIndices[0] = iTemp+2;
pScene->mMeshes[0]->mFaces[i].mIndices[1] = iTemp+1;
pScene->mMeshes[0]->mFaces[i].mIndices[2] = iTemp+0;
DefaultLogger::get()->warn("Texture file name has zero length. It will be skipped.");
}
}
catch (ImportErrorException* ex)
else
{
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw ex;
// apply a default material
const int iMode = (int)aiShadingMode_Gouraud;
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
aiColor3D clr;
clr.b = clr.g = clr.r = 0.6f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
aiString szName;
szName.Set(AI_DEFAULT_MATERIAL_NAME);
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
}
// now read all triangles of the first frame, apply scaling and translation
unsigned int iCurrent = 0;
float fDivisorU,fDivisorV;
if (this->m_pcHeader->numTexCoords)
{
// allocate storage for texture coordinates, too
pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
pcMesh->mNumUVComponents[0] = 2;
// check whether the skin width or height are zero (this would
// cause a division through zero)
if (!this->m_pcHeader->skinWidth)
{
DefaultLogger::get()->error("Skin width is zero but there are "
"valid absolute texture coordinates. Unable to compute "
"relative texture coordinates ranging from 0 to 1");
fDivisorU = 1.0f;
}
else fDivisorU = (float)this->m_pcHeader->skinWidth;
if (!this->m_pcHeader->skinHeight)
{
DefaultLogger::get()->error("Skin height is zero but there are "
"valid absolute texture coordinates. Unable to compute "
"relative texture coordinates ranging from 0 to 1");
fDivisorV = 1.0f;
}
else fDivisorV = (float)this->m_pcHeader->skinHeight;
}
for (unsigned int i = 0; i < (unsigned int)this->m_pcHeader->numTriangles;++i)
{
// allocate the face
pScene->mMeshes[0]->mFaces[i].mIndices = new unsigned int[3];
pScene->mMeshes[0]->mFaces[i].mNumIndices = 3;
// copy texture coordinates
// check whether they are different from the previous value at this index.
// In this case, create a full separate set of vertices/normals/texcoords
unsigned int iTemp = iCurrent;
for (unsigned int c = 0; c < 3;++c,++iCurrent)
{
// validate vertex indices
if (pcTriangles[i].vertexIndices[c] >= this->m_pcHeader->numVertices)
{
DefaultLogger::get()->error("Vertex index is outside the allowed range");
pcTriangles[i].vertexIndices[c] = this->m_pcHeader->numVertices-1;
}
// copy face indices
unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c];
// read x,y, and z component of the vertex
aiVector3D& vec = pcMesh->mVertices[iCurrent];
vec.x = (float)pcVerts[iIndex].vertex[0] * pcFrame->scale[0];
vec.x += pcFrame->translate[0];
// (flip z and y component)
// FIX: no .... invert y instead
vec.y = (float)pcVerts[iIndex].vertex[1] * pcFrame->scale[1];
vec.y += pcFrame->translate[1];
vec.y *= -1.0f;
vec.z = (float)pcVerts[iIndex].vertex[2] * pcFrame->scale[2];
vec.z += pcFrame->translate[2];
// read the normal vector from the precalculated normal table
aiVector3D& vNormal = pcMesh->mNormals[iCurrent];
LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal);
vNormal.y *= -1.0f;
if (this->m_pcHeader->numTexCoords)
{
// validate texture coordinates
if (pcTriangles[iIndex].textureIndices[c] >= this->m_pcHeader->numTexCoords)
{
DefaultLogger::get()->error("UV index is outside the allowed range");
pcTriangles[iIndex].textureIndices[c] = this->m_pcHeader->numTexCoords-1;
}
aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent];
float u,v;
// the texture coordinates are absolute values but we
// need relative values between 0 and 1
u = (float)pcTexCoords[pcTriangles[i].textureIndices[c]].s / fDivisorU;
v = (float)pcTexCoords[pcTriangles[i].textureIndices[c]].t / fDivisorV;
pcOut.x = u;
pcOut.y = 1.0f - v; // FIXME: Is this correct for MD2?
}
}
// FIX: flip the face order for use with OpenGL
pScene->mMeshes[0]->mFaces[i].mIndices[0] = iTemp+2;
pScene->mMeshes[0]->mFaces[i].mIndices[1] = iTemp+1;
pScene->mMeshes[0]->mFaces[i].mIndices[2] = iTemp+0;
}
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
}
+2 -2
View File
@@ -144,10 +144,10 @@ void MD3Importer::SetupProperties(const Importer* pImp)
{
// The AI_CONFIG_IMPORT_MD3_KEYFRAME option overrides the
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
AI_CONFIG_IMPORT_MD3_KEYFRAME,0xffffffff)))
{
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
}
// ------------------------------------------------------------------------------------------------
+36 -27
View File
@@ -61,14 +61,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
// we're just doing this with static buffers whose size is known at
// compile time, so the compiler should automatically expand to
// sprintf<array_length>(...)
#if _MSC_VER >= 1400
# define sprintf sprintf_s
#endif
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
MD5Importer::MD5Importer()
@@ -122,9 +114,8 @@ void MD5Importer::InternReadFile(
// make sure we return no incomplete data
if (!bHadMD5Mesh && !bHadMD5Anim)
{
throw new ImportErrorException("Failed to read valid data from this MD5");
}
if (!bHadMD5Mesh)pScene->mFlags |= AI_SCENE_FLAGS_ANIM_SKELETON_ONLY;
}
// ------------------------------------------------------------------------------------------------
@@ -285,30 +276,48 @@ void MD5Importer::LoadMD5MeshFile ()
pScene->mRootNode->mNumChildren = 2;
pScene->mRootNode->mChildren = new aiNode*[2];
aiNode* pcNode = pScene->mRootNode->mChildren[0] = new aiNode();
pcNode->mNumMeshes = (unsigned int)meshParser.mMeshes.size();
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
pcNode->mName.Set("MD5Mesh");
pcNode->mParent = pScene->mRootNode;
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
{
pcNode->mMeshes[i] = i;
}
// now create the hierarchy of animated bones
pcNode = pScene->mRootNode->mChildren[1] = new aiNode();
aiNode* pcNode = pScene->mRootNode->mChildren[1] = new aiNode();
pcNode->mName.Set("MD5Anim");
pcNode->mParent = pScene->mRootNode;
AttachChilds(-1,pcNode,meshParser.mJoints);
pcNode = pScene->mRootNode->mChildren[0] = new aiNode();
pcNode->mName.Set("MD5Mesh");
pcNode->mParent = pScene->mRootNode;
std::vector<MD5::MeshDesc>::const_iterator end = meshParser.mMeshes.end();
// FIX: MD5 files exported from Blender can have empty meshes
for (std::vector<MD5::MeshDesc>::const_iterator
it = meshParser.mMeshes.begin(),
end = meshParser.mMeshes.end(); it != end;++it)
{
if (!(*it).mFaces.empty() && !(*it).mVertices.empty())
++pScene->mNumMaterials;
}
// generate all meshes
pScene->mNumMeshes = pScene->mNumMaterials = (unsigned int)meshParser.mMeshes.size();
pScene->mNumMeshes = pScene->mNumMaterials;
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
// storage for node mesh indices
pcNode->mNumMeshes = pScene->mNumMeshes;
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
for (unsigned int m = 0; m < pcNode->mNumMeshes;++m)
pcNode->mMeshes[m] = m;
unsigned int n = 0;
for (std::vector<MD5::MeshDesc>::iterator
it = meshParser.mMeshes.begin(),
end = meshParser.mMeshes.end(); it != end;++it)
{
aiMesh* mesh = pScene->mMeshes[i] = new aiMesh();
MD5::MeshDesc& meshSrc = meshParser.mMeshes[i];
MD5::MeshDesc& meshSrc = *it;
if (meshSrc.mFaces.empty() || meshSrc.mVertices.empty())
continue;
aiMesh* mesh = pScene->mMeshes[n] = new aiMesh();
// generate unique vertices in our internal verbose format
MakeDataUnique(meshSrc);
@@ -424,9 +433,9 @@ void MD5Importer::LoadMD5MeshFile ()
// generate a material for the mesh
MaterialHelper* mat = new MaterialHelper();
pScene->mMaterials[i] = mat;
pScene->mMaterials[n] = mat;
mat->AddProperty(&meshSrc.mShader,AI_MATKEY_TEXTURE_DIFFUSE(0));
mesh->mMaterialIndex = i;
mesh->mMaterialIndex = n++;
}
// delete the file again
+3 -3
View File
@@ -194,10 +194,10 @@ void MDCImporter::SetupProperties(const Importer* pImp)
{
// The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
AI_CONFIG_IMPORT_MDC_KEYFRAME,0xffffffff)))
{
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
}
// ------------------------------------------------------------------------------------------------
@@ -443,7 +443,7 @@ void MDCImporter::InternReadFile(
pScene->mMeshes[i]->mTextureCoords[3] = NULL;
// create materials
pScene->mNumMaterials = aszShaders.size();
pScene->mNumMaterials = (unsigned int)aszShaders.size();
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
{
+5 -5
View File
@@ -51,11 +51,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// public ASSIMP headers
#include "../include/DefaultLogger.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/aiMesh.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/assimp.hpp"
// boost headers
@@ -119,11 +118,12 @@ void MDLImporter::SetupProperties(const Importer* pImp)
{
// The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff)))
{
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
this->configPalette = pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP,"colormap.lmp");
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
+7 -8
View File
@@ -55,8 +55,7 @@ struct aiNode;
#include "MDLFileData.h"
#include "HalfLifeFileData.h"
namespace Assimp
{
namespace Assimp {
class MaterialHelper;
using namespace MDL;
@@ -442,6 +441,9 @@ protected:
/** Configuration option: frame to be loaded */
unsigned int configFrameID;
/** Configuration option: palette to be used to decode palletized images*/
std::string configPalette;
/** Buffer to hold the loaded file */
unsigned char* mBuffer;
@@ -449,16 +451,13 @@ protected:
* (MDL7 doesn't need this, the format has a separate loader) */
unsigned int iGSFileVersion;
/** Output I/O handler. used to load external lmp files
*/
/** Output I/O handler. used to load external lmp files */
IOSystem* pIOHandler;
/** Output scene to be filled
*/
/** Output scene to be filled */
aiScene* pScene;
/** Size of the input file in bytes
*/
/** Size of the input file in bytes */
unsigned int iFileSize;
};
+1 -1
View File
@@ -61,7 +61,7 @@ using namespace Assimp;
void MDLImporter::SearchPalette(const unsigned char** pszColorMap)
{
// now try to find the color map in the current directory
IOStream* pcStream = this->pIOHandler->Open("colormap.lmp","rb");
IOStream* pcStream = this->pIOHandler->Open(configPalette,"rb");
const unsigned char* szColorMap = (const unsigned char*)::g_aclrDefaultColorMap;
if(pcStream)
+3 -3
View File
@@ -268,7 +268,7 @@ uint32_t MaterialHelper::ComputeHash()
// NOTE: We need to exclude the material name from the hash
if ((prop = this->mProperties[i]) && 0 != ::strcmp(prop->mKey.data,AI_MATKEY_NAME))
{
hash = SuperFastHash(prop->mKey.data,prop->mKey.length,hash);
hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash);
hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
}
}
@@ -371,8 +371,8 @@ aiReturn MaterialHelper::AddProperty (const aiString* pInput,
const char* pKey)
{
// fix ... don't keep the whole string buffer
return this->AddBinaryProperty(pInput,
pInput->length+1+ (size_t)((uint8_t*)&pInput->data - (uint8_t*)&pInput->length),
return this->AddBinaryProperty(pInput,(unsigned int)pInput->length+1+
(unsigned int)(((uint8_t*)&pInput->data - (uint8_t*)&pInput->length)),
pKey,aiPTI_String);
}
// ------------------------------------------------------------------------------------------------
+5 -5
View File
@@ -41,13 +41,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ObjFileImporter.h"
#include "ObjFileParser.h"
#include "ObjFileData.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/aiMesh.h"
#include "MaterialSystem.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/DefaultLogger.h"
#include "MaterialSystem.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include <boost/scoped_ptr.hpp>
#include <boost/format.hpp>
@@ -237,7 +237,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
if ( meshSizeDiff > 0 )
{
pNode->mMeshes = new unsigned int[ meshSizeDiff ];
pNode->mNumMeshes = meshSizeDiff;
pNode->mNumMeshes = (unsigned int)meshSizeDiff;
size_t index = 0;
for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
{
+3 -3
View File
@@ -306,8 +306,8 @@ void ObjFileParser::getFace()
// Store the face
m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
m_pModel->m_pCurrentMesh->m_uiNumIndices += face->m_pVertices->size();
m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += face->m_pTexturCoords[0].size();
m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size();
// Skip the rest of the line
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
@@ -462,7 +462,7 @@ int ObjFileParser::getMaterialIndex( const std::string &strMaterialName )
{
if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
{
mat_index = index;
mat_index = (int)index;
break;
}
}
+909
View File
@@ -0,0 +1,909 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** Implementation of the OptimizeGraphProcess post-processing step*/
#include <vector>
#include <list>
#include "OptimizeGraphProcess.h"
#include "Hash.h"
#include "../include/aiPostProcess.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/assimp.hpp"
#include "../include/DefaultLogger.h"
using namespace Assimp;
// MSB for type unsigned int
#define AI_OG_UINT_MSB (1u<<((sizeof(unsigned int)*8u)-1u))
#define AI_OG_UINT_MSB_2 (AI_OG_UINT_MSB>>1)
// check whether a node/a mesh is locked
#define AI_OG_IS_NODE_LOCKED(nd) (nd->mNumChildren & AI_OG_UINT_MSB)
#define AI_OG_IS_MESH_LOCKED(ms) (ms->mNumBones & AI_OG_UINT_MSB)
// check whether a node has locked meshes in its list
#define AI_OG_HAS_NODE_LOCKED_MESHES(nd) (nd->mNumChildren & AI_OG_UINT_MSB_2)
// unmask the two upper bits of an unsigned int
#define AI_OG_UNMASK(p) (p & (~(AI_OG_UINT_MSB|AI_OG_UINT_MSB_2)))
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
OptimizeGraphProcess::OptimizeGraphProcess()
{
configRemoveAnimations = AI_OG_REMOVE_ANIMATIONS;
configMinNumFaces = AI_OG_MIN_NUM_FACES;
configJoinInequalTransforms = AI_OG_JOIN_INEQUAL_TRANSFORMS;
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
OptimizeGraphProcess::~OptimizeGraphProcess()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const
{
return (pFlags & aiProcess_OptimizeGraph) != 0;
}
// ------------------------------------------------------------------------------------------------
// Setup properties of the step
void OptimizeGraphProcess::SetupProperties(const Importer* pImp)
{
// remove animation nodes?
configRemoveAnimations = pImp->GetPropertyInteger(AI_CONFIG_PP_OG_REMOVE_ANIMATIONS,
AI_OG_REMOVE_ANIMATIONS) != 0 ? true : false;
// join nods with inequal transformations?
configRemoveAnimations = pImp->GetPropertyInteger(AI_CONFIG_PP_OG_JOIN_INEQUAL_TRANSFORMS,
AI_OG_JOIN_INEQUAL_TRANSFORMS) != 0 ? true : false;
// minimum face number per node
configMinNumFaces = pImp->GetPropertyInteger(AI_CONFIG_PP_OG_MIN_NUM_FACES,
AI_OG_MIN_NUM_FACES);
}
// ------------------------------------------------------------------------------------------------
aiNode* OptimizeGraphProcess::RemoveAnimationNodes (aiNode* node)
{
ai_assert(NULL != node);
std::vector<aiNode*> out;
RemoveAnimationNodes(node,out);
if (out.empty())
throw new ImportErrorException("OptimizeGraphProcess: no nodes are remaining.");
if (1 == out.size())
return out[0];
aiNode* p = new aiNode();
p->mName.Set("<dummy_root>");
p->mNumChildren = (unsigned int)out.size();
p->mChildren = new aiNode*[p->mNumChildren];
::memcpy(p->mChildren,&out[0],p->mNumChildren*sizeof(void*));
return p;
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::RemoveAnimationNodes (aiNode* node,std::vector<aiNode*>& out)
{
ai_assert(NULL != node);
// if this is an animation node: shift all children on this layer
if (!node->mNumMeshes)
{
unsigned int old = (unsigned int)out.size();
for (unsigned int i = 0; i < node->mNumChildren;++i)
{
RemoveAnimationNodes(node->mChildren[i],out);
}
// update the transformations of all shifted childs
std::vector<aiNode*>::iterator it2 = out.end(),it = out.begin()+old;
for (; it != it2; ++it)
(*it)->mTransformation = node->mTransformation * (*it)->mTransformation;
delete[] node->mChildren;node->mChildren = NULL;
delete node;
}
else
{
// *this* node remains on this layer, and the children, too
out.push_back(node);
std::vector<aiNode*> outNew;
for (unsigned int i = 0; i < node->mNumChildren;++i)
{
RemoveAnimationNodes(node->mChildren[i],outNew);
}
if (outNew.size() > node->mNumChildren)
{
delete[] node->mChildren;
node->mChildren = new aiNode*[outNew.size()];
}
node->mNumChildren = (unsigned int)outNew.size();
::memcpy(node->mChildren,&outNew[0],node->mNumChildren*sizeof(void*));
}
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::FindLockedNodes(aiNode* node)
{
ai_assert(NULL != node);
for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
{
aiAnimation* pani = pScene->mAnimations[i];
for (unsigned int a = 0; a < pani->mNumBones;++a)
{
aiBoneAnim* pba = pani->mBones[a];
if (pba->mBoneName == node->mName)
{
// this node is locked
node->mNumChildren |= AI_OG_UINT_MSB;
}
}
}
// call all children
for (unsigned int i = 0; i < node->mNumChildren;++i)
FindLockedNodes(node->mChildren[i]);
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::FindLockedMeshes(aiNode* node, MeshRefCount* pRefCount)
{
ai_assert(NULL != node && NULL != pRefCount);
for (unsigned int i = 0;i < node->mNumMeshes;++i)
{
unsigned int m = node->mMeshes[i];
if (pRefCount[m].first)
{
// we have already one reference - lock the first node
// that had a referenced to this mesh too if it has only
// one mesh assigned. If there are multiple meshes,
// the others could still be used for optimizations.
if (pRefCount[m].second)
{
pRefCount[m].second->mNumChildren |= (pRefCount[m].second->mNumMeshes <= 1
? AI_OG_UINT_MSB : AI_OG_UINT_MSB_2);
pRefCount[m].second = NULL;
}
pScene->mMeshes[m]->mNumBones |= AI_OG_UINT_MSB;
// lock this node
node->mNumChildren |= (node->mNumMeshes <= 1
? AI_OG_UINT_MSB : AI_OG_UINT_MSB_2);
}
else pRefCount[m].second = node;
++pRefCount[m].first;
}
// call all children
for (unsigned int i = 0; i < node->mNumChildren;++i)
FindLockedMeshes(node->mChildren[i],pRefCount);
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::FindLockedMeshes(aiNode* node)
{
ai_assert(NULL != node);
MeshRefCount* pRefCount = new MeshRefCount[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
pRefCount[i] = MeshRefCount();
// execute the algorithm
FindLockedMeshes(node,pRefCount);
delete[] pRefCount;
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::UnlockNodes(aiNode* node)
{
ai_assert(NULL != node);
node->mNumChildren &= ~(AI_OG_UINT_MSB|AI_OG_UINT_MSB_2);
// call all children
for (unsigned int i = 0; i < node->mNumChildren;++i)
UnlockNodes(node->mChildren[i]);
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::UnlockMeshes()
{
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
pScene->mMeshes[i]->mNumBones &= ~AI_OG_UINT_MSB;
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::ComputeMeshHashes()
{
mMeshHashes.resize(pScene->mNumMeshes);
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
unsigned int iRet = 0;
aiMesh* pcMesh = pScene->mMeshes[i];
// normals
if (pcMesh->HasNormals())iRet |= 0x1;
// tangents and bitangents
if (pcMesh->HasTangentsAndBitangents())iRet |= 0x2;
// texture coordinates
unsigned int p = 0;
ai_assert(4 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
while (pcMesh->HasTextureCoords(p))
{
iRet |= (0x100 << p++);
// NOTE: meshes with numUVComp != 3 && != 2 aren't handled correctly here
ai_assert(pcMesh->mNumUVComponents[p] == 3 || pcMesh->mNumUVComponents[p] == 2);
if (3 == pcMesh->mNumUVComponents[p])
iRet |= (0x1000 << p++);
}
// vertex colors
p = 0;
ai_assert(4 >= AI_MAX_NUMBER_OF_COLOR_SETS);
while (pcMesh->HasVertexColors(p))iRet |= (0x10000 << p++);
mMeshHashes[i] = iRet;
// material index -store it in the upper 1 1/2 bytes, so
// are able to encode 2^12 material indices.
iRet |= (pcMesh->mMaterialIndex << 20u);
}
}
// ------------------------------------------------------------------------------------------------
inline unsigned int OptimizeGraphProcess::BinarySearch(NodeIndexList& sortedArray,
unsigned int min, unsigned int& index, unsigned int iStart)
{
unsigned int first = iStart,last = (unsigned int)sortedArray.size()-1;
while (first <= last)
{
unsigned int mid = (first + last) / 2;
unsigned int id = sortedArray[mid].second;
if (min > id)
first = mid + 1;
else if (min <= id)
{
last = mid - 1;
if (!mid || min > sortedArray[last].second)
{
index = sortedArray[last].first;
return mid;
}
}
}
return (unsigned int)sortedArray.size();
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::BuildUniqueBoneList(
std::vector<aiMesh*>::const_iterator it,
std::vector<aiMesh*>::const_iterator end,
std::list<BoneWithHash>& asBones)
{
unsigned int iOffset = 0;
for (; it != end;++it)
{
for (unsigned int l = 0; l < (*it)->mNumBones;++l)
{
aiBone* p = (*it)->mBones[l];
uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length);
std::list<BoneWithHash>::iterator it2 = asBones.begin();
std::list<BoneWithHash>::iterator end2 = asBones.end();
for (;it2 != end2;++it2)
{
if ((*it2).first == itml)
{
(*it2).pSrcBones.push_back(BoneSrcIndex(p,iOffset));
break;
}
}
if (end2 == it2)
{
// need to begin a new bone entry
asBones.push_back(BoneWithHash());
BoneWithHash& btz = asBones.back();
// setup members
btz.first = itml;
btz.second = &p->mName;
btz.pSrcBones.push_back(BoneSrcIndex(p,iOffset));
}
}
iOffset += (*it)->mNumVertices;
}
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::JoinBones(
std::vector<aiMesh*>::const_iterator it,
std::vector<aiMesh*>::const_iterator end,
aiMesh* out)
{
ai_assert(NULL != out);
// find we need to build an unique list of all bones.
// we work with hashes to make the comparisons MUCH faster,
// at least if we have many bones.
std::list<BoneWithHash> asBones;
BuildUniqueBoneList(it,end,asBones);
// now create the output bones
out->mBones = new aiBone*[asBones.size()];
for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),
end = asBones.end(); it != end;++it)
{
aiBone* pc = out->mBones[out->mNumBones++] = new aiBone();
pc->mName = aiString( *((*it).second ));
// get an itrator to the end of the list
std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end();
// loop through all bones to be joined for this bone
for (std::vector< BoneSrcIndex >::const_iterator
wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)
{
pc->mNumWeights += (*wmit).first->mNumWeights;
// NOTE: different offset matrices for bones with equal names
// are - at the moment - not handled correctly.
if (wmit != (*it).pSrcBones.begin() &&
pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix)
{
DefaultLogger::get()->warn("Bones with equal names but different "
"offset matrices can't be joined at the moment. If this causes "
"problems, deactivate the OptimizeGraph-Step");
continue;
}
pc->mOffsetMatrix = (*wmit).first->mOffsetMatrix;
}
// allocate the vertex weight array
aiVertexWeight* avw = pc->mWeights = new aiVertexWeight[pc->mNumWeights];
// and copy the final weights - adjust the vertex IDs by the
// face index offset of the coresponding mesh.
for (std::vector< BoneSrcIndex >::const_iterator
wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)
{
aiBone* pip = (*wmit).first;
for (unsigned int mp = 0; mp < pip->mNumWeights;++mp)
{
aiVertexWeight& vf = aiVertexWeight(pip->mWeights[mp]);
vf.mVertexId += (*wmit).second;
}
}
}
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::JoinMeshes(std::vector<aiMesh*>& meshList,
aiMesh*& out, unsigned int max)
{
ai_assert(NULL != out && 0 != max);
out->mMaterialIndex = meshList[0]->mMaterialIndex;
// allocate the output mesh
out = new aiMesh();
std::vector<aiMesh*>::const_iterator end = meshList.begin()+max;
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
{
out->mNumVertices += (*it)->mNumVertices;
out->mNumFaces += (*it)->mNumFaces;
out->mNumBones += AI_OG_UNMASK((*it)->mNumBones);
}
if (out->mNumVertices) // just for safety
{
aiVector3D* pv2;
// copy vertex positions
if (meshList[0]->HasPositions())
{
pv2 = out->mVertices = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
{
::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D));
pv2 += (*it)->mNumVertices;
}
}
// copy normals
if (meshList[0]->HasNormals())
{
pv2 = out->mNormals = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
{
::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
pv2 += (*it)->mNumVertices;
}
}
// copy tangents and bitangents
if (meshList[0]->HasTangentsAndBitangents())
{
pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
{
::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D));
::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
pv2 += (*it)->mNumVertices;
pv2b += (*it)->mNumVertices;
}
}
// copy texture coordinates
unsigned int n = 0;
while (meshList[0]->HasTextureCoords(n))
{
out->mNumUVComponents[n] = meshList[0]->mNumUVComponents[n];
pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
{
::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
pv2 += (*it)->mNumVertices;
}
++n;
}
// copy vertex colors
n = 0;
while (meshList[0]->HasVertexColors(n))
{
aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
{
::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
pv2 += (*it)->mNumVertices;
}
++n;
}
}
if (out->mNumFaces) // just for safety
{
// copy faces
out->mFaces = new aiFace[out->mNumFaces];
aiFace* pf2 = out->mFaces;
unsigned int ofs = 0;
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
{
for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2)
{
aiFace& face = (*it)->mFaces[m];
pf2->mNumIndices = face.mNumIndices;
pf2->mIndices = face.mIndices;
if (ofs)
{
// add the offset to the vertex
for (unsigned int q = 0; q < face.mNumIndices; ++q)
face.mIndices[q] += ofs;
}
ofs += (*it)->mNumVertices;
face.mIndices = NULL;
}
}
}
// bones - as this is quite lengthy, I moved the code to a separate function
if (out->mNumBones)JoinBones(meshList.begin(),end,out);
// delete all source meshes
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
delete *it;
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::ApplyNodeMeshesOptimization(aiNode* pNode)
{
ai_assert(NULL != pNode);
// find all meshes which are compatible and could therefore be joined.
// we can't join meshes that are locked
std::vector<aiMesh*> apcMeshes(pNode->mNumMeshes);
unsigned int iNumMeshes;
for (unsigned int m = 0, ttt = 0; m < pNode->mNumMeshes;++m)
{
iNumMeshes = 0;
unsigned int nm = pNode->mMeshes[m];
if (0xffffffff == nm || AI_OG_IS_MESH_LOCKED(pScene->mMeshes[nm]))continue;
for (unsigned int q = m+1; q < pNode->mNumMeshes;++q)
{
register unsigned int nq = pNode->mMeshes[q];
// skip locked meshes
if (AI_OG_IS_MESH_LOCKED(pScene->mMeshes[nq]))continue;
// compare the mesh hashes
if (mMeshHashes[nm] == mMeshHashes[nq])
{
apcMeshes[iNumMeshes++] = pScene->mMeshes[nq];
pNode->mMeshes[q] = 0xffffffff;
}
}
aiMesh* out;
if (iNumMeshes > 0)
{
apcMeshes[iNumMeshes++] = pScene->mMeshes[nm];
JoinMeshes(apcMeshes,out,iNumMeshes);
}
else out = pScene->mMeshes[nm];
pNode->mMeshes[ttt++] = (unsigned int)mOutputMeshes.size();
mOutputMeshes.push_back(out);
}
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::TransformMeshes(aiNode* quak,aiNode* pNode)
{
for (unsigned int ä = 0; ä < quak->mNumMeshes;++ä)
{
aiMesh* mariusIsHot = pScene->mMeshes[quak->mMeshes[ä]];
aiMatrix4x4 mMatTransform = pNode->mTransformation;
// transformation: first back to the parent's local space,
// later into the local space of the destination child node
mMatTransform.Inverse();
mMatTransform = quak->mTransformation * mMatTransform;
// transform all vertices
for (unsigned int oo =0; oo < mariusIsHot->mNumVertices;++oo)
mariusIsHot->mVertices[oo] = mMatTransform * mariusIsHot->mVertices[oo];
// transform all normal vectors
if (mariusIsHot->HasNormals())
{
mMatTransform.Inverse().Transpose();
for (unsigned int oo =0; oo < mariusIsHot->mNumVertices;++oo)
mariusIsHot->mNormals[oo] = mMatTransform * mariusIsHot->mNormals[oo];
}
}
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::ApplyOptimizations(aiNode* node)
{
ai_assert(NULL != node);
unsigned int iJoinedIndex = 0;
// first: node index; second: number of faces in node
NodeIndexList aiBelowTreshold;
aiBelowTreshold.reserve(node->mNumChildren);
for (unsigned int i = 0; i < node->mNumChildren;++i)
{
aiNode* pChild = node->mChildren[i];
if (AI_OG_IS_NODE_LOCKED(pChild) || !pChild->mNumMeshes)continue;
// find out how many faces this node is referencing
unsigned int iFaceCnt = 0;
for (unsigned int a = 0; a < pChild->mNumMeshes;++a)
iFaceCnt += pScene->mMeshes[pChild->mMeshes[a]]->mNumFaces;
// are we below the treshold?
if (iFaceCnt < configMinNumFaces)
{
aiBelowTreshold.push_back(NodeIndexEntry());
NodeIndexEntry& p = aiBelowTreshold.back();
p.first = i;
p.second = iFaceCnt;
p.pNode = pChild;
}
}
if (!aiBelowTreshold.empty())
{
// some typedefs for the data structures we'll need
typedef std::pair<unsigned int, unsigned int> JoinListEntry;
std::vector<JoinListEntry> aiJoinList(aiBelowTreshold.size());
std::vector<unsigned int> aiTempList(aiBelowTreshold.size());
unsigned int iNumJoins, iNumTemp;
// sort the list by size
std::sort(aiBelowTreshold.begin(),aiBelowTreshold.end());
unsigned int iStart = 0;
for (NodeIndexList::const_iterator it = aiBelowTreshold.begin(),end = aiBelowTreshold.end();
it != end; /*++it */++iStart)
{
aiNode* pNode = node->mChildren[(*it).first];
// get the hash of the mesh
const unsigned int iMeshVFormat = mMeshHashes[pNode->mMeshes[0]];
// we search for a node with more faces than this ... find
// the one that fits best and continue until we've reached
// treshold size.
int iDiff = configMinNumFaces-(*it).second;
for (;;)
{
// do a binary search and start the iteration there
unsigned int index;
unsigned int start = BinarySearch(aiBelowTreshold,iDiff,index,iStart);
if (index == (*it).first)start++;
if (start >= aiBelowTreshold.size())
{
// there is no node with enough faces. take the first
start = 0;
}
// todo: implement algorithm to find the best possible combination ...
iNumTemp = 0;
while( start < aiBelowTreshold.size())
{
// check whether the node has akready been processed before
const NodeIndexEntry& entry = aiBelowTreshold[start];
if (!entry.pNode)continue;
const aiNode* pip = node->mChildren[entry.first];
if (configJoinInequalTransforms )
{
// we need to check whether this node has locked meshes
// in this case we can't add it here - the meshes will
// be transformed from one to another coordinate space
if (!AI_OG_HAS_NODE_LOCKED_MESHES(pip) || pip->mTransformation == pNode->mTransformation)
aiTempList[iNumTemp++] = start;
}
else if (node->mChildren[entry.first]->mTransformation == pNode->mTransformation)
{
aiTempList[iNumTemp++] = start;
break;
}
++start;
}
if (iNumTemp)
{
// search for a node which has a mesh with
// - the same material index
// - the same vertex layout
unsigned int d = iNumJoins = 0;
for (unsigned int m = 0; m < iNumTemp;++m)
{
register unsigned int mn = aiTempList[m];
aiNode* pip = aiBelowTreshold[mn].pNode;
for (unsigned int tt = 0; tt < pip->mNumMeshes;++tt)
{
register unsigned int mm = pip->mMeshes[tt];
if (mMeshHashes [ mm ] == iMeshVFormat)
{
d = mn;
goto break_out;
}
}
}
break_out:
aiJoinList[iNumJoins++] = JoinListEntry( aiBelowTreshold[d].first, d );
iDiff -= aiBelowTreshold[d].second;
}
// did we reach the target treshold?
if (iDiff <= 0)break;
}
// did we found any nodes to be joined with *this* one?
if (iNumJoins)
{
unsigned int iNumTotalChilds = pNode->mNumChildren;
unsigned int iNumTotalMeshes = pNode->mNumMeshes;
std::vector<JoinListEntry>::const_iterator wend = aiJoinList.begin()+iNumJoins;
// get output array bounds
for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
wit != wend;++wit )
{
aiNode*& quak = node->mChildren[(*wit).first];
iNumTotalChilds += AI_OG_UNMASK( quak->mNumChildren );
iNumTotalMeshes += quak->mNumMeshes;
}
// build the output child list
if (iNumTotalChilds != pNode->mNumChildren)
{
aiNode** ppc = pNode->mChildren;
delete[] pNode->mChildren;
pNode->mChildren = new aiNode*[iNumTotalChilds];
::memcpy(pNode->mChildren,ppc, sizeof(void*)* AI_OG_UNMASK( pNode->mNumChildren ));
for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
wit != wend;++wit )
{
aiNode*& quak = node->mChildren[(*wit).first];
::memcpy(pNode->mChildren+pNode->mNumChildren,
quak->mChildren, sizeof(void*)*quak->mNumChildren);
pNode->mNumChildren += AI_OG_UNMASK( quak->mNumChildren );
}
}
// build the output mesh list
unsigned int* ppc = pNode->mMeshes;
delete[] pNode->mMeshes;
pNode->mMeshes = new unsigned int[iNumTotalMeshes];
::memcpy(pNode->mMeshes,ppc, sizeof(void*)*pNode->mNumMeshes);
for (std::vector<JoinListEntry>::const_iterator wit = aiJoinList.begin();
wit != wend;++wit )
{
aiNode*& quak = node->mChildren[(*wit).first];
::memcpy(pNode->mMeshes+pNode->mNumMeshes,
quak->mMeshes, sizeof(unsigned int)*quak->mNumMeshes);
// if the node has a transformation matrix that is not equal to ours,
// we'll need to transform all vertices of the mesh into our
// local coordinate space.
if (configJoinInequalTransforms && quak->mTransformation != pNode->mTransformation)
TransformMeshes(quak,pNode);
pNode->mNumMeshes += quak->mNumMeshes;
// remove the joined nodes from all lists.
aiBelowTreshold[(*wit).second].pNode = NULL;
if ((*wit).second == iStart+1)++iStart;
}
// now generate an output name for the joined nodes
if (1 == iNumTotalChilds)
{
pNode->mName.length = ::sprintf( pNode->mName.data, "<Joined_%i_%i>",
iJoinedIndex++,iNumJoins+1);
}
}
// now optimize the meshes in this node
ApplyNodeMeshesOptimization(pNode);
// note - this has been optimized away. The search in the binary
// list starts with iStart, which is incremented each iteration
++it; // = aiBelowTreshold.erase(it);
}
}
// call all children recursively
for (unsigned int i = 0; i < node->mNumChildren;++i)
ApplyOptimizations(node->mChildren[i]);
}
// ------------------------------------------------------------------------------------------------
void OptimizeGraphProcess::BuildOutputMeshList()
{
// all meshes should have been deleted before if they are
// not contained in the new mesh list
if (pScene->mNumMeshes < mOutputMeshes.size())
{
delete[] pScene->mMeshes;
pScene->mMeshes = new aiMesh*[mOutputMeshes.size()];
}
pScene->mNumMeshes = (unsigned int)mOutputMeshes.size();
::memcpy(pScene->mMeshes,&mOutputMeshes[0],pScene->mNumMeshes*sizeof(void*));
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void OptimizeGraphProcess::Execute( aiScene* pScene)
{
this->pScene = pScene;
/*
a) the term "mesh node" stands for a node with numMeshes > 0
b) the term "animation node" stands for a node with numMeshes == 0,
regardless whether the node is referenced by animation channels.
Algorithm:
1. Compute hashes for all meshes that we're able to check whether
two meshes are compatible.
2. Remove animation nodes if we have been configured to do so
3. Find out which nodes may not be moved, so to speak are "locked" - a
locked node will never be joined with neighbors.
- A node lock is indicated by a set MSB in the aiNode::mNumChildren member
4. Find out which meshes are locked - they are referenced by
more than one node. They will never be joined. Mark all
nodes referencing such a mesh as "locked", too.
- A mesh lock is indicated by a set MSB in the aiMesh::mNumBones member
5. For each unlocked node count the face numbers of all assigned meshes
- if it is below the pre-defined treshold add the node to a list.
For each node in the list - try to find enough joinable nodes to
have enough faces all together.
Two nodes are joined if:
- none of them is locked
- (optional) their world matrices are identical
- nodes whose meshes share the same material indices are prefered
Two meshes in one node are joined if:
- their material indices are identical
- none of them is locked
- they share the same vertex format
6. Build the final mesh list
7. For all meshes and all nodes - remove locks.
*/
throw new ImportErrorException("OG step is still undeer development and not yet finished");
// STEP 1
ComputeMeshHashes();
// STEP 2
if (configRemoveAnimations)
pScene->mRootNode = RemoveAnimationNodes(pScene->mRootNode);
// STEP 3
else FindLockedNodes(pScene->mRootNode);
// STEP 4
FindLockedMeshes(pScene->mRootNode);
// STEP 5
ApplyOptimizations(pScene->mRootNode);
// STEP 6
BuildOutputMeshList();
// STEP 7
UnlockNodes(pScene->mRootNode);
UnlockMeshes();
}
+340
View File
@@ -0,0 +1,340 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** Defines a post processing step to refactor the output node graph to
be more compact */
#ifndef AI_OPTIMIZEGRAPHPROCESS_H_INC
#define AI_OPTIMIZEGRAPHPROCESS_H_INC
#include "BaseProcess.h"
struct aiMesh;
struct aiNode;
struct aiBone;
class OptimizeGraphProcessTest;
namespace Assimp {
// NOTE: If you change these limits, don't forget to change the
// corresponding values in all Assimp ports
// **********************************************************
// Java: ConfigProperty.java,
// ConfigProperty.OG_MAX_HIERARCHY_DEPTH
// ConfigProperty.OG_MIN_NUM_FACES
// ConfigProperty.JOIN_INEQUAL_TRANSFORMS
// **********************************************************
#if (!defined AI_OG_MAX_DEPTH)
# define AI_OG_MAX_DEPTH 0x4
#endif // !! AI_LMW_MAX_WEIGHTS
#if (!defined AI_OG_MIN_NUM_FACES)
# define AI_OG_MIN_NUM_FACES 0xffffffff
#endif // !! AI_LMW_MAX_WEIGHTS
#if (!defined AI_OG_REMOVE_ANIMATIONS)
# define AI_OG_REMOVE_ANIMATIONS false
#endif // !! AI_LMW_MAX_WEIGHTS
#if (!defined AI_OG_JOIN_INEQUAL_TRANSFORMS)
# define AI_OG_JOIN_INEQUAL_TRANSFORMS false
#endif // !! AI_LMW_MAX_WEIGHTS
// ---------------------------------------------------------------------------
struct NodeIndexEntry : public std::pair<unsigned int, unsigned int>
{
// binary operator < for use with std::sort
bool operator< (const NodeIndexEntry& other)
{
return second < other.second;
}
// pointer to the original node
aiNode* pNode;
};
typedef std::vector<NodeIndexEntry> NodeIndexList;
typedef std::pair<aiBone*,unsigned int> BoneSrcIndex;
// ---------------------------------------------------------------------------
struct BoneWithHash : public std::pair<uint32_t,aiString*>
{
std::vector<BoneSrcIndex> pSrcBones;
};
// ---------------------------------------------------------------------------
/** This post processing step reformats the output node graph to be more
* compact. There are several options, e.g. maximum hierachy depth or
* minimum mesh size. Some files store every face as a new mesh, so
* some Assimp steps (such as FixInfacingNormals or SmoothNormals) don't
* work properly on these meshes. This step joins such small meshes and
* nodes. Animations are kept during the step.
* @note Use the PretransformVertices step to remove the node graph
* completely (and all animations, too).
*/
class ASSIMP_API OptimizeGraphProcess : public BaseProcess
{
friend class Importer;
friend class ::OptimizeGraphProcessTest;
protected:
/** Constructor to be privately used by Importer */
OptimizeGraphProcess();
/** Destructor, private as well */
~OptimizeGraphProcess();
typedef std::pair< unsigned int, aiNode* > MeshRefCount;
typedef unsigned int MeshHash;
public:
// -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag.
* @param pFlags The processing flags the importer was called with.
* A bitwise combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields,
* false if not.
*/
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
/** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
// set the configMinNumfaces property
inline void SetMinNumFaces(unsigned int n)
{
configMinNumFaces = n;
}
// set the configRemoveAnimations property
inline void SetRemoveAnimations(bool b)
{
configRemoveAnimations = b;
}
protected:
// -------------------------------------------------------------------
/** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail.
* @param pScene The imported data to work at.
*/
void Execute( aiScene* pScene);
// -------------------------------------------------------------------
/** Removes animation nodes from the tree.
* @param node Current node
* @param out Receives a list of replacement nodes for *this* node -
* if *this* node should be kept, it must be added to the list.
*/
void RemoveAnimationNodes (aiNode* node,std::vector<aiNode*>& out);
// -------------------------------------------------------------------
/** Entry point to the RemoveAnimationNodes algorithm.
* @param node Root node to start with
* @return New root node
*/
aiNode* RemoveAnimationNodes (aiNode* node);
// -------------------------------------------------------------------
/** Finds and marks all locked nodes in the tree.
* A node is locked if it is referenced by animations.
* @param node ROot node to start with
* @note A locked node has the MSB set in its mNumChildren member
*/
void FindLockedNodes(aiNode* node);
// -------------------------------------------------------------------
/** Searches for locked meshes. A mesh is locked if it is referenced
* by more than one node in the hierarchy.
* @param node Root node to start with
*/
void FindLockedMeshes(aiNode* node);
void FindLockedMeshes(aiNode* node, MeshRefCount* pRefCount);
// -------------------------------------------------------------------
/** Unlocks all nodes in the output tree.
* @param node Root node to start with
*/
void UnlockNodes(aiNode* node);
// -------------------------------------------------------------------
/** Unlocks all meshes in the output tree.
*/
void UnlockMeshes();
// -------------------------------------------------------------------
/** Apply the final optimization algorithm to the tree.
* See the Execute-method for a detailled description of the algorithm.
* @param node Root node to start with
*/
void ApplyOptimizations(aiNode* node);
// -------------------------------------------------------------------
/** Binary search for the first element that is >= min.
* @param sortedArray Input array
* @param min Treshold
*/
unsigned int BinarySearch(NodeIndexList& sortedArray,
unsigned int min, unsigned int& index, unsigned int iStart);
// -------------------------------------------------------------------
/** Compute stable hashes for all meshes and fill mMeshHashes
* with the results.
*/
void ComputeMeshHashes();
// -------------------------------------------------------------------
/** Optimizes the meshes in a single node aftr the joining process.
* @param pNode Node to be optimized. Childs noded won't be processed
* automatically.
*/
void ApplyNodeMeshesOptimization(aiNode* pNode);
// -------------------------------------------------------------------
/** Join meshes.
* The output meshes are deleted afterwards.
* @param meshList List of meshes to be joined
* @param out Receives a pointer to the output mesh.
*/
void JoinMeshes(std::vector<aiMesh*>& meshList,aiMesh*& out,
unsigned int max);
// -------------------------------------------------------------------
/** Join bones from a collection of meshes.
*
* @param it First mesh to be processed
* @param end Last mesh to be processed
* @param out Valid output mesh to receive the output bone list.
*/
void JoinBones(std::vector<aiMesh*>::const_iterator it,
std::vector<aiMesh*>::const_iterator end,
aiMesh* out);
// -------------------------------------------------------------------
/** Build a list of unique bones from a collection of meshes.
*
* @param it First mesh to be processed
* @param end Last mesh to be processed
* @param asBones Receives a list of unique bones
*/
void BuildUniqueBoneList(std::vector<aiMesh*>::const_iterator it,
std::vector<aiMesh*>::const_iterator end,
std::list<BoneWithHash>& asBones);
// -------------------------------------------------------------------
/** Build the output mesh list.
*/
void BuildOutputMeshList();
// -------------------------------------------------------------------
/** Transform meshes from one coordinate space into another.
* @param quak Input space. All meshes referenced by this node -
* assuming none of them is locked - are transformed in the
* local coordinate space of pNode
* @param pNode Destination coordinate space
*/
void TransformMeshes(aiNode* quak,aiNode* pNode);
private:
/** Configuration option: specifies the minimum number of faces
a node should have. The steps tries to join meshes with less
vertices that are on the same hierarchy level.
If this value is set to a very large value (e.g. 0xffffffff)
all meshes on the same hierarchy level are joined - if they
aren't animation nodes and if they have the same world matrices
*/
unsigned int configMinNumFaces;
/** Configuration option: specifies whether animations are removed
from the node graph. If animations aren't needed by the caller,
this allows for further optimization.
*/
bool configRemoveAnimations;
/** Configuration option: specifies whether nodes with inequal
world matrices are joined if they are on the same hierarchy
level and if it seems to make sense.
*/
bool configJoinInequalTransforms;
/** Working data */
aiScene* pScene;
/** List of hash identifiers for all meshes.
The hashes are build from both the meshes vertex format
and the material indices. Bones are not taken into account.
*/
std::vector<MeshHash> mMeshHashes;
/** List of output meshes.
*/
std::vector<aiMesh*> mOutputMeshes;
};
} // end of namespace Assimp
#endif // AI_LIMITBONEWEIGHTSPROCESS_H_INC
+14 -46
View File
@@ -40,16 +40,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @file Implementation of the PLY importer class */
// internal headers
#include "PlyLoader.h"
#include "MaterialSystem.h"
#include "StringComparison.h"
// public ASSIMP headers
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/aiMesh.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/DefaultLogger.h"
// boost headeers
#include <boost/scoped_ptr.hpp>
using namespace Assimp;
@@ -95,24 +100,19 @@ void PLYImporter::InternReadFile(
// Check whether we can read from the file
if( file.get() == NULL)
{
throw new ImportErrorException( "Failed to open PLY file " + pFile + ".");
}
// check whether the ply file is large enough to contain
// at least the file header
size_t fileSize = file->FileSize();
if( fileSize < 10)
{
throw new ImportErrorException( "PLY File is too small.");
}
// allocate storage and copy the contents of the file to a memory buffer
// (terminate it with zero)
// FIX: Allocate an extra buffer of 12.5% to be sure we won't crash
// if an overrun occurs.
this->mBuffer = new unsigned char[fileSize+1 + (fileSize>>3)];
file->Read( (void*)mBuffer, 1, fileSize);
std::vector<unsigned char> mBuffer2(fileSize+1);
file->Read( &mBuffer2[0], 1, fileSize);
this->mBuffer = &mBuffer2[0];
this->mBuffer[fileSize] = '\0';
// the beginning of the file must be PLY
@@ -120,8 +120,6 @@ void PLYImporter::InternReadFile(
this->mBuffer[1] != 'L' && this->mBuffer[1] != 'l' ||
this->mBuffer[2] != 'Y' && this->mBuffer[2] != 'y')
{
delete[] this->mBuffer;
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw new ImportErrorException( "Invalid .ply file: Magic number \'ply\' is no there");
}
char* szMe = (char*)&this->mBuffer[3];
@@ -137,11 +135,7 @@ void PLYImporter::InternReadFile(
szMe += 6;
SkipLine(szMe,(const char**)&szMe);
if(!PLY::DOM::ParseInstance(szMe,&sPlyDom))
{
delete[] this->mBuffer;
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw new ImportErrorException( "Invalid .ply file: Unable to build DOM (#1)");
}
}
else if (0 == ASSIMP_strincmp(szMe,"binary_",7))
{
@@ -159,18 +153,9 @@ void PLYImporter::InternReadFile(
// skip the line, parse the rest of the header and build the DOM
SkipLine(szMe,(const char**)&szMe);
if(!PLY::DOM::ParseInstanceBinary(szMe,&sPlyDom,bIsBE))
{
delete[] this->mBuffer;
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw new ImportErrorException( "Invalid .ply file: Unable to build DOM (#2)");
}
}
else
{
delete[] this->mBuffer;
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw new ImportErrorException( "Invalid .ply file: Unknown file format");
}
else throw new ImportErrorException( "Invalid .ply file: Unknown file format");
}
else
{
@@ -185,12 +170,8 @@ void PLYImporter::InternReadFile(
this->LoadVertices(&avPositions,false);
if (avPositions.empty())
{
delete[] this->mBuffer;
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw new ImportErrorException( "Invalid .ply file: No vertices found. "
"Unable to interpret the data format of the PLY file");
}
"Unable to parse the data format of the PLY file.");
// now load a list of normals.
std::vector<aiVector3D> avNormals;
@@ -206,10 +187,8 @@ void PLYImporter::InternReadFile(
{
if (avPositions.size() < 3)
{
delete[] this->mBuffer;
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw new ImportErrorException( "Invalid .ply file: Not enough vertices to build "
"a face list. ");
throw new ImportErrorException( "Invalid .ply file: Not enough "
"vertices to build a face list. ");
}
unsigned int iNum = (unsigned int)avPositions.size() / 3;
@@ -244,11 +223,7 @@ void PLYImporter::InternReadFile(
&avColors,&avTexCoords,&avMaterials,&avMeshes);
if (avMeshes.empty())
{
delete[] this->mBuffer;
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw new ImportErrorException( "Invalid .ply file: Unable to extract mesh data ");
}
// now generate the output scene object. Fill the material list
pScene->mNumMaterials = (unsigned int)avMaterials.size();
@@ -269,12 +244,6 @@ void PLYImporter::InternReadFile(
for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes;++i)
pScene->mRootNode->mMeshes[i] = i;
// delete the file buffer
delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
// DOM is lying on the stack, will be deconstructed automatically
return;
}
// ------------------------------------------------------------------------------------------------
void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
@@ -819,9 +788,8 @@ void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
if (3 > iNum)
{
// We must filter out all degenerates. Leave a message
// in the log ...
// LOG
// We must filter out all degenerates.
DefaultLogger::get()->warn("PLY: Found degenerated triangle");
continue;
}
+6 -6
View File
@@ -52,17 +52,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
PretransformVertices::PretransformVertices()
{
}
{
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
PretransformVertices::~PretransformVertices()
{
{
// nothing to do here
}
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool PretransformVertices::IsActive( unsigned int pFlags) const
@@ -12,18 +12,18 @@ with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -40,66 +40,53 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @file Implementation of the helper class to quickly find
vertices close to a given position. Special implementation for
the 3ds loader handling smooth groups correctly */
vertices close to a given position. Special implementation for
the 3ds loader handling smooth groups correctly */
#include <algorithm>
#include "3DSSpatialSort.h"
#include "SGSpatialSort.h"
#include "../include/aiAssert.h"
using namespace Assimp;
using namespace Assimp::Dot3DS;
// ------------------------------------------------------------------------------------------------
D3DSSpatialSorter::D3DSSpatialSorter()
{
SGSpatialSort::SGSpatialSort()
{
// define the reference plane. We choose some arbitrary vector away from all basic axises
// in the hope that no model spreads all its vertices along this plane.
mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
mPlaneNormal.Normalize();
}
// ------------------------------------------------------------------------------------------------
// Destructor
D3DSSpatialSorter::~D3DSSpatialSorter()
{
// nothing to do here, everything destructs automatically
}
// ------------------------------------------------------------------------------------------------
void D3DSSpatialSorter::AddFace(const Dot3DS::Face* pcFace,
const std::vector<aiVector3D>& vPositions)
{
ai_assert(NULL != pcFace);
// store position by index and distance
float distance = vPositions[pcFace->mIndices[0]] * mPlaneNormal;
mPositions.push_back( Entry( pcFace->mIndices[0], vPositions[pcFace->mIndices[0]],
distance, pcFace->iSmoothGroup));
// triangle vertex 2
distance = vPositions[pcFace->mIndices[1]] * mPlaneNormal;
mPositions.push_back( Entry( pcFace->mIndices[1], vPositions[pcFace->mIndices[1]],
distance, pcFace->iSmoothGroup));
// triangle vertex 3
distance = vPositions[pcFace->mIndices[2]] * mPlaneNormal;
mPositions.push_back( Entry( pcFace->mIndices[2], vPositions[pcFace->mIndices[2]],
distance, pcFace->iSmoothGroup));
}
// ------------------------------------------------------------------------------------------------
void D3DSSpatialSorter::Prepare()
// Destructor
SGSpatialSort::~SGSpatialSort()
{
// nothing to do here, everything destructs automatically
}
// ------------------------------------------------------------------------------------------------
void SGSpatialSort::Add(const aiVector3D& vPosition, unsigned int index,
unsigned int smoothingGroup)
{
// store position by index and distance
float distance = vPosition * mPlaneNormal;
mPositions.push_back( Entry( index, vPosition,
distance, smoothingGroup));
}
// ------------------------------------------------------------------------------------------------
void SGSpatialSort::Prepare()
{
// now sort the array ascending by distance.
std::sort( this->mPositions.begin(), this->mPositions.end());
}
// ------------------------------------------------------------------------------------------------
// Returns an iterator for all positions close to the given position.
void D3DSSpatialSorter::FindPositions( const aiVector3D& pPosition,
uint32_t pSG,
float pRadius,
std::vector<unsigned int>& poResults) const
{
void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
uint32_t pSG,
float pRadius,
std::vector<unsigned int>& poResults) const
{
float dist = pPosition * mPlaneNormal;
float minDist = dist - pRadius, maxDist = dist + pRadius;
@@ -119,14 +106,14 @@ void D3DSSpatialSorter::FindPositions( const aiVector3D& pPosition,
unsigned int index = (unsigned int)mPositions.size() / 2;
unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
while( binaryStepSize > 1)
{
{
if( mPositions[index].mDistance < minDist)
index += binaryStepSize;
else
index -= binaryStepSize;
binaryStepSize /= 2;
}
}
// depending on the direction of the last step we need to single step a bit back or forth
// to find the actual beginning element of the range
@@ -140,33 +127,16 @@ void D3DSSpatialSorter::FindPositions( const aiVector3D& pPosition,
float squareEpsilon = pRadius * pRadius;
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
if (0 == pSG)
while( it->mDistance < maxDist)
{
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
(it->mSmoothGroups & pSG || 0 == it->mSmoothGroups || 0 == pSG))
{
while( it->mDistance < maxDist)
{
if((it->mPosition - pPosition).SquareLength() < squareEpsilon)
{
poResults.push_back( it->mIndex);
}
++it;
if( it == mPositions.end())
break;
}
poResults.push_back( it->mIndex);
}
else
{
while( it->mDistance < maxDist)
{
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
(it->mSmoothGroups & pSG || 0 == it->mSmoothGroups))
{
poResults.push_back( it->mIndex);
}
++it;
if( it == mPositions.end())
break;
}
}
return;
++it;
if( it == mPositions.end())
break;
}
}
+11 -17
View File
@@ -44,40 +44,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_D3DSSPATIALSORT_H_INC
#include <vector>
#include "../include/aiVector3D.h"
#if (!defined AI_BUILD_NO_ASE_IMPORTER)
# include "3DSHelper.h"
#endif
#include "../include/aiTypes.h"
namespace Assimp
{
using namespace Dot3DS;
// ------------------------------------------------------------------------------------------------
/** Specialized version of SpatialSort to support smoothing groups
* This is used in the .3ds loader
*/
class D3DSSpatialSorter
class SGSpatialSort
{
public:
D3DSSpatialSorter();
SGSpatialSort();
// -------------------------------------------------------------------
/** Construction from a given face array, handling smoothing groups properly
*/
D3DSSpatialSorter(const std::vector<aiVector3D>& vPositions);
SGSpatialSort(const std::vector<aiVector3D>& vPositions);
// -------------------------------------------------------------------
/** Add a face to the spatial sorter
* @param pcFace Face to be added
* @param vPositions Input position list
/** Add a vertex to the spatial sort
* @param vPosition Vertex position to be added
* @param index Index of the vrtex
* @param smoothingGroup SmoothingGroup for this vertex
*/
void AddFace(const Dot3DS::Face* pcFace,
const std::vector<aiVector3D>& vPositions);
void Add(const aiVector3D& vPosition, unsigned int index,
unsigned int smoothingGroup);
// -------------------------------------------------------------------
/** Prepare the spatial sorter for use
@@ -85,7 +79,7 @@ public:
void Prepare();
/** Destructor */
~D3DSSpatialSorter();
~SGSpatialSort();
// -------------------------------------------------------------------
/** Returns an iterator for all positions close to the given position.
+2 -2
View File
@@ -110,10 +110,10 @@ void SMDImporter::SetupProperties(const Importer* pImp)
{
// The AI_CONFIG_IMPORT_SMD_KEYFRAME option overrides the
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
AI_CONFIG_IMPORT_SMD_KEYFRAME,0xffffffff)))
{
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
}
// ------------------------------------------------------------------------------------------------
+103
View File
@@ -0,0 +1,103 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file Defines the helper data structures for importing 3DS files.
http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
#ifndef AI_SMOOTHINGGROUPS_H_INC
#define AI_SMOOTHINGGROUPS_H_INC
// ---------------------------------------------------------------------------
/** Helper structure representing a face with smoothing groups assigned */
struct FaceWithSmoothingGroup
{
FaceWithSmoothingGroup() : iSmoothGroup(0)
{
// let the rest uninitialized for performance - in release builds.
// in debug builds set all indices to a common magic value
#ifdef _DEBUG
this->mIndices[0] = 0xffffffff;
this->mIndices[1] = 0xffffffff;
this->mIndices[2] = 0xffffffff;
#endif
}
//! Indices. .3ds is using uint16. However, after
//! an unique vrtex set has been geneerated it might
//! be an index becomes > 2^16
uint32_t mIndices[3];
//! specifies to which smoothing group the face belongs to
uint32_t iSmoothGroup;
};
// ---------------------------------------------------------------------------
/** Helper structure representing a mesh whose faces have smoothing
groups assigned. This allows us to reuse the code for normal computations
from smoothings groups for several loaders (3DS, ASE). All of them
use face structures which inherit from #FaceWithSmoothingGroup,
but as they add extra members and need to be copied by value we
need to use a template here.
*/
template <class T>
struct MeshWithSmoothingGroups
{
//! Vertex positions
std::vector<aiVector3D> mPositions;
//! Face lists
std::vector<T> mFaces;
//! List of normal vectors
std::vector<aiVector3D> mNormals;
};
// ---------------------------------------------------------------------------
/** Computes normal vectors for the mesh
*/
template <class T>
void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh);
// include implementations
#include "SmoothingGroups.inl"
#endif // !! AI_SMOOTHINGGROUPS_H_INC
@@ -39,80 +39,81 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file Implementation of the 3ds importer class */
#include "3DSLoader.h"
#include "MaterialSystem.h"
/** @file Generation of normal vectors basing on smoothing groups */
#ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED
#define AI_SMOOTHINGGROUPS_INL_INCLUDED
// internal headers
#include "SGSpatialSort.h"
// CRT header
#include <algorithm>
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
#include "../include/aiMesh.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "3DSSpatialSort.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
void Dot3DSImporter::GenNormals(Dot3DS::Mesh* sMesh)
template <class T>
void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh)
{
// First generate face normals
sMesh->mNormals.resize(sMesh->mPositions.size(),aiVector3D());
for( unsigned int a = 0; a < sMesh->mFaces.size(); a++)
sMesh.mNormals.resize(sMesh.mPositions.size(),aiVector3D());
for( unsigned int a = 0; a < sMesh.mFaces.size(); a++)
{
Dot3DS::Face& face = sMesh->mFaces[a];
T& face = sMesh.mFaces[a];
// assume it is a triangle
aiVector3D* pV1 = &sMesh->mPositions[face.mIndices[0]];
aiVector3D* pV2 = &sMesh->mPositions[face.mIndices[1]];
aiVector3D* pV3 = &sMesh->mPositions[face.mIndices[2]];
aiVector3D* pV1 = &sMesh.mPositions[face.mIndices[0]];
aiVector3D* pV2 = &sMesh.mPositions[face.mIndices[1]];
aiVector3D* pV3 = &sMesh.mPositions[face.mIndices[2]];
// FIX invert all vertex normals
aiVector3D pDelta1 = *pV3 - *pV1;
aiVector3D pDelta2 = *pV2 - *pV1;
aiVector3D pDelta1 = *pV2 - *pV1;
aiVector3D pDelta2 = *pV3 - *pV1;
aiVector3D vNor = pDelta1 ^ pDelta2;
sMesh->mNormals[face.mIndices[0]] = vNor;
sMesh->mNormals[face.mIndices[1]] = vNor;
sMesh->mNormals[face.mIndices[2]] = vNor;
sMesh.mNormals[face.mIndices[0]] = vNor;
sMesh.mNormals[face.mIndices[1]] = vNor;
sMesh.mNormals[face.mIndices[2]] = vNor;
}
// calculate the position bounds so we have a reliable epsilon to
// check position differences against
// @Schrompf: This is the 6th time this snippet is repeated!
aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
for( unsigned int a = 0; a < sMesh->mPositions.size(); a++)
for( unsigned int a = 0; a < sMesh.mPositions.size(); a++)
{
minVec.x = std::min( minVec.x, sMesh->mPositions[a].x);
minVec.y = std::min( minVec.y, sMesh->mPositions[a].y);
minVec.z = std::min( minVec.z, sMesh->mPositions[a].z);
maxVec.x = std::max( maxVec.x, sMesh->mPositions[a].x);
maxVec.y = std::max( maxVec.y, sMesh->mPositions[a].y);
maxVec.z = std::max( maxVec.z, sMesh->mPositions[a].z);
minVec.x = std::min( minVec.x, sMesh.mPositions[a].x);
minVec.y = std::min( minVec.y, sMesh.mPositions[a].y);
minVec.z = std::min( minVec.z, sMesh.mPositions[a].z);
maxVec.x = std::max( maxVec.x, sMesh.mPositions[a].x);
maxVec.y = std::max( maxVec.y, sMesh.mPositions[a].y);
maxVec.z = std::max( maxVec.z, sMesh.mPositions[a].z);
}
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
std::vector<aiVector3D> avNormals;
avNormals.resize(sMesh->mNormals.size());
avNormals.resize(sMesh.mNormals.size());
// now generate the spatial sort tree
D3DSSpatialSorter sSort;
for( std::vector<Dot3DS::Face>::iterator
i = sMesh->mFaces.begin();
i != sMesh->mFaces.end();++i)
SGSpatialSort sSort;
for( std::vector<T>::iterator
i = sMesh.mFaces.begin();
i != sMesh.mFaces.end();++i)
{
sSort.AddFace(&(*i),sMesh->mPositions);
sSort.Add(sMesh.mPositions[(*i).mIndices[0]],(*i).mIndices[0],(*i).iSmoothGroup);
sSort.Add(sMesh.mPositions[(*i).mIndices[1]],(*i).mIndices[1],(*i).iSmoothGroup);
sSort.Add(sMesh.mPositions[(*i).mIndices[2]],(*i).mIndices[2],(*i).iSmoothGroup);
}
sSort.Prepare();
for( std::vector<Dot3DS::Face>::iterator
i = sMesh->mFaces.begin();
i != sMesh->mFaces.end();++i)
for( std::vector<T>::iterator
i = sMesh.mFaces.begin();
i != sMesh.mFaces.end();++i)
{
std::vector<unsigned int> poResult;
for (unsigned int c = 0; c < 3;++c)
{
sSort.FindPositions(sMesh->mPositions[(*i).mIndices[c]],(*i).iSmoothGroup,
sSort.FindPositions(sMesh.mPositions[(*i).mIndices[c]],(*i).iSmoothGroup,
posEpsilon,poResult);
aiVector3D vNormals;
@@ -121,21 +122,16 @@ void Dot3DSImporter::GenNormals(Dot3DS::Mesh* sMesh)
a = poResult.begin();
a != poResult.end();++a)
{
vNormals += sMesh->mNormals[(*a)];
vNormals += sMesh.mNormals[(*a)];
fDiv += 1.0f;
}
vNormals.x /= fDiv;
vNormals.y /= fDiv;
vNormals.z /= fDiv;
vNormals.Normalize();
// do the common coordinate system adjustment
std::swap(vNormals.y,vNormals.z);
vNormals.x /= fDiv;vNormals.y /= fDiv;vNormals.z /= fDiv;
//vNormals.Normalize();
avNormals[(*i).mIndices[c]] = vNormals;
poResult.clear();
//poResult.clear();
}
}
sMesh->mNormals = avNormals;
return;
sMesh.mNormals = avNormals;
}
#endif // !! AI_SMOOTHINGGROUPS_INL_INCLUDED
+2 -2
View File
@@ -101,7 +101,7 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
{
// get the current value of the split property
this->LIMIT = pImp->GetProperty(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
}
// ------------------------------------------------------------------------------------------------
// Update a node after some meshes have been split
@@ -373,7 +373,7 @@ void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
// Setup properties
void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp)
{
this->LIMIT = pImp->GetProperty(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.