Fixed some minor issues in the AC loader. However, it still crashes with large and complicated models. Line handling is complete.

Moved the code to find degenerated primitives to a separate step that is not anymore active by default. 
The FindInvalidData-Step isn't active by default now. It hast a flag and must be explicitly requested.
Added line and point handling code to the CalcTangentsStep - not yet tested.
Added support for the Sense 8 (WorldToolKit) NFF file format. The format uses the same file extension as the "Neutral File Format" (and is implemented in the same loader). Seems to work well, added test files for it.
Added itoa10 function - so we have itoa on all platforms.
Small optimizations in the SortByPType step.
Fixed the material validation: textured meshes without uv coords cause a warning now.
Fixed a minor isses with the OFF loader.
Added empty unit tests for the new steps - to be filled in the next days. 
Added SceneCombiner.cpp. It contains utilities to join meshes and scenes. The latter will be needed by the LWS loader (LWS files contain references to external LWO files and the LWO loader is already to complicated that it would make sense to add an additional code path to it). Mesh joining is needed by some pp steps, but the code has not yet been moved to its new location.
Added WIP light & camera support to the ASE loader. Works for the moment, but there's much missing. ASE parser refactored, the code is still quite long but at least cleaner. Fixed a bug that caused ASE to import invalid texture coordinates.
Makefiles and VC8 solution are up-to-date. The rest isn't.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@192 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2008-10-22 20:06:16 +00:00
parent 013ff599a5
commit 383a614931
55 changed files with 22566 additions and 879 deletions

View File

@ -683,7 +683,9 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
if (1 != rootObjects.size())delete root; if (1 != rootObjects.size())delete root;
// build output arrays // build output arrays
ai_assert(!meshes.empty()); if (meshes.empty())
{
}
pScene->mNumMeshes = (unsigned int)meshes.size(); pScene->mNumMeshes = (unsigned int)meshes.size();
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*)); ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));

View File

