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-9d2fd5bffc1fpull/1/head
parent
51bfc46c1d
commit
38d04b6796
|
@ -59,10 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# define sprintf sprintf_s
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ReplaceDefaultMaterial()
|
void Dot3DSImporter::ReplaceDefaultMaterial()
|
||||||
{
|
{
|
||||||
|
@ -130,70 +126,66 @@ void Dot3DSImporter::ReplaceDefaultMaterial()
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::CheckIndices(Dot3DS::Mesh* sMesh)
|
void Dot3DSImporter::CheckIndices(Dot3DS::Mesh& sMesh)
|
||||||
{
|
{
|
||||||
for (std::vector< Dot3DS::Face >::iterator
|
for (std::vector< Dot3DS::Face >::iterator
|
||||||
i = sMesh->mFaces.begin();
|
i = sMesh.mFaces.begin();
|
||||||
i != sMesh->mFaces.end();++i)
|
i != sMesh.mFaces.end();++i)
|
||||||
{
|
{
|
||||||
// check whether all indices are in range
|
// 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)");
|
if ((*i).mIndices[a] >= sMesh.mPositions.size())
|
||||||
(*i).mIndices[0] = (uint32_t)sMesh->mPositions.size()-1;
|
{
|
||||||
}
|
DefaultLogger::get()->warn("3DS: Face index overflow)");
|
||||||
if ((*i).mIndices[1] >= sMesh->mPositions.size())
|
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
|
||||||
{
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
|
void Dot3DSImporter::MakeUnique(Dot3DS::Mesh& sMesh)
|
||||||
{
|
{
|
||||||
unsigned int iBase = 0;
|
unsigned int iBase = 0;
|
||||||
|
|
||||||
std::vector<aiVector3D> vNew;
|
std::vector<aiVector3D> vNew;
|
||||||
std::vector<aiVector2D> vNew2;
|
std::vector<aiVector2D> vNew2;
|
||||||
|
|
||||||
vNew.resize(sMesh->mFaces.size() * 3);
|
vNew.resize(sMesh.mFaces.size() * 3);
|
||||||
if (sMesh->mTexCoords.size())vNew2.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;
|
uint32_t iTemp1,iTemp2;
|
||||||
|
|
||||||
// positions
|
// positions
|
||||||
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]];
|
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[2]];
|
||||||
iTemp1 = iBase++;
|
iTemp1 = iBase++;
|
||||||
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]];
|
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[1]];
|
||||||
iTemp2 = iBase++;
|
iTemp2 = iBase++;
|
||||||
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]];
|
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[0]];
|
||||||
|
|
||||||
// texture coordinates
|
// texture coordinates
|
||||||
if (sMesh->mTexCoords.size())
|
if (sMesh.mTexCoords.size())
|
||||||
{
|
{
|
||||||
vNew2[iTemp1] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[2]];
|
vNew2[iTemp1] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[2]];
|
||||||
vNew2[iTemp2] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[1]];
|
vNew2[iTemp2] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[1]];
|
||||||
vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[0]];
|
vNew2[iBase] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
sMesh->mFaces[i].mIndices[2] = iBase++;
|
sMesh.mFaces[i].mIndices[2] = iBase++;
|
||||||
sMesh->mFaces[i].mIndices[0] = iTemp1;
|
sMesh.mFaces[i].mIndices[0] = iTemp1;
|
||||||
sMesh->mFaces[i].mIndices[1] = iTemp2;
|
sMesh.mFaces[i].mIndices[1] = iTemp2;
|
||||||
}
|
}
|
||||||
sMesh->mPositions = vNew;
|
sMesh.mPositions = vNew;
|
||||||
sMesh->mTexCoords = vNew2;
|
sMesh.mTexCoords = vNew2;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
||||||
MaterialHelper& mat)
|
MaterialHelper& mat)
|
||||||
|
@ -201,14 +193,14 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
||||||
// NOTE: Pass the background image to the viewer by bypassing the
|
// NOTE: Pass the background image to the viewer by bypassing the
|
||||||
// material system. This is an evil hack, never do it again!
|
// material system. This is an evil hack, never do it again!
|
||||||
if (0 != this->mBackgroundImage.length() && this->bHasBG)
|
if (0 != this->mBackgroundImage.length() && this->bHasBG)
|
||||||
{
|
{
|
||||||
aiString tex;
|
aiString tex;
|
||||||
tex.Set( this->mBackgroundImage);
|
tex.Set( this->mBackgroundImage);
|
||||||
mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
|
mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
|
||||||
|
|
||||||
// be sure this is only done for the first material
|
// be sure this is only done for the first material
|
||||||
this->mBackgroundImage = std::string("");
|
this->mBackgroundImage = std::string("");
|
||||||
}
|
}
|
||||||
|
|
||||||
// At first add the base ambient color of the
|
// At first add the base ambient color of the
|
||||||
// scene to the material
|
// scene to the material
|
||||||
|
@ -250,7 +242,7 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
||||||
// two sided rendering?
|
// two sided rendering?
|
||||||
if (oldMat.mTwoSided)
|
if (oldMat.mTwoSided)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 1;
|
||||||
mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
|
mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,8 +260,6 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
||||||
eShading = aiShadingMode_Gouraud; break;
|
eShading = aiShadingMode_Gouraud; break;
|
||||||
|
|
||||||
// assume cook-torrance shading for metals.
|
// 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 :
|
case Dot3DS::Dot3DSFile::Phong :
|
||||||
eShading = aiShadingMode_Phong; break;
|
eShading = aiShadingMode_Phong; break;
|
||||||
|
|
||||||
|
@ -409,20 +399,7 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
|
||||||
a = (*i).mFaceMaterials.begin();
|
a = (*i).mFaceMaterials.begin();
|
||||||
a != (*i).mFaceMaterials.end();++a,++iNum)
|
a != (*i).mFaceMaterials.end();++a,++iNum)
|
||||||
{
|
{
|
||||||
// check range
|
aiSplit[*a].push_back(iNum);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
// now generate submeshes
|
// now generate submeshes
|
||||||
bool bFirst = true;
|
bool bFirst = true;
|
||||||
|
@ -506,12 +483,9 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
|
||||||
pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
|
pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
|
||||||
pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
|
pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
|
||||||
for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
|
for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
|
||||||
{
|
|
||||||
pcOut->mMeshes[a] = avOutMeshes[a];
|
pcOut->mMeshes[a] = avOutMeshes[a];
|
||||||
}
|
|
||||||
|
|
||||||
if (!iFaceCnt)
|
if (!iFaceCnt)throw new ImportErrorException("No faces loaded. The mesh is empty");
|
||||||
throw new ImportErrorException("No faces loaded. The mesh is empty");
|
|
||||||
|
|
||||||
// for each material in the scene we need to setup the UV source
|
// for each material in the scene we need to setup the UV source
|
||||||
// set for each texture
|
// set for each texture
|
||||||
|
@ -519,6 +493,7 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
|
||||||
TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &this->mScene->mMaterials[a] );
|
TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &this->mScene->mMaterials[a] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node* pcIn)
|
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);
|
ai_assert(NULL != pcMesh);
|
||||||
|
|
||||||
// do case independent comparisons here, just for safety
|
// do case independent comparisons here, just for safety
|
||||||
if (pcIn->mName.length() == pcMesh->mName.length() &&
|
if (!ASSIMP_stricmp(pcIn->mName,pcMesh->mName))
|
||||||
!ASSIMP_stricmp(pcIn->mName.c_str(),pcMesh->mName.c_str()))
|
|
||||||
{
|
|
||||||
iArray.push_back(a);
|
iArray.push_back(a);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!iArray.empty())
|
if (!iArray.empty())
|
||||||
{
|
{
|
||||||
|
@ -568,10 +540,11 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
|
||||||
pvCurrent->y -= pivot.y;
|
pvCurrent->y -= pivot.y;
|
||||||
pvCurrent->z -= pivot.z;
|
pvCurrent->z -= pivot.z;
|
||||||
*pvCurrent = mTrafo * (*pvCurrent);
|
*pvCurrent = mTrafo * (*pvCurrent);
|
||||||
std::swap( pvCurrent->y, pvCurrent->z );
|
//std::swap( pvCurrent->y, pvCurrent->z );
|
||||||
++pvCurrent;
|
++pvCurrent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (pvCurrent != pvEnd)
|
while (pvCurrent != pvEnd)
|
||||||
|
@ -580,6 +553,7 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
|
||||||
++pvCurrent;
|
++pvCurrent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
pcOut->mMeshes[i] = iIndex;
|
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 the root node is a default node setup a name for it
|
||||||
if (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')
|
if (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')
|
||||||
{
|
|
||||||
pcOut->mRootNode->mName.Set("<root>");
|
pcOut->mRootNode->mName.Set("<root>");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ConvertScene(aiScene* pcOut)
|
void Dot3DSImporter::ConvertScene(aiScene* pcOut)
|
||||||
|
|
|
@ -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 */
|
http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
|
||||||
|
|
||||||
#ifndef AI_3DSFILEHELPER_H_INC
|
#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 "../include/aiMaterial.h"
|
||||||
|
|
||||||
#include "SpatialSort.h"
|
#include "SpatialSort.h"
|
||||||
|
#include "SmoothingGroups.h"
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace Dot3DS {
|
namespace Dot3DS {
|
||||||
|
|
||||||
#include "./Compiler/pushpack1.h"
|
#include "./Compiler/pushpack1.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# define sprintf sprintf_s
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Dot3DSFile class: Helper class for loading 3ds files. Defines chunks
|
/** Dot3DSFile class: Helper class for loading 3ds files. Defines chunks
|
||||||
* and data structures.
|
* and data structures.
|
||||||
*/
|
*/
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
class Dot3DSFile
|
class Dot3DSFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -91,32 +89,27 @@ public:
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
// translated to gouraud shading with wireframe active
|
// translated to gouraud shading with wireframe active
|
||||||
Wire = 0,
|
Wire = 0x0,
|
||||||
|
|
||||||
// if this material is set, no vertex normals will
|
// if this material is set, no vertex normals will
|
||||||
// be calculated for the model. Face normals + gouraud
|
// be calculated for the model. Face normals + gouraud
|
||||||
Flat = 1,
|
Flat = 0x1,
|
||||||
|
|
||||||
// standard gouraud shading
|
// standard gouraud shading
|
||||||
Gouraud = 2,
|
Gouraud = 0x2,
|
||||||
|
|
||||||
// phong shading
|
// phong shading
|
||||||
Phong = 3,
|
Phong = 0x3,
|
||||||
|
|
||||||
// cooktorrance or anistropic phong shading ...
|
// cooktorrance or anistropic phong shading ...
|
||||||
// the exact meaning is unknown, if you know it
|
// the exact meaning is unknown, if you know it
|
||||||
// feel free to tell me ;-)
|
// feel free to tell me ;-)
|
||||||
Metal = 4,
|
Metal = 0x4,
|
||||||
|
|
||||||
// required by the ASE loader
|
// required by the ASE loader
|
||||||
Blinn = 5
|
Blinn = 0x5
|
||||||
} shadetype3ds;
|
} shadetype3ds;
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// enum for all chunks in 3ds files. Unused
|
|
||||||
// ones are commented, list is not complete since
|
|
||||||
// there are many undocumented chunks
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -316,26 +309,10 @@ public:
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure representing a 3ds mesh face */
|
/** Helper structure representing a 3ds mesh face */
|
||||||
struct Face
|
struct Face : public FaceWithSmoothingGroup
|
||||||
{
|
{
|
||||||
Face() : iSmoothGroup(0), bFlipped(false)
|
//! Specifies that the face normal must be flipped.
|
||||||
{
|
//! todo: do we really need this?
|
||||||
// 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
|
|
||||||
bool bFlipped;
|
bool bFlipped;
|
||||||
};
|
};
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -442,7 +419,7 @@ struct Material
|
||||||
};
|
};
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure to represent a 3ds file mesh */
|
/** Helper structure to represent a 3ds file mesh */
|
||||||
struct Mesh
|
struct Mesh : public MeshWithSmoothingGroups<Dot3DS::Face>
|
||||||
{
|
{
|
||||||
//! Default constructor
|
//! Default constructor
|
||||||
Mesh()
|
Mesh()
|
||||||
|
@ -457,21 +434,12 @@ struct Mesh
|
||||||
//! Name of the mesh
|
//! Name of the mesh
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
//! Vertex positions
|
|
||||||
std::vector<aiVector3D> mPositions;
|
|
||||||
|
|
||||||
//! Face lists
|
|
||||||
std::vector<Face> mFaces;
|
|
||||||
|
|
||||||
//! Texture coordinates
|
//! Texture coordinates
|
||||||
std::vector<aiVector2D> mTexCoords;
|
std::vector<aiVector2D> mTexCoords;
|
||||||
|
|
||||||
//! Face materials
|
//! Face materials
|
||||||
std::vector<unsigned int> mFaceMaterials;
|
std::vector<unsigned int> mFaceMaterials;
|
||||||
|
|
||||||
//! Normal vectors
|
|
||||||
std::vector<aiVector3D> mNormals;
|
|
||||||
|
|
||||||
//! Local transformation matrix
|
//! Local transformation matrix
|
||||||
aiMatrix4x4 mMat;
|
aiMatrix4x4 mMat;
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,11 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// public ASSIMP headers
|
// public ASSIMP headers
|
||||||
#include "../include/DefaultLogger.h"
|
#include "../include/DefaultLogger.h"
|
||||||
#include "../include/IOStream.h"
|
|
||||||
#include "../include/IOSystem.h"
|
|
||||||
#include "../include/aiMesh.h"
|
|
||||||
#include "../include/aiScene.h"
|
#include "../include/aiScene.h"
|
||||||
#include "../include/aiAssert.h"
|
#include "../include/aiAssert.h"
|
||||||
|
#include "../include/IOStream.h"
|
||||||
|
#include "../include/IOSystem.h"
|
||||||
#include "../include/assimp.hpp"
|
#include "../include/assimp.hpp"
|
||||||
|
|
||||||
// boost headers
|
// boost headers
|
||||||
|
@ -62,11 +61,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
#if (!defined ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG)
|
|
||||||
# define ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG \
|
// begin a chunk: parse it, validate its length, get a pointer to its end
|
||||||
"WARNING: Size of chunk data plus size of " \
|
#define ASSIMP_3DS_BEGIN_CHUNK() \
|
||||||
"subordinate chunks is larger than the size " \
|
const Dot3DSFile::Chunk* psChunk; \
|
||||||
"specified in the top-level chunk header."
|
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
|
#endif
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -92,7 +117,7 @@ bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) co
|
||||||
return false;
|
return false;
|
||||||
std::string extension = pFile.substr( pos);
|
std::string extension = pFile.substr( pos);
|
||||||
|
|
||||||
// not brilliant but working ;-)
|
// not brillant but working ;-)
|
||||||
if( extension == ".3ds" || extension == ".3DS" ||
|
if( extension == ".3ds" || extension == ".3DS" ||
|
||||||
extension == ".3Ds" || extension == ".3dS")
|
extension == ".3Ds" || extension == ".3dS")
|
||||||
return true;
|
return true;
|
||||||
|
@ -103,7 +128,7 @@ bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) co
|
||||||
// Setup configuration properties
|
// Setup configuration properties
|
||||||
void Dot3DSImporter::SetupProperties(const Importer* pImp)
|
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.
|
// Imports the given file into the given scene structure.
|
||||||
|
@ -151,11 +176,11 @@ void Dot3DSImporter::InternReadFile(
|
||||||
i != this->mScene->mMeshes.end();++i)
|
i != this->mScene->mMeshes.end();++i)
|
||||||
{
|
{
|
||||||
// TODO: see function body
|
// TODO: see function body
|
||||||
this->CheckIndices(&(*i));
|
this->CheckIndices(*i);
|
||||||
this->MakeUnique(&(*i));
|
this->MakeUnique(*i);
|
||||||
|
|
||||||
// first generate normals for the mesh
|
// first generate normals for the mesh
|
||||||
this->GenNormals(&(*i));
|
ComputeNormalsWithSmoothingsGroups<Dot3DS::Face>(*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply scaling and offsets to all texture coordinates
|
// Apply scaling and offsets to all texture coordinates
|
||||||
|
@ -179,11 +204,7 @@ void Dot3DSImporter::InternReadFile(
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ApplyMasterScale(aiScene* pScene)
|
void Dot3DSImporter::ApplyMasterScale(aiScene* pScene)
|
||||||
{
|
{
|
||||||
// NOTE: Some invalid files have masterscale set to 0.0
|
if (!this->mMasterScale)this->mMasterScale = 1.0f;
|
||||||
if (0.0f == this->mMasterScale)
|
|
||||||
{
|
|
||||||
this->mMasterScale = 1.0f;
|
|
||||||
}
|
|
||||||
else this->mMasterScale = 1.0f / this->mMasterScale;
|
else this->mMasterScale = 1.0f / this->mMasterScale;
|
||||||
|
|
||||||
// construct an uniform scaling matrix and multiply with it
|
// construct an uniform scaling matrix and multiply with it
|
||||||
|
@ -200,9 +221,8 @@ void Dot3DSImporter::ReadChunk(const Dot3DSFile::Chunk** p_ppcOut)
|
||||||
|
|
||||||
// read chunk
|
// read chunk
|
||||||
if (this->mCurrent >= this->mLast)
|
if (this->mCurrent >= this->mLast)
|
||||||
{
|
|
||||||
throw new ImportErrorException("Unexpected end of file, can't read chunk header");
|
throw new ImportErrorException("Unexpected end of file, can't read chunk header");
|
||||||
}
|
|
||||||
const uintptr_t iDiff = this->mLast - this->mCurrent;
|
const uintptr_t iDiff = this->mLast - this->mCurrent;
|
||||||
if (iDiff < sizeof(Dot3DSFile::Chunk))
|
if (iDiff < sizeof(Dot3DSFile::Chunk))
|
||||||
{
|
{
|
||||||
|
@ -211,23 +231,15 @@ void Dot3DSImporter::ReadChunk(const Dot3DSFile::Chunk** p_ppcOut)
|
||||||
}
|
}
|
||||||
*p_ppcOut = (const Dot3DSFile::Chunk*) this->mCurrent;
|
*p_ppcOut = (const Dot3DSFile::Chunk*) this->mCurrent;
|
||||||
if ((**p_ppcOut).Size + this->mCurrent > this->mLast)
|
if ((**p_ppcOut).Size + this->mCurrent > this->mLast)
|
||||||
{
|
|
||||||
throw new ImportErrorException("Unexpected end of file, can't read chunk footer");
|
throw new ImportErrorException("Unexpected end of file, can't read chunk footer");
|
||||||
}
|
|
||||||
this->mCurrent += sizeof(Dot3DSFile::Chunk);
|
this->mCurrent += sizeof(Dot3DSFile::Chunk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseMainChunk(int& piRemaining)
|
void Dot3DSImporter::ParseMainChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
this->ReadChunk(&psChunk);
|
|
||||||
|
|
||||||
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
|
||||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size
|
|
||||||
- sizeof(Dot3DSFile::Chunk));
|
|
||||||
|
|
||||||
// get chunk type
|
// get chunk type
|
||||||
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||||
|
@ -237,27 +249,14 @@ void Dot3DSImporter::ParseMainChunk(int& piRemaining)
|
||||||
this->ParseEditorChunk(iRemaining);
|
this->ParseEditorChunk(iRemaining);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return this->ParseMainChunk(piRemaining);
|
return this->ParseMainChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseEditorChunk(int& piRemaining)
|
void Dot3DSImporter::ParseEditorChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
this->ReadChunk(&psChunk);
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
|
||||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
|
||||||
|
|
||||||
// get chunk type
|
// get chunk type
|
||||||
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||||
|
@ -291,27 +290,14 @@ void Dot3DSImporter::ParseEditorChunk(int& piRemaining)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return this->ParseEditorChunk(piRemaining);
|
return this->ParseEditorChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseObjectChunk(int& piRemaining)
|
void Dot3DSImporter::ParseObjectChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
this->ReadChunk(&psChunk);
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
|
||||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
|
||||||
|
|
||||||
const unsigned char* sz = this->mCurrent;
|
const unsigned char* sz = this->mCurrent;
|
||||||
unsigned int iCnt = 0;
|
unsigned int iCnt = 0;
|
||||||
|
@ -384,17 +370,8 @@ void Dot3DSImporter::ParseObjectChunk(int& piRemaining)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return this->ParseObjectChunk(piRemaining);
|
return this->ParseObjectChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -409,11 +386,7 @@ void Dot3DSImporter::SkipChunk()
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseChunk(int& piRemaining)
|
void Dot3DSImporter::ParseChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
this->ReadChunk(&psChunk);
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
|
||||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
|
||||||
|
|
||||||
// get chunk type
|
// get chunk type
|
||||||
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||||
|
@ -424,28 +397,14 @@ void Dot3DSImporter::ParseChunk(int& piRemaining)
|
||||||
this->ParseMeshChunk(iRemaining);
|
this->ParseMeshChunk(iRemaining);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return this->ParseChunk(piRemaining);
|
return this->ParseChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseKeyframeChunk(int& piRemaining)
|
void Dot3DSImporter::ParseKeyframeChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
this->ReadChunk(&psChunk);
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
|
||||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
|
||||||
|
|
||||||
// get chunk type
|
// get chunk type
|
||||||
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||||
|
@ -456,18 +415,8 @@ void Dot3DSImporter::ParseKeyframeChunk(int& piRemaining)
|
||||||
this->ParseHierarchyChunk(iRemaining);
|
this->ParseHierarchyChunk(iRemaining);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return this->ParseKeyframeChunk(piRemaining);
|
return this->ParseKeyframeChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -489,14 +438,7 @@ void Dot3DSImporter::InverseNodeSearch(Dot3DS::Node* pcNode,Dot3DS::Node* pcCurr
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
this->ReadChunk(&psChunk);
|
|
||||||
|
|
||||||
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
|
||||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size
|
|
||||||
- sizeof(Dot3DSFile::Chunk));
|
|
||||||
|
|
||||||
// get chunk type
|
// get chunk type
|
||||||
const unsigned char* sz = (unsigned char*)this->mCurrent;
|
const unsigned char* sz = (unsigned char*)this->mCurrent;
|
||||||
|
@ -548,6 +490,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
||||||
|
|
||||||
// pivot = origin of rotation and scaling
|
// pivot = origin of rotation and scaling
|
||||||
this->mCurrentNode->vPivot = *((const aiVector3D*)this->mCurrent);
|
this->mCurrentNode->vPivot = *((const aiVector3D*)this->mCurrent);
|
||||||
|
std::swap(this->mCurrentNode->vPivot.y,this->mCurrentNode->vPivot.z);
|
||||||
this->mCurrent += sizeof(aiVector3D);
|
this->mCurrent += sizeof(aiVector3D);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -576,8 +519,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
||||||
uint16_t sNum = *((const uint16_t*)mCurrent);
|
uint16_t sNum = *((const uint16_t*)mCurrent);
|
||||||
this->mCurrent += sizeof(uint16_t);
|
this->mCurrent += sizeof(uint16_t);
|
||||||
|
|
||||||
aiVectorKey v;
|
aiVectorKey v;v.mTime = (double)sNum;
|
||||||
v.mTime = (double)sNum;
|
|
||||||
|
|
||||||
this->mCurrent += sizeof(uint32_t);
|
this->mCurrent += sizeof(uint32_t);
|
||||||
v.mValue = *((const aiVector3D*)this->mCurrent);
|
v.mValue = *((const aiVector3D*)this->mCurrent);
|
||||||
|
@ -591,7 +533,8 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
||||||
if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
|
if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
|
||||||
}
|
}
|
||||||
// add the new keyframe
|
// 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;
|
break;
|
||||||
|
|
||||||
|
@ -618,9 +561,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
||||||
uint16_t sNum = *((const uint16_t*)mCurrent);
|
uint16_t sNum = *((const uint16_t*)mCurrent);
|
||||||
this->mCurrent += sizeof(uint16_t);
|
this->mCurrent += sizeof(uint16_t);
|
||||||
|
|
||||||
aiQuatKey v;
|
aiQuatKey v;v.mTime = (double)sNum;
|
||||||
v.mTime = (double)sNum;
|
|
||||||
|
|
||||||
this->mCurrent += sizeof(uint32_t);
|
this->mCurrent += sizeof(uint32_t);
|
||||||
|
|
||||||
float fRadians = *((const float*)this->mCurrent);
|
float fRadians = *((const float*)this->mCurrent);
|
||||||
|
@ -640,7 +581,8 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
||||||
if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
|
if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
|
||||||
}
|
}
|
||||||
// add the new keyframe
|
// 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;
|
break;
|
||||||
|
|
||||||
|
@ -698,31 +640,16 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return this->ParseHierarchyChunk(piRemaining);
|
return this->ParseHierarchyChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseFaceChunk(int& piRemaining)
|
void Dot3DSImporter::ParseFaceChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
Dot3DS::Mesh& mMesh = this->mScene->mMeshes.back();
|
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
|
// get chunk type
|
||||||
const unsigned char* sz = this->mCurrent;
|
const unsigned char* sz = this->mCurrent;
|
||||||
uint32_t iCnt = 0,iTemp;
|
uint32_t iCnt = 0,iTemp;
|
||||||
|
@ -796,31 +723,16 @@ void Dot3DSImporter::ParseFaceChunk(int& piRemaining)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return ParseFaceChunk(piRemaining);
|
return ParseFaceChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
|
void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
Dot3DS::Mesh& mMesh = this->mScene->mMeshes.back();
|
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
|
// get chunk type
|
||||||
const unsigned char* sz = this->mCurrent;
|
const unsigned char* sz = this->mCurrent;
|
||||||
unsigned int iCnt = 0;
|
unsigned int iCnt = 0;
|
||||||
|
@ -837,7 +749,7 @@ void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
mMesh.mPositions.push_back(*((aiVector3D*)this->mCurrent));
|
mMesh.mPositions.push_back(*((aiVector3D*)this->mCurrent));
|
||||||
aiVector3D& v = mMesh.mPositions.back();
|
aiVector3D& v = mMesh.mPositions.back();
|
||||||
//std::swap( v.y, v.z);
|
std::swap( v.y, v.z);
|
||||||
//v.y *= -1.0f;
|
//v.y *= -1.0f;
|
||||||
this->mCurrent += sizeof(aiVector3D);
|
this->mCurrent += sizeof(aiVector3D);
|
||||||
}
|
}
|
||||||
|
@ -924,28 +836,14 @@ void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return ParseMeshChunk(piRemaining);
|
return ParseMeshChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
this->ReadChunk(&psChunk);
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
|
||||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
|
||||||
|
|
||||||
// get chunk type
|
// get chunk type
|
||||||
const unsigned char* sz = this->mCurrent;
|
const unsigned char* sz = this->mCurrent;
|
||||||
|
@ -958,9 +856,8 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
||||||
case Dot3DSFile::CHUNK_MAT_MATNAME:
|
case Dot3DSFile::CHUNK_MAT_MATNAME:
|
||||||
|
|
||||||
// string in file is zero-terminated,
|
// string in file is zero-terminated,
|
||||||
// this should be no problem. However, validate whether
|
// this should be no problem. However, validate whether it overlaps
|
||||||
// it overlaps the end of the chunk, if yes we should
|
// the end of the chunk, if yes we should truncate it.
|
||||||
// truncate it.
|
|
||||||
while (*sz++ != '\0')
|
while (*sz++ != '\0')
|
||||||
{
|
{
|
||||||
if (sz > pcCurNext-1)
|
if (sz > pcCurNext-1)
|
||||||
|
@ -1017,8 +914,7 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
||||||
pcf = &this->mScene->mMaterials.back().mTransparency;
|
pcf = &this->mScene->mMaterials.back().mTransparency;
|
||||||
*pcf = this->ParsePercentageChunk();
|
*pcf = this->ParsePercentageChunk();
|
||||||
// NOTE: transparency, not opacity
|
// NOTE: transparency, not opacity
|
||||||
if (is_qnan(*pcf))
|
if (is_qnan(*pcf))*pcf = 1.0f;
|
||||||
*pcf = 1.0f;
|
|
||||||
else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
|
else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1037,16 +933,14 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
||||||
case Dot3DSFile::CHUNK_MAT_SHININESS:
|
case Dot3DSFile::CHUNK_MAT_SHININESS:
|
||||||
pcf = &this->mScene->mMaterials.back().mSpecularExponent;
|
pcf = &this->mScene->mMaterials.back().mSpecularExponent;
|
||||||
*pcf = this->ParsePercentageChunk();
|
*pcf = this->ParsePercentageChunk();
|
||||||
if (is_qnan(*pcf))
|
if (is_qnan(*pcf))*pcf = 0.0f;
|
||||||
*pcf = 0.0f;
|
|
||||||
else *pcf *= (float)0xFFFF;
|
else *pcf *= (float)0xFFFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Dot3DSFile::CHUNK_MAT_SHININESS_PERCENT:
|
case Dot3DSFile::CHUNK_MAT_SHININESS_PERCENT:
|
||||||
pcf = &this->mScene->mMaterials.back().mShininessStrength;
|
pcf = &this->mScene->mMaterials.back().mShininessStrength;
|
||||||
*pcf = this->ParsePercentageChunk();
|
*pcf = this->ParsePercentageChunk();
|
||||||
if (is_qnan(*pcf))
|
if (is_qnan(*pcf))*pcf = 0.0f;
|
||||||
*pcf = 0.0f;
|
|
||||||
else *pcf *= (float)0xffff / 100.0f;
|
else *pcf *= (float)0xffff / 100.0f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1054,8 +948,7 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
||||||
// TODO: need to multiply with emissive base color?
|
// TODO: need to multiply with emissive base color?
|
||||||
pcf = &this->mScene->mMaterials.back().sTexEmissive.mTextureBlend;
|
pcf = &this->mScene->mMaterials.back().sTexEmissive.mTextureBlend;
|
||||||
*pcf = this->ParsePercentageChunk();
|
*pcf = this->ParsePercentageChunk();
|
||||||
if (is_qnan(*pcf))
|
if (is_qnan(*pcf))*pcf = 0.0f;
|
||||||
*pcf = 0.0f;
|
|
||||||
else *pcf = *pcf * (float)0xFFFF / 100.0f;
|
else *pcf = *pcf * (float)0xFFFF / 100.0f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1085,31 +978,14 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
||||||
this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexEmissive);
|
this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexEmissive);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if (pcCurNext < this->mCurrent)
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
{
|
ASSIMP_3DS_END_CHUNK();
|
||||||
// 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;
|
|
||||||
return ParseMaterialChunk(piRemaining);
|
return ParseMaterialChunk(piRemaining);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::ParseTextureChunk(int& piRemaining,Dot3DS::Texture* pcOut)
|
void Dot3DSImporter::ParseTextureChunk(int& piRemaining,Dot3DS::Texture* pcOut)
|
||||||
{
|
{
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
ASSIMP_3DS_BEGIN_CHUNK();
|
||||||
|
|
||||||
this->ReadChunk(&psChunk);
|
|
||||||
|
|
||||||
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
|
||||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size
|
|
||||||
- sizeof(Dot3DSFile::Chunk));
|
|
||||||
|
|
||||||
// get chunk type
|
// get chunk type
|
||||||
const unsigned char* sz = this->mCurrent;
|
const unsigned char* sz = this->mCurrent;
|
||||||
|
@ -1184,11 +1060,8 @@ void Dot3DSImporter::ParseTextureChunk(int& piRemaining,Dot3DS::Texture* pcOut)
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Go to the starting position of the next chunk on this level
|
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||||
this->mCurrent = pcCurNext;
|
ASSIMP_3DS_END_CHUNK();
|
||||||
|
|
||||||
piRemaining -= psChunk->Size;
|
|
||||||
if (0 >= piRemaining)return;
|
|
||||||
return ParseTextureChunk(piRemaining,pcOut);
|
return ParseTextureChunk(piRemaining,pcOut);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -1226,20 +1099,22 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
||||||
|
|
||||||
const Dot3DSFile::Chunk* psChunk;
|
const Dot3DSFile::Chunk* psChunk;
|
||||||
this->ReadChunk(&psChunk);
|
this->ReadChunk(&psChunk);
|
||||||
if (NULL == psChunk)
|
if (!psChunk)
|
||||||
{
|
{
|
||||||
*p_pcOut = clrError;
|
*p_pcOut = clrError;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const unsigned int diff = psChunk->Size - sizeof(Dot3DSFile::Chunk);
|
||||||
|
|
||||||
const unsigned char* pcCur = this->mCurrent;
|
const unsigned char* pcCur = this->mCurrent;
|
||||||
this->mCurrent += psChunk->Size - sizeof(Dot3DSFile::Chunk);
|
this->mCurrent += diff;
|
||||||
bool bGamma = false;
|
bool bGamma = false;
|
||||||
switch(psChunk->Flag)
|
switch(psChunk->Flag)
|
||||||
{
|
{
|
||||||
case Dot3DSFile::CHUNK_LINRGBF:
|
case Dot3DSFile::CHUNK_LINRGBF:
|
||||||
bGamma = true;
|
bGamma = true;
|
||||||
case Dot3DSFile::CHUNK_RGBF:
|
case Dot3DSFile::CHUNK_RGBF:
|
||||||
if (sizeof(float) * 3 > psChunk->Size - sizeof(Dot3DSFile::Chunk))
|
if (sizeof(float) * 3 > diff)
|
||||||
{
|
{
|
||||||
*p_pcOut = clrError;
|
*p_pcOut = clrError;
|
||||||
return;
|
return;
|
||||||
|
@ -1252,7 +1127,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
||||||
case Dot3DSFile::CHUNK_LINRGBB:
|
case Dot3DSFile::CHUNK_LINRGBB:
|
||||||
bGamma = true;
|
bGamma = true;
|
||||||
case Dot3DSFile::CHUNK_RGBB:
|
case Dot3DSFile::CHUNK_RGBB:
|
||||||
if (sizeof(char) * 3 > psChunk->Size - sizeof(Dot3DSFile::Chunk))
|
if (sizeof(char) * 3 > diff)
|
||||||
{
|
{
|
||||||
*p_pcOut = clrError;
|
*p_pcOut = clrError;
|
||||||
return;
|
return;
|
||||||
|
@ -1265,7 +1140,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
||||||
// percentage chunks: accepted to be compatible with various
|
// percentage chunks: accepted to be compatible with various
|
||||||
// .3ds files with very curious content
|
// .3ds files with very curious content
|
||||||
case Dot3DSFile::CHUNK_PERCENTF:
|
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->r = *((float*)pcCur);
|
||||||
p_pcOut->g = *((float*)pcCur);
|
p_pcOut->g = *((float*)pcCur);
|
||||||
|
@ -1275,7 +1150,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
||||||
*p_pcOut = clrError;
|
*p_pcOut = clrError;
|
||||||
return;
|
return;
|
||||||
case Dot3DSFile::CHUNK_PERCENTW:
|
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->r = (float)pcCur[0] / 255.0f;
|
||||||
p_pcOut->g = (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.
|
// skip unknown chunks, hope this won't cause any problems.
|
||||||
return this->ParseColorChunk(p_pcOut,p_bAcceptPercent);
|
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)
|
if (bGamma)
|
||||||
{
|
{
|
||||||
p_pcOut->r = powf(p_pcOut->r, 1.0f / 2.2f);
|
p_pcOut->r = powf(p_pcOut->r, 1.0f / 2.2f);
|
||||||
|
|
|
@ -206,15 +206,10 @@ protected:
|
||||||
*/
|
*/
|
||||||
void ConvertScene(aiScene* pcOut);
|
void ConvertScene(aiScene* pcOut);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
/** generate normal vectors for a given mesh
|
|
||||||
*/
|
|
||||||
void GenNormals(Dot3DS::Mesh* sMesh);
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** generate unique vertices for a mesh
|
/** generate unique vertices for a mesh
|
||||||
*/
|
*/
|
||||||
void MakeUnique(Dot3DS::Mesh* sMesh);
|
void MakeUnique(Dot3DS::Mesh& sMesh);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Add a node to the node graph
|
/** Add a node to the node graph
|
||||||
|
@ -235,7 +230,7 @@ protected:
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Clamp all indices in the file to a valid range
|
/** Clamp all indices in the file to a valid range
|
||||||
*/
|
*/
|
||||||
void CheckIndices(Dot3DS::Mesh* sMesh);
|
void CheckIndices(Dot3DS::Mesh& sMesh);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// internal headers
|
// internal headers
|
||||||
#include "ASELoader.h"
|
#include "ASELoader.h"
|
||||||
#include "3DSSpatialSort.h"
|
|
||||||
#include "MaterialSystem.h"
|
#include "MaterialSystem.h"
|
||||||
#include "StringComparison.h"
|
#include "StringComparison.h"
|
||||||
#include "TextureTransform.h"
|
#include "TextureTransform.h"
|
||||||
|
@ -142,6 +141,7 @@ void ASEImporter::InternReadFile(
|
||||||
if ((*i).bSkip)continue;
|
if ((*i).bSkip)continue;
|
||||||
|
|
||||||
this->TransformVertices(*i);
|
this->TransformVertices(*i);
|
||||||
|
|
||||||
// now we need to create proper meshes from the import we need to
|
// now we need to create proper meshes from the import we need to
|
||||||
// split them by materials, build valid vertex/face lists ...
|
// split them by materials, build valid vertex/face lists ...
|
||||||
this->BuildUniqueRepresentation(*i);
|
this->BuildUniqueRepresentation(*i);
|
||||||
|
@ -1135,9 +1135,7 @@ void ASEImporter::BuildMaterialIndices()
|
||||||
}
|
}
|
||||||
// prepare for the next step
|
// prepare for the next step
|
||||||
for (unsigned int hans = 0; hans < this->mParser->m_vMaterials.size();++hans)
|
for (unsigned int hans = 0; hans < this->mParser->m_vMaterials.size();++hans)
|
||||||
{
|
|
||||||
TextureTransform::ApplyScaleNOffset(this->mParser->m_vMaterials[hans]);
|
TextureTransform::ApplyScaleNOffset(this->mParser->m_vMaterials[hans]);
|
||||||
}
|
|
||||||
|
|
||||||
// now we need to iterate through all meshes,
|
// now we need to iterate through all meshes,
|
||||||
// generating correct texture coordinates and material uv indices
|
// generating correct texture coordinates and material uv indices
|
||||||
|
@ -1182,75 +1180,6 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mesh.mNormals.empty())
|
if (mesh.mNormals.empty())
|
||||||
{
|
ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ using namespace Assimp::ASE;
|
||||||
#define BLUBB(_message_) \
|
#define BLUBB(_message_) \
|
||||||
{this->LogError(_message_);return;}
|
{this->LogError(_message_);return;}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
#define AI_ASE_HANDLE_TOP_LEVEL_SECTION(iDepth) \
|
#define AI_ASE_HANDLE_TOP_LEVEL_SECTION(iDepth) \
|
||||||
else if ('{' == *this->m_szFile)iDepth++; \
|
else if ('{' == *this->m_szFile)iDepth++; \
|
||||||
else if ('}' == *this->m_szFile) \
|
else if ('}' == *this->m_szFile) \
|
||||||
|
@ -87,6 +87,7 @@ using namespace Assimp::ASE;
|
||||||
} else bLastWasEndLine = false; \
|
} else bLastWasEndLine = false; \
|
||||||
++this->m_szFile;
|
++this->m_szFile;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
#define AI_ASE_HANDLE_SECTION(iDepth, level, msg) \
|
#define AI_ASE_HANDLE_SECTION(iDepth, level, msg) \
|
||||||
else if ('{' == *this->m_szFile)iDepth++; \
|
else if ('{' == *this->m_szFile)iDepth++; \
|
||||||
else if ('}' == *this->m_szFile) \
|
else if ('}' == *this->m_szFile) \
|
||||||
|
@ -1723,62 +1724,29 @@ void Parser::ParseLV4MeshLongTriple(unsigned int* apOut)
|
||||||
ai_assert(NULL != apOut);
|
ai_assert(NULL != apOut);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 3;++i)
|
for (unsigned int i = 0; i < 3;++i)
|
||||||
{
|
ParseLV4MeshLong(apOut[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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut)
|
void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut)
|
||||||
{
|
{
|
||||||
ai_assert(NULL != apOut);
|
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
|
// parse the index
|
||||||
rIndexOut = strtol10(this->m_szFile,&this->m_szFile);
|
ParseLV4MeshLong(rIndexOut);
|
||||||
|
|
||||||
// parse the three others
|
// parse the three others
|
||||||
this->ParseLV4MeshLongTriple(apOut);
|
this->ParseLV4MeshLongTriple(apOut);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Parser::ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut)
|
void Parser::ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut)
|
||||||
{
|
{
|
||||||
ai_assert(NULL != apOut);
|
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
|
// parse the index
|
||||||
rIndexOut = strtol10(this->m_szFile,&this->m_szFile);
|
ParseLV4MeshLong(rIndexOut);
|
||||||
|
|
||||||
// parse the three others
|
// parse the three others
|
||||||
this->ParseLV4MeshFloatTriple(apOut);
|
this->ParseLV4MeshFloatTriple(apOut);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Parser::ParseLV4MeshFloatTriple(float* apOut)
|
void Parser::ParseLV4MeshFloatTriple(float* apOut)
|
||||||
|
@ -1786,20 +1754,7 @@ void Parser::ParseLV4MeshFloatTriple(float* apOut)
|
||||||
ai_assert(NULL != apOut);
|
ai_assert(NULL != apOut);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 3;++i)
|
for (unsigned int i = 0; i < 3;++i)
|
||||||
{
|
ParseLV4MeshFloat(apOut[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;
|
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Parser::ParseLV4MeshFloat(float& fOut)
|
void Parser::ParseLV4MeshFloat(float& fOut)
|
||||||
|
@ -1815,9 +1770,6 @@ void Parser::ParseLV4MeshFloat(float& fOut)
|
||||||
}
|
}
|
||||||
// parse the first float
|
// parse the first float
|
||||||
this->m_szFile = fast_atof_move(this->m_szFile,fOut);
|
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)
|
void Parser::ParseLV4MeshLong(unsigned int& iOut)
|
||||||
|
@ -1833,7 +1785,4 @@ void Parser::ParseLV4MeshLong(unsigned int& iOut)
|
||||||
}
|
}
|
||||||
// parse the value
|
// parse the value
|
||||||
iOut = strtol10(this->m_szFile,&this->m_szFile);
|
iOut = strtol10(this->m_szFile,&this->m_szFile);
|
||||||
// go to the next valid sequence
|
|
||||||
//this->SkipToNextToken();
|
|
||||||
return;
|
|
||||||
}
|
}
|
|
@ -54,7 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "../include/aiAnim.h"
|
#include "../include/aiAnim.h"
|
||||||
|
|
||||||
// for some helper routines like IsSpace()
|
// for some helper routines like IsSpace()
|
||||||
#include "PlyParser.h"
|
#include "ParsingUtils.h"
|
||||||
#include "qnan.h"
|
#include "qnan.h"
|
||||||
|
|
||||||
// ASE is quite similar to 3ds. We can reuse some structures
|
// 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 */
|
/** Helper structure to represent an ASE file face */
|
||||||
struct Face : public Dot3DS::Face
|
struct Face : public FaceWithSmoothingGroup
|
||||||
{
|
{
|
||||||
//! Default constructor. Initializes everything with 0
|
//! Default constructor. Initializes everything with 0
|
||||||
Face()
|
Face()
|
||||||
|
@ -224,13 +224,13 @@ struct DecompTransform
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Helper structure to represent an ASE file mesh */
|
/** Helper structure to represent an ASE file mesh */
|
||||||
struct Mesh
|
struct Mesh : public MeshWithSmoothingGroups<ASE::Face>
|
||||||
{
|
{
|
||||||
//! Constructor. Creates a default name for the mesh
|
//! Constructor. Creates a default name for the mesh
|
||||||
Mesh() : bSkip(false)
|
Mesh() : bSkip(false)
|
||||||
{
|
{
|
||||||
static int iCnt = 0;
|
static int iCnt = 0;
|
||||||
char szTemp[128];
|
char szTemp[128]; // should be sufficiently large
|
||||||
::sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
::sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
||||||
mName = szTemp;
|
mName = szTemp;
|
||||||
|
|
||||||
|
@ -249,21 +249,12 @@ struct Mesh
|
||||||
//! "" if there is no parent ...
|
//! "" if there is no parent ...
|
||||||
std::string mParent;
|
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
|
//! List of all texture coordinate sets
|
||||||
std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||||
|
|
||||||
//! List of all vertex color sets.
|
//! List of all vertex color sets.
|
||||||
std::vector<aiColor4D> mVertexColors;
|
std::vector<aiColor4D> mVertexColors;
|
||||||
|
|
||||||
//! List of normal vectors
|
|
||||||
std::vector<aiVector3D> mNormals;
|
|
||||||
|
|
||||||
//! List of all bone vertices
|
//! List of all bone vertices
|
||||||
std::vector<BoneVertex> mBoneVertices;
|
std::vector<BoneVertex> mBoneVertices;
|
||||||
|
|
||||||
|
|
173
code/Assimp.cpp
173
code/Assimp.cpp
|
@ -40,14 +40,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
/** @file Implementation of the Plain-C API */
|
/** @file Implementation of the Plain-C API */
|
||||||
|
|
||||||
// CRT headers
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
// public ASSIMP headers
|
// public ASSIMP headers
|
||||||
#include "../include/assimp.h"
|
#include "../include/assimp.h"
|
||||||
|
#include "../include/aiFileIO.h"
|
||||||
#include "../include/assimp.hpp"
|
#include "../include/assimp.hpp"
|
||||||
#include "../include/DefaultLogger.h"
|
#include "../include/DefaultLogger.h"
|
||||||
#include "../include/aiAssert.h"
|
#include "../include/aiAssert.h"
|
||||||
|
#include "../include/IOStream.h"
|
||||||
|
#include "../include/IOSystem.h"
|
||||||
|
|
||||||
|
#include "GenericProperty.h"
|
||||||
|
|
||||||
// boost headers
|
// boost headers
|
||||||
#define AI_C_THREADSAFE
|
#define AI_C_THREADSAFE
|
||||||
|
@ -67,19 +70,158 @@ static ImporterMap gActiveImports;
|
||||||
/** Error message of the last failed import process */
|
/** Error message of the last failed import process */
|
||||||
static std::string gLastErrorString;
|
static std::string gLastErrorString;
|
||||||
|
|
||||||
|
/** Configuration properties */
|
||||||
|
static Importer::IntPropertyMap gIntProperties;
|
||||||
|
static Importer::FloatPropertyMap gFloatProperties;
|
||||||
|
static Importer::StringPropertyMap gStringProperties;
|
||||||
|
|
||||||
#if (defined AI_C_THREADSAFE)
|
#if (defined AI_C_THREADSAFE)
|
||||||
/** Global mutex to manage the access to the importer map */
|
/** Global mutex to manage the access to the importer map */
|
||||||
static boost::mutex gMutex;
|
static boost::mutex gMutex;
|
||||||
#endif
|
#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.
|
// Reads the given file and returns its content.
|
||||||
const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
|
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);
|
ai_assert(NULL != pFile);
|
||||||
|
|
||||||
// create an Importer for this file
|
// create an Importer for this file
|
||||||
Assimp::Importer* imp = new Assimp::Importer;
|
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
|
// and have it read the file
|
||||||
const aiScene* scene = imp->ReadFile( pFile, pFlags);
|
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
|
// it should be there... else the user is playing fools with us
|
||||||
if( it == gActiveImports.end())
|
if( it == gActiveImports.end())
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->error("Unable to find the Importer instance for this scene. "
|
ReportSceneNotFoundError();
|
||||||
"Are you sure it has been created by aiImportFile(ex)(...)?");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,11 +337,31 @@ void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
|
||||||
// it should be there... else the user is playing fools with us
|
// it should be there... else the user is playing fools with us
|
||||||
if( it == gActiveImports.end())
|
if( it == gActiveImports.end())
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->error("Unable to find the Importer instance for this scene. "
|
ReportSceneNotFoundError();
|
||||||
"Are you sure it has been created by aiImportFile(ex)(...)?");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// get memory statistics
|
// get memory statistics
|
||||||
it->second->GetMemoryRequirements(*in);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
|
||||||
void CalcTangentsProcess::SetupProperties(const Importer* pImp)
|
void CalcTangentsProcess::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
// get the current value of the property
|
// 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 = std::max(std::min(this->configMaxAngle,180.0f),0.0f);
|
||||||
this->configMaxAngle = AI_DEG_TO_RAD(this->configMaxAngle);
|
this->configMaxAngle = AI_DEG_TO_RAD(this->configMaxAngle);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
|
@ -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
|
|
@ -76,7 +76,7 @@ bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const
|
||||||
void GenVertexNormalsProcess::SetupProperties(const Importer* pImp)
|
void GenVertexNormalsProcess::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
// get the current value of the property
|
// 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 = std::max(std::min(this->configMaxAngle,180.0f),0.0f);
|
||||||
this->configMaxAngle = AI_DEG_TO_RAD(this->configMaxAngle);
|
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));
|
SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||||
std::vector<unsigned int> verticesFound;
|
std::vector<unsigned int> verticesFound;
|
||||||
|
|
||||||
const float fLimit = (AI_MESH_SMOOTHING_ANGLE_NOT_SET == pMesh->mMaxSmoothingAngle
|
const float fLimit = this->configMaxAngle;
|
||||||
? this->configMaxAngle : pMesh->mMaxSmoothingAngle);
|
|
||||||
|
|
||||||
aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
|
aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
|
||||||
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
|
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
|
||||||
|
|
|
@ -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
|
44
code/Hash.h
44
code/Hash.h
|
@ -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
|
#ifndef AI_HASH_H_INCLUDED
|
||||||
#define AI_HASH_H_INCLUDED
|
#define AI_HASH_H_INCLUDED
|
||||||
|
@ -19,11 +58,12 @@
|
||||||
#endif
|
#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;
|
uint32_t tmp;
|
||||||
int rem;
|
int rem;
|
||||||
|
|
||||||
if (len <= 0 || data == NULL) return 0;
|
if (!data) return 0;
|
||||||
|
if (!len)len = (unsigned int)::strlen(data);
|
||||||
|
|
||||||
rem = len & 3;
|
rem = len & 3;
|
||||||
len >>= 2;
|
len >>= 2;
|
||||||
|
|
|
@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "BaseProcess.h"
|
#include "BaseProcess.h"
|
||||||
#include "DefaultIOStream.h"
|
#include "DefaultIOStream.h"
|
||||||
#include "DefaultIOSystem.h"
|
#include "DefaultIOSystem.h"
|
||||||
|
#include "GenericProperty.h"
|
||||||
|
|
||||||
// Importers
|
// Importers
|
||||||
#if (!defined AI_BUILD_NO_X_IMPORTER)
|
#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)
|
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
|
||||||
# include "RemoveRedundantMaterials.h"
|
# include "RemoveRedundantMaterials.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
|
||||||
|
# include "OptimizeGraphProcess.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
@ -168,6 +172,9 @@ Importer::Importer() :
|
||||||
bExtraVerbose = false; // disable extra verbose mode by default
|
bExtraVerbose = false; // disable extra verbose mode by default
|
||||||
|
|
||||||
// add an instance of each worker class here
|
// 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)
|
#if (!defined AI_BUILD_NO_X_IMPORTER)
|
||||||
mImporter.push_back( new XFileImporter());
|
mImporter.push_back( new XFileImporter());
|
||||||
#endif
|
#endif
|
||||||
|
@ -217,13 +224,18 @@ Importer::Importer() :
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// add an instance of each post processing step here in the order
|
// 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)
|
#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS)
|
||||||
mPostProcessingSteps.push_back( new ValidateDSProcess()); // must be first
|
mPostProcessingSteps.push_back( new ValidateDSProcess()); // must be first
|
||||||
#endif
|
#endif
|
||||||
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
|
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
|
||||||
mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
|
mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
|
||||||
#endif
|
#endif
|
||||||
|
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
|
||||||
|
mPostProcessingSteps.push_back( new OptimizeGraphProcess());
|
||||||
|
#endif
|
||||||
#if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
|
#if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
|
||||||
mPostProcessingSteps.push_back( new TriangulateProcess());
|
mPostProcessingSteps.push_back( new TriangulateProcess());
|
||||||
#endif
|
#endif
|
||||||
|
@ -379,8 +391,16 @@ bool ValidateFlags(unsigned int pFlags)
|
||||||
if (pFlags & aiProcess_GenSmoothNormals &&
|
if (pFlags & aiProcess_GenSmoothNormals &&
|
||||||
pFlags & aiProcess_GenNormals)
|
pFlags & aiProcess_GenNormals)
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->error("aiProcess_GenSmoothNormals and aiProcess_GenNormals "
|
DefaultLogger::get()->error("aiProcess_GenSmoothNormals and "
|
||||||
"may not be specified together");
|
"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;
|
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
|
// Helper function to check whether an extension is supported by ASSIMP
|
||||||
bool Importer::IsExtensionSupported(const std::string& szExtension)
|
bool Importer::IsExtensionSupported(const std::string& szExtension)
|
||||||
|
{
|
||||||
|
return NULL != FindLoader(szExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
BaseImporter* Importer::FindLoader (const std::string& szExtension)
|
||||||
{
|
{
|
||||||
for (std::vector<BaseImporter*>::const_iterator
|
for (std::vector<BaseImporter*>::const_iterator
|
||||||
i = this->mImporter.begin();
|
i = this->mImporter.begin();
|
||||||
i != this->mImporter.end();++i)
|
i != this->mImporter.end();++i)
|
||||||
{
|
{
|
||||||
// pass the file extension to the CanRead(..,NULL)-method
|
// 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
|
// 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
|
void Importer::SetPropertyFloat(const char* szName, float iValue,
|
||||||
i = this->mIntProperties.begin();
|
bool* bWasExisting /*= NULL*/)
|
||||||
i != this->mIntProperties.end();++i)
|
{
|
||||||
{
|
SetGenericProperty<float>(mFloatProperties, szName,iValue,bWasExisting);
|
||||||
if (0 == ::strcmp( (*i).name.c_str(), szName ))
|
}
|
||||||
{
|
|
||||||
int iOld = (*i).value;
|
// ------------------------------------------------------------------------------------------------
|
||||||
(*i).value = iValue;
|
void Importer::SetPropertyString(const char* szName, const std::string& value,
|
||||||
return iOld;
|
bool* bWasExisting /*= NULL*/)
|
||||||
}
|
{
|
||||||
}
|
SetGenericProperty<std::string>(mStringProperties, szName,value,bWasExisting);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get a configuration property
|
// Get a configuration property
|
||||||
int Importer::GetProperty(const char* szName,
|
int Importer::GetPropertyInteger(const char* szName,
|
||||||
int iErrorReturn /*= 0xffffffff*/) const
|
int iErrorReturn /*= 0xffffffff*/) const
|
||||||
{
|
{
|
||||||
ai_assert(NULL != szName);
|
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
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)
|
void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "../include/aiTypes.h"
|
#include "../include/aiTypes.h"
|
||||||
|
|
||||||
struct aiMesh;
|
struct aiMesh;
|
||||||
|
class JoinVerticesTest;
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp
|
||||||
{
|
{
|
||||||
|
@ -62,6 +63,7 @@ namespace Assimp
|
||||||
class ASSIMP_API JoinVerticesProcess : public BaseProcess
|
class ASSIMP_API JoinVerticesProcess : public BaseProcess
|
||||||
{
|
{
|
||||||
friend class Importer;
|
friend class Importer;
|
||||||
|
friend class ::JoinVerticesTest;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Constructor to be privately used by Importer */
|
/** Constructor to be privately used by Importer */
|
||||||
|
|
|
@ -95,8 +95,8 @@ bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
|
||||||
// Setup configuration properties
|
// Setup configuration properties
|
||||||
void LWOImporter::SetupProperties(const Importer* pImp)
|
void LWOImporter::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
this->configGradientResX = pImp->GetProperty(AI_CONFIG_IMPORT_LWO_GRADIENT_RESX,512);
|
this->configGradientResX = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWO_GRADIENT_RESX,512);
|
||||||
this->configGradientResY = pImp->GetProperty(AI_CONFIG_IMPORT_LWO_GRADIENT_RESY,512);
|
this->configGradientResY = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWO_GRADIENT_RESY,512);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// 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<aiMesh*> apcMeshes;
|
||||||
std::vector<aiNode*> apcNodes;
|
std::vector<aiNode*> apcNodes;
|
||||||
apcNodes.reserve(mLayers->size());
|
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
|
// 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)
|
for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat)
|
||||||
{
|
{
|
||||||
MaterialHelper* pcMat = new MaterialHelper();
|
MaterialHelper* pcMat = new MaterialHelper();
|
||||||
|
@ -192,7 +192,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||||
const LWO::Layer& layer = *lit;
|
const LWO::Layer& layer = *lit;
|
||||||
|
|
||||||
// I don't know whether there could be dummy layers, but it would be possible
|
// 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())
|
if (!layer.mFaces.empty() && !layer.mTempPoints.empty())
|
||||||
{
|
{
|
||||||
// now sort all faces by the surfaces assigned to them
|
// 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())
|
if (idx >= mTags->size())
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->warn("LWO: Invalid face surface index");
|
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 == (idx = _mMapping[idx]))
|
||||||
{
|
{
|
||||||
if (0xffffffff == iDefaultSurface)
|
if (0xffffffff == iDefaultSurface)
|
||||||
{
|
{
|
||||||
iDefaultSurface = mSurfaces->size();
|
iDefaultSurface = (unsigned int)mSurfaces->size();
|
||||||
mSurfaces->push_back(LWO::Surface());
|
mSurfaces->push_back(LWO::Surface());
|
||||||
LWO::Surface& surf = mSurfaces->back();
|
LWO::Surface& surf = mSurfaces->back();
|
||||||
surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f;
|
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
|
// generate the mesh
|
||||||
aiMesh* mesh = new aiMesh();
|
aiMesh* mesh = new aiMesh();
|
||||||
apcMeshes.push_back(mesh);
|
apcMeshes.push_back(mesh);
|
||||||
mesh->mNumFaces = sorted.size();
|
mesh->mNumFaces = (unsigned int)sorted.size();
|
||||||
|
|
||||||
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
|
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
|
||||||
it != end;++it)
|
it != end;++it)
|
||||||
|
@ -281,7 +281,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||||
apcNodes.push_back(pcNode);
|
apcNodes.push_back(pcNode);
|
||||||
pcNode->mName.Set(layer.mName);
|
pcNode->mName.Set(layer.mName);
|
||||||
pcNode->mParent = reinterpret_cast<aiNode*>(layer.mParent);
|
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];
|
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
||||||
for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
|
for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
|
||||||
pcNode->mMeshes[p] = p + meshStart;
|
pcNode->mMeshes[p] = p + meshStart;
|
||||||
|
@ -292,7 +292,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||||
// copy the meshes to the output structure
|
// copy the meshes to the output structure
|
||||||
if (apcMeshes.size()) // shouldn't occur, just to be sure we don't crash
|
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*));
|
::memcpy(pScene->mMeshes,&apcMeshes[0],pScene->mNumMeshes*sizeof(void*));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -414,7 +414,7 @@ void LWOImporter::CopyFaceIndices(FaceList::iterator& it,
|
||||||
if (mi > mCurLayer->mTempPoints.size())
|
if (mi > mCurLayer->mTempPoints.size())
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->warn("LWO: face index is out of range");
|
DefaultLogger::get()->warn("LWO: face index is out of range");
|
||||||
mi = mCurLayer->mTempPoints.size()-1;
|
mi = (unsigned int)mCurLayer->mTempPoints.size()-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ void LimitBoneWeightsProcess::Execute( aiScene* pScene)
|
||||||
void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp)
|
void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
// get the current value of the property
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -45,14 +45,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "ByteSwap.h"
|
#include "ByteSwap.h"
|
||||||
#include "MD2NormalTable.h" // shouldn't be included by other units
|
#include "MD2NormalTable.h" // shouldn't be included by other units
|
||||||
|
|
||||||
#include "../include/IOStream.h"
|
// public ASSIMP headers
|
||||||
#include "../include/IOSystem.h"
|
#include "../include/assimp.hpp"
|
||||||
#include "../include/aiMesh.h"
|
|
||||||
#include "../include/aiScene.h"
|
#include "../include/aiScene.h"
|
||||||
#include "../include/aiAssert.h"
|
#include "../include/aiAssert.h"
|
||||||
|
#include "../include/IOStream.h"
|
||||||
|
#include "../include/IOSystem.h"
|
||||||
#include "../include/DefaultLogger.h"
|
#include "../include/DefaultLogger.h"
|
||||||
#include "../include/assimp.hpp"
|
|
||||||
|
|
||||||
|
// boost headers
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
@ -117,10 +118,10 @@ void MD2Importer::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
// The AI_CONFIG_IMPORT_MD2_KEYFRAME option overrides the
|
// The AI_CONFIG_IMPORT_MD2_KEYFRAME option overrides the
|
||||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||||
AI_CONFIG_IMPORT_MD2_KEYFRAME,0xffffffff)))
|
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))
|
if( fileSize < sizeof(MD2::Header))
|
||||||
throw new ImportErrorException( "MD2 File is too small");
|
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
|
for (unsigned int p = 0; p < 3;++p)
|
||||||
this->mBuffer = new unsigned char[fileSize];
|
{
|
||||||
file->Read( (void*)mBuffer, 1, fileSize);
|
ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]);
|
||||||
|
ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]);
|
||||||
this->m_pcHeader = (const MD2::Header*)this->mBuffer;
|
}
|
||||||
|
}
|
||||||
#ifdef AI_BUILD_BIG_ENDIAN
|
for (uint32_t i = 0; i < m_pcHeader->offsetTexCoords;++i)
|
||||||
|
{
|
||||||
ByteSwap::Swap4(&m_pcHeader->frameSize);
|
ByteSwap::Swap2(& pcTexCoords[i].s);
|
||||||
ByteSwap::Swap4(&m_pcHeader->magic);
|
ByteSwap::Swap2(& pcTexCoords[i].t);
|
||||||
ByteSwap::Swap4(&m_pcHeader->numFrames);
|
}
|
||||||
ByteSwap::Swap4(&m_pcHeader->numGlCommands);
|
ByteSwap::Swap4( & pcFrame->scale[0] );
|
||||||
ByteSwap::Swap4(&m_pcHeader->numSkins);
|
ByteSwap::Swap4( & pcFrame->scale[1] );
|
||||||
ByteSwap::Swap4(&m_pcHeader->numTexCoords);
|
ByteSwap::Swap4( & pcFrame->scale[2] );
|
||||||
ByteSwap::Swap4(&m_pcHeader->numTriangles);
|
ByteSwap::Swap4( & pcFrame->translate[0] );
|
||||||
ByteSwap::Swap4(&m_pcHeader->numVertices);
|
ByteSwap::Swap4( & pcFrame->translate[1] );
|
||||||
ByteSwap::Swap4(&m_pcHeader->offsetEnd);
|
ByteSwap::Swap4( & pcFrame->translate[2] );
|
||||||
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
|
#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
|
// allocate output storage
|
||||||
pScene->mNumMaterials = 1;
|
pcMesh->mNumVertices = (unsigned int)pcMesh->mNumFaces*3;
|
||||||
pScene->mRootNode = new aiNode();
|
pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
|
||||||
pScene->mRootNode->mNumMeshes = 1;
|
pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
|
||||||
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
|
// not sure whether there are MD2 files without texture coordinates
|
||||||
const MD2::Frame* pcFrame = (const MD2::Frame*) ((uint8_t*)
|
// NOTE: texture coordinates can be there without a texture,
|
||||||
this->m_pcHeader + this->m_pcHeader->offsetFrames);
|
// but a texture can't be there without a valid UV channel
|
||||||
pcFrame += this->configFrameID;
|
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
|
const int iMode = (int)aiShadingMode_Gouraud;
|
||||||
MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)
|
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
|
||||||
this->m_pcHeader + this->m_pcHeader->offsetTriangles);
|
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||||
|
|
||||||
// navigate to the begin of the tex coords data
|
aiColor3D clr;
|
||||||
const MD2::TexCoord* pcTexCoords = (const MD2::TexCoord*) ((uint8_t*)
|
clr.b = clr.g = clr.r = 1.0f;
|
||||||
this->m_pcHeader + this->m_pcHeader->offsetTexCoords);
|
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
|
clr.b = clr.g = clr.r = 0.05f;
|
||||||
const MD2::Vertex* pcVerts = (const MD2::Vertex*) (pcFrame->vertices);
|
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
|
||||||
|
|
||||||
#ifdef AI_BUILD_BIG_ENDIAN
|
if (pcSkins->name[0])
|
||||||
for (uint32_t i = 0; i< m_pcHeader->numTriangles)
|
|
||||||
{
|
{
|
||||||
for (unsigned int p = 0; p < 3;++p)
|
aiString szString;
|
||||||
{
|
const size_t iLen = ::strlen(pcSkins->name);
|
||||||
ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]);
|
::memcpy(szString.data,pcSkins->name,iLen);
|
||||||
ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]);
|
szString.data[iLen] = '\0';
|
||||||
}
|
szString.length = iLen;
|
||||||
}
|
|
||||||
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
|
|
||||||
|
|
||||||
pcMesh->mNumFaces = this->m_pcHeader->numTriangles;
|
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||||
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.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// apply a default material
|
DefaultLogger::get()->warn("Texture file name has zero length. It will be skipped.");
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ImportErrorException* ex)
|
else
|
||||||
{
|
{
|
||||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
// apply a default material
|
||||||
throw ex;
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,10 +144,10 @@ void MD3Importer::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
// The AI_CONFIG_IMPORT_MD3_KEYFRAME option overrides the
|
// The AI_CONFIG_IMPORT_MD3_KEYFRAME option overrides the
|
||||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||||
AI_CONFIG_IMPORT_MD3_KEYFRAME,0xffffffff)))
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -61,14 +61,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
using namespace Assimp;
|
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
|
// Constructor to be privately used by Importer
|
||||||
MD5Importer::MD5Importer()
|
MD5Importer::MD5Importer()
|
||||||
|
@ -122,9 +114,8 @@ void MD5Importer::InternReadFile(
|
||||||
|
|
||||||
// make sure we return no incomplete data
|
// make sure we return no incomplete data
|
||||||
if (!bHadMD5Mesh && !bHadMD5Anim)
|
if (!bHadMD5Mesh && !bHadMD5Anim)
|
||||||
{
|
|
||||||
throw new ImportErrorException("Failed to read valid data from this MD5");
|
throw new ImportErrorException("Failed to read valid data from this MD5");
|
||||||
}
|
|
||||||
if (!bHadMD5Mesh)pScene->mFlags |= AI_SCENE_FLAGS_ANIM_SKELETON_ONLY;
|
if (!bHadMD5Mesh)pScene->mFlags |= AI_SCENE_FLAGS_ANIM_SKELETON_ONLY;
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -285,30 +276,48 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
pScene->mRootNode->mNumChildren = 2;
|
pScene->mRootNode->mNumChildren = 2;
|
||||||
pScene->mRootNode->mChildren = new aiNode*[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
|
// 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->mName.Set("MD5Anim");
|
||||||
pcNode->mParent = pScene->mRootNode;
|
pcNode->mParent = pScene->mRootNode;
|
||||||
AttachChilds(-1,pcNode,meshParser.mJoints);
|
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
|
// generate all meshes
|
||||||
pScene->mNumMeshes = pScene->mNumMaterials = (unsigned int)meshParser.mMeshes.size();
|
pScene->mNumMeshes = pScene->mNumMaterials;
|
||||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||||
pScene->mMaterials = new aiMaterial*[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 = *it;
|
||||||
MD5::MeshDesc& meshSrc = meshParser.mMeshes[i];
|
if (meshSrc.mFaces.empty() || meshSrc.mVertices.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
aiMesh* mesh = pScene->mMeshes[n] = new aiMesh();
|
||||||
|
|
||||||
// generate unique vertices in our internal verbose format
|
// generate unique vertices in our internal verbose format
|
||||||
MakeDataUnique(meshSrc);
|
MakeDataUnique(meshSrc);
|
||||||
|
@ -424,9 +433,9 @@ void MD5Importer::LoadMD5MeshFile ()
|
||||||
|
|
||||||
// generate a material for the mesh
|
// generate a material for the mesh
|
||||||
MaterialHelper* mat = new MaterialHelper();
|
MaterialHelper* mat = new MaterialHelper();
|
||||||
pScene->mMaterials[i] = mat;
|
pScene->mMaterials[n] = mat;
|
||||||
mat->AddProperty(&meshSrc.mShader,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
mat->AddProperty(&meshSrc.mShader,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||||
mesh->mMaterialIndex = i;
|
mesh->mMaterialIndex = n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the file again
|
// delete the file again
|
||||||
|
|
|
@ -194,10 +194,10 @@ void MDCImporter::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
// The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the
|
// The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the
|
||||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||||
AI_CONFIG_IMPORT_MDC_KEYFRAME,0xffffffff)))
|
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;
|
pScene->mMeshes[i]->mTextureCoords[3] = NULL;
|
||||||
|
|
||||||
// create materials
|
// create materials
|
||||||
pScene->mNumMaterials = aszShaders.size();
|
pScene->mNumMaterials = (unsigned int)aszShaders.size();
|
||||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
||||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,11 +51,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// public ASSIMP headers
|
// public ASSIMP headers
|
||||||
#include "../include/DefaultLogger.h"
|
#include "../include/DefaultLogger.h"
|
||||||
#include "../include/IOStream.h"
|
|
||||||
#include "../include/IOSystem.h"
|
|
||||||
#include "../include/aiMesh.h"
|
|
||||||
#include "../include/aiScene.h"
|
#include "../include/aiScene.h"
|
||||||
#include "../include/aiAssert.h"
|
#include "../include/aiAssert.h"
|
||||||
|
#include "../include/IOStream.h"
|
||||||
|
#include "../include/IOSystem.h"
|
||||||
#include "../include/assimp.hpp"
|
#include "../include/assimp.hpp"
|
||||||
|
|
||||||
// boost headers
|
// boost headers
|
||||||
|
@ -119,11 +118,12 @@ void MDLImporter::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
// The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
|
// The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
|
||||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||||
AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff)))
|
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.
|
// Imports the given file into the given scene structure.
|
||||||
|
|
|
@ -55,8 +55,7 @@ struct aiNode;
|
||||||
#include "MDLFileData.h"
|
#include "MDLFileData.h"
|
||||||
#include "HalfLifeFileData.h"
|
#include "HalfLifeFileData.h"
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp {
|
||||||
{
|
|
||||||
class MaterialHelper;
|
class MaterialHelper;
|
||||||
|
|
||||||
using namespace MDL;
|
using namespace MDL;
|
||||||
|
@ -442,6 +441,9 @@ protected:
|
||||||
/** Configuration option: frame to be loaded */
|
/** Configuration option: frame to be loaded */
|
||||||
unsigned int configFrameID;
|
unsigned int configFrameID;
|
||||||
|
|
||||||
|
/** Configuration option: palette to be used to decode palletized images*/
|
||||||
|
std::string configPalette;
|
||||||
|
|
||||||
/** Buffer to hold the loaded file */
|
/** Buffer to hold the loaded file */
|
||||||
unsigned char* mBuffer;
|
unsigned char* mBuffer;
|
||||||
|
|
||||||
|
@ -449,16 +451,13 @@ protected:
|
||||||
* (MDL7 doesn't need this, the format has a separate loader) */
|
* (MDL7 doesn't need this, the format has a separate loader) */
|
||||||
unsigned int iGSFileVersion;
|
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;
|
IOSystem* pIOHandler;
|
||||||
|
|
||||||
/** Output scene to be filled
|
/** Output scene to be filled */
|
||||||
*/
|
|
||||||
aiScene* pScene;
|
aiScene* pScene;
|
||||||
|
|
||||||
/** Size of the input file in bytes
|
/** Size of the input file in bytes */
|
||||||
*/
|
|
||||||
unsigned int iFileSize;
|
unsigned int iFileSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ using namespace Assimp;
|
||||||
void MDLImporter::SearchPalette(const unsigned char** pszColorMap)
|
void MDLImporter::SearchPalette(const unsigned char** pszColorMap)
|
||||||
{
|
{
|
||||||
// now try to find the color map in the current directory
|
// 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;
|
const unsigned char* szColorMap = (const unsigned char*)::g_aclrDefaultColorMap;
|
||||||
if(pcStream)
|
if(pcStream)
|
||||||
|
|
|
@ -268,7 +268,7 @@ uint32_t MaterialHelper::ComputeHash()
|
||||||
// NOTE: We need to exclude the material name from the hash
|
// NOTE: We need to exclude the material name from the hash
|
||||||
if ((prop = this->mProperties[i]) && 0 != ::strcmp(prop->mKey.data,AI_MATKEY_NAME))
|
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);
|
hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,8 +371,8 @@ aiReturn MaterialHelper::AddProperty (const aiString* pInput,
|
||||||
const char* pKey)
|
const char* pKey)
|
||||||
{
|
{
|
||||||
// fix ... don't keep the whole string buffer
|
// fix ... don't keep the whole string buffer
|
||||||
return this->AddBinaryProperty(pInput,
|
return this->AddBinaryProperty(pInput,(unsigned int)pInput->length+1+
|
||||||
pInput->length+1+ (size_t)((uint8_t*)&pInput->data - (uint8_t*)&pInput->length),
|
(unsigned int)(((uint8_t*)&pInput->data - (uint8_t*)&pInput->length)),
|
||||||
pKey,aiPTI_String);
|
pKey,aiPTI_String);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -41,13 +41,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "ObjFileImporter.h"
|
#include "ObjFileImporter.h"
|
||||||
#include "ObjFileParser.h"
|
#include "ObjFileParser.h"
|
||||||
#include "ObjFileData.h"
|
#include "ObjFileData.h"
|
||||||
#include "../include/IOStream.h"
|
#include "MaterialSystem.h"
|
||||||
#include "../include/IOSystem.h"
|
|
||||||
#include "../include/aiMesh.h"
|
|
||||||
#include "../include/aiScene.h"
|
#include "../include/aiScene.h"
|
||||||
#include "../include/aiAssert.h"
|
#include "../include/aiAssert.h"
|
||||||
#include "../include/DefaultLogger.h"
|
#include "../include/DefaultLogger.h"
|
||||||
#include "MaterialSystem.h"
|
#include "../include/IOStream.h"
|
||||||
|
#include "../include/IOSystem.h"
|
||||||
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
@ -237,7 +237,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
|
||||||
if ( meshSizeDiff > 0 )
|
if ( meshSizeDiff > 0 )
|
||||||
{
|
{
|
||||||
pNode->mMeshes = new unsigned int[ meshSizeDiff ];
|
pNode->mMeshes = new unsigned int[ meshSizeDiff ];
|
||||||
pNode->mNumMeshes = meshSizeDiff;
|
pNode->mNumMeshes = (unsigned int)meshSizeDiff;
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
|
for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -306,8 +306,8 @@ void ObjFileParser::getFace()
|
||||||
|
|
||||||
// Store the face
|
// Store the face
|
||||||
m_pModel->m_pCurrentMesh->m_Faces.push_back( 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_uiNumIndices += (unsigned int)face->m_pVertices->size();
|
||||||
m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += face->m_pTexturCoords[0].size();
|
m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size();
|
||||||
|
|
||||||
// Skip the rest of the line
|
// Skip the rest of the line
|
||||||
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
|
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 ])
|
if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
|
||||||
{
|
{
|
||||||
mat_index = index;
|
mat_index = (int)index;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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
|
|
@ -40,16 +40,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file Implementation of the PLY importer class */
|
/** @file Implementation of the PLY importer class */
|
||||||
|
|
||||||
|
// internal headers
|
||||||
#include "PlyLoader.h"
|
#include "PlyLoader.h"
|
||||||
#include "MaterialSystem.h"
|
#include "MaterialSystem.h"
|
||||||
#include "StringComparison.h"
|
#include "StringComparison.h"
|
||||||
|
|
||||||
|
// public ASSIMP headers
|
||||||
#include "../include/IOStream.h"
|
#include "../include/IOStream.h"
|
||||||
#include "../include/IOSystem.h"
|
#include "../include/IOSystem.h"
|
||||||
#include "../include/aiMesh.h"
|
#include "../include/aiMesh.h"
|
||||||
#include "../include/aiScene.h"
|
#include "../include/aiScene.h"
|
||||||
#include "../include/aiAssert.h"
|
#include "../include/aiAssert.h"
|
||||||
|
#include "../include/DefaultLogger.h"
|
||||||
|
|
||||||
|
// boost headeers
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
@ -95,24 +100,19 @@ void PLYImporter::InternReadFile(
|
||||||
|
|
||||||
// Check whether we can read from the file
|
// Check whether we can read from the file
|
||||||
if( file.get() == NULL)
|
if( file.get() == NULL)
|
||||||
{
|
|
||||||
throw new ImportErrorException( "Failed to open PLY file " + pFile + ".");
|
throw new ImportErrorException( "Failed to open PLY file " + pFile + ".");
|
||||||
}
|
|
||||||
|
|
||||||
// check whether the ply file is large enough to contain
|
// check whether the ply file is large enough to contain
|
||||||
// at least the file header
|
// at least the file header
|
||||||
size_t fileSize = file->FileSize();
|
size_t fileSize = file->FileSize();
|
||||||
if( fileSize < 10)
|
if( fileSize < 10)
|
||||||
{
|
|
||||||
throw new ImportErrorException( "PLY File is too small.");
|
throw new ImportErrorException( "PLY File is too small.");
|
||||||
}
|
|
||||||
|
|
||||||
// allocate storage and copy the contents of the file to a memory buffer
|
// allocate storage and copy the contents of the file to a memory buffer
|
||||||
// (terminate it with zero)
|
// (terminate it with zero)
|
||||||
// FIX: Allocate an extra buffer of 12.5% to be sure we won't crash
|
std::vector<unsigned char> mBuffer2(fileSize+1);
|
||||||
// if an overrun occurs.
|
file->Read( &mBuffer2[0], 1, fileSize);
|
||||||
this->mBuffer = new unsigned char[fileSize+1 + (fileSize>>3)];
|
this->mBuffer = &mBuffer2[0];
|
||||||
file->Read( (void*)mBuffer, 1, fileSize);
|
|
||||||
this->mBuffer[fileSize] = '\0';
|
this->mBuffer[fileSize] = '\0';
|
||||||
|
|
||||||
// the beginning of the file must be PLY
|
// 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[1] != 'L' && this->mBuffer[1] != 'l' ||
|
||||||
this->mBuffer[2] != 'Y' && this->mBuffer[2] != 'y')
|
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");
|
throw new ImportErrorException( "Invalid .ply file: Magic number \'ply\' is no there");
|
||||||
}
|
}
|
||||||
char* szMe = (char*)&this->mBuffer[3];
|
char* szMe = (char*)&this->mBuffer[3];
|
||||||
|
@ -137,11 +135,7 @@ void PLYImporter::InternReadFile(
|
||||||
szMe += 6;
|
szMe += 6;
|
||||||
SkipLine(szMe,(const char**)&szMe);
|
SkipLine(szMe,(const char**)&szMe);
|
||||||
if(!PLY::DOM::ParseInstance(szMe,&sPlyDom))
|
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)");
|
throw new ImportErrorException( "Invalid .ply file: Unable to build DOM (#1)");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (0 == ASSIMP_strincmp(szMe,"binary_",7))
|
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
|
// skip the line, parse the rest of the header and build the DOM
|
||||||
SkipLine(szMe,(const char**)&szMe);
|
SkipLine(szMe,(const char**)&szMe);
|
||||||
if(!PLY::DOM::ParseInstanceBinary(szMe,&sPlyDom,bIsBE))
|
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)");
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -185,12 +170,8 @@ void PLYImporter::InternReadFile(
|
||||||
this->LoadVertices(&avPositions,false);
|
this->LoadVertices(&avPositions,false);
|
||||||
|
|
||||||
if (avPositions.empty())
|
if (avPositions.empty())
|
||||||
{
|
|
||||||
delete[] this->mBuffer;
|
|
||||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
|
||||||
throw new ImportErrorException( "Invalid .ply file: No vertices found. "
|
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.
|
// now load a list of normals.
|
||||||
std::vector<aiVector3D> avNormals;
|
std::vector<aiVector3D> avNormals;
|
||||||
|
@ -206,10 +187,8 @@ void PLYImporter::InternReadFile(
|
||||||
{
|
{
|
||||||
if (avPositions.size() < 3)
|
if (avPositions.size() < 3)
|
||||||
{
|
{
|
||||||
delete[] this->mBuffer;
|
throw new ImportErrorException( "Invalid .ply file: Not enough "
|
||||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
"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;
|
unsigned int iNum = (unsigned int)avPositions.size() / 3;
|
||||||
|
@ -244,11 +223,7 @@ void PLYImporter::InternReadFile(
|
||||||
&avColors,&avTexCoords,&avMaterials,&avMeshes);
|
&avColors,&avTexCoords,&avMaterials,&avMeshes);
|
||||||
|
|
||||||
if (avMeshes.empty())
|
if (avMeshes.empty())
|
||||||
{
|
|
||||||
delete[] this->mBuffer;
|
|
||||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
|
||||||
throw new ImportErrorException( "Invalid .ply file: Unable to extract mesh data ");
|
throw new ImportErrorException( "Invalid .ply file: Unable to extract mesh data ");
|
||||||
}
|
|
||||||
|
|
||||||
// now generate the output scene object. Fill the material list
|
// now generate the output scene object. Fill the material list
|
||||||
pScene->mNumMaterials = (unsigned int)avMaterials.size();
|
pScene->mNumMaterials = (unsigned int)avMaterials.size();
|
||||||
|
@ -269,12 +244,6 @@ void PLYImporter::InternReadFile(
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes;++i)
|
for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes;++i)
|
||||||
pScene->mRootNode->mMeshes[i] = 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,
|
void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
|
||||||
|
@ -819,9 +788,8 @@ void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
|
||||||
|
|
||||||
if (3 > iNum)
|
if (3 > iNum)
|
||||||
{
|
{
|
||||||
// We must filter out all degenerates. Leave a message
|
// We must filter out all degenerates.
|
||||||
// in the log ...
|
DefaultLogger::get()->warn("PLY: Found degenerated triangle");
|
||||||
// LOG
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,17 +52,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
PretransformVertices::PretransformVertices()
|
PretransformVertices::PretransformVertices()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Destructor, private as well
|
// Destructor, private as well
|
||||||
PretransformVertices::~PretransformVertices()
|
PretransformVertices::~PretransformVertices()
|
||||||
{
|
{
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the processing step is present in the given flag field.
|
// Returns whether the processing step is present in the given flag field.
|
||||||
bool PretransformVertices::IsActive( unsigned int pFlags) const
|
bool PretransformVertices::IsActive( unsigned int pFlags) const
|
||||||
|
|
|
@ -12,18 +12,18 @@ with or without modification, are permitted provided that the following
|
||||||
conditions are met:
|
conditions are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above
|
* Redistributions of source code must retain the above
|
||||||
copyright notice, this list of conditions and the
|
copyright notice, this list of conditions and the
|
||||||
following disclaimer.
|
following disclaimer.
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
* Redistributions in binary form must reproduce the above
|
||||||
copyright notice, this list of conditions and the
|
copyright notice, this list of conditions and the
|
||||||
following disclaimer in the documentation and/or other
|
following disclaimer in the documentation and/or other
|
||||||
materials provided with the distribution.
|
materials provided with the distribution.
|
||||||
|
|
||||||
* Neither the name of the ASSIMP team, nor the names of its
|
* Neither the name of the ASSIMP team, nor the names of its
|
||||||
contributors may be used to endorse or promote products
|
contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior
|
derived from this software without specific prior
|
||||||
written permission of the ASSIMP Development Team.
|
written permission of the ASSIMP Development Team.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
"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
|
/** @file Implementation of the helper class to quickly find
|
||||||
vertices close to a given position. Special implementation for
|
vertices close to a given position. Special implementation for
|
||||||
the 3ds loader handling smooth groups correctly */
|
the 3ds loader handling smooth groups correctly */
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "3DSSpatialSort.h"
|
#include "SGSpatialSort.h"
|
||||||
|
|
||||||
#include "../include/aiAssert.h"
|
#include "../include/aiAssert.h"
|
||||||
|
|
||||||
using namespace Assimp;
|
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
|
// 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.
|
// in the hope that no model spreads all its vertices along this plane.
|
||||||
mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
|
mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
|
||||||
mPlaneNormal.Normalize();
|
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.
|
// now sort the array ascending by distance.
|
||||||
std::sort( this->mPositions.begin(), this->mPositions.end());
|
std::sort( this->mPositions.begin(), this->mPositions.end());
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns an iterator for all positions close to the given position.
|
// Returns an iterator for all positions close to the given position.
|
||||||
void D3DSSpatialSorter::FindPositions( const aiVector3D& pPosition,
|
void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
|
||||||
uint32_t pSG,
|
uint32_t pSG,
|
||||||
float pRadius,
|
float pRadius,
|
||||||
std::vector<unsigned int>& poResults) const
|
std::vector<unsigned int>& poResults) const
|
||||||
{
|
{
|
||||||
float dist = pPosition * mPlaneNormal;
|
float dist = pPosition * mPlaneNormal;
|
||||||
float minDist = dist - pRadius, maxDist = dist + pRadius;
|
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 index = (unsigned int)mPositions.size() / 2;
|
||||||
unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
|
unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
|
||||||
while( binaryStepSize > 1)
|
while( binaryStepSize > 1)
|
||||||
{
|
{
|
||||||
if( mPositions[index].mDistance < minDist)
|
if( mPositions[index].mDistance < minDist)
|
||||||
index += binaryStepSize;
|
index += binaryStepSize;
|
||||||
else
|
else
|
||||||
index -= binaryStepSize;
|
index -= binaryStepSize;
|
||||||
|
|
||||||
binaryStepSize /= 2;
|
binaryStepSize /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// depending on the direction of the last step we need to single step a bit back or forth
|
// 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
|
// to find the actual beginning element of the range
|
||||||
|
@ -140,33 +127,16 @@ void D3DSSpatialSorter::FindPositions( const aiVector3D& pPosition,
|
||||||
|
|
||||||
float squareEpsilon = pRadius * pRadius;
|
float squareEpsilon = pRadius * pRadius;
|
||||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
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)
|
poResults.push_back( it->mIndex);
|
||||||
{
|
|
||||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon)
|
|
||||||
{
|
|
||||||
poResults.push_back( it->mIndex);
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
if( it == mPositions.end())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
++it;
|
||||||
{
|
if( it == mPositions.end())
|
||||||
while( it->mDistance < maxDist)
|
break;
|
||||||
{
|
|
||||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
|
|
||||||
(it->mSmoothGroups & pSG || 0 == it->mSmoothGroups))
|
|
||||||
{
|
|
||||||
poResults.push_back( it->mIndex);
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
if( it == mPositions.end())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -44,40 +44,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define AI_D3DSSPATIALSORT_H_INC
|
#define AI_D3DSSPATIALSORT_H_INC
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "../include/aiVector3D.h"
|
#include "../include/aiTypes.h"
|
||||||
|
|
||||||
|
|
||||||
#if (!defined AI_BUILD_NO_ASE_IMPORTER)
|
|
||||||
# include "3DSHelper.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp
|
||||||
{
|
{
|
||||||
|
|
||||||
using namespace Dot3DS;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
/** Specialized version of SpatialSort to support smoothing groups
|
/** Specialized version of SpatialSort to support smoothing groups
|
||||||
* This is used in the .3ds loader
|
* This is used in the .3ds loader
|
||||||
*/
|
*/
|
||||||
class D3DSSpatialSorter
|
class SGSpatialSort
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
D3DSSpatialSorter();
|
SGSpatialSort();
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Construction from a given face array, handling smoothing groups properly
|
/** 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
|
/** Add a vertex to the spatial sort
|
||||||
* @param pcFace Face to be added
|
* @param vPosition Vertex position to be added
|
||||||
* @param vPositions Input position list
|
* @param index Index of the vrtex
|
||||||
|
* @param smoothingGroup SmoothingGroup for this vertex
|
||||||
*/
|
*/
|
||||||
void AddFace(const Dot3DS::Face* pcFace,
|
void Add(const aiVector3D& vPosition, unsigned int index,
|
||||||
const std::vector<aiVector3D>& vPositions);
|
unsigned int smoothingGroup);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Prepare the spatial sorter for use
|
/** Prepare the spatial sorter for use
|
||||||
|
@ -85,7 +79,7 @@ public:
|
||||||
void Prepare();
|
void Prepare();
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~D3DSSpatialSorter();
|
~SGSpatialSort();
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns an iterator for all positions close to the given position.
|
/** Returns an iterator for all positions close to the given position.
|
|
@ -110,10 +110,10 @@ void SMDImporter::SetupProperties(const Importer* pImp)
|
||||||
{
|
{
|
||||||
// The AI_CONFIG_IMPORT_SMD_KEYFRAME option overrides the
|
// The AI_CONFIG_IMPORT_SMD_KEYFRAME option overrides the
|
||||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||||
AI_CONFIG_IMPORT_SMD_KEYFRAME,0xffffffff)))
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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 */
|
/** @file Generation of normal vectors basing on smoothing groups */
|
||||||
#include "3DSLoader.h"
|
|
||||||
#include "MaterialSystem.h"
|
#ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED
|
||||||
|
#define AI_SMOOTHINGGROUPS_INL_INCLUDED
|
||||||
|
|
||||||
|
// internal headers
|
||||||
|
#include "SGSpatialSort.h"
|
||||||
|
|
||||||
|
// CRT header
|
||||||
#include <algorithm>
|
#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;
|
using namespace Assimp;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Dot3DSImporter::GenNormals(Dot3DS::Mesh* sMesh)
|
template <class T>
|
||||||
|
void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh)
|
||||||
{
|
{
|
||||||
// First generate face normals
|
// First generate face normals
|
||||||
sMesh->mNormals.resize(sMesh->mPositions.size(),aiVector3D());
|
sMesh.mNormals.resize(sMesh.mPositions.size(),aiVector3D());
|
||||||
for( unsigned int a = 0; a < sMesh->mFaces.size(); a++)
|
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
|
// assume it is a triangle
|
||||||
aiVector3D* pV1 = &sMesh->mPositions[face.mIndices[0]];
|
aiVector3D* pV1 = &sMesh.mPositions[face.mIndices[0]];
|
||||||
aiVector3D* pV2 = &sMesh->mPositions[face.mIndices[1]];
|
aiVector3D* pV2 = &sMesh.mPositions[face.mIndices[1]];
|
||||||
aiVector3D* pV3 = &sMesh->mPositions[face.mIndices[2]];
|
aiVector3D* pV3 = &sMesh.mPositions[face.mIndices[2]];
|
||||||
|
|
||||||
// FIX invert all vertex normals
|
aiVector3D pDelta1 = *pV2 - *pV1;
|
||||||
aiVector3D pDelta1 = *pV3 - *pV1;
|
aiVector3D pDelta2 = *pV3 - *pV1;
|
||||||
aiVector3D pDelta2 = *pV2 - *pV1;
|
|
||||||
aiVector3D vNor = pDelta1 ^ pDelta2;
|
aiVector3D vNor = pDelta1 ^ pDelta2;
|
||||||
|
|
||||||
sMesh->mNormals[face.mIndices[0]] = vNor;
|
sMesh.mNormals[face.mIndices[0]] = vNor;
|
||||||
sMesh->mNormals[face.mIndices[1]] = vNor;
|
sMesh.mNormals[face.mIndices[1]] = vNor;
|
||||||
sMesh->mNormals[face.mIndices[2]] = vNor;
|
sMesh.mNormals[face.mIndices[2]] = vNor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the position bounds so we have a reliable epsilon to
|
// calculate the position bounds so we have a reliable epsilon to
|
||||||
// check position differences against
|
// check position differences against
|
||||||
// @Schrompf: This is the 6th time this snippet is repeated!
|
// @Schrompf: This is the 6th time this snippet is repeated!
|
||||||
aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
|
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.x = std::min( minVec.x, sMesh.mPositions[a].x);
|
||||||
minVec.y = std::min( minVec.y, sMesh->mPositions[a].y);
|
minVec.y = std::min( minVec.y, sMesh.mPositions[a].y);
|
||||||
minVec.z = std::min( minVec.z, sMesh->mPositions[a].z);
|
minVec.z = std::min( minVec.z, sMesh.mPositions[a].z);
|
||||||
maxVec.x = std::max( maxVec.x, sMesh->mPositions[a].x);
|
maxVec.x = std::max( maxVec.x, sMesh.mPositions[a].x);
|
||||||
maxVec.y = std::max( maxVec.y, sMesh->mPositions[a].y);
|
maxVec.y = std::max( maxVec.y, sMesh.mPositions[a].y);
|
||||||
maxVec.z = std::max( maxVec.z, sMesh->mPositions[a].z);
|
maxVec.z = std::max( maxVec.z, sMesh.mPositions[a].z);
|
||||||
}
|
}
|
||||||
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
|
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
|
||||||
std::vector<aiVector3D> avNormals;
|
std::vector<aiVector3D> avNormals;
|
||||||
avNormals.resize(sMesh->mNormals.size());
|
avNormals.resize(sMesh.mNormals.size());
|
||||||
|
|
||||||
// now generate the spatial sort tree
|
// now generate the spatial sort tree
|
||||||
D3DSSpatialSorter sSort;
|
SGSpatialSort sSort;
|
||||||
for( std::vector<Dot3DS::Face>::iterator
|
for( std::vector<T>::iterator
|
||||||
i = sMesh->mFaces.begin();
|
i = sMesh.mFaces.begin();
|
||||||
i != sMesh->mFaces.end();++i)
|
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();
|
sSort.Prepare();
|
||||||
|
|
||||||
for( std::vector<Dot3DS::Face>::iterator
|
for( std::vector<T>::iterator
|
||||||
i = sMesh->mFaces.begin();
|
i = sMesh.mFaces.begin();
|
||||||
i != sMesh->mFaces.end();++i)
|
i != sMesh.mFaces.end();++i)
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> poResult;
|
std::vector<unsigned int> poResult;
|
||||||
|
|
||||||
for (unsigned int c = 0; c < 3;++c)
|
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);
|
posEpsilon,poResult);
|
||||||
|
|
||||||
aiVector3D vNormals;
|
aiVector3D vNormals;
|
||||||
|
@ -121,21 +122,16 @@ void Dot3DSImporter::GenNormals(Dot3DS::Mesh* sMesh)
|
||||||
a = poResult.begin();
|
a = poResult.begin();
|
||||||
a != poResult.end();++a)
|
a != poResult.end();++a)
|
||||||
{
|
{
|
||||||
vNormals += sMesh->mNormals[(*a)];
|
vNormals += sMesh.mNormals[(*a)];
|
||||||
fDiv += 1.0f;
|
fDiv += 1.0f;
|
||||||
}
|
}
|
||||||
vNormals.x /= fDiv;
|
vNormals.x /= fDiv;vNormals.y /= fDiv;vNormals.z /= fDiv;
|
||||||
vNormals.y /= fDiv;
|
//vNormals.Normalize();
|
||||||
vNormals.z /= fDiv;
|
|
||||||
vNormals.Normalize();
|
|
||||||
|
|
||||||
// do the common coordinate system adjustment
|
|
||||||
std::swap(vNormals.y,vNormals.z);
|
|
||||||
|
|
||||||
avNormals[(*i).mIndices[c]] = vNormals;
|
avNormals[(*i).mIndices[c]] = vNormals;
|
||||||
poResult.clear();
|
//poResult.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sMesh->mNormals = avNormals;
|
sMesh.mNormals = avNormals;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !! AI_SMOOTHINGGROUPS_INL_INCLUDED
|
|
@ -101,7 +101,7 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
|
||||||
void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
|
void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
|
||||||
{
|
{
|
||||||
// get the current value of the split property
|
// 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
|
// Update a node after some meshes have been split
|
||||||
|
@ -373,7 +373,7 @@ void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
|
||||||
// Setup properties
|
// Setup properties
|
||||||
void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp)
|
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.
|
// Executes the post processing step on the given imported data.
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
/>
|
/>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
<Configuration
|
<Configuration
|
||||||
Name="Release|Win32"
|
Name="Debug|x64"
|
||||||
>
|
>
|
||||||
<DebugSettings
|
<DebugSettings
|
||||||
Command=""
|
Command=""
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
/>
|
/>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
<Configuration
|
<Configuration
|
||||||
Name="Debug|x64"
|
Name="Release|Win32"
|
||||||
>
|
>
|
||||||
<DebugSettings
|
<DebugSettings
|
||||||
Command=""
|
Command=""
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
virtual size_t Tell(void) const = 0;
|
virtual size_t Tell(void) const = 0;
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns filesize
|
/** Returns filesize
|
||||||
*
|
*
|
||||||
|
|
|
@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* whether a mesh must be splitted or not.
|
* whether a mesh must be splitted or not.
|
||||||
* \note The default value is AI_SLM_DEFAULT_MAX_VERTICES, defined in
|
* \note The default value is AI_SLM_DEFAULT_MAX_VERTICES, defined in
|
||||||
* the internal header file SplitLargeMeshes.h
|
* the internal header file SplitLargeMeshes.h
|
||||||
|
* Property type: integer.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_PP_SLM_TRIANGLE_LIMIT "pp.slm.triangle_limit"
|
#define AI_CONFIG_PP_SLM_TRIANGLE_LIMIT "pp.slm.triangle_limit"
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* whether a mesh must be splitted or not.
|
* whether a mesh must be splitted or not.
|
||||||
* \note The default value is AI_SLM_DEFAULT_MAX_TRIANGLES, defined in
|
* \note The default value is AI_SLM_DEFAULT_MAX_TRIANGLES, defined in
|
||||||
* the internal header file SplitLargeMeshes.h
|
* the internal header file SplitLargeMeshes.h
|
||||||
|
* Property type: integer.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_PP_SLM_VERTEX_LIMIT "pp.slm.vertex_limit"
|
#define AI_CONFIG_PP_SLM_VERTEX_LIMIT "pp.slm.vertex_limit"
|
||||||
|
|
||||||
|
@ -71,6 +73,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* This is used by the aiProcess_LimitBoneWeights PostProcess-Step.
|
* This is used by the aiProcess_LimitBoneWeights PostProcess-Step.
|
||||||
* \note The default value is AI_LBW_MAX_WEIGHTS, defined in
|
* \note The default value is AI_LBW_MAX_WEIGHTS, defined in
|
||||||
* the internal header file LimitBoneWeightsProcess.h
|
* the internal header file LimitBoneWeightsProcess.h
|
||||||
|
* Property type: integer.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_PP_LBW_MAX_WEIGHTS "pp.lbw.weights_limit"
|
#define AI_CONFIG_PP_LBW_MAX_WEIGHTS "pp.lbw.weights_limit"
|
||||||
|
|
||||||
|
@ -86,6 +89,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* for a specific loader. You can use the AI_CONFIG_IMPORT_XXX_KEYFRAME
|
* for a specific loader. You can use the AI_CONFIG_IMPORT_XXX_KEYFRAME
|
||||||
* options (where XXX is a placeholder for the file format for which you
|
* options (where XXX is a placeholder for the file format for which you
|
||||||
* want to override the global setting).
|
* want to override the global setting).
|
||||||
|
* Property type: integer.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_GLOBAL_KEYFRAME "imp.global.kf"
|
#define AI_CONFIG_IMPORT_GLOBAL_KEYFRAME "imp.global.kf"
|
||||||
|
|
||||||
|
@ -101,7 +105,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
/** \brief Causes the 3DS loader to ignore pivot points in the file
|
/** \brief Causes the 3DS loader to ignore pivot points in the file
|
||||||
*
|
*
|
||||||
* There are some faulty 3DS files which look only correctly with
|
* There are some faulty 3DS files which look only correctly with
|
||||||
* pivot points disabled
|
* pivot points disabled.
|
||||||
|
* Property type: integer (1: true; !1: false).
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT "imp.3ds.nopivot"
|
#define AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT "imp.3ds.nopivot"
|
||||||
|
|
||||||
|
@ -112,6 +117,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* LightWave represents the gradients with infinite detail,
|
* LightWave represents the gradients with infinite detail,
|
||||||
* but for use in realtime the loader computes replacement textures.
|
* but for use in realtime the loader computes replacement textures.
|
||||||
* The default size is 512 * 512.
|
* The default size is 512 * 512.
|
||||||
|
* Property type: integer.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_LWO_GRADIENT_RESX "imp.lwo.gradres_x"
|
#define AI_CONFIG_IMPORT_LWO_GRADIENT_RESX "imp.lwo.gradres_x"
|
||||||
#define AI_CONFIG_IMPORT_LWO_GRADIENT_RESY "imp.lwo.gradres_y"
|
#define AI_CONFIG_IMPORT_LWO_GRADIENT_RESY "imp.lwo.gradres_y"
|
||||||
|
@ -121,8 +127,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* that their tangents and bitangents are smoothed.
|
* that their tangents and bitangents are smoothed.
|
||||||
*
|
*
|
||||||
* This applies to the CalcTangentSpace-Step. The angle is specified
|
* This applies to the CalcTangentSpace-Step. The angle is specified
|
||||||
* in degrees * 1000, so 180000 is PI. The default value is
|
* in degrees , so 180 is PI. The default value is
|
||||||
* 45 degrees. The maximum value is 180000.
|
* 45 degrees. The maximum value is 180.
|
||||||
|
* Property type: float.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE "pp.ct.max_smoothing"
|
#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE "pp.ct.max_smoothing"
|
||||||
|
|
||||||
|
@ -131,15 +138,59 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* at the same vertex position that their are smoothed.
|
* at the same vertex position that their are smoothed.
|
||||||
*
|
*
|
||||||
* This applies to the GenSmoothNormals-Step. The angle is specified
|
* This applies to the GenSmoothNormals-Step. The angle is specified
|
||||||
* in degrees * 1000, so 180000 is PI. The default value is
|
* in degrees, so 180 is PI. The default value is
|
||||||
* 180 degrees (all vertex normals are smoothed). The maximum value is 180000
|
* 180 degrees (all vertex normals are smoothed). The maximum value is 180
|
||||||
* \note This can be manually overriden by loaders via #aiMesh::mMaxSmoothingAngle;
|
* Property type: float.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE "pp.gsn.max_smoothing"
|
#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE "pp.gsn.max_smoothing"
|
||||||
|
|
||||||
|
|
||||||
#define AI_CONFIG_PP_OG_MAX_DEPTH "pp.og.max_depth"
|
// ---------------------------------------------------------------------------
|
||||||
#define AI_CONFIG_PP_OG_MIN_TRIS_PER_NODE "pp.og.min_tris"
|
/** \brief Specifies the minimum number of faces a node should have.
|
||||||
#define AI_CONFIG_PP_OG_MAXIMALLY_SMALL "pp.og.maximally_small"
|
* This is an input parameter to the OptimizeGraph-Step.
|
||||||
|
*
|
||||||
|
* Nodes whose referenced meshes have less faces than this value
|
||||||
|
* are propably joined with neighbors with identical world matrices.
|
||||||
|
* However, it is just a hint to the step.
|
||||||
|
* Property type: integer
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_PP_OG_MIN_NUM_FACES "pp.og.min_faces"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** \brief Specifies whether animations are removed from the asset.
|
||||||
|
* This is an input parameter to the OptimizeGraph-Step.
|
||||||
|
*
|
||||||
|
* If an application does not need the animation data, erasing it at the
|
||||||
|
* beginning of the post-process pipeline allows some steps - including
|
||||||
|
* OptimizeGraph itself - to apply further optimizations.
|
||||||
|
* Property type: integer (1: true; !1: false).
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_PP_OG_REMOVE_ANIMATIONS "pp.og.remove_anims"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** \brief Specifies whether the OptimizeGraphProcess joins nodes even if
|
||||||
|
* their local transformations are inequal.
|
||||||
|
*
|
||||||
|
* By default, nodes with different local transformations are never joined.
|
||||||
|
* The intention is that all vertices should remain in their original
|
||||||
|
* local coordinate space where they are correctly centered and aligned,
|
||||||
|
* which does also allow for some significant culling improvements.
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_PP_OG_JOIN_INEQUAL_TRANSFORMS "pp.og.allow_diffwm"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** \brief Sets the colormap (= palette) to be used to decode embedded
|
||||||
|
* textures in MDL files.
|
||||||
|
*
|
||||||
|
* This must be a valid path to a file. The file is 768 (256*3) bytes
|
||||||
|
* large and contains RGB tripels for each of the 256 palette entries.
|
||||||
|
* The default value is colormap.lmp. If the file is nto found,
|
||||||
|
* a default palette is used.
|
||||||
|
* Property type: string.
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_IMPORT_MDL_COLORMAP "imp.mdl.color_map"
|
||||||
|
|
||||||
#endif // !! AI_CONFIG_H_INC
|
#endif // !! AI_CONFIG_H_INC
|
||||||
|
|
|
@ -53,11 +53,13 @@ extern "C" {
|
||||||
|
|
||||||
|
|
||||||
struct aiFileIO;
|
struct aiFileIO;
|
||||||
|
struct aiFile;
|
||||||
|
|
||||||
typedef aiFileIO (*aiFileOpenProc)(C_STRUCT aiFileIO*, const char*, const char*);
|
typedef aiFile* (*aiFileOpenProc)(C_STRUCT aiFileIO*, const char*, const char*);
|
||||||
typedef aiReturn (*aiFileCloseProc)(C_STRUCT aiFileIO*);
|
typedef void (*aiFileCloseProc)(C_STRUCT aiFileIO*, C_STRUCT aiFile*);
|
||||||
typedef unsigned long (*aiFileReadWriteProc)(C_STRUCT aiFileIO*, char*, unsigned int, unsigned int);
|
typedef size_t (*aiFileWriteProc)(C_STRUCT aiFile*, const char*, size_t, size_t);
|
||||||
typedef unsigned long (*aiFileTellProc)(C_STRUCT aiFileIO*);
|
typedef size_t (*aiFileReadProc)(C_STRUCT aiFile*, char*, size_t,size_t);
|
||||||
|
typedef size_t (*aiFileTellProc)(C_STRUCT aiFile*);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Define seek origins in fseek()-style.
|
/** Define seek origins in fseek()-style.
|
||||||
|
@ -70,10 +72,26 @@ enum aiOrigin
|
||||||
aiOrigin_END = 0x2 //!< End of file
|
aiOrigin_END = 0x2 //!< End of file
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef aiReturn (*aiFileSeek)(aiFileIO*, unsigned long, aiOrigin);
|
typedef aiReturn (*aiFileSeek)(aiFile*, size_t, aiOrigin);
|
||||||
|
|
||||||
typedef char* aiUserData;
|
typedef char* aiUserData;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** Defines how C-Assimp accesses files. Provided are functions to open
|
||||||
|
* and close files.
|
||||||
|
*/
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
struct aiFileIO
|
||||||
|
{
|
||||||
|
//! Function used to open a new file
|
||||||
|
aiFileOpenProc OpenProc;
|
||||||
|
|
||||||
|
//! Function used to close an existing file
|
||||||
|
aiFileCloseProc CloseProc;
|
||||||
|
|
||||||
|
//! User-defined data
|
||||||
|
aiUserData UserData;
|
||||||
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Data structure to wrap a set of fXXXX (e.g fopen) replacement functions
|
/** Data structure to wrap a set of fXXXX (e.g fopen) replacement functions
|
||||||
*
|
*
|
||||||
|
@ -81,30 +99,27 @@ typedef char* aiUserData;
|
||||||
* counterparts in the CRT.
|
* counterparts in the CRT.
|
||||||
*/
|
*/
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
struct aiFileIO
|
struct aiFile
|
||||||
{
|
{
|
||||||
//! User data assigned to the structure
|
|
||||||
aiUserData UserData;
|
|
||||||
|
|
||||||
//! Function used to open a new file
|
|
||||||
aiFileOpenProc OpenFunc;
|
|
||||||
|
|
||||||
//! Function used to close an existing file
|
|
||||||
aiFileCloseProc CloseFunc;
|
|
||||||
|
|
||||||
//! Function used to read from a file
|
//! Function used to read from a file
|
||||||
aiFileReadWriteProc ReadFunc;
|
aiFileReadProc ReadProc;
|
||||||
|
|
||||||
//! Function used to write to a file
|
//! Function used to write to a file
|
||||||
aiFileReadWriteProc WriteFunc;
|
aiFileWriteProc WriteProc;
|
||||||
|
|
||||||
//! Function used to retrieve the current
|
//! Function used to retrieve the current
|
||||||
//! position of the file cursor (ftell())
|
//! position of the file cursor (ftell())
|
||||||
aiFileTellProc TellProc;
|
aiFileTellProc TellProc;
|
||||||
|
|
||||||
|
//! Function used to retrieve the size of the file, in bytes
|
||||||
|
aiFileTellProc FileSizeProc;
|
||||||
|
|
||||||
//! Function used to set the current position
|
//! Function used to set the current position
|
||||||
//! of the file cursor (fseek())
|
//! of the file cursor (fseek())
|
||||||
aiFileSeek SeekProc;
|
aiFileSeek SeekProc;
|
||||||
|
|
||||||
|
//! User-defined data
|
||||||
|
aiUserData UserData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -356,16 +356,6 @@ struct aiMesh
|
||||||
*/
|
*/
|
||||||
unsigned int mMaterialIndex;
|
unsigned int mMaterialIndex;
|
||||||
|
|
||||||
/** The maximum vertex smooth angle for the mesh, in radians
|
|
||||||
* If the angle between two vertex normals is larger,
|
|
||||||
* the vertex normals should not be smoothed. The GenVertexNormals-Step
|
|
||||||
* takes care of this value. The angle is specified in radians.
|
|
||||||
* It is set to AI_MESH_SMOOTHING_ANGLE_NOT_SET if the source file didn't
|
|
||||||
* contain any additional information related to the calculation of
|
|
||||||
* vertex normals.
|
|
||||||
*/
|
|
||||||
float mMaxSmoothingAngle;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
//! Default constructor. Initializes all members to 0
|
//! Default constructor. Initializes all members to 0
|
||||||
|
@ -384,7 +374,6 @@ struct aiMesh
|
||||||
mColors[a] = NULL;
|
mColors[a] = NULL;
|
||||||
mNumBones = 0; mBones = NULL;
|
mNumBones = 0; mBones = NULL;
|
||||||
mMaterialIndex = 0;
|
mMaterialIndex = 0;
|
||||||
mMaxSmoothingAngle = AI_MESH_SMOOTHING_ANGLE_NOT_SET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Deletes all storage allocated for the mesh
|
//! Deletes all storage allocated for the mesh
|
||||||
|
|
|
@ -169,14 +169,66 @@ enum aiPostProcessSteps
|
||||||
* the bounding box of all vertices + their normals is compared against
|
* the bounding box of all vertices + their normals is compared against
|
||||||
* the volume of the bounding box of all vertices without their normals.
|
* the volume of the bounding box of all vertices without their normals.
|
||||||
* This works well for most objects, problems might occur with planar
|
* This works well for most objects, problems might occur with planar
|
||||||
* surfaces. However the step tries to filter such cases out.
|
* surfaces. However, the step tries to filter such cases.
|
||||||
* The step inverts all infacing normals. Generally it is recommended
|
* The step inverts all infacing normals. Generally it is recommended
|
||||||
* to enable this step.
|
* to enable this step, although the result is not always correct.
|
||||||
*/
|
*/
|
||||||
aiProcess_FixInfacingNormals = 0x2000
|
aiProcess_FixInfacingNormals = 0x2000,
|
||||||
|
|
||||||
|
/** This step performs some optimizations on the node graph.
|
||||||
|
*
|
||||||
|
* It is incompatible to the PreTransformVertices-Step. Some configuration
|
||||||
|
* options exist, see aiConfig.h for more details.
|
||||||
|
* Generally, two actions are available:<br>
|
||||||
|
* 1. Remove animation nodes and data from the scene. This allows other
|
||||||
|
* steps for further optimizations.<br>
|
||||||
|
* 2. Combine very small meshes to larger ones. Only if the meshes
|
||||||
|
* are used by the same node or by nodes on the same hierarchy (with
|
||||||
|
* equal local transformations). Unlike PreTransformVertices, the
|
||||||
|
* OptimizeGraph-step doesn't transform vertices from one space
|
||||||
|
* another.<br>
|
||||||
|
* 3. Remove hierarchy levels<br>
|
||||||
|
*
|
||||||
|
* It is recommended to have this step run with the default configuration.
|
||||||
|
*/
|
||||||
|
aiProcess_OptimizeGraph = 0x4000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** @def AI_POSTPROCESS_DEFAULT_REALTIME_FASTEST
|
||||||
|
* @brief Default postprocess configuration targeted at realtime applications
|
||||||
|
* which need to load models as fast as possible.
|
||||||
|
*
|
||||||
|
* If you're using DirectX, don't forget to combine this value with
|
||||||
|
* the #aiProcess_ConvertToLeftHanded step.
|
||||||
|
*/
|
||||||
|
#define AI_POSTPROCESS_DEFAULT_REALTIME_FASTEST \
|
||||||
|
aiProcess_CalcTangentSpace | \
|
||||||
|
aiProcess_GenNormals | \
|
||||||
|
aiProcess_JoinIdenticalVertices | \
|
||||||
|
aiProcess_Triangulate
|
||||||
|
|
||||||
|
|
||||||
|
/** @def AI_POSTPROCESS_DEFAULT_REALTIME_FASTEST
|
||||||
|
* @brief Default postprocess configuration targeted at realtime applications.
|
||||||
|
* Unlike AI_POSTPROCESS_DEFAULT_REALTIME_FASTEST, this configuration
|
||||||
|
* performs some extra optimizations.
|
||||||
|
*
|
||||||
|
* If you're using DirectX, don't forget to combine this value with
|
||||||
|
* the #aiProcess_ConvertToLeftHanded step.
|
||||||
|
*/
|
||||||
|
#define AI_POSTPROCESS_DEFAULT_REALTIME \
|
||||||
|
aiProcess_CalcTangentSpace | \
|
||||||
|
aiProcess_GenSmoothNormals | \
|
||||||
|
aiProcess_JoinIdenticalVertices | \
|
||||||
|
aiProcess_ImproveCacheLocality | \
|
||||||
|
aiProcess_LimitBoneWeights | \
|
||||||
|
aiProcess_RemoveRedundantMaterials | \
|
||||||
|
aiProcess_SplitLargeMeshes | \
|
||||||
|
aiProcess_OptimizeGraph | \
|
||||||
|
aiProcess_Triangulate
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // end of extern "C"
|
} // end of extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -75,6 +75,9 @@ struct aiVector3D
|
||||||
inline bool operator!= (const aiVector3D& other) const
|
inline bool operator!= (const aiVector3D& other) const
|
||||||
{return x != other.x || y != other.y || z != other.z;}
|
{return x != other.x || y != other.y || z != other.z;}
|
||||||
|
|
||||||
|
inline aiVector3D& operator= (float f)
|
||||||
|
{x = y = z = f;return *this;}
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
|
|
|
@ -66,8 +66,8 @@ struct aiString;
|
||||||
* @param pFile Path and filename of the file to be imported,
|
* @param pFile Path and filename of the file to be imported,
|
||||||
* expected to be a null-terminated c-string. NULL is not a valid value.
|
* expected to be a null-terminated c-string. NULL is not a valid value.
|
||||||
* @param pFlags Optional post processing steps to be executed after
|
* @param pFlags Optional post processing steps to be executed after
|
||||||
* a successful import. Provide a bitwise combination of the #aiPostProcessSteps
|
* a successful import. Provide a bitwise combination of the
|
||||||
* flags.
|
* #aiPostProcessSteps flags.
|
||||||
* @return Pointer to the imported data or NULL if the import failed.
|
* @return Pointer to the imported data or NULL if the import failed.
|
||||||
*/
|
*/
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -85,18 +85,19 @@ ASSIMP_API const C_STRUCT aiScene* aiImportFile( const char* pFile,
|
||||||
* done with it, call aiReleaseImport() to free the resources associated with
|
* done with it, call aiReleaseImport() to free the resources associated with
|
||||||
* this file. If the import fails, NULL is returned instead. Call
|
* this file. If the import fails, NULL is returned instead. Call
|
||||||
* aiGetErrorString() to retrieve a human-readable error text.
|
* aiGetErrorString() to retrieve a human-readable error text.
|
||||||
* @param pFile aiFileIO structure. All functions pointers must be
|
* @param pFile Path and filename of the file to be imported,
|
||||||
* initialized. aiFileIO::OpenFunc() and aiFileIO::CloseFunc()
|
* expected to be a null-terminated c-string. NULL is not a valid value.
|
||||||
* will be used to open other files in the fs if the asset to be
|
* @param pFlags Optional post processing steps to be executed after
|
||||||
* loaded depends on them. NULL is not a valid value.
|
* a successful import. Provide a bitwise combination of the
|
||||||
|
* #aiPostProcessSteps flags.
|
||||||
|
* @param pFS aiFileIO structure. Will be used to open the model file itself
|
||||||
|
* and any other files the loader needs to open.
|
||||||
* @return Pointer to the imported data or NULL if the import failed.
|
* @return Pointer to the imported data or NULL if the import failed.
|
||||||
*
|
|
||||||
* @note The C-API creates a new Importer instance internally for each call
|
|
||||||
* to this function. Therefore the C-API is thread-safe.
|
|
||||||
*/
|
*/
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
ASSIMP_API const C_STRUCT aiScene* aiImportFileEx(
|
ASSIMP_API const C_STRUCT aiScene* aiImportFileEx(
|
||||||
const C_STRUCT aiFileIO* pFile);
|
const char* pFile, unsigned int pFlags,
|
||||||
|
C_STRUCT aiFileIO* pFS);
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -151,6 +152,31 @@ ASSIMP_API void aiGetExtensionList(C_STRUCT aiString* szOut);
|
||||||
ASSIMP_API void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
|
ASSIMP_API void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
|
||||||
C_STRUCT aiMemoryInfo* in);
|
C_STRUCT aiMemoryInfo* in);
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** Set an integer property. This is the C-version of
|
||||||
|
* #Importer::SetPropertyInteger(). In the C-API properties are shared by
|
||||||
|
* all imports. It is not possible to specify them per asset.
|
||||||
|
*
|
||||||
|
* \param szName Name of the configuration property to be set. All constants
|
||||||
|
* are defined in the aiConfig.h header file.
|
||||||
|
* \param value New value for the property
|
||||||
|
*/
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
ASSIMP_API void aiSetImportPropertyInteger(const char* szName, int value);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @see aiSetImportPropertyInteger()
|
||||||
|
*/
|
||||||
|
ASSIMP_API void aiSetImportPropertyFloat(const char* szName, float value);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @see aiSetImportPropertyInteger()
|
||||||
|
*/
|
||||||
|
ASSIMP_API void aiSetImportPropertyString(const char* szName,
|
||||||
|
const C_STRUCT aiString* st);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// STL headers
|
// STL headers
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// public ASSIMP headers
|
// public ASSIMP headers
|
||||||
|
@ -67,6 +68,8 @@ namespace Assimp
|
||||||
#define AI_PROPERTY_WAS_NOT_EXISTING 0xffffffff
|
#define AI_PROPERTY_WAS_NOT_EXISTING 0xffffffff
|
||||||
|
|
||||||
struct aiScene;
|
struct aiScene;
|
||||||
|
struct aiFileIO;
|
||||||
|
const aiScene* aiImportFileEx( const char*, unsigned int, aiFileIO*);
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp
|
||||||
{
|
{
|
||||||
|
@ -101,28 +104,14 @@ class ASSIMP_API Importer
|
||||||
{
|
{
|
||||||
// used internally
|
// used internally
|
||||||
friend class BaseProcess;
|
friend class BaseProcess;
|
||||||
|
friend const aiScene* ::aiImportFileEx( const char*, unsigned int, aiFileIO*);
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
|
|
||||||
template <typename Type>
|
typedef uint32_t KeyType;
|
||||||
struct PropertyInfo
|
typedef std::map<KeyType, int> IntPropertyMap;
|
||||||
{
|
typedef std::map<KeyType, float> FloatPropertyMap;
|
||||||
std::string name;
|
typedef std::map<KeyType, std::string> StringPropertyMap;
|
||||||
Type value;
|
|
||||||
|
|
||||||
bool operator==(const PropertyInfo<Type>& other) const
|
|
||||||
{
|
|
||||||
return other.name == this->name &&
|
|
||||||
other.value == this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const PropertyInfo<Type>& other) const
|
|
||||||
{
|
|
||||||
return !(other == *this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef PropertyInfo<int> IntPropertyInfo;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -188,28 +177,66 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Set a configuration property.
|
/** Set an integer configuration property.
|
||||||
* @param szName Name of the property. All supported properties
|
* @param szName Name of the property. All supported properties
|
||||||
* are defined in the aiConfig.g header (the constants share the
|
* are defined in the aiConfig.g header (all constants share the
|
||||||
* prefix AI_CONFIG_XXX).
|
* prefix AI_CONFIG_XXX).
|
||||||
* @param iValue New value of the property
|
* @param iValue New value of the property
|
||||||
* @return Old value of the property or AI_PROPERTY_WAS_NOT_EXISTING
|
* @param bWasExisting Optional pointer to receive true if the
|
||||||
* if the property has not yet been set.
|
* property was set before. The new value replaced the old value
|
||||||
|
* in this case.
|
||||||
|
* @note Property of different types (float, int, string ..) are kept
|
||||||
|
* on different stacks, so calling SetPropertyInteger() for a
|
||||||
|
* floating-point property has no effect - the loader will call
|
||||||
|
* GetPropertyFloat() to read the property, but it won't be there.
|
||||||
*/
|
*/
|
||||||
int SetProperty(const char* szName, int iValue);
|
void SetPropertyInteger(const char* szName, int iValue,
|
||||||
|
bool* bWasExisting = NULL);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Set a floating-point configuration property.
|
||||||
|
* @see SetPropertyInteger()
|
||||||
|
*/
|
||||||
|
void SetPropertyFloat(const char* szName, float fValue,
|
||||||
|
bool* bWasExisting = NULL);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Set a string configuration property.
|
||||||
|
* @see SetPropertyInteger()
|
||||||
|
*/
|
||||||
|
void SetPropertyString(const char* szName, const std::string& sValue,
|
||||||
|
bool* bWasExisting = NULL);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Get a configuration property.
|
/** Get a configuration property.
|
||||||
* @param szName Name of the property. All supported properties
|
* @param szName Name of the property. All supported properties
|
||||||
* are defined in the aiConfig.g header (the constants start
|
* are defined in the aiConfig.g header (all constants share the
|
||||||
* with AI_CONFIG_XXX).
|
* prefix AI_CONFIG_XXX).
|
||||||
* @param iErrorReturn Value that is returned if the property
|
* @param iErrorReturn Value that is returned if the property
|
||||||
* is not found. Note that this value, not the default value
|
* is not found.
|
||||||
* for the requested property is returned!
|
|
||||||
* @return Current value of the property
|
* @return Current value of the property
|
||||||
|
* @note Property of different types (float, int, string ..) are kept
|
||||||
|
* on different lists, so calling SetPropertyInteger() for a
|
||||||
|
* floating-point property has no effect - the loader will call
|
||||||
|
* GetPropertyFloat() to read the property, but it won't be there.
|
||||||
*/
|
*/
|
||||||
int GetProperty(const char* szName, int iErrorReturn = 0xffffffff) const;
|
int GetPropertyInteger(const char* szName,
|
||||||
|
int iErrorReturn = 0xffffffff) const;
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Get a floating-point configuration property
|
||||||
|
* @see GetPropertyInteger()
|
||||||
|
*/
|
||||||
|
float GetPropertyFloat(const char* szName,
|
||||||
|
float fErrorReturn = 10e10f) const;
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Get a string configuration property
|
||||||
|
* @see GetPropertyInteger()
|
||||||
|
*/
|
||||||
|
std::string GetPropertyString(const char* szName,
|
||||||
|
const std::string& sErrorReturn = "") const;
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
@ -278,10 +305,11 @@ public:
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns whether a given file extension is supported by ASSIMP
|
/** Returns whether a given file extension is supported by ASSIMP.
|
||||||
*
|
*
|
||||||
* @param szExtension Extension to be checked.
|
* @param szExtension Extension to be checked.
|
||||||
* Must include a leading dot '.'. Example: ".3ds", ".md3"
|
* Must include a trailing dot '.'. Example: ".3ds", ".md3".
|
||||||
|
* Cases-insensitive.
|
||||||
* @return true if the extension is supported, false otherwise
|
* @return true if the extension is supported, false otherwise
|
||||||
*/
|
*/
|
||||||
bool IsExtensionSupported(const std::string& szExtension);
|
bool IsExtensionSupported(const std::string& szExtension);
|
||||||
|
@ -298,6 +326,18 @@ public:
|
||||||
void GetExtensionList(std::string& szOut);
|
void GetExtensionList(std::string& szOut);
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Find the loader corresponding to a specific file extension.
|
||||||
|
*
|
||||||
|
* This is quite similar to IsExtensionSupported() except a
|
||||||
|
* BaseImporter instance is returned.
|
||||||
|
* @param szExtension Extension to be checke, cases insensitive,
|
||||||
|
* must include a trailing dot.
|
||||||
|
* @return NULL if there is no loader for the extension.
|
||||||
|
*/
|
||||||
|
BaseImporter* FindLoader (const std::string& szExtension);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Returns the scene loaded by the last successful call to ReadFile()
|
/** Returns the scene loaded by the last successful call to ReadFile()
|
||||||
*
|
*
|
||||||
|
@ -351,9 +391,17 @@ protected:
|
||||||
std::string mErrorString;
|
std::string mErrorString;
|
||||||
|
|
||||||
/** List of integer properties */
|
/** List of integer properties */
|
||||||
std::vector<IntPropertyInfo> mIntProperties;
|
IntPropertyMap mIntProperties;
|
||||||
|
|
||||||
/** Used for testing */
|
/** List of floating-point properties */
|
||||||
|
FloatPropertyMap mFloatProperties;
|
||||||
|
|
||||||
|
/** List of string properties */
|
||||||
|
StringPropertyMap mStringProperties;
|
||||||
|
|
||||||
|
/** Used for testing - extra verbose mode causes the
|
||||||
|
validateDataStructure-Step to be executed before
|
||||||
|
and after every single postprocess step */
|
||||||
bool bExtraVerbose;
|
bool bExtraVerbose;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ package assimp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines configuration properties.
|
* Defines configuration properties.
|
||||||
*
|
* <p/>
|
||||||
* Static helper class, can't be instanced. It defines configuration
|
* Static helper class, can't be instanced. It defines configuration
|
||||||
* property keys to be used with <code> Importer.setPropertyInt</code>
|
* property keys to be used with <code> Importer.setPropertyInt</code>
|
||||||
*
|
*
|
||||||
|
@ -57,7 +57,6 @@ public class ConfigProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default value for the <code>CONFIG_PP_SLM_TRIANGLE_LIMIT</code>
|
* Default value for the <code>CONFIG_PP_SLM_TRIANGLE_LIMIT</code>
|
||||||
* configuration property.
|
* configuration property.
|
||||||
|
@ -79,15 +78,13 @@ public class ConfigProperty {
|
||||||
public static final int DEFAULT_LBW_MAX_WEIGHTS = 4;
|
public static final int DEFAULT_LBW_MAX_WEIGHTS = 4;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the maximum number of vertices in a mesh.
|
* Set the maximum number of vertices in a mesh.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is used by the "SplitLargeMeshes" PostProcess-Step to determine
|
* This is used by the "SplitLargeMeshes" PostProcess-Step to determine
|
||||||
* whether a mesh must be splitted or not.
|
* whether a mesh must be splitted or not.
|
||||||
* \note The default value is <code>DEFAULT_SLM_MAX_TRIANGLES</code>
|
* note: The default value is <code>DEFAULT_SLM_MAX_TRIANGLES</code>.
|
||||||
|
* The type of the property is int.
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_PP_SLM_TRIANGLE_LIMIT
|
public static final String CONFIG_PP_SLM_TRIANGLE_LIMIT
|
||||||
= "pp.slm.triangle_limit";
|
= "pp.slm.triangle_limit";
|
||||||
|
@ -98,7 +95,8 @@ public class ConfigProperty {
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is used by the "SplitLargeMeshes" PostProcess-Step to determine
|
* This is used by the "SplitLargeMeshes" PostProcess-Step to determine
|
||||||
* whether a mesh must be splitted or not.
|
* whether a mesh must be splitted or not.
|
||||||
* \note The default value is <code>DEFAULT_SLM_MAX_VERTICES</code>
|
* note: The default value is <code>DEFAULT_SLM_MAX_VERTICES</code>.
|
||||||
|
* The type of the property is int.
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_PP_SLM_VERTEX_LIMIT
|
public static final String CONFIG_PP_SLM_VERTEX_LIMIT
|
||||||
= "pp.slm.vertex_limit";
|
= "pp.slm.vertex_limit";
|
||||||
|
@ -108,7 +106,8 @@ public class ConfigProperty {
|
||||||
* Set the maximum number of bones affecting a single vertex
|
* Set the maximum number of bones affecting a single vertex
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is used by the aiProcess_LimitBoneWeights PostProcess-Step.
|
* This is used by the aiProcess_LimitBoneWeights PostProcess-Step.
|
||||||
* \note The default value is <code>DEFAULT_LBW_MAX_WEIGHTS</code>
|
* note :The default value is <code>DEFAULT_LBW_MAX_WEIGHTS</code>.
|
||||||
|
* The type of the property is int.
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_PP_LBW_MAX_WEIGHTS
|
public static final String CONFIG_PP_LBW_MAX_WEIGHTS
|
||||||
= "pp.lbw.weights_limit";
|
= "pp.lbw.weights_limit";
|
||||||
|
@ -126,6 +125,7 @@ public class ConfigProperty {
|
||||||
* <code>CONFIG_IMPORT_XXX_KEYFRAME</code> options (where XXX is a
|
* <code>CONFIG_IMPORT_XXX_KEYFRAME</code> options (where XXX is a
|
||||||
* placeholder for the file format for which you want to override the
|
* placeholder for the file format for which you want to override the
|
||||||
* global setting).
|
* global setting).
|
||||||
|
* The type of the property is int.
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_IMPORT_GLOBAL_KEYFRAME
|
public static final String CONFIG_IMPORT_GLOBAL_KEYFRAME
|
||||||
= "imp.global.kf";
|
= "imp.global.kf";
|
||||||
|
@ -144,11 +144,60 @@ public class ConfigProperty {
|
||||||
* There are some faulty 3DS files on the internet which look
|
* There are some faulty 3DS files on the internet which look
|
||||||
* only correctly with pivot points disabled. By default,
|
* only correctly with pivot points disabled. By default,
|
||||||
* this option is disabled.
|
* this option is disabled.
|
||||||
|
* note: This is a boolean property stored as an integer, 0 is false
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_IMPORT_3DS_IGNORE_PIVOT
|
public static final String CONFIG_IMPORT_3DS_IGNORE_PIVOT
|
||||||
= "imp.3ds.nopivot";
|
= "imp.3ds.nopivot";
|
||||||
|
|
||||||
public static final String CONFIG_PP_OG_MAX_DEPTH = "pp.og.max_depth";
|
|
||||||
public static final String CONFIG_PP_OG_MIN_TRIS_PER_NODE = "pp.og.min_tris";
|
/**
|
||||||
public static final String CONFIG_PP_OG_MAXIMALLY_SMALL = "pp.og.maximally_small";
|
* Specifies the maximum angle that may be between two vertex tangents
|
||||||
|
* that their tangents and bitangents are smoothed.
|
||||||
|
* <p/>
|
||||||
|
* This applies to the CalcTangentSpace-Step. The angle is specified
|
||||||
|
* in degrees, so 180 is PI. The default value is
|
||||||
|
* 45 degrees. The maximum value is 180.f
|
||||||
|
* The type of the property is float.
|
||||||
|
*/
|
||||||
|
public static final String AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE
|
||||||
|
= "pp.ct.max_smoothing";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the maximum angle that may be between two face normals
|
||||||
|
* at the same vertex position that their are smoothed.
|
||||||
|
* <p/>
|
||||||
|
* This applies to the GenSmoothNormals-Step. The angle is specified
|
||||||
|
* in degrees * 1000, so 180.f is PI. The default value is
|
||||||
|
* 180 degrees (all vertex normals are smoothed). The maximum value is 180.f
|
||||||
|
* The type of the property is float.
|
||||||
|
*/
|
||||||
|
public static final String AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE
|
||||||
|
= "pp.gsn.max_smoothing";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the minimum number of faces a node should have.
|
||||||
|
* This is an input parameter to the OptimizeGraph-Step.
|
||||||
|
* <p/>
|
||||||
|
* Nodes whose referenced meshes have less faces than this value
|
||||||
|
* are propably joined with neighbors with identical world matrices.
|
||||||
|
* However, it is just a hint to the step.
|
||||||
|
* The type of the property is int.
|
||||||
|
*/
|
||||||
|
public static final String AI_CONFIG_PP_OG_MIN_NUM_FACES
|
||||||
|
= "pp.og.min_faces";
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Specifies whether animations are removed from the asset.
|
||||||
|
* This is an input parameter to the OptimizeGraph-Step.
|
||||||
|
*
|
||||||
|
* If an application does not need the animation data, erasing it at the
|
||||||
|
* beginning of the post-process pipeline allows some steps - including
|
||||||
|
* OptimizeGraph itself - to apply further optimizations.
|
||||||
|
* note: This is a boolean property stored as an integer, 0 is false
|
||||||
|
*/
|
||||||
|
public static final String AI_CONFIG_PP_OG_REMOVE_ANIMATIONS
|
||||||
|
= "pp.og.remove_anims";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,38 @@ public class Importer {
|
||||||
Type value;
|
Type value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a property list
|
||||||
|
*/
|
||||||
|
private class PropertyList<Type> extends Vector<Property<Type>> {
|
||||||
|
|
||||||
|
public void setProperty(final String prop, final Type val) {
|
||||||
|
|
||||||
|
for (Property<Type> i : this) {
|
||||||
|
if (i.key.equals(prop)) {
|
||||||
|
i.value = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Property<Type> propNew = new Property<Type>();
|
||||||
|
propNew.key = prop;
|
||||||
|
propNew.value = val;
|
||||||
|
this.add(propNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getProperty(final String prop) {
|
||||||
|
|
||||||
|
for (Property<Type> i : this) {
|
||||||
|
if (i.key.equals(prop)) {
|
||||||
|
return i.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of <code>IOStream</code>.
|
* Default implementation of <code>IOStream</code>.
|
||||||
* <br>
|
* <br>
|
||||||
|
@ -158,12 +190,14 @@ public class Importer {
|
||||||
/**
|
/**
|
||||||
* I/O system to be used
|
* I/O system to be used
|
||||||
*/
|
*/
|
||||||
private IOSystem ioSystem = null;
|
private IOSystem ioSystem = new DefaultIOSystem();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of config properties
|
* List of config properties for all supported types: int, float and string
|
||||||
*/
|
*/
|
||||||
private Vector<Property<Integer>> properties;
|
private PropertyList<Integer> properties = new PropertyList<Integer>();
|
||||||
|
private PropertyList<Float> propertiesFloat = new PropertyList<Float>();
|
||||||
|
private PropertyList<String> propertiesString = new PropertyList<String>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -186,14 +220,11 @@ public class Importer {
|
||||||
*
|
*
|
||||||
* @param iVersion Version of the JNI interface to be used.
|
* @param iVersion Version of the JNI interface to be used.
|
||||||
* @throws NativeException Thrown if the jassimp library could not be loaded
|
* @throws NativeException Thrown if the jassimp library could not be loaded
|
||||||
* or if the entry point to the module wasn't found. if this exception
|
* or if the entry point to the module wasn't found. if this exception
|
||||||
* is not thrown, you can assume that jAssimp is fully available.
|
* is not thrown, you can assume that jAssimp is fully available.
|
||||||
*/
|
*/
|
||||||
public Importer(int iVersion) throws NativeException {
|
public Importer(int iVersion) throws NativeException {
|
||||||
|
|
||||||
// allocate a default I/O system
|
|
||||||
ioSystem = new DefaultIOSystem();
|
|
||||||
|
|
||||||
if (!bLibInitialized) {
|
if (!bLibInitialized) {
|
||||||
|
|
||||||
/** try to load the jassimp library. First try to load the
|
/** try to load the jassimp library. First try to load the
|
||||||
|
@ -319,7 +350,7 @@ public class Importer {
|
||||||
* @param path Path to the file to be read
|
* @param path Path to the file to be read
|
||||||
* @return null if the import failed, otherwise a valid Scene instance
|
* @return null if the import failed, otherwise a valid Scene instance
|
||||||
* @throws NativeException This exception is thrown when an unknown error
|
* @throws NativeException This exception is thrown when an unknown error
|
||||||
* occurs in the JNI bridge module.
|
* occurs in the JNI bridge module.
|
||||||
*/
|
*/
|
||||||
public final Scene readFile(String path) throws NativeException {
|
public final Scene readFile(String path) throws NativeException {
|
||||||
this.scene = new Scene(this);
|
this.scene = new Scene(this);
|
||||||
|
@ -346,8 +377,10 @@ public class Importer {
|
||||||
else if (step.equals(PostProcessStep.PreTransformVertices)) flags |= 0x100;
|
else if (step.equals(PostProcessStep.PreTransformVertices)) flags |= 0x100;
|
||||||
else if (step.equals(PostProcessStep.LimitBoneWeights)) flags |= 0x200;
|
else if (step.equals(PostProcessStep.LimitBoneWeights)) flags |= 0x200;
|
||||||
else if (step.equals(PostProcessStep.ValidateDataStructure)) flags |= 0x400;
|
else if (step.equals(PostProcessStep.ValidateDataStructure)) flags |= 0x400;
|
||||||
else if (step.equals(PostProcessStep.FixInfacingNormals)) flags |= 0x800;
|
else if (step.equals(PostProcessStep.ImproveVertexLocality)) flags |= 0x800;
|
||||||
else if (step.equals(PostProcessStep.ImproveVertexLocality)) flags |= 0x1600;
|
else if (step.equals(PostProcessStep.RemoveRedundantMaterials)) flags |= 0x1000;
|
||||||
|
else if (step.equals(PostProcessStep.FixInfacingNormals)) flags |= 0x2000;
|
||||||
|
else if (step.equals(PostProcessStep.OptimizeGraph)) flags |= 0x4000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now load the mesh
|
// now load the mesh
|
||||||
|
@ -418,30 +451,39 @@ public class Importer {
|
||||||
*
|
*
|
||||||
* @param prop Name of the config property
|
* @param prop Name of the config property
|
||||||
* @param val New value for the config property
|
* @param val New value for the config property
|
||||||
* @return Old value of the property or <code>PROPERTY_WAS_NOT_EXISTING</code>
|
|
||||||
* if the property has not yet been set.
|
|
||||||
*/
|
*/
|
||||||
public final int setPropertyInt(final String prop, int val) {
|
public final void setPropertyInt(final String prop, int val) {
|
||||||
|
|
||||||
for (Property<Integer> i : this.properties) {
|
this.properties.setProperty(prop, val);
|
||||||
if (i.key.equals(prop)) {
|
|
||||||
int old = i.value;
|
|
||||||
i.value = val;
|
|
||||||
|
|
||||||
// make sure all changes are sent to the native implementation
|
|
||||||
this._NativeSetPropertyInt(prop, val, this.getContext());
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Property<Integer> propNew = new Property<Integer>();
|
|
||||||
propNew.key = prop;
|
|
||||||
propNew.value = val;
|
|
||||||
this.properties.add(propNew);
|
|
||||||
|
|
||||||
// make sure all changes are sent to the native implementation
|
|
||||||
this._NativeSetPropertyInt(prop, val, this.getContext());
|
this._NativeSetPropertyInt(prop, val, this.getContext());
|
||||||
return PROPERTY_WAS_NOT_EXISTING;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a floating-point property. All supported config properties are
|
||||||
|
* defined as constants in the <code>ConfigProperty</code> class
|
||||||
|
*
|
||||||
|
* @param prop Name of the config property
|
||||||
|
* @param val New value for the config property
|
||||||
|
*/
|
||||||
|
public final void setPropertyFloat(final String prop, float val) {
|
||||||
|
|
||||||
|
this.propertiesFloat.setProperty(prop, val);
|
||||||
|
this._NativeSetPropertyFloat(prop, val, this.getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a string property. All supported config properties are
|
||||||
|
* defined as constants in the <code>ConfigProperty</code> class
|
||||||
|
*
|
||||||
|
* @param prop Name of the config property
|
||||||
|
* @param val New value for the config property
|
||||||
|
*/
|
||||||
|
public final void setPropertyString(final String prop, String val) {
|
||||||
|
|
||||||
|
this.propertiesString.setProperty(prop, val);
|
||||||
|
this._NativeSetPropertyString(prop, val, this.getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -457,12 +499,36 @@ public class Importer {
|
||||||
*/
|
*/
|
||||||
public final int getPropertyInt(final String prop, int error_return) {
|
public final int getPropertyInt(final String prop, int error_return) {
|
||||||
|
|
||||||
for (Property<Integer> i : this.properties) {
|
Integer i = this.properties.getProperty(prop);
|
||||||
if (i.key.equals(prop)) {
|
return i != null ? i : error_return;
|
||||||
return i.value;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return error_return;
|
/**
|
||||||
|
* Gets a floating-point config property that has been set using
|
||||||
|
* <code>setPropertyFloat</code>. All supported config properties are
|
||||||
|
* defined as constants in the <code>ConfigProperty</code> class
|
||||||
|
*
|
||||||
|
* @see <code>getPropertyInt</code>
|
||||||
|
*/
|
||||||
|
public final float getPropertyFloat(final String prop, float error_return) {
|
||||||
|
|
||||||
|
Float i = this.propertiesFloat.getProperty(prop);
|
||||||
|
return i != null ? i : error_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string config property that has been set using
|
||||||
|
* <code>setPropertyString</code>. All supported config properties are
|
||||||
|
* defined as constants in the <code>ConfigProperty</code> class
|
||||||
|
*
|
||||||
|
* @see <code>getPropertyInt</code>
|
||||||
|
*/
|
||||||
|
public final String getPropertyString(final String prop, String error_return) {
|
||||||
|
|
||||||
|
String i = this.propertiesString.getProperty(prop);
|
||||||
|
return i != null ? i : error_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -531,4 +597,12 @@ public class Importer {
|
||||||
* @return 0xffffffff if an error occured
|
* @return 0xffffffff if an error occured
|
||||||
*/
|
*/
|
||||||
private native int _NativeSetPropertyInt(String name, int prop, long iContext);
|
private native int _NativeSetPropertyInt(String name, int prop, long iContext);
|
||||||
|
|
||||||
|
// float-version
|
||||||
|
private native int _NativeSetPropertyFloat(String name,
|
||||||
|
float prop, long iContext);
|
||||||
|
|
||||||
|
// String-version
|
||||||
|
private native int _NativeSetPropertyString(String name,
|
||||||
|
String prop, long iContext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,7 +174,6 @@ public class PostProcessStep {
|
||||||
public static final PostProcessStep LimitBoneWeights =
|
public static final PostProcessStep LimitBoneWeights =
|
||||||
new PostProcessStep("LimitBoneWeights");
|
new PostProcessStep("LimitBoneWeights");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the aiScene data structure before it is returned.
|
* Validates the aiScene data structure before it is returned.
|
||||||
* This makes sure that all indices are valid, all animations and
|
* This makes sure that all indices are valid, all animations and
|
||||||
|
@ -187,19 +186,6 @@ public class PostProcessStep {
|
||||||
new PostProcessStep("ValidateDataStructure");
|
new PostProcessStep("ValidateDataStructure");
|
||||||
|
|
||||||
|
|
||||||
/** This step tries to determine which meshes have normal vectors
|
|
||||||
* that are facing inwards. The algorithm is simple but effective:
|
|
||||||
* the bounding box of all vertices + their normals is compared against
|
|
||||||
* the volume of the bounding box of all vertices without their normals.
|
|
||||||
* This works well for most objects, problems might occur with planar
|
|
||||||
* surfaces. However the step tries to filter such cases out.
|
|
||||||
* The step inverts all infacing normals. Generally it is recommended
|
|
||||||
* to enable this step.
|
|
||||||
*/
|
|
||||||
public static final PostProcessStep FixInfacingNormals =
|
|
||||||
new PostProcessStep("FixInfacingNormals");
|
|
||||||
|
|
||||||
|
|
||||||
/** Reorders triangles for vertex cache locality and thus better performance.
|
/** Reorders triangles for vertex cache locality and thus better performance.
|
||||||
* The step tries to improve the ACMR (average post-transform vertex cache
|
* The step tries to improve the ACMR (average post-transform vertex cache
|
||||||
* miss ratio) for all meshes. The step runs in O(n) and is roughly
|
* miss ratio) for all meshes. The step runs in O(n) and is roughly
|
||||||
|
@ -210,6 +196,46 @@ public class PostProcessStep {
|
||||||
new PostProcessStep("ImproveVertexLocality");
|
new PostProcessStep("ImproveVertexLocality");
|
||||||
|
|
||||||
|
|
||||||
|
/** Searches for redundant materials and removes them.
|
||||||
|
*
|
||||||
|
* This is especially useful in combination with the PretransformVertices
|
||||||
|
* and OptimizeGraph steps. Both steps join small meshes, but they
|
||||||
|
* can't do that if two meshes have different materials.
|
||||||
|
*/
|
||||||
|
public static final PostProcessStep RemoveRedundantMaterials =
|
||||||
|
new PostProcessStep("RemoveRedundantMaterials");
|
||||||
|
|
||||||
|
/** This step tries to determine which meshes have normal vectors
|
||||||
|
* that are facing inwards. The algorithm is simple but effective:
|
||||||
|
* the bounding box of all vertices + their normals is compared against
|
||||||
|
* the volume of the bounding box of all vertices without their normals.
|
||||||
|
* This works well for most objects, problems might occur with planar
|
||||||
|
* surfaces. However, the step tries to filter such cases.
|
||||||
|
* The step inverts all infacing normals. Generally it is recommended
|
||||||
|
* to enable this step, although the result is not always correct.
|
||||||
|
*/
|
||||||
|
public static final PostProcessStep FixInfacingNormals =
|
||||||
|
new PostProcessStep("FixInfacingNormals");
|
||||||
|
|
||||||
|
/** This step performs some optimizations on the node graph.
|
||||||
|
*
|
||||||
|
* It is incompatible to the PreTransformVertices-Step. Some configuration
|
||||||
|
* options exist, see aiConfig.h for more details.
|
||||||
|
* Generally, two actions are available:<br>
|
||||||
|
* 1. Remove animation nodes and data from the scene. This allows other
|
||||||
|
* steps for further optimizations.<br>
|
||||||
|
* 2. Combine very small meshes to larger ones. Only if the meshes
|
||||||
|
* are used by the same node or by nodes on the same hierarchy (with
|
||||||
|
* equal local transformations). Unlike PreTransformVertices, the
|
||||||
|
* OptimizeGraph-step doesn't transform vertices from one space
|
||||||
|
* another.<br>
|
||||||
|
* 3. Remove hierarchy levels<br>
|
||||||
|
*
|
||||||
|
* It is recommended to have this step run with the default configuration.
|
||||||
|
*/
|
||||||
|
public static final PostProcessStep OptimizeGraph =
|
||||||
|
new PostProcessStep("OptimizeGraph");
|
||||||
|
|
||||||
private final String myName; // for debug only
|
private final String myName; // for debug only
|
||||||
|
|
||||||
private PostProcessStep(String name) {
|
private PostProcessStep(String name) {
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
#include "utImporter.h"
|
||||||
|
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION (ImporterTest);
|
||||||
|
|
||||||
|
#define AIUT_DEF_ERROR_TEXT "sorry, this is a test"
|
||||||
|
|
||||||
|
|
||||||
|
bool TestPlugin :: CanRead( const std::string& pFile,
|
||||||
|
IOSystem* pIOHandler) const
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
// todo ... make case-insensitive
|
||||||
|
return (extension == ".apple" || extension == ".mac" ||
|
||||||
|
extension == ".linux" || extension == ".windows" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPlugin :: GetExtensionList(std::string& append)
|
||||||
|
{
|
||||||
|
append.append("*.apple;*.mac;*.linux;*.windows");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPlugin :: InternReadFile( const std::string& pFile,
|
||||||
|
aiScene* pScene, IOSystem* pIOHandler)
|
||||||
|
{
|
||||||
|
throw new ImportErrorException(AIUT_DEF_ERROR_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ImporterTest :: setUp (void)
|
||||||
|
{
|
||||||
|
pImp = new Importer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImporterTest :: tearDown (void)
|
||||||
|
{
|
||||||
|
delete pImp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImporterTest :: testIntProperty (void)
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
pImp->SetPropertyInteger("quakquak",1503,&b);
|
||||||
|
CPPUNIT_ASSERT(!b);
|
||||||
|
CPPUNIT_ASSERT(1503 == pImp->GetPropertyInteger("quakquak",0));
|
||||||
|
CPPUNIT_ASSERT(314159 == pImp->GetPropertyInteger("not_there",314159));
|
||||||
|
|
||||||
|
pImp->SetPropertyInteger("quakquak",1504,&b);
|
||||||
|
CPPUNIT_ASSERT(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImporterTest :: testFloatProperty (void)
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
pImp->SetPropertyFloat("quakquak",1503.f,&b);
|
||||||
|
CPPUNIT_ASSERT(!b);
|
||||||
|
CPPUNIT_ASSERT(1503.f == pImp->GetPropertyFloat("quakquak",0.f));
|
||||||
|
CPPUNIT_ASSERT(314159.f == pImp->GetPropertyFloat("not_there",314159.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImporterTest :: testStringProperty (void)
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
pImp->SetPropertyString("quakquak","test",&b);
|
||||||
|
CPPUNIT_ASSERT(!b);
|
||||||
|
CPPUNIT_ASSERT("test" == pImp->GetPropertyString("quakquak","weghwekg"));
|
||||||
|
CPPUNIT_ASSERT("ILoveYou" == pImp->GetPropertyString("not_there","ILoveYou"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImporterTest :: testPluginInterface (void)
|
||||||
|
{
|
||||||
|
pImp->RegisterLoader(new TestPlugin());
|
||||||
|
CPPUNIT_ASSERT(pImp->IsExtensionSupported(".apple"));
|
||||||
|
CPPUNIT_ASSERT(pImp->IsExtensionSupported(".mac"));
|
||||||
|
CPPUNIT_ASSERT(pImp->IsExtensionSupported(".linux"));
|
||||||
|
CPPUNIT_ASSERT(pImp->IsExtensionSupported(".windows"));
|
||||||
|
|
||||||
|
TestPlugin* p = (TestPlugin*) pImp->FindLoader(".windows");
|
||||||
|
CPPUNIT_ASSERT(NULL != p);
|
||||||
|
|
||||||
|
try {
|
||||||
|
p->InternReadFile("",0,NULL);
|
||||||
|
}
|
||||||
|
catch ( ImportErrorException* ex)
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT(ex->GetErrorText() == AIUT_DEF_ERROR_TEXT);
|
||||||
|
|
||||||
|
// unregister the plugin and delete it
|
||||||
|
pImp->UnregisterLoader(p);
|
||||||
|
delete p;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(false); // control shouldn't reach this point
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImporterTest :: testExtensionCheck (void)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
pImp->GetExtensionList(s);
|
||||||
|
|
||||||
|
// todo ..
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef TESTIMPORTER_H
|
||||||
|
#define TESTIMPORTER_H
|
||||||
|
|
||||||
|
#include <cppunit/TestFixture.h>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
#include <assimp.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Assimp;
|
||||||
|
|
||||||
|
class ImporterTest : public CPPUNIT_NS :: TestFixture
|
||||||
|
{
|
||||||
|
CPPUNIT_TEST_SUITE (ImporterTest);
|
||||||
|
CPPUNIT_TEST (testIntProperty);
|
||||||
|
CPPUNIT_TEST (testFloatProperty);
|
||||||
|
CPPUNIT_TEST (testStringProperty);
|
||||||
|
CPPUNIT_TEST (testPluginInterface);
|
||||||
|
CPPUNIT_TEST (testExtensionCheck);
|
||||||
|
CPPUNIT_TEST_SUITE_END ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setUp (void);
|
||||||
|
void tearDown (void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void testIntProperty (void);
|
||||||
|
void testFloatProperty (void);
|
||||||
|
void testStringProperty (void);
|
||||||
|
|
||||||
|
void testPluginInterface (void);
|
||||||
|
void testExtensionCheck (void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Importer* pImp;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestPlugin : public BaseImporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// overriden
|
||||||
|
bool CanRead( const std::string& pFile,
|
||||||
|
IOSystem* pIOHandler) const;
|
||||||
|
|
||||||
|
// overriden
|
||||||
|
void GetExtensionList(std::string& append);
|
||||||
|
|
||||||
|
// overriden
|
||||||
|
void InternReadFile( const std::string& pFile,
|
||||||
|
aiScene* pScene, IOSystem* pIOHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,85 @@
|
||||||
|
|
||||||
|
#include "utJoinVertices.h"
|
||||||
|
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION (JoinVerticesTest);
|
||||||
|
|
||||||
|
void JoinVerticesTest :: setUp (void)
|
||||||
|
{
|
||||||
|
// construct the process
|
||||||
|
this->piProcess = new JoinVerticesProcess();
|
||||||
|
|
||||||
|
// create a quite small mesh for testing purposes -
|
||||||
|
// the mesh itself is *something* but it has redundant vertices
|
||||||
|
this->pcMesh = new aiMesh();
|
||||||
|
|
||||||
|
pcMesh->mNumVertices = 900;
|
||||||
|
aiVector3D*& pv = pcMesh->mVertices = new aiVector3D[900];
|
||||||
|
for (unsigned int i = 0; i < 3;++i)
|
||||||
|
{
|
||||||
|
const unsigned int base = i*300;
|
||||||
|
for (unsigned int a = 0; a < 300;++a)
|
||||||
|
{
|
||||||
|
pv[base+a].x = pv[base+a].y = pv[base+a].z = (float)a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate faces - each vertex is referenced once
|
||||||
|
pcMesh->mNumFaces = 300;
|
||||||
|
pcMesh->mFaces = new aiFace[300];
|
||||||
|
for (unsigned int i = 0,p = 0; i < 300;++i)
|
||||||
|
{
|
||||||
|
aiFace& face = pcMesh->mFaces[i];
|
||||||
|
face.mIndices = new unsigned int[ face.mNumIndices = 3 ];
|
||||||
|
for (unsigned int a = 0; a < 3;++a)
|
||||||
|
face.mIndices[a] = p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate extra members - set them to zero to make sure they're identical
|
||||||
|
pcMesh->mTextureCoords[0] = new aiVector3D[900];
|
||||||
|
for (unsigned int i = 0; i < 900;++i)pcMesh->mTextureCoords[0][i] = 0.f;
|
||||||
|
|
||||||
|
pcMesh->mNormals = new aiVector3D[900];
|
||||||
|
for (unsigned int i = 0; i < 900;++i)pcMesh->mNormals[i] = 0.f;
|
||||||
|
|
||||||
|
pcMesh->mTangents = new aiVector3D[900];
|
||||||
|
for (unsigned int i = 0; i < 900;++i)pcMesh->mTangents[i] = 0.f;
|
||||||
|
|
||||||
|
pcMesh->mBitangents = new aiVector3D[900];
|
||||||
|
for (unsigned int i = 0; i < 900;++i)pcMesh->mBitangents[i] = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinVerticesTest :: tearDown (void)
|
||||||
|
{
|
||||||
|
delete this->pcMesh;
|
||||||
|
delete this->piProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinVerticesTest :: testProcess(void)
|
||||||
|
{
|
||||||
|
// execute the step on the given data
|
||||||
|
this->piProcess->ProcessMesh(this->pcMesh,0);
|
||||||
|
|
||||||
|
// the number of faces shouldn't change
|
||||||
|
CPPUNIT_ASSERT(pcMesh->mNumFaces == 300);
|
||||||
|
CPPUNIT_ASSERT(pcMesh->mNumVertices == 300);
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(NULL != pcMesh->mNormals);
|
||||||
|
CPPUNIT_ASSERT(NULL != pcMesh->mTangents);
|
||||||
|
CPPUNIT_ASSERT(NULL != pcMesh->mBitangents);
|
||||||
|
CPPUNIT_ASSERT(NULL != pcMesh->mTextureCoords[0]);
|
||||||
|
|
||||||
|
// the order doesn't care
|
||||||
|
float fSum = 0.f;
|
||||||
|
for (unsigned int i = 0; i < 300;++i)
|
||||||
|
{
|
||||||
|
aiVector3D& v = pcMesh->mVertices[i];
|
||||||
|
fSum += v.x + v.y + v.z;
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(!pcMesh->mNormals[i].x);
|
||||||
|
CPPUNIT_ASSERT(!pcMesh->mTangents[i].x);
|
||||||
|
CPPUNIT_ASSERT(!pcMesh->mBitangents[i].x);
|
||||||
|
CPPUNIT_ASSERT(!pcMesh->mTextureCoords[0][i].x);
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(fSum == 150.f*299.f*3.f); // gaussian sum equation
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef TESTLBW_H
|
||||||
|
#define TESTLBW_H
|
||||||
|
|
||||||
|
#include <cppunit/TestFixture.h>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
#include <aiScene.h>
|
||||||
|
#include <JoinVerticesProcess.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Assimp;
|
||||||
|
|
||||||
|
class JoinVerticesTest : public CPPUNIT_NS :: TestFixture
|
||||||
|
{
|
||||||
|
CPPUNIT_TEST_SUITE (JoinVerticesTest);
|
||||||
|
CPPUNIT_TEST (testProcess);
|
||||||
|
CPPUNIT_TEST_SUITE_END ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setUp (void);
|
||||||
|
void tearDown (void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void testProcess (void);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
JoinVerticesProcess* piProcess;
|
||||||
|
aiMesh* pcMesh;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,8 +4,6 @@
|
||||||
#include <cppunit/TestFixture.h>
|
#include <cppunit/TestFixture.h>
|
||||||
#include <cppunit/extensions/HelperMacros.h>
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
#include <aiTypes.h>
|
|
||||||
#include <aiMesh.h>
|
|
||||||
#include <aiScene.h>
|
#include <aiScene.h>
|
||||||
#include <LimitBoneWeightsProcess.h>
|
#include <LimitBoneWeightsProcess.h>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef TESTOG_H
|
||||||
|
#define TESTOG_H
|
||||||
|
|
||||||
|
#include <cppunit/TestFixture.h>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
#include <aiScene.h>
|
||||||
|
#include <OptimizeGraphProcess.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Assimp;
|
||||||
|
|
||||||
|
class OptimizeGraphProcessTest : public CPPUNIT_NS :: TestFixture
|
||||||
|
{
|
||||||
|
CPPUNIT_TEST_SUITE (OptimizeGraphProcessTest);
|
||||||
|
CPPUNIT_TEST (testProcess);
|
||||||
|
CPPUNIT_TEST_SUITE_END ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setUp (void);
|
||||||
|
void tearDown (void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void testProcess (void);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
OptimizeGraphProcess* piProcess;
|
||||||
|
aiScene* pcMesh;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -134,7 +134,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
|
||||||
aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space
|
aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space
|
||||||
aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes
|
aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes
|
||||||
aiProcess_ValidateDataStructure | aiProcess_ImproveCacheLocality
|
aiProcess_ValidateDataStructure | aiProcess_ImproveCacheLocality
|
||||||
| aiProcess_RemoveRedundantMaterials | aiProcess_FixInfacingNormals); // validate the output data structure
|
| aiProcess_RemoveRedundantMaterials ); // validate the output data structure
|
||||||
|
|
||||||
// get the end time of zje operation, calculate delta t
|
// get the end time of zje operation, calculate delta t
|
||||||
double fEnd = (double)timeGetTime();
|
double fEnd = (double)timeGetTime();
|
||||||
|
|
|
@ -178,7 +178,7 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://J:/Programmieren/ASSIMP/ASSIMP3/port/jAssimp/assimp.iml" filepath="J:/Programmieren/ASSIMP/ASSIMP3/port/jAssimp/assimp.iml" />
|
<module fileurl="file://J:/Programmieren/ASSIMP/assimp3/trunk/port/jAssimp/assimp.iml" filepath="J:/Programmieren/ASSIMP/assimp3/trunk/port/jAssimp/assimp.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" />
|
<component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" />
|
||||||
|
|
|
@ -683,6 +683,10 @@
|
||||||
RelativePath="..\..\test\unit\utGenNormals.cpp"
|
RelativePath="..\..\test\unit\utGenNormals.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\test\unit\utImporter.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\test\unit\utImproveCacheLocality.cpp"
|
RelativePath="..\..\test\unit\utImproveCacheLocality.cpp"
|
||||||
>
|
>
|
||||||
|
@ -699,6 +703,10 @@
|
||||||
RelativePath="..\..\test\unit\utMaterialSystem.cpp"
|
RelativePath="..\..\test\unit\utMaterialSystem.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\test\unit\utOptimizeGraph.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\test\unit\utPretransformVertices.cpp"
|
RelativePath="..\..\test\unit\utPretransformVertices.cpp"
|
||||||
>
|
>
|
||||||
|
@ -733,6 +741,14 @@
|
||||||
RelativePath="..\..\test\unit\utGenNormals.h"
|
RelativePath="..\..\test\unit\utGenNormals.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\test\unit\utImporter.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\test\unit\utJoinVertices.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\test\unit\utLimitBoneWeights.h"
|
RelativePath="..\..\test\unit\utLimitBoneWeights.h"
|
||||||
>
|
>
|
||||||
|
@ -741,6 +757,10 @@
|
||||||
RelativePath="..\..\test\unit\utMaterialSystem.h"
|
RelativePath="..\..\test\unit\utMaterialSystem.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\test\unit\utOptimizeGraph.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\test\unit\utPretransformVertices.h"
|
RelativePath="..\..\test\unit\utPretransformVertices.h"
|
||||||
>
|
>
|
||||||
|
|
|
@ -734,6 +734,10 @@
|
||||||
RelativePath="..\..\code\FixNormalsStep.h"
|
RelativePath="..\..\code\FixNormalsStep.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\GenericProperty.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\GenFaceNormalsProcess.h"
|
RelativePath="..\..\code\GenFaceNormalsProcess.h"
|
||||||
>
|
>
|
||||||
|
@ -770,6 +774,10 @@
|
||||||
RelativePath="..\..\code\MaterialSystem.h"
|
RelativePath="..\..\code\MaterialSystem.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\OptimizeGraphProcess.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\ParsingUtils.h"
|
RelativePath="..\..\code\ParsingUtils.h"
|
||||||
>
|
>
|
||||||
|
@ -790,6 +798,18 @@
|
||||||
RelativePath="..\..\code\RemoveRedundantMaterials.h"
|
RelativePath="..\..\code\RemoveRedundantMaterials.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\SGSpatialSort.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\SmoothingGroups.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\SmoothingGroups.inl"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\SpatialSort.h"
|
RelativePath="..\..\code\SpatialSort.h"
|
||||||
>
|
>
|
||||||
|
@ -868,10 +888,6 @@
|
||||||
RelativePath="..\..\code\3DSLoader.h"
|
RelativePath="..\..\code\3DSLoader.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\code\3DSSpatialSort.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="ASE"
|
Name="ASE"
|
||||||
|
@ -886,7 +902,7 @@
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="HMPLoader"
|
Name="HMP"
|
||||||
>
|
>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\HMPFileData.h"
|
RelativePath="..\..\code\HMPFileData.h"
|
||||||
|
@ -1061,6 +1077,14 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="DXF"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\DXFLoader.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
|
@ -1138,6 +1162,10 @@
|
||||||
RelativePath="..\..\code\MaterialSystem.cpp"
|
RelativePath="..\..\code\MaterialSystem.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\OptimizeGraphProcess.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\PretransformVertices.cpp"
|
RelativePath="..\..\code\PretransformVertices.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1150,6 +1178,10 @@
|
||||||
RelativePath="..\..\code\RemoveRedundantMaterials.cpp"
|
RelativePath="..\..\code\RemoveRedundantMaterials.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\SGSpatialSort.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\SpatialSort.cpp"
|
RelativePath="..\..\code\SpatialSort.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1196,18 +1228,10 @@
|
||||||
RelativePath="..\..\code\3DSConverter.cpp"
|
RelativePath="..\..\code\3DSConverter.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\code\3DSGenNormals.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\3DSLoader.cpp"
|
RelativePath="..\..\code\3DSLoader.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\code\3DSSpatialSort.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="ASE"
|
Name="ASE"
|
||||||
|
@ -1345,6 +1369,14 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="DXF"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\DXFLoader.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
|
|
|
@ -238,22 +238,6 @@
|
||||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||||
>
|
>
|
||||||
<File
|
|
||||||
RelativePath="..\..\port\jAssimp\jni_bridge\assimp_Importer.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\port\jAssimp\jni_bridge\assimp_Importer_DefaultIOStream.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\port\jAssimp\jni_bridge\assimp_Importer_DefaultIOSystem.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\port\jAssimp\jni_bridge\assimp_Importer_Property.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\port\jAssimp\jni_bridge\JNIEnvironment.h"
|
RelativePath="..\..\port\jAssimp\jni_bridge\JNIEnvironment.h"
|
||||||
>
|
>
|
||||||
|
@ -262,6 +246,26 @@
|
||||||
RelativePath="..\..\port\jAssimp\jni_bridge\JNILogger.h"
|
RelativePath="..\..\port\jAssimp\jni_bridge\JNILogger.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<Filter
|
||||||
|
Name="javah"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\port\jAssimp\jni_bridge\assimp_Importer.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\port\jAssimp\jni_bridge\assimp_Importer_DefaultIOStream.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\port\jAssimp\jni_bridge\assimp_Importer_DefaultIOSystem.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\port\jAssimp\jni_bridge\assimp_Importer_Property.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="resources"
|
Name="resources"
|
||||||
|
|
Loading…
Reference in New Issue