Added first working version of a MDC loader; no further features like compressed frames tested at the moment. Added config options for keyframe loading, this has been tested with MDL7 only (atm). Some refactoring, a few files are much cleaner and smaller now. RemoveRedundantMats step does now remove unreferenced materials.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@103 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2008-08-09 22:39:57 +00:00
parent 5ef187c1d0
commit 6f49c4518c
33 changed files with 1723 additions and 835 deletions

View File

@ -59,6 +59,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
#ifdef _MSC_VER
# define sprintf sprintf_s
#endif
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ReplaceDefaultMaterial() void Dot3DSImporter::ReplaceDefaultMaterial()
@ -113,8 +116,7 @@ void Dot3DSImporter::ReplaceDefaultMaterial()
{ {
(*a) = iIndex; (*a) = iIndex;
++iCnt; ++iCnt;
DefaultLogger::get()->warn("Material index overflow in 3DS file. Assigning " DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
"default material ...");
} }
} }
} }
@ -157,58 +159,36 @@ void Dot3DSImporter::CheckIndices(Dot3DS::Mesh* sMesh)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh) void Dot3DSImporter::MakeUnique(Dot3DS::Mesh* sMesh)
{ {
std::vector<aiVector3D> vNew;
vNew.resize(sMesh->mFaces.size() * 3);
std::vector<aiVector2D> vNew2;
// TODO: Remove this step. By maintaining a small LUT it
// would be possible to do this directly in the parsing step
unsigned int iBase = 0; unsigned int iBase = 0;
if (0 != sMesh->mTexCoords.size()) std::vector<aiVector3D> vNew;
std::vector<aiVector2D> vNew2;
vNew.resize(sMesh->mFaces.size() * 3);
if (sMesh->mTexCoords.size())vNew2.resize(sMesh->mFaces.size() * 3);
for (unsigned int i = 0; i < sMesh->mFaces.size();++i)
{ {
vNew2.resize(sMesh->mFaces.size() * 3); uint32_t iTemp1,iTemp2;
for (unsigned int i = 0; i < sMesh->mFaces.size();++i)
// positions
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]];
iTemp1 = iBase++;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]];
iTemp2 = iBase++;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]];
// texture coordinates
if (sMesh->mTexCoords.size())
{ {
uint32_t iTemp1,iTemp2; vNew2[iTemp1] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[2]];
vNew2[iTemp2] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[1]];
// position and texture coordinates vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[0]];
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]];
vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[2]];
iTemp1 = iBase++;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]];
vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[1]];
iTemp2 = iBase++;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]];
vNew2[iBase] = sMesh->mTexCoords[sMesh->mFaces[i].mIndices[0]];
sMesh->mFaces[i].mIndices[2] = iBase++;
sMesh->mFaces[i].mIndices[0] = iTemp1;
sMesh->mFaces[i].mIndices[1] = iTemp2;
} }
}
else
{
for (unsigned int i = 0; i < sMesh->mFaces.size();++i)
{
uint32_t iTemp1,iTemp2;
// position only sMesh->mFaces[i].mIndices[2] = iBase++;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[2]]; sMesh->mFaces[i].mIndices[0] = iTemp1;
iTemp1 = iBase++; sMesh->mFaces[i].mIndices[1] = iTemp2;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[1]];
iTemp2 = iBase++;
vNew[iBase] = sMesh->mPositions[sMesh->mFaces[i].mIndices[0]];
sMesh->mFaces[i].mIndices[2] = iBase++;
sMesh->mFaces[i].mIndices[0] = iTemp1;
sMesh->mFaces[i].mIndices[1] = iTemp2;
}
} }
sMesh->mPositions = vNew; sMesh->mPositions = vNew;
sMesh->mTexCoords = vNew2; sMesh->mTexCoords = vNew2;
@ -400,7 +380,7 @@ void Dot3DSImporter::ConvertMaterial(Dot3DS::Material& oldMat,
} }
// store the name of the material itself, too // store the name of the material itself, too
if( oldMat.mName.length() > 0) if( oldMat.mName.length())
{ {
aiString tex; aiString tex;
tex.Set( oldMat.mName); tex.Set( oldMat.mName);
@ -430,14 +410,19 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
a != (*i).mFaceMaterials.end();++a,++iNum) a != (*i).mFaceMaterials.end();++a,++iNum)
{ {
// check range // check range
// FIX: shouldn't be necessary anymore, has been moved to ReplaceDefaultMaterial()
#if 0
if ((*a) >= this->mScene->mMaterials.size()) if ((*a) >= this->mScene->mMaterials.size())
{ {
DefaultLogger::get()->error("3DS face material index is out of range"); DefaultLogger::get()->error("3DS face material index is out of range");
// use the last material instead // use the last material instead
// TODO: assign the default material index
aiSplit[this->mScene->mMaterials.size()-1].push_back(iNum); aiSplit[this->mScene->mMaterials.size()-1].push_back(iNum);
} }
else aiSplit[*a].push_back(iNum); else
#endif
aiSplit[*a].push_back(iNum);
} }
// now generate submeshes // now generate submeshes
bool bFirst = true; bool bFirst = true;
@ -455,14 +440,14 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
avOutMeshes.push_back(p_pcOut); avOutMeshes.push_back(p_pcOut);
// convert vertices // convert vertices
p_pcOut->mNumVertices = (unsigned int)aiSplit[p].size()*3;
p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
p_pcOut->mNumVertices = p_pcOut->mNumFaces*3;
// allocate enough storage for faces // allocate enough storage for faces
p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces]; p_pcOut->mFaces = new aiFace[p_pcOut->mNumFaces];
iFaceCnt += p_pcOut->mNumFaces; iFaceCnt += p_pcOut->mNumFaces;
if (p_pcOut->mNumVertices != 0) if (p_pcOut->mNumVertices)
{ {
p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices]; p_pcOut->mVertices = new aiVector3D[p_pcOut->mNumVertices];
p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices]; p_pcOut->mNormals = new aiVector3D[p_pcOut->mNumVertices];
@ -489,7 +474,7 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
} }
} }
// convert texture coordinates // convert texture coordinates
if ((*i).mTexCoords.size() != 0) if ((*i).mTexCoords.size())
{ {
p_pcOut->mTextureCoords[0] = new aiVector3D[p_pcOut->mNumVertices]; p_pcOut->mTextureCoords[0] = new aiVector3D[p_pcOut->mNumVertices];
@ -525,17 +510,13 @@ void Dot3DSImporter::ConvertMeshes(aiScene* pcOut)
pcOut->mMeshes[a] = avOutMeshes[a]; pcOut->mMeshes[a] = avOutMeshes[a];
} }
if (0 == iFaceCnt) if (!iFaceCnt)
{
throw new ImportErrorException("No faces loaded. The mesh is empty"); throw new ImportErrorException("No faces loaded. The mesh is empty");
}
// for each material in the scene we need to setup the UV source // for each material in the scene we need to setup the UV source
// set for each texture // set for each texture
for (unsigned int a = 0; a < pcOut->mNumMaterials;++a) for (unsigned int a = 0; a < pcOut->mNumMaterials;++a)
{
TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &this->mScene->mMaterials[a] ); TextureTransform::SetupMatUVSrc( pcOut->mMaterials[a], &this->mScene->mMaterials[a] );
}
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -551,7 +532,9 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
const Dot3DS::Mesh* pcMesh = (const Dot3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; const Dot3DS::Mesh* pcMesh = (const Dot3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0];
ai_assert(NULL != pcMesh); ai_assert(NULL != pcMesh);
if (0 == ASSIMP_stricmp(pcIn->mName.c_str(),pcMesh->mName.c_str())) // do case independent comparisons here, just for safety
if (pcIn->mName.length() == pcMesh->mName.length() &&
!ASSIMP_stricmp(pcIn->mName.c_str(),pcMesh->mName.c_str()))
{ {
iArray.push_back(a); iArray.push_back(a);
} }
@ -560,7 +543,8 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
{ {
aiMatrix4x4& mTrafo = ((Dot3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat; aiMatrix4x4& mTrafo = ((Dot3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat;
aiMatrix4x4 mInv = mTrafo; aiMatrix4x4 mInv = mTrafo;
mInv.Inverse(); if (!this->configSkipPivot)
mInv.Inverse();
pcOut->mName.Set(pcIn->mName); pcOut->mName.Set(pcIn->mName);
pcOut->mNumMeshes = (unsigned int)iArray.size(); pcOut->mNumMeshes = (unsigned int)iArray.size();
@ -575,7 +559,7 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices; const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
aiVector3D* pvCurrent = mesh->mVertices; aiVector3D* pvCurrent = mesh->mVertices;
if(pivot.x || pivot.y || pivot.z) if(pivot.x || pivot.y || pivot.z && !this->configSkipPivot)
{ {
while (pvCurrent != pvEnd) while (pvCurrent != pvEnd)
{ {
@ -593,18 +577,12 @@ void Dot3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,Dot3DS::Node*
while (pvCurrent != pvEnd) while (pvCurrent != pvEnd)
{ {
std::swap( pvCurrent->y, pvCurrent->z ); std::swap( pvCurrent->y, pvCurrent->z );
//pvCurrent->y *= -1.0f;
++pvCurrent; ++pvCurrent;
} }
} }
pcOut->mMeshes[i] = iIndex; pcOut->mMeshes[i] = iIndex;
} }
} }
/*else
{
DefaultLogger::get()->warn("A node that is not a dummy does not "
"reference a valid mesh.");
}*/
} }
pcOut->mTransformation = aiMatrix4x4(); pcOut->mTransformation = aiMatrix4x4();
pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size();
@ -636,8 +614,7 @@ void Dot3DSImporter::GenerateNodeGraph(aiScene* pcOut)
// //
unsigned int iCnt = 0; unsigned int iCnt = 0;
DefaultLogger::get()->warn("No hierarchy information has been " DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
"found in the file. A flat hierarchy tree is built ...");
pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes; pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes;
pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mNumMeshes ]; pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mNumMeshes ];
@ -654,11 +631,7 @@ void Dot3DSImporter::GenerateNodeGraph(aiScene* pcOut)
char szBuffer[128]; char szBuffer[128];
int iLen; int iLen;
#if _MSC_VER >= 1400
iLen = sprintf_s(szBuffer,"UNNAMED_%i",i);
#else
iLen = sprintf(szBuffer,"UNNAMED_%i",i); iLen = sprintf(szBuffer,"UNNAMED_%i",i);
#endif
ai_assert(0 < iLen); ai_assert(0 < iLen);
::memcpy(pcNode->mName.data,szBuffer,iLen); ::memcpy(pcNode->mName.data,szBuffer,iLen);
pcNode->mName.data[iLen] = '\0'; pcNode->mName.data[iLen] = '\0';

View File

@ -120,8 +120,8 @@ public:
enum enum
{ {
// ************************************************************** // ********************************************************************
// Base chunks which can be found everywhere in the file // Basic chunks which can be found everywhere in the file
CHUNK_VERSION = 0x0002, CHUNK_VERSION = 0x0002,
CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B
CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B
@ -132,7 +132,7 @@ public:
CHUNK_PERCENTW = 0x0030, // int2 percentage CHUNK_PERCENTW = 0x0030, // int2 percentage
CHUNK_PERCENTF = 0x0031, // float4 percentage CHUNK_PERCENTF = 0x0031, // float4 percentage
// ************************************************************** // ********************************************************************
// Unknown and ignored. Possibly a chunk used by PROJ ( // Unknown and ignored. Possibly a chunk used by PROJ (
// Discreet 3DS max Project File)? // Discreet 3DS max Project File)?
@ -162,7 +162,7 @@ public:
CHUNK_BIT_MAP = 0x1100, CHUNK_BIT_MAP = 0x1100,
CHUNK_BIT_MAP_EXISTS = 0x1101, CHUNK_BIT_MAP_EXISTS = 0x1101,
// ************************************************************** // ********************************************************************
// Viewport related stuff. Ignored // Viewport related stuff. Ignored
CHUNK_DEFAULT_VIEW = 0x3000, CHUNK_DEFAULT_VIEW = 0x3000,
CHUNK_VIEW_TOP = 0x3010, CHUNK_VIEW_TOP = 0x3010,
@ -173,7 +173,7 @@ public:
CHUNK_VIEW_BACK = 0x3060, CHUNK_VIEW_BACK = 0x3060,
CHUNK_VIEW_USER = 0x3070, CHUNK_VIEW_USER = 0x3070,
CHUNK_VIEW_CAMERA = 0x3080, CHUNK_VIEW_CAMERA = 0x3080,
// ************************************************************** // ********************************************************************
// Mesh chunks // Mesh chunks
CHUNK_OBJBLOCK = 0x4000, CHUNK_OBJBLOCK = 0x4000,
@ -196,7 +196,7 @@ public:
// to the root node's transformation matrix // to the root node's transformation matrix
CHUNK_MASTER_SCALE = 0x0100, CHUNK_MASTER_SCALE = 0x0100,
// ************************************************************** // ********************************************************************
// Material chunks // Material chunks
CHUNK_MAT_MATERIAL = 0xAFFF, CHUNK_MAT_MATERIAL = 0xAFFF,
@ -280,7 +280,7 @@ public:
// Specifies whether a materail requires two-sided rendering // Specifies whether a materail requires two-sided rendering
CHUNK_MAT_TWO_SIDE = 0xA081, CHUNK_MAT_TWO_SIDE = 0xA081,
// ************************************************************** // ********************************************************************
// Main keyframer chunk. Contains translation/rotation/scaling data // Main keyframer chunk. Contains translation/rotation/scaling data
CHUNK_KEYFRAMER = 0xB000, CHUNK_KEYFRAMER = 0xB000,
@ -293,7 +293,7 @@ public:
CHUNK_TRACKROTATE = 0xB021, CHUNK_TRACKROTATE = 0xB021,
CHUNK_TRACKSCALE = 0xB022, CHUNK_TRACKSCALE = 0xB022,
// ************************************************************** // ********************************************************************
// Keyframes for various other stuff in the file // Keyframes for various other stuff in the file
// Ignored // Ignored
CHUNK_AMBIENTKEY = 0xB001, CHUNK_AMBIENTKEY = 0xB001,
@ -308,7 +308,7 @@ public:
CHUNK_TRACKLIGTGT = 0xB006, CHUNK_TRACKLIGTGT = 0xB006,
CHUNK_TRACKSPOTL = 0xB007, CHUNK_TRACKSPOTL = 0xB007,
CHUNK_FRAMES = 0xB008 CHUNK_FRAMES = 0xB008
// ************************************************************** // ********************************************************************
}; };
}; };

View File