@ -117,33 +117,33 @@ void ASEImporter::InternReadFile(
// construct an ASE parser and parse the file // construct an ASE parser and parse the file
// TODO: clean this up, mParser should be a reference, not a pointer ... // TODO: clean this up, mParser should be a reference, not a pointer ...
ASE::Parser parser(this->mBuffer); ASE::Parser parser(this->mBuffer);
this->mParser = &parser; mParser = &parser;
this->mParser->Parse(); mParser->Parse();
// if absolutely no material has been loaded from the file // if absolutely no material has been loaded from the file
// we need to generate a default material // we need to generate a default material
this->GenerateDefaultMaterial(); GenerateDefaultMaterial();
// process all meshes // process all meshes
std::vector<aiMesh*> avOutMeshes; std::vector<aiMesh*> avOutMeshes;
avOutMeshes.reserve(this->mParser->m_vMeshes.size()*2); avOutMeshes.reserve(mParser->m_vMeshes.size()*2);
for (std::vector<ASE::Mesh>::iterator for (std::vector<ASE::Mesh>::iterator
i = this->mParser->m_vMeshes.begin(); i = mParser->m_vMeshes.begin();
i != this->mParser->m_vMeshes.end();++i) i != mParser->m_vMeshes.end();++i)
{ {
if ((*i).bSkip)continue; if ((*i).bSkip)continue;
this->TransformVertices(*i); 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); BuildUniqueRepresentation(*i);
// need to generate proper vertex normals if necessary // need to generate proper vertex normals if necessary
this->GenerateNormals(*i); GenerateNormals(*i);
// convert all meshes to aiMesh objects // convert all meshes to aiMesh objects
this->ConvertMeshes(*i,avOutMeshes); ConvertMeshes(*i,avOutMeshes);
} }
// now build the output mesh list. remove dummies // now build the output mesh list. remove dummies
@ -159,37 +159,42 @@ void ASEImporter::InternReadFile(
pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes); pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes);
// buil final material indices (remove submaterials and make the final list) // buil final material indices (remove submaterials and make the final list)
this->BuildMaterialIndices(); BuildMaterialIndices();
// build the final node graph // build the final node graph
this->BuildNodes(); BuildNodes();
// build output animations // build output animations
this->BuildAnimations(); BuildAnimations();
return;
// build output cameras
BuildCameras();
// build output lights
BuildLights();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::GenerateDefaultMaterial() void ASEImporter::GenerateDefaultMaterial()
{ {
ai_assert(NULL != this->mParser); ai_assert(NULL != mParser);
bool bHas = false; bool bHas = false;
for (std::vector<ASE::Mesh>::iterator for (std::vector<ASE::Mesh>::iterator
i = this->mParser->m_vMeshes.begin(); i = mParser->m_vMeshes.begin();
i != this->mParser->m_vMeshes.end();++i) i != mParser->m_vMeshes.end();++i)
{ {
if ((*i).bSkip)continue; if ((*i).bSkip)continue;
if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex) if (ASE::Face::DEFAULT_MATINDEX == (*i).iMaterialIndex)
{ {
(*i).iMaterialIndex = (unsigned int)this->mParser->m_vMaterials.size(); (*i).iMaterialIndex = (unsigned int)mParser->m_vMaterials.size();
bHas = true; bHas = true;
} }
} }
if (bHas || this->mParser->m_vMaterials.empty()) if (bHas || mParser->m_vMaterials.empty())
{ {
// add a simple material without sub materials to the parser's list // add a simple material without sub materials to the parser's list
this->mParser->m_vMaterials.push_back ( ASE::Material() ); mParser->m_vMaterials.push_back ( ASE::Material() );
ASE::Material& mat = this->mParser->m_vMaterials.back(); ASE::Material& mat = 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);
@ -198,13 +203,14 @@ void ASEImporter::GenerateDefaultMaterial()
mat.mName = AI_DEFAULT_MATERIAL_NAME; mat.mName = AI_DEFAULT_MATERIAL_NAME;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::BuildAnimations() void ASEImporter::BuildAnimations()
{ {
// check whether we have at least one mesh which has animations // check whether we have at least one mesh which has animations
std::vector<ASE::Mesh>::iterator i = this->mParser->m_vMeshes.begin(); std::vector<ASE::Mesh>::iterator i = mParser->m_vMeshes.begin();
unsigned int iNum = 0; unsigned int iNum = 0;
for (;i != this->mParser->m_vMeshes.end();++i) for (;i != mParser->m_vMeshes.end();++i)
{ {
if ((*i).bSkip)continue; if ((*i).bSkip)continue;
if ((*i).mAnim.akeyPositions.size() > 1 || (*i).mAnim.akeyRotations.size() > 1) if ((*i).mAnim.akeyPositions.size() > 1 || (*i).mAnim.akeyRotations.size() > 1)
@ -212,188 +218,294 @@ void ASEImporter::BuildAnimations()
} }
if (iNum) if (iNum)
{ {
this->pcScene->mNumAnimations = 1; // Generate a new animation channel and setup everything for it
this->pcScene->mAnimations = new aiAnimation*[1]; pcScene->mNumAnimations = 1;
aiAnimation* pcAnim = this->pcScene->mAnimations[0] = new aiAnimation(); pcScene->mAnimations = new aiAnimation*[1];
aiAnimation* pcAnim = pcScene->mAnimations[0] = new aiAnimation();
pcAnim->mNumChannels = iNum; pcAnim->mNumChannels = iNum;
pcAnim->mChannels = new aiNodeAnim*[iNum]; pcAnim->mChannels = new aiNodeAnim*[iNum];
pcAnim->mTicksPerSecond = this->mParser->iFrameSpeed * this->mParser->iTicksPerFrame; pcAnim->mTicksPerSecond = mParser->iFrameSpeed * mParser->iTicksPerFrame;
iNum = 0; iNum = 0;
i = this->mParser->m_vMeshes.begin(); i = mParser->m_vMeshes.begin();
for (;i != this->mParser->m_vMeshes.end();++i)
// Now iterate through all meshes and collect all data we can find
for (;i != mParser->m_vMeshes.end();++i)
{ {
if ((*i).bSkip)continue; if ((*i).bSkip)continue; // mesh unreferenced?
if ((*i).mAnim.akeyPositions.size() > 1 || (*i).mAnim.akeyRotations.size() > 1) if ((*i).mAnim.akeyPositions.size() > 1 || (*i).mAnim.akeyRotations.size() > 1)
{ {
// Begin a new node animation channel for this node
aiNodeAnim* pcNodeAnim = pcAnim->mChannels[iNum++] = new aiNodeAnim(); aiNodeAnim* pcNodeAnim = pcAnim->mChannels[iNum++] = new aiNodeAnim();
pcNodeAnim->mNodeName.Set((*i).mName); pcNodeAnim->mNodeName.Set((*i).mName);
// copy position keys // copy position keys
if ((*i).mAnim.akeyPositions.size() > 1 ) if ((*i).mAnim.akeyPositions.size() > 1 )
{ {
// Allocate the key array and fill it
pcNodeAnim->mNumPositionKeys = (unsigned int) (*i).mAnim.akeyPositions.size(); pcNodeAnim->mNumPositionKeys = (unsigned int) (*i).mAnim.akeyPositions.size();
pcNodeAnim->mPositionKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys]; pcNodeAnim->mPositionKeys = new aiVectorKey[pcNodeAnim->mNumPositionKeys];
::memcpy(pcNodeAnim->mPositionKeys,&(*i).mAnim.akeyPositions[0], ::memcpy(pcNodeAnim->mPositionKeys,&(*i).mAnim.akeyPositions[0],
pcNodeAnim->mNumPositionKeys * sizeof(aiVectorKey)); pcNodeAnim->mNumPositionKeys * sizeof(aiVectorKey));
// get the longest node anim here
for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys;++qq) for (unsigned int qq = 0; qq < pcNodeAnim->mNumPositionKeys;++qq)
{ {
double dTime = pcNodeAnim->mPositionKeys[qq].mTime; pcAnim->mDuration = std::max(pcAnim->mDuration,
pcAnim->mDuration = std::max(pcAnim->mDuration,dTime); pcNodeAnim->mPositionKeys[qq].mTime);
} }
} }
// copy rotation keys // copy rotation keys
if ((*i).mAnim.akeyRotations.size() > 1 ) if ((*i).mAnim.akeyRotations.size() > 1 )
{ {
// Allocate the key array and fill it
pcNodeAnim->mNumRotationKeys = (unsigned int) (*i).mAnim.akeyPositions.size(); pcNodeAnim->mNumRotationKeys = (unsigned int) (*i).mAnim.akeyPositions.size();
pcNodeAnim->mRotationKeys = new aiQuatKey[pcNodeAnim->mNumPositionKeys]; pcNodeAnim->mRotationKeys = new aiQuatKey[pcNodeAnim->mNumPositionKeys];
::memcpy(pcNodeAnim->mRotationKeys,&(*i).mAnim.akeyRotations[0], ::memcpy(pcNodeAnim->mRotationKeys,&(*i).mAnim.akeyRotations[0],
pcNodeAnim->mNumRotationKeys * sizeof(aiQuatKey)); pcNodeAnim->mNumRotationKeys * sizeof(aiQuatKey));
// get the longest node anim here
for (unsigned int qq = 0; qq < pcNodeAnim->mNumRotationKeys;++qq) for (unsigned int qq = 0; qq < pcNodeAnim->mNumRotationKeys;++qq)
{ {
double dTime = pcNodeAnim->mRotationKeys[qq].mTime; pcAnim->mDuration = std::max(pcAnim->mDuration,
pcAnim->mDuration = std::max(pcAnim->mDuration,dTime); pcNodeAnim->mRotationKeys[qq].mTime);
} }
} }
// there are no scaling keys
} }
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::AddNodes(aiNode* pcParent,const char* szName) void ASEImporter::BuildCameras()
{
if (!mParser->m_vCameras.empty())
{
pcScene->mNumCameras = (unsigned int)mParser->m_vCameras.size();
pcScene->mCameras = new aiCamera*[pcScene->mNumCameras];
for (unsigned int i = 0; i < pcScene->mNumCameras;++i)
{
aiCamera* out = pcScene->mCameras[i] = new aiCamera();
ASE::Camera& in = mParser->m_vCameras[i];
// copy members
out->mClipPlaneFar = in.mFar;
out->mClipPlaneNear = (in.mNear ? in.mNear : 0.1f);
out->mHorizontalFOV = AI_RAD_TO_DEG( in.mFOV );
out->mName.Set(in.mName);
}
}
}
// ------------------------------------------------------------------------------------------------
void ASEImporter::BuildLights()
{
if (!mParser->m_vLights.empty())
{
pcScene->mNumLights = (unsigned int)mParser->m_vLights.size();
pcScene->mLights = new aiLight*[pcScene->mNumLights];
for (unsigned int i = 0; i < pcScene->mNumLights;++i)
{
aiLight* out = pcScene->mLights[i] = new aiLight();
ASE::Light& in = mParser->m_vLights[i];
out->mName.Set(in.mName);
out->mType = aiLightSource_POINT;
}
}
}
// ------------------------------------------------------------------------------------------------
void ASEImporter::AddNodes(std::vector<BaseNode*>& nodes,
aiNode* pcParent,const char* szName)
{ {
aiMatrix4x4 m; aiMatrix4x4 m;
ASE::DecompTransform dec(m); this->AddNodes(nodes,pcParent,szName,m);
this->AddNodes(pcParent,szName,dec);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::AddNodes(aiNode* pcParent,const char* szName, void ASEImporter::AddNodes (std::vector<BaseNode*>& nodes,
const ASE::DecompTransform& decompTrafo) aiNode* pcParent, const char* szName,
const aiMatrix4x4& mat)
{ {
const size_t len = szName ? strlen(szName) : 0; const size_t len = szName ? ::strlen(szName) : 0;
ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS); ai_assert(4 <= AI_MAX_NUMBER_OF_COLOR_SETS);
std::vector<aiNode*> apcNodes;
aiMesh** pcMeshes = pcScene->mMeshes;
for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
{
// get the name of the mesh
aiMesh* pcMesh = *pcMeshes++;
const ASE::Mesh& mesh = *((const ASE::Mesh*)pcMesh->mColors[2]);
// TODO: experimental quick'n'dirty, clean this up ... // Receives child nodes for the pcParent node
std::string szMyName[2] = {mesh.mName,mesh.mParent} ; std::vector<aiNode*> apcNodes;
// Now iterate through all nodes in the scene and search for one
// which has *us* as parent.
for (std::vector<BaseNode*>::const_iterator it = nodes.begin(), end = nodes.end();
it != end; ++it)
{
const BaseNode* snode = *it;
if (szName) if (szName)
{ {
if( len != szMyName[1].length() || if (len != snode->mParent.length() || ::strcmp(szName,snode->mParent.c_str()))
0 != ASSIMP_stricmp ( szName, szMyName[1].c_str() ))
{
continue; continue;
}
} }
else if ('\0' != szMyName[1].c_str()[0])continue; else if (snode->mParent.length())
continue;
(*it)->mProcessed = true;
// Allocate a new node and add it to the output data structure
apcNodes.push_back(new aiNode()); apcNodes.push_back(new aiNode());
aiNode* node = apcNodes.back(); aiNode* node = apcNodes.back();
node->mName.Set(szMyName[0]); node->mName.Set((snode->mName.length() ? snode->mName.c_str() : "Unnamed_Node"));
node->mNumMeshes = 1;
node->mMeshes = new unsigned int[1];
node->mMeshes[0] = i;
node->mParent = pcParent; node->mParent = pcParent;
aiMatrix4x4 mParentAdjust = decompTrafo.mMatrix; // Setup the transformation matrix of the node
aiMatrix4x4 mParentAdjust = mat;
mParentAdjust.Inverse(); mParentAdjust.Inverse();
node->mTransformation = mParentAdjust*mesh.mTransform; node->mTransformation = mParentAdjust*snode->mTransform;
// Transform all vertices of the mesh back into their local space -> // If the type of this node is "Mesh" we need to search
// at the moment they are pretransformed // the list of output meshes in the data structure for
aiMatrix4x4 mInverse = mesh.mTransform; // all those that belonged to this node once. This is
mInverse.Inverse(); // slightly inconvinient here and a better solution should
// be used when this code is refactored next.
aiVector3D* pvCurPtr = pcMesh->mVertices; if (snode->mType == BaseNode::Mesh)
const aiVector3D* const pvEndPtr = pcMesh->mVertices + pcMesh->mNumVertices;
while (pvCurPtr != pvEndPtr)
{ {
*pvCurPtr = mInverse * (*pvCurPtr); for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
pvCurPtr++; {
// Get the name of the mesh (the mesh instance has been temporarily
// stored in the third vertex color)
const aiMesh* pcMesh = pcScene->mMeshes[i];
const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
if (mesh == snode)++node->mNumMeshes;
}
if(node->mNumMeshes)
{
node->mMeshes = new unsigned int[node->mNumMeshes];
for (unsigned int i = 0, p = 0; i < pcScene->mNumMeshes;++i)
{
const aiMesh* pcMesh = pcScene->mMeshes[i];
const ASE::Mesh* mesh = (const ASE::Mesh*)pcMesh->mColors[2];
if (mesh == snode)
{
node->mMeshes[p++] = i;
// Transform all vertices of the mesh back into their local space ->
// at the moment they are pretransformed
mParentAdjust = mesh->mTransform;
mParentAdjust.Inverse();
aiVector3D* pvCurPtr = pcMesh->mVertices;
const aiVector3D* pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
while (pvCurPtr != pvEndPtr)
{
*pvCurPtr = mParentAdjust * (*pvCurPtr);
pvCurPtr++;
}
// Do the same for the normal vectors if we have them
// Here we need to use the (Inverse)Transpose of a 3x3
// matrix without the translational component.
if (pcMesh->mNormals)
{
aiMatrix3x3 m3 = aiMatrix3x3( mesh->mTransform );
m3.Transpose();
pvCurPtr = pcMesh->mNormals;
pvEndPtr = pvCurPtr + pcMesh->mNumVertices;
while (pvCurPtr != pvEndPtr)
{
*pvCurPtr = m3 * (*pvCurPtr);
pvCurPtr++;
}
}
}
}
}
} }
// add sub nodes // add sub nodes
aiMatrix4x4 mNewAbs = decompTrafo.mMatrix * node->mTransformation; aiMatrix4x4 mNewAbs = mat * node->mTransformation;
ASE::DecompTransform dec( mNewAbs); AddNodes(nodes,node,node->mName.data,mNewAbs);
this->AddNodes(node,node->mName.data,dec);
} }
// allocate enough space for the child nodes // allocate enough space for the child nodes
pcParent->mNumChildren = (unsigned int)apcNodes.size(); pcParent->mNumChildren = (unsigned int)apcNodes.size();
pcParent->mChildren = new aiNode*[apcNodes.size()]; pcParent->mChildren = new aiNode*[apcNodes.size()];
// now build all nodes // now build all nodes for our nice new children
for (unsigned int p = 0; p < apcNodes.size();++p) for (unsigned int p = 0; p < apcNodes.size();++p)
{ {
pcParent->mChildren[p] = apcNodes[p]; pcParent->mChildren[p] = apcNodes[p];
} }
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::BuildNodes() void ASEImporter::BuildNodes()
{ {
ai_assert(NULL != pcScene); ai_assert(NULL != pcScene);
// allocate the root node // allocate the one and only root node
pcScene->mRootNode = new aiNode(); pcScene->mRootNode = new aiNode();
pcScene->mRootNode->mNumMeshes = 0; pcScene->mRootNode->mNumMeshes = 0;
pcScene->mRootNode->mMeshes = 0; pcScene->mRootNode->mMeshes = 0;
pcScene->mRootNode->mName.Set("<root>"); pcScene->mRootNode->mName.Set("<root>");
// add all nodes // generate a full list of all scenegraph elements we have
this->AddNodes(pcScene->mRootNode,NULL); std::vector<BaseNode*> nodes;
nodes.reserve(mParser->m_vMeshes.size() +mParser->m_vLights.size()
+ mParser->m_vCameras.size());
// now iterate through al meshes and find those that have not yet for (std::vector<ASE::Light>::iterator it = mParser->m_vLights.begin(),
end = mParser->m_vLights.end();it != end; ++it)nodes.push_back(&(*it));
for (std::vector<ASE::Camera>::iterator it = mParser->m_vCameras.begin(),
end = mParser->m_vCameras.end();it != end; ++it)nodes.push_back(&(*it));
for (std::vector<ASE::Mesh>::iterator it = mParser->m_vMeshes.begin(),
end = mParser->m_vMeshes.end();it != end; ++it)nodes.push_back(&(*it));
// add all nodes
AddNodes(nodes,pcScene->mRootNode,NULL);
// now iterate through al nodes and find those that have not yet
// been added to the nodegraph (= their parent could not be recognized) // been added to the nodegraph (= their parent could not be recognized)
std::vector<unsigned int> aiList; std::vector<const BaseNode*> aiList;
for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) for (std::vector<BaseNode*>::iterator it = nodes.begin(), end = nodes.end();
it != end; ++it)
{ {
// get the name of the mesh if ((*it)->mProcessed)continue;
const ASE::Mesh& mesh = *((const ASE::Mesh*)pcScene->mMeshes[i]->mColors[2]);
// TODO: experimental quick'n'dirty, clean this up ...
std::string szMyName[2] = {mesh.mName,mesh.mParent} ;
// check whether our parent is known // check whether our parent is known
bool bKnowParent = false; bool bKnowParent = false;
for (unsigned int i2 = 0; i2 < pcScene->mNumMeshes;++i2)
// research the list, beginning from now and try to find out whether
// there is a node that references *us* as a parent
for (std::vector<BaseNode*>::const_iterator it2 = nodes.begin();
it2 != end; ++it2)
{ {
if (i2 == i)continue; if (it2 == it)continue;
const ASE::Mesh& mesh2 = *((const ASE::Mesh*)pcScene->mMeshes[i2]->mColors[2]);
// TODO: experimental quick'n'dirty, clean this up ... if ((*it2)->mParent == (*it)->mName)
std::string szMyName2[2] = {mesh2.mName,mesh2.mParent} ;
if (!ASSIMP_stricmp ( szMyName[1], szMyName2[0]))
{ {
bKnowParent = true; bKnowParent = true;
break; break;
} }
// check if there is another mesh with the same unknown parent
// that has already been handled and added to the list
if (i2 < i)
{
if (ASSIMP_stricmp ( szMyName[1], szMyName2[1]))
{
bKnowParent = true;
break;
}
}
} }
if (!bKnowParent) if (!bKnowParent)
{ {
aiList.push_back(i); aiList.push_back(*it);
} }
} }
// Are there ane orphaned nodes?
if (!aiList.empty()) if (!aiList.empty())
{ {
std::vector<aiNode*> apcNodes; std::vector<aiNode*> apcNodes;
@ -403,25 +515,28 @@ void ASEImporter::BuildNodes()
apcNodes.push_back(pcScene->mRootNode->mChildren[i]); apcNodes.push_back(pcScene->mRootNode->mChildren[i]);
delete[] pcScene->mRootNode->mChildren; delete[] pcScene->mRootNode->mChildren;
for (std::vector<unsigned int>::/*const_*/iterator for (std::vector<const BaseNode*>::/*const_*/iterator
i = aiList.begin(); i = aiList.begin();
i != aiList.end();++i) i != aiList.end();++i)
{ {
std::string* szMyName = (std::string*)pcScene->mMeshes[*i]->mColors[1]; const ASE::BaseNode* src = *i;
if (!szMyName)continue;
DefaultLogger::get()->info("Generating dummy node: " + szMyName[1] + ". " /*
DefaultLogger::get()->info("Generating dummy node: " + src->mName + ". "
"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");
*/
// the parent is not known, so we can assume that we must add // the parent is not known, so we can assume that we must add
// this node to the root node of the whole scene // this node to the root node of the whole scene
aiNode* pcNode = new aiNode(); aiNode* pcNode = new aiNode();
pcNode->mParent = pcScene->mRootNode; pcNode->mParent = pcScene->mRootNode;
pcNode->mName.Set(szMyName[1]); pcNode->mName.Set(src->mName);
this->AddNodes(pcNode,pcNode->mName.data); AddNodes(nodes,pcNode,pcNode->mName.data);
apcNodes.push_back(pcNode); apcNodes.push_back(pcNode);
} }
// Regenerate our output array
pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()]; pcScene->mRootNode->mChildren = new aiNode*[apcNodes.size()];
for (unsigned int i = 0; i < apcNodes.size();++i) for (unsigned int i = 0; i < apcNodes.size();++i)
pcScene->mRootNode->mChildren[i] = apcNodes[i]; pcScene->mRootNode->mChildren[i] = apcNodes[i];
@ -429,6 +544,8 @@ void ASEImporter::BuildNodes()
pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size(); pcScene->mRootNode->mNumChildren = (unsigned int)apcNodes.size();
} }
// Reset the third color set to NULL - we used this field to
// store a temporary pointer
for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
pcScene->mMeshes[i]->mColors[2] = NULL; pcScene->mMeshes[i]->mColors[2] = NULL;
@ -445,12 +562,14 @@ void ASEImporter::BuildNodes()
pc->mNumChildren = 0; pc->mNumChildren = 0;
delete pc; delete pc;
} }
// The root node should not have at least one child or the file is invalid
else if (!pcScene->mRootNode->mNumChildren) else if (!pcScene->mRootNode->mNumChildren)
{ {
throw new ImportErrorException("No nodes loaded. The ASE/ASK file is either empty or corrupt"); throw new ImportErrorException("No nodes loaded. The ASE/ASK file is either empty or corrupt");
} }
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::TransformVertices(ASE::Mesh& mesh) void ASEImporter::TransformVertices(ASE::Mesh& mesh)
{ {
@ -458,6 +577,7 @@ void ASEImporter::TransformVertices(ASE::Mesh& mesh)
// but we need row major // but we need row major
mesh.mTransform.Transpose(); mesh.mTransform.Transpose();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh) void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)
{ {
@ -556,6 +676,7 @@ void ASEImporter::BuildUniqueRepresentation(ASE::Mesh& mesh)
mesh.amTexCoords[c] = amTexCoords[c]; mesh.amTexCoords[c] = amTexCoords[c];
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::ConvertMaterial(ASE::Material& mat) void ASEImporter::ConvertMaterial(ASE::Material& mat)
{ {
@ -705,22 +826,22 @@ void ASEImporter::ConvertMaterial(ASE::Material& mat)
} }
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes) void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMeshes)
{ {
// validate the material index of the mesh // validate the material index of the mesh
if (mesh.iMaterialIndex >= this->mParser->m_vMaterials.size()) if (mesh.iMaterialIndex >= mParser->m_vMaterials.size())
{ {
mesh.iMaterialIndex = (unsigned int)this->mParser->m_vMaterials.size()-1; mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1;
DefaultLogger::get()->warn("Material index is out of range"); DefaultLogger::get()->warn("Material index is out of range");
} }
// if the material the mesh is assigned to is consisting of submeshes // if the material the mesh is assigned to is consisting of submeshes
// we'll need to split it ... Quak. // we'll need to split it ... Quak.
if (!this->mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty()) if (!mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials.empty())
{ {
std::vector<ASE::Material> vSubMaterials = this->mParser-> std::vector<ASE::Material> vSubMaterials = mParser->
m_vMaterials[mesh.iMaterialIndex].avSubMaterials; m_vMaterials[mesh.iMaterialIndex].avSubMaterials;
std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[ std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[
@ -752,7 +873,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
p_pcOut->mMaterialIndex = p; p_pcOut->mMaterialIndex = p;
// we will need this material // we will need this material
this->mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true; mParser->m_vMaterials[mesh.iMaterialIndex].avSubMaterials[p].bNeed = true;
// store the real index here ... color channel 3 // store the real index here ... color channel 3
p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
@ -775,15 +896,14 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
// 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];
if (p_pcOut->mNumVertices != 0) unsigned int iBase = 0,iIndex;
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];
unsigned int iBase = 0;
for (unsigned int q = 0; q < aiSplit[p].size();++q) for (unsigned int q = 0; q < aiSplit[p].size();++q)
{ {
unsigned int iIndex = aiSplit[p][q]; iIndex = aiSplit[p][q];
p_pcOut->mFaces[q].mIndices = new unsigned int[3]; p_pcOut->mFaces[q].mIndices = new unsigned int[3];
p_pcOut->mFaces[q].mNumIndices = 3; p_pcOut->mFaces[q].mNumIndices = 3;
@ -792,8 +912,8 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
{ {
const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t]; const uint32_t iIndex2 = mesh.mFaces[iIndex].mIndices[t];
p_pcOut->mVertices[iBase] = mesh.mPositions[iIndex2]; p_pcOut->mVertices[iBase] = mesh.mPositions [iIndex2];
p_pcOut->mNormals[iBase] = mesh.mNormals[iIndex2]; p_pcOut->mNormals [iBase] = mesh.mNormals [iIndex2];
// convert bones, if existing // convert bones, if existing
if (!mesh.mBones.empty()) if (!mesh.mBones.empty())
@ -814,21 +934,23 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
} }
++iBase; ++iBase;
} }
// Flip the face order
p_pcOut->mFaces[q].mIndices[0] = iBase-3; p_pcOut->mFaces[q].mIndices[0] = iBase-3;
p_pcOut->mFaces[q].mIndices[1] = iBase-2; p_pcOut->mFaces[q].mIndices[1] = iBase-2;
p_pcOut->mFaces[q].mIndices[2] = iBase-1; p_pcOut->mFaces[q].mIndices[2] = iBase-1;
} }
} }
// convert texture coordinates // convert texture coordinates (up to AI_MAX_NUMBER_OF_TEXTURECOORDS sets supported)
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 (!mesh.amTexCoords[c].empty()) if (!mesh.amTexCoords[c].empty())
{ {
p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices]; p_pcOut->mTextureCoords[c] = new aiVector3D[p_pcOut->mNumVertices];
unsigned int iBase = 0; iBase = 0;
for (unsigned int q = 0; q < aiSplit[p].size();++q) for (unsigned int q = 0; q < aiSplit[p].size();++q)
{ {
unsigned int iIndex = aiSplit[p][q]; iIndex = aiSplit[p][q];
for (unsigned int t = 0; t < 3;++t) for (unsigned int t = 0; t < 3;++t)
{ {
p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]]; p_pcOut->mTextureCoords[c][iBase++] = mesh.amTexCoords[c][mesh.mFaces[iIndex].mIndices[t]];
@ -843,10 +965,10 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
if (!mesh.mVertexColors.empty()) if (!mesh.mVertexColors.empty())
{ {
p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices]; p_pcOut->mColors[0] = new aiColor4D[p_pcOut->mNumVertices];
unsigned int iBase = 0; iBase = 0;
for (unsigned int q = 0; q < aiSplit[p].size();++q) for (unsigned int q = 0; q < aiSplit[p].size();++q)
{ {
unsigned int iIndex = aiSplit[p][q]; iIndex = aiSplit[p][q];
for (unsigned int t = 0; t < 3;++t) for (unsigned int t = 0; t < 3;++t)
{ {
p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]]; p_pcOut->mColors[0][iBase++] = mesh.mVertexColors[mesh.mFaces[iIndex].mIndices[t]];
@ -892,13 +1014,17 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
} }
else else
{ {
// otherwise we can simply copy the data to one output mesh // Otherwise we can simply copy the data to one output mesh
// This codepath needs less memory and uses fast memcpy()s
// to do the actual copying. So I think it is worth the
// effort here.
aiMesh* p_pcOut = new aiMesh(); aiMesh* p_pcOut = new aiMesh();
p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; p_pcOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
// set an empty sub material index // set an empty sub material index
p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX; p_pcOut->mMaterialIndex = ASE::Face::DEFAULT_MATINDEX;
this->mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true; mParser->m_vMaterials[mesh.iMaterialIndex].bNeed = true;
// store the real index here ... in color channel 3 // store the real index here ... in color channel 3
p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex; p_pcOut->mColors[3] = (aiColor4D*)(uintptr_t)mesh.iMaterialIndex;
@ -960,10 +1086,10 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
p_pcOut->mFaces[iFace].mNumIndices = 3; p_pcOut->mFaces[iFace].mNumIndices = 3;
p_pcOut->mFaces[iFace].mIndices = new unsigned int[3]; p_pcOut->mFaces[iFace].mIndices = new unsigned int[3];
// copy indices // copy indices (flip the face order, too)
p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[0]; p_pcOut->mFaces[iFace].mIndices[0] = mesh.mFaces[iFace].mIndices[2];
p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1]; p_pcOut->mFaces[iFace].mIndices[1] = mesh.mFaces[iFace].mIndices[1];
p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[2]; p_pcOut->mFaces[iFace].mIndices[2] = mesh.mFaces[iFace].mIndices[0];
} }
// copy vertex bones // copy vertex bones
@ -1009,9 +1135,11 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
++pcBone; ++pcBone;
} }
} }
// delete allocated storage
delete[] avBonesOut;
} }
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1020,24 +1148,24 @@ void ASEImporter::BuildMaterialIndices()
ai_assert(NULL != pcScene); ai_assert(NULL != pcScene);
// iterate through all materials and check whether we need them // iterate through all materials and check whether we need them
for (unsigned int iMat = 0; iMat < this->mParser->m_vMaterials.size();++iMat) for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
{ {
if (this->mParser->m_vMaterials[iMat].bNeed) if (mParser->m_vMaterials[iMat].bNeed)
{ {
// convert it to the aiMaterial layout // convert it to the aiMaterial layout
ASE::Material& mat = this->mParser->m_vMaterials[iMat]; ASE::Material& mat = mParser->m_vMaterials[iMat];
this->ConvertMaterial(mat); ConvertMaterial(mat);
TextureTransform::ApplyScaleNOffset(mat); TextureTransform::ApplyScaleNOffset(mat);
++pcScene->mNumMaterials; ++pcScene->mNumMaterials;
} }
for (unsigned int iSubMat = 0; iSubMat < this->mParser->m_vMaterials[ for (unsigned int iSubMat = 0; iSubMat < mParser->m_vMaterials[
iMat].avSubMaterials.size();++iSubMat) iMat].avSubMaterials.size();++iSubMat)
{ {
if (this->mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].bNeed) if (mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].bNeed)
{ {
// convert it to the aiMaterial layout // convert it to the aiMaterial layout
ASE::Material& mat = this->mParser->m_vMaterials[iMat].avSubMaterials[iSubMat]; ASE::Material& mat = mParser->m_vMaterials[iMat].avSubMaterials[iSubMat];
this->ConvertMaterial(mat); ConvertMaterial(mat);
TextureTransform::ApplyScaleNOffset(mat); TextureTransform::ApplyScaleNOffset(mat);
++pcScene->mNumMaterials; ++pcScene->mNumMaterials;
} }
@ -1049,15 +1177,15 @@ void ASEImporter::BuildMaterialIndices()
Dot3DS::Material** pcIntMaterials = new Dot3DS::Material*[pcScene->mNumMaterials]; Dot3DS::Material** pcIntMaterials = new Dot3DS::Material*[pcScene->mNumMaterials];
unsigned int iNum = 0; unsigned int iNum = 0;
for (unsigned int iMat = 0; iMat < this->mParser->m_vMaterials.size();++iMat) for (unsigned int iMat = 0; iMat < mParser->m_vMaterials.size();++iMat)
{ {
if (this->mParser->m_vMaterials[iMat].bNeed) if (mParser->m_vMaterials[iMat].bNeed)
{ {
ai_assert(NULL != this->mParser->m_vMaterials[iMat].pcInstance); ai_assert(NULL != mParser->m_vMaterials[iMat].pcInstance);
pcScene->mMaterials[iNum] = this->mParser->m_vMaterials[iMat].pcInstance; pcScene->mMaterials[iNum] = mParser->m_vMaterials[iMat].pcInstance;
// store the internal material, too // store the internal material, too
pcIntMaterials[iNum] = &this->mParser->m_vMaterials[iMat]; pcIntMaterials[iNum] = &mParser->m_vMaterials[iMat];
// iterate through all meshes and search for one which is using // iterate through all meshes and search for one which is using
// this top-level material index // this top-level material index
@ -1072,16 +1200,16 @@ void ASEImporter::BuildMaterialIndices()
} }
iNum++; iNum++;
} }
for (unsigned int iSubMat = 0; iSubMat < this->mParser->m_vMaterials[iMat].avSubMaterials.size();++iSubMat) for (unsigned int iSubMat = 0; iSubMat < mParser->m_vMaterials[iMat].avSubMaterials.size();++iSubMat)
{ {
if (this->mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].bNeed) if (mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].bNeed)
{ {
ai_assert(NULL != this->mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].pcInstance); ai_assert(NULL != mParser->m_vMaterials[iMat].avSubMaterials[iSubMat].pcInstance);
pcScene->mMaterials[iNum] = this->mParser->m_vMaterials[iMat]. pcScene->mMaterials[iNum] = mParser->m_vMaterials[iMat].
avSubMaterials[iSubMat].pcInstance; avSubMaterials[iSubMat].pcInstance;
// store the internal material, too // store the internal material, too
pcIntMaterials[iNum] = &this->mParser->m_vMaterials[iMat].avSubMaterials[iSubMat]; pcIntMaterials[iNum] = &mParser->m_vMaterials[iMat].avSubMaterials[iSubMat];
// iterate through all meshes and search for one which is using // iterate through all meshes and search for one which is using
// this sub-level material index // this sub-level material index
@ -1091,7 +1219,7 @@ void ASEImporter::BuildMaterialIndices()
iMat == (uintptr_t)pcScene->mMeshes[iMesh]->mColors[3]) iMat == (uintptr_t)pcScene->mMeshes[iMesh]->mColors[3])
{ {
pcScene->mMeshes[iMesh]->mMaterialIndex = iNum; pcScene->mMeshes[iMesh]->mMaterialIndex = iNum;
pcScene->mMeshes[iMesh]->mColors[3] = NULL; pcScene->mMeshes[iMesh]->mColors[3] = NULL;
} }
} }
iNum++; iNum++;
@ -1099,8 +1227,8 @@ void ASEImporter::BuildMaterialIndices()
} }
} }
// prepare for the next step // prepare for the next step
for (unsigned int hans = 0; hans < this->mParser->m_vMaterials.size();++hans) for (unsigned int hans = 0; hans < mParser->m_vMaterials.size();++hans)
TextureTransform::ApplyScaleNOffset(this->mParser->m_vMaterials[hans]); TextureTransform::ApplyScaleNOffset(mParser->m_vMaterials[hans]);
// now we need to iterate through all meshes, // now we need to iterate through all meshes,
// generating correct texture coordinates and material uv indices // generating correct texture coordinates and material uv indices
@ -1134,8 +1262,9 @@ void ASEImporter::GenerateNormals(ASE::Mesh& mesh)
qq = mesh.mNormals.begin(); qq = mesh.mNormals.begin();
qq != mesh.mNormals.end();++qq) qq != mesh.mNormals.end();++qq)
{ {
if (!(*qq).x || !(*qq).y || !(*qq).z) if ((*qq).x || (*qq).y || (*qq).z)
{ {
DefaultLogger::get()->debug("Using normal vectors from the ASE file. They are sometimes crappy");
return; return;
} }
} }

