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
pull/1/head
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

@ -120,5 +120,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#endif // !! ASSIMP_PCH_INCLUDED #endif // !! ASSIMP_PCH_INCLUDED

View File

@ -139,8 +139,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
const static float LOWER_LIMIT = 0.1f; const static float LOWER_LIMIT = 0.1f;
const static float UPPER_LIMIT = 0.9f; const static float UPPER_LIMIT = 0.9f;
const static float LOWER_EPSILON = 1e-3f; const static float LOWER_EPSILON = 10e-3f;
const static float UPPER_EPSILON = 1.f-1e-3f; const static float UPPER_EPSILON = 1.f-10e-3f;
for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
{ {

View File

@ -917,7 +917,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// Now compute the final local transformation matrix of the // Now compute the final local transformation matrix of the
// node from the given translation, rotation and scaling values. // node from the given translation, rotation and scaling values.
// (the rotation is given in Euler angles, XYZ order) // (the rotation is given in Euler angles, XYZ order)
rootOut->mTransformation.FromEulerAngles(AI_DEG_TO_RAD(root->rotation) ); rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation) );
// apply scaling // apply scaling
aiMatrix4x4& mat = rootOut->mTransformation; aiMatrix4x4& mat = rootOut->mTransformation;

View File

@ -147,6 +147,8 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, a
aiUVTransform trafo; aiUVTransform trafo;
trafo.mScaling.x = (*it).wrapAmountW; trafo.mScaling.x = (*it).wrapAmountW;
trafo.mScaling.y = (*it).wrapAmountH; trafo.mScaling.y = (*it).wrapAmountH;
pcMat->AddProperty((float*)&trafo,sizeof(aiUVTransform),AI_MATKEY_UVTRANSFORM(type,cur));
} }
DefaultLogger::get()->debug("LWO2: Setting up non-UV mapping"); DefaultLogger::get()->debug("LWO2: Setting up non-UV mapping");
} }

View File

@ -144,8 +144,8 @@ struct Frame
*/ */
struct TexCoord struct TexCoord
{ {
uint16_t s; int16_t s;
uint16_t t; int16_t t;
} PACK_STRUCT; } PACK_STRUCT;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -413,8 +413,8 @@ void MD2Importer::InternReadFile( const std::string& pFile,
// the texture coordinates are absolute values but we // the texture coordinates are absolute values but we
// need relative values between 0 and 1 // need relative values between 0 and 1
pcOut.x = pcTexCoords[iIndex].s / fDivisorU; pcOut.y = pcTexCoords[iIndex].s / fDivisorU;
pcOut.y = 1.f - pcTexCoords[iIndex].t / fDivisorV; pcOut.x = pcTexCoords[iIndex].t / fDivisorV;
} }
} }
// FIX: flip the face order for use with OpenGL // FIX: flip the face order for use with OpenGL

View File