@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/aiMesh.h" #include "../include/aiMesh.h"
#include "../include/aiScene.h" #include "../include/aiScene.h"
#include "../include/aiAssert.h" #include "../include/aiAssert.h"
#include "../include/assimp.hpp"
// boost headers // boost headers
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
@ -99,6 +100,12 @@ bool Dot3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) co
return false; return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup configuration properties
void Dot3DSImporter::SetupProperties(const Importer* pImp)
{
this->configSkipPivot = pImp->GetProperty(AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT,0) ? true : false;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void Dot3DSImporter::InternReadFile( void Dot3DSImporter::InternReadFile(
const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
@ -144,48 +151,46 @@ void Dot3DSImporter::InternReadFile(
try try
{ {
this->ParseMainChunk(iRemaining); this->ParseMainChunk(iRemaining);
// Generate an unique set of vertices/indices for
// all meshes contained in the file
for (std::vector<Dot3DS::Mesh>::iterator
i = this->mScene->mMeshes.begin();
i != this->mScene->mMeshes.end();++i)
{
// TODO: see function body
this->CheckIndices(&(*i));
this->MakeUnique(&(*i));
// first generate normals for the mesh
this->GenNormals(&(*i));
}
// Apply scaling and offsets to all texture coordinates
TextureTransform::ApplyScaleNOffset(this->mScene->mMaterials);
// Replace all occurences of the default material with a valid material.
// Generate it if no material containing DEFAULT in its name has been
// found in the file
this->ReplaceDefaultMaterial();
// Convert the scene from our internal representation to an aiScene object
this->ConvertScene(pScene);
// Generate the node graph for the scene. This is a little bit
// tricky since we'll need to split some meshes into submeshes
this->GenerateNodeGraph(pScene);
// Now apply a master scaling factor to the scene
this->ApplyMasterScale(pScene);
} }
catch ( ImportErrorException* ex) catch ( ImportErrorException* ex)
{ {
delete[] this->mBuffer; delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
throw ex; throw ex;
};
// Generate an unique set of vertices/indices for
// all meshes contained in the file
for (std::vector<Dot3DS::Mesh>::iterator
i = this->mScene->mMeshes.begin();
i != this->mScene->mMeshes.end();++i)
{
// TODO: see function body
this->CheckIndices(&(*i));
this->MakeUnique(&(*i));
// first generate normals for the mesh
this->GenNormals(&(*i));
} }
delete[] this->mBuffer;AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
// Apply scaling and offsets to all texture coordinates
TextureTransform::ApplyScaleNOffset(this->mScene->mMaterials);
// Replace all occurences of the default material with a valid material.
// Generate it if no material containing DEFAULT in its name has been
// found in the file
this->ReplaceDefaultMaterial();
// Convert the scene from our internal representation to an aiScene object
this->ConvertScene(pScene);
// Generate the node graph for the scene. This is a little bit
// tricky since we'll need to split some meshes into submeshes
this->GenerateNodeGraph(pScene);
// Now apply a master scaling factor to the scene
this->ApplyMasterScale(pScene);
delete[] this->mBuffer;
delete this->mScene;
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Dot3DSImporter::ApplyMasterScale(aiScene* pScene) void Dot3DSImporter::ApplyMasterScale(aiScene* pScene)

View File

@ -43,8 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_3DSIMPORTER_H_INC #ifndef AI_3DSIMPORTER_H_INC
#define AI_3DSIMPORTER_H_INC #define AI_3DSIMPORTER_H_INC
#include <map>
#include "BaseImporter.h" #include "BaseImporter.h"
#include "../include/aiTypes.h" #include "../include/aiTypes.h"
@ -73,11 +71,19 @@ protected:
~Dot3DSImporter(); ~Dot3DSImporter();
public: public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */ * See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const;
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -233,6 +239,10 @@ protected:
protected: protected:
/** Configuration option: skip pivot chunks */
bool configSkipPivot;
/** Buffer to hold the loaded file */ /** Buffer to hold the loaded file */
unsigned char* mBuffer; unsigned char* mBuffer;

View File

@ -109,14 +109,11 @@ void ASEImporter::InternReadFile(
// Check whether we can read from the file // Check whether we can read from the file
if( file.get() == NULL) if( file.get() == NULL)
{
throw new ImportErrorException( "Failed to open ASE file " + pFile + "."); throw new ImportErrorException( "Failed to open ASE file " + pFile + ".");
}
size_t fileSize = file->FileSize(); size_t fileSize = file->FileSize();
std::string::size_type pos = pFile.find_last_of('.'); std::string::size_type pos = pFile.find_last_of('.');
std::string extension = pFile.substr( pos); std::string extension = pFile.substr( pos);
this->mIsAsk = (extension[3] == 'k' || extension[3] == 'K');
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer
// (terminate it with zero) // (terminate it with zero)
@ -144,11 +141,7 @@ void ASEImporter::InternReadFile(
{ {
if ((*i).bSkip)continue; if ((*i).bSkip)continue;
// transform all vertices into worldspace
// world2obj transform is specified in the
// transformation matrix of a scenegraph node
this->TransformVertices(*i); this->TransformVertices(*i);
// now we need to create proper meshes from the import we need to // now we need to create proper meshes from the import we need to
// split them by materials, build valid vertex/face lists ... // split them by materials, build valid vertex/face lists ...
this->BuildUniqueRepresentation(*i); this->BuildUniqueRepresentation(*i);
@ -215,7 +208,7 @@ void ASEImporter::GenerateDefaultMaterial()
this->mParser->m_vMaterials.push_back ( ASE::Material() ); this->mParser->m_vMaterials.push_back ( ASE::Material() );
ASE::Material& mat = this->mParser->m_vMaterials.back(); ASE::Material& mat = this->mParser->m_vMaterials.back();
mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f); mat.mDiffuse = aiColor3D(0.6f,0.6f,0.6f);
mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f); mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f);
mat.mAmbient = aiColor3D(0.05f,0.05f,0.05f); mat.mAmbient = aiColor3D(0.05f,0.05f,0.05f);
mat.mShading = Dot3DSFile::Gouraud; mat.mShading = Dot3DSFile::Gouraud;
@ -449,21 +442,6 @@ void ASEImporter::BuildNodes()
std::string* szMyName = (std::string*)pcScene->mMeshes[*i]->mColors[1]; std::string* szMyName = (std::string*)pcScene->mMeshes[*i]->mColors[1];
if (!szMyName)continue; if (!szMyName)continue;
#if 0 // moved to the scope above
for (std::vector<unsigned int>::iterator
a = i+1;
a != aiList.end();++a)
{
std::string* szMyName2 = (std::string*)pcScene->mMeshes[*i]->mColors[1];
if (!szMyName)continue;
if (0 == ASSIMP_stricmp(szMyName2->c_str(),szMyName->c_str()))
{
a = aiList.erase(a);
if (a == aiList.end())break;
}
}
#endif
DefaultLogger::get()->info("Generating dummy node: " + szMyName[1] + ". " DefaultLogger::get()->info("Generating dummy node: " + szMyName[1] + ". "
"This node is not defined in the ASE file, but referenced as " "This node is not defined in the ASE file, but referenced as "
"parent node."); "parent node.");
@ -604,19 +582,6 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
mesh.amTexCoords[c] = amTexCoords[c]; mesh.amTexCoords[c] = amTexCoords[c];
// now need to transform all vertices with the inverse of their
// transformation matrix ...
//aiMatrix4x4 mInverse = mesh.mTransform;
//mInverse.Inverse();
//for (std::vector<aiVector3D>::iterator
// i = mesh.mPositions.begin();
// i != mesh.mPositions.end();++i)
//{
// (*i) = mInverse * (*i);
//}
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1066,7 +1031,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
pc->mName.Set(mesh.mBones[jfkennedy].mName); pc->mName.Set(mesh.mBones[jfkennedy].mName);
pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size(); pc->mNumWeights = (unsigned int)avBonesOut[jfkennedy].size();
pc->mWeights = new aiVertexWeight[pc->mNumWeights]; pc->mWeights = new aiVertexWeight[pc->mNumWeights];
memcpy(pc->mWeights,&avBonesOut[jfkennedy][0], ::memcpy(pc->mWeights,&avBonesOut[jfkennedy][0],
sizeof(aiVertexWeight) * pc->mNumWeights); sizeof(aiVertexWeight) * pc->mNumWeights);
++pcBone; ++pcBone;
} }
@ -1246,9 +1211,8 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh)
aiVector3D pDelta2 = *pV3 - *pV1; aiVector3D pDelta2 = *pV3 - *pV1;
aiVector3D vNor = pDelta1 ^ pDelta2; aiVector3D vNor = pDelta1 ^ pDelta2;
mesh.mNormals[face.mIndices[0]] = vNor; for (unsigned int i = 0; i < 3;++i)
mesh.mNormals[face.mIndices[1]] = vNor; mesh.mNormals[face.mIndices[i]] = vNor;
mesh.mNormals[face.mIndices[2]] = vNor;
} }
// calculate the position bounds so we have a reliable epsilon to // calculate the position bounds so we have a reliable epsilon to
@ -1287,15 +1251,13 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh)
posEpsilon,poResult); posEpsilon,poResult);
aiVector3D vNormals; aiVector3D vNormals;
float fDiv = 0.0f;
for (std::vector<unsigned int>::const_iterator for (std::vector<unsigned int>::const_iterator
a = poResult.begin(); a = poResult.begin();
a != poResult.end();++a) a != poResult.end();++a)
{ {
vNormals += mesh.mNormals[(*a)]; vNormals += mesh.mNormals[(*a)];
fDiv += 1.0f;
} }
vNormals /= fDiv; vNormals.Normalize();
avNormals[(*i).mIndices[c]] = vNormals; avNormals[(*i).mIndices[c]] = vNormals;
poResult.clear(); poResult.clear();
} }

View File

@ -114,8 +114,6 @@ protected:
* \param mesh Mesh to work on * \param mesh Mesh to work on
*/ */
void TransformVertices(ASE::Mesh& mesh); void TransformVertices(ASE::Mesh& mesh);
// -------------------------------------------------------------------
/** Create one-material-per-mesh meshes ;-) /** Create one-material-per-mesh meshes ;-)
* \param mesh Mesh to work with * \param mesh Mesh to work with
* \param Receives the list of all created meshes * \param Receives the list of all created meshes
@ -168,9 +166,6 @@ protected:
/** Buffer to hold the loaded file */ /** Buffer to hold the loaded file */
unsigned char* mBuffer; unsigned char* mBuffer;
/** true if this is an .ask file */
bool mIsAsk;
/** Scene to be filled */ /** Scene to be filled */
aiScene* pcScene; aiScene* pcScene;
}; };

View File

@ -794,6 +794,7 @@ void Parser::ParseLV1GeometryObjectBlock(ASE::Mesh& mesh)
{ {
this->m_szFile+=9; this->m_szFile+=9;
this->ParseLV2NodeTransformBlock(mesh);continue; this->ParseLV2NodeTransformBlock(mesh);continue;
//mesh.mTransform.Transpose();
} }
// mesh data // mesh data
if (0 == strncmp(this->m_szFile,"*MESH" ,5) && if (0 == strncmp(this->m_szFile,"*MESH" ,5) &&

View File

@ -56,6 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/aiPostProcess.h" #include "../include/aiPostProcess.h"
#include "../include/aiMesh.h" #include "../include/aiMesh.h"
#include "../include/aiScene.h" #include "../include/aiScene.h"
#include "../include/assimp.hpp"
using namespace Assimp; using namespace Assimp;
@ -80,6 +81,16 @@ bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
return (pFlags & aiProcess_CalcTangentSpace) != 0; return (pFlags & aiProcess_CalcTangentSpace) != 0;
} }
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void CalcTangentsProcess::SetupProperties(const Importer* pImp)
{
// get the current value of the property
this->configMaxAngle = pImp->GetProperty(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45000) / 1000.0f;
this->configMaxAngle = std::max(std::min(this->configMaxAngle,180.0f),0.0f);
this->configMaxAngle *= 0.0174532925f;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void CalcTangentsProcess::Execute( aiScene* pScene) void CalcTangentsProcess::Execute( aiScene* pScene)
@ -213,7 +224,6 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh)
vertexFinder.FindPositions( origPos, posEpsilon, verticesFound); vertexFinder.FindPositions( origPos, posEpsilon, verticesFound);
// look among them for other vertices sharing the same normal and a close-enough tangent/bitangent // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
static const float MAX_DIFF_ANGLE = 0.701f;
for( unsigned int b = 0; b < verticesFound.size(); b++) for( unsigned int b = 0; b < verticesFound.size(); b++)
{ {
unsigned int idx = verticesFound[b]; unsigned int idx = verticesFound[b];
@ -221,9 +231,9 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh)
continue; continue;
if( meshNorm[idx] * origNorm < angleEpsilon) if( meshNorm[idx] * origNorm < angleEpsilon)
continue; continue;
if( meshTang[idx] * origTang < MAX_DIFF_ANGLE) if( acosf( meshTang[idx] * origTang) > this->configMaxAngle)
continue; continue;
if( meshBitang[idx] * origBitang < MAX_DIFF_ANGLE) if( acosf( meshBitang[idx] * origBitang) > this->configMaxAngle)
continue; continue;
// it's similar enough -> add it to the smoothing group // it's similar enough -> add it to the smoothing group

View File

@ -70,26 +70,39 @@ protected:
public: public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag.
* @param pFlags The processing flags the importer was called with. A bitwise * @param pFlags The processing flags the importer was called with.
* combination of #aiPostProcessSteps. * A bitwise combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @return true if the process is present in this flag fields,
* false if not.
*/ */
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
/** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
protected:
// -------------------------------------------------------------------
/** Calculates tangents and bitangents for a specific mesh.
* @param pMesh The mesh to process.
*/
bool ProcessMesh( aiMesh* pMesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post processing step on the given imported data. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail.
* @param pScene The imported data to work at. * @param pScene The imported data to work at.
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene);
protected: private:
// -------------------------------------------------------------------
/** Calculates tangents and bitangents for the given mesh /** Configuration option: maximum smoothing angle, in radians*/
* @param pMesh The mesh to process. float configMaxAngle;
*/
bool ProcessMesh( aiMesh* pMesh);
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/aiPostProcess.h" #include "../include/aiPostProcess.h"
#include "../include/aiMesh.h" #include "../include/aiMesh.h"
#include "../include/aiScene.h" #include "../include/aiScene.h"
#include "../include/assimp.hpp"
using namespace Assimp; using namespace Assimp;
@ -70,7 +71,15 @@ bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const
{ {
return (pFlags & aiProcess_GenSmoothNormals) != 0; return (pFlags & aiProcess_GenSmoothNormals) != 0;
} }
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void GenVertexNormalsProcess::SetupProperties(const Importer* pImp)
{
// get the current value of the property
this->configMaxAngle = pImp->GetProperty(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,180000) / 1000.0f;
this->configMaxAngle = std::max(std::min(this->configMaxAngle,180.0f),0.0f);
this->configMaxAngle *= 0.0174532925f;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void GenVertexNormalsProcess::Execute( aiScene* pScene) void GenVertexNormalsProcess::Execute( aiScene* pScene)
@ -111,14 +120,10 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
aiVector3D pDelta1 = *pV2 - *pV1; aiVector3D pDelta1 = *pV2 - *pV1;
aiVector3D pDelta2 = *pV3 - *pV1; aiVector3D pDelta2 = *pV3 - *pV1;
aiVector3D vNor = pDelta1 ^ pDelta2; aiVector3D vNor = pDelta1 ^ pDelta2;
vNor.Normalize();
/*if (face.mIndices[1] > face.mIndices[2])
vNor *= -1.0f;*/
for (unsigned int i = 0;i < face.mNumIndices;++i) for (unsigned int i = 0;i < face.mNumIndices;++i)
{
pMesh->mNormals[face.mIndices[i]] = vNor; pMesh->mNormals[face.mIndices[i]] = vNor;
}
} }
// calculate the position bounds so we have a reliable epsilon to // calculate the position bounds so we have a reliable epsilon to
@ -135,10 +140,14 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
} }
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f; const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
// set up a SpatialSort to quickly find all vertices close to a given position // set up a SpatialSort to quickly find all vertices close to a given position
SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
std::vector<unsigned int> verticesFound; std::vector<unsigned int> verticesFound;
const float fLimit = (AI_MESH_SMOOTHING_ANGLE_NOT_SET == pMesh->mMaxSmoothingAngle
? this->configMaxAngle : pMesh->mMaxSmoothingAngle);
aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices]; aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
for (unsigned int i = 0; i < pMesh->mNumVertices;++i) for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
{ {
@ -148,12 +157,19 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
vertexFinder.FindPositions( posThis, posEpsilon, verticesFound); vertexFinder.FindPositions( posThis, posEpsilon, verticesFound);
aiVector3D pcNor; aiVector3D pcNor;
unsigned int div = 0;
for (unsigned int a = 0; a < verticesFound.size(); ++a) for (unsigned int a = 0; a < verticesFound.size(); ++a)
{ {
unsigned int vidx = verticesFound[a]; unsigned int vidx = verticesFound[a];
// check whether the angle between the two normals is not too large
if (acosf(pMesh->mNormals[vidx] * pMesh->mNormals[i]) > fLimit)
continue;
pcNor += pMesh->mNormals[vidx]; pcNor += pMesh->mNormals[vidx];
++div;
} }
pcNor /= (float) verticesFound.size(); pcNor.Normalize();
pcNew[i] = pcNor; pcNew[i] = pcNor;
} }
delete[] pMesh->mNormals; delete[] pMesh->mNormals;

View File