View File

@ -136,6 +136,16 @@ protected:
*/ */
void BuildNodes(); void BuildNodes();
// -------------------------------------------------------------------
/** Build output cameras
*/
void BuildCameras();
// -------------------------------------------------------------------
/** Build output lights
*/
void BuildLights();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Build output animations /** Build output animations
*/ */
@ -145,11 +155,14 @@ protected:
/** Add sub nodes to a node /** Add sub nodes to a node
* \param pcParent parent node to be filled * \param pcParent parent node to be filled
* \param szName Name of the parent node * \param szName Name of the parent node
* \param decompTrafo Decomposed absolute parent transformation mat * \param matrix Current transform
*/ */
void AddNodes(aiNode* pcParent,const char* szName); void AddNodes(std::vector<BaseNode*>& nodes,
void AddNodes(aiNode* pcParent,const char* szName, aiNode* pcParent,const char* szName);
const ASE::DecompTransform& decompTrafo);
void AddNodes(std::vector<BaseNode*>& nodes,
aiNode* pcParent,const char* szName,
const aiMatrix4x4& matrix);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Generate a default material and add it to the parser's list /** Generate a default material and add it to the parser's list

File diff suppressed because it is too large Load Diff

View File

@ -190,50 +190,49 @@ struct InheritanceInfo
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Stores a decomposed transformation matrix */ /** Represents an ASE file node. Base class for mesh, light and cameras */
struct DecompTransform struct BaseNode
{ {
//! Construction from a reference to an existing matrix enum Type {Light, Camera, Mesh, Dummy} mType;
DecompTransform(aiMatrix4x4& ref)
: vPosition(std::numeric_limits<float>::quiet_NaN(),0.0f,0.0f)
, vScaling(1.0f,1.0f,1.0f)
, mMatrix(ref)
{}
//! Translational component //! Constructor. Creates a default name for the node
mutable aiVector3D vPosition; BaseNode(Type _mType)
: mType (_mType)
//! Rotational component , mProcessed (false)
mutable aiQuaternion qRotation;
//! Scaling component
mutable aiVector3D vScaling;
//! Reference to the matrix being decomposed
const aiMatrix4x4& mMatrix;
//! Decomposes the matrix if this has not yet been done
inline void NeedDecomposedMatrixNOW() const
{
if (is_qnan(vPosition.x))
{
mMatrix.Decompose(vScaling,qRotation,vPosition);
}
}
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file mesh */
struct Mesh : public MeshWithSmoothingGroups<ASE::Face>
{
//! Constructor. Creates a default name for the mesh
Mesh() : bSkip(false)
{ {
// generate a default name for the node
static int iCnt = 0; static int iCnt = 0;
char szTemp[128]; // should be sufficiently large char szTemp[128]; // should be sufficiently large
::sprintf(szTemp,"UNNAMED_%i",iCnt++); ::sprintf(szTemp,"UNNAMED_%i",iCnt++);
mName = szTemp; mName = szTemp;
}
//! Name of the mesh
std::string mName;
//! Name of the parent of the node
//! "" if there is no parent ...
std::string mParent;
//! Transformation matrix of the node
aiMatrix4x4 mTransform;
//! Specifies which axes transformations a node inherits
//! from its parent ...
InheritanceInfo inherit;
bool mProcessed;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE file mesh */
struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode
{
//! Constructor.
Mesh()
: BaseNode (BaseNode::Mesh)
, bSkip (false)
{
// use 2 texture vertex components by default // use 2 texture vertex components by default
for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
this->mNumUVComponents[c] = 2; this->mNumUVComponents[c] = 2;
@ -242,13 +241,6 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>
iMaterialIndex = Face::DEFAULT_MATINDEX; iMaterialIndex = Face::DEFAULT_MATINDEX;
} }
//! Name of the mesh
std::string mName;
//! Name of the parent of the mesh
//! "" if there is no parent ...
std::string mParent;
//! List of all texture coordinate sets //! List of all texture coordinate sets
std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
@ -261,9 +253,6 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>
//! List of all bones //! List of all bones
std::vector<Bone> mBones; std::vector<Bone> mBones;
//! Transformation matrix of the mesh
aiMatrix4x4 mTransform;
//! Animation channels for the node //! Animation channels for the node
Animation mAnim; Animation mAnim;
@ -275,10 +264,45 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>
//! used internally //! used internally
bool bSkip; bool bSkip;
};
//! Specifies which axes transformations a node inherits // ---------------------------------------------------------------------------
//! from its parent ... /** Helper structure to represent an ASE light source */
InheritanceInfo inherit; struct Light : public BaseNode
{
enum LightType
{
OMNI
};
//! Constructor.
Light()
: BaseNode (BaseNode::Light)
, mLightType (OMNI)
, mColor (1.f,1.f,1.f)
, mIntensity (1.f) // light is white by default
{
}
LightType mLightType;
aiColor3D mColor;
float mIntensity;
};
// ---------------------------------------------------------------------------
/** Helper structure to represent an ASE camera */
struct Camera : public BaseNode
{
//! Constructor
Camera()
: BaseNode (BaseNode::Camera)
, mFOV (0.75f) // in radians
, mNear (0.1f)
, mFar (1000.f) // could be zero
{
}
float mFOV, mNear, mFar;
}; };
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
@ -317,6 +341,23 @@ private:
//! \param mesh Mesh object to be filled //! \param mesh Mesh object to be filled
void ParseLV1GeometryObjectBlock(Mesh& mesh); void ParseLV1GeometryObjectBlock(Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *LIGHTOBJECT block in a file
//! \param light Light object to be filled
void ParseLV1LightObjectBlock(Light& mesh);
// -------------------------------------------------------------------
//! Parse a *CAMERAOBJECT block in a file
//! \param cam Camera object to be filled
void ParseLV1CameraObjectBlock(Camera& cam);
// -------------------------------------------------------------------
//! Parse the shared parts of the *GEOMOBJECT, *LIGHTOBJECT and
//! *CAMERAOBJECT chunks.
//! \param mesh ..
//! \return true = token parsed, get next please
bool ParseSharedNodeInfo(ASE::BaseNode& mesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse a *MATERIAL blocks in a material list //! Parse a *MATERIAL blocks in a material list
//! \param mat Material structure to be filled //! \param mat Material structure to be filled
@ -324,8 +365,8 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse a *NODE_TM block in a file //! Parse a *NODE_TM block in a file
//! \param mesh Mesh object to be filled //! \param mesh Node (!) object to be filled
void ParseLV2NodeTransformBlock(Mesh& mesh); void ParseLV2NodeTransformBlock(BaseNode& mesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse a *TM_ANIMATION block in a file //! Parse a *TM_ANIMATION block in a file
@ -339,6 +380,16 @@ private:
//! \param mesh Mesh object to be filled //! \param mesh Mesh object to be filled
void ParseLV2MeshBlock(Mesh& mesh); void ParseLV2MeshBlock(Mesh& mesh);
// -------------------------------------------------------------------
//! Parse a *LIGHT_SETTINGS block in a file
//! \param light Light object to be filled
void ParseLV2LightSettingsBlock(Light& light);
// -------------------------------------------------------------------
//! Parse a *CAMERA_SETTINGS block in a file
//! \param cam Camera object to be filled
void ParseLV2CameraSettingsBlock(Camera& cam);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse the *MAP_XXXXXX blocks in a material //! Parse the *MAP_XXXXXX blocks in a material
//! \param map Texture structure to be filled //! \param map Texture structure to be filled
@ -522,10 +573,15 @@ public:
//! List of all meshes found in the file //! List of all meshes found in the file
std::vector<Mesh> m_vMeshes; std::vector<Mesh> m_vMeshes;
//! List of all lights found in the file
std::vector<Light> m_vLights;
//! List of all cameras found in the file
std::vector<Camera> m_vCameras;
//! Current line in the file //! Current line in the file
unsigned int iLineNumber; unsigned int iLineNumber;
//! First frame //! First frame
unsigned int iFirstFrame; unsigned int iFirstFrame;

View File

@ -60,9 +60,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// If we have at least VC8 some C string manipulation functions // If we have at least VC8 some C string manipulation functions
// are mapped to their safe _s counterparts (e.g. _itoa_s). // are mapped to their safe _s counterparts (e.g. _itoa_s).
// ******************************************************************* // *******************************************************************
# if _MSC_VER >= 1400 && !(defined _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) #if _MSC_VER >= 1400 && !(defined _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
# define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 # define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
# endif #endif
// ******************************************************************* // *******************************************************************
// STL headers - we need quite a lot of them // STL headers - we need quite a lot of them

View File

@ -105,10 +105,15 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// assert() it here. // assert() it here.
//assert( must be verbose, dammit); //assert( must be verbose, dammit);
if (pMesh->mTangents) // thisimplies that mBitangents is also there
return false;
if (pMesh->mTangents && pMesh->mBitangents || // If the mesh consists of lines and/or points but not of
!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) // triangles or higher-order polygons the normal vectors
// are undefined.
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
{ {
DefaultLogger::get()->info("Tangents are undefined for line and point meshes");
return false; return false;
} }
@ -121,6 +126,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
const float angleEpsilon = 0.9999f; const float angleEpsilon = 0.9999f;
std::vector<bool> vertexDone( pMesh->mNumVertices, false); std::vector<bool> vertexDone( pMesh->mNumVertices, false);
const float qnan = std::numeric_limits<float>::quiet_NaN();
// create space for the tangents and bitangents // create space for the tangents and bitangents
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
@ -138,8 +144,14 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
const aiFace& face = pMesh->mFaces[a]; const aiFace& face = pMesh->mFaces[a];
if (face.mNumIndices < 3) if (face.mNumIndices < 3)
{ {
// There are less than three indices, thus the tangent vector
// is not defined. We are finished with these vertices now,
// their tangent vectors are set to qnan.
for (unsigned int i = 0; i < face.mNumIndices;++i) for (unsigned int i = 0; i < face.mNumIndices;++i)
{
vertexDone[face.mIndices[i]] = true; vertexDone[face.mIndices[i]] = true;
meshTang [face.mIndices[i]] = qnan;
}
continue; continue;
} }

View File

@ -430,14 +430,14 @@ bool DXFImporter::ParsePolyLine()
// optional number of vertices // optional number of vertices
case 71: case 71:
{ {
positions.reserve(std::min(std::max(100u, strtol10(cursor)),100000000u)); positions.reserve(strtol10(cursor));
break; break;
} }
// optional number of faces // optional number of faces
case 72: case 72:
{ {
indices.reserve(std::min(std::max(100u, strtol10(cursor)),100000000u) * 4u); indices.reserve(strtol10(cursor) * 4u);
break; break;
} }
@ -496,6 +496,8 @@ bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned i
case 0: ret = true;break; case 0: ret = true;break;
// todo - handle the correct layer for the vertex // todo - handle the correct layer for the vertex
// At the moment it is assumed that all vertices of
// a polyline are placed on the same global layer.
// x position of the first corner // x position of the first corner
case 10: out.x = fast_atof(cursor);break; case 10: out.x = fast_atof(cursor);break;

View File

@ -42,10 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_DXFLOADER_H_INCLUDED #ifndef AI_DXFLOADER_H_INCLUDED
#define AI_DXFLOADER_H_INCLUDED #define AI_DXFLOADER_H_INCLUDED
#include <vector>
#include "BaseImporter.h"
#include "../include/aiTypes.h"
namespace Assimp { namespace Assimp {
@ -159,7 +155,8 @@ protected:
* Wont't be modified otherwise. Size must be at least 4. * Wont't be modified otherwise. Size must be at least 4.
* @return false if the end of the file was reached * @return false if the end of the file was reached
*/ */
bool ParsePolyLineVertex(aiVector3D& out, aiColor4D& clr, unsigned int* outIdx); bool ParsePolyLineVertex(aiVector3D& out, aiColor4D& clr,
unsigned int* outIdx);
private: private:

View File

@ -0,0 +1,152 @@
/*
---------------------------------------------------------------------------
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 DeterminePTypeHelperProcess and
* SortByPTypeProcess post-process steps.
*/
#include "AssimpPCH.h"
// internal headers
#include "ProcessHelper.h"
#include "FindDegenerates.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
FindDegeneratesProcess::FindDegeneratesProcess()
{
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FindDegeneratesProcess::~FindDegeneratesProcess()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const
{
return 0 != (pFlags & aiProcess_FindDegenerates);
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void FindDegeneratesProcess::Execute( aiScene* pScene)
{
DefaultLogger::get()->debug("FindDegeneratesProcess begin");
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
aiMesh* mesh = pScene->mMeshes[i];
mesh->mPrimitiveTypes = 0;
unsigned int deg = 0;
for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
{
aiFace& face = mesh->mFaces[a];
bool first = true;
// check whether the face contains degenerated entries
for (register unsigned int i = 0; i < face.mNumIndices; ++i)
{
for (register unsigned int a = i+1; a < face.mNumIndices; ++a)
{
if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[a]])
{
// we have found a matching vertex position
// remove the corresponding index from the array
for (unsigned int m = a; m < face.mNumIndices-1; ++m)
{
face.mIndices[m] = face.mIndices[m+1];
}
--a;
--face.mNumIndices;
// NOTE: we set the removed vertex index to an unique value
// to make sure the developer gets notified when his
// application attemps to access this data.
face.mIndices[face.mNumIndices] = 0xdeadbeef;
if(first)
{
++deg;
first = false;
}
}
}
}
// We need to update the primitive flags array of the mesh.
// Unfortunately it is not possible to execute
// FindDegenerates before DeterminePType. The latter does
// nothing if the primitive flags have already been set by
// the loader - our changes would be ignored. Although
// we could use some tricks regarding - i.e setting
// mPrimitiveTypes to 0 in every case - but this is the cleanest
// way and causes no additional dependencies in the pipeline.
switch (face.mNumIndices)
{
case 1u:
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
break;
case 2u:
mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
break;
case 3u:
mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
break;
default:
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
break;
};
}
if (deg)
{
char s[64];
itoa10(s,deg);
DefaultLogger::get()->warn(std::string("Found ") + s + " degenerated primitives");
}
}
DefaultLogger::get()->debug("FindDegeneratesProcess finished");
}

View File

@ -0,0 +1,80 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file Defines a post processing step to search all meshes for
degenerated faces */
#ifndef AI_FINDDEGENERATESPROCESS_H_INC
#define AI_FINDDEGENERATESPROCESS_H_INC
#include "BaseProcess.h"
#include "../include/aiMesh.h"
class FindDegeneratesProcessTest;
namespace Assimp {
// ---------------------------------------------------------------------------
/** FindDegeneratesProcess: Searches a mesh for degenerated triangles.
*/
class ASSIMP_API FindDegeneratesProcess : public BaseProcess
{
friend class Importer;
friend class ::FindDegeneratesProcessTest; // grant the unit test full access to us
protected:
/** Constructor to be privately used by Importer */
FindDegeneratesProcess();
/** Destructor, private as well */
~FindDegeneratesProcess();
public:
// -------------------------------------------------------------------
bool IsActive( unsigned int pFlags) const;
// -------------------------------------------------------------------
void Execute( aiScene* pScene);
private:
};
}
#endif // !! AI_FINDDEGENERATESPROCESS_H_INC

View File

@ -70,8 +70,7 @@ FindInvalidDataProcess::~FindInvalidDataProcess()
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const
{ {
// this step is always active return 0 != (pFlags & aiProcess_FindInvalidData);
return true;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -258,18 +257,21 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
} }
// process mesh normals // process mesh normals
if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices,"normals",dirtyMask)) if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices,
"normals",dirtyMask))
ret = true; ret = true;
// process mesh tangents // process mesh tangents
if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,"tangents",dirtyMask)) if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,
"tangents",dirtyMask))
{ {
delete[] pMesh->mBitangents; pMesh->mBitangents = NULL; delete[] pMesh->mBitangents; pMesh->mBitangents = NULL;
ret = true; ret = true;
} }
// process mesh bitangents // process mesh bitangents
if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,"bitangents",dirtyMask)) if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,
"bitangents",dirtyMask))
{ {
delete[] pMesh->mTangents; pMesh->mTangents = NULL; delete[] pMesh->mTangents; pMesh->mTangents = NULL;
ret = true; ret = true;

View File

@ -53,8 +53,7 @@ namespace Assimp
{ {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** The FindInvalidData postprocessing step is always active, there is /** The FindInvalidData postprocessing step. It searches the mesh data
* no corresponding aiPostProcess flag. It searches the mesh data
* for parts that are obviously invalid and removes them. * for parts that are obviously invalid and removes them.
* *
* Originally this was a workaround for some models written by Blender * Originally this was a workaround for some models written by Blender

View File

@ -108,7 +108,8 @@ void GenVertexNormalsProcess::Execute( aiScene* pScene)
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex) bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex)
{ {
if (NULL != pMesh->mNormals)return false; if (NULL != pMesh->mNormals)
return false;
// If the mesh consists of lines and/or points but not of // If the mesh consists of lines and/or points but not of
// triangles or higher-order polygons the normal vectors // triangles or higher-order polygons the normal vectors

View File

@ -167,6 +167,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_BUILD_NO_FINDINVALIDDATA_PROCESS #ifndef AI_BUILD_NO_FINDINVALIDDATA_PROCESS
# include "FindInvalidDataProcess.h" # include "FindInvalidDataProcess.h"
#endif #endif
#ifndef AI_BUILD_NO_FINDDEGENERATES_PROCESS
# include "FindDegenerates.h"
#endif
// NOTE: the preprocessor code has been moved to the header as // NOTE: the preprocessor code has been moved to the header as
// we've also declared the DeterminePType process in it, which // we've also declared the DeterminePType process in it, which
@ -272,6 +275,11 @@ Importer::Importer() :
mPostProcessingSteps.push_back( new DeterminePTypeHelperProcess()); mPostProcessingSteps.push_back( new DeterminePTypeHelperProcess());
#if (!defined AI_BUILD_NO_FINDDEGENERATES_PROCESS)
mPostProcessingSteps.push_back( new FindDegeneratesProcess());
#endif
#if (!defined AI_BUILD_NO_REMOVEVC_PROCESS) #if (!defined AI_BUILD_NO_REMOVEVC_PROCESS)
mPostProcessingSteps.push_back( new RemoveVCProcess()); mPostProcessingSteps.push_back( new RemoveVCProcess());
#endif #endif
@ -535,9 +543,9 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
mScene = imp->ReadFile( pFile, mIOHandler); mScene = imp->ReadFile( pFile, mIOHandler);
// if successful, apply all active post processing steps to the imported data // if successful, apply all active post processing steps to the imported data
DefaultLogger::get()->info("Import succesful, entering postprocessing-steps");
if( mScene) if( mScene)
{ {
DefaultLogger::get()->info("Import successful, entering postprocessing-steps");
#ifdef _DEBUG #ifdef _DEBUG
if (bExtraVerbose) if (bExtraVerbose)
{ {

View File

@ -0,0 +1,91 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file Declaration of the .LWS (LightWave Scene Format) importer class. */
#ifndef AI_LWSLOADER_H_INCLUDED
#define AI_LWSLOADER_H_INCLUDED
namespace Assimp {
// ---------------------------------------------------------------------------
/** LWS (LightWave Scene Format) importer class.
*
* This class does heavily depend on the LWO importer class. LWS files
* contain mainly descriptions how LWO objects are composed together
* in a scene.
*/
class LWSImporter : public BaseImporter
{
friend class Importer;
protected:
/** Constructor to be privately used by Importer */
LWSImporter();
/** Destructor, private as well */
~LWSImporter();
public:
// -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const;
protected:
// -------------------------------------------------------------------
/** Called by Importer::GetExtensionList() for each loaded importer.
* See BaseImporter::GetExtensionList() for details
*/
void GetExtensionList(std::string& append)
{
append.append("*.lws");
}
private:
};
} // end of namespace Assimp
#endif // AI_LWSIMPORTER_H_INC

View File

@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ParsingUtils.h" #include "ParsingUtils.h"
#include "StandardShapes.h" #include "StandardShapes.h"
#include "fast_atof.h" #include "fast_atof.h"
#include "RemoveComments.h"
using namespace Assimp; using namespace Assimp;
@ -75,18 +75,13 @@ bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
std::string extension = pFile.substr( pos); std::string extension = pFile.substr( pos);
// extensions: enff and nff // extensions: enff and nff
if (!extension.length() || extension[0] != '.')return false; for( std::string::iterator it = extension.begin(); it != extension.end(); ++it)
if (extension.length() == 4) *it = tolower( *it);
{
return !(extension[1] != 'n' && extension[1] != 'N' || if( extension == ".nff" || extension == ".enff")
extension[2] != 'f' && extension[2] != 'F' || return true;
extension[3] != 'f' && extension[3] != 'F');
} return false;
else return !( extension.length() != 5 ||
extension[1] != 'e' && extension[1] != 'E' ||
extension[2] != 'n' && extension[2] != 'N' ||
extension[3] != 'f' && extension[3] != 'F' ||
extension[4] != 'f' && extension[4] != 'F');
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -110,6 +105,122 @@ bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
currentMesh.radius = radius; \ currentMesh.radius = radius; \
currentMesh.center = center; currentMesh.center = center;
// ------------------------------------------------------------------------------------------------
#define AI_NFF2_GET_NEXT_TOKEN() \
do \
{ \
if (!GetNextLine(buffer,line)) \
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read next token");break;} \
SkipSpaces(line,&sz); \
} \
while(IsLineEnd(*sz))
// ------------------------------------------------------------------------------------------------
// Loads the materail table for the NFF2 file format from an external file
void NFFImporter::LoadNFF2MaterialTable(std::vector<ShadingInfo>& output,
const std::string& path, IOSystem* pIOHandler)
{
boost::scoped_ptr<IOStream> file( pIOHandler->Open( path, "rb"));
// Check whether we can read from the file
if( !file.get())
{
DefaultLogger::get()->error("NFF2: Unable to open material library " + path + ".");
return;
}
// get the size of the file
const unsigned int m = (unsigned int)file->FileSize();
// allocate storage and copy the contents of the file to a memory buffer
// (terminate it with zero)
std::vector<char> mBuffer2(m+1);
file->Read(&mBuffer2[0],m,1);
const char* buffer = &mBuffer2[0];
mBuffer2[m] = '\0';
// First of all: remove all comments from the file
CommentRemover::RemoveLineComments("//",&mBuffer2[0]);
// The file should start with the magic sequence "mat"
if (!TokenMatch(buffer,"mat",3))
{
DefaultLogger::get()->error("NFF2: Not a valid material library " + path + ".");
return;
}
ShadingInfo* curShader = NULL;
// No read the file line per line
char line[4096];
const char* sz;
while (GetNextLine(buffer,line))
{
SkipSpaces(line,&sz);
// 'version' defines the version of the file format
if (TokenMatch(sz,"version",7))
{
DefaultLogger::get()->info("NFF (Sense8) material library file format: " + std::string(sz));
}
// 'matdef' starts a new material in the file
else if (TokenMatch(sz,"matdef",6))
{
// add a new material to the list
output.push_back( ShadingInfo() );
curShader = & output.back();
// parse the name of the material
}
else if (!TokenMatch(sz,"valid",5))
{
// check whether we have an active material at the moment
if (!IsLineEnd(*sz))
{
if (!curShader)
{
DefaultLogger::get()->error(std::string("NFF2 material library: Found element ") +
sz + "but there is no active material");
continue;
}
}
else continue;
// now read the material property and determine its type
aiColor3D c;
if (TokenMatch(sz,"ambient",7))
{
AI_NFF_PARSE_TRIPLE(c);
curShader->ambient = c;
}
else if (TokenMatch(sz,"diffuse",7) || TokenMatch(sz,"ambientdiffuse",14) /* correct? */)
{
AI_NFF_PARSE_TRIPLE(c);
curShader->diffuse = c;
}
else if (TokenMatch(sz,"specular",8))
{
AI_NFF_PARSE_TRIPLE(c);
curShader->specular = c;
}
else if (TokenMatch(sz,"emission",8))
{
AI_NFF_PARSE_TRIPLE(c);
curShader->emissive = c;
}
else if (TokenMatch(sz,"shininess",9))
{
AI_NFF_PARSE_FLOAT(curShader->shininess);
}
else if (TokenMatch(sz,"opacity",7))
{
AI_NFF_PARSE_FLOAT(curShader->opacity);
}
}
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void NFFImporter::InternReadFile( const std::string& pFile, void NFFImporter::InternReadFile( const std::string& pFile,
@ -118,7 +229,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
// Check whether we can read from the file // Check whether we can read from the file
if( file.get() == NULL) if( !file.get())
throw new ImportErrorException( "Failed to open NFF file " + pFile + "."); throw new ImportErrorException( "Failed to open NFF file " + pFile + ".");
unsigned int m = (unsigned int)file->FileSize(); unsigned int m = (unsigned int)file->FileSize();
@ -142,7 +253,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// camera parameters // camera parameters
aiVector3D camPos, camUp(0.f,1.f,0.f), camLookAt(0.f,0.f,1.f); aiVector3D camPos, camUp(0.f,1.f,0.f), camLookAt(0.f,0.f,1.f);
float angle; float angle = 45.f;
aiVector2D resolution; aiVector2D resolution;
bool hasCam = false; bool hasCam = false;
@ -172,16 +283,24 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// check whether this is the NFF2 file format // check whether this is the NFF2 file format
if (TokenMatch(buffer,"nff",3)) if (TokenMatch(buffer,"nff",3))
{ {
const float qnan = std::numeric_limits<float>::quiet_NaN();
const aiColor4D cQNAN = aiColor4D (qnan,0.f,0.f,1.f);
const aiVector3D vQNAN = aiVector3D(qnan,0.f,0.f);
// another NFF file format ... just a raw parser has been implemented // another NFF file format ... just a raw parser has been implemented
// no support for textures yet, I don't think it is worth the effort // no support for further details, I don't think it is worth the effort
// http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/nff/nff2.html // http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/nff/nff2.html
// http://www.netghost.narod.ru/gff/graphics/summary/sense8.htm
// First of all: remove all comments from the file
CommentRemover::RemoveLineComments("//",&mBuffer2[0]);
while (GetNextLine(buffer,line)) while (GetNextLine(buffer,line))
{ {
sz = line; SkipSpaces(line,&sz);
if (TokenMatch(sz,"version",7)) if (TokenMatch(sz,"version",7))
{ {
DefaultLogger::get()->info("NFF (alt.) file format: " + std::string(sz)); DefaultLogger::get()->info("NFF (Sense8) file format: " + std::string(sz));
} }
else if (TokenMatch(sz,"viewpos",7)) else if (TokenMatch(sz,"viewpos",7))
{ {
@ -193,79 +312,341 @@ void NFFImporter::InternReadFile( const std::string& pFile,
AI_NFF_PARSE_TRIPLE(camLookAt); AI_NFF_PARSE_TRIPLE(camLookAt);
hasCam = true; hasCam = true;
} }
else if (TokenMatch(sz,"//",2)) // This starts a new object section
else if (!IsSpaceOrNewLine(*sz))
{ {
// comment ... unsigned int subMeshIdx = 0;
DefaultLogger::get()->info(sz);
}
else if (!IsSpace(*sz))
{
// must be a new object
meshes.push_back(MeshInfo(PatchType_Simple));
MeshInfo& mesh = meshes.back();
if (!GetNextLine(buffer,line)) // read the name of the object, skip all spaces
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read number of vertices");break;} // at the end of it.
const char* sz3 = sz;
while (!IsSpaceOrNewLine(*sz))++sz;
std::string objectName = std::string(sz3,(unsigned int)(sz-sz3));
SkipSpaces(line,&sz); const unsigned int objStart = (unsigned int)meshes.size();
// There could be a material table in a separate file
std::vector<ShadingInfo> materialTable;
while (true)
{
AI_NFF2_GET_NEXT_TOKEN();
// material table - an external file
if (TokenMatch(sz,"mtable",6))
{
SkipSpaces(&sz);
sz3 = sz;
while (!IsSpaceOrNewLine(*sz))++sz;
const unsigned int diff = (unsigned int)(sz-sz3);
if (!diff)DefaultLogger::get()->warn("NFF2: Found empty mtable token");
else
{
// The material table has the file extension .mat.
// If it is not there, we need to append it
std::string path = std::string(sz3,diff);
if(std::string::npos == path.find_last_of(".mat"))
{
path.append(".mat");
}
// Now extract the working directory from the path to
// this file and append the material library filename
// to it.
std::string::size_type s;
if ((std::string::npos == (s = path.find_last_of('\\')) || !s) &&
(std::string::npos == (s = path.find_last_of('/')) || !s) )
{
s = pFile.find_last_of('\\');
if (std::string::npos == s)s = pFile.find_last_of('/');
if (std::string::npos != s)
{
path = pFile.substr(0,s+1) + path;
}
}
LoadNFF2MaterialTable(materialTable,path,pIOHandler);
}
}
else break;
}
// read the numbr of vertices
unsigned int num = ::strtol10(sz,&sz); unsigned int num = ::strtol10(sz,&sz);
std::vector<aiVector3D> tempPositions; // temporary storage
std::vector<aiVector3D> outPositions; std::vector<aiColor4D> tempColors;
mesh.vertices.reserve(num*3); std::vector<aiVector3D> tempPositions,tempTextureCoords,tempNormals;
mesh.colors.reserve (num*3);
tempPositions.reserve(num); bool hasNormals = false,hasUVs = false,hasColor = false;
tempPositions.reserve (num);
tempColors.reserve (num);
tempNormals.reserve (num);
tempTextureCoords.reserve (num);
for (unsigned int i = 0; i < num; ++i) for (unsigned int i = 0; i < num; ++i)
{ {
if (!GetNextLine(buffer,line)) AI_NFF2_GET_NEXT_TOKEN();
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read vertices");break;}
sz = line;
aiVector3D v; aiVector3D v;
AI_NFF_PARSE_TRIPLE(v); AI_NFF_PARSE_TRIPLE(v);
tempPositions.push_back(v); tempPositions.push_back(v);
}
if (!GetNextLine(buffer,line))
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read number of faces");break;}
if (!num)throw new ImportErrorException("NFF2: There are zero vertices"); // parse all other attributes in the line
while (true)
SkipSpaces(line,&sz);
num = ::strtol10(sz,&sz);
mesh.faces.reserve(num);
for (unsigned int i = 0; i < num; ++i)
{
if (!GetNextLine(buffer,line))
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read faces");break;}
SkipSpaces(line,&sz);
unsigned int idx, numIdx = ::strtol10(sz,&sz);
if (numIdx)
{ {
mesh.faces.push_back(numIdx); SkipSpaces(&sz);
for (unsigned int a = 0; a < numIdx;++a) if (IsLineEnd(*sz))break;
// color definition
if (TokenMatch(sz,"0x",2))
{ {
SkipSpaces(sz,&sz); hasColor = true;
idx = ::strtol10(sz,&sz); register unsigned int numIdx = ::strtol16(sz,&sz);
if (idx >= (unsigned int)tempPositions.size()) aiColor4D clr;
{ clr.a = 1.f;
DefaultLogger::get()->error("NFF2: Index overflow");
idx = 0; // 0xRRGGBB
} clr.r = ((numIdx >> 16u) & 0xff) / 255.f;
mesh.vertices.push_back(tempPositions[idx]); clr.g = ((numIdx >> 8u) & 0xff) / 255.f;
clr.b = ((numIdx) & 0xff) / 255.f;
tempColors.push_back(clr);
}
// normal vector
else if (TokenMatch(sz,"norm",4))
{
hasNormals = true;
AI_NFF_PARSE_TRIPLE(v);
tempNormals.push_back(v);
}
// UV coordinate
else if (TokenMatch(sz,"uv",2))
{
hasUVs = true;
AI_NFF_PARSE_FLOAT(v.x);
AI_NFF_PARSE_FLOAT(v.y);
v.z = 0.f;
tempTextureCoords.push_back(v);
} }
} }
SkipSpaces(sz,&sz); // fill in dummies for all attributes that have not been set
idx = ::strtol_cppstyle(sz,&sz); if (tempNormals.size() != tempPositions.size())
aiColor4D clr; tempNormals.push_back(vQNAN);
clr.r = ((numIdx >> 8u) & 0xf) / 16.f;
clr.g = ((numIdx >> 4u) & 0xf) / 16.f; if (tempTextureCoords.size() != tempPositions.size())
clr.b = ((numIdx) & 0xf) / 16.f; tempTextureCoords.push_back(vQNAN);
clr.a = 1.f;
for (unsigned int a = 0; a < numIdx;++a) if (tempColors.size() != tempPositions.size())
mesh.colors.push_back(clr); tempColors.push_back(cQNAN);
}
AI_NFF2_GET_NEXT_TOKEN();
if (!num)throw new ImportErrorException("NFF2: There are zero vertices");
num = ::strtol10(sz,&sz);
std::vector<unsigned int> tempIdx;
tempIdx.reserve(10);
for (unsigned int i = 0; i < num; ++i)
{
AI_NFF2_GET_NEXT_TOKEN();
SkipSpaces(line,&sz);
unsigned int numIdx = ::strtol10(sz,&sz);
// read all faces indices
if (numIdx)
{
// mesh.faces.push_back(numIdx);
// tempIdx.erase(tempIdx.begin(),tempIdx.end());
tempIdx.resize(numIdx);
for (unsigned int a = 0; a < numIdx;++a)
{
SkipSpaces(sz,&sz);
m = ::strtol10(sz,&sz);
if (m >= (unsigned int)tempPositions.size())
{
DefaultLogger::get()->error("NFF2: Vertex index overflow");
m= 0;
}
// mesh.vertices.push_back (tempPositions[idx]);
tempIdx[a] = m;
}
}
// build a temporary shader object for the face.
ShadingInfo shader;
unsigned int matIdx = 0;
// white material color - we have vertex colors
shader.color = aiColor3D(1.f,1.f,1.f);
aiColor4D c = aiColor4D(1.f,1.f,1.f,1.f);
while (true)
{
SkipSpaces(sz,&sz);
if(IsLineEnd(*sz))break;
// per-polygon colors
if (TokenMatch(sz,"0x",2))
{
hasColor = true;
const char* sz2 = sz;
numIdx = ::strtol16(sz,&sz);
const unsigned int diff = (unsigned int)(sz-sz2);
// 0xRRGGBB
if (diff > 3)
{
c.r = ((numIdx >> 16u) & 0xff) / 255.f;
c.g = ((numIdx >> 8u) & 0xff) / 255.f;
c.b = ((numIdx) & 0xff) / 255.f;
}
// 0xRGB
else
{
c.r = ((numIdx >> 8u) & 0xf) / 16.f;
c.g = ((numIdx >> 4u) & 0xf) / 16.f;
c.b = ((numIdx) & 0xf) / 16.f;
}
}
// TODO - implement texture mapping here
#if 0
// mirror vertex texture coordinate?
else if (TokenMatch(sz,"mirror",6))
{
}
// texture coordinate scaling
else if (TokenMatch(sz,"scale",5))
{
}
// texture coordinate translation
else if (TokenMatch(sz,"trans",5))
{
}
// texture coordinate rotation angle
else if (TokenMatch(sz,"rot",3))
{
}
#endif
// texture file name for this polygon + mapping information
else if ('_' == sz[0])
{
// get mapping information
switch (sz[1])
{
case 'v':
case 'V':
shader.shaded = false;
break;
case 't':
case 'T':
case 'u':
case 'U':
DefaultLogger::get()->warn("Unsupported NFF2 texture attribute: trans");
};
if (!sz[1] || '_' != sz[2])
{
DefaultLogger::get()->warn("NFF2: Expected underscore after texture attributes");
continue;
}
const char* sz2 = sz+3;
while (!IsSpaceOrNewLine( *sz ))++sz;
const unsigned int diff = (unsigned int)(sz-sz2);
if (diff)shader.texFile = std::string(sz2,diff);
}
// Two-sided material?
else if (TokenMatch(sz,"both",4))
{
shader.twoSided = true;
}
// Material ID?
else if (!materialTable.empty() && TokenMatch(sz,"matid",5))
{
SkipSpaces(&sz);
matIdx = ::strtol10(sz,&sz);
if (matIdx >= materialTable.size())
{
DefaultLogger::get()->error("NFF2: Material index overflow.");
matIdx = 0;
}
// now combine our current shader with the shader we
// read from the material table.
ShadingInfo& mat = materialTable[matIdx];
shader.ambient = mat.ambient;
shader.diffuse = mat.diffuse;
shader.emissive = mat.emissive;
shader.opacity = mat.opacity;
shader.specular = mat.specular;
shader.shininess = mat.shininess;
}
else SkipToken(sz);
}
// search the list of all shaders we have for this object whether
// there is an identical one. In this case, we append our mesh
// data to it.
MeshInfo* mesh = NULL;
for (std::vector<MeshInfo>::iterator it = meshes.begin() + objStart, end = meshes.end();
it != end; ++it)
{
if ((*it).shader == shader && (*it).matIndex == matIdx)
{
// we have one, we can append our data to it
mesh = &(*it);
}
}
if (!mesh)
{
meshes.push_back(MeshInfo(PatchType_Simple,false));
mesh = &meshes.back();
mesh->matIndex = matIdx;
// We need to add a new mesh to the list. We assign
// an unique name to it to make sure the scene will
// pass the validation step for the moment.
// TODO: fix naming of objects in the scenegraph later
if (objectName.length())
{
::strcpy(mesh->name,objectName.c_str());
itoa10(&mesh->name[objectName.length()],30,subMeshIdx++);
}
// copy the shader to the mesh.
mesh->shader = shader;
}
// fill the mesh with data
if (!tempIdx.empty())
{
mesh->faces.push_back((unsigned int)tempIdx.size());
for (std::vector<unsigned int>::const_iterator it = tempIdx.begin(), end = tempIdx.end();
it != end;++it)
{
m = *it;
// copy colors -vertex color specifications override polygon color specifications
if (hasColor)
{
const aiColor4D& clr = tempColors[m];
mesh->colors.push_back((is_qnan( clr.r ) ? c : clr));
}
// positions should always be there
mesh->vertices.push_back (tempPositions[m]);
// copy normal vectors
if (hasNormals)
mesh->normals.push_back (tempNormals[m]);
// copy texture coordinates
if (hasUVs)
mesh->uvs.push_back (tempTextureCoords[m]);
}
}
} }
if (!num)throw new ImportErrorException("NFF2: There are zero faces"); if (!num)throw new ImportErrorException("NFF2: There are zero faces");
} }
@ -375,12 +756,17 @@ void NFFImporter::InternReadFile( const std::string& pFile,
AI_NFF_PARSE_TRIPLE(s.color); AI_NFF_PARSE_TRIPLE(s.color);
// read the other properties // read the other properties
AI_NFF_PARSE_FLOAT(s.diffuse); AI_NFF_PARSE_FLOAT(s.diffuse.r);
AI_NFF_PARSE_FLOAT(s.specular); AI_NFF_PARSE_FLOAT(s.specular.r);
AI_NFF_PARSE_FLOAT(d); // skip shininess and transmittance AI_NFF_PARSE_FLOAT(d); // skip shininess and transmittance
AI_NFF_PARSE_FLOAT(d); AI_NFF_PARSE_FLOAT(d);
AI_NFF_PARSE_FLOAT(s.refracti); AI_NFF_PARSE_FLOAT(s.refracti);
// NFF2 uses full colors here so we need to use them too
// although NFF uses simple scaling factors
s.diffuse.g = s.diffuse.b = s.diffuse.r;
s.specular.g = s.specular.b = s.specular.r;
// if the next one is NOT a number we assume it is a texture file name // if the next one is NOT a number we assume it is a texture file name
// this feature is used by some NFF files on the internet and it has // this feature is used by some NFF files on the internet and it has
// been implemented as it can be really useful // been implemented as it can be really useful
@ -436,14 +822,12 @@ void NFFImporter::InternReadFile( const std::string& pFile,
currentMesh = &meshes.back(); currentMesh = &meshes.back();
currentMesh->shader = s; currentMesh->shader = s;
} }
if (!currentMeshWithNormals) if (!currentMeshWithNormals)
{ {
meshesWithNormals.push_back(MeshInfo(PatchType_Normals)); meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
currentMeshWithNormals = &meshesWithNormals.back(); currentMeshWithNormals = &meshesWithNormals.back();
currentMeshWithNormals->shader = s; currentMeshWithNormals->shader = s;
} }
if (!currentMeshWithUVCoords) if (!currentMeshWithUVCoords)
{ {
meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals)); meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals));
@ -676,7 +1060,11 @@ void NFFImporter::InternReadFile( const std::string& pFile,
c->mLookAt = camLookAt - camPos; c->mLookAt = camLookAt - camPos;
c->mPosition = camPos; c->mPosition = camPos;
c->mUp = camUp; c->mUp = camUp;
c->mAspect = resolution.x / resolution.y;
// If the resolution is not specified in the file we
// need to set 1.0 as aspect. The division would become
// INF otherwise.
c->mAspect = (!resolution.y ? 0.f : resolution.x / resolution.y);
++ppcChildren; ++ppcChildren;
} }
@ -715,7 +1103,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
mesh->mNumVertices = (unsigned int)src.vertices.size(); mesh->mNumVertices = (unsigned int)src.vertices.size();
mesh->mNumFaces = (unsigned int)src.faces.size(); mesh->mNumFaces = (unsigned int)src.faces.size();
// generate sub nodes for named meshes // Generate sub nodes for named meshes
if (src.name[0]) if (src.name[0])
{ {
aiNode* const node = *ppcChildren = new aiNode(); aiNode* const node = *ppcChildren = new aiNode();
@ -754,7 +1142,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
sizeof(aiColor4D)*mesh->mNumVertices); sizeof(aiColor4D)*mesh->mNumVertices);
} }
if (src.pType != PatchType_Simple) if (!src.normals.empty())
{ {
ai_assert(src.normals.size() == src.vertices.size()); ai_assert(src.normals.size() == src.vertices.size());
@ -764,7 +1152,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
sizeof(aiVector3D)*mesh->mNumVertices); sizeof(aiVector3D)*mesh->mNumVertices);
} }
if (src.pType == PatchType_UVAndNormals) if (!src.uvs.empty())
{ {
ai_assert(src.uvs.size() == src.vertices.size()); ai_assert(src.uvs.size() == src.vertices.size());
@ -800,11 +1188,39 @@ void NFFImporter::InternReadFile( const std::string& pFile,
c = src.shader.color * src.shader.specular; c = src.shader.color * src.shader.specular;
pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR); pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR);
// NFF2 - default values for NFF
pcMat->AddProperty(&src.shader.ambient, 1,AI_MATKEY_COLOR_AMBIENT);
pcMat->AddProperty(&src.shader.emissive,1,AI_MATKEY_COLOR_EMISSIVE);
pcMat->AddProperty(&src.shader.opacity, 1,AI_MATKEY_OPACITY);
// setup the first texture layer, if existing
if (src.shader.texFile.length()) if (src.shader.texFile.length())
{ {
s.Set(src.shader.texFile); s.Set(src.shader.texFile);
pcMat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); pcMat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
} }
// setup the name of the material
if (src.shader.name.length())
{
s.Set(src.shader.texFile);
pcMat->AddProperty(&s,AI_MATKEY_NAME);
}
// setup some more material properties that are specific to NFF2
int i;
if (src.shader.twoSided)
{
i = 1;
pcMat->AddProperty(&i,1,AI_MATKEY_TWOSIDED);
}
i = (src.shader.shaded ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
if (src.shader.shininess)
{
i = aiShadingMode_Phong;
pcMat->AddProperty(&src.shader.shininess,1,AI_MATKEY_SHININESS);
}
pcMat->AddProperty(&i,1,AI_MATKEY_SHADING_MODEL);
} }
pScene->mRootNode = root; pScene->mRootNode = root;
} }

View File

@ -50,7 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** NFF (Neutral File Format) Importer class /** NFF (Neutral File Format) Importer class.
*
* The class implements both Eric Haynes NFF format and Sense8's NFF (NFF2) format.
* Both are quite different and the loading code is somewhat dirty at
* the moment. Sense8 should be moved to a separate loader.
*/ */
class NFFImporter : public BaseImporter class NFFImporter : public BaseImporter
{ {
@ -95,18 +99,30 @@ private:
struct ShadingInfo struct ShadingInfo
{ {
ShadingInfo() ShadingInfo()
: color(0.6f,0.6f,0.6f) : color (0.6f,0.6f,0.6f)
, diffuse (1.f) , diffuse (1.f,1.f,1.f)
, specular (1.f) , specular (1.f,1.f,1.f)
, ambient (0.1f) , ambient (0.f,0.f,0.f)
, emissive (0.f,0.f,0.f)
, refracti (1.f) , refracti (1.f)
, twoSided (false) // for NFF2
, shaded (true) // for NFF2
, opacity (1.f)
, shininess (0.f)
{} {}
aiColor3D color; aiColor3D color,diffuse,specular,ambient,emissive;
float diffuse, specular, ambient, refracti; float refracti;
std::string texFile; std::string texFile;
// For NFF2
bool twoSided;
bool shaded;
float opacity, shininess;
std::string name;
// shininess is ignored for the moment // shininess is ignored for the moment
bool operator == (const ShadingInfo& other) const bool operator == (const ShadingInfo& other) const
{ {
@ -115,7 +131,12 @@ private:
specular == other.specular && specular == other.specular &&
ambient == other.ambient && ambient == other.ambient &&
refracti == other.refracti && refracti == other.refracti &&
texFile == other.texFile; texFile == other.texFile &&
twoSided == other.twoSided &&
shaded == other.shaded;
// Some properties from NFF2 aren't compared by this operator.
// Comparing MeshInfo::matIndex should do that.
} }
}; };
@ -143,8 +164,10 @@ private:
struct MeshInfo struct MeshInfo
{ {
MeshInfo(PatchType _pType, bool bL = false) MeshInfo(PatchType _pType, bool bL = false)
: pType(_pType) : pType (_pType)
, bLocked(bL) , bLocked (bL)
, matIndex (0)
, radius (1.f,1.f,1.f)
{ {
name[0] = '\0'; // by default meshes are unnamed name[0] = '\0'; // by default meshes are unnamed
} }
@ -159,9 +182,25 @@ private:
char name[128]; char name[128];
std::vector<aiVector3D> vertices, normals, uvs; std::vector<aiVector3D> vertices, normals, uvs;
std::vector<aiColor4D> colors; // for NFF2
std::vector<unsigned int> faces; std::vector<unsigned int> faces;
// for NFF2
std::vector<aiColor4D> colors;
unsigned int matIndex;
}; };
// -------------------------------------------------------------------
/** Loads the material table for the NFF2 file format from an
* external file.
*
* @param output Receives the list of output meshes
* @param path Path to the file (abs. or rel.)
* @param pIOHandler IOSystem to be used to open the file
*/
void LoadNFF2MaterialTable(std::vector<ShadingInfo>& output,
const std::string& path, IOSystem* pIOHandler);
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -75,7 +75,7 @@ bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
return !(extension.length() != 4 || extension[0] != '.' || return !(extension.length() != 4 || extension[0] != '.' ||
extension[1] != 'o' && extension[1] != 'R' || extension[1] != 'o' && extension[1] != 'O' ||
extension[2] != 'f' && extension[2] != 'F' || extension[2] != 'f' && extension[2] != 'F' ||
extension[3] != 'f' && extension[3] != 'F'); extension[3] != 'f' && extension[3] != 'F');
} }

View File

@ -148,4 +148,10 @@ AI_FORCE_INLINE bool TokenMatch(char*& in, const char* token, unsigned int len)
} }
return false; return false;
} }
// ---------------------------------------------------------------------------------
AI_FORCE_INLINE void SkipToken(const char*& in)
{
SkipSpaces(&in);
while (!IsSpaceOrNewLine(*in))++in;
}
#endif // ! AI_PARSING_UTILS_H_INC #endif // ! AI_PARSING_UTILS_H_INC