@ -665,32 +665,66 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// 'tpp' - texture polygon patch primitive // 'tpp' - texture polygon patch primitive
if ('t' == line[0]) if ('t' == line[0])
{ {
if (meshesWithUVCoords.empty()) currentMeshWithUVCoords = NULL;
for (std::vector<MeshInfo>::iterator it = meshesWithUVCoords.begin(), end = meshesWithUVCoords.end();
it != end;++it)
{
if ((*it).shader == s)
{
currentMeshWithUVCoords = &(*it);
break;
}
}
if (!currentMeshWithUVCoords)
{ {
meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals)); meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals));
currentMeshWithUVCoords = &meshesWithUVCoords.back(); currentMeshWithUVCoords = &meshesWithUVCoords.back();
currentMeshWithUVCoords->shader = s;
} }
out = currentMeshWithUVCoords; out = currentMeshWithUVCoords;
} }
// 'pp' - polygon patch primitive // 'pp' - polygon patch primitive
else if ('p' == line[1]) else if ('p' == line[1])
{ {
if (meshesWithNormals.empty()) currentMeshWithNormals = NULL;
for (std::vector<MeshInfo>::iterator it = meshesWithNormals.begin(), end = meshesWithNormals.end();
it != end;++it)
{
if ((*it).shader == s)
{
currentMeshWithNormals = &(*it);
break;
}
}
if (!currentMeshWithNormals)
{ {
meshesWithNormals.push_back(MeshInfo(PatchType_Normals)); meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
currentMeshWithNormals = &meshesWithNormals.back(); currentMeshWithNormals = &meshesWithNormals.back();
currentMeshWithNormals->shader = s;
} }
sz = &line[2];out = currentMeshWithNormals; sz = &line[2];out = currentMeshWithNormals;
} }
// 'p' - polygon primitive // 'p' - polygon primitive
else else
{ {
if (meshes.empty()) currentMesh = NULL;
for (std::vector<MeshInfo>::iterator it = meshes.begin(), end = meshes.end();
it != end;++it)
{
if ((*it).shader == s)
{
currentMesh = &(*it);
break;
}
}
if (!currentMesh)
{ {
meshes.push_back(MeshInfo(PatchType_Simple)); meshes.push_back(MeshInfo(PatchType_Simple));
currentMesh = &meshes.back(); currentMesh = &meshes.back();
currentMesh->shader = s;
} }
sz = &line[1];out = currentMesh; sz = &line[1];out = currentMesh;
} }
@ -711,7 +745,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
{ {
if(!GetNextLine(buffer,line)) if(!GetNextLine(buffer,line))
{ {
DefaultLogger::get()->error("NFF: Unexpected EOF was encountered"); DefaultLogger::get()->error("NFF: Unexpected EOF was encountered. Patch definition incomplete");
continue; continue;
} }
@ -764,7 +798,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// NFF2 uses full colors here so we need to use them too // NFF2 uses full colors here so we need to use them too
// although NFF uses simple scaling factors // although NFF uses simple scaling factors
s.diffuse.g = s.diffuse.b = s.diffuse.r; s.diffuse.g = s.diffuse.b = s.diffuse.r;
s.specular.g = s.specular.b = s.specular.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
@ -787,58 +821,14 @@ void NFFImporter::InternReadFile( const std::string& pFile,
{ {
AI_NFF_PARSE_FLOAT(s.ambient); // optional AI_NFF_PARSE_FLOAT(s.ambient); // optional
} }
// check whether we have this material already -
// although we have the RRM-Step, this is necessary here.
// otherwise we would generate hundreds of small meshes
// with just a few faces - this is surely never wanted.
currentMesh = currentMeshWithNormals = currentMeshWithUVCoords = NULL;
for (std::vector<MeshInfo>::iterator it = meshes.begin(), end = meshes.end();
it != end;++it)
{
if ((*it).bLocked)continue;
if ((*it).shader == s)
{
switch ((*it).pType)
{
case PatchType_Normals:
currentMeshWithNormals = &(*it);
break;
case PatchType_Simple:
currentMesh = &(*it);
break;
default:
currentMeshWithUVCoords = &(*it);
break;
};
}
}
if (!currentMesh)
{
meshes.push_back(MeshInfo(PatchType_Simple));
currentMesh = &meshes.back();
currentMesh->shader = s;
}
if (!currentMeshWithNormals)
{
meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
currentMeshWithNormals = &meshesWithNormals.back();
currentMeshWithNormals->shader = s;
}
if (!currentMeshWithUVCoords)
{
meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals));
currentMeshWithUVCoords = &meshesWithUVCoords.back();
currentMeshWithUVCoords->shader = s;
}
} }
// 'shader' - other way to specify a texture // 'shader' - other way to specify a texture
else if (TokenMatch(sz,"shader",6)) else if (TokenMatch(sz,"shader",6))
{ {
// todo SkipSpaces(&sz);
const char* old = sz;
while (!IsSpaceOrNewLine(*sz))++sz;
s.texFile = std::string(old, (uintptr_t)sz - (uintptr_t)old);
} }
// 'l' - light source // 'l' - light source
else if (TokenMatch(sz,"l",1)) else if (TokenMatch(sz,"l",1))
@ -856,7 +846,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back(); MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s; currentMesh.shader = s;
s.mapping = aiTextureMapping_SPHERE; currentMesh.shader.mapping = aiTextureMapping_SPHERE;
AI_NFF_PARSE_SHAPE_INFORMATION(); AI_NFF_PARSE_SHAPE_INFORMATION();
@ -873,7 +863,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back(); MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s; currentMesh.shader = s;
s.mapping = aiTextureMapping_SPHERE; currentMesh.shader.mapping = aiTextureMapping_SPHERE;
AI_NFF_PARSE_SHAPE_INFORMATION(); AI_NFF_PARSE_SHAPE_INFORMATION();
@ -891,7 +881,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back(); MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s; currentMesh.shader = s;
s.mapping = aiTextureMapping_SPHERE; currentMesh.shader.mapping = aiTextureMapping_SPHERE;
AI_NFF_PARSE_SHAPE_INFORMATION(); AI_NFF_PARSE_SHAPE_INFORMATION();
@ -909,7 +899,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back(); MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s; currentMesh.shader = s;
s.mapping = aiTextureMapping_SPHERE; currentMesh.shader.mapping = aiTextureMapping_SPHERE;
AI_NFF_PARSE_SHAPE_INFORMATION(); AI_NFF_PARSE_SHAPE_INFORMATION();
@ -927,7 +917,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back(); MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s; currentMesh.shader = s;
s.mapping = aiTextureMapping_SPHERE; currentMesh.shader.mapping = aiTextureMapping_BOX;
AI_NFF_PARSE_SHAPE_INFORMATION(); AI_NFF_PARSE_SHAPE_INFORMATION();
@ -942,26 +932,54 @@ void NFFImporter::InternReadFile( const std::string& pFile,
else if (TokenMatch(sz,"c",1)) else if (TokenMatch(sz,"c",1))
{ {
meshesLocked.push_back(MeshInfo(PatchType_Simple,true)); meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshes.back(); MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s; currentMesh.shader = s;
s.mapping = aiTextureMapping_CYLINDER; currentMesh.shader.mapping = aiTextureMapping_CYLINDER;
if(!GetNextLine(buffer,line))
{
DefaultLogger::get()->error("NFF: Unexpected end of file (cone definition not complete)");
break;
}
sz = line;
// read the two center points and the respective radii
aiVector3D center1, center2; float radius1, radius2; aiVector3D center1, center2; float radius1, radius2;
AI_NFF_PARSE_TRIPLE(center1); AI_NFF_PARSE_TRIPLE(center1);
AI_NFF_PARSE_FLOAT(radius1); AI_NFF_PARSE_FLOAT(radius1);
if(!GetNextLine(buffer,line))
{
DefaultLogger::get()->error("NFF: Unexpected end of file (cone definition not complete)");
break;
}
sz = line;
AI_NFF_PARSE_TRIPLE(center2); AI_NFF_PARSE_TRIPLE(center2);
AI_NFF_PARSE_FLOAT(radius2); AI_NFF_PARSE_FLOAT(radius2);
// compute the center point of the cone/cylinder // compute the center point of the cone/cylinder -
center2 = (center2-center1)/2.f; // it is its local transformation origin
currentMesh.center = center1+center2; currentMesh.dir = center2-center1;
center1 = -center2; currentMesh.center = center1+currentMesh.dir/2.f;
float f;
if (( f = currentMesh.dir.Length()) < 10e-3f )
{
DefaultLogger::get()->error("NFF: Cone height is close to zero");
continue;
}
currentMesh.dir /= f; // normalize
// generate the cone - it consists of simple triangles // generate the cone - it consists of simple triangles
StandardShapes::MakeCone(center1, radius1, center2, radius2, iTesselation, currentMesh.vertices); StandardShapes::MakeCone(f, radius1, radius2,
integer_pow(4, iTesselation), currentMesh.vertices);
// MakeCone() returns tris
currentMesh.faces.resize(currentMesh.vertices.size()/3,3); currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
// generate a name for the mesh // generate a name for the mesh. 'cone' if it a cone,
// 'cylinder' if it is a cylinder. Funny, isn't it?
if (radius1 != radius2) if (radius1 != radius2)
::sprintf(currentMesh.name,"cone_%i",cone++); ::sprintf(currentMesh.name,"cone_%i",cone++);
else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++); else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
@ -1125,13 +1143,16 @@ void NFFImporter::InternReadFile( const std::string& pFile,
node->mName.Set(src.name); node->mName.Set(src.name);
// setup the transformation matrix of the node // setup the transformation matrix of the node
node->mTransformation.a4 = src.center.x; aiMatrix4x4::FromToMatrix(aiVector3D(0.f,1.f,0.f),
node->mTransformation.b4 = src.center.y; src.dir,node->mTransformation);
node->mTransformation.c4 = src.center.z;
node->mTransformation.a1 = src.radius.x; aiMatrix4x4& mat = node->mTransformation;
node->mTransformation.b2 = src.radius.y; mat.a1 *= src.radius.x; mat.b1 *= src.radius.x; mat.c1 *= src.radius.x;
node->mTransformation.c3 = src.radius.z; mat.a2 *= src.radius.y; mat.b2 *= src.radius.y; mat.c2 *= src.radius.y;
mat.a3 *= src.radius.z; mat.b3 *= src.radius.z; mat.c3 *= src.radius.z;
mat.a4 = src.center.x;
mat.b4 = src.center.y;
mat.c4 = src.center.z;
++ppcChildren; ++ppcChildren;
} }
@ -1194,7 +1215,8 @@ void NFFImporter::InternReadFile( const std::string& pFile,
s.Set(AI_DEFAULT_MATERIAL_NAME); s.Set(AI_DEFAULT_MATERIAL_NAME);
pcMat->AddProperty(&s, AI_MATKEY_NAME); pcMat->AddProperty(&s, AI_MATKEY_NAME);
aiColor3D c = src.shader.color * src.shader.diffuse; // FIX: Ignore diffuse == 0
aiColor3D c = src.shader.color * (src.shader.diffuse.r ? src.shader.diffuse : aiColor3D(1.f,1.f,1.f));
pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE); pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);
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);
@ -1209,6 +1231,9 @@ void NFFImporter::InternReadFile( const std::string& pFile,
{ {
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));
if (aiTextureMapping_UV != src.shader.mapping)
pcMat->AddProperty((int*)&src.shader.mapping, 1,AI_MATKEY_MAPPING_DIFFUSE(0));
} }
// setup the name of the material // setup the name of the material
@ -1218,11 +1243,6 @@ void NFFImporter::InternReadFile( const std::string& pFile,
pcMat->AddProperty(&s,AI_MATKEY_NAME); pcMat->AddProperty(&s,AI_MATKEY_NAME);
} }
if (aiTextureMapping_UV != src.shader.mapping)
{
pcMat->AddProperty((int*)&src.shader.mapping, 1,AI_MATKEY_MAPPING_DIFFUSE(0));
}
// setup some more material properties that are specific to NFF2 // setup some more material properties that are specific to NFF2
int i; int i;
if (src.shader.twoSided) if (src.shader.twoSided)