@ -38,7 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file Defines a post processing step to compute vertex normals for all loaded vertizes */ /** @file Defines a post processing step to compute vertex normals
for all loaded vertizes */
#ifndef AI_GENVERTEXNORMALPROCESS_H_INC #ifndef AI_GENVERTEXNORMALPROCESS_H_INC
#define AI_GENVERTEXNORMALPROCESS_H_INC #define AI_GENVERTEXNORMALPROCESS_H_INC
@ -48,7 +49,7 @@ class GenNormalsTest;
namespace Assimp { namespace Assimp {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** The GenFaceNormalsProcess computes vertex normals for all vertizes of all meshes /** The GenFaceNormalsProcess computes vertex normals for all vertizes
*/ */
class ASSIMP_API GenVertexNormalsProcess : public BaseProcess class ASSIMP_API GenVertexNormalsProcess : public BaseProcess
{ {
@ -64,13 +65,21 @@ protected:
public: public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag.
* @param pFlags The processing flags the importer was called with. A bitwise * @param pFlags The processing flags the importer was called with.
* combination of #aiPostProcessSteps. * A bitwise combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @return true if the process is present in this flag fields,
* false if not.
*/ */
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
/** Called prior to ExecuteOnScene().
* The function is a request to the process to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Executes the post processing step on the given imported data. /** Executes the post processing step on the given imported data.
* At the moment a process is not supposed to fail. * At the moment a process is not supposed to fail.
@ -78,9 +87,19 @@ public:
*/ */
void Execute( aiScene* pScene); void Execute( aiScene* pScene);
protected:
// -------------------------------------------------------------------
/** Computes normals for a specific mesh
* @param pcMesh Mesh
* @return true if vertex normals have been computed
*/
bool GenMeshVertexNormals (aiMesh* pcMesh);
private: private:
bool GenMeshVertexNormals (aiMesh* pcMesh);
/** Configuration option: maximum smoothing angle, in radians*/
float configMaxAngle;
}; };
}; // end of namespace Assimp }; // end of namespace Assimp

View File

@ -93,10 +93,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#if (!defined AI_BUILD_NO_MDR_IMPORTER) #if (!defined AI_BUILD_NO_MDR_IMPORTER)
# include "MDRLoader.h" # include "MDRLoader.h"
#endif #endif
#endif
#if (!defined AI_BUILD_NO_MDC_IMPORTER) #if (!defined AI_BUILD_NO_MDC_IMPORTER)
# include "MDCLoader.h" # include "MDCLoader.h"
#endif #endif
#endif
#if (!defined AI_BUILD_NO_MD5_IMPORTER) #if (!defined AI_BUILD_NO_MD5_IMPORTER)
# include "MD5Loader.h" # include "MD5Loader.h"
#endif #endif
@ -202,10 +202,10 @@ Importer::Importer() :
#if (!defined AI_BUILD_NO_MDR_IMPORTER) #if (!defined AI_BUILD_NO_MDR_IMPORTER)
mImporter.push_back( new MDRImporter()); mImporter.push_back( new MDRImporter());
#endif #endif
#endif
#if (!defined AI_BUILD_NO_MDC_IMPORTER) #if (!defined AI_BUILD_NO_MDC_IMPORTER)
mImporter.push_back( new MDCImporter()); mImporter.push_back( new MDCImporter());
#endif #endif
#endif
#if (!defined AI_BUILD_NO_MD5_IMPORTER) #if (!defined AI_BUILD_NO_MD5_IMPORTER)
mImporter.push_back( new MD5Importer()); mImporter.push_back( new MD5Importer());
#endif #endif

View File

@ -88,11 +88,7 @@ void LimitBoneWeightsProcess::Execute( aiScene* pScene)
void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp)
{ {
// get the current value of the property // get the current value of the property
if(0xffffffff == (this->mMaxWeights = pImp->GetProperty( this->mMaxWeights = pImp->GetProperty(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
AI_CONFIG_PP_LBW_MAX_WEIGHTS,0xffffffff)))
{
this->mMaxWeights = AI_LMW_MAX_WEIGHTS;
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -83,10 +83,11 @@ protected:
public: public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the processing step is present in the given flag field. /** Returns whether the processing step is present in the given flag.
* @param pFlags The processing flags the importer was called with. A bitwise * @param pFlags The processing flags the importer was called with.
* combination of #aiPostProcessSteps. * A bitwise combination of #aiPostProcessSteps.
* @return true if the process is present in this flag fields, false if not. * @return true if the process is present in this flag fields,
* false if not.
*/ */
bool IsActive( unsigned int pFlags) const; bool IsActive( unsigned int pFlags) const;
@ -95,7 +96,7 @@ public:
* The function is a request to the process to update its configuration * The function is a request to the process to update its configuration
* basing on the Importer's configuration property list. * basing on the Importer's configuration property list.
*/ */
virtual void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp);
protected: protected:

View File

@ -169,7 +169,7 @@ void MD2Importer::ValidateHeader( )
if (this->m_pcHeader->numVertices > AI_MD2_MAX_VERTS) if (this->m_pcHeader->numVertices > AI_MD2_MAX_VERTS)
DefaultLogger::get()->warn("The model contains more vertices than Quake 2 supports"); DefaultLogger::get()->warn("The model contains more vertices than Quake 2 supports");
if (this->m_pcHeader->numFrames >= this->configFrameID ) if (this->m_pcHeader->numFrames <= this->configFrameID )
throw new ImportErrorException("The requested frame is not existing the file"); throw new ImportErrorException("The requested frame is not existing the file");
} }

View File

@ -93,28 +93,26 @@ bool MD3Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
void MD3Importer::ValidateHeaderOffsets() void MD3Importer::ValidateHeaderOffsets()
{ {
// check magic number // check magic number
if (this->m_pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_BE && if (pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_BE &&
this->m_pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_LE) pcHeader->IDENT != AI_MD3_MAGIC_NUMBER_LE)
throw new ImportErrorException( "Invalid MD3 file: Magic bytes not found"); throw new ImportErrorException( "Invalid MD3 file: Magic bytes not found");
// check file format version // check file format version
if (this->m_pcHeader->VERSION > 15) if (pcHeader->VERSION > 15)
DefaultLogger::get()->warn( "Unsupported MD3 file version. Continuing happily ..."); DefaultLogger::get()->warn( "Unsupported MD3 file version. Continuing happily ...");
// check some values whether they are valid // check some values whether they are valid
if (!this->m_pcHeader->NUM_FRAMES) if (!pcHeader->NUM_SURFACES)
throw new ImportErrorException( "Invalid MD3 file: NUM_FRAMES is 0");
if (!this->m_pcHeader->NUM_SURFACES)
throw new ImportErrorException( "Invalid md3 file: NUM_SURFACES is 0"); throw new ImportErrorException( "Invalid md3 file: NUM_SURFACES is 0");
if (this->m_pcHeader->OFS_FRAMES >= this->fileSize || if (pcHeader->OFS_FRAMES >= fileSize ||
this->m_pcHeader->OFS_SURFACES >= this->fileSize || pcHeader->OFS_SURFACES >= fileSize ||
this->m_pcHeader->OFS_EOF > this->fileSize) pcHeader->OFS_EOF > fileSize)
{ {
throw new ImportErrorException("Invalid MD3 header: some offsets are outside the file"); throw new ImportErrorException("Invalid MD3 header: some offsets are outside the file");
} }
if (this->m_pcHeader->NUM_FRAMES >= this->configFrameID ) if (pcHeader->NUM_FRAMES <= this->configFrameID )
throw new ImportErrorException("The requested frame is not existing the file"); throw new ImportErrorException("The requested frame is not existing the file");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -123,10 +121,10 @@ void MD3Importer::ValidateSurfaceHeaderOffsets(const MD3::Surface* pcSurf)
// calculate the relative offset of the surface // calculate the relative offset of the surface
int32_t ofs = int32_t((const unsigned char*)pcSurf-this->mBuffer); int32_t ofs = int32_t((const unsigned char*)pcSurf-this->mBuffer);
if (pcSurf->OFS_TRIANGLES + ofs + pcSurf->NUM_TRIANGLES * sizeof(MD3::Triangle) > this->fileSize || if (pcSurf->OFS_TRIANGLES + ofs + pcSurf->NUM_TRIANGLES * sizeof(MD3::Triangle) > fileSize ||
pcSurf->OFS_SHADERS + ofs + pcSurf->NUM_SHADER * sizeof(MD3::Shader) > this->fileSize || pcSurf->OFS_SHADERS + ofs + pcSurf->NUM_SHADER * sizeof(MD3::Shader) > fileSize ||
pcSurf->OFS_ST + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::TexCoord) > this->fileSize || pcSurf->OFS_ST + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::TexCoord) > fileSize ||
pcSurf->OFS_XYZNORMAL + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::Vertex) > this->fileSize) pcSurf->OFS_XYZNORMAL + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::Vertex) > fileSize)
{ {
throw new ImportErrorException("Invalid MD3 surface header: some offsets are outside the file"); throw new ImportErrorException("Invalid MD3 surface header: some offsets are outside the file");
} }
@ -170,310 +168,279 @@ void MD3Importer::InternReadFile(
throw new ImportErrorException( "MD3 File is too small."); throw new ImportErrorException( "MD3 File is too small.");
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer
this->mBuffer = new unsigned char[fileSize]; std::vector<unsigned char> mBuffer2 (fileSize);
file->Read( (void*)mBuffer, 1, fileSize); file->Read( &mBuffer2[0], 1, fileSize);
mBuffer = &mBuffer2[0];
try pcHeader = (BE_NCONST MD3::Header*)mBuffer;
#ifdef AI_BUILD_BIG_ENDIAN
ByteSwap::Swap4(&pcHeader->VERSION);
ByteSwap::Swap4(&pcHeader->FLAGS);
ByteSwap::Swap4(&pcHeader->IDENT);
ByteSwap::Swap4(&pcHeader->NUM_FRAMES);
ByteSwap::Swap4(&pcHeader->NUM_SKINS);
ByteSwap::Swap4(&pcHeader->NUM_SURFACES);
ByteSwap::Swap4(&pcHeader->NUM_TAGS);
ByteSwap::Swap4(&pcHeader->OFS_EOF);
ByteSwap::Swap4(&pcHeader->OFS_FRAMES);
ByteSwap::Swap4(&pcHeader->OFS_SURFACES);
ByteSwap::Swap4(&pcHeader->OFS_TAGS);
#endif
// validate the header
this->ValidateHeaderOffsets();
// now navigate to the list of surfaces
const MD3::Surface* pcSurfaces = (const MD3::Surface*)(mBuffer + pcHeader->OFS_SURFACES);
// allocate output storage
pScene->mNumMeshes = pcHeader->NUM_SURFACES;
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
pScene->mNumMaterials = pcHeader->NUM_SURFACES;
pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes];
// if an exception is thrown before the meshes are allocated ->
// otherwise the pointer value would be invalid and delete would crash
::memset(pScene->mMeshes,0,pScene->mNumMeshes*sizeof(aiMesh*));
::memset(pScene->mMaterials,0,pScene->mNumMaterials*sizeof(aiMaterial*));
unsigned int iNum = pcHeader->NUM_SURFACES;
unsigned int iNumMaterials = 0;
unsigned int iDefaultMatIndex = 0xFFFFFFFF;
while (iNum-- > 0)
{ {
this->m_pcHeader = (const MD3::Header*)this->mBuffer;
#ifdef AI_BUILD_BIG_ENDIAN #ifdef AI_BUILD_BIG_ENDIAN
ByteSwap::Swap4(&m_pcHeader->VERSION); ByteSwap::Swap4(pcSurfaces->FLAGS);
ByteSwap::Swap4(&m_pcHeader->FLAGS); ByteSwap::Swap4(pcSurfaces->IDENT);
ByteSwap::Swap4(&m_pcHeader->IDENT); ByteSwap::Swap4(pcSurfaces->NUM_FRAMES);
ByteSwap::Swap4(&m_pcHeader->NUM_FRAMES); ByteSwap::Swap4(pcSurfaces->NUM_SHADER);
ByteSwap::Swap4(&m_pcHeader->NUM_SKINS); ByteSwap::Swap4(pcSurfaces->NUM_TRIANGLES);
ByteSwap::Swap4(&m_pcHeader->NUM_SURFACES); ByteSwap::Swap4(pcSurfaces->NUM_VERTICES);
ByteSwap::Swap4(&m_pcHeader->NUM_TAGS); ByteSwap::Swap4(pcSurfaces->OFS_END);
ByteSwap::Swap4(&m_pcHeader->OFS_EOF); ByteSwap::Swap4(pcSurfaces->OFS_SHADERS);
ByteSwap::Swap4(&m_pcHeader->OFS_FRAMES); ByteSwap::Swap4(pcSurfaces->OFS_ST);
ByteSwap::Swap4(&m_pcHeader->OFS_SURFACES); ByteSwap::Swap4(pcSurfaces->OFS_TRIANGLES);
ByteSwap::Swap4(&m_pcHeader->OFS_TAGS); ByteSwap::Swap4(pcSurfaces->OFS_XYZNORMAL);
#endif #endif
// validate the header // validate the surface
this->ValidateHeaderOffsets(); this->ValidateSurfaceHeaderOffsets(pcSurfaces);
// now navigate to the list of surfaces // navigate to the vertex list of the surface
const MD3::Surface* pcSurfaces = (const MD3::Surface*) const MD3::Vertex* pcVertices = (const MD3::Vertex*)
(this->mBuffer + this->m_pcHeader->OFS_SURFACES); (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_XYZNORMAL);
// allocate output storage // navigate to the triangle list of the surface
pScene->mNumMeshes = this->m_pcHeader->NUM_SURFACES; const MD3::Triangle* pcTriangles = (const MD3::Triangle*)
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_TRIANGLES);
pScene->mNumMaterials = this->m_pcHeader->NUM_SURFACES; // navigate to the texture coordinate list of the surface
pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes]; const MD3::TexCoord* pcUVs = (const MD3::TexCoord*)
(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_ST);
// if an exception is thrown before the meshes are allocated -> // navigate to the shader list of the surface
// otherwise the pointer value would be invalid and delete would crash const MD3::Shader* pcShaders = (const MD3::Shader*)
::memset(pScene->mMeshes,0,pScene->mNumMeshes*sizeof(aiMesh*)); (((uint8_t*)pcSurfaces) + pcSurfaces->OFS_SHADERS);
::memset(pScene->mMaterials,0,pScene->mNumMaterials*sizeof(aiMaterial*));
unsigned int iNum = this->m_pcHeader->NUM_SURFACES; // if the submesh is empty ignore it
unsigned int iNumMaterials = 0; if (0 == pcSurfaces->NUM_VERTICES || 0 == pcSurfaces->NUM_TRIANGLES)
unsigned int iDefaultMatIndex = 0xFFFFFFFF;
while (iNum-- > 0)
{ {
pcSurfaces = (const MD3::Surface*)(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_END);
pScene->mNumMeshes--;
continue;
}
#ifdef AI_BUILD_BIG_ENDIAN #ifdef AI_BUILD_BIG_ENDIAN
ByteSwap::Swap4(pcSurfaces->FLAGS); for (uint32_t i = 0; i < pcSurfaces->NUM_VERTICES;++i)
ByteSwap::Swap4(pcSurfaces->IDENT); {
ByteSwap::Swap4(pcSurfaces->NUM_FRAMES); ByteSwap::Swap2( & pcVertices[i].NORMAL );
ByteSwap::Swap4(pcSurfaces->NUM_SHADER); ByteSwap::Swap2( & pcVertices[i].X );
ByteSwap::Swap4(pcSurfaces->NUM_TRIANGLES); ByteSwap::Swap2( & pcVertices[i].Y );
ByteSwap::Swap4(pcSurfaces->NUM_VERTICES); ByteSwap::Swap2( & pcVertices[i].Z );
ByteSwap::Swap4(pcSurfaces->OFS_END);
ByteSwap::Swap4(pcSurfaces->OFS_SHADERS); ByteSwap::Swap4( & pcUVs[i].U );
ByteSwap::Swap4(pcSurfaces->OFS_ST); ByteSwap::Swap4( & pcUVs[i].U );
ByteSwap::Swap4(pcSurfaces->OFS_TRIANGLES); }
ByteSwap::Swap4(pcSurfaces->OFS_XYZNORMAL); for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i)
{
ByteSwap::Swap4(pcTriangles[i].INDEXES[0]);
ByteSwap::Swap4(pcTriangles[i].INDEXES[1]);
ByteSwap::Swap4(pcTriangles[i].INDEXES[2]);
}
#endif #endif
// validate the surface // allocate the output mesh
this->ValidateSurfaceHeaderOffsets(pcSurfaces); pScene->mMeshes[iNum] = new aiMesh();
aiMesh* pcMesh = pScene->mMeshes[iNum];
// navigate to the vertex list of the surface pcMesh->mNumVertices = pcSurfaces->NUM_TRIANGLES*3;
const MD3::Vertex* pcVertices = (const MD3::Vertex*) pcMesh->mNumFaces = pcSurfaces->NUM_TRIANGLES;
(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_XYZNORMAL); 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->mNumUVComponents[0] = 2;
// navigate to the triangle list of the surface // fill in all triangles
const MD3::Triangle* pcTriangles = (const MD3::Triangle*) unsigned int iCurrent = 0;
(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_TRIANGLES); for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES;++i)
{
pcMesh->mFaces[i].mIndices = new unsigned int[3];
pcMesh->mFaces[i].mNumIndices = 3;
// navigate to the texture coordinate list of the surface unsigned int iTemp = iCurrent;
const MD3::TexCoord* pcUVs = (const MD3::TexCoord*) for (unsigned int c = 0; c < 3;++c,++iCurrent)
(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_ST);
// navigate to the shader list of the surface
const MD3::Shader* pcShaders = (const MD3::Shader*)
(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_SHADERS);
// if the submesh is empty ignore it
if (0 == pcSurfaces->NUM_VERTICES || 0 == pcSurfaces->NUM_TRIANGLES)
{ {
pcSurfaces = (const MD3::Surface*)(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_END); // read vertices
pScene->mNumMeshes--; pcMesh->mVertices[iCurrent].x = pcVertices[ pcTriangles->INDEXES[c]].X;
continue; pcMesh->mVertices[iCurrent].y = pcVertices[ pcTriangles->INDEXES[c]].Y*-1.0f;
pcMesh->mVertices[iCurrent].z = pcVertices[ pcTriangles->INDEXES[c]].Z;
// convert the normal vector to uncompressed float3 format
LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL,
(float*)&pcMesh->mNormals[iCurrent]);
pcMesh->mNormals[iCurrent].y *= -1.0f;
// read texture coordinates
pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U;
pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V;
} }
// FIX: flip the face ordering for use with OpenGL
pcMesh->mFaces[i].mIndices[0] = iTemp+2;
pcMesh->mFaces[i].mIndices[1] = iTemp+1;
pcMesh->mFaces[i].mIndices[2] = iTemp+0;
pcTriangles++;
}
#ifdef AI_BUILD_BIG_ENDIAN // get the first shader (= texture?) assigned to the surface
if (pcSurfaces->NUM_SHADER)
{
// make a relative path.
// if the MD3's internal path itself and the given path are using
// the same directory remove it
const char* szEndDir1 = ::strrchr((const char*)pcHeader->NAME,'\\');
if (!szEndDir1)szEndDir1 = ::strrchr((const char*)pcHeader->NAME,'/');
for (uint32_t i = 0; i < pcSurfaces->NUM_VERTICES;++i) const char* szEndDir2 = ::strrchr((const char*)pcShaders->NAME,'\\');
if (!szEndDir2)szEndDir2 = ::strrchr((const char*)pcShaders->NAME,'/');
if (szEndDir1 && szEndDir2)
{ {
ByteSwap::Swap2( & pcVertices[i].NORMAL ); // both of them are valid
ByteSwap::Swap2( & pcVertices[i].X ); const unsigned int iLen1 = (unsigned int)(szEndDir1 - (const char*)pcHeader->NAME);
ByteSwap::Swap2( & pcVertices[i].Y ); const unsigned int iLen2 = std::min (iLen1, (unsigned int)(szEndDir2 - (const char*)pcShaders->NAME) );
ByteSwap::Swap2( & pcVertices[i].Z );
ByteSwap::Swap4( & pcUVs[i].U ); bool bSuccess = true;
ByteSwap::Swap4( & pcUVs[i].U ); for (unsigned int a = 0; a < iLen2;++a)
}
for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i)
{
ByteSwap::Swap4(pcTriangles[i].INDEXES[0]);
ByteSwap::Swap4(pcTriangles[i].INDEXES[1]);
ByteSwap::Swap4(pcTriangles[i].INDEXES[2]);
}
#endif
// allocate the output mesh
pScene->mMeshes[iNum] = new aiMesh();
aiMesh* pcMesh = pScene->mMeshes[iNum];
pcMesh->mNumVertices = pcSurfaces->NUM_TRIANGLES*3;
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->mNumUVComponents[0] = 2;
// fill in all triangles
unsigned int iCurrent = 0;
for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES;++i)
{
pcMesh->mFaces[i].mIndices = new unsigned int[3];
pcMesh->mFaces[i].mNumIndices = 3;
unsigned int iTemp = iCurrent;
for (unsigned int c = 0; c < 3;++c,++iCurrent)
{ {
// read vertices char sz = ::tolower ( pcShaders->NAME[a] );
pcMesh->mVertices[iCurrent].x = pcVertices[ pcTriangles->INDEXES[c]].X; char sz2 = ::tolower ( pcHeader->NAME[a] );
pcMesh->mVertices[iCurrent].y = pcVertices[ pcTriangles->INDEXES[c]].Y*-1.0f; if (sz != sz2)
pcMesh->mVertices[iCurrent].z = pcVertices[ pcTriangles->INDEXES[c]].Z;
// convert the normal vector to uncompressed float3 format
LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL,
(float*)&pcMesh->mNormals[iCurrent]);
pcMesh->mNormals[iCurrent].y *= -1.0f;
// read texture coordinates
pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U;
pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V;
}
// FIX: flip the face ordering for use with OpenGL
pcMesh->mFaces[i].mIndices[0] = iTemp+2;
pcMesh->mFaces[i].mIndices[1] = iTemp+1;
pcMesh->mFaces[i].mIndices[2] = iTemp+0;
pcTriangles++;
}
// get the first shader (= texture?) assigned to the surface
if (0 != pcSurfaces->NUM_SHADER)
{
// make a relative path.
// if the MD3's internal path itself and the given path are using
// the same directory remove it
const char* szEndDir1 = ::strrchr((const char*)this->m_pcHeader->NAME,'\\');
if (!szEndDir1)szEndDir1 = ::strrchr((const char*)this->m_pcHeader->NAME,'/');
const char* szEndDir2 = ::strrchr((const char*)pcShaders->NAME,'\\');
if (!szEndDir2)szEndDir2 = ::strrchr((const char*)pcShaders->NAME,'/');
if (szEndDir1 && szEndDir2)
{
// both of them are valid
const unsigned int iLen1 = (unsigned int)(szEndDir1 - (const char*)this->m_pcHeader->NAME);
const unsigned int iLen2 = std::min (iLen1, (unsigned int)(szEndDir2 - (const char*)pcShaders->NAME) );
bool bSuccess = true;
for (unsigned int a = 0; a < iLen2;++a)
{ {
char sz = ::tolower ( pcShaders->NAME[a] ); bSuccess = false;
char sz2 = ::tolower ( this->m_pcHeader->NAME[a] ); break;
if (sz != sz2)
{
bSuccess = false;
break;
}
}
if (bSuccess)
{
// use the file name only
szEndDir2++;
}
else
{
// use the full path
szEndDir2 = (const char*)pcShaders->NAME;
} }
} }
if (bSuccess)
// now try to find out whether we have this shader already
bool bHave = false;
for (unsigned int p = 0; p < iNumMaterials;++p)
{ {
if (iDefaultMatIndex == p)continue; // use the file name only
szEndDir2++;
aiString szOut;
if(AI_SUCCESS == aiGetMaterialString ( (aiMaterial*)pScene->mMaterials[p],
AI_MATKEY_TEXTURE_DIFFUSE(0),&szOut))
{
if (0 == ASSIMP_stricmp(szOut.data,szEndDir2))
{
// equal. reuse this material (texture)
bHave = true;
pcMesh->mMaterialIndex = p;
break;
}
}
}
if (!bHave)
{
MaterialHelper* pcHelper = new MaterialHelper();
if (szEndDir2)
{
if (szEndDir2[0])
{
aiString szString;
const size_t iLen = ::strlen(szEndDir2);
::memcpy(szString.data,szEndDir2,iLen);
szString.data[iLen] = '\0';
szString.length = iLen;
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
}
else
{
DefaultLogger::get()->warn("Texture file name has zero length. "
"It will be skipped.");
}
}
int iMode = (int)aiShadingMode_Gouraud;
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
// add a small ambient color value - Quake 3 seems to have one
aiColor3D clr;
clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
aiString szName;
szName.Set(AI_DEFAULT_MATERIAL_NAME);
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper;
iDefaultMatIndex = pcMesh->mMaterialIndex = iNumMaterials++;
}
}
else
{
if (0xFFFFFFFF != iDefaultMatIndex)
{
pcMesh->mMaterialIndex = iDefaultMatIndex;
} }
else else
{ {
MaterialHelper* pcHelper = new MaterialHelper(); // use the full path
szEndDir2 = (const char*)pcShaders->NAME;
// fill in a default material
int iMode = (int)aiShadingMode_Gouraud;
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
aiColor3D clr;
clr.b = clr.g = clr.r = 0.6f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper;
iDefaultMatIndex = pcMesh->mMaterialIndex = iNumMaterials++;
} }
} }
// go to the next surface MaterialHelper* pcHelper = new MaterialHelper();
pcSurfaces = (const MD3::Surface*)(((unsigned char*)pcSurfaces) + pcSurfaces->OFS_END);
if (szEndDir2)
{
if (szEndDir2[0])
{
aiString szString;
const size_t iLen = ::strlen(szEndDir2);
::memcpy(szString.data,szEndDir2,iLen);
szString.data[iLen] = '\0';
szString.length = iLen;
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
}
else
{
DefaultLogger::get()->warn("Texture file name has zero length. "
"It will be skipped.");
}
}
int iMode = (int)aiShadingMode_Gouraud;
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
// add a small ambient color value - Quake 3 seems to have one
aiColor3D clr;
clr.b = clr.g = clr.r = 0.05f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
clr.b = clr.g = clr.r = 1.0f;
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
aiString szName;
szName.Set(AI_DEFAULT_MATERIAL_NAME);
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper;
pcMesh->mMaterialIndex = iNumMaterials++;
} }
else
{
if (0xFFFFFFFF != iDefaultMatIndex)
{
pcMesh->mMaterialIndex = iDefaultMatIndex;
}
else
{
MaterialHelper* pcHelper = new MaterialHelper();
if (0 == pScene->mNumMeshes) // fill in a default material
throw new ImportErrorException( "Invalid md3 file: File contains no valid mesh"); int iMode = (int)aiShadingMode_Gouraud;
pScene->mNumMaterials = iNumMaterials; pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
// now we need to generate an empty node graph aiColor3D clr;
pScene->mRootNode = new aiNode(); clr.b = clr.g = clr.r = 0.6f;
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) clr.b = clr.g = clr.r = 0.05f;
pScene->mRootNode->mMeshes[i] = i; pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper;
iDefaultMatIndex = pcMesh->mMaterialIndex = iNumMaterials++;
}
}
// go to the next surface
pcSurfaces = (const MD3::Surface*)(((unsigned char*)pcSurfaces) + pcSurfaces->OFS_END);
} }
catch (ImportErrorException* ex)
{ if (!pScene->mNumMeshes)
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer); throw new ImportErrorException( "Invalid MD3 file: File contains no valid mesh");
throw ex; pScene->mNumMaterials = iNumMaterials;
}
delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR(this->mBuffer); // now we need to generate an empty node graph
pScene->mRootNode = new aiNode();
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
pScene->mRootNode->mMeshes[i] = i;
} }