View File

@ -44,6 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BaseProcess.h" #include "BaseProcess.h"
#include "../include/aiMesh.h" #include "../include/aiMesh.h"
class RemoveVCProcessTest;
namespace Assimp namespace Assimp
{ {
@ -53,6 +55,7 @@ namespace Assimp
class ASSIMP_API RemoveVCProcess : public BaseProcess class ASSIMP_API RemoveVCProcess : public BaseProcess
{ {
friend class Importer; friend class Importer;
friend class ::RemoveVCProcessTest;
protected: protected:
/** Constructor to be privately used by Importer */ /** Constructor to be privately used by Importer */

View File

@ -0,0 +1,226 @@
/*
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 Implements Assimp::SceneCombiner. This is a smart utility
* class that can be used to combine several scenes, meshes, ...
* in one.
*/
#include "AssimpPCH.h"
#include "SceneCombiner.h"
#include "fast_atof.h"
namespace Assimp
{
// ------------------------------------------------------------------------------------------------
// Merges two scenes. Currently only used by the LWS loader.
void SceneCombiner::MergeScenes(aiScene* dest,std::vector<aiScene*>& src,
unsigned int flags)
{
ai_assert(NULL != dest);
ai_assert(0 == dest->mNumTextures);
ai_assert(0 == dest->mNumLights);
ai_assert(0 == dest->mNumCameras);
ai_assert(0 == dest->mNumMeshes);
ai_assert(0 == dest->mNumMaterials);
if (src.empty())return;
// some iterators will be needed multiple times
std::vector<aiScene*>::iterator begin = src.begin(),
end = src.end(), cur;
// this helper array is used as lookup table several times
std::vector<unsigned int> offset(src.size());
std::vector<unsigned int>::iterator ofsbegin = offset.begin(),
offend = offset.end(), ofscur;
unsigned int cnt;
bool bNeedPrefix = false;
// First find out how large the respective output arrays must be
for ( cur = begin; cur != end; ++cur)
{
dest->mNumTextures += (*cur)->mNumTextures;
dest->mNumMaterials += (*cur)->mNumMaterials;
dest->mNumMeshes += (*cur)->mNumMeshes;
dest->mNumLights += (*cur)->mNumLights;
dest->mNumCameras += (*cur)->mNumCameras;
dest->mNumAnimations += (*cur)->mNumAnimations;
if ((*cur)->mNumAnimations > 0 ||
(*cur)->mNumCameras > 0 ||
(*cur)->mNumLights > 0)bNeedPrefix = true;
}
// generate the output texture list + an offset table
if (dest->mNumTextures)
{
aiTexture** pip = dest->mTextures = new aiTexture*[dest->mNumMaterials];
for ( cur = begin, ofscur = ofsbegin,cnt = 0; cur != end; ++cur,++ofscur)
{
for (unsigned int i = 0; i < (*cur)->mNumTextures;++i,++pip)
*pip = (*cur)->mTextures[i];
*ofscur = cnt;
cnt += (*cur)->mNumTextures;
}
}
// generate the output material list + an offset table
if (dest->mNumMaterials)
{
aiMaterial** pip = dest->mMaterials = new aiMaterial*[dest->mNumMaterials];
for ( cur = begin, ofscur = ofsbegin,cnt = 0; cur != end; ++cur,++ofscur)
{
for (unsigned int i = 0; i < (*cur)->mNumMaterials;++i,++pip)
{
*pip = (*cur)->mMaterials[i];
if ((*cur)->mNumTextures != dest->mNumTextures)
{
// We need to update all texture indices of the mesh.
// So we need to search for a material property like
// that follows the following pattern: "$tex.file.<s>.<n>"
// where s is the texture type (i.e. diffuse) and n is
// the index of the texture.
for (unsigned int a = 0; a < (*pip)->mNumProperties;++a)
{
aiMaterialProperty* prop = (*pip)->mProperties[a];
if (!strncmp(prop->mKey.data,"$tex.file",9))
{
// Check whether this texture is an embedded texture.
// In this case the property looks like this: *<n>,
// where n is the index of the texture.
aiString& s = *((aiString*)prop->mData);
if ('*' == s.data[0])
{
// Offset the index and write it back ..
const unsigned int idx = strtol10(&s.data[1]) + *ofscur;
itoa10(&s.data[1],sizeof(s.data)-1,idx);
}
}
}
}
}
*ofscur = cnt;
cnt += (*cur)->mNumMaterials;
}
}
// generate the output mesh list + again an offset table
if (dest->mNumMeshes)
{
aiMesh** pip = dest->mMeshes = new aiMesh*[dest->mNumMeshes];
for ( cur = begin, ofscur = ofsbegin,cnt = 0; cur != end; ++cur,++ofscur)
{
for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i,++pip)
{
*pip = (*cur)->mMeshes[i];
// update the material index of the mesh
(*pip)->mMaterialIndex += *ofscur;
}
// reuse the offset array - store now the mesh offset in it
*ofscur = cnt;
cnt += (*cur)->mNumMeshes;
}
}
// Now generate the output node graph. We need to make those
// names in the graph that are referenced by anims or lights
// or cameras unique. So we add a prefix to them ... $SC1_
// First step for now: find out which nodes are referenced by
// anim bones or cameras and add the prefix to their names.
if (bNeedPrefix)
{
for (cur = begin, cnt = 0; cur != end; ++cur)
{
char buffer[10];
buffer[0] = '$';
buffer[1] = 'S';
buffer[2] = 'C';
char* sz = &buffer[itoa10(&buffer[3],sizeof(buffer)-3, cnt++)+2];
*sz++ = '_';
*sz++ = '\0';
// AddNodePrefixes((*cur)->mRootNode,buffer,*cur);
/** CONTINUE WORK HERE **/
}
}
// now copy all cameras
// now delete all input scenes
for (cur = begin; cur != end; ++cur)
{
aiScene* deleteMe = *cur;
// We need to delete the arrays before the destructor is called -
// we are reusing the array members
delete[] deleteMe->mMeshes; deleteMe->mMeshes = NULL;
delete[] deleteMe->mCameras; deleteMe->mCameras = NULL;
delete[] deleteMe->mLights; deleteMe->mLights = NULL;
delete[] deleteMe->mMaterials; deleteMe->mMaterials = NULL;
delete[] deleteMe->mAnimations; deleteMe->mAnimations = NULL;
delete[] deleteMe->mRootNode->mChildren;
deleteMe->mRootNode->mChildren = NULL;
// Now we can safely delete the scene
delete[] deleteMe;
AI_DEBUG_INVALIDATE_PTR(*cur);
}
}
// ------------------------------------------------------------------------------------------------
void SceneCombiner::MergeMeshes(aiMesh* dest,std::vector<aiMesh*>& src,
unsigned int flags)
{
}
}

View File

@ -0,0 +1,93 @@
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file Declares a helper class, "SceneCombiner" providing various
* utilities to merge scenes.
*/
#ifndef AI_SCENE_COMBINER_H_INC
#define AI_SCENE_COMBINER_H_INC
#include "../include/aiAssert.h"
namespace Assimp {
// ---------------------------------------------------------------------------
/** \brief Static helper class providing various utilities to merge two
* scenes. It is intended as internal utility and NOT for use by
* applications.
*
* The class is currently being used by various postprocessing steps
* and loaders (ie. LWS).
*/
class ASSIMP_API SceneCombiner
{
// class cannot be instanced
SceneCombiner() {}
public:
// -------------------------------------------------------------------
/** Merges two or more scenes.
*
* @param dest Destination scene. Must be empty.
* @param src Non-empty list of scenes to be merged. The function
* deletes the input scenes afterwards.
* @param flags Combination of the AI_INT_MERGE_SCENE flags defined above
*/
static void MergeScenes(aiScene* dest,std::vector<aiScene*>& src,
unsigned int flags);
// -------------------------------------------------------------------
/** Merges two or more meshes
*
* @param dest Destination mesh. Must be empty.
* @param src Non-empty list of meshes to be merged. The function
* deletes the input meshes afterwards.
* @param flags Currently no parameters
*/
static void MergeMeshes(aiMesh* dest,std::vector<aiMesh*>& src,
unsigned int flags);
};
}
#endif // !! AI_SCENE_COMBINER_H_INC

View File

@ -55,7 +55,6 @@ using namespace Assimp;
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
DeterminePTypeHelperProcess ::DeterminePTypeHelperProcess() DeterminePTypeHelperProcess ::DeterminePTypeHelperProcess()
{ {
bSpeedFlag = false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -73,13 +72,6 @@ bool DeterminePTypeHelperProcess::IsActive( unsigned int pFlags) const
return true; return true;
} }
// ------------------------------------------------------------------------------------------------
// called as a request to the step to update its configuration
void DeterminePTypeHelperProcess::SetupProperties(const Importer* pImp)
{
bSpeedFlag = (pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0) ? true : false);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void DeterminePTypeHelperProcess::Execute( aiScene* pScene) void DeterminePTypeHelperProcess::Execute( aiScene* pScene)
@ -88,59 +80,6 @@ void DeterminePTypeHelperProcess::Execute( aiScene* pScene)
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{ {
aiMesh* mesh = pScene->mMeshes[i]; aiMesh* mesh = pScene->mMeshes[i];
// if the speed flag is not set search whether there are any degenerated
// primitives in the mesh
if (false && !bSpeedFlag)
{
unsigned int deg = 0;
for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
{
aiFace& face = mesh->mFaces[a];
bool first = true;
// check whether the face contains degenerated entries
for (register unsigned int i = 0; i < face.mNumIndices; ++i)
{
for (register unsigned int a = i+1; a < face.mNumIndices; ++a)
{
if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[a]])
{
// we have found a matching vertex position
// remove the corresponding index from the array
for (unsigned int m = a; m < face.mNumIndices-1; ++m)
{
face.mIndices[m] = face.mIndices[m+1];
}
--a;
--face.mNumIndices;
// NOTE: we set the removed vertex index to an unique value
// to make sure the developer gets notified when his
// application attemps to access this data.
face.mIndices[face.mNumIndices] = 0xdeadbeef;
if(first)
{
++deg;
first = false;
}
}
}
}
}
if (deg)
{
char s[64];
#if defined(_MSC_VER)
::_itoa(deg,s,10);
#else
snprintf(s, 64, "%d", deg); //itoa is not available under linux
#endif
DefaultLogger::get()->warn(std::string("Found ") + s + " degenerated primitives");
}
}
if (!mesh->mPrimitiveTypes) if (!mesh->mPrimitiveTypes)
{ {
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
@ -248,6 +187,8 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
std::vector<aiMesh*> outMeshes; std::vector<aiMesh*> outMeshes;
outMeshes.reserve(pScene->mNumMeshes<<1u); outMeshes.reserve(pScene->mNumMeshes<<1u);
bool bAnyChanges = false;
std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes*5,0xffffffff); std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes*5,0xffffffff);
std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin(); std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin();
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
@ -288,7 +229,7 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
++meshIdx; ++meshIdx;
continue; continue;
} }
bAnyChanges = true;
const unsigned int first = (unsigned int)outMeshes.size(); const unsigned int first = (unsigned int)outMeshes.size();
// reuse our current mesh arrays for the submesh // reuse our current mesh arrays for the submesh
@ -468,7 +409,12 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
delete mesh; delete mesh;
} }
UpdateNodes(replaceMeshIndex,pScene->mRootNode); // If we added at least one mesh process all nodes in the node
// graph and update their respective mesh indices.
if (bAnyChanges)
{
UpdateNodes(replaceMeshIndex,pScene->mRootNode);
}
if (outMeshes.size() != pScene->mNumMeshes) if (outMeshes.size() != pScene->mNumMeshes)
{ {

View File

@ -73,12 +73,8 @@ public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
void Execute( aiScene* pScene); void Execute( aiScene* pScene);
// -------------------------------------------------------------------
void SetupProperties(const Importer* pImp);
private: private:
bool bSpeedFlag;
}; };
#if (!defined AI_BUILD_NO_SORTBYPTYPE_PROCESS) #if (!defined AI_BUILD_NO_SORTBYPTYPE_PROCESS)

