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;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define sprintf sprintf_s
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ReplaceDefaultMaterial()
|
||||
{
|
||||
|
@ -130,70 +126,66 @@ void Dot3DSImporter::ReplaceDefaultMaterial()
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::CheckIndices(Dot3DS::Mesh* sMesh)
|
||||
void Dot3DSImporter::CheckIndices(Dot3DS::Mesh& sMesh)
|
||||
{
|
||||
for (std::vector< Dot3DS::Face >::iterator
|
||||
i = sMesh->mFaces.begin();
|
||||
i != sMesh->mFaces.end();++i)
|
||||
i = sMesh.mFaces.begin();
|
||||
i != sMesh.mFaces.end();++i)
|
||||
{
|
||||
// check whether all indices are in range
|
||||
if ((*i).mIndices[0] >= sMesh->mPositions.size())
|
||||
for (unsigned int a = 0; a < 3;++a)
|
||||
{
|
||||
DefaultLogger::get()->warn("Face index overflow in 3DS file (#1)");
|
||||
(*i).mIndices[0] = (uint32_t)sMesh->mPositions.size()-1;
|
||||
}
|
||||
if ((*i).mIndices[1] >= sMesh->mPositions.size())
|
||||
{
|
||||
DefaultLogger::get()->warn("Face index overflow in 3DS file (#2)");
|
||||
(*i).mIndices[1] = (uint32_t)sMesh->mPositions.size()-1;
|
||||
}
|
||||
if ((*i).mIndices[2] >= sMesh->mPositions.size())
|
||||
{
|
||||
DefaultLogger::get()->warn("Face index overflow in 3DS file (#3)");
|
||||
(*i).mIndices[2] = (uint32_t)sMesh->mPositions.size()-1;
|
||||
if ((*i).mIndices[a] >= sMesh.mPositions.size())
|
||||
{
|
||||
DefaultLogger::get()->warn("3DS: Face index overflow)");
|
||||
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
|
||||
void Dot3DSImporter::MakeUnique(Dot3DS::Mesh& sMesh)
|
||||
{
|
||||
unsigned int iBase = 0;
|
||||
|
||||
std::vector<aiVector3D> vNew;
|
||||
std::vector<aiVector2D> vNew2;
|
||||
|
||||
vNew.resize(sMesh->mFaces.size() * 3);
|
||||
if (sMesh->mTexCoords.size())vNew2.resize(sMesh->mFaces.size() * 3);
|
||||
vNew.resize(sMesh.mFaces.size() * 3);
|
||||
if (sMesh.mTexCoords.size())vNew2.resize(sMesh.mFaces.size() * 3);
|
||||
|
||||
for (unsigned int i = 0; i < sMesh->mFaces.size();++i)
|
||||
for (unsigned int i = 0; i < sMesh.mFaces.size();++i)
|
||||
{
|
||||
uint32_t iTemp1,iTemp2;
|
||||
|
||||
// positions
|
||||
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]];
|
||||
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[2]];
|
||||
iTemp1 = iBase++;
|
||||
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]];
|
||||
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[1]];
|
||||
iTemp2 = iBase++;
|
||||
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]];
|
||||
vNew[iBase] = sMesh.mPositions[sMesh.mFaces[i].mIndices[0]];
|
||||
|
||||
// texture coordinates
|
||||
if (sMesh->mTexCoords.size())
|
||||
if (sMesh.mTexCoords.size())
|
||||
{
|
||||
vNew2[iTemp1] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[2]];
|
||||
vNew2[iTemp2] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[1]];
|
||||
vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[0]];
|
||||
vNew2[iTemp1] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[2]];
|
||||
vNew2[iTemp2] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[1]];
|
||||
vNew2[iBase] = sMesh.mTexCoords[sMesh.mFaces[i].mIndices[0]];
|
||||
}
|
||||
|
||||
sMesh->mFaces[i].mIndices[2] = iBase++;
|
||||
sMesh->mFaces[i].mIndices[0] = iTemp1;
|
||||
sMesh->mFaces[i].mIndices[1] = iTemp2;
|
||||
sMesh.mFaces[i].mIndices[2] = iBase++;
|
||||
sMesh.mFaces[i].mIndices[0] = iTemp1;
|
||||
sMesh.mFaces[i].mIndices[1] = iTemp2;
|
||||
}
|
||||
sMesh->mPositions = vNew;
|
||||
sMesh->mTexCoords = vNew2;
|
||||
sMesh.mPositions = vNew;
|
||||
sMesh.mTexCoords = vNew2;
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
||||
MaterialHelper& mat)
|
||||
|
@ -201,14 +193,14 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
|||
// NOTE: Pass the background image to the viewer by bypassing the
|
||||
// material system. This is an evil hack, never do it again!
|
||||
if (0 != this->mBackgroundImage.length() && this->bHasBG)
|
||||
{
|
||||
{
|
||||
aiString tex;
|
||||
tex.Set( this->mBackgroundImage);
|
||||
mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE);
|
||||
|
||||
// be sure this is only done for the first material
|
||||
this->mBackgroundImage = std::string("");
|
||||
}
|
||||
}
|
||||
|
||||
// At first add the base ambient color of the
|
||||
// scene to the material
|
||||
|
@ -250,7 +242,7 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
|||
// two sided rendering?
|
||||
if (oldMat.mTwoSided)
|
||||
{
|
||||
int i = 0;
|
||||
int i = 1;
|
||||
mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
|
||||
}
|
||||
|
||||
|
@ -268,8 +260,6 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
|
|||
eShading = aiShadingMode_Gouraud; break;
|
||||
|
||||
// assume cook-torrance shading for metals.
|
||||
// NOTE: I assume the real shader inside 3ds max is an anisotropic
|
||||
// Phong-Blinn shader, but this is a good approximation too
|
||||
case Dot3DS::Dot3DSFile::Phong :
|
||||
eShading = aiShadingMode_Phong; break;
|
||||
|
||||
|
@ -409,20 +399,7 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
a = (*i).mFaceMaterials.begin();
|
||||
a != (*i).mFaceMaterials.end();++a,++iNum)
|
||||
{
|
||||
// check range
|
||||
// FIX: shouldn't be necessary anymore, has been moved to ReplaceDefaultMaterial()
|
||||
#if 0
|
||||
if ((*a) >= this->mScene->mMaterials.size())
|
||||
{
|
||||
DefaultLogger::get()->error("3DS face material index is out of range");
|
||||
|
||||
// use the last material instead
|
||||
// TODO: assign the default material index
|
||||
aiSplit[this->mScene->mMaterials.size()-1].push_back(iNum);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
aiSplit[*a].push_back(iNum);
|
||||
aiSplit[*a].push_back(iNum);
|
||||
}
|
||||
// now generate submeshes
|
||||
bool bFirst = true;
|
||||
|
@ -506,12 +483,9 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
pcOut->mNumMeshes = (unsigned int)avOutMeshes.size();
|
||||
pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes]();
|
||||
for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
|
||||
{
|
||||
pcOut->mMeshes[a] = avOutMeshes[a];
|
||||
}
|
||||
|
||||
if (!iFaceCnt)
|
||||
throw new ImportErrorException("No faces loaded. The mesh is empty");
|
||||
if (!iFaceCnt)throw new ImportErrorException("No faces loaded. The mesh is empty");
|
||||
|
||||
// for each material in the scene we need to setup the UV source
|
||||
// set for each texture
|
||||
|
@ -519,6 +493,7 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
|
|||
TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &this->mScene->mMaterials[a] );
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node* pcIn)
|
||||
{
|
||||
|
@ -533,11 +508,8 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
|
|||
ai_assert(NULL != pcMesh);
|
||||
|
||||
// do case independent comparisons here, just for safety
|
||||
if (pcIn->mName.length() == pcMesh->mName.length() &&
|
||||
!ASSIMP_stricmp(pcIn->mName.c_str(),pcMesh->mName.c_str()))
|
||||
{
|
||||
if (!ASSIMP_stricmp(pcIn->mName,pcMesh->mName))
|
||||
iArray.push_back(a);
|
||||
}
|
||||
}
|
||||
if (!iArray.empty())
|
||||
{
|
||||
|
@ -568,10 +540,11 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
|
|||
pvCurrent->y -= pivot.y;
|
||||
pvCurrent->z -= pivot.z;
|
||||
*pvCurrent = mTrafo * (*pvCurrent);
|
||||
std::swap( pvCurrent->y, pvCurrent->z );
|
||||
//std::swap( pvCurrent->y, pvCurrent->z );
|
||||
++pvCurrent;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
while (pvCurrent != pvEnd)
|
||||
|
@ -580,6 +553,7 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
|
|||
++pvCurrent;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pcOut->mMeshes[i] = iIndex;
|
||||
}
|
||||
}
|
||||
|
@ -658,9 +632,7 @@ void Dot3DSImporter::GenerateNodeGraph(aiScene* pcOut)
|
|||
|
||||
// if the root node is a default node setup a name for it
|
||||
if (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$')
|
||||
{
|
||||
pcOut->mRootNode->mName.Set("<root>");
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ConvertScene(aiScene* pcOut)
|
||||
|
|
|
@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Defines the helper data structures for importing 3DS files.
|
||||
/** @file Defines helper data structures for the import of 3DS files.
|
||||
http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
|
||||
|
||||
#ifndef AI_3DSFILEHELPER_H_INC
|
||||
|
@ -55,20 +55,18 @@ http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
|
|||
#include "../include/aiMaterial.h"
|
||||
|
||||
#include "SpatialSort.h"
|
||||
#include "SmoothingGroups.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Dot3DS {
|
||||
|
||||
#include "./Compiler/pushpack1.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define sprintf sprintf_s
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Dot3DSFile class: Helper class for loading 3ds files. Defines chunks
|
||||
* and data structures.
|
||||
*/
|
||||
// ---------------------------------------------------------------------------
|
||||
class Dot3DSFile
|
||||
{
|
||||
public:
|
||||
|
@ -91,32 +89,27 @@ public:
|
|||
typedef enum
|
||||
{
|
||||
// translated to gouraud shading with wireframe active
|
||||
Wire = 0,
|
||||
Wire = 0x0,
|
||||
|
||||
// if this material is set, no vertex normals will
|
||||
// be calculated for the model. Face normals + gouraud
|
||||
Flat = 1,
|
||||
Flat = 0x1,
|
||||
|
||||
// standard gouraud shading
|
||||
Gouraud = 2,
|
||||
Gouraud = 0x2,
|
||||
|
||||
// phong shading
|
||||
Phong = 3,
|
||||
Phong = 0x3,
|
||||
|
||||
// cooktorrance or anistropic phong shading ...
|
||||
// the exact meaning is unknown, if you know it
|
||||
// feel free to tell me ;-)
|
||||
Metal = 4,
|
||||
Metal = 0x4,
|
||||
|
||||
// required by the ASE loader
|
||||
Blinn = 5
|
||||
Blinn = 0x5
|
||||
} shadetype3ds;
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// enum for all chunks in 3ds files. Unused
|
||||
// ones are commented, list is not complete since
|
||||
// there are many undocumented chunks
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
enum
|
||||
{
|
||||
|
||||
|
@ -316,26 +309,10 @@ public:
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure representing a 3ds mesh face */
|
||||
struct Face
|
||||
struct Face : public FaceWithSmoothingGroup
|
||||
{
|
||||
Face() : iSmoothGroup(0), bFlipped(false)
|
||||
{
|
||||
// let the rest uninitialized for performance
|
||||
this->mIndices[0] = 0;
|
||||
this->mIndices[1] = 0;
|
||||
this->mIndices[2] = 0;
|
||||
}
|
||||
|
||||
|
||||
//! Indices. .3ds is using uint16. However, after
|
||||
//! an unique vrtex set has been geneerated it might
|
||||
//! be an index becomes > 2^16
|
||||
uint32_t mIndices[3];
|
||||
|
||||
//! specifies to which smoothing group the face belongs to
|
||||
uint32_t iSmoothGroup;
|
||||
|
||||
//! Specifies that the face normal must be flipped
|
||||
//! Specifies that the face normal must be flipped.
|
||||
//! todo: do we really need this?
|
||||
bool bFlipped;
|
||||
};
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -442,7 +419,7 @@ struct Material
|
|||
};
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure to represent a 3ds file mesh */
|
||||
struct Mesh
|
||||
struct Mesh : public MeshWithSmoothingGroups<Dot3DS::Face>
|
||||
{
|
||||
//! Default constructor
|
||||
Mesh()
|
||||
|
@ -457,21 +434,12 @@ struct Mesh
|
|||
//! Name of the mesh
|
||||
std::string mName;
|
||||
|
||||
//! Vertex positions
|
||||
std::vector<aiVector3D> mPositions;
|
||||
|
||||
//! Face lists
|
||||
std::vector<Face> mFaces;
|
||||
|
||||
//! Texture coordinates
|
||||
std::vector<aiVector2D> mTexCoords;
|
||||
|
||||
//! Face materials
|
||||
std::vector<unsigned int> mFaceMaterials;
|
||||
|
||||
//! Normal vectors
|
||||
std::vector<aiVector3D> mNormals;
|
||||
|
||||
//! Local transformation matrix
|
||||
aiMatrix4x4 mMat;
|
||||
};
|
||||
|
|
|
@ -50,23 +50,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// public ASSIMP headers
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/assimp.hpp"
|
||||
|
||||
// boost headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
#if (!defined ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG)
|
||||
# define ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG \
|
||||
"WARNING: Size of chunk data plus size of " \
|
||||
"subordinate chunks is larger than the size " \
|
||||
"specified in the top-level chunk header."
|
||||
// begin a chunk: parse it, validate its length, get a pointer to its end
|
||||
#define ASSIMP_3DS_BEGIN_CHUNK() \
|
||||
const Dot3DSFile::Chunk* psChunk; \
|
||||
this->ReadChunk(&psChunk); \
|
||||
const unsigned char* pcCur = this->mCurrent; \
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size \
|
||||
- sizeof(Dot3DSFile::Chunk));
|
||||
|
||||
// process the end of a chunk and return if the end of the file is reached
|
||||
#define ASSIMP_3DS_END_CHUNK() \
|
||||
this->mCurrent = pcCurNext; \
|
||||
piRemaining -= psChunk->Size; \
|
||||
if (0 >= piRemaining)return;
|
||||
|
||||
|
||||
// check whether the size of all subordinate chunks of a chunks is
|
||||
// not larger than the size of the chunk itself
|
||||
#ifdef _DEBUG
|
||||
# define ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG \
|
||||
"Size of chunk data plus size of subordinate chunks is " \
|
||||
"larger than the size specified in the top-level chunk header."
|
||||
|
||||
# define ASSIMP_3DS_VALIDATE_CHUNK_SIZE() \
|
||||
if (pcCurNext < this->mCurrent) \
|
||||
{ \
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG); \
|
||||
pcCurNext = this->mCurrent; \
|
||||
}
|
||||
#else
|
||||
# define ASSIMP_3DS_VALIDATE_CHUNK_SIZE()
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -92,7 +117,7 @@ bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) co
|
|||
return false;
|
||||
std::string extension = pFile.substr( pos);
|
||||
|
||||
// not brilliant but working ;-)
|
||||
// not brillant but working ;-)
|
||||
if( extension == ".3ds" || extension == ".3DS" ||
|
||||
extension == ".3Ds" || extension == ".3dS")
|
||||
return true;
|
||||
|
@ -103,7 +128,7 @@ bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) co
|
|||
// Setup configuration properties
|
||||
void Dot3DSImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
this->configSkipPivot = pImp->GetProperty(AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT,0) ? true : false;
|
||||
this->configSkipPivot = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT,0) ? true : false;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
|
@ -151,11 +176,11 @@ void Dot3DSImporter::InternReadFile(
|
|||
i != this->mScene->mMeshes.end();++i)
|
||||
{
|
||||
// TODO: see function body
|
||||
this->CheckIndices(&(*i));
|
||||
this->MakeUnique(&(*i));
|
||||
this->CheckIndices(*i);
|
||||
this->MakeUnique(*i);
|
||||
|
||||
// first generate normals for the mesh
|
||||
this->GenNormals(&(*i));
|
||||
ComputeNormalsWithSmoothingsGroups<Dot3DS::Face>(*i);
|
||||
}
|
||||
|
||||
// Apply scaling and offsets to all texture coordinates
|
||||
|
@ -179,11 +204,7 @@ void Dot3DSImporter::InternReadFile(
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ApplyMasterScale(aiScene* pScene)
|
||||
{
|
||||
// NOTE: Some invalid files have masterscale set to 0.0
|
||||
if (0.0f == this->mMasterScale)
|
||||
{
|
||||
this->mMasterScale = 1.0f;
|
||||
}
|
||||
if (!this->mMasterScale)this->mMasterScale = 1.0f;
|
||||
else this->mMasterScale = 1.0f / this->mMasterScale;
|
||||
|
||||
// construct an uniform scaling matrix and multiply with it
|
||||
|
@ -200,9 +221,8 @@ void Dot3DSImporter::ReadChunk(const Dot3DSFile::Chunk** p_ppcOut)
|
|||
|
||||
// read chunk
|
||||
if (this->mCurrent >= this->mLast)
|
||||
{
|
||||
throw new ImportErrorException("Unexpected end of file, can't read chunk header");
|
||||
}
|
||||
|
||||
const uintptr_t iDiff = this->mLast - this->mCurrent;
|
||||
if (iDiff < sizeof(Dot3DSFile::Chunk))
|
||||
{
|
||||
|
@ -211,23 +231,15 @@ void Dot3DSImporter::ReadChunk(const Dot3DSFile::Chunk** p_ppcOut)
|
|||
}
|
||||
*p_ppcOut = (const Dot3DSFile::Chunk*) this->mCurrent;
|
||||
if ((**p_ppcOut).Size + this->mCurrent > this->mLast)
|
||||
{
|
||||
throw new ImportErrorException("Unexpected end of file, can't read chunk footer");
|
||||
}
|
||||
|
||||
this->mCurrent += sizeof(Dot3DSFile::Chunk);
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseMainChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
|
||||
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size
|
||||
- sizeof(Dot3DSFile::Chunk));
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
|
@ -237,27 +249,14 @@ void Dot3DSImporter::ParseMainChunk(int& piRemaining)
|
|||
this->ParseEditorChunk(iRemaining);
|
||||
break;
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next top-level chunk
|
||||
this->mCurrent = pcCurNext;
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return this->ParseMainChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseEditorChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
|
@ -291,27 +290,14 @@ void Dot3DSImporter::ParseEditorChunk(int& piRemaining)
|
|||
}
|
||||
break;
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next top-level chunk
|
||||
this->mCurrent = pcCurNext;
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return this->ParseEditorChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseObjectChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
const unsigned char* sz = this->mCurrent;
|
||||
unsigned int iCnt = 0;
|
||||
|
@ -384,17 +370,8 @@ void Dot3DSImporter::ParseObjectChunk(int& piRemaining)
|
|||
break;
|
||||
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next top-level chunk
|
||||
this->mCurrent = pcCurNext;
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return this->ParseObjectChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -409,11 +386,7 @@ void Dot3DSImporter::SkipChunk()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
|
@ -424,28 +397,14 @@ void Dot3DSImporter::ParseChunk(int& piRemaining)
|
|||
this->ParseMeshChunk(iRemaining);
|
||||
break;
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next top-level chunk
|
||||
this->mCurrent = pcCurNext;
|
||||
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return this->ParseChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseKeyframeChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
int iRemaining = (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
|
@ -456,18 +415,8 @@ void Dot3DSImporter::ParseKeyframeChunk(int& piRemaining)
|
|||
this->ParseHierarchyChunk(iRemaining);
|
||||
break;
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next top-level chunk
|
||||
this->mCurrent = pcCurNext;
|
||||
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return this->ParseKeyframeChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -489,14 +438,7 @@ void Dot3DSImporter::InverseNodeSearch(Dot3DS::Node* pcNode,Dot3DS::Node* pcCurr
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
|
||||
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size
|
||||
- sizeof(Dot3DSFile::Chunk));
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
const unsigned char* sz = (unsigned char*)this->mCurrent;
|
||||
|
@ -548,6 +490,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
|||
|
||||
// pivot = origin of rotation and scaling
|
||||
this->mCurrentNode->vPivot = *((const aiVector3D*)this->mCurrent);
|
||||
std::swap(this->mCurrentNode->vPivot.y,this->mCurrentNode->vPivot.z);
|
||||
this->mCurrent += sizeof(aiVector3D);
|
||||
break;
|
||||
|
||||
|
@ -576,8 +519,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
|||
uint16_t sNum = *((const uint16_t*)mCurrent);
|
||||
this->mCurrent += sizeof(uint16_t);
|
||||
|
||||
aiVectorKey v;
|
||||
v.mTime = (double)sNum;
|
||||
aiVectorKey v;v.mTime = (double)sNum;
|
||||
|
||||
this->mCurrent += sizeof(uint32_t);
|
||||
v.mValue = *((const aiVector3D*)this->mCurrent);
|
||||
|
@ -591,7 +533,8 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
|||
if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
|
||||
}
|
||||
// add the new keyframe
|
||||
if (v.mTime != -10e10f)this->mCurrentNode->aPositionKeys.push_back(v);
|
||||
if (v.mTime != -10e10f)
|
||||
this->mCurrentNode->aPositionKeys.push_back(v);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -618,9 +561,7 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
|||
uint16_t sNum = *((const uint16_t*)mCurrent);
|
||||
this->mCurrent += sizeof(uint16_t);
|
||||
|
||||
aiQuatKey v;
|
||||
v.mTime = (double)sNum;
|
||||
|
||||
aiQuatKey v;v.mTime = (double)sNum;
|
||||
this->mCurrent += sizeof(uint32_t);
|
||||
|
||||
float fRadians = *((const float*)this->mCurrent);
|
||||
|
@ -640,7 +581,8 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
|||
if ((*i).mTime == v.mTime){v.mTime = -10e10f;break;}
|
||||
}
|
||||
// add the new keyframe
|
||||
if (v.mTime != -10e10f)this->mCurrentNode->aRotationKeys.push_back(v);
|
||||
if (v.mTime != -10e10f)
|
||||
this->mCurrentNode->aRotationKeys.push_back(v);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -698,31 +640,16 @@ void Dot3DSImporter::ParseHierarchyChunk(int& piRemaining)
|
|||
break;
|
||||
#endif
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next top-level chunk
|
||||
this->mCurrent = pcCurNext;
|
||||
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return this->ParseHierarchyChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseFaceChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
Dot3DS::Mesh& mMesh = this->mScene->mMeshes.back();
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
|
||||
// get chunk type
|
||||
const unsigned char* sz = this->mCurrent;
|
||||
uint32_t iCnt = 0,iTemp;
|
||||
|
@ -796,31 +723,16 @@ void Dot3DSImporter::ParseFaceChunk(int& piRemaining)
|
|||
|
||||
break;
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next chunk on this level
|
||||
this->mCurrent = pcCurNext;
|
||||
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return ParseFaceChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
Dot3DS::Mesh& mMesh = this->mScene->mMeshes.back();
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
|
||||
// get chunk type
|
||||
const unsigned char* sz = this->mCurrent;
|
||||
unsigned int iCnt = 0;
|
||||
|
@ -837,7 +749,7 @@ void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
|
|||
{
|
||||
mMesh.mPositions.push_back(*((aiVector3D*)this->mCurrent));
|
||||
aiVector3D& v = mMesh.mPositions.back();
|
||||
//std::swap( v.y, v.z);
|
||||
std::swap( v.y, v.z);
|
||||
//v.y *= -1.0f;
|
||||
this->mCurrent += sizeof(aiVector3D);
|
||||
}
|
||||
|
@ -924,28 +836,14 @@ void Dot3DSImporter::ParseMeshChunk(int& piRemaining)
|
|||
break;
|
||||
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next chunk on this level
|
||||
this->mCurrent = pcCurNext;
|
||||
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return ParseMeshChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size - sizeof(Dot3DSFile::Chunk));
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
const unsigned char* sz = this->mCurrent;
|
||||
|
@ -958,9 +856,8 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
|||
case Dot3DSFile::CHUNK_MAT_MATNAME:
|
||||
|
||||
// string in file is zero-terminated,
|
||||
// this should be no problem. However, validate whether
|
||||
// it overlaps the end of the chunk, if yes we should
|
||||
// truncate it.
|
||||
// this should be no problem. However, validate whether it overlaps
|
||||
// the end of the chunk, if yes we should truncate it.
|
||||
while (*sz++ != '\0')
|
||||
{
|
||||
if (sz > pcCurNext-1)
|
||||
|
@ -1017,8 +914,7 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
|||
pcf = &this->mScene->mMaterials.back().mTransparency;
|
||||
*pcf = this->ParsePercentageChunk();
|
||||
// NOTE: transparency, not opacity
|
||||
if (is_qnan(*pcf))
|
||||
*pcf = 1.0f;
|
||||
if (is_qnan(*pcf))*pcf = 1.0f;
|
||||
else *pcf = 1.0f - *pcf * (float)0xFFFF / 100.0f;
|
||||
break;
|
||||
|
||||
|
@ -1037,16 +933,14 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
|||
case Dot3DSFile::CHUNK_MAT_SHININESS:
|
||||
pcf = &this->mScene->mMaterials.back().mSpecularExponent;
|
||||
*pcf = this->ParsePercentageChunk();
|
||||
if (is_qnan(*pcf))
|
||||
*pcf = 0.0f;
|
||||
if (is_qnan(*pcf))*pcf = 0.0f;
|
||||
else *pcf *= (float)0xFFFF;
|
||||
break;
|
||||
|
||||
case Dot3DSFile::CHUNK_MAT_SHININESS_PERCENT:
|
||||
pcf = &this->mScene->mMaterials.back().mShininessStrength;
|
||||
*pcf = this->ParsePercentageChunk();
|
||||
if (is_qnan(*pcf))
|
||||
*pcf = 0.0f;
|
||||
if (is_qnan(*pcf))*pcf = 0.0f;
|
||||
else *pcf *= (float)0xffff / 100.0f;
|
||||
break;
|
||||
|
||||
|
@ -1054,8 +948,7 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
|||
// TODO: need to multiply with emissive base color?
|
||||
pcf = &this->mScene->mMaterials.back().sTexEmissive.mTextureBlend;
|
||||
*pcf = this->ParsePercentageChunk();
|
||||
if (is_qnan(*pcf))
|
||||
*pcf = 0.0f;
|
||||
if (is_qnan(*pcf))*pcf = 0.0f;
|
||||
else *pcf = *pcf * (float)0xFFFF / 100.0f;
|
||||
break;
|
||||
|
||||
|
@ -1085,31 +978,14 @@ void Dot3DSImporter::ParseMaterialChunk(int& piRemaining)
|
|||
this->ParseTextureChunk(iRemaining,&this->mScene->mMaterials.back().sTexEmissive);
|
||||
break;
|
||||
};
|
||||
if (pcCurNext < this->mCurrent)
|
||||
{
|
||||
// place an error message. If we crash the programmer
|
||||
// will be able to find it
|
||||
DefaultLogger::get()->warn(ASSIMP_3DS_WARN_CHUNK_OVERFLOW_MSG);
|
||||
pcCurNext = this->mCurrent;
|
||||
}
|
||||
// Go to the starting position of the next chunk on this level
|
||||
this->mCurrent = pcCurNext;
|
||||
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return ParseMaterialChunk(piRemaining);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::ParseTextureChunk(int& piRemaining,Dot3DS::Texture* pcOut)
|
||||
{
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
|
||||
this->ReadChunk(&psChunk);
|
||||
|
||||
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
const unsigned char* pcCurNext = pcCur + (psChunk->Size
|
||||
- sizeof(Dot3DSFile::Chunk));
|
||||
ASSIMP_3DS_BEGIN_CHUNK();
|
||||
|
||||
// get chunk type
|
||||
const unsigned char* sz = this->mCurrent;
|
||||
|
@ -1184,11 +1060,8 @@ void Dot3DSImporter::ParseTextureChunk(int& piRemaining,Dot3DS::Texture* pcOut)
|
|||
break;
|
||||
};
|
||||
|
||||
// Go to the starting position of the next chunk on this level
|
||||
this->mCurrent = pcCurNext;
|
||||
|
||||
piRemaining -= psChunk->Size;
|
||||
if (0 >= piRemaining)return;
|
||||
ASSIMP_3DS_VALIDATE_CHUNK_SIZE();
|
||||
ASSIMP_3DS_END_CHUNK();
|
||||
return ParseTextureChunk(piRemaining,pcOut);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -1226,20 +1099,22 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
|||
|
||||
const Dot3DSFile::Chunk* psChunk;
|
||||
this->ReadChunk(&psChunk);
|
||||
if (NULL == psChunk)
|
||||
if (!psChunk)
|
||||
{
|
||||
*p_pcOut = clrError;
|
||||
return;
|
||||
}
|
||||
const unsigned int diff = psChunk->Size - sizeof(Dot3DSFile::Chunk);
|
||||
|
||||
const unsigned char* pcCur = this->mCurrent;
|
||||
this->mCurrent += psChunk->Size - sizeof(Dot3DSFile::Chunk);
|
||||
this->mCurrent += diff;
|
||||
bool bGamma = false;
|
||||
switch(psChunk->Flag)
|
||||
{
|
||||
case Dot3DSFile::CHUNK_LINRGBF:
|
||||
bGamma = true;
|
||||
case Dot3DSFile::CHUNK_RGBF:
|
||||
if (sizeof(float) * 3 > psChunk->Size - sizeof(Dot3DSFile::Chunk))
|
||||
if (sizeof(float) * 3 > diff)
|
||||
{
|
||||
*p_pcOut = clrError;
|
||||
return;
|
||||
|
@ -1252,7 +1127,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
|||
case Dot3DSFile::CHUNK_LINRGBB:
|
||||
bGamma = true;
|
||||
case Dot3DSFile::CHUNK_RGBB:
|
||||
if (sizeof(char) * 3 > psChunk->Size - sizeof(Dot3DSFile::Chunk))
|
||||
if (sizeof(char) * 3 > diff)
|
||||
{
|
||||
*p_pcOut = clrError;
|
||||
return;
|
||||
|
@ -1265,7 +1140,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
|||
// percentage chunks: accepted to be compatible with various
|
||||
// .3ds files with very curious content
|
||||
case Dot3DSFile::CHUNK_PERCENTF:
|
||||
if (p_bAcceptPercent && 4 <= psChunk->Size - sizeof(Dot3DSFile::Chunk))
|
||||
if (p_bAcceptPercent && 4 <= diff)
|
||||
{
|
||||
p_pcOut->r = *((float*)pcCur);
|
||||
p_pcOut->g = *((float*)pcCur);
|
||||
|
@ -1275,7 +1150,7 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
|||
*p_pcOut = clrError;
|
||||
return;
|
||||
case Dot3DSFile::CHUNK_PERCENTW:
|
||||
if (p_bAcceptPercent && 1 <= psChunk->Size - sizeof(Dot3DSFile::Chunk))
|
||||
if (p_bAcceptPercent && 1 <= diff)
|
||||
{
|
||||
p_pcOut->r = (float)pcCur[0] / 255.0f;
|
||||
p_pcOut->g = (float)pcCur[0] / 255.0f;
|
||||
|
@ -1289,9 +1164,6 @@ void Dot3DSImporter::ParseColorChunk(aiColor3D* p_pcOut,
|
|||
// skip unknown chunks, hope this won't cause any problems.
|
||||
return this->ParseColorChunk(p_pcOut,p_bAcceptPercent);
|
||||
};
|
||||
// assume input gamma = 1.0, output gamma = 2.2
|
||||
// Not sure whether this is correct, too tired to
|
||||
// think about it ;-)
|
||||
if (bGamma)
|
||||
{
|
||||
p_pcOut->r = powf(p_pcOut->r, 1.0f / 2.2f);
|
||||
|
|
|
@ -206,15 +206,10 @@ protected:
|
|||
*/
|
||||
void ConvertScene(aiScene* pcOut);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** generate normal vectors for a given mesh
|
||||
*/
|
||||
void GenNormals(Dot3DS::Mesh* sMesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** generate unique vertices for a mesh
|
||||
*/
|
||||
void MakeUnique(Dot3DS::Mesh* sMesh);
|
||||
void MakeUnique(Dot3DS::Mesh& sMesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add a node to the node graph
|
||||
|
@ -235,7 +230,7 @@ protected:
|
|||
// -------------------------------------------------------------------
|
||||
/** Clamp all indices in the file to a valid range
|
||||
*/
|
||||
void CheckIndices(Dot3DS::Mesh* sMesh);
|
||||
void CheckIndices(Dot3DS::Mesh& sMesh);
|
||||
|
||||
|
||||
protected:
|
||||
|
|
|
@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// internal headers
|
||||
#include "ASELoader.h"
|
||||
#include "3DSSpatialSort.h"
|
||||
#include "MaterialSystem.h"
|
||||
#include "StringComparison.h"
|
||||
#include "TextureTransform.h"
|
||||
|
@ -142,6 +141,7 @@ void ASEImporter::InternReadFile(
|
|||
if ((*i).bSkip)continue;
|
||||
|
||||
this->TransformVertices(*i);
|
||||
|
||||
// now we need to create proper meshes from the import we need to
|
||||
// split them by materials, build valid vertex/face lists ...
|
||||
this->BuildUniqueRepresentation(*i);
|
||||
|
@ -1135,9 +1135,7 @@ void ASEImporter::BuildMaterialIndices()
|
|||
}
|
||||
// prepare for the next step
|
||||
for (unsigned int hans = 0; hans < this->mParser->m_vMaterials.size();++hans)
|
||||
{
|
||||
TextureTransform::ApplyScaleNOffset(this->mParser->m_vMaterials[hans]);
|
||||
}
|
||||
|
||||
// now we need to iterate through all meshes,
|
||||
// generating correct texture coordinates and material uv indices
|
||||
|
@ -1182,75 +1180,6 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh)
|
|||
}
|
||||
}
|
||||
if (mesh.mNormals.empty())
|
||||
{
|
||||
// need to calculate normals ...
|
||||
// TODO: Find a way to merge this with the code in 3DSGenNormals.cpp
|
||||
mesh.mNormals.resize(mesh.mPositions.size(),aiVector3D());
|
||||
for( unsigned int a = 0; a < mesh.mFaces.size(); a++)
|
||||
{
|
||||
const ASE::Face& face = mesh.mFaces[a];
|
||||
|
||||
// assume it is a triangle
|
||||
aiVector3D* pV1 = &mesh.mPositions[face.mIndices[2]];
|
||||
aiVector3D* pV2 = &mesh.mPositions[face.mIndices[1]];
|
||||
aiVector3D* pV3 = &mesh.mPositions[face.mIndices[0]];
|
||||
|
||||
aiVector3D pDelta1 = *pV2 - *pV1;
|
||||
aiVector3D pDelta2 = *pV3 - *pV1;
|
||||
aiVector3D vNor = pDelta1 ^ pDelta2;
|
||||
|
||||
for (unsigned int i = 0; i < 3;++i)
|
||||
mesh.mNormals[face.mIndices[i]] = vNor;
|
||||
}
|
||||
|
||||
// calculate the position bounds so we have a reliable epsilon to
|
||||
// check position differences against
|
||||
// @Schrompf: This is the 7th time this snippet is repeated!
|
||||
aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
|
||||
for( unsigned int a = 0; a < mesh.mPositions.size(); a++)
|
||||
{
|
||||
minVec.x = std::min( minVec.x, mesh.mPositions[a].x);
|
||||
minVec.y = std::min( minVec.y, mesh.mPositions[a].y);
|
||||
minVec.z = std::min( minVec.z, mesh.mPositions[a].z);
|
||||
maxVec.x = std::max( maxVec.x, mesh.mPositions[a].x);
|
||||
maxVec.y = std::max( maxVec.y, mesh.mPositions[a].y);
|
||||
maxVec.z = std::max( maxVec.z, mesh.mPositions[a].z);
|
||||
}
|
||||
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
|
||||
|
||||
std::vector<aiVector3D> avNormals;
|
||||
avNormals.resize(mesh.mNormals.size());
|
||||
|
||||
// now generate the spatial sort tree
|
||||
D3DSSpatialSorter sSort;
|
||||
for( std::vector<ASE::Face>::iterator
|
||||
i = mesh.mFaces.begin();
|
||||
i != mesh.mFaces.end();++i){sSort.AddFace(&(*i),mesh.mPositions);}
|
||||
sSort.Prepare();
|
||||
|
||||
for( std::vector<ASE::Face>::iterator
|
||||
i = mesh.mFaces.begin();
|
||||
i != mesh.mFaces.end();++i)
|
||||
{
|
||||
std::vector<unsigned int> poResult;
|
||||
for (unsigned int c = 0; c < 3;++c)
|
||||
{
|
||||
sSort.FindPositions(mesh.mPositions[(*i).mIndices[c]],(*i).iSmoothGroup,
|
||||
posEpsilon,poResult);
|
||||
|
||||
aiVector3D vNormals;
|
||||
for (std::vector<unsigned int>::const_iterator
|
||||
a = poResult.begin();
|
||||
a != poResult.end();++a)
|
||||
{
|
||||
vNormals += mesh.mNormals[(*a)];
|
||||
}
|
||||
vNormals.Normalize();
|
||||
avNormals[(*i).mIndices[c]] = vNormals;
|
||||
poResult.clear();
|
||||
}
|
||||
}
|
||||
mesh.mNormals = avNormals;
|
||||
}
|
||||
ComputeNormalsWithSmoothingsGroups<ASE::Face>(mesh);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ using namespace Assimp::ASE;
|
|||
#define BLUBB(_message_) \
|
||||
{this->LogError(_message_);return;}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#define AI_ASE_HANDLE_TOP_LEVEL_SECTION(iDepth) \
|
||||
else if ('{' == *this->m_szFile)iDepth++; \
|
||||
else if ('}' == *this->m_szFile) \
|
||||
|
@ -87,6 +87,7 @@ using namespace Assimp::ASE;
|
|||
} else bLastWasEndLine = false; \
|
||||
++this->m_szFile;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#define AI_ASE_HANDLE_SECTION(iDepth, level, msg) \
|
||||
else if ('{' == *this->m_szFile)iDepth++; \
|
||||
else if ('}' == *this->m_szFile) \
|
||||
|
@ -1723,62 +1724,29 @@ void Parser::ParseLV4MeshLongTriple(unsigned int* apOut)
|
|||
ai_assert(NULL != apOut);
|
||||
|
||||
for (unsigned int i = 0; i < 3;++i)
|
||||
{
|
||||
// skip spaces and tabs
|
||||
if(!SkipSpaces(this->m_szFile,&this->m_szFile))
|
||||
{
|
||||
// LOG
|
||||
this->LogWarning("Unable to parse indexable long triple: unexpected EOL [#1]");
|
||||
++this->iLineNumber;
|
||||
apOut[0] = apOut[1] = apOut[2] = 0;
|
||||
return;
|
||||
}
|
||||
apOut[i] = strtol10(this->m_szFile,&this->m_szFile);
|
||||
}
|
||||
ParseLV4MeshLong(apOut[i]);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut)
|
||||
{
|
||||
ai_assert(NULL != apOut);
|
||||
|
||||
// skip spaces and tabs
|
||||
if(!SkipSpaces(this->m_szFile,&this->m_szFile))
|
||||
{
|
||||
// LOG
|
||||
this->LogWarning("Unable to parse indexed long triple: unexpected EOL [#4]");
|
||||
rIndexOut = 0;
|
||||
apOut[0] = apOut[1] = apOut[2] = 0;
|
||||
++this->iLineNumber;
|
||||
return;
|
||||
}
|
||||
// parse the index
|
||||
rIndexOut = strtol10(this->m_szFile,&this->m_szFile);
|
||||
ParseLV4MeshLong(rIndexOut);
|
||||
|
||||
// parse the three others
|
||||
this->ParseLV4MeshLongTriple(apOut);
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut)
|
||||
{
|
||||
ai_assert(NULL != apOut);
|
||||
|
||||
// skip spaces and tabs
|
||||
if(!SkipSpaces(this->m_szFile,&this->m_szFile))
|
||||
{
|
||||
// LOG
|
||||
this->LogWarning("Unable to parse indexed float triple: unexpected EOL [#1]");
|
||||
rIndexOut = 0;
|
||||
apOut[0] = apOut[1] = apOut[2] = 0.0f;
|
||||
++this->iLineNumber;
|
||||
return;
|
||||
}
|
||||
// parse the index
|
||||
rIndexOut = strtol10(this->m_szFile,&this->m_szFile);
|
||||
ParseLV4MeshLong(rIndexOut);
|
||||
|
||||
// parse the three others
|
||||
this->ParseLV4MeshFloatTriple(apOut);
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshFloatTriple(float* apOut)
|
||||
|
@ -1786,20 +1754,7 @@ void Parser::ParseLV4MeshFloatTriple(float* apOut)
|
|||
ai_assert(NULL != apOut);
|
||||
|
||||
for (unsigned int i = 0; i < 3;++i)
|
||||
{
|
||||
// skip spaces and tabs
|
||||
if(!SkipSpaces(this->m_szFile,&this->m_szFile))
|
||||
{
|
||||
// LOG
|
||||
this->LogWarning("Unable to parse float triple: unexpected EOL [#5]");
|
||||
apOut[0] = apOut[1] = apOut[2] = 0.0f;
|
||||
++this->iLineNumber;
|
||||
return;
|
||||
}
|
||||
// parse the float
|
||||
this->m_szFile = fast_atof_move(this->m_szFile,apOut[i]);
|
||||
}
|
||||
return;
|
||||
ParseLV4MeshFloat(apOut[i]);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshFloat(float& fOut)
|
||||
|
@ -1815,9 +1770,6 @@ void Parser::ParseLV4MeshFloat(float& fOut)
|
|||
}
|
||||
// parse the first float
|
||||
this->m_szFile = fast_atof_move(this->m_szFile,fOut);
|
||||
// go to the next valid sequence
|
||||
//this->SkipToNextToken();
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Parser::ParseLV4MeshLong(unsigned int& iOut)
|
||||
|
@ -1833,7 +1785,4 @@ void Parser::ParseLV4MeshLong(unsigned int& iOut)
|
|||
}
|
||||
// parse the value
|
||||
iOut = strtol10(this->m_szFile,&this->m_szFile);
|
||||
// go to the next valid sequence
|
||||
//this->SkipToNextToken();
|
||||
return;
|
||||
}
|
|
@ -54,7 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/aiAnim.h"
|
||||
|
||||
// for some helper routines like IsSpace()
|
||||
#include "PlyParser.h"
|
||||
#include "ParsingUtils.h"
|
||||
#include "qnan.h"
|
||||
|
||||
// ASE is quite similar to 3ds. We can reuse some structures
|
||||
|
@ -87,7 +87,7 @@ struct Material : public Dot3DS::Material
|
|||
};
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure to represent an ASE file face */
|
||||
struct Face : public Dot3DS::Face
|
||||
struct Face : public FaceWithSmoothingGroup
|
||||
{
|
||||
//! Default constructor. Initializes everything with 0
|
||||
Face()
|
||||
|
@ -224,13 +224,13 @@ struct DecompTransform
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure to represent an ASE file mesh */
|
||||
struct Mesh
|
||||
struct Mesh : public MeshWithSmoothingGroups<ASE::Face>
|
||||
{
|
||||
//! Constructor. Creates a default name for the mesh
|
||||
Mesh() : bSkip(false)
|
||||
{
|
||||
static int iCnt = 0;
|
||||
char szTemp[128];
|
||||
char szTemp[128]; // should be sufficiently large
|
||||
::sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
||||
mName = szTemp;
|
||||
|
||||
|
@ -249,21 +249,12 @@ struct Mesh
|
|||
//! "" if there is no parent ...
|
||||
std::string mParent;
|
||||
|
||||
//! vertex positions
|
||||
std::vector<aiVector3D> mPositions;
|
||||
|
||||
//! List of all faces loaded
|
||||
std::vector<ASE::Face> mFaces;
|
||||
|
||||
//! List of all texture coordinate sets
|
||||
std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
|
||||
//! List of all vertex color sets.
|
||||
std::vector<aiColor4D> mVertexColors;
|
||||
|
||||
//! List of normal vectors
|
||||
std::vector<aiVector3D> mNormals;
|
||||
|
||||
//! List of all bone vertices
|
||||
std::vector<BoneVertex> mBoneVertices;
|
||||
|
||||
|
|
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 */
|
||||
|
||||
// CRT headers
|
||||
#include <map>
|
||||
|
||||
// public ASSIMP headers
|
||||
#include "../include/assimp.h"
|
||||
#include "../include/aiFileIO.h"
|
||||
#include "../include/assimp.hpp"
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
|
||||
#include "GenericProperty.h"
|
||||
|
||||
// boost headers
|
||||
#define AI_C_THREADSAFE
|
||||
|
@ -67,19 +70,158 @@ static ImporterMap gActiveImports;
|
|||
/** Error message of the last failed import process */
|
||||
static std::string gLastErrorString;
|
||||
|
||||
/** Configuration properties */
|
||||
static Importer::IntPropertyMap gIntProperties;
|
||||
static Importer::FloatPropertyMap gFloatProperties;
|
||||
static Importer::StringPropertyMap gStringProperties;
|
||||
|
||||
#if (defined AI_C_THREADSAFE)
|
||||
/** Global mutex to manage the access to the importer map */
|
||||
static boost::mutex gMutex;
|
||||
#endif
|
||||
|
||||
class CIOSystemWrapper;
|
||||
class CIOStreamWrapper;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Custom IOStream implementation for the C-API
|
||||
class CIOStreamWrapper : public IOStream
|
||||
{
|
||||
friend class CIOSystemWrapper;
|
||||
public:
|
||||
|
||||
CIOStreamWrapper(aiFile* pFile)
|
||||
: mFile(pFile)
|
||||
{}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
size_t Read(void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
{
|
||||
// need to typecast here as C has no void*
|
||||
return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
size_t Write(const void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
{
|
||||
// need to typecast here as C has no void*
|
||||
return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
aiReturn Seek(size_t pOffset,
|
||||
aiOrigin pOrigin)
|
||||
{
|
||||
return mFile->SeekProc(mFile,pOffset,pOrigin);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
size_t Tell(void) const
|
||||
{
|
||||
return mFile->TellProc(mFile);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
size_t FileSize() const
|
||||
{
|
||||
return mFile->FileSizeProc(mFile);
|
||||
}
|
||||
|
||||
private:
|
||||
aiFile* mFile;
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Custom IOStream implementation for the C-API
|
||||
class CIOSystemWrapper : public IOSystem
|
||||
{
|
||||
public:
|
||||
|
||||
CIOSystemWrapper(aiFileIO* pFile)
|
||||
: mFileSystem(pFile)
|
||||
{}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool Exists( const std::string& pFile) const
|
||||
{
|
||||
CIOSystemWrapper* pip = const_cast<CIOSystemWrapper*>(this);
|
||||
IOStream* p = pip->Open(pFile);
|
||||
if (p){pip->Close(p);return true;}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
std::string getOsSeparator() const
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
IOStream* Open(const std::string& pFile,
|
||||
const std::string& pMode = std::string("rb"))
|
||||
{
|
||||
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile.c_str(),pMode.c_str());
|
||||
if (!p)return NULL;
|
||||
return new CIOStreamWrapper(p);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Close( IOStream* pFile)
|
||||
{
|
||||
if (!pFile)return;
|
||||
mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
|
||||
delete pFile;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
aiFileIO* mFileSystem;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ReportSceneNotFoundError()
|
||||
{
|
||||
DefaultLogger::get()->error("Unable to find the Importer instance for this scene. "
|
||||
"Are you sure it has been created by aiImportFile(ex)(...)?");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the given file and returns its content.
|
||||
const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
|
||||
{
|
||||
return aiImportFileEx(pFile,pFlags,NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,
|
||||
aiFileIO* pFS)
|
||||
{
|
||||
ai_assert(NULL != pFile);
|
||||
|
||||
// create an Importer for this file
|
||||
Assimp::Importer* imp = new Assimp::Importer;
|
||||
|
||||
// copy the global property lists to the Importer instance
|
||||
// (we are a friend of Importer)
|
||||
imp->mIntProperties = gIntProperties;
|
||||
imp->mFloatProperties = gFloatProperties;
|
||||
imp->mStringProperties = gStringProperties;
|
||||
|
||||
// setup a custom IO system if necessary
|
||||
if (pFS)
|
||||
{
|
||||
imp->SetIOHandler( new CIOSystemWrapper (pFS) );
|
||||
}
|
||||
|
||||
// and have it read the file
|
||||
const aiScene* scene = imp->ReadFile( pFile, pFlags);
|
||||
|
||||
|
@ -118,8 +260,7 @@ void aiReleaseImport( const aiScene* pScene)
|
|||
// it should be there... else the user is playing fools with us
|
||||
if( it == gActiveImports.end())
|
||||
{
|
||||
DefaultLogger::get()->error("Unable to find the Importer instance for this scene. "
|
||||
"Are you sure it has been created by aiImportFile(ex)(...)?");
|
||||
ReportSceneNotFoundError();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -196,11 +337,31 @@ void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
|
|||
// it should be there... else the user is playing fools with us
|
||||
if( it == gActiveImports.end())
|
||||
{
|
||||
DefaultLogger::get()->error("Unable to find the Importer instance for this scene. "
|
||||
"Are you sure it has been created by aiImportFile(ex)(...)?");
|
||||
ReportSceneNotFoundError();
|
||||
return;
|
||||
}
|
||||
// get memory statistics
|
||||
it->second->GetMemoryRequirements(*in);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiSetImportPropertyInteger(const char* szName, int value)
|
||||
{
|
||||
SetGenericProperty<int>(gIntProperties,szName,value,NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiSetImportPropertyFloat(const char* szName, float value)
|
||||
{
|
||||
SetGenericProperty<float>(gFloatProperties,szName,value,NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiSetImportPropertyString(const char* szName,
|
||||
const C_STRUCT aiString* st)
|
||||
{
|
||||
if (!st)return;
|
||||
|
||||
SetGenericProperty<std::string>(gStringProperties,szName,
|
||||
std::string( st->data ),NULL);
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
|
|||
void CalcTangentsProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
// get the current value of the property
|
||||
this->configMaxAngle = pImp->GetProperty(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45000) / 1000.0f;
|
||||
this->configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
|
||||
this->configMaxAngle = std::max(std::min(this->configMaxAngle,180.0f),0.0f);
|
||||
this->configMaxAngle = AI_DEG_TO_RAD(this->configMaxAngle);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
// get the current value of the property
|
||||
this->configMaxAngle = pImp->GetProperty(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,180000) / 1000.0f;
|
||||
this->configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,180.f);
|
||||
this->configMaxAngle = std::max(std::min(this->configMaxAngle,180.0f),0.0f);
|
||||
this->configMaxAngle = AI_DEG_TO_RAD(this->configMaxAngle);
|
||||
}
|
||||
|
@ -145,8 +145,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
|
|||
SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
std::vector<unsigned int> verticesFound;
|
||||
|
||||
const float fLimit = (AI_MESH_SMOOTHING_ANGLE_NOT_SET == pMesh->mMaxSmoothingAngle
|
||||
? this->configMaxAngle : pMesh->mMaxSmoothingAngle);
|
||||
const float fLimit = this->configMaxAngle;
|
||||
|
||||
aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
|
||||
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
|
||||
|
|
|
@ -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
|
||||
#define AI_HASH_H_INCLUDED
|
||||
|
@ -19,11 +58,12 @@
|
|||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline uint32_t SuperFastHash (const char * data, int len, uint32_t hash = 0) {
|
||||
inline uint32_t SuperFastHash (const char * data, unsigned int len = 0, uint32_t hash = 0) {
|
||||
uint32_t tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL) return 0;
|
||||
if (!data) return 0;
|
||||
if (!len)len = (unsigned int)::strlen(data);
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
|
|
@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "BaseProcess.h"
|
||||
#include "DefaultIOStream.h"
|
||||
#include "DefaultIOSystem.h"
|
||||
#include "GenericProperty.h"
|
||||
|
||||
// Importers
|
||||
#if (!defined AI_BUILD_NO_X_IMPORTER)
|
||||
|
@ -151,6 +152,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
|
||||
# include "RemoveRedundantMaterials.h"
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
|
||||
# include "OptimizeGraphProcess.h"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -168,6 +172,9 @@ Importer::Importer() :
|
|||
bExtraVerbose = false; // disable extra verbose mode by default
|
||||
|
||||
// add an instance of each worker class here
|
||||
// the order doesn't really care, however file formats that are
|
||||
// used more frequently than others should be at the beginning.
|
||||
|
||||
#if (!defined AI_BUILD_NO_X_IMPORTER)
|
||||
mImporter.push_back( new XFileImporter());
|
||||
#endif
|
||||
|
@ -217,13 +224,18 @@ Importer::Importer() :
|
|||
#endif
|
||||
|
||||
// add an instance of each post processing step here in the order
|
||||
// of sequence it is executed
|
||||
// of sequence it is executed. steps that are added here are not validated -
|
||||
// as RegisterPPStep() does - all dependencies must be there.
|
||||
|
||||
#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS)
|
||||
mPostProcessingSteps.push_back( new ValidateDSProcess()); // must be first
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
|
||||
mPostProcessingSteps.push_back( new RemoveRedundantMatsProcess());
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
|
||||
mPostProcessingSteps.push_back( new OptimizeGraphProcess());
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
|
||||
mPostProcessingSteps.push_back( new TriangulateProcess());
|
||||
#endif
|
||||
|
@ -379,8 +391,16 @@ bool ValidateFlags(unsigned int pFlags)
|
|||
if (pFlags & aiProcess_GenSmoothNormals &&
|
||||
pFlags & aiProcess_GenNormals)
|
||||
{
|
||||
DefaultLogger::get()->error("aiProcess_GenSmoothNormals and aiProcess_GenNormals "
|
||||
"may not be specified together");
|
||||
DefaultLogger::get()->error("aiProcess_GenSmoothNormals and "
|
||||
"aiProcess_GenNormals may not be specified together");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pFlags & aiProcess_PreTransformVertices &&
|
||||
pFlags & aiProcess_OptimizeGraph)
|
||||
{
|
||||
DefaultLogger::get()->error("aiProcess_PreTransformVertives and "
|
||||
"aiProcess_OptimizeGraph may not be specified together");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -488,15 +508,21 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Helper function to check whether an extension is supported by ASSIMP
|
||||
bool Importer::IsExtensionSupported(const std::string& szExtension)
|
||||
{
|
||||
return NULL != FindLoader(szExtension);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BaseImporter* Importer::FindLoader (const std::string& szExtension)
|
||||
{
|
||||
for (std::vector<BaseImporter*>::const_iterator
|
||||
i = this->mImporter.begin();
|
||||
i != this->mImporter.end();++i)
|
||||
{
|
||||
// pass the file extension to the CanRead(..,NULL)-method
|
||||
if ((*i)->CanRead(szExtension,NULL))return true;
|
||||
if ((*i)->CanRead(szExtension,NULL))return *i;
|
||||
}
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -519,49 +545,48 @@ void Importer::GetExtensionList(std::string& szOut)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
int Importer::SetProperty(const char* szName, int iValue)
|
||||
void Importer::SetPropertyInteger(const char* szName, int iValue,
|
||||
bool* bWasExisting /*= NULL*/)
|
||||
{
|
||||
ai_assert(NULL != szName);
|
||||
SetGenericProperty<int>(mIntProperties, szName,iValue,bWasExisting);
|
||||
}
|
||||
|
||||
// search in the list ...
|
||||
for (std::vector<IntPropertyInfo>::iterator
|
||||
i = this->mIntProperties.begin();
|
||||
i != this->mIntProperties.end();++i)
|
||||
{
|
||||
if (0 == ::strcmp( (*i).name.c_str(), szName ))
|
||||
{
|
||||
int iOld = (*i).value;
|
||||
(*i).value = iValue;
|
||||
return iOld;
|
||||
}
|
||||
}
|
||||
// the property is not yet in the list ...
|
||||
this->mIntProperties.push_back( IntPropertyInfo() );
|
||||
IntPropertyInfo& me = this->mIntProperties.back();
|
||||
me.name = std::string(szName);
|
||||
me.value = iValue;
|
||||
return AI_PROPERTY_WAS_NOT_EXISTING;
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Importer::SetPropertyFloat(const char* szName, float iValue,
|
||||
bool* bWasExisting /*= NULL*/)
|
||||
{
|
||||
SetGenericProperty<float>(mFloatProperties, szName,iValue,bWasExisting);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Importer::SetPropertyString(const char* szName, const std::string& value,
|
||||
bool* bWasExisting /*= NULL*/)
|
||||
{
|
||||
SetGenericProperty<std::string>(mStringProperties, szName,value,bWasExisting);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
int Importer::GetProperty(const char* szName,
|
||||
int Importer::GetPropertyInteger(const char* szName,
|
||||
int iErrorReturn /*= 0xffffffff*/) const
|
||||
{
|
||||
ai_assert(NULL != szName);
|
||||
|
||||
// search in the list ...
|
||||
for (std::vector<IntPropertyInfo>::const_iterator
|
||||
i = this->mIntProperties.begin();
|
||||
i != this->mIntProperties.end();++i)
|
||||
{
|
||||
if (0 == ::strcmp( (*i).name.c_str(), szName ))
|
||||
{
|
||||
return (*i).value;
|
||||
}
|
||||
}
|
||||
return iErrorReturn;
|
||||
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
float Importer::GetPropertyFloat(const char* szName,
|
||||
float iErrorReturn /*= 10e10*/) const
|
||||
{
|
||||
return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string Importer::GetPropertyString(const char* szName,
|
||||
const std::string& iErrorReturn /*= ""*/) const
|
||||
{
|
||||
return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/aiTypes.h"
|
||||
|
||||
struct aiMesh;
|
||||
class JoinVerticesTest;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
@ -62,6 +63,7 @@ namespace Assimp
|
|||
class ASSIMP_API JoinVerticesProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
friend class ::JoinVerticesTest;
|
||||
|
||||
protected:
|
||||
/** Constructor to be privately used by Importer */
|
||||
|
|
|
@ -95,8 +95,8 @@ bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
|
|||
// Setup configuration properties
|
||||
void LWOImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
this->configGradientResX = pImp->GetProperty(AI_CONFIG_IMPORT_LWO_GRADIENT_RESX,512);
|
||||
this->configGradientResY = pImp->GetProperty(AI_CONFIG_IMPORT_LWO_GRADIENT_RESY,512);
|
||||
this->configGradientResX = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWO_GRADIENT_RESX,512);
|
||||
this->configGradientResY = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWO_GRADIENT_RESY,512);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
|
@ -174,10 +174,10 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
|||
std::vector<aiMesh*> apcMeshes;
|
||||
std::vector<aiNode*> apcNodes;
|
||||
apcNodes.reserve(mLayers->size());
|
||||
apcMeshes.reserve(mLayers->size()*std::min((mSurfaces->size()/2u), 1u));
|
||||
apcMeshes.reserve(mLayers->size()*std::min(((unsigned int)mSurfaces->size()/2u), 1u));
|
||||
|
||||
// the RemoveRedundantMaterials step will clean this up later
|
||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = mSurfaces->size()];
|
||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
|
||||
for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat)
|
||||
{
|
||||
MaterialHelper* pcMat = new MaterialHelper();
|
||||
|
@ -192,7 +192,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
|||
const LWO::Layer& layer = *lit;
|
||||
|
||||
// I don't know whether there could be dummy layers, but it would be possible
|
||||
const unsigned int meshStart = apcMeshes.size();
|
||||
const unsigned int meshStart = (unsigned int)apcMeshes.size();
|
||||
if (!layer.mFaces.empty() && !layer.mTempPoints.empty())
|
||||
{
|
||||
// now sort all faces by the surfaces assigned to them
|
||||
|
@ -207,13 +207,13 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
|||
if (idx >= mTags->size())
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO: Invalid face surface index");
|
||||
idx = mTags->size()-1;
|
||||
idx = (unsigned int)mTags->size()-1;
|
||||
}
|
||||
if(0xffffffff == (idx = _mMapping[idx]))
|
||||
{
|
||||
if (0xffffffff == iDefaultSurface)
|
||||
{
|
||||
iDefaultSurface = mSurfaces->size();
|
||||
iDefaultSurface = (unsigned int)mSurfaces->size();
|
||||
mSurfaces->push_back(LWO::Surface());
|
||||
LWO::Surface& surf = mSurfaces->back();
|
||||
surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f;
|
||||
|
@ -240,7 +240,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
|||
// generate the mesh
|
||||
aiMesh* mesh = new aiMesh();
|
||||
apcMeshes.push_back(mesh);
|
||||
mesh->mNumFaces = sorted.size();
|
||||
mesh->mNumFaces = (unsigned int)sorted.size();
|
||||
|
||||
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
|
||||
it != end;++it)
|
||||
|
@ -281,7 +281,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
|||
apcNodes.push_back(pcNode);
|
||||
pcNode->mName.Set(layer.mName);
|
||||
pcNode->mParent = reinterpret_cast<aiNode*>(layer.mParent);
|
||||
pcNode->mNumMeshes = apcMeshes.size() - meshStart;
|
||||
pcNode->mNumMeshes = (unsigned int)apcMeshes.size() - meshStart;
|
||||
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
||||
for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
|
||||
pcNode->mMeshes[p] = p + meshStart;
|
||||
|
@ -292,7 +292,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
|||
// copy the meshes to the output structure
|
||||
if (apcMeshes.size()) // shouldn't occur, just to be sure we don't crash
|
||||
{
|
||||
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = apcMeshes.size() ];
|
||||
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = (unsigned int)apcMeshes.size() ];
|
||||
::memcpy(pScene->mMeshes,&apcMeshes[0],pScene->mNumMeshes*sizeof(void*));
|
||||
}
|
||||
}
|
||||
|
@ -414,7 +414,7 @@ void LWOImporter::CopyFaceIndices(FaceList::iterator& it,
|
|||
if (mi > mCurLayer->mTempPoints.size())
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO: face index is out of range");
|
||||
mi = mCurLayer->mTempPoints.size()-1;
|
||||
mi = (unsigned int)mCurLayer->mTempPoints.size()-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ void LimitBoneWeightsProcess::Execute( aiScene* pScene)
|
|||
void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
// get the current value of the property
|
||||
this->mMaxWeights = pImp->GetProperty(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
|
||||
this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -45,14 +45,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "ByteSwap.h"
|
||||
#include "MD2NormalTable.h" // shouldn't be included by other units
|
||||
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/aiMesh.h"
|
||||
// public ASSIMP headers
|
||||
#include "../include/assimp.hpp"
|
||||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "../include/assimp.hpp"
|
||||
|
||||
// boost headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -117,10 +118,10 @@ void MD2Importer::SetupProperties(const Importer* pImp)
|
|||
{
|
||||
// The AI_CONFIG_IMPORT_MD2_KEYFRAME option overrides the
|
||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||
AI_CONFIG_IMPORT_MD2_KEYFRAME,0xffffffff)))
|
||||
{
|
||||
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -190,255 +191,247 @@ void MD2Importer::InternReadFile( const std::string& pFile,
|
|||
if( fileSize < sizeof(MD2::Header))
|
||||
throw new ImportErrorException( "MD2 File is too small");
|
||||
|
||||
try
|
||||
std::vector<unsigned char> mBuffer2(fileSize);
|
||||
file->Read(&mBuffer2[0], 1, fileSize);
|
||||
this->mBuffer = &mBuffer2[0];
|
||||
|
||||
|
||||
this->m_pcHeader = (const MD2::Header*)this->mBuffer;
|
||||
|
||||
#ifdef AI_BUILD_BIG_ENDIAN
|
||||
|
||||
ByteSwap::Swap4(&m_pcHeader->frameSize);
|
||||
ByteSwap::Swap4(&m_pcHeader->magic);
|
||||
ByteSwap::Swap4(&m_pcHeader->numFrames);
|
||||
ByteSwap::Swap4(&m_pcHeader->numGlCommands);
|
||||
ByteSwap::Swap4(&m_pcHeader->numSkins);
|
||||
ByteSwap::Swap4(&m_pcHeader->numTexCoords);
|
||||
ByteSwap::Swap4(&m_pcHeader->numTriangles);
|
||||
ByteSwap::Swap4(&m_pcHeader->numVertices);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetEnd);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetFrames);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetGlCommands);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetSkins);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetTexCoords);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetTriangles);
|
||||
ByteSwap::Swap4(&m_pcHeader->skinHeight);
|
||||
ByteSwap::Swap4(&m_pcHeader->skinWidth);
|
||||
ByteSwap::Swap4(&m_pcHeader->version);
|
||||
|
||||
#endif
|
||||
|
||||
this->ValidateHeader();
|
||||
|
||||
// there won't be more than one mesh inside the file
|
||||
pScene->mNumMaterials = 1;
|
||||
pScene->mRootNode = new aiNode();
|
||||
pScene->mRootNode->mNumMeshes = 1;
|
||||
pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||
pScene->mRootNode->mMeshes[0] = 0;
|
||||
pScene->mMaterials = new aiMaterial*[1];
|
||||
pScene->mMaterials[0] = new MaterialHelper();
|
||||
pScene->mNumMeshes = 1;
|
||||
pScene->mMeshes = new aiMesh*[1];
|
||||
aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
|
||||
|
||||
// navigate to the begin of the frame data
|
||||
const MD2::Frame* pcFrame = (const MD2::Frame*) ((uint8_t*)
|
||||
this->m_pcHeader + this->m_pcHeader->offsetFrames);
|
||||
pcFrame += this->configFrameID;
|
||||
|
||||
// navigate to the begin of the triangle data
|
||||
MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)
|
||||
this->m_pcHeader + this->m_pcHeader->offsetTriangles);
|
||||
|
||||
// navigate to the begin of the tex coords data
|
||||
const MD2::TexCoord* pcTexCoords = (const MD2::TexCoord*) ((uint8_t*)
|
||||
this->m_pcHeader + this->m_pcHeader->offsetTexCoords);
|
||||
|
||||
// navigate to the begin of the vertex data
|
||||
const MD2::Vertex* pcVerts = (const MD2::Vertex*) (pcFrame->vertices);
|
||||
|
||||
#ifdef AI_BUILD_BIG_ENDIAN
|
||||
for (uint32_t i = 0; i< m_pcHeader->numTriangles)
|
||||
{
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
this->mBuffer = new unsigned char[fileSize];
|
||||
file->Read( (void*)mBuffer, 1, fileSize);
|
||||
|
||||
this->m_pcHeader = (const MD2::Header*)this->mBuffer;
|
||||
|
||||
#ifdef AI_BUILD_BIG_ENDIAN
|
||||
|
||||
ByteSwap::Swap4(&m_pcHeader->frameSize);
|
||||
ByteSwap::Swap4(&m_pcHeader->magic);
|
||||
ByteSwap::Swap4(&m_pcHeader->numFrames);
|
||||
ByteSwap::Swap4(&m_pcHeader->numGlCommands);
|
||||
ByteSwap::Swap4(&m_pcHeader->numSkins);
|
||||
ByteSwap::Swap4(&m_pcHeader->numTexCoords);
|
||||
ByteSwap::Swap4(&m_pcHeader->numTriangles);
|
||||
ByteSwap::Swap4(&m_pcHeader->numVertices);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetEnd);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetFrames);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetGlCommands);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetSkins);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetTexCoords);
|
||||
ByteSwap::Swap4(&m_pcHeader->offsetTriangles);
|
||||
ByteSwap::Swap4(&m_pcHeader->skinHeight);
|
||||
ByteSwap::Swap4(&m_pcHeader->skinWidth);
|
||||
ByteSwap::Swap4(&m_pcHeader->version);
|
||||
|
||||
for (unsigned int p = 0; p < 3;++p)
|
||||
{
|
||||
ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]);
|
||||
ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < m_pcHeader->offsetTexCoords;++i)
|
||||
{
|
||||
ByteSwap::Swap2(& pcTexCoords[i].s);
|
||||
ByteSwap::Swap2(& pcTexCoords[i].t);
|
||||
}
|
||||
ByteSwap::Swap4( & pcFrame->scale[0] );
|
||||
ByteSwap::Swap4( & pcFrame->scale[1] );
|
||||
ByteSwap::Swap4( & pcFrame->scale[2] );
|
||||
ByteSwap::Swap4( & pcFrame->translate[0] );
|
||||
ByteSwap::Swap4( & pcFrame->translate[1] );
|
||||
ByteSwap::Swap4( & pcFrame->translate[2] );
|
||||
#endif
|
||||
|
||||
this->ValidateHeader();
|
||||
pcMesh->mNumFaces = this->m_pcHeader->numTriangles;
|
||||
pcMesh->mFaces = new aiFace[this->m_pcHeader->numTriangles];
|
||||
|
||||
// there won't be more than one mesh inside the file
|
||||
pScene->mNumMaterials = 1;
|
||||
pScene->mRootNode = new aiNode();
|
||||
pScene->mRootNode->mNumMeshes = 1;
|
||||
pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||
pScene->mRootNode->mMeshes[0] = 0;
|
||||
pScene->mMaterials = new aiMaterial*[1];
|
||||
pScene->mMaterials[0] = new MaterialHelper();
|
||||
pScene->mNumMeshes = 1;
|
||||
pScene->mMeshes = new aiMesh*[1];
|
||||
aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
|
||||
// allocate output storage
|
||||
pcMesh->mNumVertices = (unsigned int)pcMesh->mNumFaces*3;
|
||||
pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
|
||||
pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
|
||||
|
||||
// navigate to the begin of the frame data
|
||||
const MD2::Frame* pcFrame = (const MD2::Frame*) ((uint8_t*)
|
||||
this->m_pcHeader + this->m_pcHeader->offsetFrames);
|
||||
pcFrame += this->configFrameID;
|
||||
// not sure whether there are MD2 files without texture coordinates
|
||||
// NOTE: texture coordinates can be there without a texture,
|
||||
// but a texture can't be there without a valid UV channel
|
||||
if (this->m_pcHeader->numTexCoords && this->m_pcHeader->numSkins)
|
||||
{
|
||||
// navigate to the first texture associated with the mesh
|
||||
const MD2::Skin* pcSkins = (const MD2::Skin*) ((unsigned char*)this->m_pcHeader +
|
||||
this->m_pcHeader->offsetSkins);
|
||||
|
||||
// navigate to the begin of the triangle data
|
||||
MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)
|
||||
this->m_pcHeader + this->m_pcHeader->offsetTriangles);
|
||||
const int iMode = (int)aiShadingMode_Gouraud;
|
||||
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
|
||||
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
// navigate to the begin of the tex coords data
|
||||
const MD2::TexCoord* pcTexCoords = (const MD2::TexCoord*) ((uint8_t*)
|
||||
this->m_pcHeader + this->m_pcHeader->offsetTexCoords);
|
||||
aiColor3D clr;
|
||||
clr.b = clr.g = clr.r = 1.0f;
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
|
||||
|
||||
// navigate to the begin of the vertex data
|
||||
const MD2::Vertex* pcVerts = (const MD2::Vertex*) (pcFrame->vertices);
|
||||
clr.b = clr.g = clr.r = 0.05f;
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
|
||||
|
||||
#ifdef AI_BUILD_BIG_ENDIAN
|
||||
for (uint32_t i = 0; i< m_pcHeader->numTriangles)
|
||||
if (pcSkins->name[0])
|
||||
{
|
||||
for (unsigned int p = 0; p < 3;++p)
|
||||
{
|
||||
ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]);
|
||||
ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < m_pcHeader->offsetTexCoords;++i)
|
||||
{
|
||||
ByteSwap::Swap2(& pcTexCoords[i].s);
|
||||
ByteSwap::Swap2(& pcTexCoords[i].t);
|
||||
}
|
||||
ByteSwap::Swap4( & pcFrame->scale[0] );
|
||||
ByteSwap::Swap4( & pcFrame->scale[1] );
|
||||
ByteSwap::Swap4( & pcFrame->scale[2] );
|
||||
ByteSwap::Swap4( & pcFrame->translate[0] );
|
||||
ByteSwap::Swap4( & pcFrame->translate[1] );
|
||||
ByteSwap::Swap4( & pcFrame->translate[2] );
|
||||
#endif
|
||||
aiString szString;
|
||||
const size_t iLen = ::strlen(pcSkins->name);
|
||||
::memcpy(szString.data,pcSkins->name,iLen);
|
||||
szString.data[iLen] = '\0';
|
||||
szString.length = iLen;
|
||||
|
||||
pcMesh->mNumFaces = this->m_pcHeader->numTriangles;
|
||||
pcMesh->mFaces = new aiFace[this->m_pcHeader->numTriangles];
|
||||
|
||||
// allocate output storage
|
||||
pcMesh->mNumVertices = (unsigned int)pcMesh->mNumFaces*3;
|
||||
pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
|
||||
pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
|
||||
|
||||
// not sure whether there are MD2 files without texture coordinates
|
||||
// NOTE: texture coordinates can be there without a texture,
|
||||
// but a texture can't be there without a valid UV channel
|
||||
if (this->m_pcHeader->numTexCoords && this->m_pcHeader->numSkins)
|
||||
{
|
||||
// navigate to the first texture associated with the mesh
|
||||
const MD2::Skin* pcSkins = (const MD2::Skin*) ((unsigned char*)this->m_pcHeader +
|
||||
this->m_pcHeader->offsetSkins);
|
||||
|
||||
const int iMode = (int)aiShadingMode_Gouraud;
|
||||
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
|
||||
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
aiColor3D clr;
|
||||
clr.b = clr.g = clr.r = 1.0f;
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
|
||||
|
||||
clr.b = clr.g = clr.r = 0.05f;
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
|
||||
|
||||
if (pcSkins->name[0])
|
||||
{
|
||||
aiString szString;
|
||||
const size_t iLen = ::strlen(pcSkins->name);
|
||||
::memcpy(szString.data,pcSkins->name,iLen);
|
||||
szString.data[iLen] = '\0';
|
||||
szString.length = iLen;
|
||||
|
||||
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultLogger::get()->warn("Texture file name has zero length. It will be skipped.");
|
||||
}
|
||||
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// apply a default material
|
||||
const int iMode = (int)aiShadingMode_Gouraud;
|
||||
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
|
||||
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
aiColor3D clr;
|
||||
clr.b = clr.g = clr.r = 0.6f;
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
|
||||
|
||||
clr.b = clr.g = clr.r = 0.05f;
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
|
||||
|
||||
aiString szName;
|
||||
szName.Set(AI_DEFAULT_MATERIAL_NAME);
|
||||
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
|
||||
}
|
||||
|
||||
|
||||
// now read all triangles of the first frame, apply scaling and translation
|
||||
unsigned int iCurrent = 0;
|
||||
|
||||
float fDivisorU,fDivisorV;
|
||||
if (this->m_pcHeader->numTexCoords)
|
||||
{
|
||||
// allocate storage for texture coordinates, too
|
||||
pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
|
||||
pcMesh->mNumUVComponents[0] = 2;
|
||||
|
||||
// check whether the skin width or height are zero (this would
|
||||
// cause a division through zero)
|
||||
if (!this->m_pcHeader->skinWidth)
|
||||
{
|
||||
DefaultLogger::get()->error("Skin width is zero but there are "
|
||||
"valid absolute texture coordinates. Unable to compute "
|
||||
"relative texture coordinates ranging from 0 to 1");
|
||||
fDivisorU = 1.0f;
|
||||
}
|
||||
else fDivisorU = (float)this->m_pcHeader->skinWidth;
|
||||
if (!this->m_pcHeader->skinHeight)
|
||||
{
|
||||
DefaultLogger::get()->error("Skin height is zero but there are "
|
||||
"valid absolute texture coordinates. Unable to compute "
|
||||
"relative texture coordinates ranging from 0 to 1");
|
||||
fDivisorV = 1.0f;
|
||||
}
|
||||
else fDivisorV = (float)this->m_pcHeader->skinHeight;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < (unsigned int)this->m_pcHeader->numTriangles;++i)
|
||||
{
|
||||
// allocate the face
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices = new unsigned int[3];
|
||||
pScene->mMeshes[0]->mFaces[i].mNumIndices = 3;
|
||||
|
||||
// copy texture coordinates
|
||||
// check whether they are different from the previous value at this index.
|
||||
// In this case, create a full separate set of vertices/normals/texcoords
|
||||
unsigned int iTemp = iCurrent;
|
||||
for (unsigned int c = 0; c < 3;++c,++iCurrent)
|
||||
{
|
||||
// validate vertex indices
|
||||
if (pcTriangles[i].vertexIndices[c] >= this->m_pcHeader->numVertices)
|
||||
{
|
||||
DefaultLogger::get()->error("Vertex index is outside the allowed range");
|
||||
pcTriangles[i].vertexIndices[c] = this->m_pcHeader->numVertices-1;
|
||||
}
|
||||
|
||||
// copy face indices
|
||||
unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c];
|
||||
|
||||
// read x,y, and z component of the vertex
|
||||
aiVector3D& vec = pcMesh->mVertices[iCurrent];
|
||||
|
||||
vec.x = (float)pcVerts[iIndex].vertex[0] * pcFrame->scale[0];
|
||||
vec.x += pcFrame->translate[0];
|
||||
|
||||
// (flip z and y component)
|
||||
// FIX: no .... invert y instead
|
||||
vec.y = (float)pcVerts[iIndex].vertex[1] * pcFrame->scale[1];
|
||||
vec.y += pcFrame->translate[1];
|
||||
vec.y *= -1.0f;
|
||||
|
||||
vec.z = (float)pcVerts[iIndex].vertex[2] * pcFrame->scale[2];
|
||||
vec.z += pcFrame->translate[2];
|
||||
|
||||
// read the normal vector from the precalculated normal table
|
||||
aiVector3D& vNormal = pcMesh->mNormals[iCurrent];
|
||||
LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal);
|
||||
vNormal.y *= -1.0f;
|
||||
|
||||
if (this->m_pcHeader->numTexCoords)
|
||||
{
|
||||
// validate texture coordinates
|
||||
if (pcTriangles[iIndex].textureIndices[c] >= this->m_pcHeader->numTexCoords)
|
||||
{
|
||||
DefaultLogger::get()->error("UV index is outside the allowed range");
|
||||
pcTriangles[iIndex].textureIndices[c] = this->m_pcHeader->numTexCoords-1;
|
||||
}
|
||||
|
||||
aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent];
|
||||
float u,v;
|
||||
|
||||
// the texture coordinates are absolute values but we
|
||||
// need relative values between 0 and 1
|
||||
u = (float)pcTexCoords[pcTriangles[i].textureIndices[c]].s / fDivisorU;
|
||||
v = (float)pcTexCoords[pcTriangles[i].textureIndices[c]].t / fDivisorV;
|
||||
pcOut.x = u;
|
||||
pcOut.y = 1.0f - v; // FIXME: Is this correct for MD2?
|
||||
}
|
||||
}
|
||||
// FIX: flip the face order for use with OpenGL
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices[0] = iTemp+2;
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices[1] = iTemp+1;
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices[2] = iTemp+0;
|
||||
DefaultLogger::get()->warn("Texture file name has zero length. It will be skipped.");
|
||||
}
|
||||
}
|
||||
catch (ImportErrorException* ex)
|
||||
else
|
||||
{
|
||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw ex;
|
||||
// apply a default material
|
||||
const int iMode = (int)aiShadingMode_Gouraud;
|
||||
MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
|
||||
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
aiColor3D clr;
|
||||
clr.b = clr.g = clr.r = 0.6f;
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
|
||||
|
||||
clr.b = clr.g = clr.r = 0.05f;
|
||||
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
|
||||
|
||||
aiString szName;
|
||||
szName.Set(AI_DEFAULT_MATERIAL_NAME);
|
||||
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
|
||||
}
|
||||
|
||||
|
||||
// now read all triangles of the first frame, apply scaling and translation
|
||||
unsigned int iCurrent = 0;
|
||||
|
||||
float fDivisorU,fDivisorV;
|
||||
if (this->m_pcHeader->numTexCoords)
|
||||
{
|
||||
// allocate storage for texture coordinates, too
|
||||
pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
|
||||
pcMesh->mNumUVComponents[0] = 2;
|
||||
|
||||
// check whether the skin width or height are zero (this would
|
||||
// cause a division through zero)
|
||||
if (!this->m_pcHeader->skinWidth)
|
||||
{
|
||||
DefaultLogger::get()->error("Skin width is zero but there are "
|
||||
"valid absolute texture coordinates. Unable to compute "
|
||||
"relative texture coordinates ranging from 0 to 1");
|
||||
fDivisorU = 1.0f;
|
||||
}
|
||||
else fDivisorU = (float)this->m_pcHeader->skinWidth;
|
||||
if (!this->m_pcHeader->skinHeight)
|
||||
{
|
||||
DefaultLogger::get()->error("Skin height is zero but there are "
|
||||
"valid absolute texture coordinates. Unable to compute "
|
||||
"relative texture coordinates ranging from 0 to 1");
|
||||
fDivisorV = 1.0f;
|
||||
}
|
||||
else fDivisorV = (float)this->m_pcHeader->skinHeight;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < (unsigned int)this->m_pcHeader->numTriangles;++i)
|
||||
{
|
||||
// allocate the face
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices = new unsigned int[3];
|
||||
pScene->mMeshes[0]->mFaces[i].mNumIndices = 3;
|
||||
|
||||
// copy texture coordinates
|
||||
// check whether they are different from the previous value at this index.
|
||||
// In this case, create a full separate set of vertices/normals/texcoords
|
||||
unsigned int iTemp = iCurrent;
|
||||
for (unsigned int c = 0; c < 3;++c,++iCurrent)
|
||||
{
|
||||
// validate vertex indices
|
||||
if (pcTriangles[i].vertexIndices[c] >= this->m_pcHeader->numVertices)
|
||||
{
|
||||
DefaultLogger::get()->error("Vertex index is outside the allowed range");
|
||||
pcTriangles[i].vertexIndices[c] = this->m_pcHeader->numVertices-1;
|
||||
}
|
||||
|
||||
// copy face indices
|
||||
unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c];
|
||||
|
||||
// read x,y, and z component of the vertex
|
||||
aiVector3D& vec = pcMesh->mVertices[iCurrent];
|
||||
|
||||
vec.x = (float)pcVerts[iIndex].vertex[0] * pcFrame->scale[0];
|
||||
vec.x += pcFrame->translate[0];
|
||||
|
||||
// (flip z and y component)
|
||||
// FIX: no .... invert y instead
|
||||
vec.y = (float)pcVerts[iIndex].vertex[1] * pcFrame->scale[1];
|
||||
vec.y += pcFrame->translate[1];
|
||||
vec.y *= -1.0f;
|
||||
|
||||
vec.z = (float)pcVerts[iIndex].vertex[2] * pcFrame->scale[2];
|
||||
vec.z += pcFrame->translate[2];
|
||||
|
||||
// read the normal vector from the precalculated normal table
|
||||
aiVector3D& vNormal = pcMesh->mNormals[iCurrent];
|
||||
LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal);
|
||||
vNormal.y *= -1.0f;
|
||||
|
||||
if (this->m_pcHeader->numTexCoords)
|
||||
{
|
||||
// validate texture coordinates
|
||||
if (pcTriangles[iIndex].textureIndices[c] >= this->m_pcHeader->numTexCoords)
|
||||
{
|
||||
DefaultLogger::get()->error("UV index is outside the allowed range");
|
||||
pcTriangles[iIndex].textureIndices[c] = this->m_pcHeader->numTexCoords-1;
|
||||
}
|
||||
|
||||
aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent];
|
||||
float u,v;
|
||||
|
||||
// the texture coordinates are absolute values but we
|
||||
// need relative values between 0 and 1
|
||||
u = (float)pcTexCoords[pcTriangles[i].textureIndices[c]].s / fDivisorU;
|
||||
v = (float)pcTexCoords[pcTriangles[i].textureIndices[c]].t / fDivisorV;
|
||||
pcOut.x = u;
|
||||
pcOut.y = 1.0f - v; // FIXME: Is this correct for MD2?
|
||||
}
|
||||
}
|
||||
// FIX: flip the face order for use with OpenGL
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices[0] = iTemp+2;
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices[1] = iTemp+1;
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices[2] = iTemp+0;
|
||||
}
|
||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
}
|
||||
|
|
|
@ -144,10 +144,10 @@ void MD3Importer::SetupProperties(const Importer* pImp)
|
|||
{
|
||||
// The AI_CONFIG_IMPORT_MD3_KEYFRAME option overrides the
|
||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||
AI_CONFIG_IMPORT_MD3_KEYFRAME,0xffffffff)))
|
||||
{
|
||||
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -61,14 +61,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
// we're just doing this with static buffers whose size is known at
|
||||
// compile time, so the compiler should automatically expand to
|
||||
// sprintf<array_length>(...)
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
# define sprintf sprintf_s
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
MD5Importer::MD5Importer()
|
||||
|
@ -122,9 +114,8 @@ void MD5Importer::InternReadFile(
|
|||
|
||||
// make sure we return no incomplete data
|
||||
if (!bHadMD5Mesh && !bHadMD5Anim)
|
||||
{
|
||||
throw new ImportErrorException("Failed to read valid data from this MD5");
|
||||
}
|
||||
|
||||
if (!bHadMD5Mesh)pScene->mFlags |= AI_SCENE_FLAGS_ANIM_SKELETON_ONLY;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -285,30 +276,48 @@ void MD5Importer::LoadMD5MeshFile ()
|
|||
pScene->mRootNode->mNumChildren = 2;
|
||||
pScene->mRootNode->mChildren = new aiNode*[2];
|
||||
|
||||
aiNode* pcNode = pScene->mRootNode->mChildren[0] = new aiNode();
|
||||
pcNode->mNumMeshes = (unsigned int)meshParser.mMeshes.size();
|
||||
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
||||
pcNode->mName.Set("MD5Mesh");
|
||||
pcNode->mParent = pScene->mRootNode;
|
||||
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
|
||||
{
|
||||
pcNode->mMeshes[i] = i;
|
||||
}
|
||||
|
||||
// now create the hierarchy of animated bones
|
||||
pcNode = pScene->mRootNode->mChildren[1] = new aiNode();
|
||||
aiNode* pcNode = pScene->mRootNode->mChildren[1] = new aiNode();
|
||||
pcNode->mName.Set("MD5Anim");
|
||||
pcNode->mParent = pScene->mRootNode;
|
||||
AttachChilds(-1,pcNode,meshParser.mJoints);
|
||||
|
||||
pcNode = pScene->mRootNode->mChildren[0] = new aiNode();
|
||||
pcNode->mName.Set("MD5Mesh");
|
||||
pcNode->mParent = pScene->mRootNode;
|
||||
|
||||
std::vector<MD5::MeshDesc>::const_iterator end = meshParser.mMeshes.end();
|
||||
|
||||
// FIX: MD5 files exported from Blender can have empty meshes
|
||||
for (std::vector<MD5::MeshDesc>::const_iterator
|
||||
it = meshParser.mMeshes.begin(),
|
||||
end = meshParser.mMeshes.end(); it != end;++it)
|
||||
{
|
||||
if (!(*it).mFaces.empty() && !(*it).mVertices.empty())
|
||||
++pScene->mNumMaterials;
|
||||
}
|
||||
|
||||
// generate all meshes
|
||||
pScene->mNumMeshes = pScene->mNumMaterials = (unsigned int)meshParser.mMeshes.size();
|
||||
pScene->mNumMeshes = pScene->mNumMaterials;
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes];
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
|
||||
// storage for node mesh indices
|
||||
pcNode->mNumMeshes = pScene->mNumMeshes;
|
||||
pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
||||
for (unsigned int m = 0; m < pcNode->mNumMeshes;++m)
|
||||
pcNode->mMeshes[m] = m;
|
||||
|
||||
unsigned int n = 0;
|
||||
for (std::vector<MD5::MeshDesc>::iterator
|
||||
it = meshParser.mMeshes.begin(),
|
||||
end = meshParser.mMeshes.end(); it != end;++it)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[i] = new aiMesh();
|
||||
MD5::MeshDesc& meshSrc = meshParser.mMeshes[i];
|
||||
MD5::MeshDesc& meshSrc = *it;
|
||||
if (meshSrc.mFaces.empty() || meshSrc.mVertices.empty())
|
||||
continue;
|
||||
|
||||
aiMesh* mesh = pScene->mMeshes[n] = new aiMesh();
|
||||
|
||||
// generate unique vertices in our internal verbose format
|
||||
MakeDataUnique(meshSrc);
|
||||
|
@ -424,9 +433,9 @@ void MD5Importer::LoadMD5MeshFile ()
|
|||
|
||||
// generate a material for the mesh
|
||||
MaterialHelper* mat = new MaterialHelper();
|
||||
pScene->mMaterials[i] = mat;
|
||||
pScene->mMaterials[n] = mat;
|
||||
mat->AddProperty(&meshSrc.mShader,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
mesh->mMaterialIndex = i;
|
||||
mesh->mMaterialIndex = n++;
|
||||
}
|
||||
|
||||
// delete the file again
|
||||
|
|
|
@ -194,10 +194,10 @@ void MDCImporter::SetupProperties(const Importer* pImp)
|
|||
{
|
||||
// The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the
|
||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||
AI_CONFIG_IMPORT_MDC_KEYFRAME,0xffffffff)))
|
||||
{
|
||||
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -443,7 +443,7 @@ void MDCImporter::InternReadFile(
|
|||
pScene->mMeshes[i]->mTextureCoords[3] = NULL;
|
||||
|
||||
// create materials
|
||||
pScene->mNumMaterials = aszShaders.size();
|
||||
pScene->mNumMaterials = (unsigned int)aszShaders.size();
|
||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
{
|
||||
|
|
|
@ -51,11 +51,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// public ASSIMP headers
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/assimp.hpp"
|
||||
|
||||
// boost headers
|
||||
|
@ -119,11 +118,12 @@ void MDLImporter::SetupProperties(const Importer* pImp)
|
|||
{
|
||||
// The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
|
||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||
AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff)))
|
||||
{
|
||||
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
}
|
||||
this->configPalette = pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP,"colormap.lmp");
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
|
|
|
@ -55,8 +55,7 @@ struct aiNode;
|
|||
#include "MDLFileData.h"
|
||||
#include "HalfLifeFileData.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Assimp {
|
||||
class MaterialHelper;
|
||||
|
||||
using namespace MDL;
|
||||
|
@ -442,6 +441,9 @@ protected:
|
|||
/** Configuration option: frame to be loaded */
|
||||
unsigned int configFrameID;
|
||||
|
||||
/** Configuration option: palette to be used to decode palletized images*/
|
||||
std::string configPalette;
|
||||
|
||||
/** Buffer to hold the loaded file */
|
||||
unsigned char* mBuffer;
|
||||
|
||||
|
@ -449,16 +451,13 @@ protected:
|
|||
* (MDL7 doesn't need this, the format has a separate loader) */
|
||||
unsigned int iGSFileVersion;
|
||||
|
||||
/** Output I/O handler. used to load external lmp files
|
||||
*/
|
||||
/** Output I/O handler. used to load external lmp files */
|
||||
IOSystem* pIOHandler;
|
||||
|
||||
/** Output scene to be filled
|
||||
*/
|
||||
/** Output scene to be filled */
|
||||
aiScene* pScene;
|
||||
|
||||
/** Size of the input file in bytes
|
||||
*/
|
||||
/** Size of the input file in bytes */
|
||||
unsigned int iFileSize;
|
||||
};
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ using namespace Assimp;
|
|||
void MDLImporter::SearchPalette(const unsigned char** pszColorMap)
|
||||
{
|
||||
// now try to find the color map in the current directory
|
||||
IOStream* pcStream = this->pIOHandler->Open("colormap.lmp","rb");
|
||||
IOStream* pcStream = this->pIOHandler->Open(configPalette,"rb");
|
||||
|
||||
const unsigned char* szColorMap = (const unsigned char*)::g_aclrDefaultColorMap;
|
||||
if(pcStream)
|
||||
|
|
|
@ -268,7 +268,7 @@ uint32_t MaterialHelper::ComputeHash()
|
|||
// NOTE: We need to exclude the material name from the hash
|
||||
if ((prop = this->mProperties[i]) && 0 != ::strcmp(prop->mKey.data,AI_MATKEY_NAME))
|
||||
{
|
||||
hash = SuperFastHash(prop->mKey.data,prop->mKey.length,hash);
|
||||
hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash);
|
||||
hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
|
||||
}
|
||||
}
|
||||
|
@ -371,8 +371,8 @@ aiReturn MaterialHelper::AddProperty (const aiString* pInput,
|
|||
const char* pKey)
|
||||
{
|
||||
// fix ... don't keep the whole string buffer
|
||||
return this->AddBinaryProperty(pInput,
|
||||
pInput->length+1+ (size_t)((uint8_t*)&pInput->data - (uint8_t*)&pInput->length),
|
||||
return this->AddBinaryProperty(pInput,(unsigned int)pInput->length+1+
|
||||
(unsigned int)(((uint8_t*)&pInput->data - (uint8_t*)&pInput->length)),
|
||||
pKey,aiPTI_String);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -41,13 +41,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "ObjFileImporter.h"
|
||||
#include "ObjFileParser.h"
|
||||
#include "ObjFileData.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/aiMesh.h"
|
||||
#include "MaterialSystem.h"
|
||||
|
||||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "MaterialSystem.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
@ -237,7 +237,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
|
|||
if ( meshSizeDiff > 0 )
|
||||
{
|
||||
pNode->mMeshes = new unsigned int[ meshSizeDiff ];
|
||||
pNode->mNumMeshes = meshSizeDiff;
|
||||
pNode->mNumMeshes = (unsigned int)meshSizeDiff;
|
||||
size_t index = 0;
|
||||
for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
|
||||
{
|
||||
|
|
|
@ -306,8 +306,8 @@ void ObjFileParser::getFace()
|
|||
|
||||
// Store the face
|
||||
m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
|
||||
m_pModel->m_pCurrentMesh->m_uiNumIndices += face->m_pVertices->size();
|
||||
m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += face->m_pTexturCoords[0].size();
|
||||
m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
|
||||
m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size();
|
||||
|
||||
// Skip the rest of the line
|
||||
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
|
||||
|
@ -462,7 +462,7 @@ int ObjFileParser::getMaterialIndex( const std::string &strMaterialName )
|
|||
{
|
||||
if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
|
||||
{
|
||||
mat_index = index;
|
||||
mat_index = (int)index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
||||
// internal headers
|
||||
#include "PlyLoader.h"
|
||||
#include "MaterialSystem.h"
|
||||
#include "StringComparison.h"
|
||||
|
||||
// public ASSIMP headers
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "../include/DefaultLogger.h"
|
||||
|
||||
// boost headeers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -95,24 +100,19 @@ void PLYImporter::InternReadFile(
|
|||
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL)
|
||||
{
|
||||
throw new ImportErrorException( "Failed to open PLY file " + pFile + ".");
|
||||
}
|
||||
|
||||
// check whether the ply file is large enough to contain
|
||||
// at least the file header
|
||||
size_t fileSize = file->FileSize();
|
||||
if( fileSize < 10)
|
||||
{
|
||||
throw new ImportErrorException( "PLY File is too small.");
|
||||
}
|
||||
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
// (terminate it with zero)
|
||||
// FIX: Allocate an extra buffer of 12.5% to be sure we won't crash
|
||||
// if an overrun occurs.
|
||||
this->mBuffer = new unsigned char[fileSize+1 + (fileSize>>3)];
|
||||
file->Read( (void*)mBuffer, 1, fileSize);
|
||||
std::vector<unsigned char> mBuffer2(fileSize+1);
|
||||
file->Read( &mBuffer2[0], 1, fileSize);
|
||||
this->mBuffer = &mBuffer2[0];
|
||||
this->mBuffer[fileSize] = '\0';
|
||||
|
||||
// the beginning of the file must be PLY
|
||||
|
@ -120,8 +120,6 @@ void PLYImporter::InternReadFile(
|
|||
this->mBuffer[1] != 'L' && this->mBuffer[1] != 'l' ||
|
||||
this->mBuffer[2] != 'Y' && this->mBuffer[2] != 'y')
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw new ImportErrorException( "Invalid .ply file: Magic number \'ply\' is no there");
|
||||
}
|
||||
char* szMe = (char*)&this->mBuffer[3];
|
||||
|
@ -137,11 +135,7 @@ void PLYImporter::InternReadFile(
|
|||
szMe += 6;
|
||||
SkipLine(szMe,(const char**)&szMe);
|
||||
if(!PLY::DOM::ParseInstance(szMe,&sPlyDom))
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw new ImportErrorException( "Invalid .ply file: Unable to build DOM (#1)");
|
||||
}
|
||||
}
|
||||
else if (0 == ASSIMP_strincmp(szMe,"binary_",7))
|
||||
{
|
||||
|
@ -159,18 +153,9 @@ void PLYImporter::InternReadFile(
|
|||
// skip the line, parse the rest of the header and build the DOM
|
||||
SkipLine(szMe,(const char**)&szMe);
|
||||
if(!PLY::DOM::ParseInstanceBinary(szMe,&sPlyDom,bIsBE))
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw new ImportErrorException( "Invalid .ply file: Unable to build DOM (#2)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw new ImportErrorException( "Invalid .ply file: Unknown file format");
|
||||
}
|
||||
else throw new ImportErrorException( "Invalid .ply file: Unknown file format");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -185,12 +170,8 @@ void PLYImporter::InternReadFile(
|
|||
this->LoadVertices(&avPositions,false);
|
||||
|
||||
if (avPositions.empty())
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw new ImportErrorException( "Invalid .ply file: No vertices found. "
|
||||
"Unable to interpret the data format of the PLY file");
|
||||
}
|
||||
"Unable to parse the data format of the PLY file.");
|
||||
|
||||
// now load a list of normals.
|
||||
std::vector<aiVector3D> avNormals;
|
||||
|
@ -206,10 +187,8 @@ void PLYImporter::InternReadFile(
|
|||
{
|
||||
if (avPositions.size() < 3)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw new ImportErrorException( "Invalid .ply file: Not enough vertices to build "
|
||||
"a face list. ");
|
||||
throw new ImportErrorException( "Invalid .ply file: Not enough "
|
||||
"vertices to build a face list. ");
|
||||
}
|
||||
|
||||
unsigned int iNum = (unsigned int)avPositions.size() / 3;
|
||||
|
@ -244,11 +223,7 @@ void PLYImporter::InternReadFile(
|
|||
&avColors,&avTexCoords,&avMaterials,&avMeshes);
|
||||
|
||||
if (avMeshes.empty())
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw new ImportErrorException( "Invalid .ply file: Unable to extract mesh data ");
|
||||
}
|
||||
|
||||
// now generate the output scene object. Fill the material list
|
||||
pScene->mNumMaterials = (unsigned int)avMaterials.size();
|
||||
|
@ -269,12 +244,6 @@ void PLYImporter::InternReadFile(
|
|||
|
||||
for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes;++i)
|
||||
pScene->mRootNode->mMeshes[i] = i;
|
||||
|
||||
// delete the file buffer
|
||||
delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
|
||||
// DOM is lying on the stack, will be deconstructed automatically
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
|
||||
|
@ -819,9 +788,8 @@ void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
|
|||
|
||||
if (3 > iNum)
|
||||
{
|
||||
// We must filter out all degenerates. Leave a message
|
||||
// in the log ...
|
||||
// LOG
|
||||
// We must filter out all degenerates.
|
||||
DefaultLogger::get()->warn("PLY: Found degenerated triangle");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,17 +52,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
PretransformVertices::PretransformVertices()
|
||||
{
|
||||
}
|
||||
|
||||
{
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
PretransformVertices::~PretransformVertices()
|
||||
{
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool PretransformVertices::IsActive( unsigned int pFlags) const
|
||||
|
|
|
@ -12,18 +12,18 @@ with or without modification, are permitted provided that the following
|
|||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
|
@ -40,66 +40,53 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
/** @file Implementation of the helper class to quickly find
|
||||
vertices close to a given position. Special implementation for
|
||||
the 3ds loader handling smooth groups correctly */
|
||||
vertices close to a given position. Special implementation for
|
||||
the 3ds loader handling smooth groups correctly */
|
||||
|
||||
#include <algorithm>
|
||||
#include "3DSSpatialSort.h"
|
||||
#include "SGSpatialSort.h"
|
||||
|
||||
#include "../include/aiAssert.h"
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Dot3DS;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
D3DSSpatialSorter::D3DSSpatialSorter()
|
||||
{
|
||||
SGSpatialSort::SGSpatialSort()
|
||||
{
|
||||
// define the reference plane. We choose some arbitrary vector away from all basic axises
|
||||
// in the hope that no model spreads all its vertices along this plane.
|
||||
mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
|
||||
mPlaneNormal.Normalize();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
D3DSSpatialSorter::~D3DSSpatialSorter()
|
||||
{
|
||||
// nothing to do here, everything destructs automatically
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void D3DSSpatialSorter::AddFace(const Dot3DS::Face* pcFace,
|
||||
const std::vector<aiVector3D>& vPositions)
|
||||
{
|
||||
ai_assert(NULL != pcFace);
|
||||
|
||||
// store position by index and distance
|
||||
float distance = vPositions[pcFace->mIndices[0]] * mPlaneNormal;
|
||||
mPositions.push_back( Entry( pcFace->mIndices[0], vPositions[pcFace->mIndices[0]],
|
||||
distance, pcFace->iSmoothGroup));
|
||||
|
||||
// triangle vertex 2
|
||||
distance = vPositions[pcFace->mIndices[1]] * mPlaneNormal;
|
||||
mPositions.push_back( Entry( pcFace->mIndices[1], vPositions[pcFace->mIndices[1]],
|
||||
distance, pcFace->iSmoothGroup));
|
||||
|
||||
// triangle vertex 3
|
||||
distance = vPositions[pcFace->mIndices[2]] * mPlaneNormal;
|
||||
mPositions.push_back( Entry( pcFace->mIndices[2], vPositions[pcFace->mIndices[2]],
|
||||
distance, pcFace->iSmoothGroup));
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void D3DSSpatialSorter::Prepare()
|
||||
// Destructor
|
||||
SGSpatialSort::~SGSpatialSort()
|
||||
{
|
||||
// nothing to do here, everything destructs automatically
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SGSpatialSort::Add(const aiVector3D& vPosition, unsigned int index,
|
||||
unsigned int smoothingGroup)
|
||||
{
|
||||
// store position by index and distance
|
||||
float distance = vPosition * mPlaneNormal;
|
||||
mPositions.push_back( Entry( index, vPosition,
|
||||
distance, smoothingGroup));
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SGSpatialSort::Prepare()
|
||||
{
|
||||
// now sort the array ascending by distance.
|
||||
std::sort( this->mPositions.begin(), this->mPositions.end());
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns an iterator for all positions close to the given position.
|
||||
void D3DSSpatialSorter::FindPositions( const aiVector3D& pPosition,
|
||||
uint32_t pSG,
|
||||
float pRadius,
|
||||
std::vector<unsigned int>& poResults) const
|
||||
{
|
||||
void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
|
||||
uint32_t pSG,
|
||||
float pRadius,
|
||||
std::vector<unsigned int>& poResults) const
|
||||
{
|
||||
float dist = pPosition * mPlaneNormal;
|
||||
float minDist = dist - pRadius, maxDist = dist + pRadius;
|
||||
|
||||
|
@ -119,14 +106,14 @@ void D3DSSpatialSorter::FindPositions( const aiVector3D& pPosition,
|
|||
unsigned int index = (unsigned int)mPositions.size() / 2;
|
||||
unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
|
||||
while( binaryStepSize > 1)
|
||||
{
|
||||
{
|
||||
if( mPositions[index].mDistance < minDist)
|
||||
index += binaryStepSize;
|
||||
else
|
||||
index -= binaryStepSize;
|
||||
|
||||
binaryStepSize /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// depending on the direction of the last step we need to single step a bit back or forth
|
||||
// to find the actual beginning element of the range
|
||||
|
@ -140,33 +127,16 @@ void D3DSSpatialSorter::FindPositions( const aiVector3D& pPosition,
|
|||
|
||||
float squareEpsilon = pRadius * pRadius;
|
||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
||||
if (0 == pSG)
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
|
||||
(it->mSmoothGroups & pSG || 0 == it->mSmoothGroups || 0 == pSG))
|
||||
{
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon)
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
++it;
|
||||
if( it == mPositions.end())
|
||||
break;
|
||||
}
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
|
||||
(it->mSmoothGroups & pSG || 0 == it->mSmoothGroups))
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
++it;
|
||||
if( it == mPositions.end())
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
++it;
|
||||
if( it == mPositions.end())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -44,40 +44,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define AI_D3DSSPATIALSORT_H_INC
|
||||
|
||||
#include <vector>
|
||||
#include "../include/aiVector3D.h"
|
||||
|
||||
|
||||
#if (!defined AI_BUILD_NO_ASE_IMPORTER)
|
||||
# include "3DSHelper.h"
|
||||
#endif
|
||||
#include "../include/aiTypes.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
using namespace Dot3DS;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Specialized version of SpatialSort to support smoothing groups
|
||||
* This is used in the .3ds loader
|
||||
*/
|
||||
class D3DSSpatialSorter
|
||||
class SGSpatialSort
|
||||
{
|
||||
public:
|
||||
|
||||
D3DSSpatialSorter();
|
||||
SGSpatialSort();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Construction from a given face array, handling smoothing groups properly
|
||||
*/
|
||||
D3DSSpatialSorter(const std::vector<aiVector3D>& vPositions);
|
||||
SGSpatialSort(const std::vector<aiVector3D>& vPositions);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add a face to the spatial sorter
|
||||
* @param pcFace Face to be added
|
||||
* @param vPositions Input position list
|
||||
/** Add a vertex to the spatial sort
|
||||
* @param vPosition Vertex position to be added
|
||||
* @param index Index of the vrtex
|
||||
* @param smoothingGroup SmoothingGroup for this vertex
|
||||
*/
|
||||
void AddFace(const Dot3DS::Face* pcFace,
|
||||
const std::vector<aiVector3D>& vPositions);
|
||||
void Add(const aiVector3D& vPosition, unsigned int index,
|
||||
unsigned int smoothingGroup);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Prepare the spatial sorter for use
|
||||
|
@ -85,7 +79,7 @@ public:
|
|||
void Prepare();
|
||||
|
||||
/** Destructor */
|
||||
~D3DSSpatialSorter();
|
||||
~SGSpatialSort();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns an iterator for all positions close to the given position.
|
|
@ -110,10 +110,10 @@ void SMDImporter::SetupProperties(const Importer* pImp)
|
|||
{
|
||||
// The AI_CONFIG_IMPORT_SMD_KEYFRAME option overrides the
|
||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
|
||||
if(0xffffffff == (this->configFrameID = pImp->GetPropertyInteger(
|
||||
AI_CONFIG_IMPORT_SMD_KEYFRAME,0xffffffff)))
|
||||
{
|
||||
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
this->configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Open Asset Import Library (ASSIMP)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2008, ASSIMP Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Defines the helper data structures for importing 3DS files.
|
||||
http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
|
||||
|
||||
#ifndef AI_SMOOTHINGGROUPS_H_INC
|
||||
#define AI_SMOOTHINGGROUPS_H_INC
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure representing a face with smoothing groups assigned */
|
||||
struct FaceWithSmoothingGroup
|
||||
{
|
||||
FaceWithSmoothingGroup() : iSmoothGroup(0)
|
||||
{
|
||||
// let the rest uninitialized for performance - in release builds.
|
||||
// in debug builds set all indices to a common magic value
|
||||
#ifdef _DEBUG
|
||||
this->mIndices[0] = 0xffffffff;
|
||||
this->mIndices[1] = 0xffffffff;
|
||||
this->mIndices[2] = 0xffffffff;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//! Indices. .3ds is using uint16. However, after
|
||||
//! an unique vrtex set has been geneerated it might
|
||||
//! be an index becomes > 2^16
|
||||
uint32_t mIndices[3];
|
||||
|
||||
//! specifies to which smoothing group the face belongs to
|
||||
uint32_t iSmoothGroup;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure representing a mesh whose faces have smoothing
|
||||
groups assigned. This allows us to reuse the code for normal computations
|
||||
from smoothings groups for several loaders (3DS, ASE). All of them
|
||||
use face structures which inherit from #FaceWithSmoothingGroup,
|
||||
but as they add extra members and need to be copied by value we
|
||||
need to use a template here.
|
||||
*/
|
||||
template <class T>
|
||||
struct MeshWithSmoothingGroups
|
||||
{
|
||||
//! Vertex positions
|
||||
std::vector<aiVector3D> mPositions;
|
||||
|
||||
//! Face lists
|
||||
std::vector<T> mFaces;
|
||||
|
||||
//! List of normal vectors
|
||||
std::vector<aiVector3D> mNormals;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Computes normal vectors for the mesh
|
||||
*/
|
||||
template <class T>
|
||||
void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh);
|
||||
|
||||
|
||||
// include implementations
|
||||
#include "SmoothingGroups.inl"
|
||||
|
||||
#endif // !! AI_SMOOTHINGGROUPS_H_INC
|
|
@ -39,80 +39,81 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Implementation of the 3ds importer class */
|
||||
#include "3DSLoader.h"
|
||||
#include "MaterialSystem.h"
|
||||
/** @file Generation of normal vectors basing on smoothing groups */
|
||||
|
||||
#ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED
|
||||
#define AI_SMOOTHINGGROUPS_INL_INCLUDED
|
||||
|
||||
// internal headers
|
||||
#include "SGSpatialSort.h"
|
||||
|
||||
// CRT header
|
||||
#include <algorithm>
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "3DSSpatialSort.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Dot3DSImporter::GenNormals(Dot3DS::Mesh* sMesh)
|
||||
template <class T>
|
||||
void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh)
|
||||
{
|
||||
// First generate face normals
|
||||
sMesh->mNormals.resize(sMesh->mPositions.size(),aiVector3D());
|
||||
for( unsigned int a = 0; a < sMesh->mFaces.size(); a++)
|
||||
sMesh.mNormals.resize(sMesh.mPositions.size(),aiVector3D());
|
||||
for( unsigned int a = 0; a < sMesh.mFaces.size(); a++)
|
||||
{
|
||||
Dot3DS::Face& face = sMesh->mFaces[a];
|
||||
T& face = sMesh.mFaces[a];
|
||||
|
||||
// assume it is a triangle
|
||||
aiVector3D* pV1 = &sMesh->mPositions[face.mIndices[0]];
|
||||
aiVector3D* pV2 = &sMesh->mPositions[face.mIndices[1]];
|
||||
aiVector3D* pV3 = &sMesh->mPositions[face.mIndices[2]];
|
||||
aiVector3D* pV1 = &sMesh.mPositions[face.mIndices[0]];
|
||||
aiVector3D* pV2 = &sMesh.mPositions[face.mIndices[1]];
|
||||
aiVector3D* pV3 = &sMesh.mPositions[face.mIndices[2]];
|
||||
|
||||
// FIX invert all vertex normals
|
||||
aiVector3D pDelta1 = *pV3 - *pV1;
|
||||
aiVector3D pDelta2 = *pV2 - *pV1;
|
||||
aiVector3D pDelta1 = *pV2 - *pV1;
|
||||
aiVector3D pDelta2 = *pV3 - *pV1;
|
||||
aiVector3D vNor = pDelta1 ^ pDelta2;
|
||||
|
||||
sMesh->mNormals[face.mIndices[0]] = vNor;
|
||||
sMesh->mNormals[face.mIndices[1]] = vNor;
|
||||
sMesh->mNormals[face.mIndices[2]] = vNor;
|
||||
sMesh.mNormals[face.mIndices[0]] = vNor;
|
||||
sMesh.mNormals[face.mIndices[1]] = vNor;
|
||||
sMesh.mNormals[face.mIndices[2]] = vNor;
|
||||
}
|
||||
|
||||
// calculate the position bounds so we have a reliable epsilon to
|
||||
// check position differences against
|
||||
// @Schrompf: This is the 6th time this snippet is repeated!
|
||||
aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
|
||||
for( unsigned int a = 0; a < sMesh->mPositions.size(); a++)
|
||||
for( unsigned int a = 0; a < sMesh.mPositions.size(); a++)
|
||||
{
|
||||
minVec.x = std::min( minVec.x, sMesh->mPositions[a].x);
|
||||
minVec.y = std::min( minVec.y, sMesh->mPositions[a].y);
|
||||
minVec.z = std::min( minVec.z, sMesh->mPositions[a].z);
|
||||
maxVec.x = std::max( maxVec.x, sMesh->mPositions[a].x);
|
||||
maxVec.y = std::max( maxVec.y, sMesh->mPositions[a].y);
|
||||
maxVec.z = std::max( maxVec.z, sMesh->mPositions[a].z);
|
||||
minVec.x = std::min( minVec.x, sMesh.mPositions[a].x);
|
||||
minVec.y = std::min( minVec.y, sMesh.mPositions[a].y);
|
||||
minVec.z = std::min( minVec.z, sMesh.mPositions[a].z);
|
||||
maxVec.x = std::max( maxVec.x, sMesh.mPositions[a].x);
|
||||
maxVec.y = std::max( maxVec.y, sMesh.mPositions[a].y);
|
||||
maxVec.z = std::max( maxVec.z, sMesh.mPositions[a].z);
|
||||
}
|
||||
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
|
||||
std::vector<aiVector3D> avNormals;
|
||||
avNormals.resize(sMesh->mNormals.size());
|
||||
avNormals.resize(sMesh.mNormals.size());
|
||||
|
||||
// now generate the spatial sort tree
|
||||
D3DSSpatialSorter sSort;
|
||||
for( std::vector<Dot3DS::Face>::iterator
|
||||
i = sMesh->mFaces.begin();
|
||||
i != sMesh->mFaces.end();++i)
|
||||
SGSpatialSort sSort;
|
||||
for( std::vector<T>::iterator
|
||||
i = sMesh.mFaces.begin();
|
||||
i != sMesh.mFaces.end();++i)
|
||||
{
|
||||
sSort.AddFace(&(*i),sMesh->mPositions);
|
||||
sSort.Add(sMesh.mPositions[(*i).mIndices[0]],(*i).mIndices[0],(*i).iSmoothGroup);
|
||||
sSort.Add(sMesh.mPositions[(*i).mIndices[1]],(*i).mIndices[1],(*i).iSmoothGroup);
|
||||
sSort.Add(sMesh.mPositions[(*i).mIndices[2]],(*i).mIndices[2],(*i).iSmoothGroup);
|
||||
}
|
||||
sSort.Prepare();
|
||||
|
||||
for( std::vector<Dot3DS::Face>::iterator
|
||||
i = sMesh->mFaces.begin();
|
||||
i != sMesh->mFaces.end();++i)
|
||||
for( std::vector<T>::iterator
|
||||
i = sMesh.mFaces.begin();
|
||||
i != sMesh.mFaces.end();++i)
|
||||
{
|
||||
std::vector<unsigned int> poResult;
|
||||
|
||||
for (unsigned int c = 0; c < 3;++c)
|
||||
{
|
||||
|
||||
sSort.FindPositions(sMesh->mPositions[(*i).mIndices[c]],(*i).iSmoothGroup,
|
||||
sSort.FindPositions(sMesh.mPositions[(*i).mIndices[c]],(*i).iSmoothGroup,
|
||||
posEpsilon,poResult);
|
||||
|
||||
aiVector3D vNormals;
|
||||
|
@ -121,21 +122,16 @@ void Dot3DSImporter::GenNormals(Dot3DS::Mesh* sMesh)
|
|||
a = poResult.begin();
|
||||
a != poResult.end();++a)
|
||||
{
|
||||
vNormals += sMesh->mNormals[(*a)];
|
||||
vNormals += sMesh.mNormals[(*a)];
|
||||
fDiv += 1.0f;
|
||||
}
|
||||
vNormals.x /= fDiv;
|
||||
vNormals.y /= fDiv;
|
||||
vNormals.z /= fDiv;
|
||||
vNormals.Normalize();
|
||||
|
||||
// do the common coordinate system adjustment
|
||||
std::swap(vNormals.y,vNormals.z);
|
||||
|
||||
vNormals.x /= fDiv;vNormals.y /= fDiv;vNormals.z /= fDiv;
|
||||
//vNormals.Normalize();
|
||||
avNormals[(*i).mIndices[c]] = vNormals;
|
||||
poResult.clear();
|
||||
//poResult.clear();
|
||||
}
|
||||
}
|
||||
sMesh->mNormals = avNormals;
|
||||
return;
|
||||
sMesh.mNormals = avNormals;
|
||||
}
|
||||
|
||||
#endif // !! AI_SMOOTHINGGROUPS_INL_INCLUDED
|
|
@ -101,7 +101,7 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
|
|||
void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
|
||||
{
|
||||
// get the current value of the split property
|
||||
this->LIMIT = pImp->GetProperty(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
|
||||
this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Update a node after some meshes have been split
|
||||
|
@ -373,7 +373,7 @@ void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
|
|||
// Setup properties
|
||||
void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp)
|
||||
{
|
||||
this->LIMIT = pImp->GetProperty(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
|
||||
this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
Name="Debug|x64"
|
||||
>
|
||||
<DebugSettings
|
||||
Command=""
|
||||
|
@ -62,7 +62,7 @@
|
|||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<DebugSettings
|
||||
Command=""
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
// -------------------------------------------------------------------
|
||||
virtual size_t Tell(void) const = 0;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** 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.
|
||||
* \note The default value is AI_SLM_DEFAULT_MAX_VERTICES, defined in
|
||||
* the internal header file SplitLargeMeshes.h
|
||||
* Property type: integer.
|
||||
*/
|
||||
#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.
|
||||
* \note The default value is AI_SLM_DEFAULT_MAX_TRIANGLES, defined in
|
||||
* the internal header file SplitLargeMeshes.h
|
||||
* Property type: integer.
|
||||
*/
|
||||
#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.
|
||||
* \note The default value is AI_LBW_MAX_WEIGHTS, defined in
|
||||
* the internal header file LimitBoneWeightsProcess.h
|
||||
* Property type: integer.
|
||||
*/
|
||||
#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
|
||||
* options (where XXX is a placeholder for the file format for which you
|
||||
* want to override the global setting).
|
||||
* Property type: integer.
|
||||
*/
|
||||
#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
|
||||
*
|
||||
* 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"
|
||||
|
||||
|
@ -112,6 +117,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* LightWave represents the gradients with infinite detail,
|
||||
* but for use in realtime the loader computes replacement textures.
|
||||
* 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_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.
|
||||
*
|
||||
* This applies to the CalcTangentSpace-Step. The angle is specified
|
||||
* in degrees * 1000, so 180000 is PI. The default value is
|
||||
* 45 degrees. The maximum value is 180000.
|
||||
* in degrees , so 180 is PI. The default value is
|
||||
* 45 degrees. The maximum value is 180.
|
||||
* Property type: float.
|
||||
*/
|
||||
#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.
|
||||
*
|
||||
* This applies to the GenSmoothNormals-Step. The angle is specified
|
||||
* in degrees * 1000, so 180000 is PI. The default value is
|
||||
* 180 degrees (all vertex normals are smoothed). The maximum value is 180000
|
||||
* \note This can be manually overriden by loaders via #aiMesh::mMaxSmoothingAngle;
|
||||
* in degrees, so 180 is PI. The default value is
|
||||
* 180 degrees (all vertex normals are smoothed). The maximum value is 180
|
||||
* Property type: float.
|
||||
*/
|
||||
#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"
|
||||
#define AI_CONFIG_PP_OG_MAXIMALLY_SMALL "pp.og.maximally_small"
|
||||
// ---------------------------------------------------------------------------
|
||||
/** \brief Specifies the minimum number of faces a node should have.
|
||||
* 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
|
||||
|
|
|
@ -53,11 +53,13 @@ extern "C" {
|
|||
|
||||
|
||||
struct aiFileIO;
|
||||
struct aiFile;
|
||||
|
||||
typedef aiFileIO (*aiFileOpenProc)(C_STRUCT aiFileIO*, const char*, const char*);
|
||||
typedef aiReturn (*aiFileCloseProc)(C_STRUCT aiFileIO*);
|
||||
typedef unsigned long (*aiFileReadWriteProc)(C_STRUCT aiFileIO*, char*, unsigned int, unsigned int);
|
||||
typedef unsigned long (*aiFileTellProc)(C_STRUCT aiFileIO*);
|
||||
typedef aiFile* (*aiFileOpenProc)(C_STRUCT aiFileIO*, const char*, const char*);
|
||||
typedef void (*aiFileCloseProc)(C_STRUCT aiFileIO*, C_STRUCT aiFile*);
|
||||
typedef size_t (*aiFileWriteProc)(C_STRUCT aiFile*, const char*, size_t, size_t);
|
||||
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.
|
||||
|
@ -70,10 +72,26 @@ enum aiOrigin
|
|||
aiOrigin_END = 0x2 //!< End of file
|
||||
};
|
||||
|
||||
typedef aiReturn (*aiFileSeek)(aiFileIO*, unsigned long, aiOrigin);
|
||||
|
||||
typedef aiReturn (*aiFileSeek)(aiFile*, size_t, aiOrigin);
|
||||
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
|
||||
*
|
||||
|
@ -81,30 +99,27 @@ typedef char* aiUserData;
|
|||
* 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
|
||||
aiFileReadWriteProc ReadFunc;
|
||||
aiFileReadProc ReadProc;
|
||||
|
||||
//! Function used to write to a file
|
||||
aiFileReadWriteProc WriteFunc;
|
||||
aiFileWriteProc WriteProc;
|
||||
|
||||
//! Function used to retrieve the current
|
||||
//! position of the file cursor (ftell())
|
||||
aiFileTellProc TellProc;
|
||||
|
||||
//! Function used to retrieve the size of the file, in bytes
|
||||
aiFileTellProc FileSizeProc;
|
||||
|
||||
//! Function used to set the current position
|
||||
//! of the file cursor (fseek())
|
||||
aiFileSeek SeekProc;
|
||||
|
||||
//! User-defined data
|
||||
aiUserData UserData;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -356,16 +356,6 @@ struct aiMesh
|
|||
*/
|
||||
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
|
||||
|
||||
//! Default constructor. Initializes all members to 0
|
||||
|
@ -384,7 +374,6 @@ struct aiMesh
|
|||
mColors[a] = NULL;
|
||||
mNumBones = 0; mBones = NULL;
|
||||
mMaterialIndex = 0;
|
||||
mMaxSmoothingAngle = AI_MESH_SMOOTHING_ANGLE_NOT_SET;
|
||||
}
|
||||
|
||||
//! 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 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.
|
||||
* surfaces. However, the step tries to filter such cases.
|
||||
* 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
|
||||
} // end of extern "C"
|
||||
#endif
|
||||
|
|
|
@ -75,6 +75,9 @@ struct aiVector3D
|
|||
inline bool operator!= (const aiVector3D& other) const
|
||||
{return x != other.x || y != other.y || z != other.z;}
|
||||
|
||||
inline aiVector3D& operator= (float f)
|
||||
{x = y = z = f;return *this;}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
float x, y, z;
|
||||
|
|
|
@ -66,8 +66,8 @@ struct aiString;
|
|||
* @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.
|
||||
* @param pFlags Optional post processing steps to be executed after
|
||||
* a successful import. Provide a bitwise combination of the #aiPostProcessSteps
|
||||
* flags.
|
||||
* a successful import. Provide a bitwise combination of the
|
||||
* #aiPostProcessSteps flags.
|
||||
* @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
|
||||
* this file. If the import fails, NULL is returned instead. Call
|
||||
* aiGetErrorString() to retrieve a human-readable error text.
|
||||
* @param pFile aiFileIO structure. All functions pointers must be
|
||||
* initialized. aiFileIO::OpenFunc() and aiFileIO::CloseFunc()
|
||||
* will be used to open other files in the fs if the asset to be
|
||||
* loaded depends on them. NULL is not a valid value.
|
||||
* @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.
|
||||
* @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.
|
||||
* @param pFlags Optional post processing steps to be executed after
|
||||
* 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.
|
||||
*/
|
||||
// ---------------------------------------------------------------------------
|
||||
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,
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// STL headers
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
// public ASSIMP headers
|
||||
|
@ -67,6 +68,8 @@ namespace Assimp
|
|||
#define AI_PROPERTY_WAS_NOT_EXISTING 0xffffffff
|
||||
|
||||
struct aiScene;
|
||||
struct aiFileIO;
|
||||
const aiScene* aiImportFileEx( const char*, unsigned int, aiFileIO*);
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
@ -101,28 +104,14 @@ class ASSIMP_API Importer
|
|||
{
|
||||
// used internally
|
||||
friend class BaseProcess;
|
||||
friend const aiScene* ::aiImportFileEx( const char*, unsigned int, aiFileIO*);
|
||||
|
||||
protected:
|
||||
public:
|
||||
|
||||
template <typename Type>
|
||||
struct PropertyInfo
|
||||
{
|
||||
std::string name;
|
||||
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;
|
||||
typedef uint32_t KeyType;
|
||||
typedef std::map<KeyType, int> IntPropertyMap;
|
||||
typedef std::map<KeyType, float> FloatPropertyMap;
|
||||
typedef std::map<KeyType, std::string> StringPropertyMap;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -188,28 +177,66 @@ public:
|
|||
#endif
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Set a configuration property.
|
||||
/** Set an integer configuration property.
|
||||
* @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).
|
||||
* @param iValue New value of the property
|
||||
* @return Old value of the property or AI_PROPERTY_WAS_NOT_EXISTING
|
||||
* if the property has not yet been set.
|
||||
* @param bWasExisting Optional pointer to receive true if the
|
||||
* 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.
|
||||
* @param szName Name of the property. All supported properties
|
||||
* are defined in the aiConfig.g header (the constants start
|
||||
* with AI_CONFIG_XXX).
|
||||
* @param iErrorReturn Value that is returned if the property
|
||||
* is not found. Note that this value, not the default value
|
||||
* for the requested property is returned!
|
||||
* are defined in the aiConfig.g header (all constants share the
|
||||
* prefix AI_CONFIG_XXX).
|
||||
* @param iErrorReturn Value that is returned if the property
|
||||
* is not found.
|
||||
* @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.
|
||||
* 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
|
||||
*/
|
||||
bool IsExtensionSupported(const std::string& szExtension);
|
||||
|
@ -298,6 +326,18 @@ public:
|
|||
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()
|
||||
*
|
||||
|
@ -351,9 +391,17 @@ protected:
|
|||
std::string mErrorString;
|
||||
|
||||
/** 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;
|
||||
};
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ package assimp;
|
|||
|
||||
/**
|
||||
* Defines configuration properties.
|
||||
*
|
||||
* <p/>
|
||||
* Static helper class, can't be instanced. It defines configuration
|
||||
* 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>
|
||||
* configuration property.
|
||||
|
@ -79,15 +78,13 @@ public class ConfigProperty {
|
|||
public static final int DEFAULT_LBW_MAX_WEIGHTS = 4;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the maximum number of vertices in a mesh.
|
||||
* <p/>
|
||||
* This is used by the "SplitLargeMeshes" PostProcess-Step to determine
|
||||
* 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
|
||||
= "pp.slm.triangle_limit";
|
||||
|
@ -98,7 +95,8 @@ public class ConfigProperty {
|
|||
* <p/>
|
||||
* This is used by the "SplitLargeMeshes" PostProcess-Step to determine
|
||||
* 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
|
||||
= "pp.slm.vertex_limit";
|
||||
|
@ -108,7 +106,8 @@ public class ConfigProperty {
|
|||
* Set the maximum number of bones affecting a single vertex
|
||||
* <p/>
|
||||
* 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
|
||||
= "pp.lbw.weights_limit";
|
||||
|
@ -126,6 +125,7 @@ public class ConfigProperty {
|
|||
* <code>CONFIG_IMPORT_XXX_KEYFRAME</code> options (where XXX is a
|
||||
* placeholder for the file format for which you want to override the
|
||||
* global setting).
|
||||
* The type of the property is int.
|
||||
*/
|
||||
public static final String CONFIG_IMPORT_GLOBAL_KEYFRAME
|
||||
= "imp.global.kf";
|
||||
|
@ -144,11 +144,60 @@ public class ConfigProperty {
|
|||
* There are some faulty 3DS files on the internet which look
|
||||
* only correctly with pivot points disabled. By default,
|
||||
* 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
|
||||
= "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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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>.
|
||||
* <br>
|
||||
|
@ -158,12 +190,14 @@ public class Importer {
|
|||
/**
|
||||
* 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.
|
||||
* @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
|
||||
* is not thrown, you can assume that jAssimp is fully available.
|
||||
* 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.
|
||||
*/
|
||||
public Importer(int iVersion) throws NativeException {
|
||||
|
||||
// allocate a default I/O system
|
||||
ioSystem = new DefaultIOSystem();
|
||||
|
||||
if (!bLibInitialized) {
|
||||
|
||||
/** 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
|
||||
* @return null if the import failed, otherwise a valid Scene instance
|
||||
* @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 {
|
||||
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.LimitBoneWeights)) flags |= 0x200;
|
||||
else if (step.equals(PostProcessStep.ValidateDataStructure)) flags |= 0x400;
|
||||
else if (step.equals(PostProcessStep.FixInfacingNormals)) flags |= 0x800;
|
||||
else if (step.equals(PostProcessStep.ImproveVertexLocality)) flags |= 0x1600;
|
||||
else if (step.equals(PostProcessStep.ImproveVertexLocality)) flags |= 0x800;
|
||||
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
|
||||
|
@ -418,30 +451,39 @@ public class Importer {
|
|||
*
|
||||
* @param prop Name of 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) {
|
||||
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.properties.setProperty(prop, val);
|
||||
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) {
|
||||
|
||||
for (Property<Integer> i : this.properties) {
|
||||
if (i.key.equals(prop)) {
|
||||
return i.value;
|
||||
}
|
||||
}
|
||||
return error_return;
|
||||
Integer i = this.properties.getProperty(prop);
|
||||
return i != null ? i : 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
|
||||
*/
|
||||
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 =
|
||||
new PostProcessStep("LimitBoneWeights");
|
||||
|
||||
|
||||
/**
|
||||
* Validates the aiScene data structure before it is returned.
|
||||
* This makes sure that all indices are valid, all animations and
|
||||
|
@ -187,19 +186,6 @@ public class PostProcessStep {
|
|||
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.
|
||||
* 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
|
||||
|
@ -210,6 +196,46 @@ public class PostProcessStep {
|
|||
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 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/extensions/HelperMacros.h>
|
||||
|
||||
#include <aiTypes.h>
|
||||
#include <aiMesh.h>
|
||||
#include <aiScene.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_SplitLargeMeshes | // split large, unrenderable meshes into submeshes
|
||||
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
|
||||
double fEnd = (double)timeGetTime();
|
||||
|
|
|
@ -178,7 +178,7 @@
|
|||
</component>
|
||||
<component name="ProjectModuleManager">
|
||||
<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>
|
||||
</component>
|
||||
<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"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utImporter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utImproveCacheLocality.cpp"
|
||||
>
|
||||
|
@ -699,6 +703,10 @@
|
|||
RelativePath="..\..\test\unit\utMaterialSystem.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utOptimizeGraph.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utPretransformVertices.cpp"
|
||||
>
|
||||
|
@ -733,6 +741,14 @@
|
|||
RelativePath="..\..\test\unit\utGenNormals.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utImporter.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utJoinVertices.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utLimitBoneWeights.h"
|
||||
>
|
||||
|
@ -741,6 +757,10 @@
|
|||
RelativePath="..\..\test\unit\utMaterialSystem.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utOptimizeGraph.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utPretransformVertices.h"
|
||||
>
|
||||
|
|
|
@ -734,6 +734,10 @@
|
|||
RelativePath="..\..\code\FixNormalsStep.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\GenericProperty.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\GenFaceNormalsProcess.h"
|
||||
>
|
||||
|
@ -770,6 +774,10 @@
|
|||
RelativePath="..\..\code\MaterialSystem.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\OptimizeGraphProcess.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\ParsingUtils.h"
|
||||
>
|
||||
|
@ -790,6 +798,18 @@
|
|||
RelativePath="..\..\code\RemoveRedundantMaterials.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SGSpatialSort.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SmoothingGroups.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SmoothingGroups.inl"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SpatialSort.h"
|
||||
>
|
||||
|
@ -868,10 +888,6 @@
|
|||
RelativePath="..\..\code\3DSLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\3DSSpatialSort.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="ASE"
|
||||
|
@ -886,7 +902,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="HMPLoader"
|
||||
Name="HMP"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\HMPFileData.h"
|
||||
|
@ -1061,6 +1077,14 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="DXF"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\DXFLoader.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
@ -1138,6 +1162,10 @@
|
|||
RelativePath="..\..\code\MaterialSystem.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\OptimizeGraphProcess.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\PretransformVertices.cpp"
|
||||
>
|
||||
|
@ -1150,6 +1178,10 @@
|
|||
RelativePath="..\..\code\RemoveRedundantMaterials.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SGSpatialSort.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\SpatialSort.cpp"
|
||||
>
|
||||
|
@ -1196,18 +1228,10 @@
|
|||
RelativePath="..\..\code\3DSConverter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\3DSGenNormals.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\3DSLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\3DSSpatialSort.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="ASE"
|
||||
|
@ -1345,6 +1369,14 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="DXF"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\DXFLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
|
|
@ -238,22 +238,6 @@
|
|||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
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
|
||||
RelativePath="..\..\port\jAssimp\jni_bridge\JNIEnvironment.h"
|
||||
>
|
||||
|
@ -262,6 +246,26 @@
|
|||
RelativePath="..\..\port\jAssimp\jni_bridge\JNILogger.h"
|
||||
>
|
||||
</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
|
||||
Name="resources"
|
||||
|
|
Loading…
Reference in New Issue