View File

@ -42,17 +42,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_MD3LOADER_H_INCLUDED #ifndef AI_MD3LOADER_H_INCLUDED
#define AI_MD3LOADER_H_INCLUDED #define AI_MD3LOADER_H_INCLUDED
#include <map>
#include "BaseImporter.h" #include "BaseImporter.h"
#include "ByteSwap.h"
#include "../include/aiTypes.h" #include "../include/aiTypes.h"
struct aiNode; struct aiNode;
#include "MD3FileData.h" #include "MD3FileData.h"
namespace Assimp namespace Assimp {
{
class MaterialHelper; class MaterialHelper;
using namespace MD3; using namespace MD3;
@ -117,10 +115,10 @@ protected:
unsigned int configFrameID; unsigned int configFrameID;
/** Header of the MD3 file */ /** Header of the MD3 file */
const MD3::Header* m_pcHeader; BE_NCONST MD3::Header* pcHeader;
/** Buffer to hold the loaded file */ /** File buffer */
const unsigned char* mBuffer; BE_NCONST unsigned char* mBuffer;
/** Size of the file, in bytes */ /** Size of the file, in bytes */
unsigned int fileSize; unsigned int fileSize;

View File

@ -53,14 +53,7 @@ http://themdcfile.planetwolfenstein.gamespy.com/MDC_File_Format.pdf
#include "../include/aiMesh.h" #include "../include/aiMesh.h"
#include "../include/aiAnim.h" #include "../include/aiAnim.h"
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) #include "./Compiler/pushpack1.h"
# pragma pack(push,1)
# define PACK_STRUCT
#elif defined( __GNUC__ )
# define PACK_STRUCT __attribute__((packed))
#else
# error Compiler not supported
#endif
namespace Assimp { namespace Assimp {
@ -188,11 +181,7 @@ struct Shader
} PACK_STRUCT; } PACK_STRUCT;
// reset packing to the original value #include "./Compiler/poppack1.h"
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# pragma pack( pop )
#endif
#undef PACK_STRUCT
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

476
code/MDCLoader.cpp 100644
View File

@ -0,0 +1,476 @@
/*
---------------------------------------------------------------------------
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 MDC importer class */
// internal headers
#include "MDCLoader.h"
#include "MD3FileData.h"
#include "MaterialSystem.h"
#include "StringComparison.h"
#include "MDCNormalTable.h" // shouldn't be included by other units
#include "ByteSwap.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"
#include "../include/assimp.hpp"
// boost headers
#include <boost/scoped_ptr.hpp>
using namespace Assimp;
using namespace Assimp::MDC;
// ------------------------------------------------------------------------------------------------
void MDC::BuildVertex(const Frame& frame,
const BaseVertex& bvert,
const CompressedVertex& cvert,
aiVector3D& vXYZOut,
aiVector3D& vNorOut)
{
// compute the position
const float xd = (cvert.xd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING;
const float yd = (cvert.yd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING;
const float zd = (cvert.zd - AI_MDC_CVERT_BIAS) * AI_MDC_DELTA_SCALING;
vXYZOut.x = frame.localOrigin.x + AI_MDC_BASE_SCALING * (bvert.x + xd);
vXYZOut.y = frame.localOrigin.y + AI_MDC_BASE_SCALING * (bvert.y + yd);
vXYZOut.z = frame.localOrigin.z + AI_MDC_BASE_SCALING * (bvert.z + zd);
// compute the normal vector .. ehm ... lookup it in the table :-)
vNorOut.x = mdcNormals[cvert.nd][0];
vNorOut.y = mdcNormals[cvert.nd][1];
vNorOut.z = mdcNormals[cvert.nd][2];
}
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
MDCImporter::MDCImporter()
{
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
MDCImporter::~MDCImporter()
{
}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool MDCImporter::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] != 'C' && extension[3] != 'c')return false;
return true;
}
// ------------------------------------------------------------------------------------------------
// Validate the header of the given MDC file
void MDCImporter::ValidateHeader()
{
AI_SWAP4( this->pcHeader->ulVersion );
AI_SWAP4( this->pcHeader->ulFlags );
AI_SWAP4( this->pcHeader->ulNumFrames );
AI_SWAP4( this->pcHeader->ulNumTags );
AI_SWAP4( this->pcHeader->ulNumSurfaces );
AI_SWAP4( this->pcHeader->ulNumSkins );
AI_SWAP4( this->pcHeader->ulOffsetBorderFrames );
if (pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_BE &&
pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_LE)
{
char szBuffer[5];
szBuffer[0] = ((char*)&pcHeader->ulIdent)[0];
szBuffer[1] = ((char*)&pcHeader->ulIdent)[1];
szBuffer[2] = ((char*)&pcHeader->ulIdent)[2];
szBuffer[3] = ((char*)&pcHeader->ulIdent)[3];
szBuffer[4] = '\0';
throw new ImportErrorException("Invalid MDC magic word: should be IDPC, the "
"magic word found is " + std::string( szBuffer ));
}
if (pcHeader->ulVersion != AI_MDC_VERSION)
DefaultLogger::get()->warn("Unsupported MDC file version (2 (AI_MDC_VERSION) was expected)");
if (pcHeader->ulOffsetBorderFrames + pcHeader->ulNumFrames * sizeof(MDC::Frame) > this->fileSize ||
pcHeader->ulOffsetSurfaces + pcHeader->ulNumSurfaces * sizeof(MDC::Surface) > this->fileSize)
{
throw new ImportErrorException("Some of the offset values in the MDC header are invalid "
"and point to something behind the file.");
}
if (this->configFrameID >= this->pcHeader->ulNumFrames)
throw new ImportErrorException("The requested frame is not available");
}
// ------------------------------------------------------------------------------------------------
// Validate the header of a given MDC file surface
void MDCImporter::ValidateSurfaceHeader(BE_NCONST MDC::Surface* pcSurf)
{
AI_SWAP4(pcSurf->ulFlags);
AI_SWAP4(pcSurf->ulNumCompFrames);
AI_SWAP4(pcSurf->ulNumBaseFrames);
AI_SWAP4(pcSurf->ulNumShaders);
AI_SWAP4(pcSurf->ulNumVertices);
AI_SWAP4(pcSurf->ulNumTriangles);
AI_SWAP4(pcSurf->ulOffsetTriangles);
AI_SWAP4(pcSurf->ulOffsetTexCoords);
AI_SWAP4(pcSurf->ulOffsetBaseVerts);
AI_SWAP4(pcSurf->ulOffsetCompVerts);
AI_SWAP4(pcSurf->ulOffsetFrameBaseFrames);
AI_SWAP4(pcSurf->ulOffsetFrameCompFrames);
AI_SWAP4(pcSurf->ulOffsetEnd);
const unsigned int iMax = this->fileSize - (unsigned int)((int8_t*)pcSurf-(int8_t*)pcHeader);
if (pcSurf->ulOffsetBaseVerts + pcSurf->ulNumVertices * sizeof(MDC::BaseVertex) > iMax ||
(pcSurf->ulNumCompFrames && pcSurf->ulOffsetCompVerts + pcSurf->ulNumVertices * sizeof(MDC::CompressedVertex) > iMax) ||
pcSurf->ulOffsetTriangles + pcSurf->ulNumTriangles * sizeof(MDC::Triangle) > iMax ||
pcSurf->ulOffsetTexCoords + pcSurf->ulNumVertices * sizeof(MDC::TexturCoord) > iMax ||
pcSurf->ulOffsetShaders + pcSurf->ulNumShaders * sizeof(MDC::Shader) > iMax ||
pcSurf->ulOffsetFrameBaseFrames + pcSurf->ulNumBaseFrames * 2 > iMax ||
(pcSurf->ulNumCompFrames && pcSurf->ulOffsetFrameCompFrames + pcSurf->ulNumCompFrames * 2 > iMax))
{
throw new ImportErrorException("Some of the offset values in the MDC surface header "
"are invalid and point somewhere behind the file.");
}
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties
void MDCImporter::SetupProperties(const Importer* pImp)
{
// The AI_CONFIG_IMPORT_MDC_KEYFRAME option overrides the
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
AI_CONFIG_IMPORT_MDC_KEYFRAME,0xffffffff)))
{
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void MDCImporter::InternReadFile(
const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
// Check whether we can read from the file
if( file.get() == NULL)
throw new ImportErrorException( "Failed to open MDC file " + pFile + ".");
// check whether the mdc file is large enough to contain the file header
fileSize = (unsigned int)file->FileSize();
if( fileSize < sizeof(MDC::Header))
throw new ImportErrorException( "MDC File is too small.");
std::vector<unsigned char> mBuffer2(fileSize);
file->Read( &mBuffer2[0], 1, fileSize);
mBuffer = &mBuffer2[0];
// validate the file header
this->pcHeader = (BE_NCONST MDC::Header*)this->mBuffer;
this->ValidateHeader();
std::vector<std::string> aszShaders;
// get a pointer to the frame we want to read
BE_NCONST MDC::Frame* pcFrame = (BE_NCONST MDC::Frame*)(this->mBuffer+
this->pcHeader->ulOffsetBorderFrames);
// no need to swap the other members, we won't need them
pcFrame += configFrameID;
AI_SWAP4( pcFrame->localOrigin[0] );
AI_SWAP4( pcFrame->localOrigin[1] );
AI_SWAP4( pcFrame->localOrigin[2] );
// get the number of valid surfaces
BE_NCONST MDC::Surface* pcSurface, *pcSurface2;
pcSurface = pcSurface2 = (BE_NCONST MDC::Surface*)(mBuffer + pcHeader->ulOffsetSurfaces);
unsigned int iNumShaders = 0;
for (unsigned int i = 0; i < pcHeader->ulNumSurfaces;++i)
{
// validate the surface header
this->ValidateSurfaceHeader(pcSurface2);
if (pcSurface2->ulNumVertices && pcSurface2->ulNumTriangles)++pScene->mNumMeshes;
iNumShaders += pcSurface2->ulNumShaders;
pcSurface2 = (const MDC::Surface*)((int8_t*)pcSurface2 + pcSurface2->ulOffsetEnd);
}
aszShaders.reserve(iNumShaders);
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
// necessary that we don't crash if an exception occurs
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
pScene->mMeshes[i] = NULL;
// now read all surfaces
unsigned int iDefaultMatIndex = 0xffffffff;
for (unsigned int i = 0, iNum = 0; i < pcHeader->ulNumSurfaces;++i)
{
if (!pcSurface->ulNumVertices || !pcSurface->ulNumTriangles)continue;
aiMesh* pcMesh = pScene->mMeshes[iNum++] = new aiMesh();
pcMesh->mNumFaces = pcSurface->ulNumTriangles;
pcMesh->mNumVertices = pcMesh->mNumFaces * 3;
// store the name of the surface for use as node name.
// FIX: make sure there is a 0 termination
const_cast<char&>(pcSurface->ucName[AI_MDC_MAXQPATH-1]) = '\0';
pcMesh->mTextureCoords[3] = (aiVector3D*)pcSurface->ucName;
// go to the first shader in the file. ignore the others.
if (pcSurface->ulNumShaders)
{
const MDC::Shader* pcShader = (const MDC::Shader*)((int8_t*)pcSurface + pcSurface->ulOffsetShaders);
pcMesh->mMaterialIndex = (unsigned int)aszShaders.size();
// create a new shader
aszShaders.push_back(std::string( pcShader->ucName, std::min(
::strlen(pcShader->ucName),sizeof(pcShader->ucName)) ));
}
// need to create a default material
else if (0xffffffff == iDefaultMatIndex)
{
pcMesh->mMaterialIndex = iDefaultMatIndex = (unsigned int)aszShaders.size();
aszShaders.push_back(std::string());
}
// otherwise assign a reference to the default material
else pcMesh->mMaterialIndex = iDefaultMatIndex;
// allocate output storage for the mesh
aiVector3D* pcVertCur = pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
aiVector3D* pcNorCur = pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];
aiVector3D* pcUVCur = pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
aiFace* pcFaceCur = pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
// create all vertices/faces
BE_NCONST MDC::Triangle* pcTriangle = (BE_NCONST MDC::Triangle*)
((int8_t*)pcSurface+pcSurface->ulOffsetTriangles);
BE_NCONST MDC::TexturCoord* const pcUVs = (BE_NCONST MDC::TexturCoord*)
((int8_t*)pcSurface+pcSurface->ulOffsetTexCoords);
// get a pointer to the uncompressed vertices
int16_t iOfs = *((int16_t*) ((int8_t*) pcSurface +
pcSurface->ulOffsetFrameBaseFrames) + this->configFrameID);
AI_SWAP2(iOfs);
BE_NCONST MDC::BaseVertex* const pcVerts = (BE_NCONST MDC::BaseVertex*)
((int8_t*)pcSurface+pcSurface->ulOffsetBaseVerts) +
((int)iOfs * pcSurface->ulNumVertices * 4);
// do the main swapping stuff ...
#if (defined AI_BUILD_BIG_ENDIAN)
// swap all triangles
for (unsigned int i = 0; i < pcSurface->ulNumTriangles;++i)
{
AI_SWAP4( pcTriangle[i].aiIndices[0] );
AI_SWAP4( pcTriangle[i].aiIndices[1] );
AI_SWAP4( pcTriangle[i].aiIndices[2] );
}
// swap all vertices
for (unsigned int i = 0; i < pcSurface->ulNumVertices*pcSurface->ulNumBaseFrames;++i)
{
AI_SWAP2( pcVerts->normal );
AI_SWAP2( pcVerts->x );
AI_SWAP2( pcVerts->y );
AI_SWAP2( pcVerts->z );
}
// swap all texture coordinates
for (unsigned int i = 0; i < pcSurface->ulNumVertices;++i)
{
AI_SWAP4( pcUVs->v );
AI_SWAP4( pcUVs->v );
}
#endif
const MDC::CompressedVertex* pcCVerts;
int16_t* mdcCompVert = NULL;
// access compressed frames for large frame numbers, but never for the first
if( this->configFrameID && pcSurface->ulNumCompFrames > 0 )
{
mdcCompVert = (int16_t*) ((int8_t*)pcSurface+pcSurface->ulOffsetFrameCompFrames) + this->configFrameID;
AI_SWAP2P(mdcCompVert);
if( *mdcCompVert >= 0 )
{
pcCVerts = (const MDC::CompressedVertex*)((int8_t*)pcSurface +
pcSurface->ulOffsetCompVerts) + *mdcCompVert * pcSurface->ulNumVertices;
}
else mdcCompVert = NULL;
}
// copy all faces
for (unsigned int iFace = 0; iFace < pcSurface->ulNumTriangles;++iFace,
++pcTriangle,++pcFaceCur)
{
const unsigned int iOutIndex = iFace*3;
pcFaceCur->mNumIndices = 3;
pcFaceCur->mIndices = new unsigned int[3];
for (unsigned int iIndex = 0; iIndex < 3;++iIndex,
++pcVertCur,++pcUVCur,++pcNorCur)
{
uint32_t quak = pcTriangle->aiIndices[iIndex];
if (quak >= pcSurface->ulNumVertices)
{
DefaultLogger::get()->error("MDC vertex index is out of range");
quak = pcSurface->ulNumVertices-1;
}
// compressed vertices?
if (mdcCompVert)
{
MDC::BuildVertex(*pcFrame,pcVerts[quak],pcCVerts[quak],
*pcVertCur,*pcNorCur);
}
else
{
// copy position
pcVertCur->x = pcVerts[quak].x * AI_MDC_BASE_SCALING;
pcVertCur->y = pcVerts[quak].y * AI_MDC_BASE_SCALING;
pcVertCur->z = pcVerts[quak].z * AI_MDC_BASE_SCALING;
// copy normals
MD3::LatLngNormalToVec3( pcVerts[quak].normal, &pcNorCur->x );
// copy texture coordinates
pcUVCur->x = pcUVs[quak].u;
pcUVCur->y = 1.0f-pcUVs[quak].v; // DX to OGL
}
pcVertCur->x += pcFrame->localOrigin[0] ;
pcVertCur->y += pcFrame->localOrigin[1] ;
pcVertCur->z += pcFrame->localOrigin[2] ;
}
// swap the face order - DX to OGL
pcFaceCur->mIndices[0] = iOutIndex + 2;
pcFaceCur->mIndices[1] = iOutIndex + 1;
pcFaceCur->mIndices[2] = iOutIndex + 0;
}
pcSurface = (BE_NCONST MDC::Surface*)((int8_t*)pcSurface + pcSurface->ulOffsetEnd);
}
// create a flat node graph with a root node and one child for each surface
if (!pScene->mNumMeshes)
throw new ImportErrorException( "Invalid MDC file: File contains no valid mesh");
else if (1 == pScene->mNumMeshes)
{
pScene->mRootNode = new aiNode();
pScene->mRootNode->mName.Set(std::string((const char*)pScene->mMeshes[0]->mTextureCoords[3]));
pScene->mRootNode->mNumMeshes = 1;
pScene->mRootNode->mMeshes = new unsigned int[1];
pScene->mRootNode->mMeshes[0] = 0;
}
else
{
pScene->mRootNode = new aiNode();
pScene->mRootNode->mNumChildren = pScene->mNumMeshes;
pScene->mRootNode->mChildren = new aiNode*[pScene->mNumMeshes];
pScene->mRootNode->mName.Set("<root>");
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
aiNode* pcNode = pScene->mRootNode->mChildren[i] = new aiNode();
pcNode->mParent = pScene->mRootNode;
pcNode->mName.Set(std::string((const char*)pScene->mMeshes[i]->mTextureCoords[3]));
pcNode->mNumMeshes = 1;
pcNode->mMeshes = new unsigned int[1];
pcNode->mMeshes[0] = i;
}
}
// make sure we invalidate the pointer to the mesh name
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
pScene->mMeshes[i]->mTextureCoords[3] = NULL;
// create materials
pScene->mNumMaterials = aszShaders.size();
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
{
MaterialHelper* pcMat = new MaterialHelper();
pScene->mMaterials[i] = pcMat;
const std::string& name = aszShaders[i];
int iMode = (int)aiShadingMode_Gouraud;
pcMat->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
// add a small ambient color value - RtCW seems to have one
aiColor3D clr;
clr.b = clr.g = clr.r = 0.05f;
pcMat->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
if (name.length())clr.b = clr.g = clr.r = 1.0f;
else clr.b = clr.g = clr.r = 0.6f;
pcMat->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
pcMat->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
if (name.length())
{
aiString path;
path.Set(name);
pcMat->AddProperty(&path,AI_MATKEY_TEXTURE_DIFFUSE(0));
}
}
}