View File

@ -46,6 +46,63 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp namespace Assimp
{ {
// ---------------------------------------------------------------------------
// itoa is not consistently available on all platforms so it is quite useful
// to have a small replacement function here. No need to use a full sprintf()
// if we just want to print a number ...
// @param out Output buffer
// @param max Maximum number of characters to be written, including '\0'
// @param number Number to be written
// @return Number of bytes written. Including '\0'.
// ---------------------------------------------------------------------------
inline unsigned int itoa10( char* out, unsigned int max, int32_t number)
{
ai_assert(NULL != out);
static const char lookup[] = {'0','1','2','3','4','5','6','7','8','9'};
// write the unary minus to indicate we have a negative number
unsigned int written = 1u;
if (number < 0 && written < max)
{
*out++ = '-';
++written;
}
// We begin with the largest number that is not zero.
int32_t cur = 1000000000; // 2147483648
bool mustPrint = false;
while (cur > 0 && written <= max)
{
unsigned int digit = number / cur;
if (digit > 0 || mustPrint || 1 == cur)
{
// print all future zero's from now
mustPrint = true;
*out++ = lookup[digit];
++written;
number -= digit*10;
}
cur /= 10;
}
// append a terminal zero
*out++ = '\0';
return written;
}
// ---------------------------------------------------------------------------
// Secure template overload
// The compiler should choose this function if he is able to determine the
// size of the array automatically.
// ---------------------------------------------------------------------------
template <unsigned int length>
inline unsigned int itoa10( char(& out)[length], int32_t number)
{
return itoa10(out,length,number);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** \brief Helper function to do platform independent string comparison. /** \brief Helper function to do platform independent string comparison.
* *
@ -76,6 +133,9 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2)
#endif #endif
} }
// ---------------------------------------------------------------------------
/** \brief Case independent comparison of two std::strings
*/
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
inline int ASSIMP_stricmp(const std::string& a, const std::string& b) inline int ASSIMP_stricmp(const std::string& a, const std::string& b)
{ {

View File

@ -271,7 +271,7 @@ void ValidateDSProcess::Execute( aiScene* pScene)
if (pScene->mNumMaterials) if (pScene->mNumMaterials)
{ {
has = true; has = true;
DoValidation(pScene->mCameras,pScene->mNumCameras,"mMaterials","mNumMaterials"); DoValidation(pScene->mMaterials,pScene->mNumMaterials,"mMaterials","mNumMaterials");
} }
else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{ {
@ -292,7 +292,7 @@ void ValidateDSProcess::Validate( const aiLight* pLight)
!pLight->mAttenuationLinear && !pLight->mAttenuationLinear &&
!pLight->mAttenuationQuadratic) !pLight->mAttenuationQuadratic)
{ {
ReportError("aiLight::mAttenuationXXX - all are zero"); ReportWarning("aiLight::mAttenuationXXX - all are zero");
} }
if (pLight->mAngleInnerCone > pLight->mAngleOuterCone) if (pLight->mAngleInnerCone > pLight->mAngleOuterCone)
@ -301,7 +301,7 @@ void ValidateDSProcess::Validate( const aiLight* pLight)
if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack() if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack()
&& pLight->mColorSpecular.IsBlack()) && pLight->mColorSpecular.IsBlack())
{ {
ReportError("aiLight::mColorXXX - all are black and won't have any influence"); ReportWarning("aiLight::mColorXXX - all are black and won't have any influence");
} }
} }
@ -411,12 +411,15 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
abRefList[face.mIndices[a]] = true; abRefList[face.mIndices[a]] = true;
} }
} }
// check whether there are vertices that aren't referenced by a face // check whether there are vertices that aren't referenced by a face
bool b = false;
for (unsigned int i = 0; i < pMesh->mNumVertices;++i) for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
{ {
if (!abRefList[i])this->ReportError("aiMesh::mVertices[%i] is not referenced",i); if (!abRefList[i])b = true;
} }
abRefList.clear(); abRefList.clear();
if (b)ReportWarning("There are unreferenced vertices");
// texture channel 2 may not be set if channel 1 is zero ... // texture channel 2 may not be set if channel 1 is zero ...
{ {
@ -428,7 +431,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
if (pMesh->HasTextureCoords(i)) if (pMesh->HasTextureCoords(i))
{ {
ReportError("Texture coordinate channel %i is existing, " ReportError("Texture coordinate channel %i exists "
"although the previous channel was NULL.",i); "although the previous channel was NULL.",i);
} }
} }
@ -442,7 +445,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i) for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
if (pMesh->HasVertexColors(i)) if (pMesh->HasVertexColors(i))
{ {
ReportError("Vertex color channel %i is existing, " ReportError("Vertex color channel %i is exists "
"although the previous channel was NULL.",i); "although the previous channel was NULL.",i);
} }
} }
@ -589,11 +592,13 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
this->ReportError("%s #%i is set, but there are only %i %s textures", this->ReportError("%s #%i is set, but there are only %i %s textures",
szType,iIndex,iNumIndices,szType); szType,iIndex,iNumIndices,szType);
} }
if (!iNumIndices)return;
// now check whether all UV indices are valid ... // now check whether all UV indices are valid ...
iLen = ::sprintf(szBaseBuf,"$tex.uvw.%s",szType); iLen = ::sprintf(szBaseBuf,"$tex.uvw.%s",szType);
if (0 >= iLen)return; if (0 >= iLen)return;
bool bNoSpecified = true;
for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
{ {
aiMaterialProperty* prop = pMaterial->mProperties[i]; aiMaterialProperty* prop = pMaterial->mProperties[i];
@ -607,6 +612,7 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
{ {
++sz; ++sz;
iIndex = strtol10(sz,NULL); iIndex = strtol10(sz,NULL);
bNoSpecified = false;
// ignore UV indices for texture channel that are not there ... // ignore UV indices for texture channel that are not there ...
if (iIndex >= iNumIndices) if (iIndex >= iNumIndices)
@ -616,13 +622,13 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
// check whether there is a mesh using this material // check whether there is a mesh using this material
// which has not enough UV channels ... // which has not enough UV channels ...
for (unsigned int a = 0; a < this->mScene->mNumMeshes;++a) for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
{ {
aiMesh* mesh = this->mScene->mMeshes[a]; aiMesh* mesh = this->mScene->mMeshes[a];
if(mesh->mMaterialIndex == (unsigned int)iIndex) if(mesh->mMaterialIndex == (unsigned int)iIndex)
{ {
int iChannels = 0; int iChannels = 0;
while (mesh->HasTextureCoords(iChannels++)); while (mesh->HasTextureCoords(iChannels))++iChannels;
if (iIndex >= iChannels) if (iIndex >= iChannels)
{ {
this->ReportError("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels", this->ReportError("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
@ -634,6 +640,24 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
} }
} }
} }
if (bNoSpecified)
{
// Assume that all textures are using the first UV channel
for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
{
aiMesh* mesh = this->mScene->mMeshes[a];
if(mesh->mMaterialIndex == (unsigned int)iIndex)
{
if (!mesh->mTextureCoords[0])
{
// This is a special case ... it could be that the
// original mesh format intended the use of a special
// mapping here.
ReportWarning("UV-mapped texture, but there are no UV coords");
}
}
}
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ValidateDSProcess::Validate( const aiMaterial* pMaterial) void ValidateDSProcess::Validate( const aiMaterial* pMaterial)

View File

@ -61,6 +61,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
{ {
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)
{ {
ai_assert(3 == pcFace->mNumIndices);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]); iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]); iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
iNumVertices = std::max(iNumVertices,pcFace->mIndices[2]); iNumVertices = std::max(iNumVertices,pcFace->mIndices[2]);

View File

@ -40,6 +40,8 @@ const float fast_atof_table[16] = { // we write [16] here instead of [] to work
}; };
// ------------------------------------------------------------------------------------
// convert a string in decimal format to a number
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
inline unsigned int strtol10( const char* in, const char** out=0) inline unsigned int strtol10( const char* in, const char** out=0)
{ {
@ -57,6 +59,8 @@ inline unsigned int strtol10( const char* in, const char** out=0)
return value; return value;
} }
// ------------------------------------------------------------------------------------
// convert a string in octal format to a number
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
inline unsigned int strtol8( const char* in, const char** out=0) inline unsigned int strtol8( const char* in, const char** out=0)
{ {
@ -76,6 +80,7 @@ inline unsigned int strtol8( const char* in, const char** out=0)
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// convert a string in hex format to a number // convert a string in hex format to a number
// ------------------------------------------------------------------------------------
inline unsigned int strtol16( const char* in, const char** out=0) inline unsigned int strtol16( const char* in, const char** out=0)
{ {
unsigned int value = 0; unsigned int value = 0;
@ -101,8 +106,9 @@ inline unsigned int strtol16( const char* in, const char** out=0)
return value; return value;
} }
// --------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------
// convert just one hex digit // convert just one hex digit
// ------------------------------------------------------------------------------------
inline unsigned int HexDigitToDecimal(char in) inline unsigned int HexDigitToDecimal(char in)
{ {
unsigned int out = 0xffffffff; unsigned int out = 0xffffffff;
@ -121,6 +127,7 @@ inline unsigned int HexDigitToDecimal(char in)
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// signed variant of strtol10 // signed variant of strtol10
// ------------------------------------------------------------------------------------
inline int strtol10s( const char* in, const char** out=0) inline int strtol10s( const char* in, const char** out=0)
{ {
bool bNeg = false; bool bNeg = false;
@ -132,9 +139,11 @@ inline int strtol10s( const char* in, const char** out=0)
} }
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// Parse a C++-like integer literal - hex and oct prefixes.
// 0xNNNN - hex // 0xNNNN - hex
// 0NNN - oct // 0NNN - oct
// NNN - dec // NNN - dec
// ------------------------------------------------------------------------------------
inline unsigned int strtol_cppstyle( const char* in, const char** out=0) inline unsigned int strtol_cppstyle( const char* in, const char** out=0)
{ {
if ('0' == in[0]) if ('0' == in[0])
@ -145,7 +154,9 @@ inline unsigned int strtol_cppstyle( const char* in, const char** out=0)
} }
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// specal version of the function, providing higher accuracy // Special version of the function, providing higher accuracy
// It is mainly used bx fast_atof to prevent ugly integer overflows.
// ------------------------------------------------------------------------------------
inline uint64_t strtol10_64( const char* in, const char** out=0) inline uint64_t strtol10_64( const char* in, const char** out=0)
{ {
uint64_t value = 0; uint64_t value = 0;
@ -168,6 +179,7 @@ inline uint64_t strtol10_64( const char* in, const char** out=0)
//! Provides a fast function for converting a string into a float, //! Provides a fast function for converting a string into a float,
//! about 6 times faster than atof in win32. //! about 6 times faster than atof in win32.
// If you find any bugs, please send them to me, niko (at) irrlicht3d.org. // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
// ------------------------------------------------------------------------------------
inline const char* fast_atof_move( const char* c, float& out) inline const char* fast_atof_move( const char* c, float& out)
{ {
bool inv = false; bool inv = false;

View File

@ -63,6 +63,10 @@ SOURCES = AssimpPCH.cpp \
FindInvalidDataProcess.cpp \ FindInvalidDataProcess.cpp \
ACLoader.cpp \ ACLoader.cpp \
LWSLoader.cpp \ LWSLoader.cpp \
BVHLoader.cpp \
SceneCombiner.cpp \
SkeletonMeshBuilder.cpp \
FindDegenerates.cpp \
XFileParser.cpp XFileParser.cpp
OBJECTS = $(SOURCES:.cpp=.o) OBJECTS = $(SOURCES:.cpp=.o)

View File

@ -63,7 +63,11 @@ SOURCES = AssimpPCH.cpp \
FindInvalidDataProcess.cpp \ FindInvalidDataProcess.cpp \
ACLoader.cpp \ ACLoader.cpp \
LWSLoader.cpp \ LWSLoader.cpp \
XFileParser.cpp XFileParser.cpp \
SceneCombiner.cpp \
FindDegenerates.cpp \
SkeletonMeshBuilder.cpp \
BVHLoader.cpp
OBJECTS = $(SOURCES:.cpp=.o) OBJECTS = $(SOURCES:.cpp=.o)

View File

@ -218,7 +218,25 @@ enum aiPostProcessSteps
* especially useful for real-time rendering where point and line * especially useful for real-time rendering where point and line
* primitives are often ignored or rendered separately. * primitives are often ignored or rendered separately.
*/ */
aiProcess_SortByPType = 0x8000 aiProcess_SortByPType = 0x8000,
/** This step searches all meshes for degenerated primitives and
* converts them to proper lines or points.
*
* A face is degenerated if one or more of its faces are identical.
*/
aiProcess_FindDegenerates = 0x10000,
/** This step searches all meshes for invalid data, such as zeroed
* normal vectors or invalid UV coords and removes them.
*
* This is especially useful for normals. If they are invalid, and
* the step recognizes this, they will be removed and can later
* be computed by one of the other steps.<br>
* The step will also remove meshes that are infinitely small.
*/
aiProcess_FindInvalidData = 0x20000,
}; };

View File

@ -0,0 +1,24 @@
# viewpoint
v
from 0 3 10
at 0 0 0
up 0 1 0
angle 60
hither 0
resolution 640 480
f 1 0 0 0.8 .8 20 0 1
s -2 0.8 0 2
f 0 1 0 0.8 .8 20 0 1
s 1 -1.5 1 2.2
f 0 0 1 0.8 .8 20 0 1
s 3 3 -2 2
f 1 1 1 0.8 .8 20 0 1
p 4
-7 -1 -7
-7 -1 7
7 -1 7
7 -1 -7

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
mat // cokecan.mat, Materials for coke texture example
version 3.0
valid ambientdiffuse specular shininess opacity
matdef // #0 Shiny silver ( aluminum )
ambientdiffuse 0.9 0.9 0.9
specular 1.0 1.0 1.0
shininess 128.0
matdef // #1 Semi-Transparent Green
ambientdiffuse 0.0 1.0 0.0
opacity 0.6

View File

@ -0,0 +1,39 @@
nff // cokecan.nff, A file designed to illustrate uv texturing
version 3.0
Coke_Can
mtable cokecan.mat
18 // Eighteen vertices
10.0 -37.0 0.0 uv 0.0 1.0 // #0 Start around top of can
7.071 -37.0 7.071 uv 0.125 1.0 // #1
0.0 -37.0 10.0 uv 0.25 1.0 // #2
-7.071 -37.0 7.071 uv 0.375 1.0 // #3
-10.0 -37.0 0.0 uv 0.5 1.0 // #4
-7.071 -37.0 -7.071 uv 0.625 1.0 // #5
0.0 -37.0 -10.0 uv 0.75 1.0 // #6
7.071 -37.0 -7.071 uv 0.875 1.0 // #7
10.0 -37.0 0.0 uv 1.0 1.0 // #8 ( Same as #0 except u value )
10.0 0.0 0.0 uv 0.0 0.0 // #9 Repeat around bottom of can
7.071 0.0 7.071 uv 0.125 0.0 // #10
0.0 0.0 10.0 uv 0.25 0.0 // #11
-7.071 0.0 7.071 uv 0.375 0.0 // #12
-10.0 0.0 0.0 uv 0.5 0.0 // #13
-7.071 0.0 -7.071 uv 0.625 0.0 // #14
0.0 0.0 -10.0 uv 0.75 0.0 // #15
7.071 0.0 -7.071 uv 0.875 0.0 // #16
10.0 0.0 0.0 uv 0.0 0.0 // #17 ( Same as #9 except u value )
10 // Ten polygons
8 0 1 2 3 4 5 6 7 matid 0 // Top of can. Note lack of "both"
8 9 10 11 12 13 14 15 16 matid 0 both // Bottom of can
4 9 10 1 0 matid 0 both _V_cokelabl.tga // Vanilla texture on silver
4 10 11 2 1 matid 0 both _S_cokelabl.tga // Shaded texture on silver
4 11 12 3 2 matid 0 both _T_cokelabl.tga // Transparent texture on silver
4 12 13 4 3 matid 0 both _U_cokelabl.tga // Shaded & Transparent on silver
4 13 14 5 4 matid 1 both _V_cokelabl.tga // Vanilla texture on green
4 14 15 6 5 matid 1 both _S_cokelabl.tga // Shaded texture on green
4 15 16 7 6 matid 1 both _T_cokelabl.tga // Transparent texture on green
4 16 17 8 7 matid 1 both _U_cokelabl.tga // Shaded & Transparent on green

View File

@ -0,0 +1,4 @@
teapot.nff, home4.nff - http://www.martinreddy.net/ukvrsig/wtk.html
cokecan.nff -www.vrupl.evl.uic.edu/Eng591_Pages/cokecan.nff
TODO: License status to be confirmed

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
OFF
353535235358 6 0
-0.500000 -0.500000 0.500000
0.500000 -0.500000 0.500000
-0.500000 0.500000 0.500000
0.500000 0.500000 0.500000
-0.500000 0.500000 -0.500000
0.500000 0.500000 -0.500000
-0.500000 -0.500000 -0.500000
0.500000 -0.500000 -0.500000
4 0 1 3 2
4 2 3 5 4
4 4 5 7 6
4 6 7 1 0
4 1 7 5 3
4 6 0 2 4

View File

@ -0,0 +1,26 @@
*********************************************************
GENERAL
*********************************************************
The files in this directory are invalid ... some of them are empty,
others have invalid vertices or faces, others are prepared to make
assimp allocate a few hundreds gigs of memory ...
This test case is successful if the library (and the viewer) don't
crash.
*********************************************************
FILES
*********************************************************
OutOfMemory.off - the number of faces is invalid. There won't be
enough memory so std::vector::reserve() will most likely fail.
The exception should be caught in Importer.cpp.
empty.<x> - These files are completely empty. The corresponding
loaders should not crash.

View File

@ -0,0 +1,53 @@
#include "utRemoveComponent.h"
CPPUNIT_TEST_SUITE_REGISTRATION (RemoveVCProcessTest);
void RemoveVCProcessTest :: setUp (void)
{
// construct the process
piProcess = new RemoveVCProcess();
pScene = new aiScene();
}
void RemoveVCProcessTest :: tearDown (void)
{
delete pScene;
delete piProcess;
}
void RemoveVCProcessTest::testMeshRemove (void)
{
}
void RemoveVCProcessTest::testAnimRemove (void)
{
}
void RemoveVCProcessTest::testMaterialRemove (void)
{
}
void RemoveVCProcessTest::testTextureRemove (void)
{
}
void RemoveVCProcessTest::testCameraRemove (void)
{
}
void RemoveVCProcessTest::testLightRemove (void)
{
}
void RemoveVCProcessTest::testMeshComponentsRemoveA (void)
{
}
void RemoveVCProcessTest::testMeshComponentsRemoveB (void)
{
}
void RemoveVCProcessTest::testRemoveEverything (void)
{
}

View File

@ -0,0 +1,51 @@
#ifndef TESTLBW_H
#define TESTLBW_H
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <aiScene.h>
#include <RemoveVCProcess.h>
using namespace std;
using namespace Assimp;
class RemoveVCProcessTest : public CPPUNIT_NS :: TestFixture
{
CPPUNIT_TEST_SUITE (RemoveVCProcessTest);
CPPUNIT_TEST (testMeshRemove);
CPPUNIT_TEST (testAnimRemove);
CPPUNIT_TEST (testMaterialRemove);
CPPUNIT_TEST (testTextureRemove);
CPPUNIT_TEST (testCameraRemove);
CPPUNIT_TEST (testLightRemove);
CPPUNIT_TEST (testMeshComponentsRemoveA);
CPPUNIT_TEST (testMeshComponentsRemoveB);
CPPUNIT_TEST (testRemoveEverything);
CPPUNIT_TEST_SUITE_END ();
public:
void setUp (void);
void tearDown (void);
protected:
void testMeshRemove (void);
void testAnimRemove (void);
void testMaterialRemove (void);
void testTextureRemove (void);
void testCameraRemove (void);
void testLightRemove (void);
void testMeshComponentsRemoveA (void);
void testMeshComponentsRemoveB (void);
void testRemoveEverything (void);
private:
RemoveVCProcess* piProcess;
aiScene* pScene;
};
#endif

View File

@ -786,93 +786,97 @@ int CMaterialManager::CreateMaterial(
aiString szPath; aiString szPath;
// if (pcSource->mTextureCoords[0])
// DIFFUSE TEXTURE ------------------------------------------------
//
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath))
{ {
LoadTexture(&pcMesh->piDiffuseTexture,&szPath);
}
// //
// SPECULAR TEXTURE ------------------------------------------------ // DIFFUSE TEXTURE ------------------------------------------------
// //
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0),&szPath)) if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath))
{
LoadTexture(&pcMesh->piSpecularTexture,&szPath);
}
//
// OPACITY TEXTURE ------------------------------------------------
//
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0),&szPath))
{
LoadTexture(&pcMesh->piOpacityTexture,&szPath);
}
else
{
// try to find out whether the diffuse texture has any
// non-opaque pixels. If we find a few, use it as opacity texture
if (pcMesh->piDiffuseTexture && HasAlphaPixels(pcMesh->piDiffuseTexture))
{ {
int iVal; LoadTexture(&pcMesh->piDiffuseTexture,&szPath);
}
// NOTE: This special value is set by the tree view if the user //
// manually removes the alpha texture from the view ... // SPECULAR TEXTURE ------------------------------------------------
if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",&iVal)) //
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0),&szPath))
{
LoadTexture(&pcMesh->piSpecularTexture,&szPath);
}
//
// OPACITY TEXTURE ------------------------------------------------
//
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0),&szPath))
{
LoadTexture(&pcMesh->piOpacityTexture,&szPath);
}
else
{
// try to find out whether the diffuse texture has any
// non-opaque pixels. If we find a few, use it as opacity texture
if (pcMesh->piDiffuseTexture && HasAlphaPixels(pcMesh->piDiffuseTexture))
{ {
pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture; int iVal;
pcMesh->piOpacityTexture->AddRef();
// NOTE: This special value is set by the tree view if the user
// manually removes the alpha texture from the view ...
if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",&iVal))
{
pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture;
pcMesh->piOpacityTexture->AddRef();
}
} }
} }
}
// //
// AMBIENT TEXTURE ------------------------------------------------ // AMBIENT TEXTURE ------------------------------------------------
// //
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0),&szPath)) if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0),&szPath))
{ {
LoadTexture(&pcMesh->piAmbientTexture,&szPath); LoadTexture(&pcMesh->piAmbientTexture,&szPath);
} }
// //
// EMISSIVE TEXTURE ------------------------------------------------ // EMISSIVE TEXTURE ------------------------------------------------
// //
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0),&szPath)) if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0),&szPath))
{ {
LoadTexture(&pcMesh->piEmissiveTexture,&szPath); LoadTexture(&pcMesh->piEmissiveTexture,&szPath);
} }
// //
// Shininess TEXTURE ------------------------------------------------ // Shininess TEXTURE ------------------------------------------------
// //
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SHININESS(0),&szPath)) if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SHININESS(0),&szPath))
{ {
LoadTexture(&pcMesh->piShininessTexture,&szPath); LoadTexture(&pcMesh->piShininessTexture,&szPath);
} }
// //
// NORMAL/HEIGHT MAP ------------------------------------------------ // NORMAL/HEIGHT MAP ------------------------------------------------
// //
bool bHM = false; bool bHM = false;
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0),&szPath)) if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0),&szPath))
{
LoadTexture(&pcMesh->piNormalTexture,&szPath);
}
else
{
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_HEIGHT(0),&szPath))
{ {
LoadTexture(&pcMesh->piNormalTexture,&szPath); LoadTexture(&pcMesh->piNormalTexture,&szPath);
} }
bHM = true; else
} {
if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_HEIGHT(0),&szPath))
{
LoadTexture(&pcMesh->piNormalTexture,&szPath);
}
bHM = true;
}
// normal/height maps are sometimes mixed up. Try to detect the type // normal/height maps are sometimes mixed up. Try to detect the type
// of the texture automatically // of the texture automatically
if (pcMesh->piNormalTexture) if (pcMesh->piNormalTexture)
{ {
HMtoNMIfNecessary(pcMesh->piNormalTexture, &pcMesh->piNormalTexture,bHM); HMtoNMIfNecessary(pcMesh->piNormalTexture, &pcMesh->piNormalTexture,bHM);
}
} }
// check whether a global background texture is contained // check whether a global background texture is contained