View File

@ -174,6 +174,7 @@ private:
, bLocked (bL) , bLocked (bL)
, matIndex (0) , matIndex (0)
, radius (1.f,1.f,1.f) , radius (1.f,1.f,1.f)
, dir (0.f,1.f,0.f)
{ {
name[0] = '\0'; // by default meshes are unnamed name[0] = '\0'; // by default meshes are unnamed
} }
@ -183,7 +184,7 @@ private:
bool bLocked; bool bLocked;
// for spheres, cones and cylinders: center point of the object // for spheres, cones and cylinders: center point of the object
aiVector3D center, radius; aiVector3D center, radius, dir;
char name[128]; char name[128];

View File

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

View File

@ -114,6 +114,7 @@ aiMesh* StandardShapes::MakeMesh(const std::vector<aiVector3D>& positions,
{ {
if (positions.size() & numIndices || positions.empty() || !numIndices)return NULL; if (positions.size() & numIndices || positions.empty() || !numIndices)return NULL;
// Determine which kinds of primitives the mesh will consist of
aiMesh* out = new aiMesh(); aiMesh* out = new aiMesh();
switch (numIndices) switch (numIndices)
{ {
@ -182,18 +183,18 @@ unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D>& positions)
const float t = (1.f + 2.236067977f)/2.f; const float t = (1.f + 2.236067977f)/2.f;
const float s = sqrt(1.f + t*t); const float s = sqrt(1.f + t*t);
aiVector3D v0 = aiVector3D(t,1.f, 0.f)/s; const aiVector3D v0 = aiVector3D(t,1.f, 0.f)/s;
aiVector3D v1 = aiVector3D(-t,1.f, 0.f)/s; const aiVector3D v1 = aiVector3D(-t,1.f, 0.f)/s;
aiVector3D v2 = aiVector3D(t,-1.f, 0.f)/s; const aiVector3D v2 = aiVector3D(t,-1.f, 0.f)/s;
aiVector3D v3 = aiVector3D(-t,-1.f, 0.f)/s; const aiVector3D v3 = aiVector3D(-t,-1.f, 0.f)/s;
aiVector3D v4 = aiVector3D(1.f, 0.f, t)/s; const aiVector3D v4 = aiVector3D(1.f, 0.f, t)/s;
aiVector3D v5 = aiVector3D(1.f, 0.f,-t)/s; const aiVector3D v5 = aiVector3D(1.f, 0.f,-t)/s;
aiVector3D v6 = aiVector3D(-1.f, 0.f,t)/s; const aiVector3D v6 = aiVector3D(-1.f, 0.f,t)/s;
aiVector3D v7 = aiVector3D(-1.f, 0.f,-t)/s; const aiVector3D v7 = aiVector3D(-1.f, 0.f,-t)/s;
aiVector3D v8 = aiVector3D(0.f, t, 1.f)/s; const aiVector3D v8 = aiVector3D(0.f, t, 1.f)/s;
aiVector3D v9 = aiVector3D(0.f,-t, 1.f)/s; const aiVector3D v9 = aiVector3D(0.f,-t, 1.f)/s;
aiVector3D v10 = aiVector3D(0.f, t,-1.f)/s; const aiVector3D v10 = aiVector3D(0.f, t,-1.f)/s;
aiVector3D v11 = aiVector3D(0.f,-t,-1.f)/s; const aiVector3D v11 = aiVector3D(0.f,-t,-1.f)/s;
ADD_TRIANGLE(v0,v8,v4); ADD_TRIANGLE(v0,v8,v4);
ADD_TRIANGLE(v0,v5,v10); ADD_TRIANGLE(v0,v5,v10);
@ -232,26 +233,26 @@ unsigned int StandardShapes::MakeDodecahedron(std::vector<aiVector3D>& positions
const float b = sqrt((3.f-2.23606797f)/6.f); const float b = sqrt((3.f-2.23606797f)/6.f);
const float c = sqrt((3.f+2.23606797f)/6.f); const float c = sqrt((3.f+2.23606797f)/6.f);
aiVector3D v0 = aiVector3D(a,a,a); const aiVector3D v0 = aiVector3D(a,a,a);
aiVector3D v1 = aiVector3D(a,a,-a); const aiVector3D v1 = aiVector3D(a,a,-a);
aiVector3D v2 = aiVector3D(a,-a,a); const aiVector3D v2 = aiVector3D(a,-a,a);
aiVector3D v3 = aiVector3D(a,-a,-a); const aiVector3D v3 = aiVector3D(a,-a,-a);
aiVector3D v4 = aiVector3D(-a,a,a); const aiVector3D v4 = aiVector3D(-a,a,a);
aiVector3D v5 = aiVector3D(-a,a,-a); const aiVector3D v5 = aiVector3D(-a,a,-a);
aiVector3D v6 = aiVector3D(-a,-a,a); const aiVector3D v6 = aiVector3D(-a,-a,a);
aiVector3D v7 = aiVector3D(-a,-a,-a); const aiVector3D v7 = aiVector3D(-a,-a,-a);
aiVector3D v8 = aiVector3D(b,c,0.f); const aiVector3D v8 = aiVector3D(b,c,0.f);
aiVector3D v9 = aiVector3D(-b,c,0.f); const aiVector3D v9 = aiVector3D(-b,c,0.f);
aiVector3D v10 = aiVector3D(b,-c,0.f); const aiVector3D v10 = aiVector3D(b,-c,0.f);
aiVector3D v11 = aiVector3D(-b,-c,0.f); const aiVector3D v11 = aiVector3D(-b,-c,0.f);
aiVector3D v12 = aiVector3D(c, 0.f, b); const aiVector3D v12 = aiVector3D(c, 0.f, b);
aiVector3D v13 = aiVector3D(c, 0.f, -b); const aiVector3D v13 = aiVector3D(c, 0.f, -b);
aiVector3D v14 = aiVector3D(-c, 0.f, b); const aiVector3D v14 = aiVector3D(-c, 0.f, b);
aiVector3D v15 = aiVector3D(-c, 0.f, -b); const aiVector3D v15 = aiVector3D(-c, 0.f, -b);
aiVector3D v16 = aiVector3D(0.f, b, c); const aiVector3D v16 = aiVector3D(0.f, b, c);
aiVector3D v17 = aiVector3D(0.f, -b, c); const aiVector3D v17 = aiVector3D(0.f, -b, c);
aiVector3D v18 = aiVector3D(0.f, b, -c); const aiVector3D v18 = aiVector3D(0.f, b, -c);
aiVector3D v19 = aiVector3D(0.f, -b, -c); const aiVector3D v19 = aiVector3D(0.f, -b, -c);
ADD_PENTAGON(v0, v8, v9, v4, v16); ADD_PENTAGON(v0, v8, v9, v4, v16);
ADD_PENTAGON(v0, v12, v13, v1, v8); ADD_PENTAGON(v0, v12, v13, v1, v8);
@ -274,12 +275,12 @@ unsigned int StandardShapes::MakeOctahedron(std::vector<aiVector3D>& positions)
{ {
positions.reserve(positions.size()+24); positions.reserve(positions.size()+24);
aiVector3D v0 = aiVector3D(1.0f, 0.f, 0.f) ; const aiVector3D v0 = aiVector3D(1.0f, 0.f, 0.f) ;
aiVector3D v1 = aiVector3D(-1.0f, 0.f, 0.f); const aiVector3D v1 = aiVector3D(-1.0f, 0.f, 0.f);
aiVector3D v2 = aiVector3D(0.f, 1.0f, 0.f); const aiVector3D v2 = aiVector3D(0.f, 1.0f, 0.f);
aiVector3D v3 = aiVector3D(0.f, -1.0f, 0.f); const aiVector3D v3 = aiVector3D(0.f, -1.0f, 0.f);
aiVector3D v4 = aiVector3D(0.f, 0.f, 1.0f); const aiVector3D v4 = aiVector3D(0.f, 0.f, 1.0f);
aiVector3D v5 = aiVector3D(0.f, 0.f, -1.0f); const aiVector3D v5 = aiVector3D(0.f, 0.f, -1.0f);
ADD_TRIANGLE(v4,v0,v2); ADD_TRIANGLE(v4,v0,v2);
ADD_TRIANGLE(v4,v2,v1); ADD_TRIANGLE(v4,v2,v1);
@ -301,10 +302,10 @@ unsigned int StandardShapes::MakeTetrahedron(std::vector<aiVector3D>& positions)
const float a = 1.41421f/3.f; const float a = 1.41421f/3.f;
const float b = 2.4494f/3.f; const float b = 2.4494f/3.f;
aiVector3D v0 = aiVector3D(0.f,0.f,1.f); const aiVector3D v0 = aiVector3D(0.f,0.f,1.f);
aiVector3D v1 = aiVector3D(2*a,0,-1.f/3.f); const aiVector3D v1 = aiVector3D(2*a,0,-1.f/3.f);
aiVector3D v2 = aiVector3D(-a,b,-1.f/3.f); const aiVector3D v2 = aiVector3D(-a,b,-1.f/3.f);
aiVector3D v3 = aiVector3D(-a,-b,-1.f/3.f); const aiVector3D v3 = aiVector3D(-a,-b,-1.f/3.f);
ADD_TRIANGLE(v0,v1,v2); ADD_TRIANGLE(v0,v1,v2);
ADD_TRIANGLE(v0,v2,v3); ADD_TRIANGLE(v0,v2,v3);
@ -318,16 +319,16 @@ unsigned int StandardShapes::MakeHexahedron(std::vector<aiVector3D>& positions,
bool polygons /*= false*/) bool polygons /*= false*/)
{ {
positions.reserve(positions.size()+36); positions.reserve(positions.size()+36);
float length = 1.f/1.73205080f; const float length = 1.f/1.73205080f;
aiVector3D v0 = aiVector3D(-1.f,-1.f,-1.f)*length; const aiVector3D v0 = aiVector3D(-1.f,-1.f,-1.f)*length;
aiVector3D v1 = aiVector3D(1.f,-1.f,-1.f)*length; const aiVector3D v1 = aiVector3D(1.f,-1.f,-1.f)*length;
aiVector3D v2 = aiVector3D(1.f,1.f,-1.f)*length; const aiVector3D v2 = aiVector3D(1.f,1.f,-1.f)*length;
aiVector3D v3 = aiVector3D(-1.f,1.f,-1.f)*length; const aiVector3D v3 = aiVector3D(-1.f,1.f,-1.f)*length;
aiVector3D v4 = aiVector3D(-1.f,-1.f,1.f)*length; const aiVector3D v4 = aiVector3D(-1.f,-1.f,1.f)*length;
aiVector3D v5 = aiVector3D(1.f,-1.f,1.f)*length; const aiVector3D v5 = aiVector3D(1.f,-1.f,1.f)*length;
aiVector3D v6 = aiVector3D(1.f,1.f,1.f)*length; const aiVector3D v6 = aiVector3D(1.f,1.f,1.f)*length;
aiVector3D v7 = aiVector3D(-1.f,1.f,1.f)*length; const aiVector3D v7 = aiVector3D(-1.f,1.f,1.f)*length;
ADD_QUAD(v0,v3,v2,v1); ADD_QUAD(v0,v3,v2,v1);
ADD_QUAD(v0,v1,v5,v4); ADD_QUAD(v0,v1,v5,v4);
@ -347,22 +348,95 @@ unsigned int StandardShapes::MakeHexahedron(std::vector<aiVector3D>& positions,
void StandardShapes::MakeSphere(unsigned int tess, void StandardShapes::MakeSphere(unsigned int tess,
std::vector<aiVector3D>& positions) std::vector<aiVector3D>& positions)
{ {
// Reserve enough storage. Every subdivision
// splits each triangle in 4, the icosahedron consists of 60 verts
positions.reserve(positions.size()+60 * integer_pow(4, tess));
// Construct an icosahedron to start with
MakeIcosahedron(positions); MakeIcosahedron(positions);
// ... and subdivide it until the requested output
// tesselation is reached
for (unsigned int i = 0; i<tess;++i) for (unsigned int i = 0; i<tess;++i)
Subdivide(positions); Subdivide(positions);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void StandardShapes::MakeCone( void StandardShapes::MakeCone(float height,float radius1,
aiVector3D& center1, float radius2,unsigned int tess,
float radius1, std::vector<aiVector3D>& positions,bool bOpen /*= false */)
aiVector3D& center2,
float radius2,
unsigned int tess,
std::vector<aiVector3D>& positions,
bool bOpened /*= false*/)
{ {
// Sorry, a cone with less than 3 segments makes
// ABSOLUTELY NO SENSE
if (tess < 3 || !height)
return;
// No negative radii
radius1 = fabs(radius1);
radius2 = fabs(radius2);
float halfHeight = height / 2;
// radius1 is always the smaller one
if (radius2 > radius1)
{
std::swap(radius2,radius1);
halfHeight = -halfHeight;
}
// Use a large epsilon to check whether the cone is pointy
if (radius1 < (radius2-radius1)*10e-3f)radius1 = 0.f;
// We will need 3*2 verts per segment + 3*2 verts per segment
// if the cone is closed
const unsigned int mem = tess*6 + (!bOpen ? tess*3 * (radius1 ? 2 : 1) : 0);
positions.reserve(mem);
// Now construct all segments
const float angle_delta = (float)AI_MATH_TWO_PI / tess;
const float angle_max = (float)AI_MATH_TWO_PI;
float s = 1.f; // cos(angle == 0);
float t = 0.f; // sin(angle == 0);
for (float angle = 0.f; angle < angle_max; )
{
const aiVector3D v1 = aiVector3D (s * radius1, -halfHeight, t * radius1 );
const aiVector3D v2 = aiVector3D (s * radius2, halfHeight, t * radius2 );
const float next = angle + angle_delta;
float s2 = cos(next);
float t2 = sin(next);
const aiVector3D v3 = aiVector3D (s2 * radius2, halfHeight, t2 * radius2 );
const aiVector3D v4 = aiVector3D (s2 * radius1, -halfHeight, t2 * radius1 );
positions.push_back(v1);
positions.push_back(v3);
positions.push_back(v2);
positions.push_back(v4);
positions.push_back(v3);
positions.push_back(v1);
if (!bOpen)
{
// generate the end 'cap'
positions.push_back(aiVector3D(s * radius2, halfHeight, t * radius2 ));
positions.push_back(aiVector3D(0.f, halfHeight, 0.f));
positions.push_back(aiVector3D(s2 * radius2, halfHeight, t2 * radius2 ));
if (radius1)
{
// generate the other end 'cap'
positions.push_back(aiVector3D(s * radius1, -halfHeight, t * radius1 ));
positions.push_back(aiVector3D(0.f, -halfHeight, 0.f));
positions.push_back(aiVector3D(s2 * radius1, -halfHeight, t2 * radius1 ));
}
}
s = s2;
t = t2;
angle = next;
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -373,7 +447,7 @@ void StandardShapes::MakeCircle(
unsigned int tess, unsigned int tess,
std::vector<aiVector3D>& positions) std::vector<aiVector3D>& positions)
{ {
//aiVector3D current = aiVector3D ( normal.x, // todo
} }
} // ! Assimp } // ! Assimp

View File

@ -153,28 +153,28 @@ public:
* *
* |-----| <- radius 1 * |-----| <- radius 1
* *
* __x__ <- center 1 * __x__ <- ]
* / \ * / \ | height
* / \ * / \ |
* / \ * / \ |
* / \ * / \ |
* /______x______\ <- center 2 * /______x______\ <- ] <- end cap
* *
* |-------------| <- radius 2 * |-------------| <- radius 2
* *
* @endcode * @endcode
* *
* @param center1 First center point * @param height Height of the cone
* @param radius1 First radius * @param radius1 First radius
* @param center2 Second center point
* @param radius2 Second radius * @param radius2 Second radius
* @param tess Number of subdivisions * @param tess Number of triangles.
* @param bOpened true for an open cone/cylinder. * @param bOpened true for an open cone/cylinder. An open shape has
* @param positions Receives output triangles. * no 'end caps'
* @param positions Receives output triangles
*/ */
static void MakeCone(aiVector3D& center1,float radius1, static void MakeCone(float height,float radius1,
aiVector3D& center2,float radius2,unsigned int tess, float radius2,unsigned int tess,
std::vector<aiVector3D>& positions,bool bOpened = false); std::vector<aiVector3D>& positions,bool bOpen= false);
// ---------------------------------------------------------------- // ----------------------------------------------------------------
@ -185,7 +185,7 @@ public:
* @param normal Normal vector of the circle. * @param normal Normal vector of the circle.
* This is also the normal vector of all triangles generated by * This is also the normal vector of all triangles generated by
* this function. * this function.
* @param tess Number of triangles * @param tess Number of segments.
* @param positions Receives output triangles. * @param positions Receives output triangles.
*/ */
static void MakeCircle(const aiVector3D& center, const aiVector3D& normal, static void MakeCircle(const aiVector3D& center, const aiVector3D& normal,

View File

@ -54,7 +54,6 @@ namespace Assimp
// @param max Maximum number of characters to be written, including '\0' // @param max Maximum number of characters to be written, including '\0'
// @param number Number to be written // @param number Number to be written
// @return Number of bytes written. Including '\0'. // @return Number of bytes written. Including '\0'.
// ---------------------------------------------------------------------------
inline unsigned int itoa10( char* out, unsigned int max, int32_t number) inline unsigned int itoa10( char* out, unsigned int max, int32_t number)
{ {
ai_assert(NULL != out); ai_assert(NULL != out);
@ -96,7 +95,6 @@ inline unsigned int itoa10( char* out, unsigned int max, int32_t number)
// Secure template overload // Secure template overload
// The compiler should choose this function if he is able to determine the // The compiler should choose this function if he is able to determine the
// size of the array automatically. // size of the array automatically.
// ---------------------------------------------------------------------------
template <unsigned int length> template <unsigned int length>
inline unsigned int itoa10( char(& out)[length], int32_t number) inline unsigned int itoa10( char(& out)[length], int32_t number)
{ {
@ -113,13 +111,16 @@ inline unsigned int itoa10( char(& out)[length], int32_t number)
* \param s1 First input string * \param s1 First input string
* \param s2 Second input string * \param s2 Second input string
*/ */
// ---------------------------------------------------------------------------
inline int ASSIMP_stricmp(const char *s1, const char *s2) inline int ASSIMP_stricmp(const char *s1, const char *s2)
{ {
#if (defined _MSC_VER) #if (defined _MSC_VER)
return ::_stricmp(s1,s2); return ::_stricmp(s1,s2);
#elif defined( __GNUC__ )
return ::strcasecmp(s1,s2);
#else #else
register char c1, c2; register char c1, c2;
do do
@ -136,7 +137,6 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** \brief Case independent comparison of two std::strings /** \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)
{ {
register int i = (int)b.length()-(int)a.length(); register int i = (int)b.length()-(int)a.length();
@ -154,13 +154,16 @@ inline int ASSIMP_stricmp(const std::string& a, const std::string& b)
* \param s2 Second input string * \param s2 Second input string
* \param n Macimum number of characters to compare * \param n Macimum number of characters to compare
*/ */
// ---------------------------------------------------------------------------
inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n) inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n)
{ {
#if (defined _MSC_VER) #if (defined _MSC_VER)
return ::_strnicmp(s1,s2,n); return ::_strnicmp(s1,s2,n);
#elif defined( __GNUC__ )
return ::strncasecmp(s1,s2, n);
#else #else
register char c1, c2; register char c1, c2;
unsigned int p = 0; unsigned int p = 0;
@ -175,6 +178,18 @@ inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n)
return c1 - c2; return c1 - c2;
#endif #endif
} }
// ---------------------------------------------------------------------------
// Evaluates an integer power.
inline unsigned int integer_pow (unsigned int base, unsigned int power)
{
unsigned int res = 1;
for (unsigned int i = 0; i < power;++i)
res *= base;
return res;
} }
} // end of namespace
#endif // ! AI_STRINGCOMPARISON_H_INC #endif // ! AI_STRINGCOMPARISON_H_INC

View File

@ -511,7 +511,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
// check whether all bone weights for a vertex sum to 1.0 ... // check whether all bone weights for a vertex sum to 1.0 ...
for (unsigned int i = 0; i < pMesh->mNumVertices;++i) for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
{ {
if (afSum[i] && (afSum[i] <= 0.995 || afSum[i] >= 1.005)) if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05))
{ {
ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]); ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]);
} }

View File

@ -78,7 +78,7 @@ public:
/** Compares two paths and check whether the point to identical files. /** Compares two paths and check whether the point to identical files.
* *
* The dummy implementation of this virtual performs a * The dummy implementation of this virtual performs a
* case-insensitive comparison of the path strings. * case-insensitive comparison of the absolute path strings.
* @param one First file * @param one First file
* @param second Second file * @param second Second file
* @return true if the paths point to the same file. The file needn't * @return true if the paths point to the same file. The file needn't

View File

@ -118,8 +118,8 @@ struct aiMatrix4x4
* \param y Rotation angle for the y-axis, in radians * \param y Rotation angle for the y-axis, in radians
* \param z Rotation angle for the z-axis, in radians * \param z Rotation angle for the z-axis, in radians
*/ */
inline void FromEulerAngles(float x, float y, float z); inline void FromEulerAnglesXYZ(float x, float y, float z);
inline void FromEulerAngles(const aiVector3D& blubb); inline void FromEulerAnglesXYZ(const aiVector3D& blubb);
/** \brief Returns a rotation matrix for a rotation around the x axis /** \brief Returns a rotation matrix for a rotation around the x axis
@ -158,6 +158,18 @@ struct aiMatrix4x4
*/ */
static aiMatrix4x4& Translation( const aiVector3D& v, aiMatrix4x4& out); static aiMatrix4x4& Translation( const aiVector3D& v, aiMatrix4x4& out);
/** A function for creating a rotation matrix that rotates a vector called
* "from" into another vector called "to".
* Input : from[3], to[3] which both must be *normalized* non-zero vectors
* Output: mtx[3][3] -- a 3x3 matrix in colum-major form
* Authors: Tomas Möller, John Hughes
* "Efficiently Building a Matrix to Rotate One Vector to Another"
* Journal of Graphics Tools, 4(4):1-4, 1999
*/
static aiMatrix4x4& FromToMatrix(const aiVector3D& from,
const aiVector3D& to, aiMatrix4x4& out);
#endif // __cplusplus #endif // __cplusplus
float a1, a2, a3, a4; float a1, a2, a3, a4;

View File

@ -87,12 +87,16 @@ inline aiMatrix4x4& aiMatrix4x4::Inverse()
float det = Determinant(); float det = Determinant();
if(det == 0.0f) if(det == 0.0f)
{ {
// Matrix not invertible. Setting all elements to nan is not really
// correct in a mathematical sense but it is easy to debug for the
// programmer.
const float nan = std::numeric_limits<float>::quiet_NaN(); const float nan = std::numeric_limits<float>::quiet_NaN();
*this = aiMatrix4x4( *this = aiMatrix4x4(
nan,nan,nan,nan, nan,nan,nan,nan,
nan,nan,nan,nan, nan,nan,nan,nan,
nan,nan,nan,nan, nan,nan,nan,nan,
nan,nan,nan,nan); nan,nan,nan,nan);
return *this; return *this;
} }
@ -204,43 +208,62 @@ inline void aiMatrix4x4::DecomposeNoScaling (aiQuaternion& rotation,
rotation = aiQuaternion((aiMatrix3x3)_this); rotation = aiQuaternion((aiMatrix3x3)_this);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
inline void aiMatrix4x4::FromEulerAngles(const aiVector3D& blubb) inline void aiMatrix4x4::FromEulerAnglesXYZ(const aiVector3D& blubb)
{ {
FromEulerAngles(blubb.x,blubb.y,blubb.z); FromEulerAnglesXYZ(blubb.x,blubb.y,blubb.z);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
inline void aiMatrix4x4::FromEulerAngles(float x, float y, float z) inline void aiMatrix4x4::FromEulerAnglesXYZ(float x, float y, float z)
{ {
aiMatrix4x4& _this = *this; aiMatrix4x4& _this = *this;
const float A = ::cos(x); float cr = cos( x );
const float B = ::sin(x); float sr = sin( x );
const float C = ::cos(y); float cp = cos( y );
const float D = ::sin(y); float sp = sin( y );
const float E = ::cos(z); float cy = cos( z );
const float F = ::sin(z); float sy = sin( z );
const float AD = A * D;
const float BD = B * D; _this.a1 = cp*cy ;
_this.a1 = C * E; _this.a2 = cp*sy;
_this.a2 = -C * F; _this.a3 = -sp ;
_this.a3 = D;
_this.b1 = BD * E + A * F; float srsp = sr*sp;
_this.b2 = -BD * F + A * E; float crsp = cr*sp;
_this.b3 = -B * C;
_this.c1 = -AD * E + B * F; _this.b1 = srsp*cy-cr*sy ;
_this.c2 = AD * F + B * E; _this.b2 = srsp*sy+cr*cy ;
_this.c3 = A * C; _this.b3 = sr*cp ;
_this.a4 = _this.b4 = _this.c4 = _this.d1 = _this.d2 = _this.d3 = 0.0f;
_this.d4 = 1.0f; _this.c1 = crsp*cy+sr*sy ;
_this.c2 = crsp*sy-sr*cy ;
_this.c3 = cr*cp ;
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
inline bool aiMatrix4x4::IsIdentity() const inline bool aiMatrix4x4::IsIdentity() const
{ {
return !(a1 != 1.0f || a2 || a3 || a4 || // Use a small epsilon to solve floating-point inaccuracies
b1 || b2 != 1.0f || b3 || b4 || const static float epsilon = 10e-3f;
c1 || c2 || c3 != 1.0f || a4 ||
d1 || d2 || d3 || d4 != 1.0f); return (a2 <= epsilon && a2 >= -epsilon &&
a3 <= epsilon && a3 >= -epsilon &&
a4 <= epsilon && a4 >= -epsilon &&
b1 <= epsilon && b1 >= -epsilon &&
b3 <= epsilon && b3 >= -epsilon &&
b4 <= epsilon && b4 >= -epsilon &&
c1 <= epsilon && c1 >= -epsilon &&
c2 <= epsilon && c2 >= -epsilon &&
c3 <= epsilon && c3 >= -epsilon &&
d1 <= epsilon && d1 >= -epsilon &&
d2 <= epsilon && d2 >= -epsilon &&
d3 <= epsilon && d3 >= -epsilon &&
a1 <= 1.f+epsilon && a1 >= 1.f-epsilon &&
b2 <= 1.f+epsilon && b2 >= 1.f-epsilon &&
c3 <= 1.f+epsilon && c3 >= 1.f-epsilon &&
d4 <= 1.f+epsilon && d4 >= 1.f-epsilon);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
inline aiMatrix4x4& aiMatrix4x4::RotationX(float a, aiMatrix4x4& out) inline aiMatrix4x4& aiMatrix4x4::RotationX(float a, aiMatrix4x4& out)
{ {
@ -312,5 +335,95 @@ inline aiMatrix4x4& aiMatrix4x4::Translation( const aiVector3D& v, aiMatrix4x4&
return out; return out;
} }
// ---------------------------------------------------------------------------
/** A function for creating a rotation matrix that rotates a vector called
* "from" into another vector called "to".
* Input : from[3], to[3] which both must be *normalized* non-zero vectors
* Output: mtx[3][3] -- a 3x3 matrix in colum-major form
* Authors: Tomas Möller, John Hughes
* "Efficiently Building a Matrix to Rotate One Vector to Another"
* Journal of Graphics Tools, 4(4):1-4, 1999
*/
// ---------------------------------------------------------------------------
inline aiMatrix4x4& aiMatrix4x4::FromToMatrix(const aiVector3D& from,
const aiVector3D& to, aiMatrix4x4& mtx)
{
const aiVector3D v = from ^ to;
const float e = from * to;
const float f = (e < 0)? -e:e;
if (f > 1.0 - 0.00001f) /* "from" and "to"-vector almost parallel */
{
aiVector3D u,v; /* temporary storage vectors */
aiVector3D x; /* vector most nearly orthogonal to "from" */
x.x = (from.x > 0.0)? from.x : -from.x;
x.y = (from.y > 0.0)? from.y : -from.y;
x.z = (from.z > 0.0)? from.z : -from.z;
if (x.x < x.y)
{
if (x.x < x.z)
{
x.x = 1.0; x.y = x.z = 0.0;
}
else
{
x.z = 1.0; x.y = x.z = 0.0;
}
}
else
{
if (x.y < x.z)
{
x.y = 1.0; x.x = x.z = 0.0;
}
else
{
x.z = 1.0; x.x = x.y = 0.0;
}
}
u.x = x.x - from.x; u.y = x.y - from.y; u.z = x.z - from.z;
v.x = x.x - to.x; v.y = x.y - to.y; v.z = x.z - to.z;
const float c1 = 2.0f / (u * u);
const float c2 = 2.0f / (v * v);
const float c3 = c1 * c2 * (u * v);
for (unsigned int i = 0; i < 3; i++)
{
for (unsigned int j = 0; j < 3; j++)
{
mtx[i][j] = - c1 * u[i] * u[j] - c2 * v[i] * v[j]
+ c3 * v[i] * u[j];
}
mtx[i][i] += 1.0;
}
}
else /* the most common case, unless "from"="to", or "from"=-"to" */
{
/* ... use this hand optimized version (9 mults less) */
const float h = 1.0f/(1.0f + e); /* optimization by Gottfried Chen */
const float hvx = h * v.x;
const float hvz = h * v.z;
const float hvxy = hvx * v.y;
const float hvxz = hvx * v.z;
const float hvyz = hvz * v.y;
mtx[0][0] = e + hvx * v.x;
mtx[0][1] = hvxy - v.z;
mtx[0][2] = hvxz + v.y;
mtx[1][0] = hvxy + v.z;
mtx[1][1] = e + h * v.y * v.y;
mtx[1][2] = hvyz - v.x;
mtx[2][0] = hvxz - v.y;
mtx[2][1] = hvyz + v.x;
mtx[2][2] = e + hvz * v.z;
}
return mtx;
}
#endif // __cplusplus #endif // __cplusplus
#endif // AI_MATRIX4x4_INL_INC #endif // AI_MATRIX4x4_INL_INC

Binary file not shown.

View File

@ -0,0 +1,25 @@
b 0.078 0.361 0.753
v
from 2.1 1.3 1.7
at 0 0 0
up 0 0 1
angle 45
hither 0.01
resolution 512 512
l 4 3 2
l 1 -4 4
l -3 1 5
f 1 0.9 0.7 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthSpherical.jpg
s 0 0 0 0.5
f 1 0.9 0.7 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthSpherical.jpg
s 0.272166 0.272166 0.544331 0.16665
s 0.643951 0.172546 1.11022e-16 0.16665
s 0.172546 0.643951 1.11022e-16 0.16665
s -0.371785 0.0996195 0.544331 0.16665
s -0.471405 0.471405 1.11022e-16 0.16665
s -0.643951 -0.172546 1.11022e-16 0.16665
s 0.0996195 -0.371785 0.544331 0.16665
s -0.172546 -0.643951 1.11022e-16 0.16665
s 0.471405 -0.471405 1.11022e-16 0.16665

View File

@ -0,0 +1,26 @@
#red
f 1.0 0.0 0.0 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthCylindric.jpg
tess 4
# a simple cone - should go directly through the center
c
10 10 10 3
-10 -10 -10 6
f 1.0 1.0 1.0 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthSpherical.jpg
s -10 -10 -10 2
s 10 10 10 3
#white
f 1.0 1.0 1.0 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthCylindric.jpg
# another cone, closed this time
c
20 20 20 6
11 11 11 0

View File

@ -0,0 +1,10 @@
#red
f 1 0.9 0.7 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthCylindric.jpg
tess 4
# a simple cylinder - should go directly through the center
c
10 10 10 6
-10 -10 -10 6

View File

@ -1,27 +1,36 @@
# Enable high-quality subdivision
tess 4 tess 4
# This represents a C4H10 molecule (Butan)
f 0.3 0.3 0.3 1 1 f 0.3 0.3 0.3 1 1
# a centered sphere
s 0 0 0 5 s 0 0 0 5
s 20 0 0 5 s 20 0 0 5
s 40 0 0 5 s 40 0 0 5
s 60 0 0 5 s 60 0 0 5
# Switch to white
f 1 1 1 1 1 f 1 1 1 1 1
s -5 0 0 3 s -5 0 0 3
s 0 5 0 3 s 0 5 0 3
s 0 -5 0 3 s 0 -5 0 3
s 20 5 0 3
s 20 -5 0 3
s 40 5 0 3
s 40 -5 0 3
s 60 5 0 3
s 60 -5 0 3
s 65 0 0 3
# Now a tube to connect them
c
0 0 0 0.8
60 0 0 0.8

View File

@ -5,13 +5,13 @@
s 5.0 5.0 5.0 3.0 s 5.0 5.0 5.0 3.0
#blue #blue
f 0.0 0.0 1.0 0 1 1 f 0.0 0.0 1.0 0 1 1 1
# Another simple sphere # Another simple sphere
s 5.0 4.0 8.0 3.0 s 5.0 4.0 8.0 3.0
#green #green
f 0.0 1.0 0.0 0 1 1 f 1.0 1.0 1.0 0.5 0.5 45.2776 0 1 ./../../LWOFiles/LWo2/MappingModes/EarthCylindric.jpg
# And another one # And another one
s 1.0 -4.0 2.0 4.0 2 2 s 1.0 -4.0 2.0 4.0 2 2
@ -19,10 +19,6 @@ s 1.0 -4.0 2.0 4.0 2 2
#red #red
f 1.0 0.0 0.0 0 1 1 f 1.0 0.0 0.0 0 1 1
# a simple cone
c 10 10 5 3
c 14 14 3 6
# An icosahedron # An icosahedron
tess 0 tess 0