132
code/MDCLoader.h 100644
View File

@ -0,0 +1,132 @@
/*
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 MDC importer class. */
#ifndef AI_MDCLOADER_H_INCLUDED
#define AI_MDCLOADER_H_INCLUDED
#include "../include/aiTypes.h"
#include "BaseImporter.h"
#include "MDCFileData.h"
#include "ByteSwap.h"
namespace Assimp
{
using namespace MDC;
// ---------------------------------------------------------------------------
/** Used to load MDC files
*/
class MDCImporter : public BaseImporter
{
friend class Importer;
protected:
/** Constructor to be privately used by Importer */
MDCImporter();
/** Destructor, private as well */
~MDCImporter();
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;
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
protected:
// -------------------------------------------------------------------
/** Called by Importer::GetExtensionList() for each loaded importer.
* See BaseImporter::GetExtensionList() for details
*/
void GetExtensionList(std::string& append)
{
append.append("*.mdc");
}
// -------------------------------------------------------------------
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
protected:
// -------------------------------------------------------------------
/** Validate the header of the file
*/
void ValidateHeader();
// -------------------------------------------------------------------
/** Validate the header of a MDC surface
*/
void ValidateSurfaceHeader(BE_NCONST MDC::Surface* pcSurf);
protected:
/** Configuration option: frame to be loaded */
unsigned int configFrameID;
/** Header of the MDC file */
BE_NCONST MDC::Header* pcHeader;
/** Buffer to hold the loaded file */
unsigned char* mBuffer;
/** size of the file, in bytes */
unsigned int fileSize;
};
} // end of namespace Assimp
#endif // AI_3DSIMPORTER_H_INC

View File