View File

@ -135,7 +135,8 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space
aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes
aiProcess_ValidateDataStructure | aiProcess_ImproveCacheLocality aiProcess_ValidateDataStructure | aiProcess_ImproveCacheLocality
| aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType); // validate the output data structure | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType | aiProcess_FindDegenerates |
aiProcess_FindInvalidData); // validate the output data structure
// get the end time of zje operation, calculate delta t // get the end time of zje operation, calculate delta t
double fEnd = (double)timeGetTime(); double fEnd = (double)timeGetTime();

View File

@ -675,14 +675,6 @@
RelativePath="..\..\test\unit\Main.cpp" RelativePath="..\..\test\unit\Main.cpp"
> >
</File> </File>
<File
RelativePath="..\..\test\unit\RemoveComponent.cpp"
>
</File>
<File
RelativePath="..\..\test\unit\RemoveComponent.h"
>
</File>
<File <File
RelativePath="..\..\test\unit\utFindInvalidData.cpp" RelativePath="..\..\test\unit\utFindInvalidData.cpp"
> >
@ -763,6 +755,14 @@
RelativePath="..\..\test\unit\utRemoveComments.h" RelativePath="..\..\test\unit\utRemoveComments.h"
> >
</File> </File>
<File
RelativePath="..\..\test\unit\utRemoveComponent.cpp"
>
</File>
<File
RelativePath="..\..\test\unit\utRemoveComponent.h"
>
</File>
<File <File
RelativePath="..\..\test\unit\utRemoveRedundantMaterials.cpp" RelativePath="..\..\test\unit\utRemoveRedundantMaterials.cpp"
> >

