Added MD5 (md5mesh works, md5anim has not yet been tested) and STL. new unittests, although not yet complete (material system, normals). Bugfixes (GFn and MDL7). Added HMP5 support. Rewrote MD2 and MD3 to be more stable.
git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@77 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
b17a5e3b69
commit
2f36cc5f5f
|
@ -94,7 +94,7 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
|
|||
|
||||
// NOTE: Sometimes the extension .ASK is also used
|
||||
// however, often it only contains static animation skeletons
|
||||
// without the real animations.
|
||||
// without real animations.
|
||||
if (extension[3] != 'e' && extension[3] != 'E' &&
|
||||
extension[3] != 'k' && extension[3] != 'K')return false;
|
||||
|
||||
|
@ -114,14 +114,9 @@ void ASEImporter::InternReadFile(
|
|||
}
|
||||
|
||||
size_t fileSize = file->FileSize();
|
||||
|
||||
std::string::size_type pos = pFile.find_last_of('.');
|
||||
std::string extension = pFile.substr( pos);
|
||||
if(extension[3] == 'k' || extension[3] == 'K')
|
||||
{
|
||||
this->mIsAsk = true;
|
||||
}
|
||||
else this->mIsAsk = false;
|
||||
this->mIsAsk = (extension[3] == 'k' || extension[3] == 'K');
|
||||
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
// (terminate it with zero)
|
||||
|
@ -132,6 +127,8 @@ void ASEImporter::InternReadFile(
|
|||
|
||||
// construct an ASE parser and parse the file
|
||||
this->mParser = new ASE::Parser((const char*)this->mBuffer);
|
||||
try
|
||||
{
|
||||
this->mParser->Parse();
|
||||
|
||||
// if absolutely no material has been loaded from the file
|
||||
|
@ -152,8 +149,8 @@ void ASEImporter::InternReadFile(
|
|||
// transformation matrix of a scenegraph node
|
||||
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 ...
|
||||
// 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);
|
||||
|
||||
// need to generate proper vertex normals if necessary
|
||||
|
@ -184,9 +181,15 @@ void ASEImporter::InternReadFile(
|
|||
// build output animations
|
||||
this->BuildAnimations();
|
||||
|
||||
// delete the ASE parser
|
||||
delete this->mParser;
|
||||
this->mParser = NULL;
|
||||
}
|
||||
catch (ImportErrorException* ex)
|
||||
{
|
||||
delete this->mParser; AI_DEBUG_INVALIDATE_PTR( this->mParser );
|
||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR( this->mBuffer );
|
||||
throw ex;
|
||||
}
|
||||
delete this->mParser; AI_DEBUG_INVALIDATE_PTR( this->mParser );
|
||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR( this->mBuffer );
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -333,11 +336,7 @@ void ASEImporter::AddNodes(aiNode* pcParent,const char* szName,
|
|||
|
||||
aiMatrix4x4 mParentAdjust = decompTrafo.mMatrix;
|
||||
mParentAdjust.Inverse();
|
||||
//if(ComputeLocalToWorldShift(mParentAdjust, decompTrafo, mesh.inherit))
|
||||
{
|
||||
node->mTransformation = mParentAdjust*mesh.mTransform;
|
||||
}
|
||||
//else node->mTransformation = mesh.mTransform;
|
||||
|
||||
// Transform all vertices of the mesh back into their local space ->
|
||||
// at the moment they are pretransformed
|
||||
|
@ -352,8 +351,6 @@ void ASEImporter::AddNodes(aiNode* pcParent,const char* szName,
|
|||
pvCurPtr++;
|
||||
}
|
||||
|
||||
//pcMesh->mColors[2] = NULL;
|
||||
|
||||
// add sub nodes
|
||||
aiMatrix4x4 mNewAbs = decompTrafo.mMatrix * node->mTransformation;
|
||||
ASE::DecompTransform dec( mNewAbs);
|
||||
|
@ -1242,8 +1239,7 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh)
|
|||
vNormals += mesh.mNormals[(*a)];
|
||||
fDiv += 1.0f;
|
||||
}
|
||||
vNormals.x /= fDiv;vNormals.y /= fDiv;vNormals.z /= fDiv;
|
||||
vNormals.Normalize();
|
||||
vNormals /= fDiv;
|
||||
avNormals[(*i).mIndices[c]] = vNormals;
|
||||
poResult.clear();
|
||||
}
|
||||
|
|
|
@ -55,9 +55,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
|
||||
// boost headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::ASE;
|
||||
|
||||
|
|
|
@ -43,11 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* tangents and bitangents for all imported meshes
|
||||
*/
|
||||
|
||||
// STL headers
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
#include "../include/DefaultLogger.h"
|
||||
|
||||
// internal headers
|
||||
#include "CalcTangentsProcess.h"
|
||||
#include "SpatialSort.h"
|
||||
|
||||
// public ASSIMP headers
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "../include/aiPostProcess.h"
|
||||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
|
@ -85,7 +90,7 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
|
|||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
if(ProcessMesh( pScene->mMeshes[a]))bHas = true;
|
||||
|
||||
if (bHas)DefaultLogger::get()->debug("CalcTangentsProcess finished. There was much work to do ...");
|
||||
if (bHas)DefaultLogger::get()->debug("CalcTangentsProcess finished. Tangents have been calculated");
|
||||
else DefaultLogger::get()->debug("CalcTangentsProcess finished");
|
||||
}
|
||||
|
||||
|
|
|
@ -50,25 +50,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
GenFaceNormalsProcess::GenFaceNormalsProcess()
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
GenFaceNormalsProcess::~GenFaceNormalsProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool GenFaceNormalsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_GenNormals) != 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void GenFaceNormalsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
|
@ -86,10 +88,10 @@ void GenFaceNormalsProcess::Execute( aiScene* pScene)
|
|||
"Face normals have been calculated");
|
||||
}
|
||||
else DefaultLogger::get()->debug("GenFaceNormalsProcess finished. "
|
||||
"There was nothing to do");
|
||||
"Normals are already there");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
|
||||
{
|
||||
|
@ -109,8 +111,8 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
|
|||
aiVector3D pDelta2 = *pV3 - *pV1;
|
||||
aiVector3D vNor = pDelta1 ^ pDelta2;
|
||||
|
||||
if (face.mIndices[1] > face.mIndices[2])
|
||||
vNor *= -1.0f;
|
||||
//if (face.mIndices[1] > face.mIndices[2])
|
||||
// vNor *= -1.0f;
|
||||
|
||||
for (unsigned int i = 0;i < face.mNumIndices;++i)
|
||||
{
|
||||
|
|
|
@ -51,25 +51,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
GenVertexNormalsProcess::GenVertexNormalsProcess()
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
GenVertexNormalsProcess::~GenVertexNormalsProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_GenSmoothNormals) != 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void GenVertexNormalsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
|
@ -88,10 +90,10 @@ void GenVertexNormalsProcess::Execute( aiScene* pScene)
|
|||
"Vertex normals have been calculated");
|
||||
}
|
||||
else DefaultLogger::get()->debug("GenVertexNormalsProcess finished. "
|
||||
"There was nothing to do");
|
||||
"Normals are already there");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
|
||||
{
|
||||
|
@ -110,8 +112,8 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
|
|||
aiVector3D pDelta2 = *pV3 - *pV1;
|
||||
aiVector3D vNor = pDelta1 ^ pDelta2;
|
||||
|
||||
if (face.mIndices[1] > face.mIndices[2])
|
||||
vNor *= -1.0f;
|
||||
/*if (face.mIndices[1] > face.mIndices[2])
|
||||
vNor *= -1.0f;*/
|
||||
|
||||
for (unsigned int i = 0;i < face.mNumIndices;++i)
|
||||
{
|
||||
|
@ -154,7 +156,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
|
|||
pcNor /= (float) verticesFound.size();
|
||||
pcNew[i] = pcNor;
|
||||
}
|
||||
delete pMesh->mNormals;
|
||||
delete[] pMesh->mNormals;
|
||||
pMesh->mNormals = pcNew;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -44,8 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "BaseProcess.h"
|
||||
#include "../include/aiMesh.h"
|
||||
namespace Assimp
|
||||
{
|
||||
class GenNormalsTest;
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** The GenFaceNormalsProcess computes vertex normals for all vertizes of all meshes
|
||||
|
@ -53,6 +53,7 @@ namespace Assimp
|
|||
class ASSIMP_API GenVertexNormalsProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
friend class ::GenNormalsTest;
|
||||
|
||||
protected:
|
||||
/** Constructor to be privately used by Importer */
|
||||
|
|
|
@ -41,9 +41,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/** @file Implementation of the MDL importer class */
|
||||
|
||||
// internal headers
|
||||
#include "MaterialSystem.h"
|
||||
#include "HMPLoader.h"
|
||||
#include "MD2FileData.h"
|
||||
|
||||
// public ASSIMP headers
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "../include/IOStream.h"
|
||||
#include "../include/IOSystem.h"
|
||||
|
@ -51,12 +54,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
|
||||
// boost headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
extern float g_avNormals[162][3];
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
HMPImporter::HMPImporter()
|
||||
|
@ -103,12 +105,12 @@ void HMPImporter::InternReadFile(
|
|||
throw new ImportErrorException( "Failed to open HMP file " + pFile + ".");
|
||||
}
|
||||
|
||||
// check whether the ply file is large enough to contain
|
||||
// check whether the HMP file is large enough to contain
|
||||
// at least the file header
|
||||
size_t fileSize = file->FileSize();
|
||||
if( fileSize < 50)
|
||||
{
|
||||
throw new ImportErrorException( ".hmp File is too small.");
|
||||
throw new ImportErrorException( "HMP File is too small.");
|
||||
}
|
||||
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
|
@ -147,9 +149,17 @@ void HMPImporter::InternReadFile(
|
|||
}
|
||||
else
|
||||
{
|
||||
// print the magic word to the logger
|
||||
char szBuffer[5];
|
||||
szBuffer[0] = ((char*)&iMagic)[0];
|
||||
szBuffer[1] = ((char*)&iMagic)[1];
|
||||
szBuffer[2] = ((char*)&iMagic)[2];
|
||||
szBuffer[3] = ((char*)&iMagic)[3];
|
||||
szBuffer[4] = '\0';
|
||||
|
||||
// we're definitely unable to load this file
|
||||
throw new ImportErrorException( "Unknown HMP subformat " + pFile +
|
||||
". Magic word is not known");
|
||||
". Magic word (" + szBuffer + ") is not known");
|
||||
}
|
||||
|
||||
} catch (ImportErrorException* ex) {
|
||||
|
@ -161,39 +171,42 @@ void HMPImporter::InternReadFile(
|
|||
delete[] this->mBuffer;
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void HMPImporter::ValidateHeader_HMP457( )
|
||||
{
|
||||
const HMP::Header_HMP5* const pcHeader = (const HMP::Header_HMP5*)this->mBuffer;
|
||||
|
||||
if (120 > this->iFileSize)
|
||||
{
|
||||
throw new ImportErrorException("HMP file is too small (header size is "
|
||||
"120 bytes, this file is smaller)");
|
||||
}
|
||||
|
||||
if (!pcHeader->ftrisize_x || !pcHeader->ftrisize_y)
|
||||
{
|
||||
throw new ImportErrorException("Size of triangles in either x or y direction is zero");
|
||||
}
|
||||
if(pcHeader->fnumverts_x < 1.0f || (pcHeader->numverts/pcHeader->fnumverts_x) < 1.0f)
|
||||
{
|
||||
throw new ImportErrorException("Number of triangles in either x or y direction is zero");
|
||||
}
|
||||
if(!pcHeader->numframes)
|
||||
{
|
||||
throw new ImportErrorException("There are no frames. At least one should be there");
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void HMPImporter::InternReadFile_HMP4( )
|
||||
{
|
||||
throw new ImportErrorException("HMP4 is currently not supported");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void HMPImporter::InternReadFile_HMP5( )
|
||||
{
|
||||
throw new ImportErrorException("HMP4 is currently not supported");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void HMPImporter::InternReadFile_HMP7( )
|
||||
{
|
||||
if (120 > this->iFileSize)
|
||||
{
|
||||
throw new ImportErrorException("HMP7 file is too small (header size is "
|
||||
"120 bytes, this file is smaller)");
|
||||
}
|
||||
|
||||
// read the file header and skip everything to byte 84
|
||||
const HMP::Header_HMP5* pcHeader = (const HMP::Header_HMP5*)this->mBuffer;
|
||||
const unsigned char* szCurrent = (const unsigned char*)(this->mBuffer+84);
|
||||
|
||||
if (!pcHeader->ftrisize_x || !pcHeader->ftrisize_y ||
|
||||
pcHeader->fnumverts_x < 1.0f || (pcHeader->numverts/pcHeader->fnumverts_x) < 1.0f ||
|
||||
!pcHeader->numframes)
|
||||
{
|
||||
throw new ImportErrorException("One or more of the values in the HMP7 "
|
||||
"file header are invalid.");
|
||||
}
|
||||
this->ValidateHeader_HMP457();
|
||||
|
||||
// generate an output mesh
|
||||
this->pScene->mNumMeshes = 1;
|
||||
|
@ -207,6 +220,120 @@ void HMPImporter::InternReadFile_HMP7( )
|
|||
const unsigned int height = (unsigned int)(pcHeader->numverts / pcHeader->fnumverts_x);
|
||||
const unsigned int width = (unsigned int)pcHeader->fnumverts_x;
|
||||
|
||||
// generate/load a material for the terrain
|
||||
this->CreateMaterial(szCurrent,&szCurrent);
|
||||
|
||||
// goto offset 120, I don't know why ...
|
||||
// (fixme) is this the frame header? I assume yes since it starts with 2.
|
||||
szCurrent += 36;
|
||||
|
||||
this->SizeCheck(szCurrent + sizeof(const HMP::Vertex_HMP7)*height*width);
|
||||
|
||||
// now load all vertices from the file
|
||||
aiVector3D* pcVertOut = pcMesh->mVertices;
|
||||
aiVector3D* pcNorOut = pcMesh->mNormals;
|
||||
const HMP::Vertex_HMP5* src = (const HMP::Vertex_HMP5*) szCurrent;
|
||||
for (unsigned int y = 0; y < height;++y)
|
||||
{
|
||||
for (unsigned int x = 0; x < width;++x)
|
||||
{
|
||||
pcVertOut->x = x * pcHeader->ftrisize_x;
|
||||
pcVertOut->y = y * pcHeader->ftrisize_y;
|
||||
pcVertOut->z = (((float)src->z / 0xffff)-0.5f) * pcHeader->ftrisize_x * 8.0f;
|
||||
MD2::LookupNormalIndex(src->normals162index, *pcNorOut );
|
||||
++pcVertOut;++pcNorOut;++src;
|
||||
}
|
||||
}
|
||||
|
||||
// generate texture coordinates if necessary
|
||||
if (pcHeader->numskins)this->GenerateTextureCoords(width,height);
|
||||
|
||||
// now build a list of faces
|
||||
this->CreateOutputFaceList(width,height);
|
||||
|
||||
// there is no nodegraph in HMP files. Simply assign the one mesh
|
||||
// (no, not the one ring) to the root node
|
||||
this->pScene->mRootNode = new aiNode();
|
||||
this->pScene->mRootNode->mName.Set("terrain_root");
|
||||
this->pScene->mRootNode->mNumMeshes = 1;
|
||||
this->pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||
this->pScene->mRootNode->mMeshes[0] = 0;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void HMPImporter::InternReadFile_HMP7( )
|
||||
{
|
||||
// read the file header and skip everything to byte 84
|
||||
const HMP::Header_HMP5* const pcHeader = (const HMP::Header_HMP5*)this->mBuffer;
|
||||
const unsigned char* szCurrent = (const unsigned char*)(this->mBuffer+84);
|
||||
this->ValidateHeader_HMP457();
|
||||
|
||||
// generate an output mesh
|
||||
this->pScene->mNumMeshes = 1;
|
||||
this->pScene->mMeshes = new aiMesh*[1];
|
||||
aiMesh* pcMesh = this->pScene->mMeshes[0] = new aiMesh();
|
||||
|
||||
pcMesh->mMaterialIndex = 0;
|
||||
pcMesh->mVertices = new aiVector3D[pcHeader->numverts];
|
||||
pcMesh->mNormals = new aiVector3D[pcHeader->numverts];
|
||||
|
||||
const unsigned int height = (unsigned int)(pcHeader->numverts / pcHeader->fnumverts_x);
|
||||
const unsigned int width = (unsigned int)pcHeader->fnumverts_x;
|
||||
|
||||
// generate/load a material for the terrain
|
||||
this->CreateMaterial(szCurrent,&szCurrent);
|
||||
|
||||
// goto offset 120, I don't know why ...
|
||||
// (fixme) is this the frame header? I assume yes since it starts with 2.
|
||||
szCurrent += 36;
|
||||
|
||||
this->SizeCheck(szCurrent + sizeof(const HMP::Vertex_HMP7)*height*width);
|
||||
|
||||
// now load all vertices from the file
|
||||
aiVector3D* pcVertOut = pcMesh->mVertices;
|
||||
aiVector3D* pcNorOut = pcMesh->mNormals;
|
||||
const HMP::Vertex_HMP7* src = (const HMP::Vertex_HMP7*) szCurrent;
|
||||
for (unsigned int y = 0; y < height;++y)
|
||||
{
|
||||
for (unsigned int x = 0; x < width;++x)
|
||||
{
|
||||
pcVertOut->x = x * pcHeader->ftrisize_x;
|
||||
pcVertOut->y = y * pcHeader->ftrisize_y;
|
||||
|
||||
// FIXME: What exctly is the correct scaling factor to use?
|
||||
// possibly pcHeader->scale_origin[2] in combination with a
|
||||
// signed interpretation of src->z?
|
||||
pcVertOut->z = (((float)src->z / 0xffff)-0.5f) * pcHeader->ftrisize_x * 8.0f;
|
||||
|
||||
pcNorOut->x = ((float)src->normal_x / 0x80 ); // * pcHeader->scale_origin[0];
|
||||
pcNorOut->y = ((float)src->normal_y / 0x80 ); // * pcHeader->scale_origin[1];
|
||||
pcNorOut->z = 1.0f;
|
||||
pcNorOut->Normalize();
|
||||
|
||||
++pcVertOut;++pcNorOut;++src;
|
||||
}
|
||||
}
|
||||
|
||||
// generate texture coordinates if necessary
|
||||
if (pcHeader->numskins)this->GenerateTextureCoords(width,height);
|
||||
|
||||
// now build a list of faces
|
||||
this->CreateOutputFaceList(width,height);
|
||||
|
||||
// there is no nodegraph in HMP files. Simply assign the one mesh
|
||||
// (no, not the One Ring) to the root node
|
||||
this->pScene->mRootNode = new aiNode();
|
||||
this->pScene->mRootNode->mName.Set("terrain_root");
|
||||
this->pScene->mRootNode->mNumMeshes = 1;
|
||||
this->pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||
this->pScene->mRootNode->mMeshes[0] = 0;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void HMPImporter::CreateMaterial(const unsigned char* szCurrent,
|
||||
const unsigned char** szCurrentOut)
|
||||
{
|
||||
aiMesh* const pcMesh = this->pScene->mMeshes[0];
|
||||
const HMP::Header_HMP5* const pcHeader = (const HMP::Header_HMP5*)this->mBuffer;
|
||||
|
||||
// we don't need to generate texture coordinates if
|
||||
// we have no textures in the file ...
|
||||
if (pcHeader->numskins)
|
||||
|
@ -225,7 +352,7 @@ void HMPImporter::InternReadFile_HMP7( )
|
|||
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
|
||||
|
||||
aiColor3D clr;
|
||||
clr.b = clr.g = clr.r = 0.7f;
|
||||
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);
|
||||
|
||||
|
@ -241,45 +368,14 @@ void HMPImporter::InternReadFile_HMP7( )
|
|||
this->pScene->mMaterials = new aiMaterial*[1];
|
||||
this->pScene->mMaterials[0] = pcHelper;
|
||||
}
|
||||
*szCurrentOut = szCurrent;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void HMPImporter::CreateOutputFaceList(unsigned int width,unsigned int height)
|
||||
{
|
||||
aiMesh* const pcMesh = this->pScene->mMeshes[0];
|
||||
|
||||
// goto offset 120, I don't know why ...
|
||||
// (fixme) is this the frame header? I assume yes since it starts
|
||||
// with 2.
|
||||
szCurrent += 36;
|
||||
|
||||
this->SizeCheck(szCurrent + sizeof(const HMP::Vertex_HMP7)*height*width);
|
||||
|
||||
// now load all vertices from the file
|
||||
aiVector3D* pcVertOut = pcMesh->mVertices;
|
||||
aiVector3D* pcNorOut = pcMesh->mNormals;
|
||||
const HMP::Vertex_HMP7* src = (const HMP::Vertex_HMP7*) szCurrent;
|
||||
for (unsigned int y = 0; y < height;++y)
|
||||
{
|
||||
for (unsigned int x = 0; x < width;++x)
|
||||
{
|
||||
pcVertOut->x = x * pcHeader->ftrisize_x;
|
||||
pcVertOut->y = y * pcHeader->ftrisize_y;
|
||||
// FIXME: What exctly is the correct scaling factor to use?
|
||||
// possibly pcHeader->scale_origin[2] in combination with a
|
||||
// signed interpretation of src->z?
|
||||
pcVertOut->z = (((float)src->z / 0xffff)-0.5f) * pcHeader->ftrisize_x * 8.0f;
|
||||
|
||||
pcNorOut->x = ((float)src->normal_x / 0x80 ); // * pcHeader->scale_origin[0];
|
||||
pcNorOut->y = ((float)src->normal_y / 0x80 ); // * pcHeader->scale_origin[1];
|
||||
pcNorOut->z = 1.0f;
|
||||
pcNorOut->Normalize();
|
||||
|
||||
++pcVertOut;++pcNorOut;++src;
|
||||
}
|
||||
}
|
||||
|
||||
// generate texture coordinates if necessary
|
||||
if (pcHeader->numskins)
|
||||
{
|
||||
this->GenerateTextureCoords(width,height);
|
||||
}
|
||||
|
||||
// now build a list of faces
|
||||
// allocate enough storage
|
||||
const unsigned int iNumSquares = (width-1) * (height-1);
|
||||
pcMesh->mNumFaces = iNumSquares << 1;
|
||||
pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
|
||||
|
@ -289,12 +385,13 @@ void HMPImporter::InternReadFile_HMP7( )
|
|||
aiVector3D* pcNormals = new aiVector3D[pcMesh->mNumVertices];
|
||||
|
||||
aiFace* pcFaceOut(pcMesh->mFaces);
|
||||
pcVertOut = pcVertices;
|
||||
pcNorOut = pcNormals;
|
||||
aiVector3D* pcVertOut = pcVertices;
|
||||
aiVector3D* pcNorOut = pcNormals;
|
||||
|
||||
aiVector3D* pcUVs = pcMesh->mTextureCoords[0] ? new aiVector3D[pcMesh->mNumVertices] : NULL;
|
||||
aiVector3D* pcUVOut(pcUVs);
|
||||
|
||||
// build the terrain square
|
||||
unsigned int iCurrent = 0;
|
||||
for (unsigned int y = 0; y < height-1;++y)
|
||||
{
|
||||
|
@ -360,16 +457,6 @@ void HMPImporter::InternReadFile_HMP7( )
|
|||
delete[] pcMesh->mTextureCoords[0];
|
||||
pcMesh->mTextureCoords[0] = pcUVs;
|
||||
}
|
||||
|
||||
// there is no nodegraph in HMP files. Simply assign the one mesh
|
||||
// (no, not the one ring) to the root node
|
||||
this->pScene->mRootNode = new aiNode();
|
||||
this->pScene->mRootNode->mName.Set("terrain_root");
|
||||
this->pScene->mRootNode->mNumMeshes = 1;
|
||||
this->pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||
this->pScene->mRootNode->mMeshes[0] = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char* szCursor,
|
||||
|
@ -433,15 +520,16 @@ void HMPImporter::GenerateTextureCoords(
|
|||
|
||||
aiVector3D* uv = this->pScene->mMeshes[0]->mTextureCoords[0];
|
||||
|
||||
const float fX = (1.0f / height) + (1.0f / height) / (height-1);
|
||||
const float fY = (1.0f / width) + (1.0f / width) / (width-1);
|
||||
const float fY = (1.0f / height) + (1.0f / height) / (height-1);
|
||||
const float fX = (1.0f / width) + (1.0f / width) / (width-1);
|
||||
|
||||
for (unsigned int y = 0; y < height;++y)
|
||||
{
|
||||
for (unsigned int x = 0; x < width;++x)
|
||||
{
|
||||
uv->x = fX*x;
|
||||
uv->y = 1.0f-fY*y;
|
||||
uv->x = fX*x;
|
||||
uv->z = 0.0f;
|
||||
++uv;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,16 @@ class MaterialHelper;
|
|||
namespace HMP
|
||||
{
|
||||
|
||||
// ugly compiler dependent packing stuff
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
|
||||
# pragma pack(push,1)
|
||||
# define PACK_STRUCT
|
||||
#elif defined( __GNUC__ )
|
||||
# define PACK_STRUCT __attribute__((packed))
|
||||
#else
|
||||
# error Compiler not supported. Never do this again.
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Data structure for the header of a HMP5 file.
|
||||
* This is also used by HMP4 and HMP7, but with modifications
|
||||
|
@ -111,8 +121,27 @@ struct Header_HMP5
|
|||
int32_t num_stverts;
|
||||
int32_t flags;
|
||||
float size;
|
||||
};
|
||||
} PACK_STRUCT;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Data structure for a terrain vertex in a HMP4 file
|
||||
*/
|
||||
struct Vertex_HMP4
|
||||
{
|
||||
uint16_t p_pos[3];
|
||||
uint8_t normals162index;
|
||||
uint8_t pad;
|
||||
} PACK_STRUCT;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Data structure for a terrain vertex in a HMP5 file
|
||||
*/
|
||||
struct Vertex_HMP5
|
||||
{
|
||||
uint16_t z;
|
||||
uint8_t normals162index;
|
||||
uint8_t pad;
|
||||
} PACK_STRUCT;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Data structure for a terrain vertex in a HMP7 file
|
||||
|
@ -121,7 +150,13 @@ struct Vertex_HMP7
|
|||
{
|
||||
uint16_t z;
|
||||
int8_t normal_x,normal_y;
|
||||
};
|
||||
} PACK_STRUCT;
|
||||
|
||||
// reset packing to the original value
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
|
||||
# pragma pack( pop )
|
||||
#endif
|
||||
#undef PACK_STRUCT
|
||||
|
||||
}; //! namespace HMP
|
||||
|
||||
|
@ -182,6 +217,25 @@ protected:
|
|||
*/
|
||||
void InternReadFile_HMP7( );
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Validate a HMP 5,4,7 file header
|
||||
*/
|
||||
void ValidateHeader_HMP457( );
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Try to load one material from the file, if this fails create
|
||||
* a default material
|
||||
*/
|
||||
void CreateMaterial(const unsigned char* szCurrent,
|
||||
const unsigned char** szCurrentOut);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Build a list of output faces and vertices. The function
|
||||
* triangulates the height map read from the file
|
||||
* \param width Width of the height field
|
||||
* \param width Height of the height field
|
||||
*/
|
||||
void CreateOutputFaceList(unsigned int width,unsigned int height);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Generate planar texture coordinates for a terrain
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
#ifndef AI_HASH_H_INCLUDED
|
||||
#define AI_HASH_H_INCLUDED
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// hashing function taken from
|
||||
// http://www.azillionmonkeys.com/qed/hash.html
|
||||
// (incremental version of the hashing function)
|
||||
// (stdint.h should have been been included here)
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline uint32_t SuperFastHash (const char * data, int len, uint32_t hash = 0) {
|
||||
uint32_t tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL) return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += get16bits (data);
|
||||
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2*sizeof (uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += get16bits (data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof (uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += get16bits (data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
#endif // !! AI_HASH_H_INCLUDED
|
|
@ -92,6 +92,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#if (!defined AI_BUILD_NO_SMD_IMPORTER)
|
||||
# include "SMDLoader.h"
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_MD5_IMPORTER)
|
||||
# include "MD5Loader.h"
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_STL_IMPORTER)
|
||||
# include "STLLoader.h"
|
||||
#endif
|
||||
|
||||
// PostProcess-Steps
|
||||
#if (!defined AI_BUILD_NO_CALCTANGENTS_PROCESS)
|
||||
|
@ -177,12 +183,18 @@ Importer::Importer() :
|
|||
#if (!defined AI_BUILD_NO_ASE_IMPORTER)
|
||||
mImporter.push_back( new ASEImporter());
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_HMP_IMPORTER)
|
||||
#if (!defined AI_BUILD_NO_HMP_IMPORTER)
|
||||
mImporter.push_back( new HMPImporter());
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_SMD_IMPORTER)
|
||||
#if (!defined AI_BUILD_NO_SMD_IMPORTER)
|
||||
mImporter.push_back( new SMDImporter());
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_MD5_IMPORTER)
|
||||
mImporter.push_back( new MD5Importer());
|
||||
#endif
|
||||
#if (!defined AI_BUILD_NO_STL_IMPORTER)
|
||||
mImporter.push_back( new STLImporter());
|
||||
#endif
|
||||
|
||||
// add an instance of each post processing step here in the order
|
||||
// of sequence it is executed
|
||||
|
|
|
@ -39,8 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Implementation of the post processing step to join identical vertices
|
||||
* for all imported meshes
|
||||
/** @file Implementation of the post processing to improve the
|
||||
* cache locality of a mesh.
|
||||
* <br>
|
||||
* The algorithm is roughly basing on this paper:
|
||||
* http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf
|
||||
|
@ -167,6 +167,17 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN
|
|||
}
|
||||
delete[] piFIFOStack;
|
||||
float fACMR = (float)iCacheMisses / pMesh->mNumFaces;
|
||||
if (3.0 == fACMR)
|
||||
{
|
||||
char szBuff[128]; // should be sufficiently large in every case
|
||||
|
||||
// the JoinIdenticalVertices process has not been executed on this
|
||||
// mesh, otherwise this value would normally be at least minimally#
|
||||
// smaller than 3.0 ...
|
||||
::sprintf(szBuff,"Mesh %i: JIV-Step has not been executed properly (precondition)",meshNum);
|
||||
DefaultLogger::get()->warn(szBuff);
|
||||
return;
|
||||
}
|
||||
|
||||
// first we need to build a vertex-triangle adjacency list
|
||||
VertexTriangleAdjacency adj(pMesh->mFaces,pMesh->mNumFaces, pMesh->mNumVertices,true);
|
||||
|
@ -351,7 +362,7 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN
|
|||
char szBuff[128]; // should be sufficiently large in every case
|
||||
float fACMR2 = (float)iCacheMisses / pMesh->mNumFaces;
|
||||
|
||||
sprintf(szBuff,"Mesh %i | ACMR in: %f out: %f | ~%.1f%%",meshNum,fACMR,fACMR2,
|
||||
::sprintf(szBuff,"Mesh %i | ACMR in: %f out: %f | ~%.1f%%",meshNum,fACMR,fACMR2,
|
||||
((fACMR - fACMR2) / fACMR) * 100.f);
|
||||
DefaultLogger::get()->info(szBuff);
|
||||
}
|
||||
|
|
|
@ -129,7 +129,6 @@ void MD2Importer::ValidateHeader( )
|
|||
this->m_pcHeader->offsetEnd > this->fileSize)
|
||||
{
|
||||
throw new ImportErrorException("Invalid MD2 header: some offsets are outside the file");
|
||||
delete[] this->mBuffer;
|
||||
}
|
||||
|
||||
if (this->m_pcHeader->numSkins > AI_MD2_MAX_SKINS)
|
||||
|
@ -160,6 +159,8 @@ void MD2Importer::InternReadFile(
|
|||
throw new ImportErrorException( "md2 File is too small.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 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);
|
||||
|
@ -170,7 +171,6 @@ void MD2Importer::InternReadFile(
|
|||
if (this->m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_BE &&
|
||||
this->m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_LE)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException( "Invalid md2 file: Magic bytes not found");
|
||||
}
|
||||
|
||||
|
@ -184,12 +184,10 @@ void MD2Importer::InternReadFile(
|
|||
// check some values whether they are valid
|
||||
if (0 == this->m_pcHeader->numFrames)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException( "Invalid md2 file: NUM_FRAMES is 0");
|
||||
}
|
||||
if (this->m_pcHeader->offsetEnd > (int32_t)fileSize)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException( "Invalid md2 file: File is too small");
|
||||
}
|
||||
|
||||
|
@ -287,6 +285,8 @@ void MD2Importer::InternReadFile(
|
|||
|
||||
// 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
|
||||
|
@ -295,7 +295,6 @@ void MD2Importer::InternReadFile(
|
|||
|
||||
// check whether the skin width or height are zero (this would
|
||||
// cause a division through zero)
|
||||
float fDivisorU;
|
||||
if (!this->m_pcHeader->skinWidth)
|
||||
{
|
||||
DefaultLogger::get()->error("Skin width is zero but there are "
|
||||
|
@ -304,8 +303,6 @@ void MD2Importer::InternReadFile(
|
|||
fDivisorU = 1.0f;
|
||||
}
|
||||
else fDivisorU = (float)this->m_pcHeader->skinWidth;
|
||||
|
||||
float fDivisorV;
|
||||
if (!this->m_pcHeader->skinHeight)
|
||||
{
|
||||
DefaultLogger::get()->error("Skin height is zero but there are "
|
||||
|
@ -314,6 +311,7 @@ void MD2Importer::InternReadFile(
|
|||
fDivisorV = 1.0f;
|
||||
}
|
||||
else fDivisorV = (float)this->m_pcHeader->skinHeight;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < (unsigned int)this->m_pcHeader->numTriangles;++i)
|
||||
{
|
||||
|
@ -357,6 +355,8 @@ void MD2Importer::InternReadFile(
|
|||
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)
|
||||
{
|
||||
|
@ -374,51 +374,6 @@ void MD2Importer::InternReadFile(
|
|||
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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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];
|
||||
vec.z = (float)pcVerts[iIndex].vertex[1] * pcFrame->scale[1];
|
||||
vec.z += pcFrame->translate[1];
|
||||
vec.y = (float)pcVerts[iIndex].vertex[2] * pcFrame->scale[2];
|
||||
vec.y += pcFrame->translate[2];
|
||||
vec.y *= -1.f;
|
||||
|
||||
// read the normal vector from the precalculated normal table
|
||||
aiVector3D& vNormal = pcMesh->mNormals[iCurrent];
|
||||
LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal);
|
||||
vNormal.y *= -1.0f;
|
||||
}
|
||||
// FIX: flip the face order for use with OpenGL
|
||||
pScene->mMeshes[0]->mFaces[i].mIndices[0] = iTemp+2;
|
||||
|
@ -426,7 +381,10 @@ void MD2Importer::InternReadFile(
|
|||
pScene->mMeshes[0]->mFaces[i].mIndices[2] = iTemp+0;
|
||||
}
|
||||
}
|
||||
// delete the file buffer and return
|
||||
delete[] this->mBuffer;
|
||||
return;
|
||||
catch (ImportErrorException* ex)
|
||||
{
|
||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw ex;
|
||||
}
|
||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
}
|
|
@ -90,11 +90,20 @@ bool MD3Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void MD3Importer::ValidateHeaderOffsets()
|
||||
{
|
||||
// check file format version
|
||||
if (this->m_pcHeader->VERSION > 15)
|
||||
DefaultLogger::get()->warn( "Unsupported md3 file version. Continuing happily ...");
|
||||
|
||||
// check some values whether they are valid
|
||||
if (0 == this->m_pcHeader->NUM_FRAMES)
|
||||
throw new ImportErrorException( "Invalid md3 file: NUM_FRAMES is 0");
|
||||
if (0 == this->m_pcHeader->NUM_SURFACES)
|
||||
throw new ImportErrorException( "Invalid md3 file: NUM_SURFACES is 0");
|
||||
|
||||
if (this->m_pcHeader->OFS_FRAMES >= this->fileSize ||
|
||||
this->m_pcHeader->OFS_SURFACES >= this->fileSize ||
|
||||
this->m_pcHeader->OFS_EOF > this->fileSize)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException("Invalid MD3 header: some offsets are outside the file");
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +118,6 @@ void MD3Importer::ValidateSurfaceHeaderOffsets(const MD3::Surface* pcSurf)
|
|||
pcSurf->OFS_ST + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::TexCoord) > this->fileSize ||
|
||||
pcSurf->OFS_XYZNORMAL + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::Vertex) > this->fileSize)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException("Invalid MD3 surface header: some offsets are outside the file");
|
||||
}
|
||||
|
||||
|
@ -147,33 +155,18 @@ void MD3Importer::InternReadFile(
|
|||
this->mBuffer = new unsigned char[fileSize];
|
||||
file->Read( (void*)mBuffer, 1, fileSize);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
this->m_pcHeader = (const MD3::Header*)this->mBuffer;
|
||||
|
||||
// check magic number
|
||||
if (this->m_pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_BE &&
|
||||
this->m_pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_LE)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException( "Invalid md3 file: Magic bytes not found");
|
||||
}
|
||||
|
||||
// check file format version
|
||||
if (this->m_pcHeader->VERSION > 15)
|
||||
{
|
||||
DefaultLogger::get()->warn( "Unsupported md3 file version. Continuing happily ...");
|
||||
}
|
||||
|
||||
// check some values whether they are valid
|
||||
if (0 == this->m_pcHeader->NUM_FRAMES)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException( "Invalid md3 file: NUM_FRAMES is 0");
|
||||
}
|
||||
if (0 == this->m_pcHeader->NUM_SURFACES)
|
||||
{
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException( "Invalid md3 file: NUM_SURFACES is 0");
|
||||
}
|
||||
// validate the header
|
||||
this->ValidateHeaderOffsets();
|
||||
|
||||
// now navigate to the list of surfaces
|
||||
|
@ -229,14 +222,11 @@ void MD3Importer::InternReadFile(
|
|||
aiMesh* pcMesh = pScene->mMeshes[iNum];
|
||||
|
||||
pcMesh->mNumVertices = pcSurfaces->NUM_TRIANGLES*3;
|
||||
//pcMesh->mNumBones = 0;
|
||||
//pcMesh->mColors[0] = pcMesh->mColors[1] = pcMesh->mColors[2] = pcMesh->mColors[3] = NULL;
|
||||
pcMesh->mNumFaces = pcSurfaces->NUM_TRIANGLES;
|
||||
pcMesh->mFaces = new aiFace[pcSurfaces->NUM_TRIANGLES];
|
||||
pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
|
||||
pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
|
||||
pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
|
||||
//pcMesh->mTextureCoords[1] = pcMesh->mTextureCoords[2] = pcMesh->mTextureCoords[3] = NULL;
|
||||
pcMesh->mNumUVComponents[0] = 2;
|
||||
|
||||
// fill in all triangles
|
||||
|
@ -292,8 +282,8 @@ void MD3Importer::InternReadFile(
|
|||
bool bSuccess = true;
|
||||
for (unsigned int a = 0; a < iLen2;++a)
|
||||
{
|
||||
char sz = tolower ( pcShaders->NAME[a] );
|
||||
char sz2 = tolower ( this->m_pcHeader->NAME[a] );
|
||||
char sz = ::tolower ( pcShaders->NAME[a] );
|
||||
char sz2 = ::tolower ( this->m_pcHeader->NAME[a] );
|
||||
if (sz != sz2)
|
||||
{
|
||||
bSuccess = false;
|
||||
|
@ -402,11 +392,7 @@ void MD3Importer::InternReadFile(
|
|||
}
|
||||
|
||||
if (0 == pScene->mNumMeshes)
|
||||
{
|
||||
// cleanup before returning
|
||||
delete[] this->mBuffer;
|
||||
throw new ImportErrorException( "Invalid md3 file: File contains no valid mesh");
|
||||
}
|
||||
pScene->mNumMaterials = iNumMaterials;
|
||||
|
||||
// now we need to generate an empty node graph
|
||||
|
@ -417,7 +403,11 @@ void MD3Importer::InternReadFile(
|
|||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
pScene->mRootNode->mMeshes[i] = i;
|
||||
|
||||
// delete the file buffer and return
|
||||
delete[] this->mBuffer;
|
||||
return;
|
||||
}
|
||||
catch (ImportErrorException* ex)
|
||||
{
|
||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw ex;
|
||||
}
|
||||
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
}
|
|
@ -0,0 +1,561 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 MD5 importer class */
|
||||
|
||||
// internal headers
|
||||
#include "MaterialSystem.h"
|
||||
#include "RemoveComments.h"
|
||||
#include "MD5Loader.h"
|
||||
#include "StringComparison.h"
|
||||
#include "fast_atof.h"
|
||||
|
||||
// public 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"
|
||||
|
||||
// boost headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
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()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
MD5Importer::~MD5Importer()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool MD5Importer::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);
|
||||
|
||||
if (extension.length() < 4)return false;
|
||||
if (extension[0] != '.')return false;
|
||||
|
||||
if (extension[1] != 'm' && extension[1] != 'M')return false;
|
||||
if (extension[2] != 'd' && extension[2] != 'D')return false;
|
||||
if (extension[3] != '5')return false;
|
||||
return true;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void MD5Importer::InternReadFile(
|
||||
const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
// remove the file extension
|
||||
std::string::size_type pos = pFile.find_last_of('.');
|
||||
this->mFile = pFile.substr(0,pos+1);
|
||||
this->pIOHandler = pIOHandler;
|
||||
this->pScene = pScene;
|
||||
|
||||
bHadMD5Mesh = bHadMD5Anim = false;
|
||||
|
||||
// load the animation keyframes
|
||||
this->LoadMD5AnimFile();
|
||||
|
||||
// load the mesh vertices and bones
|
||||
this->LoadMD5MeshFile();
|
||||
|
||||
// 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;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MD5Importer::LoadFileIntoMemory (IOStream* file)
|
||||
{
|
||||
ai_assert(NULL != file);
|
||||
|
||||
this->fileSize = (unsigned int)file->FileSize();
|
||||
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
this->pScene = pScene;
|
||||
this->mBuffer = new char[this->fileSize+1];
|
||||
file->Read( (void*)mBuffer, 1, this->fileSize);
|
||||
this->iLineNumber = 1;
|
||||
|
||||
// append a terminal 0
|
||||
this->mBuffer[this->fileSize] = '\0';
|
||||
|
||||
// now remove all line comments from the file
|
||||
CommentRemover::RemoveLineComments("//",this->mBuffer,' ');
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MD5Importer::UnloadFileFromMemory ()
|
||||
{
|
||||
// delete the file buffer
|
||||
delete[] this->mBuffer;
|
||||
this->mBuffer = NULL;
|
||||
this->fileSize = 0;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MakeDataUnique (MD5::MeshDesc& meshSrc)
|
||||
{
|
||||
std::vector<bool> abHad(meshSrc.mVertices.size(),false);
|
||||
|
||||
// allocate enough storage to keep the output structures
|
||||
const unsigned int iNewNum = (unsigned int)meshSrc.mFaces.size()*3;
|
||||
unsigned int iNewIndex = (unsigned int)meshSrc.mVertices.size();
|
||||
meshSrc.mVertices.resize(iNewNum);
|
||||
|
||||
// try to guess how much storage we'll need for new weights
|
||||
const float fWeightsPerVert = meshSrc.mWeights.size() / (float)iNewIndex;
|
||||
const unsigned int guess = (unsigned int)(fWeightsPerVert*iNewNum);
|
||||
meshSrc.mWeights.reserve(guess + (guess >> 3)); // + 12.5% as buffer
|
||||
|
||||
for (FaceList::const_iterator iter = meshSrc.mFaces.begin(),iterEnd = meshSrc.mFaces.end();
|
||||
iter != iterEnd;++iter)
|
||||
{
|
||||
const aiFace& face = *iter;
|
||||
for (unsigned int i = 0; i < 3;++i)
|
||||
{
|
||||
if (abHad[face.mIndices[i]])
|
||||
{
|
||||
// generate a new vertex
|
||||
meshSrc.mVertices[iNewIndex] = meshSrc.mVertices[face.mIndices[i]];
|
||||
face.mIndices[i] = iNewIndex++;
|
||||
|
||||
// FIX: removed this ...
|
||||
#if 0
|
||||
// the algorithm in MD5Importer::LoadMD5MeshFile() doesn't work if
|
||||
// a weight is referenced by more than one vertex. This shouldn't
|
||||
// occur in MD5 files, but we must take care that we generate new
|
||||
// weights now, too.
|
||||
|
||||
vertNew.mFirstWeight = (unsigned int)meshSrc.mWeights.size();
|
||||
meshSrc.mWeights.resize(vertNew.mFirstWeight+vertNew.mNumWeights);
|
||||
for (unsigned int q = 0; q < vertNew.mNumWeights;++q)
|
||||
{
|
||||
meshSrc.mWeights[vertNew.mFirstWeight+q] = meshSrc.mWeights[vertOld.mFirstWeight+q];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else abHad[face.mIndices[i]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AttachChilds(int iParentID,aiNode* piParent,BoneList& bones)
|
||||
{
|
||||
ai_assert(NULL != piParent && !piParent->mNumChildren);
|
||||
for (unsigned int i = 0; i < bones.size();++i)
|
||||
{
|
||||
// (avoid infinite recursion)
|
||||
if (iParentID != i && bones[i].mParentIndex == iParentID)
|
||||
{
|
||||
// have it ...
|
||||
++piParent->mNumChildren;
|
||||
}
|
||||
}
|
||||
if (piParent->mNumChildren)
|
||||
{
|
||||
piParent->mChildren = new aiNode*[piParent->mNumChildren];
|
||||
for (unsigned int i = 0; i < bones.size();++i)
|
||||
{
|
||||
// (avoid infinite recursion)
|
||||
if (iParentID != i && bones[i].mParentIndex == iParentID)
|
||||
{
|
||||
aiNode* pc;
|
||||
*piParent->mChildren++ = pc = new aiNode();
|
||||
pc->mName = aiString(bones[i].mName);
|
||||
pc->mParent = piParent;
|
||||
|
||||
// get the transformation matrix from rotation and translational components
|
||||
aiQuaternion quat = aiQuaternion ( bones[i].mRotationQuat );
|
||||
//quat.w *= -1.0f; // DX to OGL
|
||||
pc->mTransformation = aiMatrix4x4 ( quat.GetMatrix());
|
||||
aiMatrix4x4 mTranslate;
|
||||
mTranslate.a4 = bones[i].mPositionXYZ.x;
|
||||
mTranslate.b4 = bones[i].mPositionXYZ.y;
|
||||
mTranslate.c4 = bones[i].mPositionXYZ.z;
|
||||
pc->mTransformation = pc->mTransformation*mTranslate;
|
||||
|
||||
// store it for later use
|
||||
bones[i].mTransform = bones[i].mInvTransform = pc->mTransformation;
|
||||
bones[i].mInvTransform.Inverse();
|
||||
|
||||
// the transformations for each bone are absolute,
|
||||
// so we need to multiply them with the inverse
|
||||
// of the absolut matrix of the parent
|
||||
if (-1 != iParentID)
|
||||
{
|
||||
pc->mTransformation = bones[iParentID].mInvTransform*pc->mTransformation;
|
||||
}
|
||||
|
||||
// add children to this node, too
|
||||
AttachChilds( i, pc, bones);
|
||||
}
|
||||
}
|
||||
// undo our nice shift
|
||||
piParent->mChildren -= piParent->mNumChildren;
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MD5Importer::LoadMD5MeshFile ()
|
||||
{
|
||||
std::string pFile = this->mFile + "MD5MESH";
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
||||
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL)
|
||||
{
|
||||
DefaultLogger::get()->warn("Failed to read MD5 mesh file: " + pFile);
|
||||
return;
|
||||
}
|
||||
bHadMD5Mesh = true;
|
||||
|
||||
// now load the file into memory
|
||||
this->LoadFileIntoMemory(file.get());
|
||||
|
||||
// now construct a parser and parse the file
|
||||
MD5::MD5Parser parser(mBuffer,fileSize);
|
||||
|
||||
// load the mesh information from it
|
||||
MD5::MD5MeshParser meshParser(parser.mSections);
|
||||
|
||||
// create the bone hierarchy - first the root node
|
||||
// and dummy nodes for all meshes
|
||||
pScene->mRootNode = new aiNode();
|
||||
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();
|
||||
pcNode->mName.Set("MD5Anim");
|
||||
pcNode->mParent = pScene->mRootNode;
|
||||
AttachChilds(-1,pcNode,meshParser.mJoints);
|
||||
|
||||
// generate all meshes
|
||||
pScene->mNumMeshes = pScene->mNumMaterials = (unsigned int)meshParser.mMeshes.size();
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes];
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[i] = new aiMesh();
|
||||
MD5::MeshDesc& meshSrc = meshParser.mMeshes[i];
|
||||
|
||||
// generate unique vertices in our internal verbose format
|
||||
MakeDataUnique(meshSrc);
|
||||
|
||||
mesh->mNumVertices = (unsigned int) meshSrc.mVertices.size();
|
||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
||||
mesh->mNumUVComponents[0] = 2;
|
||||
|
||||
// copy texture coordinates
|
||||
aiVector3D* pv = mesh->mTextureCoords[0];
|
||||
for (MD5::VertexList::const_iterator
|
||||
iter = meshSrc.mVertices.begin();
|
||||
iter != meshSrc.mVertices.end();++iter,++pv)
|
||||
{
|
||||
pv->x = (*iter).mUV.x;
|
||||
pv->y = 1.0f-(*iter).mUV.y; // D3D to OpenGL
|
||||
pv->z = 0.0f;
|
||||
}
|
||||
|
||||
// sort all bone weights - per bone
|
||||
unsigned int* piCount = new unsigned int[meshParser.mJoints.size()];
|
||||
::memset(piCount,0,sizeof(unsigned int)*meshParser.mJoints.size());
|
||||
|
||||
for (MD5::VertexList::const_iterator
|
||||
iter = meshSrc.mVertices.begin();
|
||||
iter != meshSrc.mVertices.end();++iter,++pv)
|
||||
{
|
||||
for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w)
|
||||
{
|
||||
MD5::WeightDesc& desc = meshSrc.mWeights[w];
|
||||
++piCount[desc.mBone];
|
||||
}
|
||||
}
|
||||
|
||||
// check how many we will need
|
||||
for (unsigned int p = 0; p < meshParser.mJoints.size();++p)
|
||||
if (piCount[p])mesh->mNumBones++;
|
||||
|
||||
if (mesh->mNumBones) // just for safety
|
||||
{
|
||||
mesh->mBones = new aiBone*[mesh->mNumBones];
|
||||
for (unsigned int q = 0,h = 0; q < meshParser.mJoints.size();++q)
|
||||
{
|
||||
if (!piCount[q])continue;
|
||||
aiBone* p = mesh->mBones[h] = new aiBone();
|
||||
p->mNumWeights = piCount[q];
|
||||
p->mWeights = new aiVertexWeight[p->mNumWeights];
|
||||
p->mName = aiString(meshParser.mJoints[q].mName);
|
||||
|
||||
// store the index for later use
|
||||
meshParser.mJoints[q].mMap = h++;
|
||||
}
|
||||
|
||||
unsigned int g = 0;
|
||||
pv = mesh->mVertices;
|
||||
for (MD5::VertexList::const_iterator
|
||||
iter = meshSrc.mVertices.begin();
|
||||
iter != meshSrc.mVertices.end();++iter,++pv)
|
||||
{
|
||||
// compute the final vertex position from all single weights
|
||||
*pv = aiVector3D();
|
||||
|
||||
// there are models which have weights which don't sum to 1 ...
|
||||
// granite.md5mesh for example
|
||||
float fSum = 0.0f;
|
||||
for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w)
|
||||
fSum += meshSrc.mWeights[w].mWeight;
|
||||
if (!fSum)throw new ImportErrorException("The sum of all vertex bone weights is 0");
|
||||
|
||||
// process bone weights
|
||||
for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w)
|
||||
{
|
||||
MD5::WeightDesc& desc = meshSrc.mWeights[w];
|
||||
float fNewWeight = desc.mWeight / fSum;
|
||||
|
||||
// transform the local position into worldspace
|
||||
MD5::BoneDesc& boneSrc = meshParser.mJoints[desc.mBone];
|
||||
aiVector3D v = desc.vOffsetPosition;
|
||||
aiQuaternion quat = aiQuaternion( boneSrc.mRotationQuat );
|
||||
//quat.w *= -1.0f;
|
||||
v = quat.GetMatrix() * v;
|
||||
v += boneSrc.mPositionXYZ;
|
||||
|
||||
// use the original weight to compute the vertex position
|
||||
// (some MD5s seem to depend on the invalid weight values ...)
|
||||
pv->operator +=(v * desc.mWeight);
|
||||
|
||||
aiBone* bone = mesh->mBones[boneSrc.mMap];
|
||||
*bone->mWeights++ = aiVertexWeight((unsigned int)(pv-mesh->mVertices),fNewWeight);
|
||||
}
|
||||
// convert from DOOM coordinate system to OGL
|
||||
std::swap(pv->z,pv->y);
|
||||
}
|
||||
|
||||
// undo our nice offset tricks ...
|
||||
for (unsigned int p = 0; p < mesh->mNumBones;++p)
|
||||
mesh->mBones[p]->mWeights -= mesh->mBones[p]->mNumWeights;
|
||||
}
|
||||
|
||||
delete[] piCount;
|
||||
|
||||
// now setup all faces - we can directly copy the list
|
||||
// (however, take care that the aiFace destructor doesn't delete the mIndices array)
|
||||
mesh->mNumFaces = (unsigned int)meshSrc.mFaces.size();
|
||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
for (unsigned int c = 0; c < mesh->mNumFaces;++c)
|
||||
{
|
||||
mesh->mFaces[c].mNumIndices = 3;
|
||||
mesh->mFaces[c].mIndices = meshSrc.mFaces[c].mIndices;
|
||||
meshSrc.mFaces[c].mIndices = NULL;
|
||||
}
|
||||
|
||||
// generate a material for the mesh
|
||||
MaterialHelper* mat = new MaterialHelper();
|
||||
pScene->mMaterials[i] = mat;
|
||||
mat->AddProperty(&meshSrc.mShader,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
mesh->mMaterialIndex = i;
|
||||
}
|
||||
|
||||
// delete the file again
|
||||
this->UnloadFileFromMemory();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MD5Importer::LoadMD5AnimFile ()
|
||||
{
|
||||
std::string pFile = this->mFile + "MD5ANIM";
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
||||
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL)
|
||||
{
|
||||
DefaultLogger::get()->warn("Failed to read MD5 anim file: " + pFile);
|
||||
return;
|
||||
}
|
||||
bHadMD5Anim = true;
|
||||
|
||||
// now load the file into memory
|
||||
this->LoadFileIntoMemory(file.get());
|
||||
|
||||
// now construct a parser and parse the file
|
||||
MD5::MD5Parser parser(mBuffer,fileSize);
|
||||
|
||||
// load the animation information from it
|
||||
MD5::MD5AnimParser animParser(parser.mSections);
|
||||
|
||||
// generate and fill the output animation
|
||||
if (!animParser.mAnimatedBones.empty())
|
||||
{
|
||||
pScene->mNumAnimations = 1;
|
||||
pScene->mAnimations = new aiAnimation*[1];
|
||||
aiAnimation* anim = pScene->mAnimations[0] = new aiAnimation();
|
||||
anim->mNumBones = (unsigned int)animParser.mAnimatedBones.size();
|
||||
anim->mBones = new aiBoneAnim*[anim->mNumBones];
|
||||
for (unsigned int i = 0; i < anim->mNumBones;++i)
|
||||
{
|
||||
aiBoneAnim* bone = anim->mBones[i] = new aiBoneAnim();
|
||||
bone->mBoneName = aiString( animParser.mAnimatedBones[i].mName );
|
||||
|
||||
// allocate storage for the keyframes
|
||||
bone->mNumPositionKeys = bone->mNumRotationKeys = (unsigned int)animParser.mFrames.size();
|
||||
bone->mPositionKeys = new aiVectorKey[bone->mNumPositionKeys];
|
||||
bone->mRotationKeys = new aiQuatKey[bone->mNumPositionKeys];
|
||||
}
|
||||
|
||||
// 1 tick == 1 frame
|
||||
anim->mTicksPerSecond = animParser.fFrameRate;
|
||||
|
||||
for (FrameList::const_iterator iter = animParser.mFrames.begin(),
|
||||
iterEnd = animParser.mFrames.end();iter != iterEnd;++iter)
|
||||
{
|
||||
double dTime = (double)(*iter).iIndex;
|
||||
if (!(*iter).mValues.empty())
|
||||
{
|
||||
// now process all values in there ... read all joints
|
||||
aiBoneAnim** pcAnimBone = anim->mBones;
|
||||
MD5::BaseFrameDesc* pcBaseFrame = &animParser.mBaseFrames[0];
|
||||
for (AnimBoneList::const_iterator
|
||||
iter2 = animParser.mAnimatedBones.begin(),
|
||||
iterEnd2 = animParser.mAnimatedBones.end();
|
||||
iter2 != iterEnd2;++iter2,++pcAnimBone,++pcBaseFrame)
|
||||
{
|
||||
if((*iter2).iFirstKeyIndex >= (*iter).mValues.size())
|
||||
{
|
||||
// TODO: add proper array checks for all cases here ...
|
||||
DefaultLogger::get()->error("Keyframe index is out of range. ");
|
||||
continue;
|
||||
}
|
||||
const float* fpCur = &(*iter).mValues[(*iter2).iFirstKeyIndex];
|
||||
|
||||
aiBoneAnim* pcCurAnimBone = *pcAnimBone;
|
||||
aiVectorKey* vKey = pcCurAnimBone->mPositionKeys++;
|
||||
|
||||
// translation on the x axis
|
||||
if ((*iter2).iFlags & AI_MD5_ANIMATION_FLAG_TRANSLATE_X)
|
||||
vKey->mValue.x = *fpCur++;
|
||||
else vKey->mValue.x = pcBaseFrame->vPositionXYZ.x;
|
||||
|
||||
// translation on the y axis
|
||||
if ((*iter2).iFlags & AI_MD5_ANIMATION_FLAG_TRANSLATE_Y)
|
||||
vKey->mValue.y = *fpCur++;
|
||||
else vKey->mValue.y = pcBaseFrame->vPositionXYZ.y;
|
||||
|
||||
// translation on the z axis
|
||||
if ((*iter2).iFlags & AI_MD5_ANIMATION_FLAG_TRANSLATE_Z)
|
||||
vKey->mValue.z = *fpCur++;
|
||||
else vKey->mValue.z = pcBaseFrame->vPositionXYZ.z;
|
||||
|
||||
|
||||
// rotation quaternion, x component
|
||||
aiQuatKey* qKey = pcCurAnimBone->mRotationKeys++;
|
||||
aiVector3D vTemp;
|
||||
if ((*iter2).iFlags & AI_MD5_ANIMATION_FLAG_ROTQUAT_X)
|
||||
vTemp.x = *fpCur++;
|
||||
else vTemp.x = pcBaseFrame->vRotationQuat.x;
|
||||
|
||||
// rotation quaternion, y component
|
||||
if ((*iter2).iFlags & AI_MD5_ANIMATION_FLAG_ROTQUAT_Y)
|
||||
vTemp.y = *fpCur++;
|
||||
else vTemp.y = pcBaseFrame->vRotationQuat.y;
|
||||
|
||||
// rotation quaternion, z component
|
||||
if ((*iter2).iFlags & AI_MD5_ANIMATION_FLAG_ROTQUAT_Z)
|
||||
vTemp.z = *fpCur++;
|
||||
else vTemp.z = pcBaseFrame->vRotationQuat.z;
|
||||
|
||||
// compute the w component of the quaternion - invert it (DX to OGL)
|
||||
qKey->mValue = aiQuaternion(vTemp);
|
||||
//qKey->mValue.w *= -1.0f;
|
||||
|
||||
qKey->mTime = dTime;
|
||||
vKey->mTime = dTime;
|
||||
}
|
||||
}
|
||||
// compute the duration of the animation
|
||||
anim->mDuration = std::max(dTime,anim->mDuration);
|
||||
}
|
||||
|
||||
// undo our offset computations
|
||||
for (unsigned int i = 0; i < anim->mNumBones;++i)
|
||||
{
|
||||
aiBoneAnim* bone = anim->mBones[i];
|
||||
bone->mPositionKeys -= bone->mNumPositionKeys;
|
||||
bone->mRotationKeys -= bone->mNumPositionKeys;
|
||||
}
|
||||
}
|
||||
|
||||
// delete the file again
|
||||
this->UnloadFileFromMemory();
|
||||
}
|
|
@ -39,21 +39,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
|
||||
/** @file Definition of the .MD5 importer class. */
|
||||
/** @file Definition of the .MD5 importer class.
|
||||
http://www.modwiki.net/wiki/MD5_(file_format)
|
||||
*/
|
||||
#ifndef AI_MD5LOADER_H_INCLUDED
|
||||
#define AI_MD5LOADER_H_INCLUDED
|
||||
|
||||
#include "BaseImporter.h"
|
||||
#include "MD5Parser.h"
|
||||
|
||||
#include "../include/aiTypes.h"
|
||||
|
||||
struct aiNode;
|
||||
#include "MD5FileData.h"
|
||||
namespace Assimp {
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
class MaterialHelper;
|
||||
|
||||
using namespace MD5;
|
||||
class IOStream;
|
||||
using namespace Assimp::MD5;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Used to load MD5 files
|
||||
|
@ -96,11 +96,57 @@ protected:
|
|||
|
||||
protected:
|
||||
|
||||
/** Header of the MD5 file */
|
||||
const MD5::Header* m_pcHeader;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load the *.MD5MESH file.
|
||||
* Must be called at first.
|
||||
*/
|
||||
void LoadMD5MeshFile ();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load the *.MD5ANIM file.
|
||||
*/
|
||||
void LoadMD5AnimFile ();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load the contents of a specific file into memory and
|
||||
* alocates a buffer to keep it.
|
||||
*
|
||||
* mBuffer is changed to point to this buffer.
|
||||
* Don't forget to delete it later ...
|
||||
* @param pFile File stream to be read
|
||||
*/
|
||||
void LoadFileIntoMemory (IOStream* pFile);
|
||||
void UnloadFileFromMemory ();
|
||||
|
||||
|
||||
/** IOSystem to be used to access files */
|
||||
IOSystem* mIOHandler;
|
||||
|
||||
/** Path to the file, excluding the file extension but
|
||||
with the dot */
|
||||
std::string mFile;
|
||||
|
||||
/** Buffer to hold the loaded file */
|
||||
const unsigned char* mBuffer;
|
||||
char* mBuffer;
|
||||
|
||||
/** Size of the file */
|
||||
unsigned int fileSize;
|
||||
|
||||
/** Current line number. For debugging purposes */
|
||||
unsigned int iLineNumber;
|
||||
|
||||
/** Scene to be filled */
|
||||
aiScene* pScene;
|
||||
|
||||
/** (Custom) I/O handler implementation */
|
||||
IOSystem* pIOHandler;
|
||||
|
||||
/** true if the MD5MESH file has already been parsed */
|
||||
bool bHadMD5Mesh;
|
||||
|
||||
/** true if the MD5ANIM file has already been parsed */
|
||||
bool bHadMD5Anim;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -0,0 +1,545 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 MD5 parser class */
|
||||
|
||||
// internal headers
|
||||
#include "MD5Loader.h"
|
||||
#include "MaterialSystem.h"
|
||||
#include "fast_atof.h"
|
||||
#include "ParsingUtils.h"
|
||||
#include "StringComparison.h"
|
||||
|
||||
// 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"
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::MD5;
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
# define sprintf sprintf_s
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MD5Parser::MD5Parser(char* buffer, unsigned int fileSize)
|
||||
{
|
||||
ai_assert(NULL != buffer && 0 != fileSize);
|
||||
|
||||
this->buffer = buffer;
|
||||
this->fileSize = fileSize;
|
||||
this->lineNumber = 0;
|
||||
|
||||
DefaultLogger::get()->debug("MD5Parser begin");
|
||||
|
||||
// parse the file header
|
||||
this->ParseHeader();
|
||||
|
||||
// and read all sections until we're finished
|
||||
while (true)
|
||||
{
|
||||
this->mSections.push_back(Section());
|
||||
Section& sec = this->mSections.back();
|
||||
if(!this->ParseSection(sec))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !DefaultLogger::isNullLogger())
|
||||
{
|
||||
char szBuffer[128]; // should be sufficiently large
|
||||
::sprintf(szBuffer,"MD5Parser end. Parsed %i sections",this->mSections.size());
|
||||
DefaultLogger::get()->debug(szBuffer);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ void MD5Parser::ReportError (char* error, unsigned int line)
|
||||
{
|
||||
char szBuffer[1024]; // you, listen to me, you HAVE TO BE sufficiently large
|
||||
::sprintf(szBuffer,"Line %i: %s",line,error);
|
||||
throw new ImportErrorException(szBuffer);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ void MD5Parser::ReportWarning (char* warn, unsigned int line)
|
||||
{
|
||||
char szBuffer[1024]; // you, listen to me, you HAVE TO BE sufficiently large
|
||||
::sprintf(szBuffer,"Line %i: %s",line,warn);
|
||||
DefaultLogger::get()->warn(szBuffer);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MD5Parser::ParseHeader()
|
||||
{
|
||||
// parse and validate the file version
|
||||
SkipSpaces();
|
||||
if (0 != ASSIMP_strincmp(buffer,"MD5Version",10) ||
|
||||
!IsSpace(*(buffer+=10)))
|
||||
{
|
||||
this->ReportError("Invalid MD5 file: MD5Version tag has not been found");
|
||||
}
|
||||
SkipSpaces();
|
||||
unsigned int iVer = ::strtol10(buffer,(const char**)&buffer);
|
||||
if (10 != iVer)
|
||||
{
|
||||
this->ReportWarning("MD5 version tag is unknown (10 is expected)");
|
||||
}
|
||||
this->SkipLine();
|
||||
|
||||
// print the command line options to the console
|
||||
char* sz = buffer;
|
||||
while (!IsLineEnd( *buffer++));
|
||||
DefaultLogger::get()->info(std::string(sz,(uintptr_t)(buffer-sz)));
|
||||
this->SkipSpacesAndLineEnd();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool MD5Parser::ParseSection(Section& out)
|
||||
{
|
||||
// store the current line number for use in error messages
|
||||
out.iLineNumber = this->lineNumber;
|
||||
|
||||
// first parse the name of the section
|
||||
char* sz = buffer;
|
||||
while (!IsSpaceOrNewLine( *buffer))buffer++;
|
||||
out.mName = std::string(sz,(uintptr_t)(buffer-sz));
|
||||
SkipSpaces();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if ('{' == *buffer)
|
||||
{
|
||||
// it is a normal section so read all lines
|
||||
buffer++;
|
||||
while (true)
|
||||
{
|
||||
if (!SkipSpacesAndLineEnd())
|
||||
{
|
||||
return false; // seems this was the last section
|
||||
}
|
||||
if ('}' == *buffer)
|
||||
{
|
||||
buffer++;
|
||||
break;
|
||||
}
|
||||
|
||||
out.mElements.push_back(Element());
|
||||
Element& elem = out.mElements.back();
|
||||
|
||||
elem.iLineNumber = lineNumber;
|
||||
elem.szStart = buffer;
|
||||
|
||||
// terminate the line with zero - remove all spaces at the end
|
||||
while (!IsLineEnd( *buffer))buffer++;
|
||||
//const char* end = buffer;
|
||||
do {buffer--;}
|
||||
while (IsSpace(*buffer));
|
||||
buffer++;
|
||||
*buffer++ = '\0';
|
||||
//if (*end) ++lineNumber;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (!IsSpaceOrNewLine(*buffer))
|
||||
{
|
||||
// it is an element at global scope. Parse its value and go on
|
||||
// FIX: for MD5ANIm files - frame 0 {...} is allowed
|
||||
sz = buffer;
|
||||
while (!IsSpaceOrNewLine( *buffer++));
|
||||
out.mGlobalValue = std::string(sz,(uintptr_t)(buffer-sz));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return SkipSpacesAndLineEnd();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// skip all spaces ... handle EOL correctly
|
||||
#define AI_MD5_SKIP_SPACES() if(!SkipSpaces(&sz)) \
|
||||
MD5Parser::ReportWarning("Unexpected end of line",(*eit).iLineNumber);
|
||||
|
||||
// read a triple float in brackets: (1.0 1.0 1.0)
|
||||
#define AI_MD5_READ_TRIPLE(vec) \
|
||||
AI_MD5_SKIP_SPACES(); \
|
||||
if ('(' != *sz++) \
|
||||
MD5Parser::ReportWarning("Unexpected token: ( was expected",(*eit).iLineNumber); \
|
||||
AI_MD5_SKIP_SPACES(); \
|
||||
sz = fast_atof_move(sz,vec.x); \
|
||||
AI_MD5_SKIP_SPACES(); \
|
||||
sz = fast_atof_move(sz,vec.y); \
|
||||
AI_MD5_SKIP_SPACES(); \
|
||||
sz = fast_atof_move(sz,vec.z); \
|
||||
AI_MD5_SKIP_SPACES(); \
|
||||
if (')' != *sz++) \
|
||||
MD5Parser::ReportWarning("Unexpected token: ) was expected",(*eit).iLineNumber);
|
||||
|
||||
// parse a string, enclosed in quotation marks or not
|
||||
#define AI_MD5_PARSE_STRING(out) \
|
||||
bool bQuota = *sz == '\"'; \
|
||||
const char* szStart = sz; \
|
||||
while (!IsSpaceOrNewLine(*sz))++sz; \
|
||||
const char* szEnd = sz; \
|
||||
if (bQuota) \
|
||||
{ \
|
||||
szStart++; \
|
||||
if ('\"' != *(szEnd-=1)) \
|
||||
{ \
|
||||
MD5Parser::ReportWarning("Expected closing quotation marks in string", \
|
||||
(*eit).iLineNumber); \
|
||||
} \
|
||||
} \
|
||||
out.length = (size_t)(szEnd - szStart); \
|
||||
::memcpy(out.data,szStart,out.length); \
|
||||
out.data[out.length] = '\0';
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MD5MeshParser::MD5MeshParser(SectionList& mSections)
|
||||
{
|
||||
DefaultLogger::get()->debug("MD5MeshParser begin");
|
||||
|
||||
// now parse all sections
|
||||
for (SectionList::const_iterator
|
||||
iter = mSections.begin(), iterEnd = mSections.end();
|
||||
iter != iterEnd;++iter)
|
||||
{
|
||||
if ((*iter).mGlobalValue.length())
|
||||
{
|
||||
if ( !::strcmp("numMeshes",(*iter).mName.c_str()))
|
||||
{
|
||||
unsigned int iNumMeshes;
|
||||
if(iNumMeshes = ::strtol10((*iter).mGlobalValue.c_str()))
|
||||
{
|
||||
mMeshes.reserve(iNumMeshes);
|
||||
}
|
||||
}
|
||||
else if ( !::strcmp("numJoints",(*iter).mName.c_str()))
|
||||
{
|
||||
unsigned int iNumJoints;
|
||||
if(iNumJoints = ::strtol10((*iter).mGlobalValue.c_str()))
|
||||
{
|
||||
mJoints.reserve(iNumJoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!::strcmp("joints",(*iter).mName.c_str()))
|
||||
{
|
||||
// now read all elements
|
||||
// "origin" -1 ( -0.000000 0.016430 -0.006044 ) ( 0.707107 0.000000 0.707107 )
|
||||
for (ElementList::const_iterator
|
||||
eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();
|
||||
eit != eitEnd; ++eit)
|
||||
{
|
||||
mJoints.push_back(BoneDesc());
|
||||
BoneDesc& desc = mJoints.back();
|
||||
|
||||
const char* sz = (*eit).szStart;
|
||||
|
||||
AI_MD5_PARSE_STRING(desc.mName);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
|
||||
// negative values can occur here ...
|
||||
bool bNeg = false;
|
||||
if ('-' == *sz){sz++;bNeg = true;}
|
||||
else if ('+' == *sz){sz++;}
|
||||
desc.mParentIndex = (int)::strtol10(sz,&sz);
|
||||
if (bNeg)desc.mParentIndex *= -1;
|
||||
|
||||
AI_MD5_READ_TRIPLE(desc.mPositionXYZ);
|
||||
AI_MD5_READ_TRIPLE(desc.mRotationQuat); // normalized quaternion, so w is not there
|
||||
}
|
||||
}
|
||||
else if (!::strcmp("mesh",(*iter).mName.c_str()))
|
||||
{
|
||||
mMeshes.push_back(MeshDesc());
|
||||
MeshDesc& desc = mMeshes.back();
|
||||
|
||||
// now read all elements
|
||||
for (ElementList::const_iterator
|
||||
eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();
|
||||
eit != eitEnd; ++eit)
|
||||
{
|
||||
const char* sz = (*eit).szStart;
|
||||
|
||||
// shader attribute
|
||||
if (!ASSIMP_strincmp(sz,"shader",6) &&
|
||||
IsSpaceOrNewLine(*(sz+=6)++))
|
||||
{
|
||||
// don't expect quotation marks
|
||||
AI_MD5_SKIP_SPACES();
|
||||
AI_MD5_PARSE_STRING(desc.mShader);
|
||||
}
|
||||
// numverts attribute
|
||||
else if (!ASSIMP_strincmp(sz,"numverts",8) &&
|
||||
IsSpaceOrNewLine(*(sz+=8)++))
|
||||
{
|
||||
// reserve enough storage
|
||||
AI_MD5_SKIP_SPACES();
|
||||
unsigned int iNumVertices;
|
||||
if(iNumVertices = ::strtol10(sz))
|
||||
desc.mVertices.resize(iNumVertices);
|
||||
}
|
||||
// numtris attribute
|
||||
else if (!ASSIMP_strincmp(sz,"numtris",7) &&
|
||||
IsSpaceOrNewLine(*(sz+=7)++))
|
||||
{
|
||||
// reserve enough storage
|
||||
AI_MD5_SKIP_SPACES();
|
||||
unsigned int iNumTris;
|
||||
if(iNumTris = ::strtol10(sz))
|
||||
desc.mFaces.resize(iNumTris);
|
||||
}
|
||||
// numweights attribute
|
||||
else if (!ASSIMP_strincmp(sz,"numweights",10) &&
|
||||
IsSpaceOrNewLine(*(sz+=10)++))
|
||||
{
|
||||
// reserve enough storage
|
||||
AI_MD5_SKIP_SPACES();
|
||||
unsigned int iNumWeights;
|
||||
if(iNumWeights = ::strtol10(sz))
|
||||
desc.mWeights.resize(iNumWeights);
|
||||
}
|
||||
// vert attribute
|
||||
// "vert 0 ( 0.394531 0.513672 ) 0 1"
|
||||
else if (!ASSIMP_strincmp(sz,"vert",4) &&
|
||||
IsSpaceOrNewLine(*(sz+=4)++))
|
||||
{
|
||||
AI_MD5_SKIP_SPACES();
|
||||
unsigned int idx = ::strtol10(sz,&sz);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
if (idx >= desc.mVertices.size())
|
||||
desc.mVertices.resize(idx+1);
|
||||
|
||||
VertexDesc& vert = desc.mVertices[idx];
|
||||
if ('(' != *sz++)
|
||||
MD5Parser::ReportWarning("Unexpected token: ( was expected",(*eit).iLineNumber);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
sz = fast_atof_move(sz,vert.mUV.x);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
sz = fast_atof_move(sz,vert.mUV.y);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
if (')' != *sz++)
|
||||
MD5Parser::ReportWarning("Unexpected token: ) was expected",(*eit).iLineNumber);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
vert.mFirstWeight = ::strtol10(sz,&sz);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
vert.mNumWeights = ::strtol10(sz,&sz);
|
||||
}
|
||||
// tri attribute
|
||||
// "tri 0 15 13 12"
|
||||
else if (!ASSIMP_strincmp(sz,"tri",3) &&
|
||||
IsSpaceOrNewLine(*(sz+=3)++))
|
||||
{
|
||||
AI_MD5_SKIP_SPACES();
|
||||
unsigned int idx = ::strtol10(sz,&sz);
|
||||
if (idx >= desc.mFaces.size())
|
||||
desc.mFaces.resize(idx+1);
|
||||
|
||||
aiFace& face = desc.mFaces[idx];
|
||||
face.mIndices = new unsigned int[face.mNumIndices = 3];
|
||||
for (unsigned int i = 0; i < 3;++i)
|
||||
{
|
||||
AI_MD5_SKIP_SPACES();
|
||||
face.mIndices[i] = ::strtol10(sz,&sz);
|
||||
}
|
||||
}
|
||||
// weight attribute
|
||||
// "weight 362 5 0.500000 ( -3.553583 11.893474 9.719339 )"
|
||||
else if (!ASSIMP_strincmp(sz,"weight",6) &&
|
||||
IsSpaceOrNewLine(*(sz+=6)++))
|
||||
{
|
||||
AI_MD5_SKIP_SPACES();
|
||||
unsigned int idx = ::strtol10(sz,&sz);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
if (idx >= desc.mWeights.size())
|
||||
desc.mWeights.resize(idx+1);
|
||||
|
||||
WeightDesc& weight = desc.mWeights[idx];
|
||||
weight.mBone = ::strtol10(sz,&sz);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
sz = fast_atof_move(sz,weight.mWeight);
|
||||
AI_MD5_READ_TRIPLE(weight.vOffsetPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DefaultLogger::get()->debug("MD5MeshParser end");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MD5AnimParser::MD5AnimParser(SectionList& mSections)
|
||||
{
|
||||
DefaultLogger::get()->debug("MD5AnimParser begin");
|
||||
|
||||
fFrameRate = 24.0f;
|
||||
mNumAnimatedComponents = 0xffffffff;
|
||||
|
||||
// now parse all sections
|
||||
for (SectionList::const_iterator
|
||||
iter = mSections.begin(), iterEnd = mSections.end();
|
||||
iter != iterEnd;++iter)
|
||||
{
|
||||
if (!::strcmp("hierarchy",(*iter).mName.c_str()))
|
||||
{
|
||||
// now read all elements
|
||||
// "sheath" 0 63 6
|
||||
for (ElementList::const_iterator
|
||||
eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();
|
||||
eit != eitEnd; ++eit)
|
||||
{
|
||||
mAnimatedBones.push_back ( AnimBoneDesc () );
|
||||
AnimBoneDesc& desc = mAnimatedBones.back();
|
||||
|
||||
const char* sz = (*eit).szStart;
|
||||
AI_MD5_PARSE_STRING(desc.mName);
|
||||
AI_MD5_SKIP_SPACES();
|
||||
|
||||
// parent index
|
||||
// negative values can occur here ...
|
||||
bool bNeg = false;
|
||||
if ('-' == *sz){sz++;bNeg = true;}
|
||||
else if ('+' == *sz){sz++;}
|
||||
desc.mParentIndex = (int)::strtol10(sz,&sz);
|
||||
if (bNeg)desc.mParentIndex *= -1;
|
||||
|
||||
// flags (highest is 2^6-1)
|
||||
AI_MD5_SKIP_SPACES();
|
||||
if(63 < (desc.iFlags = ::strtol10(sz,&sz)))
|
||||
{
|
||||
MD5Parser::ReportWarning("Invalid flag combination in hierarchy section",
|
||||
(*eit).iLineNumber);
|
||||
}
|
||||
AI_MD5_SKIP_SPACES();
|
||||
|
||||
// index of the first animation keyframe component for this joint
|
||||
desc.iFirstKeyIndex = ::strtol10(sz,&sz);
|
||||
}
|
||||
}
|
||||
else if(!::strcmp("baseframe",(*iter).mName.c_str()))
|
||||
{
|
||||
// now read all elements
|
||||
// ( -0.000000 0.016430 -0.006044 ) ( 0.707107 0.000242 0.707107 )
|
||||
for (ElementList::const_iterator
|
||||
eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();
|
||||
eit != eitEnd; ++eit)
|
||||
{
|
||||
const char* sz = (*eit).szStart;
|
||||
|
||||
mBaseFrames.push_back ( BaseFrameDesc () );
|
||||
BaseFrameDesc& desc = mBaseFrames.back();
|
||||
|
||||
AI_MD5_READ_TRIPLE(desc.vPositionXYZ);
|
||||
AI_MD5_READ_TRIPLE(desc.vRotationQuat);
|
||||
}
|
||||
}
|
||||
else if(!::strcmp("frame",(*iter).mName.c_str()))
|
||||
{
|
||||
if (!(*iter).mGlobalValue.length())
|
||||
{
|
||||
MD5Parser::ReportWarning("A frame section must have a frame index",
|
||||
(*iter).iLineNumber);
|
||||
continue;
|
||||
}
|
||||
|
||||
mFrames.push_back ( FrameDesc () );
|
||||
FrameDesc& desc = mFrames.back();
|
||||
desc.iIndex = ::strtol10((*iter).mGlobalValue.c_str());
|
||||
|
||||
// we do already know how much storage we will presumably need
|
||||
if (0xffffffff != mNumAnimatedComponents)
|
||||
desc.mValues.reserve(mNumAnimatedComponents);
|
||||
|
||||
// now read all elements
|
||||
// (continous list of float values)
|
||||
for (ElementList::const_iterator
|
||||
eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();
|
||||
eit != eitEnd; ++eit)
|
||||
{
|
||||
const char* sz = (*eit).szStart;
|
||||
while (SkipSpaces(sz,&sz))
|
||||
{
|
||||
float f;
|
||||
sz = fast_atof_move(sz,f);
|
||||
desc.mValues.push_back(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!::strcmp("numFrames",(*iter).mName.c_str()))
|
||||
{
|
||||
unsigned int iNum;
|
||||
if(iNum = ::strtol10((*iter).mGlobalValue.c_str()))
|
||||
{
|
||||
mFrames.reserve(iNum);
|
||||
}
|
||||
}
|
||||
else if(!::strcmp("numJoints",(*iter).mName.c_str()))
|
||||
{
|
||||
unsigned int iNum;
|
||||
if(iNum = ::strtol10((*iter).mGlobalValue.c_str()))
|
||||
{
|
||||
mAnimatedBones.reserve(iNum);
|
||||
|
||||
// try to guess the number of animated components if that element is not given
|
||||
if (0xffffffff == mNumAnimatedComponents)
|
||||
mNumAnimatedComponents = iNum * 6;
|
||||
}
|
||||
}
|
||||
else if(!::strcmp("numAnimatedComponents",(*iter).mName.c_str()))
|
||||
{
|
||||
unsigned int iNum;
|
||||
if(iNum = ::strtol10((*iter).mGlobalValue.c_str()))
|
||||
{
|
||||
mAnimatedBones.reserve(iNum);
|
||||
}
|
||||
}
|
||||
else if(!::strcmp("frameRate",(*iter).mName.c_str()))
|
||||
{
|
||||
fast_atof_move((*iter).mGlobalValue.c_str(),this->fFrameRate);
|
||||
}
|
||||
}
|
||||
DefaultLogger::get()->debug("MD5AnimParser end");
|
||||
}
|
||||
|
||||
#undef AI_MD5_SKIP_SPACES
|
||||
#undef AI_MD5_READ_TRIPLE
|
||||
#undef AI_MD5_PARSE_STRING
|
|
@ -0,0 +1,419 @@
|
|||
/*
|
||||
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 Definition of the .MD5 parser class.
|
||||
http://www.modwiki.net/wiki/MD5_(file_format)
|
||||
*/
|
||||
#ifndef AI_MD5PARSER_H_INCLUDED
|
||||
#define AI_MD5PARSER_H_INCLUDED
|
||||
|
||||
#include "../include/aiTypes.h"
|
||||
#include "ParsingUtils.h"
|
||||
#include <vector>
|
||||
|
||||
struct aiFace;
|
||||
|
||||
namespace Assimp {
|
||||
namespace MD5 {
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a single element in a MD5 file
|
||||
*
|
||||
* Elements are always contained in sections.
|
||||
*/
|
||||
struct Element
|
||||
{
|
||||
//! Points to the starting point of the element
|
||||
//! Whitespace at the beginning and at the end have been removed,
|
||||
//! Elements are terminated with \0
|
||||
char* szStart;
|
||||
|
||||
//! Original line number (can be used in error messages
|
||||
//! if a parsing error occurs)
|
||||
unsigned int iLineNumber;
|
||||
};
|
||||
|
||||
typedef std::vector< Element > ElementList;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a section of a MD5 file (such as the mesh or the joints section)
|
||||
*
|
||||
* A section is always enclosed in { and } brackets.
|
||||
*/
|
||||
struct Section
|
||||
{
|
||||
//! Original line number (can be used in error messages
|
||||
//! if a parsing error occurs)
|
||||
unsigned int iLineNumber;
|
||||
|
||||
//! List of all elements which have been parsed in this section.
|
||||
ElementList mElements;
|
||||
|
||||
//! Name of the section
|
||||
std::string mName;
|
||||
|
||||
//! For global elements: the value of the element as string
|
||||
//! Iif !length() the section is not a global element
|
||||
std::string mGlobalValue;
|
||||
};
|
||||
|
||||
typedef std::vector< Section> SectionList;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a bone (joint) descriptor in a MD5Mesh file
|
||||
*/
|
||||
struct BoneDesc
|
||||
{
|
||||
//! Name of the bone
|
||||
aiString mName;
|
||||
|
||||
//! Parent index of the bone
|
||||
int mParentIndex;
|
||||
|
||||
//! Relative position of the bone
|
||||
aiVector3D mPositionXYZ;
|
||||
|
||||
//! Relative rotation of the bone
|
||||
aiVector3D mRotationQuat;
|
||||
|
||||
//! Absolute transformation of the bone
|
||||
//! (temporary)
|
||||
aiMatrix4x4 mTransform;
|
||||
|
||||
//! Inverse transformation of the bone
|
||||
//! (temporary)
|
||||
aiMatrix4x4 mInvTransform;
|
||||
|
||||
//! Internal
|
||||
unsigned int mMap;
|
||||
};
|
||||
|
||||
typedef std::vector< BoneDesc > BoneList;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a bone (joint) descriptor in a MD5Anim file
|
||||
*/
|
||||
struct AnimBoneDesc
|
||||
{
|
||||
//! Name of the bone
|
||||
aiString mName;
|
||||
|
||||
//! Parent index of the bone
|
||||
int mParentIndex;
|
||||
|
||||
//! Flags (AI_MD5_ANIMATION_FLAG_xxx)
|
||||
unsigned int iFlags;
|
||||
|
||||
//! Index of the first key that corresponds to this anim bone
|
||||
unsigned int iFirstKeyIndex;
|
||||
};
|
||||
|
||||
typedef std::vector< AnimBoneDesc > AnimBoneList;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a base frame descriptor in a MD5Anim file
|
||||
*/
|
||||
struct BaseFrameDesc
|
||||
{
|
||||
aiVector3D vPositionXYZ;
|
||||
aiVector3D vRotationQuat;
|
||||
};
|
||||
|
||||
typedef std::vector< BaseFrameDesc > BaseFrameList;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a frame descriptor in a MD5Anim file
|
||||
*/
|
||||
struct FrameDesc
|
||||
{
|
||||
//! Index of the frame
|
||||
unsigned int iIndex;
|
||||
|
||||
//! Animation keyframes - a large blob of data at first
|
||||
std::vector< float > mValues;
|
||||
};
|
||||
|
||||
typedef std::vector< FrameDesc > FrameList;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a vertex descriptor in a MD5 file
|
||||
*/
|
||||
struct VertexDesc
|
||||
{
|
||||
VertexDesc()
|
||||
: mFirstWeight (0)
|
||||
, mNumWeights (0)
|
||||
{}
|
||||
|
||||
//! UV cordinate of the vertex
|
||||
aiVector2D mUV;
|
||||
|
||||
//! Index of the first weight of the vertex in
|
||||
//! the vertex weight list
|
||||
unsigned int mFirstWeight;
|
||||
|
||||
//! Number of weights assigned to this vertex
|
||||
unsigned int mNumWeights;
|
||||
};
|
||||
|
||||
typedef std::vector< VertexDesc > VertexList;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a vertex weight descriptor in a MD5 file
|
||||
*/
|
||||
struct WeightDesc
|
||||
{
|
||||
//! Index of the bone to which this weight refers
|
||||
unsigned int mBone;
|
||||
|
||||
//! The weight value
|
||||
float mWeight;
|
||||
|
||||
//! The offset position of this weight
|
||||
// ! (in the coordinate system defined by the parent bone)
|
||||
aiVector3D vOffsetPosition;
|
||||
};
|
||||
|
||||
typedef std::vector< WeightDesc > WeightList;
|
||||
typedef std::vector< aiFace > FaceList;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a mesh in a MD5 file
|
||||
*/
|
||||
struct MeshDesc
|
||||
{
|
||||
//! Weights of the mesh
|
||||
WeightList mWeights;
|
||||
|
||||
//! Vertices of the mesh
|
||||
VertexList mVertices;
|
||||
|
||||
//! Faces of the mesh
|
||||
FaceList mFaces;
|
||||
|
||||
//! Name of the shader (=texture) to be assigned to the mesh
|
||||
aiString mShader;
|
||||
};
|
||||
|
||||
typedef std::vector< MeshDesc > MeshList;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Parses the data sections of a MD5 mesh file
|
||||
*/
|
||||
class MD5MeshParser
|
||||
{
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Constructs a new MD5MeshParser instance from an existing
|
||||
* preparsed list of file sections.
|
||||
*
|
||||
* @param mSections List of file sections (output of MD5Parser)
|
||||
*/
|
||||
MD5MeshParser(SectionList& mSections);
|
||||
|
||||
//! List of all meshes
|
||||
MeshList mMeshes;
|
||||
|
||||
//! List of all joints
|
||||
BoneList mJoints;
|
||||
};
|
||||
|
||||
#define AI_MD5_ANIMATION_FLAG_TRANSLATE_X 0x1
|
||||
#define AI_MD5_ANIMATION_FLAG_TRANSLATE_Y 0x2
|
||||
#define AI_MD5_ANIMATION_FLAG_TRANSLATE_Z 0x4
|
||||
|
||||
#define AI_MD5_ANIMATION_FLAG_ROTQUAT_X 0x8
|
||||
#define AI_MD5_ANIMATION_FLAG_ROTQUAT_Y 0x10
|
||||
#define AI_MD5_ANIMATION_FLAG_ROTQUAT_Z 0x12
|
||||
|
||||
// remove this flag if you need to the bounding box data
|
||||
#define AI_MD5_PARSE_NO_BOUNDS
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Parses the data sections of a MD5 animation file
|
||||
*/
|
||||
class MD5AnimParser
|
||||
{
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Constructs a new MD5AnimParser instance from an existing
|
||||
* preparsed list of file sections.
|
||||
*
|
||||
* @param mSections List of file sections (output of MD5Parser)
|
||||
*/
|
||||
MD5AnimParser(SectionList& mSections);
|
||||
|
||||
|
||||
//! Output frame rate
|
||||
float fFrameRate;
|
||||
|
||||
//! List of animation bones
|
||||
AnimBoneList mAnimatedBones;
|
||||
|
||||
//! List of base frames
|
||||
BaseFrameList mBaseFrames;
|
||||
|
||||
//! List of animation frames
|
||||
FrameList mFrames;
|
||||
|
||||
//! Number of animated components
|
||||
unsigned int mNumAnimatedComponents;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Parses the block structure of MD5MESH and MD5ANIM files (but does no
|
||||
* further processing)
|
||||
*/
|
||||
class MD5Parser
|
||||
{
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Constructs a new MD5Parser instance from an existing buffer.
|
||||
*
|
||||
* @param buffer File buffer
|
||||
* @param fileSize Length of the file in bytes (excluding a terminal 0)
|
||||
*/
|
||||
MD5Parser(char* buffer, unsigned int fileSize);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Report a specific error message and throw an exception
|
||||
* @param error Error message to be reported
|
||||
* @param line Index of the line where the error occured
|
||||
*/
|
||||
static void ReportError (char* error, unsigned int line);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Report a specific warning
|
||||
* @param warn Warn message to be reported
|
||||
* @param line Index of the line where the error occured
|
||||
*/
|
||||
static void ReportWarning (char* warn, unsigned int line);
|
||||
|
||||
|
||||
inline void ReportError (char* error)
|
||||
{return ReportError(error, this->lineNumber);}
|
||||
|
||||
inline void ReportWarning (char* warn)
|
||||
{return ReportWarning(warn, this->lineNumber);}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//! List of all sections which have been read
|
||||
SectionList mSections;
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parses a file section. The current file pointer must be outside
|
||||
* of a section.
|
||||
* @param out Receives the section data
|
||||
* @return true if the end of the file has been reached
|
||||
* @throws ImportErrorException if an error occurs
|
||||
*/
|
||||
bool ParseSection(Section& out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parses the file header
|
||||
* @throws ImportErrorException if an error occurs
|
||||
*/
|
||||
void ParseHeader();
|
||||
|
||||
|
||||
// override these functions to make sure the line counter gets incremented
|
||||
// -------------------------------------------------------------------
|
||||
inline bool SkipLine( const char* in, const char** out)
|
||||
{
|
||||
++lineNumber;
|
||||
return ::SkipLine(in,out);
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
inline bool SkipLine( )
|
||||
{
|
||||
return SkipLine(buffer,(const char**)&buffer);
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
inline bool SkipSpacesAndLineEnd( const char* in, const char** out)
|
||||
{
|
||||
bool bHad = false;
|
||||
while (true)
|
||||
{
|
||||
if( *in == '\r' || *in == '\n')
|
||||
{
|
||||
if (!bHad) // we open files in binary mode, so there could be \r\n sequences ...
|
||||
{
|
||||
bHad = true;
|
||||
++lineNumber;
|
||||
}
|
||||
}
|
||||
else if (*in == '\t' || *in == ' ')bHad = false;
|
||||
else break;
|
||||
in++;
|
||||
}
|
||||
|
||||
*out = in;
|
||||
return *in != '\0';
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
inline bool SkipSpacesAndLineEnd( )
|
||||
{
|
||||
return SkipSpacesAndLineEnd(buffer,(const char**)&buffer);
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
inline bool SkipSpaces( )
|
||||
{
|
||||
return ::SkipSpaces((const char**)&buffer);
|
||||
}
|
||||
|
||||
char* buffer;
|
||||
unsigned int fileSize;
|
||||
unsigned int lineNumber;
|
||||
};
|
||||
}}
|
||||
|
||||
#endif // AI_MD5PARSER_H_INCLUDED
|
|
@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/aiMesh.h"
|
||||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "../include/assimp.hpp"
|
||||
|
||||
// boost headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
@ -127,6 +128,17 @@ void MDLImporter::InternReadFile(
|
|||
throw new ImportErrorException( "Failed to open MDL file " + pFile + ".");
|
||||
}
|
||||
|
||||
// The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
|
||||
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
|
||||
#if 0
|
||||
if(0xffffffff == (this->configFrameID = this->mImporter->GetProperty(
|
||||
AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff)))
|
||||
{
|
||||
this->configFrameID = this->mImporter->GetProperty(
|
||||
AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// this should work for all other types of MDL files, too ...
|
||||
// the quake header is one of the smallest, afaik
|
||||
this->iFileSize = (unsigned int)file->FileSize();
|
||||
|
@ -236,17 +248,11 @@ void MDLImporter::InternReadFile(
|
|||
throw ex;
|
||||
}
|
||||
|
||||
// make sure that the normals are facing outwards
|
||||
// (mainly this applies to MDL7 (due to the FlipNormals option in MED).
|
||||
// However there are some invalid models in other format, too)
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
this->FlipNormals(pScene->mMeshes[i]);
|
||||
|
||||
// delete the file buffer and cleanup
|
||||
delete[] this->mBuffer;
|
||||
DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
DEBUG_INVALIDATE_PTR(this->pIOHandler);
|
||||
DEBUG_INVALIDATE_PTR(this->pScene);
|
||||
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
AI_DEBUG_INVALIDATE_PTR(this->pIOHandler);
|
||||
AI_DEBUG_INVALIDATE_PTR(this->pScene);
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -254,7 +260,7 @@ void MDLImporter::SizeCheck(const void* szPos)
|
|||
{
|
||||
if (!szPos || (const unsigned char*)szPos > this->mBuffer + this->iFileSize)
|
||||
{
|
||||
throw new ImportErrorException("Invalid file. The file is too small "
|
||||
throw new ImportErrorException("Invalid MDL file. The file is too small "
|
||||
"or contains invalid data.");
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +284,7 @@ void MDLImporter::SizeCheck(const void* szPos, const char* szFile, unsigned int
|
|||
#else
|
||||
::sprintf(szBuffer,
|
||||
#endif
|
||||
"Invalid file. The file is too small "
|
||||
"Invalid MDL file. The file is too small "
|
||||
"or contains invalid data (File: %s Line: %i)",szFilePtr,iLine);
|
||||
|
||||
throw new ImportErrorException(szBuffer);
|
||||
|
@ -301,7 +307,9 @@ void MDLImporter::ValidateHeader_Quake1(const MDL::Header* pcHeader)
|
|||
throw new ImportErrorException( "[Quake 1 MDL] There are no triangles in the file");
|
||||
}
|
||||
|
||||
// check whether the maxima are exceeded ...
|
||||
// check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only
|
||||
if (!this->iGSFileVersion)
|
||||
{
|
||||
if (pcHeader->num_verts > AI_MDL_MAX_VERTS)
|
||||
{
|
||||
DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices");
|
||||
|
@ -329,6 +337,7 @@ void MDLImporter::ValidateHeader_Quake1(const MDL::Header* pcHeader)
|
|||
"zero would occur ...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MDLImporter::InternReadFile_Quake1( )
|
||||
|
@ -994,8 +1003,9 @@ void MDLImporter::ReadFaces_3DGS_MDL7(
|
|||
unsigned int iIndex = pcGroupTris->v_index[c];
|
||||
if(iIndex > (unsigned int)groupInfo.pcGroup->numverts)
|
||||
{
|
||||
// LOG
|
||||
iIndex = groupInfo.pcGroup->numverts-1;
|
||||
// (we might need to read this section a second time - to process
|
||||
// frame vertices correctly)
|
||||
const_cast<MDL::Triangle_MDL7*>(pcGroupTris)->v_index[c] = iIndex = groupInfo.pcGroup->numverts-1;
|
||||
DefaultLogger::get()->warn("Index overflow in MDL7 vertex list");
|
||||
}
|
||||
|
||||
|
@ -1022,14 +1032,6 @@ void MDLImporter::ReadFaces_3DGS_MDL7(
|
|||
vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[0];
|
||||
vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[1];
|
||||
vNormal.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2];
|
||||
|
||||
// FIX: It seems to be necessary to invert all normals
|
||||
// FIX2: No, it is not necessary :-)
|
||||
#if 0
|
||||
vNormal.x *= -1.0f;
|
||||
vNormal.y *= -1.0f;
|
||||
vNormal.z *= -1.0f;
|
||||
#endif
|
||||
}
|
||||
else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size)
|
||||
{
|
||||
|
@ -1108,6 +1110,7 @@ void MDLImporter::ReadFaces_3DGS_MDL7(
|
|||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo,
|
||||
MDL::IntGroupData_MDL7& groupData,
|
||||
MDL::IntSharedData_MDL7& shared,
|
||||
const unsigned char* szCurrent,
|
||||
const unsigned char** szCurrentOut)
|
||||
|
@ -1119,9 +1122,10 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf
|
|||
|
||||
// if we have no bones we can simply skip all frames,
|
||||
// otherwise we'll need to process them.
|
||||
// FIX: If we need another frame than the first we must apply frame vertex replacements ...
|
||||
for(unsigned int iFrame = 0; iFrame < (unsigned int)groupInfo.pcGroup->numframes;++iFrame)
|
||||
{
|
||||
MDL::IntFrameInfo_MDL7 frame((const MDL::Frame_MDL7*)szCurrent,iFrame);
|
||||
MDL::IntFrameInfo_MDL7 frame ((const MDL::Frame_MDL7*)szCurrent,iFrame);
|
||||
|
||||
const unsigned int iAdd = pcHeader->frame_stc_size +
|
||||
frame.pcFrame->vertices_count * pcHeader->framevertex_stc_size +
|
||||
|
@ -1129,15 +1133,82 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf
|
|||
|
||||
if (((const char*)szCurrent - (const char*)pcHeader) + iAdd > (unsigned int)pcHeader->data_size)
|
||||
{
|
||||
DefaultLogger::get()->warn("Index overflow in frame area. Ignoring all frames and "
|
||||
"all further groups, too.");
|
||||
DefaultLogger::get()->warn("Index overflow in frame area. "
|
||||
"Ignoring all frames and all further mesh groups, too.");
|
||||
|
||||
// don't parse more groups if we can't even read one
|
||||
// FIXME: sometimes this seems to occur even for valid files ...
|
||||
*szCurrentOut = szCurrent;
|
||||
return false;
|
||||
}
|
||||
// our output frame?
|
||||
if (configFrameID == iFrame)
|
||||
{
|
||||
const MDL::Vertex_MDL7* pcFrameVertices = (const MDL::Vertex_MDL7*)
|
||||
(szCurrent + pcHeader->framevertex_stc_size);
|
||||
|
||||
for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count;++qq)
|
||||
{
|
||||
// I assume this are simple replacements for normal
|
||||
// vertices, the bone index serving as the index of the
|
||||
// vertex to be replaced.
|
||||
uint16_t iIndex = _AI_MDL7_ACCESS(pcFrameVertices,qq,
|
||||
pcHeader->framevertex_stc_size,MDL::Vertex_MDL7).vertindex;
|
||||
|
||||
if (iIndex >= groupInfo.pcGroup->numverts)
|
||||
{
|
||||
DefaultLogger::get()->warn("Invalid vertex index in frame vertex section. "
|
||||
"Skipping this frame vertex");
|
||||
continue;
|
||||
}
|
||||
|
||||
aiVector3D vPosition,vNormal;
|
||||
|
||||
vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .x;
|
||||
vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y;
|
||||
vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z;
|
||||
|
||||
// now read the normal vector
|
||||
if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size)
|
||||
{
|
||||
// read the full normal vector
|
||||
vNormal.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[0];
|
||||
vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[1];
|
||||
vNormal.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[2];
|
||||
}
|
||||
else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size)
|
||||
{
|
||||
// read the normal vector from Quake2's smart table
|
||||
MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,
|
||||
pcHeader->framevertex_stc_size) .norm162index,vNormal);
|
||||
|
||||
std::swap(vNormal.z,vNormal.y);
|
||||
}
|
||||
|
||||
// FIXME: O(n^2) at the moment ...
|
||||
// shouldn't be too worse, frame vertices aren't required more
|
||||
// than once a century ...
|
||||
const MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris;
|
||||
unsigned int iOutIndex = 0;
|
||||
for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle)
|
||||
{
|
||||
// iterate through all indices of the current triangle
|
||||
for (unsigned int c = 0; c < 3;++c,++iOutIndex)
|
||||
{
|
||||
// replace the vertex with the new data
|
||||
const unsigned int iCurIndex = pcGroupTris->v_index[c];
|
||||
if (iCurIndex == iIndex)
|
||||
{
|
||||
groupData.vPositions[iOutIndex] = vPosition;
|
||||
groupData.vNormals[iOutIndex] = vNormal;
|
||||
}
|
||||
}
|
||||
// get the next triangle in the list
|
||||
pcGroupTris = (const MDL::Triangle_MDL7*)((const char*)pcGroupTris +
|
||||
pcHeader->triangle_stc_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
// parse bone trafo matrix keys (only if there are bones ...)
|
||||
if (shared.apcOutBones)
|
||||
{
|
||||
|
@ -1331,9 +1402,13 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
|
|||
}
|
||||
|
||||
// store the name of the group
|
||||
::memcpy(&aszGroupNameBuffer[iGroup*AI_MDL7_MAX_GROUPNAMESIZE],
|
||||
const unsigned int ofs = iGroup*AI_MDL7_MAX_GROUPNAMESIZE;
|
||||
::memcpy(&aszGroupNameBuffer[ofs],
|
||||
groupInfo.pcGroup->name,AI_MDL7_MAX_GROUPNAMESIZE);
|
||||
|
||||
// make sure '\0' is at the end
|
||||
aszGroupNameBuffer[ofs+AI_MDL7_MAX_GROUPNAMESIZE-1] = '\0';
|
||||
|
||||
// read all skins
|
||||
sharedData.pcMats.reserve(sharedData.pcMats.size() + groupInfo.pcGroup->numskins);
|
||||
sharedData.abNeedMaterials.resize(sharedData.abNeedMaterials.size() +
|
||||
|
@ -1362,6 +1437,8 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
|
|||
aiString szName;
|
||||
szName.Set(AI_DEFAULT_MATERIAL_NAME);
|
||||
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
|
||||
|
||||
sharedData.abNeedMaterials.resize(1,false);
|
||||
}
|
||||
|
||||
// now get a pointer to all texture coords in the group
|
||||
|
@ -1379,10 +1456,9 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
|
|||
VALIDATE_FILE_SIZE(szCurrent);
|
||||
|
||||
MDL::IntSplittedGroupData_MDL7 splittedGroupData(sharedData,avOutList[iGroup]);
|
||||
MDL::IntGroupData_MDL7 groupData;
|
||||
if (groupInfo.pcGroup->numtris && groupInfo.pcGroup->numverts)
|
||||
{
|
||||
MDL::IntGroupData_MDL7 groupData;
|
||||
|
||||
// build output vectors
|
||||
const unsigned int iNumVertices = groupInfo.pcGroup->numtris*3;
|
||||
groupData.vPositions.resize(iNumVertices);
|
||||
|
@ -1426,7 +1502,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
|
|||
"vertices or faces. It will be skipped.");
|
||||
|
||||
// process all frames
|
||||
if(!ProcessFrames_3DGS_MDL7(groupInfo,sharedData,szCurrent,&szCurrent))
|
||||
if(!ProcessFrames_3DGS_MDL7(groupInfo,groupData, sharedData,szCurrent,&szCurrent))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1497,8 +1573,8 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
|
|||
|
||||
delete[] avOutList;
|
||||
delete[] aszGroupNameBuffer;
|
||||
DEBUG_INVALIDATE_PTR(avOutList);
|
||||
DEBUG_INVALIDATE_PTR(aszGroupNameBuffer);
|
||||
AI_DEBUG_INVALIDATE_PTR(avOutList);
|
||||
AI_DEBUG_INVALIDATE_PTR(aszGroupNameBuffer);
|
||||
|
||||
// build a final material list.
|
||||
this->CopyMaterials_3DGS_MDL7(sharedData);
|
||||
|
@ -1550,7 +1626,7 @@ void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared)
|
|||
{
|
||||
// destruction is done by the destructor of sh
|
||||
delete shared.pcMats[i];
|
||||
DEBUG_INVALIDATE_PTR(shared.pcMats[i]);
|
||||
AI_DEBUG_INVALIDATE_PTR(shared.pcMats[i]);
|
||||
continue;
|
||||
}
|
||||
this->pScene->mMaterials[p] = shared.pcMats[i];
|
||||
|
@ -1955,55 +2031,6 @@ void MDLImporter::JoinSkins_3DGS_MDL7(
|
|||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MDLImporter::FlipNormals(aiMesh* pcMesh)
|
||||
{
|
||||
ai_assert(NULL != pcMesh);
|
||||
|
||||
// compute the bounding box of both the model vertices + normals and
|
||||
// the umodified model vertices. Then check whether the first BB
|
||||
// is smaller than the second. In this case we can assume that the
|
||||
// normals need to be flipped, although there are a few special cases ..
|
||||
// convex, concave, planar models ...
|
||||
|
||||
aiVector3D vMin0(1e10f,1e10f,1e10f);
|
||||
aiVector3D vMin1(1e10f,1e10f,1e10f);
|
||||
aiVector3D vMax0(-1e10f,-1e10f,-1e10f);
|
||||
aiVector3D vMax1(-1e10f,-1e10f,-1e10f);
|
||||
|
||||
for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
|
||||
{
|
||||
vMin1.x = std::min(vMin1.x,pcMesh->mVertices[i].x);
|
||||
vMin1.y = std::min(vMin1.y,pcMesh->mVertices[i].y);
|
||||
vMin1.z = std::min(vMin1.z,pcMesh->mVertices[i].z);
|
||||
|
||||
vMax1.x = std::max(vMax1.x,pcMesh->mVertices[i].x);
|
||||
vMax1.y = std::max(vMax1.y,pcMesh->mVertices[i].y);
|
||||
vMax1.z = std::max(vMax1.z,pcMesh->mVertices[i].z);
|
||||
|
||||
aiVector3D vWithNormal = pcMesh->mVertices[i] + pcMesh->mNormals[i];
|
||||
|
||||
vMin0.x = std::min(vMin0.x,vWithNormal.x);
|
||||
vMin0.y = std::min(vMin0.y,vWithNormal.y);
|
||||
vMin0.z = std::min(vMin0.z,vWithNormal.z);
|
||||
|
||||
vMax0.x = std::max(vMax0.x,vWithNormal.x);
|
||||
vMax0.y = std::max(vMax0.y,vWithNormal.y);
|
||||
vMax0.z = std::max(vMax0.z,vWithNormal.z);
|
||||
}
|
||||
|
||||
if (::fabsf((vMax0.x - vMin0.x) * (vMax0.y - vMin0.y) * (vMax0.z - vMin0.z)) <=
|
||||
::fabsf((vMax1.x - vMin1.x) * (vMax1.y - vMin1.y) * (vMax1.z - vMin1.z)))
|
||||
{
|
||||
DefaultLogger::get()->info("The models normals are facing inwards "
|
||||
"(or the model is too planar or concave). Flipping the normal set ...");
|
||||
|
||||
for (unsigned int i = 0; i < pcMesh->mNumVertices;++i)
|
||||
{
|
||||
pcMesh->mNormals[i] *= -1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MDLImporter::InternReadFile_HL2( )
|
||||
{
|
||||
const MDL::Header_HL2* pcHeader = (const MDL::Header_HL2*)this->mBuffer;
|
||||
|
|
|
@ -393,6 +393,7 @@ protected:
|
|||
* some tiny and unsolved problems ... )
|
||||
*/
|
||||
bool ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInfo,
|
||||
MDL::IntGroupData_MDL7& groupData,
|
||||
MDL::IntSharedData_MDL7& shared,
|
||||
const unsigned char* szCurrent,
|
||||
const unsigned char** szCurrentOut);
|
||||
|
@ -428,17 +429,11 @@ protected:
|
|||
MDL::IntGroupData_MDL7& groupData,
|
||||
MDL::IntSplittedGroupData_MDL7& splittedGroupData);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Try to determine whether the normals of the model are flipped
|
||||
* Some MDL7 models seem to have flipped normals (and there is also
|
||||
* an option "flip normals" in MED). However, I don't see a proper
|
||||
* way to read from the file whether all normals are correctly
|
||||
* facing outwards ...
|
||||
*/
|
||||
void FlipNormals(aiMesh* pcMesh);
|
||||
|
||||
protected:
|
||||
|
||||
/** Configuration option: frame to be loaded */
|
||||
unsigned int configFrameID;
|
||||
|
||||
/** Buffer to hold the loaded file */
|
||||
unsigned char* mBuffer;
|
||||
|
||||
|
|
|
@ -565,7 +565,9 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
// sometimes there are MDL7 files which have a monochrome
|
||||
// texture instead of material colors ... posssible they have
|
||||
// been converted to MDL7 from other formats, such as MDL5
|
||||
aiColor4D clrTexture = this->ReplaceTextureWithColor(pcNew);
|
||||
aiColor4D clrTexture;
|
||||
if (pcNew)clrTexture = this->ReplaceTextureWithColor(pcNew);
|
||||
else clrTexture.r = std::numeric_limits<float>::quiet_NaN();
|
||||
|
||||
// check whether a material definition is contained in the skin
|
||||
if (iType & AI_MDL7_SKINTYPE_MATERIAL)
|
||||
|
@ -661,14 +663,20 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
|
||||
aiString szFile;
|
||||
const size_t iLen = strlen((const char*)szCurrent);
|
||||
size_t iLen2 = iLen+1;
|
||||
iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
|
||||
::memcpy(szFile.data,(const char*)szCurrent,iLen2);
|
||||
::memcpy(szFile.data,(const char*)szCurrent,iLen+1);
|
||||
szFile.length = iLen;
|
||||
|
||||
pcMatOut->AddProperty(&szFile,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
|
||||
// store the texture
|
||||
if (!this->pScene->mNumTextures)
|
||||
{
|
||||
this->pScene->mNumTextures = 1;
|
||||
this->pScene->mTextures = new aiTexture*[1];
|
||||
this->pScene->mTextures[0] = pcNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
aiTexture** pc = this->pScene->mTextures;
|
||||
this->pScene->mTextures = new aiTexture*[this->pScene->mNumTextures+1];
|
||||
for (unsigned int i = 0; i < this->pScene->mNumTextures;++i)
|
||||
|
@ -677,7 +685,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
this->pScene->mTextures[this->pScene->mNumTextures] = pcNew;
|
||||
this->pScene->mNumTextures++;
|
||||
delete[] pc;
|
||||
|
||||
}
|
||||
}
|
||||
VALIDATE_FILE_SIZE(szCurrent);
|
||||
*szCurrentOut = szCurrent;
|
||||
|
@ -716,6 +724,9 @@ void MDLImporter::SkipSkinLump_3DGS_MDL7(
|
|||
tex.mWidth = iWidth;
|
||||
this->ParseTextureColorData(szCurrent,iMasked,&iSkip,&tex);
|
||||
|
||||
// FIX: Important, otherwise the destructor will crash
|
||||
tex.pcData = NULL;
|
||||
|
||||
// skip length of texture data
|
||||
szCurrent += iSkip;
|
||||
}
|
||||
|
@ -761,12 +772,13 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
pcSkin->typ,pcSkin->width,pcSkin->height);
|
||||
|
||||
// place the name of the skin in the material
|
||||
const size_t iLen = strlen(pcSkin->texture_name);
|
||||
if (0 != iLen)
|
||||
if (pcSkin->texture_name[0])
|
||||
{
|
||||
// the 0 termination could be there or not - we can't know
|
||||
aiString szFile;
|
||||
memcpy(szFile.data,pcSkin->texture_name,sizeof(pcSkin->texture_name));
|
||||
szFile.length = iLen;
|
||||
::memcpy(szFile.data,pcSkin->texture_name,sizeof(pcSkin->texture_name));
|
||||
szFile.data[sizeof(pcSkin->texture_name)] = '\0';
|
||||
szFile.length = ::strlen(szFile.data);
|
||||
|
||||
pcMatOut->AddProperty(&szFile,AI_MATKEY_NAME);
|
||||
}
|
||||
|
|
|
@ -40,74 +40,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "MaterialSystem.h"
|
||||
#include "StringComparison.h"
|
||||
#include "Hash.h"
|
||||
|
||||
#include "../include/aiMaterial.h"
|
||||
#include "../include/aiAssert.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// hashing function taken from
|
||||
// http://www.azillionmonkeys.com/qed/hash.html
|
||||
// (incremental version of the hashing function)
|
||||
// (stdint.h should have been been included here)
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
// we are using sprintf only on fixed-size buffers, so the
|
||||
// compiler should automatically expand the template sprintf_s<>
|
||||
#if _MSC_VER >= 1400
|
||||
# define sprintf sprintf_s
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t SuperFastHash (const char * data, int len, uint32_t hash = 0) {
|
||||
uint32_t tmp;
|
||||
int rem;
|
||||
|
||||
if (len <= 0 || data == NULL) return 0;
|
||||
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
for (;len > 0; len--) {
|
||||
hash += get16bits (data);
|
||||
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2*sizeof (uint16_t);
|
||||
hash += hash >> 11;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3: hash += get16bits (data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof (uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += get16bits (data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
|
@ -121,7 +66,7 @@ aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
|
|||
{
|
||||
if (NULL != pMat->mProperties[i])
|
||||
{
|
||||
if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey->data, pKey ))
|
||||
if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey ))
|
||||
{
|
||||
*pPropOut = pMat->mProperties[i];
|
||||
return AI_SUCCESS;
|
||||
|
@ -145,14 +90,13 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
|
|||
{
|
||||
if (NULL != pMat->mProperties[i])
|
||||
{
|
||||
if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey->data, pKey ))
|
||||
if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey ))
|
||||
{
|
||||
// data is given in floats, simply copy it
|
||||
if( aiPTI_Float == pMat->mProperties[i]->mType ||
|
||||
aiPTI_Buffer == pMat->mProperties[i]->mType)
|
||||
{
|
||||
unsigned int iWrite = pMat->mProperties[i]->
|
||||
mDataLength / sizeof(float);
|
||||
unsigned int iWrite = pMat->mProperties[i]->mDataLength / sizeof(float);
|
||||
|
||||
if (NULL != pMax)
|
||||
iWrite = *pMax < iWrite ? *pMax : iWrite;
|
||||
|
@ -204,7 +148,7 @@ aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat,
|
|||
{
|
||||
if (NULL != pMat->mProperties[i])
|
||||
{
|
||||
if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey->data, pKey ))
|
||||
if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey ))
|
||||
{
|
||||
// data is given in ints, simply copy it
|
||||
if( aiPTI_Integer == pMat->mProperties[i]->mType ||
|
||||
|
@ -275,12 +219,12 @@ aiReturn aiGetMaterialString(const aiMaterial* pMat,
|
|||
{
|
||||
if (NULL != pMat->mProperties[i])
|
||||
{
|
||||
if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey->data, pKey ))
|
||||
if (0 == ASSIMP_stricmp( pMat->mProperties[i]->mKey.data, pKey ))
|
||||
{
|
||||
if( aiPTI_String == pMat->mProperties[i]->mType)
|
||||
{
|
||||
memcpy (pOut, pMat->mProperties[i]->mData,
|
||||
sizeof(aiString));
|
||||
const aiString* pcSrc = (const aiString*)pMat->mProperties[i]->mData;
|
||||
::memcpy (pOut->data, pcSrc->data, (pOut->length = pcSrc->length)+1);
|
||||
}
|
||||
// wrong type
|
||||
else return AI_FAILURE;
|
||||
|
@ -291,6 +235,29 @@ aiReturn aiGetMaterialString(const aiMaterial* pMat,
|
|||
return AI_FAILURE;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MaterialHelper::MaterialHelper()
|
||||
{
|
||||
// allocate 5 entries by default
|
||||
this->mNumProperties = 0;
|
||||
this->mNumAllocated = 5;
|
||||
this->mProperties = new aiMaterialProperty*[5];
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MaterialHelper::~MaterialHelper()
|
||||
{
|
||||
for (unsigned int i = 0; i < this->mNumProperties;++i)
|
||||
{
|
||||
// be careful ...
|
||||
if(NULL != this->mProperties[i])
|
||||
{
|
||||
delete[] this->mProperties[i]->mData;
|
||||
delete this->mProperties[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t MaterialHelper::ComputeHash()
|
||||
{
|
||||
uint32_t hash = 1503; // magic start value, choosen to be my birthday :-)
|
||||
|
@ -299,9 +266,9 @@ uint32_t MaterialHelper::ComputeHash()
|
|||
aiMaterialProperty* prop;
|
||||
|
||||
// NOTE: We need to exclude the material name from the hash
|
||||
if ((prop = this->mProperties[i]) && 0 != ::strcmp(prop->mKey->data,AI_MATKEY_NAME))
|
||||
if ((prop = this->mProperties[i]) && 0 != ::strcmp(prop->mKey.data,AI_MATKEY_NAME))
|
||||
{
|
||||
hash = SuperFastHash(prop->mKey->data,prop->mKey->length,hash);
|
||||
hash = SuperFastHash(prop->mKey.data,prop->mKey.length,hash);
|
||||
hash = SuperFastHash(prop->mData,prop->mDataLength,hash);
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +283,7 @@ aiReturn MaterialHelper::RemoveProperty (const char* pKey)
|
|||
{
|
||||
if (this->mProperties[i]) // just for safety
|
||||
{
|
||||
if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey->data, pKey ))
|
||||
if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey ))
|
||||
{
|
||||
// delete this entry
|
||||
delete[] this->mProperties[i]->mData;
|
||||
|
@ -352,7 +319,7 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
|
|||
{
|
||||
if (this->mProperties[i])
|
||||
{
|
||||
if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey->data, pKey ))
|
||||
if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey ))
|
||||
{
|
||||
// delete this entry
|
||||
delete[] this->mProperties[i]->mData;
|
||||
|
@ -365,16 +332,15 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
|
|||
aiMaterialProperty* pcNew = new aiMaterialProperty();
|
||||
|
||||
// fill this
|
||||
pcNew->mKey = new aiString();
|
||||
pcNew->mType = pType;
|
||||
|
||||
pcNew->mDataLength = pSizeInBytes;
|
||||
pcNew->mData = new char[pSizeInBytes];
|
||||
memcpy (pcNew->mData,pInput,pSizeInBytes);
|
||||
|
||||
pcNew->mKey->length = strlen(pKey);
|
||||
ai_assert ( MAXLEN > pcNew->mKey->length);
|
||||
strcpy( pcNew->mKey->data, pKey );
|
||||
pcNew->mKey.length = ::strlen(pKey);
|
||||
ai_assert ( MAXLEN > pcNew->mKey.length);
|
||||
::strcpy( pcNew->mKey.data, pKey );
|
||||
|
||||
if (0xFFFFFFFF != iOutIndex)
|
||||
{
|
||||
|
@ -391,7 +357,7 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
|
|||
aiMaterialProperty** ppTemp = new aiMaterialProperty*[this->mNumAllocated];
|
||||
if (NULL == ppTemp)return AI_OUTOFMEMORY;
|
||||
|
||||
memcpy (ppTemp,this->mProperties,iOld * sizeof(void*));
|
||||
::memcpy (ppTemp,this->mProperties,iOld * sizeof(void*));
|
||||
|
||||
delete[] this->mProperties;
|
||||
this->mProperties = ppTemp;
|
||||
|
@ -404,8 +370,10 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
|
|||
aiReturn MaterialHelper::AddProperty (const aiString* pInput,
|
||||
const char* pKey)
|
||||
{
|
||||
// fix ... don't keep the whole string buffer
|
||||
return this->AddBinaryProperty(pInput,
|
||||
sizeof(aiString),pKey,aiPTI_String);
|
||||
pInput->length+1+ (size_t)((uint8_t*)&pInput->data - (uint8_t*)&pInput->length),
|
||||
pKey,aiPTI_String);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
|
||||
|
@ -421,21 +389,41 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
|
|||
aiMaterialProperty** pcOld = pcDest->mProperties;
|
||||
pcDest->mProperties = new aiMaterialProperty*[pcDest->mNumAllocated];
|
||||
|
||||
if (pcOld)
|
||||
if (iOldNum && pcOld)
|
||||
{
|
||||
for (unsigned int i = 0; i < iOldNum;++i)
|
||||
pcDest->mProperties[i] = pcOld[i];
|
||||
|
||||
delete[] pcDest->mProperties;
|
||||
delete[] pcOld;
|
||||
}
|
||||
for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i)
|
||||
{
|
||||
pcDest->mProperties[i]->mKey = new aiString(*pcSrc->mProperties[i]->mKey);
|
||||
pcDest->mProperties[i]->mDataLength = pcSrc->mProperties[i]->mDataLength;
|
||||
pcDest->mProperties[i]->mType = pcSrc->mProperties[i]->mType;
|
||||
pcDest->mProperties[i]->mData = new char[pcDest->mProperties[i]->mDataLength];
|
||||
memcpy(pcDest->mProperties[i]->mData,pcSrc->mProperties[i]->mData,
|
||||
pcDest->mProperties[i]->mDataLength);
|
||||
aiMaterialProperty* propSrc = pcSrc->mProperties[i];
|
||||
|
||||
// search whether we have already a property with this name
|
||||
// (if yes we overwrite the old one)
|
||||
aiMaterialProperty* prop;
|
||||
for (unsigned int q = 0; q < iOldNum;++q)
|
||||
{
|
||||
prop = pcDest->mProperties[q];
|
||||
if (propSrc->mKey.length == prop->mKey.length &&
|
||||
!ASSIMP_stricmp(propSrc->mKey.data,prop->mKey.data))
|
||||
{
|
||||
delete prop;
|
||||
|
||||
// collapse the whole array ...
|
||||
::memmove(&pcDest->mProperties[q],&pcDest->mProperties[q+1],i-q);
|
||||
i--;
|
||||
pcDest->mNumProperties--;
|
||||
}
|
||||
}
|
||||
|
||||
prop = pcDest->mProperties[i] = new aiMaterialProperty();
|
||||
prop->mKey = propSrc->mKey;
|
||||
prop->mDataLength = propSrc->mDataLength;
|
||||
prop->mType = propSrc->mType;
|
||||
prop->mData = new char[propSrc->mDataLength];
|
||||
::memcpy(prop->mData,propSrc->mData,prop->mDataLength);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -545,12 +533,7 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
|
|||
if (iIndex > 100)return AI_FAILURE;
|
||||
|
||||
// get the path to the texture
|
||||
#if _MSC_VER >= 1400
|
||||
if(0 >= sprintf_s(szKey,"%s[%i]",szPathBase,iIndex))DummyAssertFunction();
|
||||
#else
|
||||
if(0 >= sprintf(szKey,"%s[%i]",szPathBase,iIndex))DummyAssertFunction();
|
||||
#endif
|
||||
|
||||
if (AI_SUCCESS != aiGetMaterialString(pcMat,szKey,szOut))
|
||||
{
|
||||
return AI_FAILURE;
|
||||
|
@ -559,11 +542,7 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
|
|||
if (piUVIndex)
|
||||
{
|
||||
int iUV;
|
||||
#if _MSC_VER >= 1400
|
||||
if(0 >= sprintf_s(szKey,"%s[%i]",szUVBase,iIndex))DummyAssertFunction();
|
||||
#else
|
||||
if(0 >= sprintf(szKey,"%s[%i]",szUVBase,iIndex))DummyAssertFunction();
|
||||
#endif
|
||||
if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,&iUV))
|
||||
iUV = 0;
|
||||
|
||||
|
@ -573,11 +552,7 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
|
|||
if (pfBlendFactor)
|
||||
{
|
||||
float fBlend;
|
||||
#if _MSC_VER >= 1400
|
||||
if(0 >= sprintf_s(szKey,"%s[%i]",szBlendBase,iIndex))DummyAssertFunction();
|
||||
#else
|
||||
if(0 >= sprintf(szKey,"%s[%i]",szBlendBase,iIndex))DummyAssertFunction();
|
||||
#endif
|
||||
if (AI_SUCCESS != aiGetMaterialFloat(pcMat,szKey,&fBlend))
|
||||
fBlend = 1.0f;
|
||||
|
||||
|
@ -588,11 +563,7 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
|
|||
if (peTextureOp)
|
||||
{
|
||||
aiTextureOp op;
|
||||
#if _MSC_VER >= 1400
|
||||
if(0 >= sprintf_s(szKey,"%s[%i]",szOpBase,iIndex))DummyAssertFunction();
|
||||
#else
|
||||
if(0 >= sprintf(szKey,"%s[%i]",szOpBase,iIndex))DummyAssertFunction();
|
||||
#endif
|
||||
if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&op))
|
||||
op = aiTextureOp_Multiply;
|
||||
|
||||
|
@ -605,11 +576,7 @@ aiReturn aiGetMaterialTexture(const aiMaterial* pcMat,
|
|||
aiTextureMapMode eMode;
|
||||
for (unsigned int q = 0; q < 3;++q)
|
||||
{
|
||||
#if _MSC_VER >= 1400
|
||||
if(0 >= sprintf_s(szKey,"%s[%i]",aszMapModeBase[q],iIndex))DummyAssertFunction();
|
||||
#else
|
||||
if(0 >= sprintf(szKey,"%s[%i]",aszMapModeBase[q],iIndex))DummyAssertFunction();
|
||||
#endif
|
||||
if (AI_SUCCESS != aiGetMaterialInteger(pcMat,szKey,(int*)&eMode))
|
||||
{
|
||||
eMode = aiTextureMapMode_Wrap;
|
||||
|
|
|
@ -55,8 +55,8 @@ class ASSIMP_API MaterialHelper : public ::aiMaterial
|
|||
{
|
||||
public:
|
||||
|
||||
inline MaterialHelper();
|
||||
inline ~MaterialHelper();
|
||||
MaterialHelper();
|
||||
~MaterialHelper();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add a property with a given key and type info to the material
|
||||
|
@ -125,36 +125,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
inline MaterialHelper::MaterialHelper()
|
||||
{
|
||||
// allocate 5 entries by default
|
||||
this->mNumProperties = 0;
|
||||
this->mNumAllocated = 5;
|
||||
this->mProperties = new aiMaterialProperty*[5];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
inline MaterialHelper::~MaterialHelper()
|
||||
{
|
||||
for (unsigned int i = 0; i < this->mNumProperties;++i)
|
||||
{
|
||||
// be careful ...
|
||||
if(NULL != this->mProperties[i])
|
||||
{
|
||||
delete[] this->mProperties[i]->mKey;
|
||||
delete[] this->mProperties[i]->mData;
|
||||
delete this->mProperties[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
template<class TYPE>
|
||||
|
|
|
@ -122,13 +122,13 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
|
|||
{
|
||||
// generate new names for all modified materials
|
||||
const unsigned int idx = aiMappingTable[p];
|
||||
if (!ppcMaterials[idx])
|
||||
if (ppcMaterials[idx])
|
||||
{
|
||||
aiString sz;
|
||||
sz.length = ::sprintf(sz.data,"aiMaterial #%i",p);
|
||||
ppcMaterials[idx] = pScene->mMaterials[p];
|
||||
((MaterialHelper*)pScene->mMaterials[p])->AddProperty(&sz,AI_MATKEY_NAME);
|
||||
((MaterialHelper*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
|
||||
}
|
||||
else ppcMaterials[idx] = pScene->mMaterials[p];
|
||||
}
|
||||
// update all material indices
|
||||
for (unsigned int p = 0; p < pScene->mNumMeshes;++p)
|
||||
|
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 STL importer class */
|
||||
|
||||
// internal headers
|
||||
#include "STLLoader.h"
|
||||
#include "MaterialSystem.h"
|
||||
#include "ParsingUtils.h"
|
||||
#include "fast_atof.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 headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
STLImporter::STLImporter()
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
STLImporter::~STLImporter()
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool STLImporter::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);
|
||||
|
||||
if (extension.length() < 4)return false;
|
||||
if (extension[0] != '.')return false;
|
||||
|
||||
if (extension[1] != 's' && extension[1] != 'S')return false;
|
||||
if (extension[2] != 't' && extension[2] != 'T')return false;
|
||||
if (extension[3] != 'l' && extension[3] != 'L')return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void STLImporter::InternReadFile(
|
||||
const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
||||
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL)
|
||||
{
|
||||
throw new ImportErrorException( "Failed to open STL file " + pFile + ".");
|
||||
}
|
||||
|
||||
this->fileSize = (unsigned int)file->FileSize();
|
||||
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
// (terminate it with zero)
|
||||
this->mBuffer = new char[fileSize+1];
|
||||
this->pScene = pScene;
|
||||
file->Read( (void*)mBuffer, 1, fileSize);
|
||||
const_cast<char*>(this->mBuffer)[fileSize] = '\0';
|
||||
|
||||
// the default vertex color is white
|
||||
clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = 1.0f;
|
||||
|
||||
// allocate one mesh
|
||||
pScene->mNumMeshes = 1;
|
||||
pScene->mMeshes = new aiMesh*[1];
|
||||
aiMesh* pMesh = pScene->mMeshes[0] = new aiMesh();
|
||||
pMesh->mMaterialIndex = 0;
|
||||
|
||||
// allocate a single node
|
||||
pScene->mRootNode = new aiNode();
|
||||
pScene->mRootNode->mNumMeshes = 1;
|
||||
pScene->mRootNode->mMeshes = new unsigned int[1];
|
||||
pScene->mRootNode->mMeshes[0] = 0;
|
||||
|
||||
bool bMatClr = false;
|
||||
try
|
||||
{
|
||||
// check whether the file starts with 'solid' -
|
||||
// in this case we can simply assume it IS a text file. finished.
|
||||
if (!::strncmp(mBuffer,"solid",5))
|
||||
this->LoadASCIIFile();
|
||||
else bMatClr = this->LoadBinaryFile();
|
||||
|
||||
// now copy faces
|
||||
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
|
||||
for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces;++i)
|
||||
{
|
||||
aiFace& face = pMesh->mFaces[i];
|
||||
face.mIndices = new unsigned int[face.mNumIndices = 3];
|
||||
for (unsigned int o = 0; o < 3;++o,++p)
|
||||
face.mIndices[o] = p;
|
||||
}
|
||||
}
|
||||
catch (ImportErrorException* ex)
|
||||
{
|
||||
delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
// create a single default material - everything white, as
|
||||
// we have vertex colors
|
||||
MaterialHelper* pcMat = new MaterialHelper();
|
||||
aiString s;
|
||||
s.Set(AI_DEFAULT_MATERIAL_NAME);
|
||||
pcMat->AddProperty(&s, AI_MATKEY_NAME);
|
||||
|
||||
aiColor4D clrDiffuse(1.0f,1.0f,1.0f,1.0f);
|
||||
if (bMatClr)clrDiffuse = this->clrColorDefault;
|
||||
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
|
||||
clrDiffuse = aiColor4D(0.05f,0.05f,0.05f,1.0f);
|
||||
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
|
||||
|
||||
pScene->mNumMaterials = 1;
|
||||
pScene->mMaterials = new aiMaterial*[1];
|
||||
pScene->mMaterials[0] = pcMat;
|
||||
|
||||
delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read an ASCII STL file
|
||||
void STLImporter::LoadASCIIFile()
|
||||
{
|
||||
aiMesh* pMesh = pScene->mMeshes[0];
|
||||
|
||||
const char* sz = mBuffer + 5; // skip the "solid"
|
||||
SkipSpaces(&sz);
|
||||
const char* szMe = sz;
|
||||
while (!::IsSpaceOrNewLine(*sz))sz++;
|
||||
unsigned int temp;
|
||||
|
||||
// setup the name of the node
|
||||
if (temp = unsigned int(sz-szMe))
|
||||
{
|
||||
pScene->mRootNode->mName.length = temp;
|
||||
::memcpy(pScene->mRootNode->mName.data,szMe,temp);
|
||||
pScene->mRootNode->mName.data[temp] = '\0';
|
||||
}
|
||||
else pScene->mRootNode->mName.Set("<STL_ASCII>");
|
||||
|
||||
// try to guess how many vertices we could have
|
||||
// assume we'll need 160 bytes for each face
|
||||
pMesh->mNumVertices = ( pMesh->mNumFaces = fileSize / 160 ) * 3;
|
||||
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
||||
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
||||
|
||||
unsigned int curFace = 0, curVertex = 0;
|
||||
while (true)
|
||||
{
|
||||
// go to the next token
|
||||
if(!SkipSpacesAndLineEnd(&sz))
|
||||
{
|
||||
// seems we're finished although there was no end marker
|
||||
DefaultLogger::get()->warn("STL: unexpected EOF. \'endsolid\' keyword was expected");
|
||||
break;
|
||||
}
|
||||
// facet normal -0.13 -0.13 -0.98
|
||||
if (!::strncmp(sz,"facet",5) && ::IsSpaceOrNewLine(*(sz+5)))
|
||||
{
|
||||
if (3 != curVertex)DefaultLogger::get()->warn("STL: A new facet begins but the old is not yet complete");
|
||||
if (pMesh->mNumFaces == curFace)
|
||||
{
|
||||
// need to resize the arrays, our size estimate was wrong
|
||||
unsigned int iNeededSize = unsigned int(sz-mBuffer) / pMesh->mNumFaces;
|
||||
if (iNeededSize <= 160)iNeededSize >>= 1; // prevent endless looping
|
||||
unsigned int add = unsigned int((mBuffer+fileSize)-sz) / iNeededSize;
|
||||
add += add >> 3; // add 12.5% as buffer
|
||||
iNeededSize = (pMesh->mNumFaces + add)*3;
|
||||
aiVector3D* pv = new aiVector3D[iNeededSize];
|
||||
::memcpy(pv,pMesh->mVertices,pMesh->mNumVertices*sizeof(aiVector3D));
|
||||
delete[] pMesh->mVertices;
|
||||
pMesh->mVertices = pv;
|
||||
pv = new aiVector3D[iNeededSize];
|
||||
::memcpy(pv,pMesh->mNormals,pMesh->mNumVertices*sizeof(aiVector3D));
|
||||
delete[] pMesh->mNormals;
|
||||
pMesh->mNormals = pv;
|
||||
|
||||
pMesh->mNumVertices = iNeededSize;
|
||||
pMesh->mNumFaces += add;
|
||||
}
|
||||
aiVector3D* vn = &pMesh->mNormals[curFace++*3];
|
||||
|
||||
sz += 6;
|
||||
curVertex = 0;
|
||||
SkipSpaces(&sz);
|
||||
if (::strncmp(sz,"normal",6))
|
||||
{
|
||||
DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
sz += 7;
|
||||
SkipSpaces(&sz);
|
||||
sz = fast_atof_move(sz, vn->x );
|
||||
SkipSpaces(&sz);
|
||||
sz = fast_atof_move(sz, vn->y );
|
||||
SkipSpaces(&sz);
|
||||
sz = fast_atof_move(sz, vn->z );
|
||||
*(vn+1) = *vn;
|
||||
*(vn+2) = *vn;
|
||||
}
|
||||
}
|
||||
// vertex 1.50000 1.50000 0.00000
|
||||
else if (!::strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6)))
|
||||
{
|
||||
if (3 == curVertex)
|
||||
{
|
||||
DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found");
|
||||
}
|
||||
else
|
||||
{
|
||||
sz += 7;
|
||||
SkipSpaces(&sz);
|
||||
aiVector3D* vn = &pMesh->mVertices[(curFace-1)*3 + curVertex++];
|
||||
sz = fast_atof_move(sz, vn->x );
|
||||
SkipSpaces(&sz);
|
||||
sz = fast_atof_move(sz, vn->y );
|
||||
SkipSpaces(&sz);
|
||||
sz = fast_atof_move(sz, vn->z );
|
||||
}
|
||||
}
|
||||
else if (!::strncmp(sz,"endsolid",8))
|
||||
{
|
||||
// finished!
|
||||
break;
|
||||
}
|
||||
// else skip the whole identifier
|
||||
else while (!::IsSpaceOrNewLine(*sz))++sz;
|
||||
}
|
||||
|
||||
if (!curFace)
|
||||
{
|
||||
pMesh->mNumFaces = 0;
|
||||
throw new ImportErrorException("STL: ASCII file is empty or invalid; no data loaded");
|
||||
}
|
||||
pMesh->mNumFaces = curFace;
|
||||
pMesh->mNumVertices = curFace*3;
|
||||
// we are finished!
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a binary STL file
|
||||
bool STLImporter::LoadBinaryFile()
|
||||
{
|
||||
// skip the first 80 bytes
|
||||
if (fileSize < 84)
|
||||
throw new ImportErrorException("STL: file is too small for the header");
|
||||
|
||||
bool bIsMaterialise = false;
|
||||
|
||||
// search for an occurence of "COLOR=" in the header
|
||||
const char* sz2 = (const char*)mBuffer;
|
||||
const char* const szEnd = sz2+80;
|
||||
while (sz2 < szEnd)
|
||||
{
|
||||
if ('C' == *sz2++ && 'O' == *sz2++ && 'L' == *sz2++ &&
|
||||
'O' == *sz2++ && 'R' == *sz2++ && '=' == *sz2++)
|
||||
{
|
||||
// read the default vertex color for facets
|
||||
bIsMaterialise = true;
|
||||
this->clrColorDefault.r = (*sz2++) / 255.0f;
|
||||
this->clrColorDefault.g = (*sz2++) / 255.0f;
|
||||
this->clrColorDefault.b = (*sz2++) / 255.0f;
|
||||
this->clrColorDefault.a = (*sz2++) / 255.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const unsigned char* sz = (const unsigned char*)mBuffer + 80;
|
||||
|
||||
// now read the number of facets
|
||||
aiMesh* pMesh = pScene->mMeshes[0];
|
||||
pScene->mRootNode->mName.Set("<STL_BINARY>");
|
||||
|
||||
pMesh->mNumFaces = *((uint32_t*)sz);
|
||||
sz += 4;
|
||||
|
||||
if (fileSize < 84 + pMesh->mNumFaces*50)
|
||||
throw new ImportErrorException("STL: file is too small to keep all facets");
|
||||
if (!pMesh->mNumFaces)
|
||||
throw new ImportErrorException("STL: file is empty. There are no facets defined");
|
||||
|
||||
pMesh->mNumVertices = pMesh->mNumFaces*3;
|
||||
|
||||
aiVector3D* vp,*vn;
|
||||
vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
||||
vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
||||
|
||||
for (unsigned int i = 0; i < pMesh->mNumFaces;++i)
|
||||
{
|
||||
*vn = *((aiVector3D*)sz);
|
||||
sz += sizeof(aiVector3D);
|
||||
*(vn+1) = *vn;
|
||||
*(vn+2) = *vn;
|
||||
|
||||
*vp++ = *((aiVector3D*)sz);
|
||||
sz += sizeof(aiVector3D);
|
||||
|
||||
*vp++ = *((aiVector3D*)sz);
|
||||
sz += sizeof(aiVector3D);
|
||||
|
||||
*vp++ = *((aiVector3D*)sz);
|
||||
sz += sizeof(aiVector3D);
|
||||
|
||||
uint16_t color = *((uint16_t*)sz);
|
||||
sz += 2;
|
||||
|
||||
if (color & (1 << 15))
|
||||
{
|
||||
// seems we need to take the color
|
||||
if (!pMesh->mColors[0])
|
||||
{
|
||||
pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
|
||||
for (unsigned int i = 0; i <pMesh->mNumVertices;++i)
|
||||
*pMesh->mColors[0]++ = this->clrColorDefault;
|
||||
pMesh->mColors[0] -= pMesh->mNumVertices;
|
||||
}
|
||||
aiColor4D* clr = &pMesh->mColors[0][pMesh->mNumFaces*3];
|
||||
clr->a = 1.0f;
|
||||
if (bIsMaterialise) // fuck, this is reversed
|
||||
{
|
||||
clr->r = (color & 0x31u) / 31.0f;
|
||||
clr->g = ((color & (0x31u<<5))>>5u) / 31.0f;
|
||||
clr->b = ((color & (0x31u<<10))>>10u) / 31.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
clr->b = (color & 0x31u) / 31.0f;
|
||||
clr->g = ((color & (0x31u<<5))>>5u) / 31.0f;
|
||||
clr->r = ((color & (0x31u<<10))>>10u) / 31.0f;
|
||||
}
|
||||
// assign the color to all vertices of the face
|
||||
*(clr+1) = *clr;
|
||||
*(clr+2) = *clr;
|
||||
}
|
||||
}
|
||||
if (bIsMaterialise && !pMesh->mColors[0])
|
||||
{
|
||||
// use the color was diffuse material color
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
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 STL importer class. */
|
||||
#ifndef AI_STLLOADER_H_INCLUDED
|
||||
#define AI_STLLOADER_H_INCLUDED
|
||||
|
||||
#include "BaseImporter.h"
|
||||
#include "../include/aiTypes.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Clas to load STL files
|
||||
*/
|
||||
class STLImporter : public BaseImporter
|
||||
{
|
||||
friend class Importer;
|
||||
|
||||
protected:
|
||||
/** Constructor to be privately used by Importer */
|
||||
STLImporter();
|
||||
|
||||
/** Destructor, private as well */
|
||||
~STLImporter();
|
||||
|
||||
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("*.stl");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Loads a binary .stl file
|
||||
* @return true if the default vertex color should be used as material color
|
||||
*/
|
||||
bool LoadBinaryFile();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Loads a ASCII text .stl file
|
||||
*/
|
||||
void LoadASCIIFile();
|
||||
|
||||
protected:
|
||||
|
||||
/** Buffer to hold the loaded file */
|
||||
const char* mBuffer;
|
||||
|
||||
/** Size of the file, in bytes */
|
||||
unsigned int fileSize;
|
||||
|
||||
/** Output scene */
|
||||
aiScene* pScene;
|
||||
|
||||
/** Default vertex color */
|
||||
aiColor4D clrColorDefault;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_3DSIMPORTER_H_IN
|
|
@ -265,7 +265,7 @@ void SplitLargeMeshesProcess_Triangle::SplitMesh(
|
|||
aiBone* pc = new aiBone();
|
||||
pcMesh->mBones[pcMesh->mNumBones++] = pc;
|
||||
pc->mName = aiString(bone->mName);
|
||||
pc->mNumWeights = avTempWeights.size();
|
||||
pc->mNumWeights = (unsigned int)avTempWeights.size();
|
||||
pc->mOffsetMatrix = bone->mOffsetMatrix;
|
||||
|
||||
// no need to reallocate the array for the last submesh.
|
||||
|
@ -615,7 +615,7 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh(
|
|||
*ppCurrent++ = pcOut = new aiBone();
|
||||
pcOut->mName = aiString(pcOldBone->mName);
|
||||
pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix;
|
||||
pcOut->mNumWeights = pcWeightList->size();
|
||||
pcOut->mNumWeights = (unsigned int)pcWeightList->size();
|
||||
pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights];
|
||||
|
||||
// copy the vertex weights
|
||||
|
|
|
@ -108,6 +108,7 @@ void ValidateDSProcess::ReportError(const char* msg,...)
|
|||
throw new ImportErrorException("Idiot ... learn coding!");
|
||||
}
|
||||
va_end(args);
|
||||
ai_assert(false);
|
||||
throw new ImportErrorException("Validation failed: " + std::string(szBuffer,iLen));
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -357,6 +358,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
|
|||
{
|
||||
if (!pMesh->mBones[i])
|
||||
{
|
||||
delete[] afSum;
|
||||
this->ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)",
|
||||
i,pMesh->mNumBones);
|
||||
}
|
||||
|
@ -366,6 +368,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
|
|||
{
|
||||
if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName)
|
||||
{
|
||||
delete[] afSum;
|
||||
this->ReportError("aiMesh::mBones[%i] has the same name as "
|
||||
"aiMesh::mBones[%i]",i,a);
|
||||
}
|
||||
|
@ -376,9 +379,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
|
|||
{
|
||||
if (afSum[i] && (afSum[i] <= 0.995 || afSum[i] >= 1.005))
|
||||
{
|
||||
delete[] afSum;
|
||||
this->ReportError("aiMesh::mVertices[%i]: The sum of all bone "
|
||||
"weights isn't 1.0f (sum is %f)",i,afSum[i]);
|
||||
this->ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]);
|
||||
}
|
||||
}
|
||||
delete[] afSum;
|
||||
|
@ -457,9 +458,9 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
|
|||
for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
|
||||
{
|
||||
aiMaterialProperty* prop = pMaterial->mProperties[i];
|
||||
if (0 == ASSIMP_strincmp( prop->mKey->data, szBaseBuf, iLen ))
|
||||
if (0 == ASSIMP_strincmp( prop->mKey.data, szBaseBuf, iLen ))
|
||||
{
|
||||
const char* sz = &prop->mKey->data[iLen];
|
||||
const char* sz = &prop->mKey.data[iLen];
|
||||
if (*sz)
|
||||
{
|
||||
++sz;
|
||||
|
@ -488,12 +489,12 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
|
|||
for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
|
||||
{
|
||||
aiMaterialProperty* prop = pMaterial->mProperties[i];
|
||||
if (0 == ASSIMP_strincmp( prop->mKey->data, szBaseBuf, iLen ))
|
||||
if (0 == ASSIMP_strincmp( prop->mKey.data, szBaseBuf, iLen ))
|
||||
{
|
||||
if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength)
|
||||
this->ReportError("Material property %s is expected to be an integer",prop->mKey);
|
||||
|
||||
const char* sz = &prop->mKey->data[iLen];
|
||||
const char* sz = &prop->mKey.data[iLen];
|
||||
if (*sz)
|
||||
{
|
||||
++sz;
|
||||
|
@ -546,7 +547,8 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial)
|
|||
// check all predefined types
|
||||
if (aiPTI_String == prop->mType)
|
||||
{
|
||||
if (prop->mDataLength < sizeof(aiString))
|
||||
// FIX: strings are now stored in a less expensive way ...
|
||||
if (prop->mDataLength < sizeof(size_t) + ((const aiString*)prop->mData)->length + 1)
|
||||
{
|
||||
this->ReportError("aiMaterial::mProperties[%i].mDataLength is "
|
||||
"too small to contain a string (%i, needed: %i)",
|
||||
|
|
|
@ -12,7 +12,7 @@ void Assimp::aiAssert (bool expression, const std::string &message, unsigned int
|
|||
{
|
||||
if (!expression)
|
||||
{
|
||||
std::cerr << "File :" << file << ", line " << uiLine << " : " << message << std::endl;
|
||||
std::cout << "File :" << file << ", line " << uiLine << " : " << message << std::endl;
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef __GNUC__
|
||||
|
|
|
@ -48,6 +48,25 @@ inline unsigned int strtol10( const char* in, const char** out=0)
|
|||
return value;
|
||||
}
|
||||
|
||||
|
||||
// specal version of the function, providing higher accuracy
|
||||
inline uint64_t strtol10_64( const char* in, const char** out=0)
|
||||
{
|
||||
uint64_t value = 0;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( *in < '0' || *in > '9' )
|
||||
break;
|
||||
|
||||
value = ( value * 10 ) + ( *in - '0' );
|
||||
++in;
|
||||
}
|
||||
if (out)
|
||||
*out = in;
|
||||
return value;
|
||||
}
|
||||
|
||||
//! Provides a fast function for converting a string into a float,
|
||||
//! about 6 times faster than atof in win32.
|
||||
// If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
|
||||
|
@ -64,17 +83,24 @@ inline const char* fast_atof_move( const char* c, float& out)
|
|||
}
|
||||
|
||||
//f = (float)strtol(c, &t, 10);
|
||||
f = (float) strtol10 ( c, &c );
|
||||
f = (float) strtol10_64 ( c, &c );
|
||||
|
||||
if (*c == '.')
|
||||
{
|
||||
++c;
|
||||
|
||||
// NOTE: The original implementation is highly unaccurate here
|
||||
// The precision of a single IEEE 754 float is not high enough
|
||||
// everything behind the 6th digit tends to be more inaccurate
|
||||
// than it would need to be.
|
||||
// Casting to double seems to solve the problem.
|
||||
// strtol_64 is used to prevent integer overflow.
|
||||
|
||||
//float pl = (float)strtol(c, &t, 10);
|
||||
float pl = (float) strtol10 ( c, &t );
|
||||
double pl = (double) strtol10_64 ( c, &t );
|
||||
pl *= fast_atof_table[t-c];
|
||||
|
||||
f += pl;
|
||||
f += (float)pl;
|
||||
|
||||
c = t;
|
||||
|
||||
|
|
|
@ -94,4 +94,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
# define AI_DEBUG_INVALIDATE_PTR(ptr) ptr = 0;
|
||||
#else
|
||||
# define AI_DEBUG_INVALIDATE_PTR(ptr)
|
||||
#endif
|
||||
|
||||
#endif // !! AI_DEFINES_H_INC
|
||||
|
|
|
@ -213,7 +213,7 @@ struct aiMaterialProperty
|
|||
*
|
||||
* Keys are case insensitive.
|
||||
*/
|
||||
C_STRUCT aiString* mKey;
|
||||
C_STRUCT aiString mKey;
|
||||
|
||||
/** Size of the buffer mData is pointing to, in bytes
|
||||
* This value may not be 0.
|
||||
|
|
|
@ -66,6 +66,9 @@ struct aiQuaternion
|
|||
/** Construct from an axis angle pair */
|
||||
aiQuaternion( aiVector3D axis, float angle);
|
||||
|
||||
/** Construct from a normalized quaternion stored in a vec3 */
|
||||
aiQuaternion( aiVector3D normalized);
|
||||
|
||||
/** Returns a matrix representation of the quaternion */
|
||||
aiMatrix3x3 GetMatrix() const;
|
||||
|
||||
|
@ -170,7 +173,22 @@ inline aiQuaternion::aiQuaternion( aiVector3D axis, float angle)
|
|||
z = axis.z * sin_a;
|
||||
w = cos_a;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
// Construction from am existing, normalized quaternion
|
||||
inline aiQuaternion::aiQuaternion( aiVector3D normalized)
|
||||
{
|
||||
x = normalized.x;
|
||||
y = normalized.y;
|
||||
z = normalized.z;
|
||||
|
||||
float t = 1.0f - (normalized.x * normalized.x) -
|
||||
(normalized.y * normalized.y) - (normalized.z * normalized.z);
|
||||
|
||||
if (t < 0.0f)
|
||||
w = 0.0f;
|
||||
else w = sqrt (t);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
solid testTriangle
|
||||
facet normal 0.0 0.0 1.0
|
||||
outer loop
|
||||
vertex 1.0 1.0 0.0
|
||||
vertex -1.0 1.0 0.0
|
||||
vertex 0.0 -1.0 0.0
|
||||
endloop
|
||||
endfacet
|
||||
endsolid
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
#include "utGenNormals.h"
|
||||
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (GenNormalsTest);
|
||||
|
||||
void GenNormalsTest :: setUp (void)
|
||||
{
|
||||
this->piProcess = new GenVertexNormalsProcess();
|
||||
this->pcMesh = new aiMesh();
|
||||
pcMesh->mNumFaces = 1;
|
||||
pcMesh->mFaces = new aiFace[1];
|
||||
pcMesh->mFaces[0].mIndices = new unsigned int[pcMesh->mFaces[0].mNumIndices = 3];
|
||||
pcMesh->mFaces[0].mIndices[0] = 0;
|
||||
pcMesh->mFaces[0].mIndices[1] = 1;
|
||||
pcMesh->mFaces[0].mIndices[2] = 1;
|
||||
pcMesh->mNumVertices = 3;
|
||||
pcMesh->mVertices = new aiVector3D[3];
|
||||
pcMesh->mVertices[0] = aiVector3D(0.0f,1.0f,6.0f);
|
||||
pcMesh->mVertices[1] = aiVector3D(2.0f,3.0f,1.0f);
|
||||
pcMesh->mVertices[2] = aiVector3D(3.0f,2.0f,4.0f);
|
||||
}
|
||||
|
||||
void GenNormalsTest :: tearDown (void)
|
||||
{
|
||||
delete this->pcMesh;
|
||||
delete this->piProcess;
|
||||
}
|
||||
|
||||
void GenNormalsTest :: testSimpleTriangle (void)
|
||||
{
|
||||
this->piProcess->GenMeshVertexNormals(pcMesh);
|
||||
CPPUNIT_ASSERT(0 != pcMesh->mNormals);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef TESTNORMALS_H
|
||||
#define TESTNORMALS_H
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include <aiTypes.h>
|
||||
#include <aiMesh.h>
|
||||
#include <aiScene.h>
|
||||
#include <GenVertexNormalsProcess.h>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace Assimp;
|
||||
|
||||
class GenNormalsTest : public CPPUNIT_NS :: TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (GenNormalsTest);
|
||||
CPPUNIT_TEST (testSimpleTriangle);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void setUp (void);
|
||||
void tearDown (void);
|
||||
|
||||
protected:
|
||||
|
||||
void testSimpleTriangle (void);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
aiMesh* pcMesh;
|
||||
GenVertexNormalsProcess* piProcess;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,82 @@
|
|||
|
||||
#include "utMaterialSystem.h"
|
||||
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (MaterialSystemTest);
|
||||
|
||||
void MaterialSystemTest :: setUp (void)
|
||||
{
|
||||
this->pcMat = new MaterialHelper();
|
||||
}
|
||||
|
||||
void MaterialSystemTest :: tearDown (void)
|
||||
{
|
||||
delete this->pcMat;
|
||||
}
|
||||
|
||||
|
||||
void MaterialSystemTest :: testFloatProperty (void)
|
||||
{
|
||||
float pf = 150392.63f;
|
||||
this->pcMat->AddProperty(&pf,1,"testKey1");
|
||||
pf = 0.0f;
|
||||
|
||||
CPPUNIT_ASSERT(AI_SUCCESS == pcMat->Get("testKey1",pf));
|
||||
CPPUNIT_ASSERT(pf == 150392.63f);
|
||||
}
|
||||
|
||||
void MaterialSystemTest :: testFloatArrayProperty (void)
|
||||
{
|
||||
float pf[] = {0.0f,1.0f,2.0f,3.0f};
|
||||
unsigned int pMax = sizeof(pf) / sizeof(float);
|
||||
this->pcMat->AddProperty(&pf,pMax,"testKey2");
|
||||
pf[0] = pf[1] = pf[2] = pf[3] = 12.0f;
|
||||
|
||||
CPPUNIT_ASSERT(AI_SUCCESS == pcMat->Get("testKey2",pf,&pMax));
|
||||
CPPUNIT_ASSERT(pMax == sizeof(pf) / sizeof(float));
|
||||
CPPUNIT_ASSERT(!pf[0] && 1.0f == pf[1] && 2.0f == pf[2] && 3.0f == pf[3] );
|
||||
}
|
||||
|
||||
void MaterialSystemTest :: testIntProperty (void)
|
||||
{
|
||||
int pf = 15039263;
|
||||
this->pcMat->AddProperty(&pf,1,"testKey3");
|
||||
pf = 12;
|
||||
|
||||
CPPUNIT_ASSERT(AI_SUCCESS == pcMat->Get("testKey3",pf));
|
||||
CPPUNIT_ASSERT(pf == 15039263);
|
||||
}
|
||||
|
||||
void MaterialSystemTest :: testIntArrayProperty (void)
|
||||
{
|
||||
int pf[] = {0,1,2,3};
|
||||
unsigned int pMax = sizeof(pf) / sizeof(int);
|
||||
this->pcMat->AddProperty(&pf,pMax,"testKey4");
|
||||
pf[0] = pf[1] = pf[2] = pf[3] = 12;
|
||||
|
||||
CPPUNIT_ASSERT(AI_SUCCESS == pcMat->Get("testKey4",pf,&pMax));
|
||||
CPPUNIT_ASSERT(pMax == sizeof(pf) / sizeof(int));
|
||||
CPPUNIT_ASSERT(!pf[0] && 1 == pf[1] && 2 == pf[2] && 3 == pf[3] );
|
||||
}
|
||||
|
||||
void MaterialSystemTest :: testColorProperty (void)
|
||||
{
|
||||
aiColor4D clr;
|
||||
clr.r = 2.0f;clr.g = 3.0f;clr.b = 4.0f;clr.a = 5.0f;
|
||||
this->pcMat->AddProperty(&clr,1,"testKey5");
|
||||
clr.b = 1.0f;
|
||||
clr.a = clr.g = clr.r = 0.0f;
|
||||
|
||||
CPPUNIT_ASSERT(AI_SUCCESS == pcMat->Get("testKey5",clr));
|
||||
CPPUNIT_ASSERT(clr.r == 2.0f && clr.g == 3.0f && clr.b == 4.0f && clr.a == 5.0f);
|
||||
}
|
||||
|
||||
void MaterialSystemTest :: testStringProperty (void)
|
||||
{
|
||||
aiString s;
|
||||
s.Set("Hello, this is a small test");
|
||||
this->pcMat->AddProperty(&s,"testKey6");
|
||||
s.Set("358358");
|
||||
CPPUNIT_ASSERT(AI_SUCCESS == pcMat->Get("testKey6",s));
|
||||
CPPUNIT_ASSERT(!::strcmp(s.data,"Hello, this is a small test"));
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef TESTMATERIALS_H
|
||||
#define TESTMATERIALS_H
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include <aiTypes.h>
|
||||
#include <aiMesh.h>
|
||||
#include <aiScene.h>
|
||||
#include <MaterialSystem.h>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace Assimp;
|
||||
|
||||
class MaterialSystemTest : public CPPUNIT_NS :: TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (MaterialSystemTest);
|
||||
CPPUNIT_TEST (testFloatProperty);
|
||||
CPPUNIT_TEST (testFloatArrayProperty);
|
||||
CPPUNIT_TEST (testIntProperty);
|
||||
CPPUNIT_TEST (testIntArrayProperty);
|
||||
CPPUNIT_TEST (testColorProperty);
|
||||
CPPUNIT_TEST (testStringProperty);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void setUp (void);
|
||||
void tearDown (void);
|
||||
|
||||
protected:
|
||||
|
||||
void testFloatProperty (void);
|
||||
void testFloatArrayProperty (void);
|
||||
void testIntProperty (void);
|
||||
void testIntArrayProperty (void);
|
||||
void testColorProperty (void);
|
||||
void testStringProperty (void);
|
||||
|
||||
private:
|
||||
|
||||
MaterialHelper* pcMat;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,101 @@
|
|||
#include "utRemoveRedundantMaterials.h"
|
||||
#include "aiPostProcess.h"
|
||||
#include <math.h>
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (RemoveRedundantMatsTest);
|
||||
|
||||
|
||||
|
||||
aiMaterial* getUniqueMaterial1()
|
||||
{
|
||||
// setup an unique name for each material - this shouldn't care
|
||||
aiString mTemp;
|
||||
mTemp.Set("UniqueMat1");
|
||||
|
||||
MaterialHelper* pcMat = new MaterialHelper();
|
||||
pcMat->AddProperty(&mTemp,AI_MATKEY_NAME);
|
||||
float f = 2.0f;
|
||||
pcMat->AddProperty<float>(&f, 1, AI_MATKEY_BUMPSCALING);
|
||||
pcMat->AddProperty<float>(&f, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||
return pcMat;
|
||||
}
|
||||
|
||||
aiMaterial* getUniqueMaterial2()
|
||||
{
|
||||
// setup an unique name for each material - this shouldn't care
|
||||
aiString mTemp;
|
||||
mTemp.Set("UniqueMat2");
|
||||
|
||||
MaterialHelper* pcMat = new MaterialHelper();
|
||||
pcMat->AddProperty(&mTemp,AI_MATKEY_NAME);
|
||||
float f = 4.0f;int i = 1;
|
||||
pcMat->AddProperty<float>(&f, 1, AI_MATKEY_BUMPSCALING);
|
||||
pcMat->AddProperty<int>(&i, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||
return pcMat;
|
||||
}
|
||||
|
||||
aiMaterial* getUniqueMaterial3()
|
||||
{
|
||||
// setup an unique name for each material - this shouldn't care
|
||||
aiString mTemp;
|
||||
mTemp.Set("UniqueMat3");
|
||||
|
||||
MaterialHelper* pcMat = new MaterialHelper();
|
||||
pcMat->AddProperty(&mTemp,AI_MATKEY_NAME);
|
||||
return pcMat;
|
||||
}
|
||||
|
||||
void RemoveRedundantMatsTest :: setUp (void)
|
||||
{
|
||||
// construct the process
|
||||
this->piProcess = new RemoveRedundantMatsProcess();
|
||||
|
||||
// create a scene with 5 materials (2 is a duplicate of 0, 3 of 1)
|
||||
this->pcScene1 = new aiScene();
|
||||
this->pcScene1->mNumMaterials = 5;
|
||||
this->pcScene1->mMaterials = new aiMaterial*[5];
|
||||
|
||||
this->pcScene1->mMaterials[0] = getUniqueMaterial1();
|
||||
this->pcScene1->mMaterials[1] = getUniqueMaterial2();
|
||||
this->pcScene1->mMaterials[4] = getUniqueMaterial3();
|
||||
|
||||
// setup an unique name for each material - this shouldn't care
|
||||
aiString mTemp;
|
||||
mTemp.length = 1;
|
||||
mTemp.data[0] = 48;
|
||||
mTemp.data[1] = 0;
|
||||
|
||||
MaterialHelper* pcMat;
|
||||
this->pcScene1->mMaterials[2] = pcMat = new MaterialHelper();
|
||||
MaterialHelper::CopyPropertyList(pcMat,(const MaterialHelper*)this->pcScene1->mMaterials[0]);
|
||||
pcMat->AddProperty(&mTemp,AI_MATKEY_NAME);
|
||||
mTemp.data[0]++;
|
||||
|
||||
this->pcScene1->mMaterials[3] = pcMat = new MaterialHelper();
|
||||
MaterialHelper::CopyPropertyList(pcMat,(const MaterialHelper*)this->pcScene1->mMaterials[1]);
|
||||
pcMat->AddProperty(&mTemp,AI_MATKEY_NAME);
|
||||
mTemp.data[0]++;
|
||||
}
|
||||
|
||||
void RemoveRedundantMatsTest :: tearDown (void)
|
||||
{
|
||||
delete this->piProcess;
|
||||
delete this->pcScene1;
|
||||
}
|
||||
|
||||
void RemoveRedundantMatsTest :: testRedundantMaterials (void)
|
||||
{
|
||||
this->piProcess->Execute(this->pcScene1);
|
||||
CPPUNIT_ASSERT_EQUAL(this->pcScene1->mNumMaterials,3u);
|
||||
CPPUNIT_ASSERT(0 != this->pcScene1->mMaterials &&
|
||||
0 != this->pcScene1->mMaterials[0] &&
|
||||
0 != this->pcScene1->mMaterials[1] &&
|
||||
0 != this->pcScene1->mMaterials[2]);
|
||||
|
||||
aiString sName;
|
||||
CPPUNIT_ASSERT(AI_SUCCESS == aiGetMaterialString(this->pcScene1->mMaterials[2],
|
||||
AI_MATKEY_NAME,&sName));
|
||||
|
||||
CPPUNIT_ASSERT(!::strcmp( sName.data, "UniqueMat3" ));
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef TESTRRM_H
|
||||
#define TESTRRM_H
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include <aiTypes.h>
|
||||
#include <aiMesh.h>
|
||||
#include <aiScene.h>
|
||||
#include <RemoveRedundantMaterials.h>
|
||||
#include <MaterialSystem.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace Assimp;
|
||||
|
||||
class RemoveRedundantMatsTest : public CPPUNIT_NS :: TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (RemoveRedundantMatsTest);
|
||||
CPPUNIT_TEST (testRedundantMaterials);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void setUp (void);
|
||||
void tearDown (void);
|
||||
|
||||
protected:
|
||||
|
||||
void testRedundantMaterials (void);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
RemoveRedundantMatsProcess* piProcess;
|
||||
|
||||
aiScene* pcScene1;
|
||||
aiScene* pcScene2;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -475,7 +475,7 @@ int CDisplay::AddTextureToDisplayList(unsigned int iType,
|
|||
|
||||
// find out whether this is the default texture or not
|
||||
|
||||
if (piTexture)
|
||||
if (piTexture && *piTexture)
|
||||
{
|
||||
// {9785DA94-1D96-426b-B3CB-BADC36347F5E}
|
||||
static const GUID guidPrivateData =
|
||||
|
|
|
@ -683,10 +683,6 @@
|
|||
RelativePath="..\..\test\unit\utGenNormals.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utGenSmoothNormals.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utImproveCacheLocality.cpp"
|
||||
>
|
||||
|
@ -711,6 +707,10 @@
|
|||
RelativePath="..\..\test\unit\utRemoveComments.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utRemoveRedundantMaterials.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utSplitLargeMeshes.cpp"
|
||||
>
|
||||
|
@ -729,14 +729,30 @@
|
|||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utGenNormals.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utLimitBoneWeights.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utMaterialSystem.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utPretransformVertices.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utRemoveComments.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utRemoveRedundantMaterials.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\test\unit\utSplitLargeMeshes.h"
|
||||
>
|
||||
|
|
|
@ -730,6 +730,10 @@
|
|||
RelativePath="..\..\code\GenVertexNormalsProcess.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\Hash.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\ImproveCacheLocality.h"
|
||||
>
|
||||
|
@ -799,7 +803,7 @@
|
|||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="ObjLoader"
|
||||
Name="Obj"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\ObjFileData.h"
|
||||
|
@ -823,7 +827,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="3DSLoader"
|
||||
Name="3DS"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\3DSHelper.h"
|
||||
|
@ -839,7 +843,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MD3Loader"
|
||||
Name="MD3"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MD3FileData.h"
|
||||
|
@ -851,7 +855,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MD2Loader"
|
||||
Name="MD2"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MD2FileData.h"
|
||||
|
@ -867,7 +871,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MD4Loader"
|
||||
Name="MD4"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MD4FileData.h"
|
||||
|
@ -879,7 +883,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="XLoader"
|
||||
Name="X"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\XFileHelper.h"
|
||||
|
@ -895,7 +899,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="PlyLoader"
|
||||
Name="Ply"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\PlyLoader.h"
|
||||
|
@ -907,15 +911,19 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MD5Loader"
|
||||
Name="MD5"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MD5Loader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\MD5Parser.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MDLLoader"
|
||||
Name="MDL"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\HalfLifeFileData.h"
|
||||
|
@ -935,7 +943,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="ASELoader"
|
||||
Name="ASE"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\ASELoader.h"
|
||||
|
@ -1019,13 +1027,21 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="SMDLoader"
|
||||
Name="SMD"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\SMDLoader.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="STL"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\STLLoader.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="sources"
|
||||
|
@ -1127,7 +1143,7 @@
|
|||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="ObjLoader"
|
||||
Name="Obj"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\ObjFileImporter.cpp"
|
||||
|
@ -1143,7 +1159,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="3DSLoader"
|
||||
Name="3DS"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\3DSConverter.cpp"
|
||||
|
@ -1163,7 +1179,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MD3Loader"
|
||||
Name="MD3"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MD3Loader.cpp"
|
||||
|
@ -1171,7 +1187,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MD2Loader"
|
||||
Name="MD2"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MD2Loader.cpp"
|
||||
|
@ -1179,7 +1195,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MD4Loader"
|
||||
Name="MD4"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MD4Loader.cpp"
|
||||
|
@ -1187,7 +1203,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="XLoader"
|
||||
Name="X"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\XFileImporter.cpp"
|
||||
|
@ -1199,7 +1215,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="PlyLoader"
|
||||
Name="Ply"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\PlyLoader.cpp"
|
||||
|
@ -1211,7 +1227,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MDLLoader.cpp"
|
||||
Name="MDL"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MDLLoader.cpp"
|
||||
|
@ -1223,7 +1239,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="ASELoader"
|
||||
Name="ASE"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\ASELoader.cpp"
|
||||
|
@ -1267,7 +1283,7 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="HMPLoader"
|
||||
Name="HMP"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\HMPLoader.cpp"
|
||||
|
@ -1275,13 +1291,33 @@
|
|||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="SMDLoader"
|
||||
Name="SMD"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\SMDLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="MD5"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\MD5Loader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\MD5Parser.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="STL"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\STLLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="doc"
|
||||
|
|
Loading…
Reference in New Issue