@ -0,0 +1,299 @@
/* -----------------------------------------------------------------------------
PicoModel Library
Copyright (c) 2002, Randy Reddig & seaw0lf
All rights reserved.
Redistribution and use 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 names of the copyright holders nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
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.
----------------------------------------------------------------------------- */
#if (!defined MDC_NORMAL_TABLE_INCLUDED)
#define MDC_NORMAL_TABLE_INCLUDED
/* mdc decoding normal table */
float mdcNormals[ 256 ][ 3 ] =
{
{ 1.000000f, 0.000000f, 0.000000f },
{ 0.980785f, 0.195090f, 0.000000f },
{ 0.923880f, 0.382683f, 0.000000f },
{ 0.831470f, 0.555570f, 0.000000f },
{ 0.707107f, 0.707107f, 0.000000f },
{ 0.555570f, 0.831470f, 0.000000f },
{ 0.382683f, 0.923880f, 0.000000f },
{ 0.195090f, 0.980785f, 0.000000f },
{ -0.000000f, 1.000000f, 0.000000f },
{ -0.195090f, 0.980785f, 0.000000f },
{ -0.382683f, 0.923880f, 0.000000f },
{ -0.555570f, 0.831470f, 0.000000f },
{ -0.707107f, 0.707107f, 0.000000f },
{ -0.831470f, 0.555570f, 0.000000f },
{ -0.923880f, 0.382683f, 0.000000f },
{ -0.980785f, 0.195090f, 0.000000f },
{ -1.000000f, -0.000000f, 0.000000f },
{ -0.980785f, -0.195090f, 0.000000f },
{ -0.923880f, -0.382683f, 0.000000f },
{ -0.831470f, -0.555570f, 0.000000f },
{ -0.707107f, -0.707107f, 0.000000f },
{ -0.555570f, -0.831469f, 0.000000f },
{ -0.382684f, -0.923880f, 0.000000f },
{ -0.195090f, -0.980785f, 0.000000f },
{ 0.000000f, -1.000000f, 0.000000f },
{ 0.195090f, -0.980785f, 0.000000f },
{ 0.382684f, -0.923879f, 0.000000f },
{ 0.555570f, -0.831470f, 0.000000f },
{ 0.707107f, -0.707107f, 0.000000f },
{ 0.831470f, -0.555570f, 0.000000f },
{ 0.923880f, -0.382683f, 0.000000f },
{ 0.980785f, -0.195090f, 0.000000f },
{ 0.980785f, 0.000000f, -0.195090f },
{ 0.956195f, 0.218245f, -0.195090f },
{ 0.883657f, 0.425547f, -0.195090f },
{ 0.766809f, 0.611510f, -0.195090f },
{ 0.611510f, 0.766809f, -0.195090f },
{ 0.425547f, 0.883657f, -0.195090f },
{ 0.218245f, 0.956195f, -0.195090f },
{ -0.000000f, 0.980785f, -0.195090f },
{ -0.218245f, 0.956195f, -0.195090f },
{ -0.425547f, 0.883657f, -0.195090f },
{ -0.611510f, 0.766809f, -0.195090f },
{ -0.766809f, 0.611510f, -0.195090f },
{ -0.883657f, 0.425547f, -0.195090f },
{ -0.956195f, 0.218245f, -0.195090f },
{ -0.980785f, -0.000000f, -0.195090f },
{ -0.956195f, -0.218245f, -0.195090f },
{ -0.883657f, -0.425547f, -0.195090f },
{ -0.766809f, -0.611510f, -0.195090f },
{ -0.611510f, -0.766809f, -0.195090f },
{ -0.425547f, -0.883657f, -0.195090f },
{ -0.218245f, -0.956195f, -0.195090f },
{ 0.000000f, -0.980785f, -0.195090f },
{ 0.218245f, -0.956195f, -0.195090f },
{ 0.425547f, -0.883657f, -0.195090f },
{ 0.611510f, -0.766809f, -0.195090f },
{ 0.766809f, -0.611510f, -0.195090f },
{ 0.883657f, -0.425547f, -0.195090f },
{ 0.956195f, -0.218245f, -0.195090f },
{ 0.923880f, 0.000000f, -0.382683f },
{ 0.892399f, 0.239118f, -0.382683f },
{ 0.800103f, 0.461940f, -0.382683f },
{ 0.653281f, 0.653281f, -0.382683f },
{ 0.461940f, 0.800103f, -0.382683f },
{ 0.239118f, 0.892399f, -0.382683f },
{ -0.000000f, 0.923880f, -0.382683f },
{ -0.239118f, 0.892399f, -0.382683f },
{ -0.461940f, 0.800103f, -0.382683f },
{ -0.653281f, 0.653281f, -0.382683f },
{ -0.800103f, 0.461940f, -0.382683f },
{ -0.892399f, 0.239118f, -0.382683f },
{ -0.923880f, -0.000000f, -0.382683f },
{ -0.892399f, -0.239118f, -0.382683f },
{ -0.800103f, -0.461940f, -0.382683f },
{ -0.653282f, -0.653281f, -0.382683f },
{ -0.461940f, -0.800103f, -0.382683f },
{ -0.239118f, -0.892399f, -0.382683f },
{ 0.000000f, -0.923880f, -0.382683f },
{ 0.239118f, -0.892399f, -0.382683f },
{ 0.461940f, -0.800103f, -0.382683f },
{ 0.653281f, -0.653282f, -0.382683f },
{ 0.800103f, -0.461940f, -0.382683f },
{ 0.892399f, -0.239117f, -0.382683f },
{ 0.831470f, 0.000000f, -0.555570f },
{ 0.790775f, 0.256938f, -0.555570f },
{ 0.672673f, 0.488726f, -0.555570f },
{ 0.488726f, 0.672673f, -0.555570f },
{ 0.256938f, 0.790775f, -0.555570f },
{ -0.000000f, 0.831470f, -0.555570f },
{ -0.256938f, 0.790775f, -0.555570f },
{ -0.488726f, 0.672673f, -0.555570f },
{ -0.672673f, 0.488726f, -0.555570f },
{ -0.790775f, 0.256938f, -0.555570f },
{ -0.831470f, -0.000000f, -0.555570f },
{ -0.790775f, -0.256938f, -0.555570f },
{ -0.672673f, -0.488726f, -0.555570f },
{ -0.488725f, -0.672673f, -0.555570f },
{ -0.256938f, -0.790775f, -0.555570f },
{ 0.000000f, -0.831470f, -0.555570f },
{ 0.256938f, -0.790775f, -0.555570f },
{ 0.488725f, -0.672673f, -0.555570f },
{ 0.672673f, -0.488726f, -0.555570f },
{ 0.790775f, -0.256938f, -0.555570f },
{ 0.707107f, 0.000000f, -0.707107f },
{ 0.653281f, 0.270598f, -0.707107f },
{ 0.500000f, 0.500000f, -0.707107f },
{ 0.270598f, 0.653281f, -0.707107f },
{ -0.000000f, 0.707107f, -0.707107f },
{ -0.270598f, 0.653282f, -0.707107f },
{ -0.500000f, 0.500000f, -0.707107f },
{ -0.653281f, 0.270598f, -0.707107f },
{ -0.707107f, -0.000000f, -0.707107f },
{ -0.653281f, -0.270598f, -0.707107f },
{ -0.500000f, -0.500000f, -0.707107f },
{ -0.270598f, -0.653281f, -0.707107f },
{ 0.000000f, -0.707107f, -0.707107f },
{ 0.270598f, -0.653281f, -0.707107f },
{ 0.500000f, -0.500000f, -0.707107f },
{ 0.653282f, -0.270598f, -0.707107f },
{ 0.555570f, 0.000000f, -0.831470f },
{ 0.481138f, 0.277785f, -0.831470f },
{ 0.277785f, 0.481138f, -0.831470f },
{ -0.000000f, 0.555570f, -0.831470f },
{ -0.277785f, 0.481138f, -0.831470f },
{ -0.481138f, 0.277785f, -0.831470f },
{ -0.555570f, -0.000000f, -0.831470f },
{ -0.481138f, -0.277785f, -0.831470f },
{ -0.277785f, -0.481138f, -0.831470f },
{ 0.000000f, -0.555570f, -0.831470f },
{ 0.277785f, -0.481138f, -0.831470f },
{ 0.481138f, -0.277785f, -0.831470f },
{ 0.382683f, 0.000000f, -0.923880f },
{ 0.270598f, 0.270598f, -0.923880f },
{ -0.000000f, 0.382683f, -0.923880f },
{ -0.270598f, 0.270598f, -0.923880f },
{ -0.382683f, -0.000000f, -0.923880f },
{ -0.270598f, -0.270598f, -0.923880f },
{ 0.000000f, -0.382683f, -0.923880f },
{ 0.270598f, -0.270598f, -0.923880f },
{ 0.195090f, 0.000000f, -0.980785f },
{ -0.000000f, 0.195090f, -0.980785f },
{ -0.195090f, -0.000000f, -0.980785f },
{ 0.000000f, -0.195090f, -0.980785f },
{ 0.980785f, 0.000000f, 0.195090f },
{ 0.956195f, 0.218245f, 0.195090f },
{ 0.883657f, 0.425547f, 0.195090f },
{ 0.766809f, 0.611510f, 0.195090f },
{ 0.611510f, 0.766809f, 0.195090f },
{ 0.425547f, 0.883657f, 0.195090f },
{ 0.218245f, 0.956195f, 0.195090f },
{ -0.000000f, 0.980785f, 0.195090f },
{ -0.218245f, 0.956195f, 0.195090f },
{ -0.425547f, 0.883657f, 0.195090f },
{ -0.611510f, 0.766809f, 0.195090f },
{ -0.766809f, 0.611510f, 0.195090f },
{ -0.883657f, 0.425547f, 0.195090f },
{ -0.956195f, 0.218245f, 0.195090f },
{ -0.980785f, -0.000000f, 0.195090f },
{ -0.956195f, -0.218245f, 0.195090f },
{ -0.883657f, -0.425547f, 0.195090f },
{ -0.766809f, -0.611510f, 0.195090f },
{ -0.611510f, -0.766809f, 0.195090f },
{ -0.425547f, -0.883657f, 0.195090f },
{ -0.218245f, -0.956195f, 0.195090f },
{ 0.000000f, -0.980785f, 0.195090f },
{ 0.218245f, -0.956195f, 0.195090f },
{ 0.425547f, -0.883657f, 0.195090f },
{ 0.611510f, -0.766809f, 0.195090f },
{ 0.766809f, -0.611510f, 0.195090f },
{ 0.883657f, -0.425547f, 0.195090f },
{ 0.956195f, -0.218245f, 0.195090f },
{ 0.923880f, 0.000000f, 0.382683f },
{ 0.892399f, 0.239118f, 0.382683f },
{ 0.800103f, 0.461940f, 0.382683f },
{ 0.653281f, 0.653281f, 0.382683f },
{ 0.461940f, 0.800103f, 0.382683f },
{ 0.239118f, 0.892399f, 0.382683f },
{ -0.000000f, 0.923880f, 0.382683f },
{ -0.239118f, 0.892399f, 0.382683f },
{ -0.461940f, 0.800103f, 0.382683f },
{ -0.653281f, 0.653281f, 0.382683f },
{ -0.800103f, 0.461940f, 0.382683f },
{ -0.892399f, 0.239118f, 0.382683f },
{ -0.923880f, -0.000000f, 0.382683f },
{ -0.892399f, -0.239118f, 0.382683f },
{ -0.800103f, -0.461940f, 0.382683f },
{ -0.653282f, -0.653281f, 0.382683f },
{ -0.461940f, -0.800103f, 0.382683f },
{ -0.239118f, -0.892399f, 0.382683f },
{ 0.000000f, -0.923880f, 0.382683f },
{ 0.239118f, -0.892399f, 0.382683f },
{ 0.461940f, -0.800103f, 0.382683f },
{ 0.653281f, -0.653282f, 0.382683f },
{ 0.800103f, -0.461940f, 0.382683f },
{ 0.892399f, -0.239117f, 0.382683f },
{ 0.831470f, 0.000000f, 0.555570f },
{ 0.790775f, 0.256938f, 0.555570f },
{ 0.672673f, 0.488726f, 0.555570f },
{ 0.488726f, 0.672673f, 0.555570f },
{ 0.256938f, 0.790775f, 0.555570f },
{ -0.000000f, 0.831470f, 0.555570f },
{ -0.256938f, 0.790775f, 0.555570f },
{ -0.488726f, 0.672673f, 0.555570f },
{ -0.672673f, 0.488726f, 0.555570f },
{ -0.790775f, 0.256938f, 0.555570f },
{ -0.831470f, -0.000000f, 0.555570f },
{ -0.790775f, -0.256938f, 0.555570f },
{ -0.672673f, -0.488726f, 0.555570f },
{ -0.488725f, -0.672673f, 0.555570f },
{ -0.256938f, -0.790775f, 0.555570f },
{ 0.000000f, -0.831470f, 0.555570f },
{ 0.256938f, -0.790775f, 0.555570f },
{ 0.488725f, -0.672673f, 0.555570f },
{ 0.672673f, -0.488726f, 0.555570f },
{ 0.790775f, -0.256938f, 0.555570f },
{ 0.707107f, 0.000000f, 0.707107f },
{ 0.653281f, 0.270598f, 0.707107f },
{ 0.500000f, 0.500000f, 0.707107f },
{ 0.270598f, 0.653281f, 0.707107f },
{ -0.000000f, 0.707107f, 0.707107f },
{ -0.270598f, 0.653282f, 0.707107f },
{ -0.500000f, 0.500000f, 0.707107f },
{ -0.653281f, 0.270598f, 0.707107f },
{ -0.707107f, -0.000000f, 0.707107f },
{ -0.653281f, -0.270598f, 0.707107f },
{ -0.500000f, -0.500000f, 0.707107f },
{ -0.270598f, -0.653281f, 0.707107f },
{ 0.000000f, -0.707107f, 0.707107f },
{ 0.270598f, -0.653281f, 0.707107f },
{ 0.500000f, -0.500000f, 0.707107f },
{ 0.653282f, -0.270598f, 0.707107f },
{ 0.555570f, 0.000000f, 0.831470f },
{ 0.481138f, 0.277785f, 0.831470f },
{ 0.277785f, 0.481138f, 0.831470f },
{ -0.000000f, 0.555570f, 0.831470f },
{ -0.277785f, 0.481138f, 0.831470f },
{ -0.481138f, 0.277785f, 0.831470f },
{ -0.555570f, -0.000000f, 0.831470f },
{ -0.481138f, -0.277785f, 0.831470f },
{ -0.277785f, -0.481138f, 0.831470f },
{ 0.000000f, -0.555570f, 0.831470f },
{ 0.277785f, -0.481138f, 0.831470f },
{ 0.481138f, -0.277785f, 0.831470f },
{ 0.382683f, 0.000000f, 0.923880f },
{ 0.270598f, 0.270598f, 0.923880f },
{ -0.000000f, 0.382683f, 0.923880f },
{ -0.270598f, 0.270598f, 0.923880f },
{ -0.382683f, -0.000000f, 0.923880f },
{ -0.270598f, -0.270598f, 0.923880f },
{ 0.000000f, -0.382683f, 0.923880f },
{ 0.270598f, -0.270598f, 0.923880f },
{ 0.195090f, 0.000000f, 0.980785f },
{ -0.000000f, 0.195090f, 0.980785f },
{ -0.195090f, -0.000000f, 0.980785f },
{ 0.000000f, -0.195090f, 0.980785f }
};
#endif // !! MDC_NORMAL_TABLE_INCLUDED

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "MDLDefaultColorMap.h" #include "MDLDefaultColorMap.h"
#include "MD2FileData.h" #include "MD2FileData.h"
#include "qnan.h" #include "qnan.h"
#include "ByteSwap.h"
// public ASSIMP headers // public ASSIMP headers
#include "../include/DefaultLogger.h" #include "../include/DefaultLogger.h"
@ -62,8 +63,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
extern float g_avNormals[162][3];
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// macros used by the MDL7 loader // macros used by the MDL7 loader
@ -81,7 +80,6 @@ extern float g_avNormals[162][3];
_AI_MDL7_ACCESS(_data,_index,_limit,MDL::Vertex_MDL7) _AI_MDL7_ACCESS(_data,_index,_limit,MDL::Vertex_MDL7)
#endif #endif
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
MDLImporter::MDLImporter() MDLImporter::MDLImporter()
@ -116,36 +114,34 @@ bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
return true; return true;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup configuration properties
void MDLImporter::SetupProperties(const Importer* pImp)
{
// The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the
// AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option.
if(0xffffffff == (this->configFrameID = pImp->GetProperty(
AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff)))
{
this->configFrameID = pImp->GetProperty(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void MDLImporter::InternReadFile( void MDLImporter::InternReadFile( const std::string& pFile,
const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) aiScene* pScene, IOSystem* pIOHandler)
{ {
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
// Check whether we can read from the file // Check whether we can read from the file
if( file.get() == NULL) if( file.get() == NULL)
{
throw new ImportErrorException( "Failed to open MDL file " + pFile + "."); 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 ... // this should work for all other types of MDL files, too ...
// the quake header is one of the smallest, afaik // the quake header is one of the smallest, afaik
this->iFileSize = (unsigned int)file->FileSize(); this->iFileSize = (unsigned int)file->FileSize();
if( this->iFileSize < sizeof(MDL::Header)) if( this->iFileSize < sizeof(MDL::Header))
{
throw new ImportErrorException( "MDL File is too small."); throw new ImportErrorException( "MDL File is too small.");
}
// allocate storage and copy the contents of the file to a memory buffer // allocate storage and copy the contents of the file to a memory buffer
this->pScene = pScene; this->pScene = pScene;
@ -162,89 +158,93 @@ void MDLImporter::InternReadFile(
// determine the file subtype and call the appropriate member function // determine the file subtype and call the appropriate member function
try { try {
// Original Quake1 format // Original Quake1 format
if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord || if (AI_MDL_MAGIC_NUMBER_BE == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE == iMagicWord) AI_MDL_MAGIC_NUMBER_LE == iMagicWord)
{ {
DefaultLogger::get()->debug("MDL subtype: Quake 1, magic word is IDPO"); DefaultLogger::get()->debug("MDL subtype: Quake 1, magic word is IDPO");
this->iGSFileVersion = 0; this->iGSFileVersion = 0;
this->InternReadFile_Quake1(); this->InternReadFile_Quake1();
} }
// GameStudio A<old> MDL2 format - used by some test models that come with 3DGS // GameStudio A<old> MDL2 format - used by some test models that come with 3DGS
else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord || else if (AI_MDL_MAGIC_NUMBER_BE_GS3 == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord) AI_MDL_MAGIC_NUMBER_LE_GS3 == iMagicWord)
{ {
DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A2, magic word is MDL2"); DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A2, magic word is MDL2");
this->iGSFileVersion = 2; this->iGSFileVersion = 2;
this->InternReadFile_Quake1(); this->InternReadFile_Quake1();
} }
// GameStudio A4 MDL3 format // GameStudio A4 MDL3 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord || else if (AI_MDL_MAGIC_NUMBER_BE_GS4 == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord) AI_MDL_MAGIC_NUMBER_LE_GS4 == iMagicWord)
{ {
DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL3"); DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL3");
this->iGSFileVersion = 3; this->iGSFileVersion = 3;
this->InternReadFile_3DGS_MDL345(); this->InternReadFile_3DGS_MDL345();
} }
// GameStudio A5+ MDL4 format // GameStudio A5+ MDL4 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord || else if (AI_MDL_MAGIC_NUMBER_BE_GS5a == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord) AI_MDL_MAGIC_NUMBER_LE_GS5a == iMagicWord)
{ {
DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL4"); DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A4, magic word is MDL4");
this->iGSFileVersion = 4; this->iGSFileVersion = 4;
this->InternReadFile_3DGS_MDL345(); this->InternReadFile_3DGS_MDL345();
} }
// GameStudio A5+ MDL5 format // GameStudio A5+ MDL5 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord || else if (AI_MDL_MAGIC_NUMBER_BE_GS5b == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord) AI_MDL_MAGIC_NUMBER_LE_GS5b == iMagicWord)
{ {
DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A5, magic word is MDL5"); DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A5, magic word is MDL5");
this->iGSFileVersion = 5; this->iGSFileVersion = 5;
this->InternReadFile_3DGS_MDL345(); this->InternReadFile_3DGS_MDL345();
} }
// GameStudio A6+ MDL6 format (not sure whether it is really existing ... ) // GameStudio A6+ MDL6 format (not sure whether it is really existing ... )
else if (AI_MDL_MAGIC_NUMBER_BE_GS6 == iMagicWord || else if (AI_MDL_MAGIC_NUMBER_BE_GS6 == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE_GS6 == iMagicWord) AI_MDL_MAGIC_NUMBER_LE_GS6 == iMagicWord)
{ {
DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A6, magic word is MDL6"); DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A6, magic word is MDL6");
this->iGSFileVersion = 6; this->iGSFileVersion = 6;
this->InternReadFile_3DGS_MDL345(); this->InternReadFile_3DGS_MDL345();
} }
// GameStudio A7 MDL7 format // GameStudio A7 MDL7 format
else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord || else if (AI_MDL_MAGIC_NUMBER_BE_GS7 == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord) AI_MDL_MAGIC_NUMBER_LE_GS7 == iMagicWord)
{ {
DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A7, magic word is MDL7"); DefaultLogger::get()->debug("MDL subtype: 3D GameStudio A7, magic word is MDL7");
this->iGSFileVersion = 7; this->iGSFileVersion = 7;
this->InternReadFile_3DGS_MDL7(); this->InternReadFile_3DGS_MDL7();
} }
// IDST/IDSQ Format (CS:S/HL², etc ...) // IDST/IDSQ Format (CS:S/HL², etc ...)
else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord ||
AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord) AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord)
{ {
DefaultLogger::get()->debug("MDL subtype: CS:S\\HL², magic word is IDST/IDSQ"); DefaultLogger::get()->debug("MDL subtype: CS:S\\HL², magic word is IDST/IDSQ");
this->iGSFileVersion = 0; this->iGSFileVersion = 0;
this->InternReadFile_HL2(); this->InternReadFile_HL2();
} }
else else
{ {
// print the magic word to the logger // print the magic word to the logger
char szBuffer[5]; char szBuffer[5];
szBuffer[0] = ((char*)&iMagicWord)[0]; szBuffer[0] = ((char*)&iMagicWord)[0];
szBuffer[1] = ((char*)&iMagicWord)[1]; szBuffer[1] = ((char*)&iMagicWord)[1];
szBuffer[2] = ((char*)&iMagicWord)[2]; szBuffer[2] = ((char*)&iMagicWord)[2];
szBuffer[3] = ((char*)&iMagicWord)[3]; szBuffer[3] = ((char*)&iMagicWord)[3];
szBuffer[4] = '\0'; szBuffer[4] = '\0';
// we're definitely unable to load this file // we're definitely unable to load this file
throw new ImportErrorException( "Unknown MDL subformat " + pFile + throw new ImportErrorException( "Unknown MDL subformat " + pFile +
". Magic word (" + szBuffer + ") is not known"); ". Magic word (" + szBuffer + ") is not known");
} }
} catch (ImportErrorException* ex) { }
catch (ImportErrorException* ex) {
delete[] this->mBuffer; delete[] this->mBuffer;
AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
AI_DEBUG_INVALIDATE_PTR(this->pIOHandler);
AI_DEBUG_INVALIDATE_PTR(this->pScene);
throw ex; throw ex;
} }
@ -253,7 +253,6 @@ void MDLImporter::InternReadFile(
AI_DEBUG_INVALIDATE_PTR(this->mBuffer); AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
AI_DEBUG_INVALIDATE_PTR(this->pIOHandler); AI_DEBUG_INVALIDATE_PTR(this->pIOHandler);
AI_DEBUG_INVALIDATE_PTR(this->pScene); AI_DEBUG_INVALIDATE_PTR(this->pScene);
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MDLImporter::SizeCheck(const void* szPos) void MDLImporter::SizeCheck(const void* szPos)
@ -279,12 +278,7 @@ void MDLImporter::SizeCheck(const void* szPos, const char* szFile, unsigned int
if (szFilePtr)++szFilePtr; if (szFilePtr)++szFilePtr;
char szBuffer[1024]; char szBuffer[1024];
#if _MSC_VER >= 1400 ::sprintf(szBuffer,"Invalid MDL file. The file is too small "
::sprintf_s(szBuffer,
#else
::sprintf(szBuffer,
#endif
"Invalid MDL file. The file is too small "
"or contains invalid data (File: %s Line: %i)",szFilePtr,iLine); "or contains invalid data (File: %s Line: %i)",szFilePtr,iLine);
throw new ImportErrorException(szBuffer); throw new ImportErrorException(szBuffer);
@ -295,56 +289,67 @@ void MDLImporter::ValidateHeader_Quake1(const MDL::Header* pcHeader)
{ {
// some values may not be NULL // some values may not be NULL
if (!pcHeader->num_frames) if (!pcHeader->num_frames)
{
throw new ImportErrorException( "[Quake 1 MDL] There are no frames in the file"); throw new ImportErrorException( "[Quake 1 MDL] There are no frames in the file");
}
if (!pcHeader->num_verts) if (!pcHeader->num_verts)
{
throw new ImportErrorException( "[Quake 1 MDL] There are no vertices in the file"); throw new ImportErrorException( "[Quake 1 MDL] There are no vertices in the file");
}
if (!pcHeader->num_tris) if (!pcHeader->num_tris)
{
throw new ImportErrorException( "[Quake 1 MDL] There are no triangles in the file"); throw new ImportErrorException( "[Quake 1 MDL] There are no triangles in the file");
}
// check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only // check whether the maxima are exceeded ...however, this applies for Quake 1 MDLs only
if (!this->iGSFileVersion) if (!this->iGSFileVersion)
{ {
if (pcHeader->num_verts > AI_MDL_MAX_VERTS) if (pcHeader->num_verts > AI_MDL_MAX_VERTS)
{
DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices"); DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_VERTS vertices");
}
if (pcHeader->num_tris > AI_MDL_MAX_TRIANGLES) if (pcHeader->num_tris > AI_MDL_MAX_TRIANGLES)
{
DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_TRIANGLES triangles"); DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_TRIANGLES triangles");
}
if (pcHeader->num_frames > AI_MDL_MAX_FRAMES) if (pcHeader->num_frames > AI_MDL_MAX_FRAMES)
{
DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_FRAMES frames"); DefaultLogger::get()->warn("Quake 1 MDL model has more than AI_MDL_MAX_FRAMES frames");
}
// (this does not apply for 3DGS MDLs) // (this does not apply for 3DGS MDLs)
if (!this->iGSFileVersion && pcHeader->version != AI_MDL_VERSION) if (!this->iGSFileVersion && pcHeader->version != AI_MDL_VERSION)
{
DefaultLogger::get()->warn("Quake 1 MDL model has an unknown version: AI_MDL_VERSION (=6) is " DefaultLogger::get()->warn("Quake 1 MDL model has an unknown version: AI_MDL_VERSION (=6) is "
"the expected file format version"); "the expected file format version");
} if(pcHeader->num_skins && (!pcHeader->skinwidth || !pcHeader->skinheight))
DefaultLogger::get()->warn("Skin width or height are 0");
if (pcHeader->num_skins)
{
if(!pcHeader->skinwidth || !pcHeader->skinheight)
{
DefaultLogger::get()->warn("Skin width or height are 0. Division through "
"zero would occur ...");
}
}
} }
} }
#ifdef AI_BUILD_BIG_ENDIAN
// ------------------------------------------------------------------------------------------------
void FlipQuakeHeader(BE_NCONST MDL::Header* pcHeader)
{
ByteSwap::Swap4(& pcHeader->ident);
ByteSwap::Swap4(& pcHeader->version);
ByteSwap::Swap4(& pcHeader->boundingradius);
ByteSwap::Swap4(& pcHeader->flags);
ByteSwap::Swap4(& pcHeader->num_frames);
ByteSwap::Swap4(& pcHeader->num_skins);
ByteSwap::Swap4(& pcHeader->num_tris);
ByteSwap::Swap4(& pcHeader->num_verts);
for (unsigned int i = 0; i < 3;++i)
{
ByteSwap::Swap4(& pcHeader->scale[i]);
ByteSwap::Swap4(& pcHeader->translate[i]);
}
ByteSwap::Swap4(& pcHeader->size);
ByteSwap::Swap4(& pcHeader->skinheight);
ByteSwap::Swap4(& pcHeader->skin);
}
#endif
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MDLImporter::InternReadFile_Quake1( ) void MDLImporter::InternReadFile_Quake1( )
{ {
ai_assert(NULL != pScene); ai_assert(NULL != pScene);
const MDL::Header* pcHeader = (const MDL::Header*)this->mBuffer; BE_NCONST MDL::Header* pcHeader = (BE_NCONST MDL::Header*)this->mBuffer;
#ifdef AI_BUILD_BIG_ENDIAN
FlipQuakeHeader(pcHeader);
#endif
ValidateHeader_Quake1(pcHeader); ValidateHeader_Quake1(pcHeader);
// current cursor position in the file // current cursor position in the file
@ -353,13 +358,16 @@ void MDLImporter::InternReadFile_Quake1( )
// need to read all textures // need to read all textures
for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i) for (unsigned int i = 0; i < (unsigned int)pcHeader->num_skins;++i)
{ {
union{const MDL::Skin* pcSkin;const MDL::GroupSkin* pcGroupSkin;}; union{BE_NCONST MDL::Skin* pcSkin;BE_NCONST MDL::GroupSkin* pcGroupSkin;};
pcSkin = (const MDL::Skin*)szCurrent; pcSkin = (BE_NCONST MDL::Skin*)szCurrent;
AI_SWAP4( pcSkin->group );
// Quake 1 groupskins // Quake 1 groupskins
if (1 == pcSkin->group) if (1 == pcSkin->group)
{ {
AI_SWAP4( pcGroupSkin->nb );
// need to skip multiple images // need to skip multiple images
const unsigned int iNumImages = (unsigned int)pcGroupSkin->nb; const unsigned int iNumImages = (unsigned int)pcGroupSkin->nb;
szCurrent += sizeof(uint32_t) * 2; szCurrent += sizeof(uint32_t) * 2;
@ -413,6 +421,25 @@ void MDLImporter::InternReadFile_Quake1( )
VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts)); VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts));
#ifdef AI_BUILD_BIG_ENDIAN
for (unsigned int i = 0; i<pcHeader->num_verts;++i)
{
AI_SWAP4( pcTexCoords[i].onseam );
AI_SWAP4( pcTexCoords[i].s );
AI_SWAP4( pcTexCoords[i].t );
}
for (unsigned int i = 0; i<pcHeader->num_tris;++i)
{
AI_SWAP4( pcTriangles[i].facesfront);
AI_SWAP4( pcTriangles[i].vertex[0]);
AI_SWAP4( pcTriangles[i].vertex[1]);
AI_SWAP4( pcTriangles[i].vertex[2]);
}
#endif
// setup materials // setup materials
this->SetupMaterialProperties_3DGS_MDL5_Quake1(); this->SetupMaterialProperties_3DGS_MDL5_Quake1();
@ -453,7 +480,6 @@ void MDLImporter::InternReadFile_Quake1( )
if (iIndex >= (unsigned int)pcHeader->num_verts) if (iIndex >= (unsigned int)pcHeader->num_verts)
{ {
iIndex = pcHeader->num_verts-1; iIndex = pcHeader->num_verts-1;
DefaultLogger::get()->warn("Index overflow in Q1-MDL vertex list."); DefaultLogger::get()->warn("Index overflow in Q1-MDL vertex list.");
} }
@ -461,16 +487,16 @@ void MDLImporter::InternReadFile_Quake1( )
vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
vec.x += pcHeader->translate[0]; vec.x += pcHeader->translate[0];
// (flip z and y component) vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
vec.z = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; vec.y += pcHeader->translate[1];
vec.z += pcHeader->translate[1]; vec.y *= -1.0f;
vec.y = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
vec.y += pcHeader->translate[2]; vec.z += pcHeader->translate[2];
// read the normal vector from the precalculated normal table // read the normal vector from the precalculated normal table
MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
std::swap ( pcMesh->mNormals[iCurrent].y,pcMesh->mNormals[iCurrent].z ); pcMesh->mNormals[iCurrent].y *= -1.0f;
// read texture coordinates // read texture coordinates
float s = (float)pcTexCoords[iIndex].s; float s = (float)pcTexCoords[iIndex].s;
@ -546,6 +572,9 @@ void MDLImporter::InternReadFile_3DGS_MDL345( )
// the header of MDL 3/4/5 is nearly identical to the original Quake1 header // the header of MDL 3/4/5 is nearly identical to the original Quake1 header
const MDL::Header* pcHeader = (const MDL::Header*)this->mBuffer; const MDL::Header* pcHeader = (const MDL::Header*)this->mBuffer;
#ifdef AI_BUILD_BIG_ENDIAN
FlipQuakeHeader(pcHeader);
#endif
this->ValidateHeader_Quake1(pcHeader); this->ValidateHeader_Quake1(pcHeader);
// current cursor position in the file // current cursor position in the file
@ -584,6 +613,26 @@ void MDLImporter::InternReadFile_3DGS_MDL345( )
const MDL::Triangle_MDL3* pcTriangles = (const MDL::Triangle_MDL3*)szCurrent; const MDL::Triangle_MDL3* pcTriangles = (const MDL::Triangle_MDL3*)szCurrent;
szCurrent += sizeof(MDL::Triangle_MDL3) * pcHeader->num_tris; szCurrent += sizeof(MDL::Triangle_MDL3) * pcHeader->num_tris;
#ifdef AI_BUILD_BIG_ENDIAN
for (unsigned int i = 0; i<pcHeader->synctype;++i)
{
AI_SWAP2( pcTexCoords[i].u );
AI_SWAP2( pcTexCoords[i].v );
}
for (unsigned int i = 0; i<pcHeader->num_tris;++i)
{
AI_SWAP4( pcTriangles[i].index_xyz[0]);
AI_SWAP4( pcTriangles[i].index_xyz[1]);
AI_SWAP4( pcTriangles[i].index_xyz[2]);
AI_SWAP4( pcTriangles[i].index_uv[0]);
AI_SWAP4( pcTriangles[i].index_uv[1]);
AI_SWAP4( pcTriangles[i].index_uv[2]);
}
#endif
VALIDATE_FILE_SIZE(szCurrent); VALIDATE_FILE_SIZE(szCurrent);
// setup materials // setup materials
@ -620,15 +669,15 @@ void MDLImporter::InternReadFile_3DGS_MDL345( )
const MDL::Frame* pcFrames = (const MDL::Frame*)szCurrent; const MDL::Frame* pcFrames = (const MDL::Frame*)szCurrent;
// byte packed vertices // byte packed vertices
// BIG TODO: these two snippets are nearly totally identical ...
// *********************************************************************** // ***********************************************************************
if (0 == pcFrames->type || 3 >= this->iGSFileVersion) if (0 == pcFrames->type || 3 >= this->iGSFileVersion)
{ {
const MDL::SimpleFrame* pcFirstFrame = const MDL::SimpleFrame* pcFirstFrame = (const MDL::SimpleFrame*)(szCurrent + sizeof(uint32_t));
(const MDL::SimpleFrame*)(szCurrent + sizeof(uint32_t));
// get a pointer to the vertices // get a pointer to the vertices
const MDL::Vertex* pcVertices = (const MDL::Vertex*) ( const MDL::Vertex* pcVertices = (const MDL::Vertex*) ((pcFirstFrame->name)
(pcFirstFrame->name) + sizeof(pcFirstFrame->name)); + sizeof(pcFirstFrame->name));
VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts);
@ -654,16 +703,16 @@ void MDLImporter::InternReadFile_3DGS_MDL345( )
vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
vec.x += pcHeader->translate[0]; vec.x += pcHeader->translate[0];
// (flip z and y component) vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
vec.z = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; vec.y += pcHeader->translate[1];
vec.z += pcHeader->translate[1]; vec.y *= -1.0f;
vec.y = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
vec.y += pcHeader->translate[2]; vec.z += pcHeader->translate[2];
// read the normal vector from the precalculated normal table // read the normal vector from the precalculated normal table
MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
std::swap ( pcMesh->mNormals[iCurrent].y,pcMesh->mNormals[iCurrent].z ); pcMesh->mNormals[iCurrent].y *= -1.0f;
// read texture coordinates // read texture coordinates
if (pcHeader->synctype) if (pcHeader->synctype)
@ -684,12 +733,11 @@ void MDLImporter::InternReadFile_3DGS_MDL345( )
else else
{ {
// now get a pointer to the first frame in the file // now get a pointer to the first frame in the file
const MDL::SimpleFrame_MDLn_SP* pcFirstFrame = const MDL::SimpleFrame_MDLn_SP* pcFirstFrame = (const MDL::SimpleFrame_MDLn_SP*) (szCurrent + sizeof(uint32_t));
(const MDL::SimpleFrame_MDLn_SP*) (szCurrent + sizeof(uint32_t));
// get a pointer to the vertices // get a pointer to the vertices
const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) const MDL::Vertex_MDL4* pcVertices = (const MDL::Vertex_MDL4*) ((pcFirstFrame->name) +
((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); sizeof(pcFirstFrame->name));
VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts); VALIDATE_FILE_SIZE(pcVertices + pcHeader->num_verts);
@ -715,16 +763,16 @@ void MDLImporter::InternReadFile_3DGS_MDL345( )
vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0]; vec.x = (float)pcVertices[iIndex].v[0] * pcHeader->scale[0];
vec.x += pcHeader->translate[0]; vec.x += pcHeader->translate[0];
// (flip z and y component) vec.y = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1];
vec.z = (float)pcVertices[iIndex].v[1] * pcHeader->scale[1]; vec.y += pcHeader->translate[1];
vec.z += pcHeader->translate[1]; vec.y *= -1.0f;
vec.y = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2]; vec.z = (float)pcVertices[iIndex].v[2] * pcHeader->scale[2];
vec.y += pcHeader->translate[2]; vec.z += pcHeader->translate[2];
// read the normal vector from the precalculated normal table // read the normal vector from the precalculated normal table
MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]); MD2::LookupNormalIndex(pcVertices[iIndex].normalIndex,pcMesh->mNormals[iCurrent]);
std::swap ( pcMesh->mNormals[iCurrent].y,pcMesh->mNormals[iCurrent].z ); pcMesh->mNormals[iCurrent].y *= -1.0f;
// read texture coordinates // read texture coordinates
if (pcHeader->synctype) if (pcHeader->synctype)
@ -920,14 +968,9 @@ void MDLImporter::CalcAbsBoneMatrices_3DGS_MDL7(const MDL::Bone_MDL7* pcBones,
if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size) if (AI_MDL7_BONE_STRUCT_SIZE__NAME_IS_NOT_THERE == pcHeader->bone_stc_size)
{ {
// no real name for our poor bone :-( // no real name for our poor bone is specified :-(
# if (_MSC_VER >= 1400) pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data,
pcOutBone->mName.length = ::sprintf_s(pcOutBone->mName.data, "UnnamedBone_%i",iBone);
MAXLEN,"UnnamedBone_%i",iBone);
# else
pcOutBone->mName.length = ::sprintf(pcOutBone->mName.data,
"UnnamedBone_%i",iBone);
# endif
} }
else else
{ {
@ -1012,17 +1055,15 @@ void MDLImporter::ReadFaces_3DGS_MDL7(
// write the output face index // write the output face index
groupData.pcFaces[iTriangle].mIndices[2-c] = iOutIndex; groupData.pcFaces[iTriangle].mIndices[2-c] = iOutIndex;
// swap z and y axis
aiVector3D& vPosition = groupData.vPositions[ iOutIndex ]; aiVector3D& vPosition = groupData.vPositions[ iOutIndex ];
vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .x; vPosition.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .x;
vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y; vPosition.y = -1.0f*_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .y;
vPosition.y = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z; vPosition.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .z;
// if we have bones, save the index // if we have bones, save the index
if (!groupData.aiBones.empty()) if (!groupData.aiBones.empty())
{ groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,
groupData.aiBones[iOutIndex] = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size).vertindex; iIndex,pcHeader->mainvertex_stc_size).vertindex;
}
// now read the normal vector // now read the normal vector
if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size)
@ -1030,8 +1071,8 @@ void MDLImporter::ReadFaces_3DGS_MDL7(
// read the full normal vector // read the full normal vector
aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; aiVector3D& vNormal = groupData.vNormals[ iOutIndex ];
vNormal.x = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[0]; 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 = -1.0f*_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]; vNormal.z = _AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,pcHeader->mainvertex_stc_size) .norm[2];
} }
else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size)
{ {
@ -1039,8 +1080,7 @@ void MDLImporter::ReadFaces_3DGS_MDL7(
aiVector3D& vNormal = groupData.vNormals[ iOutIndex ]; aiVector3D& vNormal = groupData.vNormals[ iOutIndex ];
MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex, MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(groupInfo.pcGroupVerts,iIndex,
pcHeader->mainvertex_stc_size) .norm162index,vNormal); pcHeader->mainvertex_stc_size) .norm162index,vNormal);
vNormal.y *= -1.0f;
std::swap(groupData.vNormals[iOutIndex].z,groupData.vNormals[iOutIndex].y);
} }
// validate and process the first uv coordinate set // validate and process the first uv coordinate set
// ************************************************************* // *************************************************************
@ -1063,9 +1103,7 @@ void MDLImporter::ReadFaces_3DGS_MDL7(
} }
// assign the material index, but only if it is existing // assign the material index, but only if it is existing
if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX) if (pcHeader->triangle_stc_size >= AI_MDL7_TRIANGLE_STD_SIZE_ONE_UV_WITH_MATINDEX)
{
groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material; groupData.pcFaces[iTriangle].iMatIndex[0] = pcGroupTris->skinsets[0].material;
}
} }
// validate and process the second uv coordinate set // validate and process the second uv coordinate set
// ************************************************************* // *************************************************************
@ -1090,14 +1128,11 @@ void MDLImporter::ReadFaces_3DGS_MDL7(
// coordinate set ... wastes memory and loading time // coordinate set ... wastes memory and loading time
if (0 != iIndex && (u != groupData.vTextureCoords1[ iOutIndex ].x || if (0 != iIndex && (u != groupData.vTextureCoords1[ iOutIndex ].x ||
v != groupData.vTextureCoords1[ iOutIndex ].y ) ) v != groupData.vTextureCoords1[ iOutIndex ].y ) )
{
groupData.bNeed2UV = true; groupData.bNeed2UV = true;
}
// if the material differs, we need a second skin, too // if the material differs, we need a second skin, too
if (pcGroupTris->skinsets[ 1 ].material != pcGroupTris->skinsets[ 0 ].material) if (pcGroupTris->skinsets[ 1 ].material != pcGroupTris->skinsets[ 0 ].material)
{
groupData.bNeed2UV = true; groupData.bNeed2UV = true;
}
} }
// assign the material index // assign the material index
groupData.pcFaces[ iTriangle ].iMatIndex[ 1 ] = pcGroupTris->skinsets[ 1 ].material; groupData.pcFaces[ iTriangle ].iMatIndex[ 1 ] = pcGroupTris->skinsets[ 1 ].material;
@ -1144,9 +1179,7 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf
// our output frame? // our output frame?
if (configFrameID == iFrame) if (configFrameID == iFrame)
{ {
const MDL::Vertex_MDL7* pcFrameVertices = (const MDL::Vertex_MDL7*) const MDL::Vertex_MDL7* pcFrameVertices = (const MDL::Vertex_MDL7*)(szCurrent+pcHeader->frame_stc_size);
(szCurrent + pcHeader->framevertex_stc_size);
for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count;++qq) for (unsigned int qq = 0; qq < frame.pcFrame->vertices_count;++qq)
{ {
// I assume this are simple replacements for normal // I assume this are simple replacements for normal
@ -1157,37 +1190,33 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf
if (iIndex >= groupInfo.pcGroup->numverts) if (iIndex >= groupInfo.pcGroup->numverts)
{ {
DefaultLogger::get()->warn("Invalid vertex index in frame vertex section. " DefaultLogger::get()->warn("Invalid vertex index in frame vertex section");
"Skipping this frame vertex");
continue; continue;
} }
aiVector3D vPosition,vNormal; aiVector3D vPosition,vNormal;
vPosition.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .x; 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 = -1.0f*_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .y;
vPosition.y = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z; vPosition.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .z;
// now read the normal vector // now read the normal vector
if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size) if (AI_MDL7_FRAMEVERTEX030305_STCSIZE <= pcHeader->mainvertex_stc_size)
{ {
// read the full normal vector // read the full normal vector
vNormal.x = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[0]; 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 = -1.0f* _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]; vNormal.z = _AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,pcHeader->framevertex_stc_size) .norm[2];
} }
else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size) else if (AI_MDL7_FRAMEVERTEX120503_STCSIZE <= pcHeader->mainvertex_stc_size)
{ {
// read the normal vector from Quake2's smart table // read the normal vector from Quake2's smart table
MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq, MD2::LookupNormalIndex(_AI_MDL7_ACCESS_VERT(pcFrameVertices,qq,
pcHeader->framevertex_stc_size) .norm162index,vNormal); pcHeader->framevertex_stc_size) .norm162index,vNormal);
vNormal.y *= -1.0f;
std::swap(vNormal.z,vNormal.y);
} }
// FIXME: O(n^2) at the moment ... // 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; const MDL::Triangle_MDL7* pcGroupTris = groupInfo.pcGroupTris;
unsigned int iOutIndex = 0; unsigned int iOutIndex = 0;
for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle) for (unsigned int iTriangle = 0; iTriangle < (unsigned int)groupInfo.pcGroup->numtris; ++iTriangle)
@ -1204,16 +1233,13 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf
} }
} }
// get the next triangle in the list // get the next triangle in the list
pcGroupTris = (const MDL::Triangle_MDL7*)((const char*)pcGroupTris + pcGroupTris = (const MDL::Triangle_MDL7*)((const char*)
pcHeader->triangle_stc_size); pcGroupTris + pcHeader->triangle_stc_size);
} }
} }
} }
// parse bone trafo matrix keys (only if there are bones ...) // parse bone trafo matrix keys (only if there are bones ...)
if (shared.apcOutBones) if (shared.apcOutBones)this->ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared);
{
this->ParseBoneTrafoKeys_3DGS_MDL7(groupInfo,frame,shared);
}
szCurrent += iAdd; szCurrent += iAdd;
} }
*szCurrentOut = szCurrent; *szCurrentOut = szCurrent;
@ -1371,7 +1397,6 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
// load all bones (they are shared by all groups, so // load all bones (they are shared by all groups, so
// we'll need to add them to all groups/meshes later) // we'll need to add them to all groups/meshes later)
// apcBonesOut is a list of all bones or NULL if they could not been loaded // apcBonesOut is a list of all bones or NULL if they could not been loaded
// TODO (aramis): Make apcBonesOut an MDL::IntBone_MDL7*
szCurrent += pcHeader->bones_num * pcHeader->bone_stc_size; szCurrent += pcHeader->bones_num * pcHeader->bone_stc_size;
sharedData.apcOutBones = this->LoadBones_3DGS_MDL7(); sharedData.apcOutBones = this->LoadBones_3DGS_MDL7();
@ -1493,19 +1518,13 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
if (!splittedGroupData.aiSplit[qq]->empty()) if (!splittedGroupData.aiSplit[qq]->empty())
sharedData.abNeedMaterials[qq] = true; sharedData.abNeedMaterials[qq] = true;
} }
// now generate output meshes
this->GenerateOutputMeshes_3DGS_MDL7(groupData,
splittedGroupData);
} }
else DefaultLogger::get()->warn("[3DGS MDL7] Mesh group consists of 0 " else DefaultLogger::get()->warn("[3DGS MDL7] Mesh group consists of 0 "
"vertices or faces. It will be skipped."); "vertices or faces. It will be skipped.");
// process all frames // process all frames and generate output meshes
if(!ProcessFrames_3DGS_MDL7(groupInfo,groupData, sharedData,szCurrent,&szCurrent)) this->ProcessFrames_3DGS_MDL7(groupInfo,groupData, sharedData,szCurrent,&szCurrent);
{ this->GenerateOutputMeshes_3DGS_MDL7(groupData,splittedGroupData);
break;
}
} }
// generate a nodegraph and subnodes for each group // generate a nodegraph and subnodes for each group
@ -1545,16 +1564,9 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
// setup the name of the node // setup the name of the node
char* const szBuffer = &aszGroupNameBuffer[i*AI_MDL7_MAX_GROUPNAMESIZE]; char* const szBuffer = &aszGroupNameBuffer[i*AI_MDL7_MAX_GROUPNAMESIZE];
if ('\0' == *szBuffer) if ('\0' == *szBuffer)pcNode->mName.length = ::sprintf(szBuffer,"Group_%i",p);
{ else pcNode->mName.length = ::strlen(szBuffer);
#if _MSC_VER >= 1400
::sprintf_s(szBuffer,AI_MDL7_MAX_GROUPNAMESIZE,"Group_%i",p);
#else
::sprintf(szBuffer,"Group_%i",p);
#endif
}
::strcpy(pcNode->mName.data,szBuffer); ::strcpy(pcNode->mName.data,szBuffer);
pcNode->mName.length = ::strlen(szBuffer);
++p; ++p;
} }
} }
@ -1566,10 +1578,9 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
this->pScene->mRootNode = pcOldRoot->mChildren[0]; this->pScene->mRootNode = pcOldRoot->mChildren[0];
pcOldRoot->mChildren[0] = NULL; pcOldRoot->mChildren[0] = NULL;
delete pcOldRoot; delete pcOldRoot;
this->pScene->mRootNode->mParent = NULL; this->pScene->mRootNode->mParent = NULL;
} }
else this->pScene->mRootNode->mName.Set("mesh_root"); else this->pScene->mRootNode->mName.Set("<mesh_root>");
delete[] avOutList; delete[] avOutList;
delete[] aszGroupNameBuffer; delete[] aszGroupNameBuffer;
@ -1578,8 +1589,6 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
// build a final material list. // build a final material list.
this->CopyMaterials_3DGS_MDL7(sharedData); this->CopyMaterials_3DGS_MDL7(sharedData);
// handle materials that are just referencing another material correctly
this->HandleMaterialReferences_3DGS_MDL7(); this->HandleMaterialReferences_3DGS_MDL7();
// generate output bone animations and add all bones to the scenegraph // generate output bone animations and add all bones to the scenegraph
@ -1590,7 +1599,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
aiNode* const pc = this->pScene->mRootNode->mChildren[ aiNode* const pc = this->pScene->mRootNode->mChildren[
this->pScene->mRootNode->mNumChildren-1] = new aiNode(); this->pScene->mRootNode->mNumChildren-1] = new aiNode();
pc->mName.Set("skeleton_root"); pc->mName.Set("<skeleton_root>");
// add bones to the nodegraph // add bones to the nodegraph
this->AddBonesToNodeGraph_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **) this->AddBonesToNodeGraph_3DGS_MDL7((const Assimp::MDL::IntBone_MDL7 **)
@ -1604,64 +1613,15 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared) void MDLImporter::CopyMaterials_3DGS_MDL7(MDL::IntSharedData_MDL7 &shared)
{ {
unsigned int iNewNumMaterials = 0; this->pScene->mNumMaterials = (unsigned int)shared.pcMats.size();
unsigned int p = 0; this->pScene->mMaterials = new aiMaterial*[this->pScene->mNumMaterials];
for (;p < shared.pcMats.size();++p) for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i)
if (shared.abNeedMaterials[p])++iNewNumMaterials; this->pScene->mMaterials[i] = shared.pcMats[i];
this->pScene->mMaterials = new aiMaterial*[iNewNumMaterials];
if ((unsigned int)shared.pcMats.size() == iNewNumMaterials)
{
this->pScene->mNumMaterials = (unsigned int)shared.pcMats.size();
for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i)
this->pScene->mMaterials[i] = shared.pcMats[i];
}
else
{
p = 0;
const unsigned int iMSB = 0x1u << (sizeof (unsigned int)*8-1);
for (unsigned int i = 0; i < (unsigned int)shared.pcMats.size();++i)
{
if (!shared.abNeedMaterials[i])
{
// destruction is done by the destructor of sh
delete shared.pcMats[i];
AI_DEBUG_INVALIDATE_PTR(shared.pcMats[i]);
continue;
}
this->pScene->mMaterials[p] = shared.pcMats[i];
if (p != i)
{
// replace the material index and MSB in all material
// indices that have been replaced to make sure they won't be
// replaced again (this won't work if there are more than
// 2^31 materials in the model - but this shouldn't care :-)).
for (unsigned int qq = 0; qq < this->pScene->mNumMeshes;++qq)
{
aiMesh* const pcMesh = this->pScene->mMeshes[qq];
if (i == pcMesh->mMaterialIndex)
{
pcMesh->mMaterialIndex = p | iMSB;
}
}
}
++p;
}
this->pScene->mNumMaterials = iNewNumMaterials;
// Remove the MSB from all material indices
for (unsigned int qq = 0; qq < this->pScene->mNumMeshes;++qq)
{
this->pScene->mMeshes[qq]->mMaterialIndex &= ~iMSB;
}
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MDLImporter::HandleMaterialReferences_3DGS_MDL7() void MDLImporter::HandleMaterialReferences_3DGS_MDL7()
{ {
// search for referrer materials // search for referrer materials
// (there is no test file but Conitec's docs say it is supported ... :cry: )
for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i) for (unsigned int i = 0; i < this->pScene->mNumMaterials;++i)
{ {
int iIndex = 0; int iIndex = 0;
@ -1672,9 +1632,7 @@ void MDLImporter::HandleMaterialReferences_3DGS_MDL7()
{ {
aiMesh* const pcMesh = this->pScene->mMeshes[a]; aiMesh* const pcMesh = this->pScene->mMeshes[a];
if (i == pcMesh->mMaterialIndex) if (i == pcMesh->mMaterialIndex)
{
pcMesh->mMaterialIndex = iIndex; pcMesh->mMaterialIndex = iIndex;
}
} }
// collapse the rest of the array // collapse the rest of the array
delete this->pScene->mMaterials[i]; delete this->pScene->mMaterials[i];
@ -1731,8 +1689,7 @@ void MDLImporter::ParseBoneTrafoKeys_3DGS_MDL7(
else else
{ {
DefaultLogger::get()->warn("Found animation keyframes " DefaultLogger::get()->warn("Found animation keyframes "
"in a group that is not the first. They will be igored, " "in a group that is not the first. They will be igored");
"the format specification says this should not occur");
} }
} }
} }
@ -1802,7 +1759,7 @@ void MDLImporter::BuildOutputAnims_3DGS_MDL7(
aiBoneAnim* const pcBoneAnim = pcAnim->mBones[iCnt++] = new aiBoneAnim(); aiBoneAnim* const pcBoneAnim = pcAnim->mBones[iCnt++] = new aiBoneAnim();
pcBoneAnim->mBoneName = aiString( intBone->mName ); pcBoneAnim->mBoneName = aiString( intBone->mName );
// allocate enough storahe for all keys // allocate enough storage for all keys
pcBoneAnim->mNumPositionKeys = (unsigned int)intBone->pkeyPositions.size(); pcBoneAnim->mNumPositionKeys = (unsigned int)intBone->pkeyPositions.size();
pcBoneAnim->mNumScalingKeys = (unsigned int)intBone->pkeyPositions.size(); pcBoneAnim->mNumScalingKeys = (unsigned int)intBone->pkeyPositions.size();
pcBoneAnim->mNumRotationKeys = (unsigned int)intBone->pkeyPositions.size(); pcBoneAnim->mNumRotationKeys = (unsigned int)intBone->pkeyPositions.size();

View File

@ -87,6 +87,14 @@ public:
* See BaseImporter::CanRead() for details. */ * See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const;
// -------------------------------------------------------------------
/** Called prior to ReadFile().
* The function is a request to the importer to update its configuration
* basing on the Importer's configuration property list.
*/
void SetupProperties(const Importer* pImp);
protected: protected:

View File

@ -88,6 +88,10 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials]; unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials];
unsigned int iNewNum = 0; unsigned int iNewNum = 0;
std::vector<bool> abReferenced(pScene->mNumMaterials,false);
for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
// iterate through all materials and calculate a hash for them // iterate through all materials and calculate a hash for them
// store all hashes in a list and so a quick search whether // store all hashes in a list and so a quick search whether
// we do already have a specific hash. This allows us to // we do already have a specific hash. This allows us to
@ -96,6 +100,9 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
aiHashes = new uint32_t[pScene->mNumMaterials]; aiHashes = new uint32_t[pScene->mNumMaterials];
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
{ {
// if the material is not referenced ... remove it
if (!abReferenced[i])continue;
uint32_t me = aiHashes[i] = ((MaterialHelper*)pScene->mMaterials[i])->ComputeHash(); uint32_t me = aiHashes[i] = ((MaterialHelper*)pScene->mMaterials[i])->ComputeHash();
for (unsigned int a = 0; a < i;++a) for (unsigned int a = 0; a < i;++a)
{ {
@ -120,6 +127,9 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
::memset(ppcMaterials,0,sizeof(void*)*iNewNum); ::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
for (unsigned int p = 0; p < pScene->mNumMaterials;++p) for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
{ {
// if the material is not referenced ... remove it
if (!abReferenced[p])continue;
// generate new names for all modified materials // generate new names for all modified materials
const unsigned int idx = aiMappingTable[p]; const unsigned int idx = aiMappingTable[p];
if (ppcMaterials[idx]) if (ppcMaterials[idx])

View File

@ -101,12 +101,8 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
// Setup properties // Setup properties
void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
{ {
// get the current value of the split property // get the current value of the split property
if(0xcdcdcdcd == (this->LIMIT = pImp->GetProperty( this->LIMIT = pImp->GetProperty(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,0xcdcdcdcd)))
{
this->LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Update a node after some meshes have been split // Update a node after some meshes have been split
@ -291,15 +287,11 @@ void SplitLargeMeshesProcess_Triangle::SplitMesh(
// copy positions // copy positions
if (pMesh->mVertices != NULL) if (pMesh->mVertices != NULL)
{
pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex]; pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex];
}
// copy normals // copy normals
if (pMesh->HasNormals()) if (pMesh->HasNormals())
{
pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex]; pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex];
}
// copy tangents/bitangents // copy tangents/bitangents
if (pMesh->HasTangentsAndBitangents()) if (pMesh->HasTangentsAndBitangents())
@ -312,17 +304,13 @@ void SplitLargeMeshesProcess_Triangle::SplitMesh(
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
{ {
if (pMesh->HasTextureCoords( c)) if (pMesh->HasTextureCoords( c))
{
pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex]; pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex];
}
} }
// vertex colors // vertex colors
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
{ {
if (pMesh->HasVertexColors( c)) if (pMesh->HasVertexColors( c))
{
pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex]; pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex];
}
} }
} }
} }
@ -386,12 +374,7 @@ void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
// Setup properties // Setup properties
void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp)
{ {
// get the current value of the split property this->LIMIT = pImp->GetProperty(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
if(0xcdcdcdcd == (this->LIMIT = pImp->GetProperty(
AI_CONFIG_PP_SLM_VERTEX_LIMIT,0xcdcdcdcd)))
{
this->LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
@ -455,9 +438,15 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh(
} }
// clear the temporary helper array // clear the temporary helper array
if (0 != iBase) if (iBase)
{ {
memset(&avWasCopied[0],0xFF,pMesh->mNumVertices * sizeof(unsigned int)); // we can't use memset here we unsigned int needn' be 32 bits
for (std::vector<unsigned int>::iterator
iter = avWasCopied.begin(),end = avWasCopied.end();
iter != end;++iter)
{
(*iter) = 0xffffffff;
}
} }
// output vectors // output vectors

View File

@ -710,10 +710,10 @@ __break_out:
} }
if (pBoneAnim->mPositionKeys[i].mTime <= dLast) if (pBoneAnim->mPositionKeys[i].mTime <= dLast)
{ {
this->ReportError("aiBoneAnim::mPositionKeys[%i].mTime (%.5f) is larger " this->ReportWarning("aiBoneAnim::mPositionKeys[%i].mTime (%.5f) is smaller "
"than aiAnimation::mPositionKeys[%i] (which is %.5f)",i, "than aiAnimation::mPositionKeys[%i] (which is %.5f)",i,
(float)pBoneAnim->mPositionKeys[i].mTime, (float)pBoneAnim->mPositionKeys[i].mTime,
i, (float)dLast); i-1, (float)dLast);
} }
dLast = pBoneAnim->mPositionKeys[i].mTime; dLast = pBoneAnim->mPositionKeys[i].mTime;
} }
@ -738,10 +738,10 @@ __break_out:
} }
if (pBoneAnim->mRotationKeys[i].mTime <= dLast) if (pBoneAnim->mRotationKeys[i].mTime <= dLast)
{ {
this->ReportError("aiBoneAnim::mRotationKeys[%i].mTime (%.5f) is larger " this->ReportWarning("aiBoneAnim::mRotationKeys[%i].mTime (%.5f) is smaller "
"than aiAnimation::mRotationKeys[%i] (which is %.5f)",i, "than aiAnimation::mRotationKeys[%i] (which is %.5f)",i,
(float)pBoneAnim->mRotationKeys[i].mTime, (float)pBoneAnim->mRotationKeys[i].mTime,
i, (float)dLast); i-1, (float)dLast);
} }
dLast = pBoneAnim->mRotationKeys[i].mTime; dLast = pBoneAnim->mRotationKeys[i].mTime;
} }
@ -766,10 +766,10 @@ __break_out:
} }
if (pBoneAnim->mScalingKeys[i].mTime <= dLast) if (pBoneAnim->mScalingKeys[i].mTime <= dLast)
{ {
this->ReportError("aiBoneAnim::mScalingKeys[%i].mTime (%.5f) is larger " this->ReportWarning("aiBoneAnim::mScalingKeys[%i].mTime (%.5f) is smaller "
"than aiAnimation::mScalingKeys[%i] (which is %.5f)",i, "than aiAnimation::mScalingKeys[%i] (which is %.5f)",i,
(float)pBoneAnim->mScalingKeys[i].mTime, (float)pBoneAnim->mScalingKeys[i].mTime,
i, (float)dLast); i-1, (float)dLast);
} }
dLast = pBoneAnim->mScalingKeys[i].mTime; dLast = pBoneAnim->mScalingKeys[i].mTime;
} }