View File

@ -787,10 +787,6 @@
RelativePath="..\..\code\DefaultLogger.cpp" RelativePath="..\..\code\DefaultLogger.cpp"
> >
</File> </File>
<File
RelativePath="..\..\code\FaceEdgeAdjacency.h"
>
</File>
<File <File
RelativePath="..\..\code\fast_atof.h" RelativePath="..\..\code\fast_atof.h"
> >
@ -839,6 +835,14 @@
RelativePath="..\..\code\RemoveComments.h" RelativePath="..\..\code\RemoveComments.h"
> >
</File> </File>
<File
RelativePath="..\..\code\SceneCombiner.cpp"
>
</File>
<File
RelativePath="..\..\code\SceneCombiner.h"
>
</File>
<File <File
RelativePath="..\..\code\SGSpatialSort.cpp" RelativePath="..\..\code\SGSpatialSort.cpp"
> >
@ -1370,6 +1374,14 @@
RelativePath="..\..\code\ConvertToLHProcess.h" RelativePath="..\..\code\ConvertToLHProcess.h"
> >
</File> </File>
<File
RelativePath="..\..\code\FindDegenerates.cpp"
>
</File>
<File
RelativePath="..\..\code\FindDegenerates.h"
>
</File>
<File <File
RelativePath="..\..\code\FindInvalidDataProcess.cpp" RelativePath="..\..\code\FindInvalidDataProcess.cpp"
> >

View File

@ -763,10 +763,6 @@
RelativePath="..\..\tools\assimp_view\MessageProc.cpp" RelativePath="..\..\tools\assimp_view\MessageProc.cpp"
> >
</File> </File>
<File
RelativePath="..\..\tools\assimp_view\no_materials.fx"
>
</File>
<File <File
RelativePath="..\..\tools\assimp_view\Normals.cpp" RelativePath="..\..\tools\assimp_view\Normals.cpp"
> >