Added support for cones and cylinders to NFF (the code to generate these primitives is hosted in StandardShapes.cpp).

Fixed some minor material bugs in NFF.
Added some more test NFF files, refactored and commented the old ones.
Added FromToMatrix function to aiMatrix4x4
Temporarily disabled animation support in SMD and fixed some minor bugs. Static models should load correctly in every case.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@254 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
This commit is contained in:
aramis_acg
2008-11-28 23:02:27 +00:00
parent 5639220859
commit be864ce4a0
22 changed files with 601 additions and 305 deletions

View File

@@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// internal headers
#include "SMDLoader.h"
#include "fast_atof.h"
#include "SkeletonMeshBuilder.h"
using namespace Assimp;
@@ -93,6 +93,7 @@ bool SMDImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
}
return true;
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties
void SMDImporter::SetupProperties(const Importer* pImp)
@@ -105,6 +106,7 @@ void SMDImporter::SetupProperties(const Importer* pImp)
configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
}
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void SMDImporter::InternReadFile(
@@ -120,7 +122,7 @@ void SMDImporter::InternReadFile(
iFileSize = (unsigned int)file->FileSize();
// allocate storage and copy the contents of the file to a memory buffer
// Allocate storage and copy the contents of the file to a memory buffer
this->pScene = pScene;
std::vector<char> buff(iFileSize+1);
@@ -132,20 +134,20 @@ void SMDImporter::InternReadFile(
bHasUVs = true;
iLineNumber = 1;
// reserve enough space for ... hm ... 10 textures
// Reserve enough space for ... hm ... 10 textures
aszTextures.reserve(10);
// reserve enough space for ... hm ... 1000 triangles
// Reserve enough space for ... hm ... 1000 triangles
asTriangles.reserve(1000);
// reserve enough space for ... hm ... 20 bones
// Reserve enough space for ... hm ... 20 bones
asBones.reserve(20);
// parse the file ...
ParseFile();
// if there are no triangles it seems to be an animation SMD,
// If there are no triangles it seems to be an animation SMD,
// containing only the animation skeleton.
if (asTriangles.empty())
{
@@ -154,14 +156,15 @@ void SMDImporter::InternReadFile(
throw new ImportErrorException("SMD: No triangles and no bones have "
"been found in the file. This file seems to be invalid.");
}
// set the flag in the scene structure which indicates
// Set the flag in the scene structure which indicates
// that there is nothing than an animation skeleton
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
}
if (!asBones.empty())
{
// check whether all bones have been initialized
// Check whether all bones have been initialized
for (std::vector<SMD::Bone>::const_iterator
i = asBones.begin();
i != asBones.end();++i)
@@ -177,8 +180,9 @@ void SMDImporter::InternReadFile(
FixTimeValues();
// compute absolute bone transformation matrices
ComputeAbsoluteBoneTransformations();
// ComputeAbsoluteBoneTransformations();
}
if (!(pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{
// create output meshes
@@ -193,36 +197,30 @@ void SMDImporter::InternReadFile(
// build output nodes (bones are added as empty dummy nodes)
CreateOutputNodes();
if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)
{
SkeletonMeshBuilder skeleton(pScene);
}
}
// ------------------------------------------------------------------------------------------------
// Write an error message with line number to the log file
void SMDImporter::LogErrorNoThrow(const char* msg)
{
char szTemp[1024];
#if _MSC_VER >= 1400
sprintf_s(szTemp,"Line %i: %s",iLineNumber,msg);
#else
ai_assert(strlen(msg) < 1000);
sprintf(szTemp,"Line %i: %s",iLineNumber,msg);
#endif
DefaultLogger::get()->error(szTemp);
}
// ------------------------------------------------------------------------------------------------
// Write a warning with line number to the log file
void SMDImporter::LogWarning(const char* msg)
{
char szTemp[1024];
#if _MSC_VER >= 1400
sprintf_s(szTemp,"Line %i: %s",iLineNumber,msg);
#else
ai_assert(strlen(msg) < 1000);
sprintf(szTemp,"Line %i: %s",iLineNumber,msg);
#endif
DefaultLogger::get()->warn(szTemp);
}
// ------------------------------------------------------------------------------------------------
// Fix invalid time values in the file
void SMDImporter::FixTimeValues()
@@ -243,10 +241,14 @@ void SMDImporter::FixTimeValues()
}
dLengthOfAnim = dMax;
}
// ------------------------------------------------------------------------------------------------
// create output meshes
void SMDImporter::CreateOutputMeshes()
{
if (aszTextures.empty())
aszTextures.push_back(std::string());
// we need to sort all faces by their material index
// in opposition to other loaders we can be sure that each
// material is at least used once.
@@ -260,9 +262,8 @@ void SMDImporter::CreateOutputMeshes()
unsigned int iNum = (unsigned int)asTriangles.size() / pScene->mNumMeshes;
iNum += iNum >> 1;
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
aaiFaces[i].reserve(iNum);
}
// collect all faces
iNum = 0;
@@ -402,10 +403,9 @@ void SMDImporter::CreateOutputMeshes()
// now build all bones of the mesh
iNum = 0;
for (unsigned int iBone = 0; iBone < asBones.size();++iBone)
{
if (!aaiBones[iBone].empty())++iNum;
}
if (iNum)
if (false && iNum)
{
pcMesh->mNumBones = iNum;
pcMesh->mBones = new aiBone*[pcMesh->mNumBones];
@@ -430,11 +430,11 @@ void SMDImporter::CreateOutputMeshes()
++iNum;
}
}
delete[] aaiBones;
}
delete[] aaiFaces;
}
// ------------------------------------------------------------------------------------------------
// add bone child nodes
void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent)
@@ -469,6 +469,7 @@ void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent)
AddBoneChildren(pc,i);
}
}
// ------------------------------------------------------------------------------------------------
// create output nodes
void SMDImporter::CreateOutputNodes()
@@ -484,7 +485,7 @@ void SMDImporter::CreateOutputNodes()
}
// now add all bones as dummy sub nodes to the graph
AddBoneChildren(pScene->mRootNode,(uint32_t)-1);
// AddBoneChildren(pScene->mRootNode,(uint32_t)-1);
// if we have only one bone we can even remove the root node
if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE &&
@@ -503,6 +504,7 @@ void SMDImporter::CreateOutputNodes()
pScene->mRootNode->mName.length = 10;
}
}
// ------------------------------------------------------------------------------------------------
// create output animations
void SMDImporter::CreateOutputAnimations()
@@ -569,10 +571,11 @@ void SMDImporter::CreateOutputAnimations()
// there are no scaling keys ...
}
}
// ------------------------------------------------------------------------------------------------
void SMDImporter::ComputeAbsoluteBoneTransformations()
{
// for each bone: determine the key with the lowest time value
// For each bone: determine the key with the lowest time value
// theoretically the SMD format should have all keyframes
// in order. However, I've seen a file where this wasn't true.
for (unsigned int i = 0; i < asBones.size();++i)
@@ -609,27 +612,27 @@ void SMDImporter::ComputeAbsoluteBoneTransformations()
const aiMatrix4x4& mat = bone.sAnim.asKeys[iIndex].matrix;
aiMatrix4x4& matOut = bone.sAnim.asKeys[iIndex].matrixAbsolute;
// the same for the parent bone ...
// The same for the parent bone ...
iIndex = parentBone.sAnim.iFirstTimeKey;
const aiMatrix4x4& mat2 = parentBone.sAnim.asKeys[iIndex].matrix;
const aiMatrix4x4& mat2 = parentBone.sAnim.asKeys[iIndex].matrixAbsolute;
// compute the absolute transformation matrix
// Compute the absolute transformation matrix
matOut = mat * mat2;
}
}
++iParent;
}
// store the inverse of the absolute transformation matrix
// Store the inverse of the absolute transformation matrix
// of the first key as bone offset matrix
for (iParent = 0; iParent < asBones.size();++iParent)
{
SMD::Bone& bone = asBones[iParent];
aiMatrix4x4& mat = bone.sAnim.asKeys[bone.sAnim.iFirstTimeKey].matrixAbsolute;
bone.mOffsetMatrix = mat;
bone.mOffsetMatrix = bone.sAnim.asKeys[bone.sAnim.iFirstTimeKey].matrixAbsolute;
bone.mOffsetMatrix.Inverse();
}
}
// ------------------------------------------------------------------------------------------------
// create output materials
void SMDImporter::CreateOutputMaterials()
@@ -646,9 +649,12 @@ void SMDImporter::CreateOutputMaterials()
szName.length = (size_t)::sprintf(szName.data,"Texture_%i",iMat);
pcMat->AddProperty(&szName,AI_MATKEY_NAME);
::strcpy(szName.data, aszTextures[iMat].c_str() );
szName.length = aszTextures[iMat].length();
pcMat->AddProperty(&szName,AI_MATKEY_TEXTURE_DIFFUSE(0));
if (aszTextures[iMat].length())
{
::strcpy(szName.data, aszTextures[iMat].c_str() );
szName.length = aszTextures[iMat].length();
pcMat->AddProperty(&szName,AI_MATKEY_TEXTURE_DIFFUSE(0));
}
}
// create a default material if necessary
@@ -675,6 +681,7 @@ void SMDImporter::CreateOutputMaterials()
pcHelper->AddProperty(&szName,AI_MATKEY_NAME);
}
}
// ------------------------------------------------------------------------------------------------
// Parse the file
void SMDImporter::ParseFile()
@@ -687,10 +694,8 @@ void SMDImporter::ParseFile()
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break;
// "version <n> \n", <n> should be 1 for hl and hl² SMD files
if (0 == ASSIMP_strincmp(szCurrent,"version",7) &&
IsSpaceOrNewLine(*(szCurrent+7)))
if (TokenMatch(szCurrent,"version",7))
{
szCurrent += 8;
if(!SkipSpaces(szCurrent,&szCurrent)) break;
if (1 != strtol10(szCurrent,&szCurrent))
{
@@ -700,35 +705,27 @@ void SMDImporter::ParseFile()
continue;
}
// "nodes\n" - Starts the node section
if (0 == ASSIMP_strincmp(szCurrent,"nodes",5) &&
IsSpaceOrNewLine(*(szCurrent+5)))
if (TokenMatch(szCurrent,"nodes",5))
{
szCurrent += 6;
ParseNodesSection(szCurrent,&szCurrent);
continue;
}
// "triangles\n" - Starts the triangle section
if (0 == ASSIMP_strincmp(szCurrent,"triangles",9) &&
IsSpaceOrNewLine(*(szCurrent+9)))
if (TokenMatch(szCurrent,"triangles",9))
{
szCurrent += 10;
ParseTrianglesSection(szCurrent,&szCurrent);
continue;
}
// "vertexanimation\n" - Starts the vertex animation section
if (0 == ASSIMP_strincmp(szCurrent,"vertexanimation",15) &&
IsSpaceOrNewLine(*(szCurrent+15)))
if (TokenMatch(szCurrent,"vertexanimation",15))
{
bHasUVs = false;
szCurrent += 16;
ParseVASection(szCurrent,&szCurrent);
continue;
}
// "skeleton\n" - Starts the skeleton section
if (0 == ASSIMP_strincmp(szCurrent,"skeleton",8) &&
IsSpaceOrNewLine(*(szCurrent+8)))
if (TokenMatch(szCurrent,"skeleton",8))
{
szCurrent += 9;
ParseSkeletonSection(szCurrent,&szCurrent);
continue;
}
@@ -736,6 +733,7 @@ void SMDImporter::ParseFile()
}
return;
}
// ------------------------------------------------------------------------------------------------
unsigned int SMDImporter::GetTextureIndex(const std::string& filename)
{
@@ -744,13 +742,14 @@ unsigned int SMDImporter::GetTextureIndex(const std::string& filename)
i = aszTextures.begin();
i != aszTextures.end();++i,++iIndex)
{
// case-insensitive ... just for safety
// case-insensitive ... it's a path
if (0 == ASSIMP_stricmp ( filename.c_str(),(*i).c_str()))return iIndex;
}
iIndex = (unsigned int)aszTextures.size();
aszTextures.push_back(filename);
return iIndex;
}
// ------------------------------------------------------------------------------------------------
// Parse the nodes section of the file
void SMDImporter::ParseNodesSection(const char* szCurrent,
@@ -770,24 +769,21 @@ void SMDImporter::ParseNodesSection(const char* szCurrent,
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
*szCurrentOut = szCurrent;
}
// ------------------------------------------------------------------------------------------------
// Parse the triangles section of the file
void SMDImporter::ParseTrianglesSection(const char* szCurrent,
const char** szCurrentOut)
{
// parse a triangle, parse another triangle, parse the next triangle ...
// Parse a triangle, parse another triangle, parse the next triangle ...
// and so on until we reach a token that looks quite similar to "end"
while (true)
{
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break;
// "end\n" - Ends the triangles section
if (0 == ASSIMP_strincmp(szCurrent,"end",3) &&
IsSpaceOrNewLine(*(szCurrent+3)))
{
szCurrent += 4;
if (TokenMatch(szCurrent,"end",3))
break;
}
ParseTriangle(szCurrent,&szCurrent);
}
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
@@ -804,39 +800,33 @@ void SMDImporter::ParseVASection(const char* szCurrent,
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break;
// "end\n" - Ends the "vertexanimation" section
if (0 == ASSIMP_strincmp(szCurrent,"end",3) &&
IsSpaceOrNewLine(*(szCurrent+3)))
{
szCurrent += 4;
//SkipLine(szCurrent,&szCurrent);
if (TokenMatch(szCurrent,"end",3))
break;
}
// "time <n>\n"
if (0 == ASSIMP_strincmp(szCurrent,"time",4) &&
IsSpaceOrNewLine(*(szCurrent+4)))
if (TokenMatch(szCurrent,"time",4))
{
szCurrent += 5;
// NOTE: The doc says that time values COULD be negative ...
// note2: this is the shape key -> valve docs
// NOTE2: this is the shape key -> valve docs
int iTime = 0;
if(!ParseSignedInt(szCurrent,&szCurrent,iTime) || configFrameID != (unsigned int)iTime)break;
SkipLine(szCurrent,&szCurrent);
}
else
{
ParseVertex(szCurrent,&szCurrent,asTriangles.back().avVertices[iCurIndex],true);
if(3 == ++iCurIndex)
if(0 == iCurIndex)
{
asTriangles.push_back(SMD::Face());
iCurIndex = 0;
}
if (++iCurIndex == 3)iCurIndex = 0;
ParseVertex(szCurrent,&szCurrent,asTriangles.back().avVertices[iCurIndex],true);
}
}
if (iCurIndex)
if (iCurIndex != 2 && !asTriangles.empty())
{
// no degenerates, so let this triangle
aszTextures.pop_back();
// we want to no degenerates, so throw this triangle away
asTriangles.pop_back();
}
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
@@ -853,18 +843,12 @@ void SMDImporter::ParseSkeletonSection(const char* szCurrent,
if(!SkipSpacesAndLineEnd(szCurrent,&szCurrent)) break;
// "end\n" - Ends the skeleton section
if (0 == ASSIMP_strincmp(szCurrent,"end",3) &&
IsSpaceOrNewLine(*(szCurrent+3)))
{
szCurrent += 4;
//SkipLine(szCurrent,&szCurrent);
if (TokenMatch(szCurrent,"end",3))
break;
}
// "time <n>\n" - Specifies the current animation frame
else if (0 == ASSIMP_strincmp(szCurrent,"time",4) &&
IsSpaceOrNewLine(*(szCurrent+4)))
else if (TokenMatch(szCurrent,"time",4))
{
szCurrent += 5;
// NOTE: The doc says that time values COULD be negative ...
if(!ParseSignedInt(szCurrent,&szCurrent,iTime))break;
@@ -876,12 +860,12 @@ void SMDImporter::ParseSkeletonSection(const char* szCurrent,
*szCurrentOut = szCurrent;
}
// ------------------------------------------------------------------------------------------------
#define SMDI_PARSE_RETURN { \
SkipLine(szCurrent,&szCurrent); \
*szCurrentOut = szCurrent; \
return; \
}
// ------------------------------------------------------------------------------------------------
// Parse a node line
void SMDImporter::ParseNodeInfo(const char* szCurrent,
@@ -941,6 +925,7 @@ void SMDImporter::ParseNodeInfo(const char* szCurrent,
// go to the beginning of the next line
SMDI_PARSE_RETURN;
}
// ------------------------------------------------------------------------------------------------
// Parse a skeleton element
void SMDImporter::ParseSkeletonElement(const char* szCurrent,
@@ -997,7 +982,7 @@ void SMDImporter::ParseSkeletonElement(const char* szCurrent,
SMDI_PARSE_RETURN;
}
// build the transformation matrix of the key
key.matrix.FromEulerAngles(vRot.x,vRot.y,vRot.z);
key.matrix.FromEulerAnglesXYZ(vRot.x,vRot.y,vRot.z);
{
aiMatrix4x4 mTemp;
mTemp.a4 = vPos.x;
@@ -1009,6 +994,7 @@ void SMDImporter::ParseSkeletonElement(const char* szCurrent,
// go to the beginning of the next line
SMDI_PARSE_RETURN;
}
// ------------------------------------------------------------------------------------------------
// Parse a triangle
void SMDImporter::ParseTriangle(const char* szCurrent,
@@ -1027,10 +1013,10 @@ void SMDImporter::ParseTriangle(const char* szCurrent,
const char* szLast = szCurrent;
while (!IsSpaceOrNewLine(*szCurrent++));
face.iTexture = GetTextureIndex(std::string(szLast,
(uintptr_t)szCurrent-(uintptr_t)szLast));
// ... and get the index that belongs to this file name
face.iTexture = GetTextureIndex(std::string(szLast,(uintptr_t)szCurrent-(uintptr_t)szLast));
SkipLine(szCurrent,&szCurrent);
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
// load three vertices
for (unsigned int iVert = 0; iVert < 3;++iVert)
@@ -1040,6 +1026,7 @@ void SMDImporter::ParseTriangle(const char* szCurrent,
}
*szCurrentOut = szCurrent;
}
// ------------------------------------------------------------------------------------------------
// Parse a float
bool SMDImporter::ParseFloat(const char* szCurrent,
@@ -1051,6 +1038,7 @@ bool SMDImporter::ParseFloat(const char* szCurrent,
*szCurrentOut = fast_atof_move(szCurrent,out);
return true;
}
// ------------------------------------------------------------------------------------------------
// Parse an unsigned int
bool SMDImporter::ParseUnsignedInt(const char* szCurrent,
@@ -1062,6 +1050,7 @@ bool SMDImporter::ParseUnsignedInt(const char* szCurrent,
out = strtol10(szCurrent,szCurrentOut);
return true;
}
// ------------------------------------------------------------------------------------------------
// Parse a signed int
bool SMDImporter::ParseSignedInt(const char* szCurrent,
@@ -1073,6 +1062,7 @@ bool SMDImporter::ParseSignedInt(const char* szCurrent,
out = strtol10s(szCurrent,szCurrentOut);
return true;
}
// ------------------------------------------------------------------------------------------------
// Parse a vertex
void SMDImporter::ParseVertex(const char* szCurrent,
@@ -1143,8 +1133,10 @@ void SMDImporter::ParseVertex(const char* szCurrent,
i = vertex.aiBoneLinks.begin();
i != vertex.aiBoneLinks.end();++i)
{
if(!ParseUnsignedInt(szCurrent,&szCurrent,(*i).first))SMDI_PARSE_RETURN;
if(!ParseFloat(szCurrent,&szCurrent,(*i).second))SMDI_PARSE_RETURN;
if(!ParseUnsignedInt(szCurrent,&szCurrent,(*i).first))
SMDI_PARSE_RETURN;
if(!ParseFloat(szCurrent,&szCurrent,(*i).second))
SMDI_PARSE_RETURN;
}
// go to the beginning of the next line