View File

@ -105,6 +105,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#define AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT "imp.3ds.nopivot" #define AI_CONFIG_IMPORT_3DS_IGNORE_PIVOT "imp.3ds.nopivot"
// ---------------------------------------------------------------------------
/** \brief Specifies the maximum angle that may be between two vertex tangents
* that their tangents and bitangents are smoothed.
*
* This applies to the CalcTangentSpace-Step. The angle is specified
* in degrees * 1000, so 180000 is PI. The default value is
* 45 degrees. The maximum value is 180000.
*/
#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE "pp.ct.max_smoothing"
// ---------------------------------------------------------------------------
/** \brief Specifies the maximum angle that may be between two face normals
* at the same vertex position that their are smoothed.
*
* This applies to the GenSmoothNormals-Step. The angle is specified
* in degrees * 1000, so 180000 is PI. The default value is
* 180 degrees (all vertex normals are smoothed). The maximum value is 180000
* \note This can be manually overriden by loaders via #aiMesh::mMaxSmoothingAngle;
*/
#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE "pp.gsn.max_smoothing"
#define AI_CONFIG_PP_OG_MAX_DEPTH "pp.og.max_depth" #define AI_CONFIG_PP_OG_MAX_DEPTH "pp.og.max_depth"
#define AI_CONFIG_PP_OG_MIN_TRIS_PER_NODE "pp.og.min_tris" #define AI_CONFIG_PP_OG_MIN_TRIS_PER_NODE "pp.og.min_tris"

View File

@ -248,6 +248,8 @@ struct aiBone
#endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS #endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS
#define AI_MESH_SMOOTHING_ANGLE_NOT_SET (10e10f)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** A mesh represents a geometry or model with a single material. /** A mesh represents a geometry or model with a single material.
* *
@ -358,8 +360,9 @@ struct aiMesh
* If the angle between two vertex normals is larger, * If the angle between two vertex normals is larger,
* the vertex normals should not be smoothed. The GenVertexNormals-Step * the vertex normals should not be smoothed. The GenVertexNormals-Step
* takes care of this value. The angle is specified in radians. * takes care of this value. The angle is specified in radians.
* It is 2PI if the source file didn't contain any additional * It is set to AI_MESH_SMOOTHING_ANGLE_NOT_SET if the source file didn't
* information related to the calculation of vertex normals. * contain any additional information related to the calculation of
* vertex normals.
*/ */
float mMaxSmoothingAngle; float mMaxSmoothingAngle;
@ -381,7 +384,7 @@ struct aiMesh
mColors[a] = NULL; mColors[a] = NULL;
mNumBones = 0; mBones = NULL; mNumBones = 0; mBones = NULL;
mMaterialIndex = 0; mMaterialIndex = 0;
mMaxSmoothingAngle = (float)AI_MATH_TWO_PI; mMaxSmoothingAngle = AI_MESH_SMOOTHING_ANGLE_NOT_SET;
} }
//! Deletes all storage allocated for the mesh //! Deletes all storage allocated for the mesh

Binary file not shown.

View File

@ -38,21 +38,22 @@ IDI_SMALL ICON "small.ico"
// Dialog // Dialog
// //
IDD_ABOUTBOX DIALOGEX 22, 17, 283, 170 IDD_ABOUTBOX DIALOGEX 22, 17, 283, 169
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CAPTION | WS_SYSMENU
CAPTION "About ASSIMP" CAPTION "About Open Asset Import Library"
FONT 10, "MS Shell Dlg", 400, 0, 0x0 FONT 10, "MS Shell Dlg", 400, 0, 0x0
BEGIN BEGIN
LTEXT "ASSIMP is the free, OpenSource ASSet IMPort Library",IDC_STATIC,42,12,204,12 LTEXT "Open Asset Import Library (Assimp)",IDC_STATIC,77,13,121,12
LTEXT "Developed by members of the german game development community www.zfx.info",IDC_STATIC,42,30,204,24 LTEXT "A free C/C++ library for game && graphics developers. Developed by members of the german game development community www.zfx.info",IDC_STATIC,47,26,204,24
LTEXT "Thomas Schulze \t\taka <Schrompf> ",IDC_STATIC,42,66,192,8 LTEXT "Thomas Schulze \t\taka <Schrompf> ",IDC_STATIC,55,80,192,8
LTEXT "Kim Kulling \t\t\taka <Sir Kimmi> ",IDC_STATIC,42,78,186,8 LTEXT "Kim Kulling \t\t\taka <Kimmi> ",IDC_STATIC,55,92,186,8
LTEXT "Rainer Schmidt \t\t\taka <Guru>",IDC_STATIC,42,90,180,8 LTEXT "Rainer Schmidt \t\t\taka <Guru>",IDC_STATIC,55,104,180,8
LTEXT "Alexander Gessler\t\taka <Aramis>",IDC_STATIC,42,102,186,8 LTEXT "Alexander Gessler\t\taka <Aramis>",IDC_STATIC,55,68,186,8
CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,60,282,1 CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,60,282,1
LTEXT "http://zfxce.svn.sourceforge.net/viewvc/zfxce/trunk/ASSIMP",IDC_STATIC,42,120,198,8 LTEXT "assimp.sourceforge.net",IDC_STATIC,7,137,78,8
DEFPUSHBUTTON "Love this library",IDOK,199,148,67,14 DEFPUSHBUTTON "Love this library",IDOK,200,128,67,14
CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,138,281,1 CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,148,283,1
CONTROL 130,IDC_STATIC,"Static",SS_BITMAP,0,149,514,20
END END
IDD_DIALOGMAIN DIALOGEX 0, 0, 594, 384 IDD_DIALOGMAIN DIALOGEX 0, 0, 594, 384
@ -233,6 +234,7 @@ GUIDELINES DESIGNINFO
BEGIN BEGIN
IDD_ABOUTBOX, DIALOG IDD_ABOUTBOX, DIALOG
BEGIN BEGIN
TOPMARGIN, 1
BOTTOMMARGIN, 158 BOTTOMMARGIN, 158
END END

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View File

@ -582,6 +582,10 @@
RelativePath="..\..\include\aiAssert.h" RelativePath="..\..\include\aiAssert.h"
> >
</File> </File>
<File
RelativePath="..\..\include\aiConfig.h"
>
</File>
<File <File
RelativePath="..\..\include\aiDefines.h" RelativePath="..\..\include\aiDefines.h"
> >
@ -674,6 +678,10 @@
RelativePath="..\..\include\LogStream.h" RelativePath="..\..\include\LogStream.h"
> >
</File> </File>
<File
RelativePath="..\..\include\NullLogger.h"
>
</File>
<Filter <Filter
Name="Compiler" Name="Compiler"
> >
@ -965,10 +973,6 @@
<Filter <Filter
Name="Logger" Name="Logger"
> >
<File
RelativePath="..\..\code\DefaultLogger.h"
>
</File>
<File <File
RelativePath="..\..\code\FileLogStream.h" RelativePath="..\..\code\FileLogStream.h"
> >
@ -1030,6 +1034,30 @@
> >
</File> </File>
</Filter> </Filter>
<Filter
Name="MDC"
>
<File
RelativePath="..\..\code\MDCFileData.h"
>
</File>
<File
RelativePath="..\..\code\MDCLoader.h"
>
</File>
<File
RelativePath="..\..\code\MDCNormalTable.h"
>
</File>
</Filter>
<Filter
Name="MDR"
>
<File
RelativePath="..\..\code\MDRFileData.h"
>
</File>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="sources" Name="sources"
@ -1302,6 +1330,14 @@
> >
</File> </File>
</Filter> </Filter>
<Filter
Name="MDC"
>
<File
RelativePath="..\..\code\MDCLoader.cpp"
>
</File>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="doc" Name="doc"