Fixed bug in the AC loader causing lines to load incorrectly. Seems to work now.

Added some more essential includes to AssimpPCH.hAdded support for line and point meshes to most steps - I did nto yet adapt all unit tests, so meshes with mixed primitive types are not absolutely safe at the moment.
Added camera and light support to the PretransformVert step. Fixed some small inaccuracies and fixed a bug reported by Mark Sibly causing all transformations to be invalid. However the step is nto yet completely correct, there are still some small artifacts.
Updated light and camera data structures, added temporary validation code for the
Renamed AI_SCENE_FLAGS_ANIM_SKELETON_ONLY to a more generic AI_SCENE_FLAGS_INCOMPLETE flag.
Fixed bug in the OFF loader causing meshes with polygons to crash
Added line support to the DXF loader - seems to fail for the moment cause of SortByPType.
Added support for lights and cameras to NFF, implemented another NFF format subtype (file starts with 'nff'). Implemented NFF 'tpp' chunk and a corresponding texture extension.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@185 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2008-10-19 11:32:33 +00:00
parent 3aecad406c
commit 2da2835b29
47 changed files with 1886 additions and 809 deletions

View File

@ -126,9 +126,13 @@ bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) cons
if( pos == std::string::npos)return false; if( pos == std::string::npos)return false;
std::string extension = pFile.substr( pos); std::string extension = pFile.substr( pos);
return !(extension.length() != 3 || extension[0] != '.' || for( std::string::iterator it = extension.begin(); it != extension.end(); ++it)
extension[1] != 'a' && extension[1] != 'A' || *it = tolower( *it);
extension[2] != 'c' && extension[2] != 'C');
if( extension == ".ac" || extension == "ac")
return true;
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -308,9 +312,16 @@ void AC3DImporter::ConvertMaterial(const Object& object,
matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE); matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE);
matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR); matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR);
float f = 1.f - matSrc.trans; int n;
if (matSrc.shin)
{
n = aiShadingMode_Phong;
matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS);
}
else n = aiShadingMode_Gouraud;
matDest.AddProperty<int>(&n,1,AI_MATKEY_SHADING_MODEL);
matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS); float f = 1.f - matSrc.trans;
matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY); matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
} }
@ -352,6 +363,13 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
faces->mIndices = new unsigned int[1]; faces->mIndices = new unsigned int[1];
faces->mIndices[0] = i; faces->mIndices[0] = i;
} }
// use the primary material in this case. this should be the
// default material if all objects of the file contain points
// and no faces.
mesh->mMaterialIndex = 0;
outMaterials.push_back(new MaterialHelper());
ConvertMaterial(object, materials[0], *outMaterials.back());
} }
else else
{ {
@ -501,7 +519,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
face.mNumIndices = 2; face.mNumIndices = 2;
face.mIndices = new unsigned int[2]; face.mIndices = new unsigned int[2];
face.mIndices[0] = cur++; face.mIndices[0] = cur++;
face.mIndices[1] = cur; face.mIndices[1] = cur++;
// copy vertex positions // copy vertex positions
*vertices++ = object.vertices[(*it2).first]; *vertices++ = object.vertices[(*it2).first];
@ -660,6 +678,7 @@ 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());
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

@ -162,7 +162,7 @@ protected:
*/ */
void GetExtensionList(std::string& append) void GetExtensionList(std::string& append)
{ {
append.append("*.ac"); append.append("*.ac;*.acc");
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------

View File

@ -1,9 +1,72 @@
/*
---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------
*/
#ifndef ASSIMP_PCH_INCLUDED #ifndef ASSIMP_PCH_INCLUDED
#define ASSIMP_PCH_INCLUDED #define ASSIMP_PCH_INCLUDED
// STL headers // *******************************************************************
// Print detailled memory allocation statistics? In this case we'll
// need to overload all C++ memory management functions. It is assumed
// that old C routines, such as malloc(), are NOT used in Assimp.
// *******************************************************************
#ifdef ASSIMP_BUILD_MEMORY_STATISTICS
void *operator new (size_t);
void operator delete (void *);
void *operator new[] (size_t);
void operator delete[] (void *);
#endif
// *******************************************************************
// If we have at least VC8 some C string manipulation functions
// are mapped to their safe _s counterparts (e.g. _itoa_s).
// *******************************************************************
# if _MSC_VER >= 1400 && !(defined _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
# define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
# endif
// *******************************************************************
// STL headers - we need quite a lot of them
// *******************************************************************
#include <vector> #include <vector>
#include <list> #include <list>
#include <map> #include <map>
@ -16,7 +79,10 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
// *******************************************************************
// public ASSIMP headers // public ASSIMP headers
// *******************************************************************
#include "../include/DefaultLogger.h" #include "../include/DefaultLogger.h"
#include "../include/IOStream.h" #include "../include/IOStream.h"
#include "../include/IOSystem.h" #include "../include/IOSystem.h"
@ -24,21 +90,32 @@
#include "../include/aiPostProcess.h" #include "../include/aiPostProcess.h"
#include "../include/assimp.hpp" #include "../include/assimp.hpp"
// *******************************************************************
// internal headers that are nearly always required // internal headers that are nearly always required
// *******************************************************************
#include "MaterialSystem.h" #include "MaterialSystem.h"
#include "StringComparison.h" #include "StringComparison.h"
#include "ByteSwap.h" #include "StreamReader.h"
#include "qnan.h" #include "qnan.h"
// *******************************************************************
// boost headers - take them from the workaround dir if possible // boost headers - take them from the workaround dir if possible
// *******************************************************************
#ifdef ASSIMP_BUILD_BOOST_WORKAROUND #ifdef ASSIMP_BUILD_BOOST_WORKAROUND
# include "../include/BoostWorkaround/boost/scoped_ptr.hpp" # include "../include/BoostWorkaround/boost/scoped_ptr.hpp"
# include "../include/BoostWorkaround/boost/format.hpp" # include "../include/BoostWorkaround/boost/format.hpp"
# include "../include/BoostWorkaround/boost/multi_array.hpp"
#else #else
// NOTE: boost::multi_array is nto yet supported by the workaround
#define AI_BUILD_NO_BVH_IMPORTER
# include <boost/scoped_ptr.hpp> # include <boost/scoped_ptr.hpp>
# include <boost/format.hpp> # include <boost/format.hpp>
# include <boost/multi_array.hpp>
#endif #endif

View File

@ -178,7 +178,7 @@ protected:
* a face is unique. Or the other way round: a vertex index may * a face is unique. Or the other way round: a vertex index may
* not occur twice in a single aiMesh. * not occur twice in a single aiMesh.
* *
* If the "AnimationSkeletonOnly"-Flag is not set:<br> * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:<br>
* - at least one mesh must be there<br> * - at least one mesh must be there<br>
* - at least one material must be there<br> * - at least one material must be there<br>
* - there may be no meshes with 0 vertices or faces<br> * - there may be no meshes with 0 vertices or faces<br>

View File

@ -246,12 +246,16 @@ void DXFImporter::InternReadFile( const std::string& pFile,
{ {
aiFace& face = pMesh->mFaces[i]; aiFace& face = pMesh->mFaces[i];
// check whether we need four indices here // check whether we need four,three or two indices here
if (vp[3] != vp[2]) if (vp[1] == vp[2])
{ {
face.mNumIndices = 4; face.mNumIndices = 2;
} }
else face.mNumIndices = 3; else if (vp[3] == vp[2])
{
face.mNumIndices = 3;
}
else face.mNumIndices = 4;
face.mIndices = new unsigned int[face.mNumIndices]; face.mIndices = new unsigned int[face.mNumIndices];
for (unsigned int a = 0; a < face.mNumIndices;++a) for (unsigned int a = 0; a < face.mNumIndices;++a)
@ -323,7 +327,7 @@ bool DXFImporter::ParseEntities()
{ {
if (!groupCode) if (!groupCode)
{ {
if (!::strcmp(cursor,"3DFACE")) if (!::strcmp(cursor,"3DFACE") || !::strcmp(cursor,"LINE") || !::strcmp(cursor,"3DLINE"))
if (!Parse3DFace()) return false; else bRepeat = true; if (!Parse3DFace()) return false; else bRepeat = true;
if (!::strcmp(cursor,"POLYLINE") || !::strcmp(cursor,"LWPOLYLINE")) if (!::strcmp(cursor,"POLYLINE") || !::strcmp(cursor,"LWPOLYLINE"))
@ -524,6 +528,10 @@ bool DXFImporter::Parse3DFace()
aiVector3D vip[4]; // -- vectors are initialized to zero aiVector3D vip[4]; // -- vectors are initialized to zero
aiColor4D clr(g_clrInvalid); aiColor4D clr(g_clrInvalid);
// this is also used for for parsing line entities
bool bThird = false;
while (GetNextToken()) while (GetNextToken())
{ {
switch (groupCode) switch (groupCode)
@ -556,22 +564,28 @@ bool DXFImporter::Parse3DFace()
case 31: vip[1].z = fast_atof(cursor);break; case 31: vip[1].z = fast_atof(cursor);break;
// x position of the third corner // x position of the third corner
case 12: vip[2].x = fast_atof(cursor);break; case 12: vip[2].x = fast_atof(cursor);
bThird = true;break;
// y position of the third corner // y position of the third corner
case 22: vip[2].y = -fast_atof(cursor);break; case 22: vip[2].y = -fast_atof(cursor);
bThird = true;break;
// z position of the third corner // z position of the third corner
case 32: vip[2].z = fast_atof(cursor);break; case 32: vip[2].z = fast_atof(cursor);
bThird = true;break;
// x position of the fourth corner // x position of the fourth corner
case 13: vip[3].x = fast_atof(cursor);break; case 13: vip[3].x = fast_atof(cursor);
bThird = true;break;
// y position of the fourth corner // y position of the fourth corner
case 23: vip[3].y = -fast_atof(cursor);break; case 23: vip[3].y = -fast_atof(cursor);
bThird = true;break;
// z position of the fourth corner // z position of the fourth corner
case 33: vip[3].z = fast_atof(cursor);break; case 33: vip[3].z = fast_atof(cursor);
bThird = true;break;
// color // color
case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break; case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break;
@ -579,6 +593,8 @@ bool DXFImporter::Parse3DFace()
if (ret)break; if (ret)break;
} }
if (!bThird)vip[2] = vip[1];
// use a default layer if necessary // use a default layer if necessary
if (!out)SetDefaultLayer(out); if (!out)SetDefaultLayer(out);
@ -592,3 +608,5 @@ bool DXFImporter::Parse3DFace()
out->vColors.push_back(clr); out->vColors.push_back(clr);
return ret; return ret;
} }

View File

@ -74,7 +74,10 @@ protected:
char name[4096]; char name[4096];
// face buffer - order is x,y,z,w v1,v2,v3 (w is equal to z if unused) // face buffer - order is x,y,z v1,v2,v3,v4
// if v2 = v3: line
// elsif v3 = v2: triangle
// else: polygon
std::vector<aiVector3D> vPositions; std::vector<aiVector3D> vPositions;
std::vector<aiColor4D> vColors; std::vector<aiColor4D> vColors;
}; };

View File

@ -91,7 +91,11 @@ void UpdateMeshReferences(aiNode* node, const std::vector<unsigned int>& meshMap
} }
// just let the members that are unused, that's much cheaper // just let the members that are unused, that's much cheaper
// than a full array realloc'n'copy party ... // than a full array realloc'n'copy party ...
node->mNumMeshes = out; if(!(node->mNumMeshes = out))
{
delete[] node->mMeshes;
node->mMeshes = NULL;
}
} }
// recursively update all children // recursively update all children
for (unsigned int i = 0; i < node->mNumChildren;++i) for (unsigned int i = 0; i < node->mNumChildren;++i)
@ -173,7 +177,8 @@ inline const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsi
} }
if (i && v != arr[i-1])b = true; if (i && v != arr[i-1])b = true;
} }
if (!b)return "All vectors are identical"; if (!b)
return "All vectors are identical";
return NULL; return NULL;
} }

View File

@ -97,11 +97,31 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
{ {
if (NULL != pMesh->mNormals)return false; if (NULL != pMesh->mNormals)return false;
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; // If the mesh consists of lines and/or points but not of
// triangles or higher-order polygons the normal vectors
// are undefined.
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
{
DefaultLogger::get()->info("Normal vectors are undefined for line and point meshes");
return false;
}
// allocate an array to hold the output normals
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
const float qnan = std::numeric_limits<float>::quiet_NaN();
// iterate through all faces and compute per-face normals but store
// them per-vertex.
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
{ {
const aiFace& face = pMesh->mFaces[a]; const aiFace& face = pMesh->mFaces[a];
if (face.mNumIndices < 3)
{
// either a point or a line -> no well-defined normal vector
for (unsigned int i = 0;i < face.mNumIndices;++i)
pMesh->mNormals[face.mIndices[i]] = qnan;
continue;
}
aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];

View File

@ -110,10 +110,30 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
{ {
if (NULL != pMesh->mNormals)return false; if (NULL != pMesh->mNormals)return false;
// If the mesh consists of lines and/or points but not of
// triangles or higher-order polygons the normal vectors
// are undefined.
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
{
DefaultLogger::get()->info("Normal vectors are undefined for line and point meshes");
return false;
}
// allocate an array to hold the output normals
const float qnan = std::numeric_limits<float>::quiet_NaN();
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
// compute per-face normals but store them per-vertex
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
{ {
const aiFace& face = pMesh->mFaces[a]; const aiFace& face = pMesh->mFaces[a];
if (face.mNumIndices < 3)
{
// either a point or a line -> no normal vector
for (unsigned int i = 0;i < face.mNumIndices;++i)
pMesh->mNormals[face.mIndices[i]] = qnan;
continue;
}
aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
@ -167,9 +187,10 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
aiVector3D pcNor; aiVector3D pcNor;
for (unsigned int a = 0; a < verticesFound.size(); ++a) for (unsigned int a = 0; a < verticesFound.size(); ++a)
{ {
register unsigned int vidx = verticesFound[a]; const aiVector3D& v = pMesh->mNormals[verticesFound[a]];
pcNor += pMesh->mNormals[vidx]; if (is_not_qnan(v.x))pcNor += v;
} }
pcNor.Normalize(); pcNor.Normalize();
// write the smoothed normal back to all affected normals // write the smoothed normal back to all affected normals
@ -183,7 +204,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
} }
else else
{ {
const float fLimit = cos(configMaxAngle); const float fLimit = ::cos(configMaxAngle);
for (unsigned int i = 0; i < pMesh->mNumVertices;++i) for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
{ {
// get all vertices that share this one ... // get all vertices that share this one ...
@ -192,16 +213,18 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
aiVector3D pcNor; aiVector3D pcNor;
for (unsigned int a = 0; a < verticesFound.size(); ++a) for (unsigned int a = 0; a < verticesFound.size(); ++a)
{ {
register unsigned int vidx = verticesFound[a]; const aiVector3D& v = pMesh->mNormals[verticesFound[a]];
// check whether the angle between the two normals is not too large // check whether the angle between the two normals is not too large
if (pMesh->mNormals[vidx] * pMesh->mNormals[i] < fLimit) // HACK: if v.x is qnan the dot product will become qnan, too
// therefore the comparison against fLimit should be false
// in every case. Contact me if you disagree with this assumption
if (v * pMesh->mNormals[i] < fLimit)
continue; continue;
pcNor += pMesh->mNormals[vidx]; pcNor += v;
} }
pcNor.Normalize(); pcNew[i] = pcNor.Normalize();
pcNew[i] = pcNor;
} }
} }

View File

@ -176,10 +176,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# include "SortByPTypeProcess.h" # include "SortByPTypeProcess.h"
//#endif //#endif
using namespace Assimp; using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor. // Constructor.
Importer::Importer() : Importer::Importer() :
@ -276,6 +276,9 @@ Importer::Importer() :
mPostProcessingSteps.push_back( new RemoveVCProcess()); mPostProcessingSteps.push_back( new RemoveVCProcess());
#endif #endif
#if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
mPostProcessingSteps.push_back( new PretransformVertices());
#endif
#if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS) #if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
mPostProcessingSteps.push_back( new TriangulateProcess()); mPostProcessingSteps.push_back( new TriangulateProcess());
#endif #endif
@ -294,9 +297,6 @@ Importer::Importer() :
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS) #if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
mPostProcessingSteps.push_back( new OptimizeGraphProcess()); mPostProcessingSteps.push_back( new OptimizeGraphProcess());
#endif #endif
#if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
mPostProcessingSteps.push_back( new PretransformVertices());
#endif
#if (!defined AI_BUILD_NO_FIXINFACINGNORMALS_PROCESS) #if (!defined AI_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
mPostProcessingSteps.push_back( new FixInfacingNormalsProcess()); mPostProcessingSteps.push_back( new FixInfacingNormalsProcess());
#endif #endif
@ -488,105 +488,121 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
// validate the flags // validate the flags
ai_assert(ValidateFlags(pFlags)); ai_assert(ValidateFlags(pFlags));
// check whether this Importer instance has already loaded // put a large try block around everything to catch all std::exception's
// a scene. In this case we need to delete the old one // that might be thrown by STL containers or by new().
if (this->mScene) // ImportErrorException's are throw by ourselves and caught elsewhere.
try
{ {
delete mScene; // check whether this Importer instance has already loaded
this->mScene = NULL; // a scene. In this case we need to delete the old one
} if (this->mScene)
// first check if the file is accessable at all
if( !mIOHandler->Exists( pFile))
{
mErrorString = "Unable to open file \"" + pFile + "\".";
DefaultLogger::get()->error(mErrorString);
return NULL;
}
// find an worker class which can handle the file
BaseImporter* imp = NULL;
for( unsigned int a = 0; a < mImporter.size(); a++)
{
if( mImporter[a]->CanRead( pFile, mIOHandler))
{ {
imp = mImporter[a]; DefaultLogger::get()->debug("The previous scene has been deleted");
break; delete mScene;
this->mScene = NULL;
} }
}
// put a proper error message if no suitable importer was found // first check if the file is accessable at all
if( !imp) if( !mIOHandler->Exists( pFile))
{
mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
DefaultLogger::get()->error(mErrorString);
return NULL;
}
// dispatch the reading to the worker class for this format
imp->SetupProperties( this );
mScene = imp->ReadFile( pFile, mIOHandler);
// if successful, apply all active post processing steps to the imported data
if( mScene)
{
#ifdef _DEBUG
if (bExtraVerbose)
{ {
mErrorString = "Unable to open file \"" + pFile + "\".";
DefaultLogger::get()->error(mErrorString);
return NULL;
}
// find an worker class which can handle the file
BaseImporter* imp = NULL;
for( unsigned int a = 0; a < mImporter.size(); a++)
{
if( mImporter[a]->CanRead( pFile, mIOHandler))
{
imp = mImporter[a];
break;
}
}
// put a proper error message if no suitable importer was found
if( !imp)
{
mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
DefaultLogger::get()->error(mErrorString);
return NULL;
}
// dispatch the reading to the worker class for this format
DefaultLogger::get()->info("Found a matching importer for this file format");
imp->SetupProperties( this );
mScene = imp->ReadFile( pFile, mIOHandler);
// if successful, apply all active post processing steps to the imported data
DefaultLogger::get()->info("Import succesful, entering postprocessing-steps");
if( mScene)
{
#ifdef _DEBUG
if (bExtraVerbose)
{
#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS) #if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS)
DefaultLogger::get()->error("Extra verbose mode not available, library" DefaultLogger::get()->error("Extra verbose mode not available, library"
" wasn't build with the ValidateDS-Step"); " wasn't build with the ValidateDS-Step");
#endif #endif
pFlags |= aiProcess_ValidateDataStructure; pFlags |= aiProcess_ValidateDataStructure;
// use the MSB to tell the ValidateDS-Step that e're in extra verbose mode
// TODO: temporary solution, clean up later
mScene->mFlags |= 0x80000000;
}
#else
if (bExtraVerbose)DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
#endif // ! DEBUG
for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++)
{
BaseProcess* process = mPostProcessingSteps[a];
if( process->IsActive( pFlags))
{
process->SetupProperties( this );
process->ExecuteOnScene ( this );
} }
if( !mScene)break; #else
if (bExtraVerbose)DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
#endif // ! DEBUG
for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++)
{
BaseProcess* process = mPostProcessingSteps[a];
if( process->IsActive( pFlags))
{
process->SetupProperties( this );
process->ExecuteOnScene ( this );
}
if( !mScene)break;
#ifdef _DEBUG #ifdef _DEBUG
#ifndef AI_BUILD_NO_VALIDATEDS_PROCESS #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS
continue; continue;
#endif #endif
// if the extra verbose mode is active execute the // if the extra verbose mode is active execute the
// VaidateDataStructureStep again after each step // VaidateDataStructureStep again after each step
if (bExtraVerbose && a) if (bExtraVerbose && a)
{
DefaultLogger::get()->debug("Extra verbose: revalidating data structures");
((ValidateDSProcess*)mPostProcessingSteps[0])->ExecuteOnScene (this);
if( !mScene)
{ {
DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures"); DefaultLogger::get()->debug("Extra verbose: revalidating data structures");
break; ((ValidateDSProcess*)mPostProcessingSteps[0])->ExecuteOnScene (this);
if( !mScene)
{
DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures");
break;
}
} }
#endif // ! DEBUG
} }
#endif // ! DEBUG
} }
#ifdef _DEBUG // if failed, extract the error string
if (bExtraVerbose)mScene->mFlags &= ~0x80000000; else if( !mScene)mErrorString = imp->GetErrorText();
#endif // ! DEBUG
}
// if failed, extract the error string
else if( !mScene)mErrorString = imp->GetErrorText();
// clear any data allocated by post-process steps // clear any data allocated by post-process steps
mPPShared->Clean(); mPPShared->Clean();
}
catch (std::exception &e)
{
#if (defined _MSC_VER) && (defined _CPPRTTI) && (defined _DEBUG)
// if we have RTTI get the full name of the exception that occured
mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
#else
mErrorString = std::string("std::exception: ") + e.what();
#endif
DefaultLogger::get()->error(mErrorString);
delete mScene;mScene = NULL;
}
// either successful or failure - the pointer expresses it anyways // either successful or failure - the pointer expresses it anyways
return mScene; return mScene;

View File

@ -84,6 +84,12 @@ bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void ImproveCacheLocalityProcess::Execute( aiScene* pScene) void ImproveCacheLocalityProcess::Execute( aiScene* pScene)
{ {
if (!pScene->mNumMeshes)
{
DefaultLogger::get()->debug("ImproveCacheLocalityProcess skipped; there are no meshes");
return;
}
DefaultLogger::get()->debug("ImproveCacheLocalityProcess begin"); DefaultLogger::get()->debug("ImproveCacheLocalityProcess begin");
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
@ -102,7 +108,14 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN
// check whether the input data is valid -> // check whether the input data is valid ->
// - there must be vertices and faces (haha) // - there must be vertices and faces (haha)
// - all faces must be triangulated // - all faces must be triangulated
if (!pMesh->HasFaces() || !pMesh->HasPositions())return; if (!pMesh->HasFaces() || !pMesh->HasPositions())
return;
if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
{
DefaultLogger::get()->error("This algorithm works on triangle meshes only");
return;
}
// find the input ACMR ... // find the input ACMR ...
unsigned int* piFIFOStack = new unsigned int[this->configCacheDepth]; unsigned int* piFIFOStack = new unsigned int[this->configCacheDepth];
@ -116,26 +129,6 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN
const aiFace* const pcEnd = pMesh->mFaces+pMesh->mNumFaces; const aiFace* const pcEnd = pMesh->mFaces+pMesh->mNumFaces;
for (const aiFace* pcFace = pMesh->mFaces;pcFace != pcEnd;++pcFace) for (const aiFace* pcFace = pMesh->mFaces;pcFace != pcEnd;++pcFace)
{ {
if (3 != pcFace->mNumIndices)
{
DefaultLogger::get()->error("Unable to improve cache locality of non-triangulated faces");
delete[] piFIFOStack;
return;
}
// although it has not been tested, I'm quite sure degenerated triangles
// would crash if the algorithm was applied to them
#if (defined _DEBUG)
if (pcFace->mIndices[0] == pcFace->mIndices[1] ||
pcFace->mIndices[2] == pcFace->mIndices[1] ||
pcFace->mIndices[2] == pcFace->mIndices[0])
{
DefaultLogger::get()->error("ImproveCacheLocalityProcess: There may be no degenerated triangles ");
return;
}
#endif
for (unsigned int qq = 0; qq < 3;++qq) for (unsigned int qq = 0; qq < 3;++qq)
{ {
bool bInCache = false; bool bInCache = false;

View File

@ -109,6 +109,8 @@ void JoinVerticesProcess::Execute( aiScene* pScene)
DefaultLogger::get()->info(szBuff); DefaultLogger::get()->info(szBuff);
} }
} }
pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -183,12 +183,12 @@ void MD2Importer::InternReadFile( const std::string& pFile,
if( fileSize < sizeof(MD2::Header)) if( fileSize < sizeof(MD2::Header))
throw new ImportErrorException( "MD2 File is too small"); throw new ImportErrorException( "MD2 File is too small");
std::vector<unsigned char> mBuffer2(fileSize); std::vector<uint8_t> mBuffer2(fileSize);
file->Read(&mBuffer2[0], 1, fileSize); file->Read(&mBuffer2[0], 1, fileSize);
mBuffer = &mBuffer2[0]; mBuffer = &mBuffer2[0];
m_pcHeader = (const MD2::Header*)mBuffer; m_pcHeader = (BE_NCONST MD2::Header*)mBuffer;
#ifdef AI_BUILD_BIG_ENDIAN #ifdef AI_BUILD_BIG_ENDIAN
@ -229,7 +229,7 @@ void MD2Importer::InternReadFile( const std::string& pFile,
pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
// navigate to the begin of the frame data // navigate to the begin of the frame data
const MD2::Frame* pcFrame = (const MD2::Frame*) ((uint8_t*) BE_NCONST MD2::Frame* pcFrame = (BE_NCONST MD2::Frame*) ((uint8_t*)
m_pcHeader + m_pcHeader->offsetFrames); m_pcHeader + m_pcHeader->offsetFrames);
pcFrame += configFrameID; pcFrame += configFrameID;
@ -239,11 +239,11 @@ void MD2Importer::InternReadFile( const std::string& pFile,
m_pcHeader + m_pcHeader->offsetTriangles); m_pcHeader + m_pcHeader->offsetTriangles);
// navigate to the begin of the tex coords data // navigate to the begin of the tex coords data
const MD2::TexCoord* pcTexCoords = (const MD2::TexCoord*) ((uint8_t*) BE_NCONST MD2::TexCoord* pcTexCoords = (BE_NCONST MD2::TexCoord*) ((uint8_t*)
m_pcHeader + m_pcHeader->offsetTexCoords); m_pcHeader + m_pcHeader->offsetTexCoords);
// navigate to the begin of the vertex data // navigate to the begin of the vertex data
const MD2::Vertex* pcVerts = (const MD2::Vertex*) (pcFrame->vertices); BE_NCONST MD2::Vertex* pcVerts = (BE_NCONST MD2::Vertex*) (pcFrame->vertices);
#ifdef AI_BUILD_BIG_ENDIAN #ifdef AI_BUILD_BIG_ENDIAN
for (uint32_t i = 0; i< m_pcHeader->numTriangles) for (uint32_t i = 0; i< m_pcHeader->numTriangles)
@ -410,14 +410,11 @@ void MD2Importer::InternReadFile( const std::string& pFile,
} }
aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent]; aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent];
float u,v;
// 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
u = pcTexCoords[iIndex].s / fDivisorU; pcOut.x = pcTexCoords[iIndex].s / fDivisorU;
v = pcTexCoords[iIndex].t / fDivisorV; pcOut.y = 1.f- pcTexCoords[iIndex].t / fDivisorV;
pcOut.x = u;
pcOut.y = 1.0f - v; // FIXME: Is this correct for MD2?
} }
} }
// FIX: flip the face order for use with OpenGL // FIX: flip the face order for use with OpenGL

View File

@ -113,10 +113,10 @@ protected:
unsigned int configFrameID; unsigned int configFrameID;
/** Header of the MD2 file */ /** Header of the MD2 file */
const MD2::Header* m_pcHeader; BE_NCONST MD2::Header* m_pcHeader;
/** Buffer to hold the loaded file */ /** Buffer to hold the loaded file */
const unsigned char* mBuffer; BE_NCONST uint8_t* mBuffer;
/** Size of the file, in bytes */ /** Size of the file, in bytes */
unsigned int fileSize; unsigned int fileSize;

View File

@ -107,7 +107,7 @@ void MD5Importer::InternReadFile(
if (!bHadMD5Mesh && !bHadMD5Anim) if (!bHadMD5Mesh && !bHadMD5Anim)
throw new ImportErrorException("Failed to read valid data from this MD5"); throw new ImportErrorException("Failed to read valid data from this MD5");
if (!bHadMD5Mesh)pScene->mFlags |= AI_SCENE_FLAGS_ANIM_SKELETON_ONLY; if (!bHadMD5Mesh)pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MD5Importer::LoadFileIntoMemory (IOStream* file) void MD5Importer::LoadFileIntoMemory (IOStream* file)

View File

@ -242,16 +242,16 @@ MaterialHelper::MaterialHelper()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
MaterialHelper::~MaterialHelper() MaterialHelper::~MaterialHelper()
{ {
for (unsigned int i = 0; i < this->mNumProperties;++i) Clear();
}
// ------------------------------------------------------------------------------------------------
void MaterialHelper::Clear()
{
for (unsigned int i = 0; i < mNumProperties;++i)
{ {
// be careful ... // delete this entry
if(NULL != this->mProperties[i]) delete mProperties[i];
{
delete[] this->mProperties[i]->mData;
delete this->mProperties[i];
}
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
uint32_t MaterialHelper::ComputeHash() uint32_t MaterialHelper::ComputeHash()
@ -282,7 +282,6 @@ aiReturn MaterialHelper::RemoveProperty (const char* pKey)
if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey )) if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey ))
{ {
// delete this entry // delete this entry
delete[] this->mProperties[i]->mData;
delete this->mProperties[i]; delete this->mProperties[i];
// collapse the array behind --. // collapse the array behind --.
@ -318,7 +317,6 @@ aiReturn MaterialHelper::AddBinaryProperty (const void* pInput,
if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey )) if (0 == ASSIMP_stricmp( this->mProperties[i]->mKey.data, pKey ))
{ {
// delete this entry // delete this entry
delete[] this->mProperties[i]->mData;
delete this->mProperties[i]; delete this->mProperties[i];
iOutIndex = i; iOutIndex = i;
} }
@ -402,8 +400,7 @@ void MaterialHelper::CopyPropertyList(MaterialHelper* pcDest,
for (unsigned int q = 0; q < iOldNum;++q) for (unsigned int q = 0; q < iOldNum;++q)
{ {
prop = pcDest->mProperties[q]; prop = pcDest->mProperties[q];
if (propSrc->mKey.length == prop->mKey.length && if (!ASSIMP_stricmp(propSrc->mKey.data,prop->mKey.data))
!ASSIMP_stricmp(propSrc->mKey.data,prop->mKey.data))
{ {
delete prop; delete prop;

View File

@ -105,6 +105,12 @@ public:
aiReturn RemoveProperty (const char* pKey); aiReturn RemoveProperty (const char* pKey);
// -------------------------------------------------------------------
/** Removes all properties from the material
*/
void Clear();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Computes a hash (hopefully unique) from all material properties /** Computes a hash (hopefully unique) from all material properties
* The hash value must be updated after material properties have * The hash value must be updated after material properties have

View File

@ -74,10 +74,19 @@ bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
if( pos == std::string::npos)return false; if( pos == std::string::npos)return false;
std::string extension = pFile.substr( pos); std::string extension = pFile.substr( pos);
return !(extension.length() != 4 || extension[0] != '.' || // extensions: enff and nff
extension[1] != 'n' && extension[1] != 'N' || if (!extension.length() || extension[0] != '.')return false;
extension[2] != 'f' && extension[2] != 'F' || if (extension.length() == 4)
extension[3] != 'f' && extension[3] != 'F'); {
return !(extension[1] != 'n' && extension[1] != 'N' ||
extension[2] != 'f' && extension[2] != 'F' ||
extension[3] != 'f' && extension[3] != 'F');
}
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');
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -87,9 +96,9 @@ bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_TRIPLE(v) \ #define AI_NFF_PARSE_TRIPLE(v) \
AI_NFF_PARSE_FLOAT(v.x) \ AI_NFF_PARSE_FLOAT(v[0]) \
AI_NFF_PARSE_FLOAT(v.y) \ AI_NFF_PARSE_FLOAT(v[1]) \
AI_NFF_PARSE_FLOAT(v.z) AI_NFF_PARSE_FLOAT(v[2])
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_SHAPE_INFORMATION() \ #define AI_NFF_PARSE_SHAPE_INFORMATION() \
@ -125,252 +134,504 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// the pointers below easier. // the pointers below easier.
std::vector<MeshInfo> meshes; std::vector<MeshInfo> meshes;
std::vector<MeshInfo> meshesWithNormals; std::vector<MeshInfo> meshesWithNormals;
std::vector<MeshInfo> meshesWithUVCoords;
std::vector<MeshInfo> meshesLocked; std::vector<MeshInfo> meshesLocked;
char line[4096];
const char* sz;
// camera parameters
aiVector3D camPos, camUp(0.f,1.f,0.f), camLookAt(0.f,0.f,1.f);
float angle;
aiVector2D resolution;
bool hasCam = false;
MeshInfo* currentMeshWithNormals = NULL; MeshInfo* currentMeshWithNormals = NULL;
MeshInfo* currentMesh = NULL; MeshInfo* currentMesh = NULL;
MeshInfo* currentMeshWithUVCoords = NULL;
ShadingInfo s; // current material info ShadingInfo s; // current material info
// degree of tesselation // degree of tesselation
unsigned int iTesselation = 4; unsigned int iTesselation = 4;
char line[4096]; // some temporary variables we need to parse the file
const char* sz; unsigned int sphere = 0,
unsigned int sphere = 0,cylinder = 0,cone = 0,numNamed = 0, cylinder = 0,
dodecahedron = 0,octahedron = 0,tetrahedron = 0, hexahedron = 0; cone = 0,
numNamed = 0,
dodecahedron = 0,
octahedron = 0,
tetrahedron = 0,
hexahedron = 0;
while (GetNextLine(buffer,line)) // lights imported from the file
std::vector<Light> lights;
// check whether this is the NFF2 file format
if (TokenMatch(buffer,"nff",3))
{ {
if ('p' == line[0]) // 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
// http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/nff/nff2.html
while (GetNextLine(buffer,line))
{ {
MeshInfo* out = NULL; sz = line;
// 'pp' - polygon patch primitive if (TokenMatch(sz,"version",7))
if ('p' == line[1])
{ {
if (meshesWithNormals.empty()) DefaultLogger::get()->info("NFF (alt.) file format: " + std::string(sz));
{
meshesWithNormals.push_back(MeshInfo(true));
currentMeshWithNormals = &meshesWithNormals.back();
}
sz = &line[2];out = currentMeshWithNormals;
} }
// 'p' - polygon primitive else if (TokenMatch(sz,"viewpos",7))
else
{ {
if (meshes.empty()) AI_NFF_PARSE_TRIPLE(camPos);
{ hasCam = true;
meshes.push_back(MeshInfo(false));
currentMesh = &meshes.back();
}
sz = &line[1];out = currentMesh;
} }
SkipSpaces(sz,&sz); else if (TokenMatch(sz,"viewdir",7))
m = strtol10(sz);
// ---- flip the face order
out->vertices.resize(out->vertices.size()+m);
if (out == currentMeshWithNormals)
{ {
out->normals.resize(out->vertices.size()); AI_NFF_PARSE_TRIPLE(camLookAt);
hasCam = true;
} }
for (unsigned int n = 0; n < m;++n) else if (TokenMatch(sz,"//",2))
{ {
if(!GetNextLine(buffer,line)) // comment ...
{ DefaultLogger::get()->info(sz);
DefaultLogger::get()->error("NFF: Unexpected EOF was encountered"); }
continue; else if (!IsSpace(*sz))
} {
// must be a new object
meshes.push_back(MeshInfo(PatchType_Simple));
MeshInfo& mesh = meshes.back();
aiVector3D v; sz = &line[0]; if (!GetNextLine(buffer,line))
AI_NFF_PARSE_TRIPLE(v); {DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read number of vertices");break;}
out->vertices[out->vertices.size()-n-1] = v;
if (out == currentMeshWithNormals) SkipSpaces(line,&sz);
unsigned int num = ::strtol10(sz,&sz);
std::vector<aiVector3D> tempPositions;
std::vector<aiVector3D> outPositions;
mesh.vertices.reserve(num*3);
mesh.colors.reserve (num*3);
tempPositions.reserve(num);
for (unsigned int i = 0; i < num; ++i)
{ {
if (!GetNextLine(buffer,line))
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read vertices");break;}
sz = line;
aiVector3D v;
AI_NFF_PARSE_TRIPLE(v); AI_NFF_PARSE_TRIPLE(v);
out->normals[out->vertices.size()-n-1] = v; tempPositions.push_back(v);
} }
} if (!GetNextLine(buffer,line))
out->faces.push_back(m); {DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read number of faces");break;}
}
// 'f' - shading information block
else if ('f' == line[0] && IsSpace(line[1]))
{
SkipSpaces(&line[1],&sz);
// read just the RGB colors, the rest is ignored for the moment if (!num)throw new ImportErrorException("NFF2: There are zero vertices");
sz = fast_atof_move(sz, (float&)s.color.r);
SkipSpaces(&sz);
sz = fast_atof_move(sz, (float&)s.color.g);
SkipSpaces(&sz);
sz = fast_atof_move(sz, (float&)s.color.b);
// check whether we have this material already - SkipSpaces(line,&sz);
// although we have the RRM-Step, this is necessary here. num = ::strtol10(sz,&sz);
// otherwise we would generate hundreds of small meshes mesh.faces.reserve(num);
// with just a few faces - this is surely never wanted.
currentMesh = currentMeshWithNormals = NULL; for (unsigned int i = 0; i < num; ++i)
for (std::vector<MeshInfo>::iterator it = meshes.begin(), end = meshes.end();
it != end;++it)
{
if ((*it).bLocked)continue;
if ((*it).shader == s)
{ {
if ((*it).bHasNormals)currentMeshWithNormals = &(*it); if (!GetNextLine(buffer,line))
else currentMesh = &(*it); {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);
for (unsigned int a = 0; a < numIdx;++a)
{
SkipSpaces(sz,&sz);
idx = ::strtol10(sz,&sz);
if (idx >= (unsigned int)tempPositions.size())
{
DefaultLogger::get()->error("NFF2: Index overflow");
idx = 0;
}
mesh.vertices.push_back(tempPositions[idx]);
}
}
SkipSpaces(sz,&sz);
idx = ::strtol_cppstyle(sz,&sz);
aiColor4D clr;
clr.r = ((numIdx >> 8u) & 0xf) / 16.f;
clr.g = ((numIdx >> 4u) & 0xf) / 16.f;
clr.b = ((numIdx) & 0xf) / 16.f;
clr.a = 1.f;
for (unsigned int a = 0; a < numIdx;++a)
mesh.colors.push_back(clr);
}
if (!num)throw new ImportErrorException("NFF2: There are zero faces");
}
}
camLookAt = camLookAt + camPos;
}
else // "Normal" Neutral file format that is quite more common
{
while (GetNextLine(buffer,line))
{
sz = line;
if ('p' == line[0] || TokenMatch(sz,"tpp",3))
{
MeshInfo* out = NULL;
// 'tpp' - texture polygon patch primitive
if ('t' == line[0])
{
if (meshesWithUVCoords.empty())
{
meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals));
currentMeshWithUVCoords = &meshesWithUVCoords.back();
}
out = currentMeshWithUVCoords;
}
// 'pp' - polygon patch primitive
else if ('p' == line[1])
{
if (meshesWithNormals.empty())
{
meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
currentMeshWithNormals = &meshesWithNormals.back();
}
sz = &line[2];out = currentMeshWithNormals;
}
// 'p' - polygon primitive
else
{
if (meshes.empty())
{
meshes.push_back(MeshInfo(PatchType_Simple));
currentMesh = &meshes.back();
}
sz = &line[1];out = currentMesh;
}
SkipSpaces(sz,&sz);
m = strtol10(sz);
// ---- flip the face order
out->vertices.resize(out->vertices.size()+m);
if (out != currentMesh)
{
out->normals.resize(out->vertices.size());
}
if (out == currentMeshWithUVCoords)
{
out->uvs.resize(out->vertices.size());
}
for (unsigned int n = 0; n < m;++n)
{
if(!GetNextLine(buffer,line))
{
DefaultLogger::get()->error("NFF: Unexpected EOF was encountered");
continue;
}
aiVector3D v; sz = &line[0];
AI_NFF_PARSE_TRIPLE(v);
out->vertices[out->vertices.size()-n-1] = v;
if (out != currentMesh)
{
AI_NFF_PARSE_TRIPLE(v);
out->normals[out->vertices.size()-n-1] = v;
}
if (out == currentMeshWithUVCoords)
{
// FIX: in one test file this wraps over multiple lines
SkipSpaces(&sz);
if (IsLineEnd(*sz))
{
GetNextLine(buffer,line);
sz = line;
}
AI_NFF_PARSE_FLOAT(v.x);
SkipSpaces(&sz);
if (IsLineEnd(*sz))
{
GetNextLine(buffer,line);
sz = line;
}
AI_NFF_PARSE_FLOAT(v.y);
v.y = 1.f - v.y;
out->uvs[out->vertices.size()-n-1] = v;
}
}
out->faces.push_back(m);
}
// 'f' - shading information block
else if (TokenMatch(sz,"f",1))
{
float d;
// read the RGB colors
AI_NFF_PARSE_TRIPLE(s.color);
// read the other properties
AI_NFF_PARSE_FLOAT(s.diffuse);
AI_NFF_PARSE_FLOAT(s.specular);
AI_NFF_PARSE_FLOAT(d); // skip shininess and transmittance
AI_NFF_PARSE_FLOAT(d);
AI_NFF_PARSE_FLOAT(s.refracti);
// 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
// been implemented as it can be really useful
SkipSpaces(&sz);
if (!IsNumeric(*sz))
{
// TODO: Support full file names with spaces and quotation marks ...
const char* p = sz;
while (!IsSpaceOrNewLine( *sz ))++sz;
unsigned int diff = (unsigned int)(sz-p);
if (diff)
{
s.texFile = std::string(p,diff);
}
}
else
{
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;
} }
} }
// 'l' - light source
if (!currentMesh) else if (TokenMatch(sz,"l",1))
{ {
meshes.push_back(MeshInfo(false)); lights.push_back(Light());
currentMesh = &meshes.back(); Light& light = lights.back();
currentMesh->shader = s;
AI_NFF_PARSE_TRIPLE(light.position);
AI_NFF_PARSE_FLOAT (light.intensity);
AI_NFF_PARSE_TRIPLE(light.color);
}
// 's' - sphere
else if (TokenMatch(sz,"s",1))
{
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
AI_NFF_PARSE_SHAPE_INFORMATION();
// we don't need scaling or translation here - we do it in the node's transform
StandardShapes::MakeSphere(iTesselation, currentMesh.vertices);
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
// generate a name for the mesh
::sprintf(currentMesh.name,"sphere_%i",sphere++);
}
// 'dod' - dodecahedron
else if (TokenMatch(sz,"dod",3))
{
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
AI_NFF_PARSE_SHAPE_INFORMATION();
// we don't need scaling or translation here - we do it in the node's transform
StandardShapes::MakeDodecahedron(currentMesh.vertices);
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
// generate a name for the mesh
::sprintf(currentMesh.name,"dodecahedron_%i",dodecahedron++);
} }
if (!currentMeshWithNormals) // 'oct' - octahedron
else if (TokenMatch(sz,"oct",3))
{ {
meshesWithNormals.push_back(MeshInfo(true)); meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
currentMeshWithNormals = &meshesWithNormals.back(); MeshInfo& currentMesh = meshesLocked.back();
currentMeshWithNormals->shader = s; currentMesh.shader = s;
AI_NFF_PARSE_SHAPE_INFORMATION();
// we don't need scaling or translation here - we do it in the node's transform
StandardShapes::MakeOctahedron(currentMesh.vertices);
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
// generate a name for the mesh
::sprintf(currentMesh.name,"octahedron_%i",octahedron++);
} }
}
// 's' - sphere
else if ('s' == line[0] && IsSpace(line[1]))
{
meshesLocked.push_back(MeshInfo(false,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[1]; // 'tet' - tetrahedron
AI_NFF_PARSE_SHAPE_INFORMATION(); else if (TokenMatch(sz,"tet",3))
{
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
// we don't need scaling or translation here - we do it in the node's transform AI_NFF_PARSE_SHAPE_INFORMATION();
StandardShapes::MakeSphere(iTesselation, currentMesh.vertices);
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
// generate a name for the mesh // we don't need scaling or translation here - we do it in the node's transform
::sprintf(currentMesh.name,"sphere_%i",sphere++); StandardShapes::MakeTetrahedron(currentMesh.vertices);
} currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
// 'dod' - dodecahedron
else if (!strncmp(line,"dod",3) && IsSpace(line[3]))
{
meshesLocked.push_back(MeshInfo(false,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[4]; // generate a name for the mesh
AI_NFF_PARSE_SHAPE_INFORMATION(); ::sprintf(currentMesh.name,"tetrahedron_%i",tetrahedron++);
}
// we don't need scaling or translation here - we do it in the node's transform // 'hex' - hexahedron
StandardShapes::MakeDodecahedron(currentMesh.vertices); else if (TokenMatch(sz,"hex",3))
currentMesh.faces.resize(currentMesh.vertices.size()/3,3); {
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
// generate a name for the mesh AI_NFF_PARSE_SHAPE_INFORMATION();
::sprintf(currentMesh.name,"dodecahedron_%i",dodecahedron++);
}
// 'oct' - octahedron // we don't need scaling or translation here - we do it in the node's transform
else if (!strncmp(line,"oct",3) && IsSpace(line[3])) StandardShapes::MakeHexahedron(currentMesh.vertices);
{ currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
meshesLocked.push_back(MeshInfo(false,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[4]; // generate a name for the mesh
AI_NFF_PARSE_SHAPE_INFORMATION(); ::sprintf(currentMesh.name,"hexahedron_%i",hexahedron++);
}
// 'c' - cone
else if (TokenMatch(sz,"c",1))
{
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshes.back();
currentMesh.shader = s;
// we don't need scaling or translation here - we do it in the node's transform aiVector3D center1, center2; float radius1, radius2;
StandardShapes::MakeOctahedron(currentMesh.vertices); AI_NFF_PARSE_TRIPLE(center1);
currentMesh.faces.resize(currentMesh.vertices.size()/3,3); AI_NFF_PARSE_FLOAT(radius1);
AI_NFF_PARSE_TRIPLE(center2);
AI_NFF_PARSE_FLOAT(radius2);
// generate a name for the mesh // compute the center point of the cone/cylinder
::sprintf(currentMesh.name,"octahedron_%i",octahedron++); center2 = (center2-center1)/2.f;
} currentMesh.center = center1+center2;
center1 = -center2;
// 'tet' - tetrahedron // generate the cone - it consists of simple triangles
else if (!strncmp(line,"tet",3) && IsSpace(line[3])) StandardShapes::MakeCone(center1, radius1, center2, radius2, iTesselation, currentMesh.vertices);
{ currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
meshesLocked.push_back(MeshInfo(false,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[4]; // generate a name for the mesh
AI_NFF_PARSE_SHAPE_INFORMATION(); if (radius1 != radius2)
::sprintf(currentMesh.name,"cone_%i",cone++);
// we don't need scaling or translation here - we do it in the node's transform else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
StandardShapes::MakeTetrahedron(currentMesh.vertices); }
currentMesh.faces.resize(currentMesh.vertices.size()/3,3); // 'tess' - tesselation
else if (TokenMatch(sz,"tess",4))
// generate a name for the mesh {
::sprintf(currentMesh.name,"tetrahedron_%i",tetrahedron++); SkipSpaces(&sz);
} iTesselation = strtol10(sz);
}
// 'hex' - hexahedron // 'from' - camera position
else if (!strncmp(line,"hex",3) && IsSpace(line[3])) else if (TokenMatch(sz,"from",4))
{ {
meshesLocked.push_back(MeshInfo(false,true)); AI_NFF_PARSE_TRIPLE(camPos);
MeshInfo& currentMesh = meshesLocked.back(); hasCam = true;
currentMesh.shader = s; }
// 'at' - camera look-at vector
sz = &line[4]; else if (TokenMatch(sz,"at",2))
AI_NFF_PARSE_SHAPE_INFORMATION(); {
AI_NFF_PARSE_TRIPLE(camLookAt);
// we don't need scaling or translation here - we do it in the node's transform hasCam = true;
StandardShapes::MakeHexahedron(currentMesh.vertices); }
currentMesh.faces.resize(currentMesh.vertices.size()/3,3); // 'up' - camera up vector
else if (TokenMatch(sz,"up",2))
// generate a name for the mesh {
::sprintf(currentMesh.name,"hexahedron_%i",hexahedron++); AI_NFF_PARSE_TRIPLE(camUp);
} hasCam = true;
}
// 'tess' - tesselation // 'angle' - (half?) camera field of view
else if (!strncmp(line,"tess",4) && IsSpace(line[4])) else if (TokenMatch(sz,"angle",5))
{ {
sz = &line[5];SkipSpaces(&sz); AI_NFF_PARSE_FLOAT(angle);
iTesselation = strtol10(sz); hasCam = true;
} }
// 'c' - cone // 'resolution' - used to compute the screen aspect
else if ('c' == line[0] && IsSpace(line[1])) else if (TokenMatch(sz,"resolution",10))
{ {
meshesLocked.push_back(MeshInfo(false,true)); AI_NFF_PARSE_FLOAT(resolution.x);
MeshInfo& currentMesh = meshes.back(); AI_NFF_PARSE_FLOAT(resolution.y);
currentMesh.shader = s; hasCam = true;
}
sz = &line[1]; // 'pb' - bezier patch. Not supported yet
aiVector3D center1, center2; float radius1, radius2; else if (TokenMatch(sz,"pb",2))
AI_NFF_PARSE_TRIPLE(center1); {
AI_NFF_PARSE_FLOAT(radius1); DefaultLogger::get()->error("NFF: Encountered unsupported ID: bezier patch");
AI_NFF_PARSE_TRIPLE(center2); }
AI_NFF_PARSE_FLOAT(radius2); // 'pn' - NURBS. Not supported yet
else if (TokenMatch(sz,"pn",2) || TokenMatch(sz,"pnn",3))
// compute the center point of the cone/cylinder {
center2 = (center2-center1)/2.f; DefaultLogger::get()->error("NFF: Encountered unsupported ID: NURBS");
currentMesh.center = center1+center2; }
center1 = -center2; // '' - comment
else if ('#' == line[0])
// generate the cone - it consists of simple triangles {
StandardShapes::MakeCone(center1, radius1, center2, radius2, iTesselation, currentMesh.vertices); const char* sz;SkipSpaces(&line[1],&sz);
currentMesh.faces.resize(currentMesh.vertices.size()/3,3); if (!IsLineEnd(*sz))DefaultLogger::get()->info(sz);
}
// generate a name for the mesh
if (radius1 != radius2)
::sprintf(currentMesh.name,"cone_%i",cone++);
else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
}
// '#' - comment
else if ('#' == line[0])
{
const char* sz;SkipSpaces(&line[1],&sz);
if (!IsLineEnd(*sz))DefaultLogger::get()->info(sz);
} }
} }
// copy all arrays into one large // copy all arrays into one large
meshes.reserve(meshes.size()+meshesLocked.size()+meshesWithNormals.size()); meshes.reserve (meshes.size()+meshesLocked.size()+meshesWithNormals.size()+meshesWithUVCoords.size());
meshes.insert(meshes.end(),meshesLocked.begin(),meshesLocked.end()); meshes.insert (meshes.end(),meshesLocked.begin(),meshesLocked.end());
meshes.insert(meshes.end(),meshesWithNormals.begin(),meshesWithNormals.end()); meshes.insert (meshes.end(),meshesWithNormals.begin(),meshesWithNormals.end());
meshes.insert (meshes.end(),meshesWithUVCoords.begin(),meshesWithUVCoords.end());
// now generate output meshes. first find out how many meshes we'll need // now generate output meshes. first find out how many meshes we'll need
std::vector<MeshInfo>::const_iterator it = meshes.begin(), end = meshes.end(); std::vector<MeshInfo>::const_iterator it = meshes.begin(), end = meshes.end();
@ -388,7 +649,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// sub nodes for named objects such as spheres and cones. // sub nodes for named objects such as spheres and cones.
aiNode* const root = new aiNode(); aiNode* const root = new aiNode();
root->mName.Set("<NFF_Root>"); root->mName.Set("<NFF_Root>");
root->mNumChildren = numNamed; root->mNumChildren = numNamed + (hasCam ? 1 : 0) + (unsigned int) lights.size();
root->mNumMeshes = pScene->mNumMeshes-numNamed; root->mNumMeshes = pScene->mNumMeshes-numNamed;
aiNode** ppcChildren; aiNode** ppcChildren;
@ -398,6 +659,49 @@ void NFFImporter::InternReadFile( const std::string& pFile,
if (root->mNumChildren) if (root->mNumChildren)
ppcChildren = root->mChildren = new aiNode*[root->mNumChildren]; ppcChildren = root->mChildren = new aiNode*[root->mNumChildren];
// generate the camera
if (hasCam)
{
aiNode* nd = *ppcChildren = new aiNode();
nd->mName.Set("<NFF_Camera>");
nd->mParent = root;
// allocate the camera in the scene
pScene->mNumCameras = 1;
pScene->mCameras = new aiCamera*[1];
aiCamera* c = pScene->mCameras[0] = new aiCamera;
c->mName = nd->mName; // make sure the names are identical
c->mHorizontalFOV = AI_DEG_TO_RAD( angle );
c->mLookAt = camLookAt - camPos;
c->mPosition = camPos;
c->mUp = camUp;
c->mAspect = resolution.x / resolution.y;
++ppcChildren;
}
// generate light sources
if (!lights.empty())
{
pScene->mNumLights = (unsigned int)lights.size();
pScene->mLights = new aiLight*[pScene->mNumLights];
for (unsigned int i = 0; i < pScene->mNumLights;++i,++ppcChildren)
{
const Light& l = lights[i];
aiNode* nd = *ppcChildren = new aiNode();
nd->mParent = root;
nd->mName.length = ::sprintf(nd->mName.data,"<NFF_Light%i>",i);
// allocate the light in the scene data structure
aiLight* out = pScene->mLights[i] = new aiLight();
out->mName = nd->mName; // make sure the names are identical
out->mType = aiLightSource_POINT;
out->mColorDiffuse = out->mColorSpecular = l.color * l.intensity;
out->mPosition = l.position;
}
}
if (!pScene->mNumMeshes)throw new ImportErrorException("NFF: No meshes loaded"); if (!pScene->mNumMeshes)throw new ImportErrorException("NFF: No meshes loaded");
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
@ -436,14 +740,38 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// copy vertex positions // copy vertex positions
mesh->mVertices = new aiVector3D[mesh->mNumVertices]; mesh->mVertices = new aiVector3D[mesh->mNumVertices];
::memcpy(mesh->mVertices,&src.vertices[0],sizeof(aiVector3D)*mesh->mNumVertices); ::memcpy(mesh->mVertices,&src.vertices[0],
if (src.bHasNormals) sizeof(aiVector3D)*mesh->mNumVertices);
// NFF2: there could be vertex colors
if (!src.colors.empty())
{
ai_assert(src.colors.size() == src.vertices.size());
// copy vertex colors
mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
::memcpy(mesh->mColors[0],&src.colors[0],
sizeof(aiColor4D)*mesh->mNumVertices);
}
if (src.pType != PatchType_Simple)
{ {
ai_assert(src.normals.size() == src.vertices.size()); ai_assert(src.normals.size() == src.vertices.size());
// copy normal vectors // copy normal vectors
mesh->mNormals = new aiVector3D[mesh->mNumVertices]; mesh->mNormals = new aiVector3D[mesh->mNumVertices];
::memcpy(mesh->mNormals,&src.normals[0],sizeof(aiVector3D)*mesh->mNumVertices); ::memcpy(mesh->mNormals,&src.normals[0],
sizeof(aiVector3D)*mesh->mNumVertices);
}
if (src.pType == PatchType_UVAndNormals)
{
ai_assert(src.uvs.size() == src.vertices.size());
// copy texture coordinates
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
::memcpy(mesh->mTextureCoords[0],&src.uvs[0],
sizeof(aiVector3D)*mesh->mNumVertices);
} }
// generate faces // generate faces
@ -459,8 +787,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
} }
// generate a material for the mesh // generate a material for the mesh
MaterialHelper* pcMat = (MaterialHelper*)(pScene-> MaterialHelper* pcMat = (MaterialHelper*)(pScene->mMaterials[m] = new MaterialHelper());
mMaterials[m] = new MaterialHelper());
mesh->mMaterialIndex = m++; mesh->mMaterialIndex = m++;
@ -468,8 +795,16 @@ 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);
pcMat->AddProperty(&src.shader.color,1,AI_MATKEY_COLOR_DIFFUSE); aiColor3D c = src.shader.color * src.shader.diffuse;
pcMat->AddProperty(&src.shader.color,1,AI_MATKEY_COLOR_SPECULAR); pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);
c = src.shader.color * src.shader.specular;
pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR);
if (src.shader.texFile.length())
{
s.Set(src.shader.texFile);
pcMat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
}
} }
pScene->mRootNode = root; pScene->mRootNode = root;
} }

View File

@ -78,7 +78,7 @@ protected:
*/ */
void GetExtensionList(std::string& append) void GetExtensionList(std::string& append)
{ {
append.append("*.nff"); append.append("*.nff;*.enff");
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -95,35 +95,71 @@ private:
struct ShadingInfo struct ShadingInfo
{ {
ShadingInfo() ShadingInfo()
: color(0.6f,0.6f,0.6f,1.0f) : color(0.6f,0.6f,0.6f)
, diffuse (1.f)
, specular (1.f)
, ambient (0.1f)
, refracti (1.f)
{} {}
aiColor4D color; aiColor3D color;
//float diffuse, specular; --- not implemented yet float diffuse, specular, ambient, refracti;
std::string texFile;
// shininess is ignored for the moment
bool operator == (const ShadingInfo& other) const bool operator == (const ShadingInfo& other) const
{return color == other.color;} {
return color == other.color &&
diffuse == other.diffuse &&
specular == other.specular &&
ambient == other.ambient &&
refracti == other.refracti &&
texFile == other.texFile;
}
};
// describes a NFF light source
struct Light
{
Light()
: color (1.f,1.f,1.f)
, intensity (1.f)
{}
aiVector3D position;
float intensity;
aiColor3D color;
};
enum PatchType
{
PatchType_Simple = 0x0,
PatchType_Normals = 0x1,
PatchType_UVAndNormals = 0x2
}; };
// describes a NFF mesh // describes a NFF mesh
struct MeshInfo struct MeshInfo
{ {
MeshInfo(bool bHN, bool bL = false) MeshInfo(PatchType _pType, bool bL = false)
: bHasNormals(bHN) : pType(_pType)
, bLocked(bL) , bLocked(bL)
{ {
name[0] = '\0'; // by default meshes are unnamed name[0] = '\0'; // by default meshes are unnamed
} }
ShadingInfo shader; ShadingInfo shader;
bool bHasNormals, bLocked; PatchType pType;
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;
char name[128]; char name[128];
std::vector<aiVector3D> vertices, normals; std::vector<aiVector3D> vertices, normals, uvs;
std::vector<aiColor4D> colors; // for NFF2
std::vector<unsigned int> faces; std::vector<unsigned int> faces;
}; };
}; };

View File

@ -109,8 +109,6 @@ void OFFImporter::InternReadFile( const std::string& pFile,
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = 1 ]; pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = 1 ];
aiMesh* mesh = pScene->mMeshes[0] = new aiMesh(); aiMesh* mesh = pScene->mMeshes[0] = new aiMesh();
mesh->mNumVertices = numFaces*3;
aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
aiFace* faces = mesh->mFaces = new aiFace [mesh->mNumFaces = numFaces]; aiFace* faces = mesh->mFaces = new aiFace [mesh->mNumFaces = numFaces];
std::vector<aiVector3D> tempPositions(numVertices); std::vector<aiVector3D> tempPositions(numVertices);
@ -131,21 +129,43 @@ void OFFImporter::InternReadFile( const std::string& pFile,
fast_atof_move(sz,(float&)v.z); fast_atof_move(sz,(float&)v.z);
} }
// now read all faces lines
for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;++i) // First find out how many vertices we'll need
const char* old = buffer;
for (unsigned int i = 0; i< mesh->mNumFaces;++i)
{ {
if(!GetNextLine(buffer,line)) if(!GetNextLine(buffer,line))
{ {
DefaultLogger::get()->error("OFF: The number of faces in the header is incorrect"); DefaultLogger::get()->error("OFF: The number of faces in the header is incorrect");
break; break;
} }
unsigned int idx;sz = line;SkipSpaces(&sz); sz = line;SkipSpaces(&sz);
if(!(faces->mNumIndices = strtol10(sz,&sz)) || faces->mNumIndices > 100) if(!(faces->mNumIndices = strtol10(sz,&sz)) || faces->mNumIndices > 9)
{ {
DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed"); DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed");
--mesh->mNumFaces; --mesh->mNumFaces;
continue; continue;
} }
mesh->mNumVertices += faces->mNumIndices;
++faces;
}
if (!mesh->mNumVertices)
throw new ImportErrorException("OFF: There are no valid faces");
// allocate storage for the output vertices
aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
// second: now parse all face indices
buffer = old;faces = mesh->mFaces;
for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;)
{
if(!GetNextLine(buffer,line))break;
unsigned int idx;
sz = line;SkipSpaces(&sz);
if(!(idx = strtol10(sz,&sz)) || idx > 9)
continue;
faces->mIndices = new unsigned int [faces->mNumIndices]; faces->mIndices = new unsigned int [faces->mNumIndices];
for (unsigned int m = 0; m < faces->mNumIndices;++m) for (unsigned int m = 0; m < faces->mNumIndices;++m)
@ -156,10 +176,10 @@ void OFFImporter::InternReadFile( const std::string& pFile,
DefaultLogger::get()->error("OFF: Vertex index is out of range"); DefaultLogger::get()->error("OFF: Vertex index is out of range");
idx = numVertices-1; idx = numVertices-1;
} }
faces->mIndices[m] = p++; faces->mIndices[m] = p++;
*verts++ = tempPositions[idx]; *verts++ = tempPositions[idx];
} }
++i;
++faces; ++faces;
} }

View File

@ -48,23 +48,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
// some array offsets
#define AI_PTVS_VERTEX 0x0
#define AI_PTVS_FACE 0x1
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
PretransformVertices::PretransformVertices() PretransformVertices::PretransformVertices()
{ {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
PretransformVertices::~PretransformVertices() PretransformVertices::~PretransformVertices()
{ {
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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 PretransformVertices::IsActive( unsigned int pFlags) const bool PretransformVertices::IsActive( unsigned int pFlags) const
{ {
return (pFlags & aiProcess_PreTransformVertices) != 0; return (pFlags & aiProcess_PreTransformVertices) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Count the number of nodes // Count the number of nodes
unsigned int CountNodes( aiNode* pcNode ) unsigned int CountNodes( aiNode* pcNode )
@ -76,14 +83,20 @@ unsigned int CountNodes( aiNode* pcNode )
} }
return iRet; return iRet;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a bitwise combination identifying the vertex format of a mesh // Get a bitwise combination identifying the vertex format of a mesh
unsigned int GetMeshVFormat(aiMesh* pcMesh) unsigned int GetMeshVFormat(aiMesh* pcMesh)
{ {
if (0xdeadbeef == pcMesh->mNumUVComponents[0]) // the vertex format is stored in aiMesh::mBones for later retrieval.
return pcMesh->mNumUVComponents[1]; // there isn't a good reason to compute it a few hundred times
// from scratch. The pointer is unused as animations are lost
// during PretransformVertices.
if (pcMesh->mBones)
return (unsigned int)pcMesh->mBones;
unsigned int iRet = 0; unsigned int iRet = 0;
ai_assert(NULL != pcMesh->mVertices);
// normals // normals
if (pcMesh->HasNormals())iRet |= 0x1; if (pcMesh->HasNormals())iRet |= 0x1;
@ -92,23 +105,25 @@ unsigned int GetMeshVFormat(aiMesh* pcMesh)
// texture coordinates // texture coordinates
unsigned int p = 0; unsigned int p = 0;
ai_assert(4 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); ai_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
while (pcMesh->HasTextureCoords(p)) while (pcMesh->HasTextureCoords(p))
{ {
iRet |= (0x100 << p++); iRet |= (0x100 << p);
if (3 == pcMesh->mNumUVComponents[p]) if (3 == pcMesh->mNumUVComponents[p])
iRet |= (0x1000 << p++); iRet |= (0x10000 << p);
++p;
} }
// vertex colors // vertex colors
p = 0; p = 0;
while (pcMesh->HasVertexColors(p))iRet |= (0x10000 << p++); ai_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++);
// store the value for later use // store the value for later use
pcMesh->mNumUVComponents[0] = 0xdeadbeef; pcMesh->mBones = (aiBone**)iRet;
pcMesh->mNumUVComponents[1] = iRet;
return iRet; return iRet;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Count the number of vertices in the whole scene and a given // Count the number of vertices in the whole scene and a given
// material index // material index
@ -132,9 +147,6 @@ void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
return; return;
} }
#define AI_PTVS_VERTEX 0x0
#define AI_PTVS_FACE 0x1
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Collect vertex/face data // Collect vertex/face data
void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
@ -157,11 +169,14 @@ void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
aiMatrix4x4 mWorldIT = pcNode->mTransformation; aiMatrix4x4 mWorldIT = pcNode->mTransformation;
mWorldIT.Inverse().Transpose(); mWorldIT.Inverse().Transpose();
// TODO: implement Inverse() for aiMatrix3x3
aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
// copy normals, transform them to worldspace // copy normals, transform them to worldspace
for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
{ {
pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] = pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] =
mWorldIT * pcMesh->mNormals[n]; m * pcMesh->mNormals[n];
} }
} }
if (iVFormat & 0x2) if (iVFormat & 0x2)
@ -185,7 +200,7 @@ void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
++p; ++p;
} }
p = 0; p = 0;
while (iVFormat & (0x10000 << p)) while (iVFormat & (0x1000000 << p))
{ {
// copy vertex colors // copy vertex colors
memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX], memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX],
@ -213,6 +228,23 @@ void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
// just make sure the array won't be deleted by the // just make sure the array won't be deleted by the
// aiFace destructor ... // aiFace destructor ...
pcMesh->mFaces[planck].mIndices = NULL; pcMesh->mFaces[planck].mIndices = NULL;
// FIX: update the mPrimitiveTypes member of the mesh
switch (pcMesh->mFaces[planck].mNumIndices)
{
case 0x1:
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT;
break;
case 0x2:
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE;
break;
case 0x3:
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
break;
default:
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
break;
};
} }
aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices; aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices;
aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces; aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces;
@ -225,11 +257,12 @@ void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
} }
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a list of all vertex formats that occur for a given material index // Get a list of all vertex formats that occur for a given material index
// The output list contains duplicate elements // The output list contains duplicate elements
void GetVFormatList( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, void GetVFormatList( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
std::list<unsigned int>& aiOut) std::list<unsigned int>& aiOut)
{ {
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
{ {
@ -245,13 +278,14 @@ void GetVFormatList( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
} }
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Compute the absolute transformation matrices of each node // Compute the absolute transformation matrices of each node
void ComputeAbsoluteTransform( aiNode* pcNode ) void ComputeAbsoluteTransform( aiNode* pcNode )
{ {
if (pcNode->mParent) if (pcNode->mParent)
{ {
pcNode->mTransformation = pcNode->mTransformation*pcNode->mParent->mTransformation; pcNode->mTransformation = pcNode->mParent->mTransformation*pcNode->mTransformation;
} }
for (unsigned int i = 0;i < pcNode->mNumChildren;++i) for (unsigned int i = 0;i < pcNode->mNumChildren;++i)
@ -260,18 +294,37 @@ void ComputeAbsoluteTransform( aiNode* pcNode )
} }
return; return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void PretransformVertices::Execute( aiScene* pScene) void PretransformVertices::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("PretransformVerticesProcess begin"); DefaultLogger::get()->debug("PretransformVerticesProcess begin");
const unsigned int iOldMeshes = pScene->mNumMeshes;
const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
// first compute absolute transformation matrices for all nodes // first compute absolute transformation matrices for all nodes
ComputeAbsoluteTransform(pScene->mRootNode); ComputeAbsoluteTransform(pScene->mRootNode);
// delete aiMesh::mBones for all meshes. The bones are
// removed during this step and we need the pointer as
// temporary storage
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
aiMesh* mesh = pScene->mMeshes[i];
for (unsigned int a = 0; a < mesh->mNumBones;++a)
delete mesh->mBones[a];
delete[] mesh->mBones;
mesh->mBones = NULL;
}
// now build a list of output meshes // now build a list of output meshes
std::vector<aiMesh*> apcOutMeshes; std::vector<aiMesh*> apcOutMeshes;
apcOutMeshes.reserve(pScene->mNumMaterials*2); apcOutMeshes.reserve(pScene->mNumMaterials<<1u);
std::list<unsigned int> aiVFormats; std::list<unsigned int> aiVFormats;
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
{ {
@ -306,12 +359,12 @@ void PretransformVertices::Execute( aiScene* pScene)
while ((*j) & (0x100 << iFaces)) while ((*j) & (0x100 << iFaces))
{ {
pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices];
if ((*j) & (0x1000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3; if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3;
else pcMesh->mNumUVComponents[iFaces] = 2; else pcMesh->mNumUVComponents[iFaces] = 2;
iFaces++; iFaces++;
} }
iFaces = 0; iFaces = 0;
while ((*j) & (0x10000 << iFaces)) while ((*j) & (0x1000000 << iFaces))
pcMesh->mColors[iFaces] = new aiColor4D[iVertices]; pcMesh->mColors[iFaces] = new aiColor4D[iVertices];
// fill the mesh ... // fill the mesh ...
@ -324,28 +377,66 @@ void PretransformVertices::Execute( aiScene* pScene)
// remove all animations from the scene // remove all animations from the scene
for (unsigned int i = 0; i < pScene->mNumAnimations;++i) for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
delete pScene->mAnimations[i]; delete pScene->mAnimations[i];
pScene->mAnimations = NULL; delete[] pScene->mAnimations;
pScene->mAnimations = NULL;
pScene->mNumAnimations = 0; pScene->mNumAnimations = 0;
// now delete all meshes in the scene and build a new mesh list // now delete all meshes in the scene and build a new mesh list
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
delete pScene->mMeshes[i]; delete pScene->mMeshes[i];
if (apcOutMeshes.size() != pScene->mNumMeshes)
// invalidate the contents of the old mesh array. We will most
// likely have less output meshes now, so the last entries of
// the mesh array are not overridden. We set them to NULL to
// make sure the developer gets notified when his application
// attempts to access these fields ...
AI_DEBUG_INVALIDATE_PTR( pScene->mMeshes[i] );
}
pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
if (apcOutMeshes.size() > pScene->mNumMeshes)
{ {
delete[] pScene->mMeshes; delete[] pScene->mMeshes;
pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
} }
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
pScene->mMeshes[i] = apcOutMeshes[i]; pScene->mMeshes[i] = apcOutMeshes[i];
// --- we need to keep all cameras and lights
for (unsigned int i = 0; i < pScene->mNumCameras;++i)
{
aiCamera* cam = pScene->mCameras[i];
const aiNode* nd = pScene->mRootNode->FindNode(cam->mName);
ai_assert(NULL != nd);
// multiply all properties of the camera with the absolute
// transformation of the corresponding node
cam->mPosition = nd->mTransformation * cam->mPosition;
cam->mLookAt = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt;
cam->mUp = aiMatrix3x3( nd->mTransformation ) * cam->mUp;
}
for (unsigned int i = 0; i < pScene->mNumLights;++i)
{
aiLight* l = pScene->mLights[i];
const aiNode* nd = pScene->mRootNode->FindNode(l->mName);
ai_assert(NULL != nd);
// multiply all properties of the camera with the absolute
// transformation of the corresponding node
l->mPosition = nd->mTransformation * l->mPosition;
l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection;
}
// now delete all nodes in the scene and build a new // now delete all nodes in the scene and build a new
// flat node graph with a root node and some level 1 children // flat node graph with a root node and some level 1 children
delete pScene->mRootNode; delete pScene->mRootNode;
pScene->mRootNode = new aiNode(); pScene->mRootNode = new aiNode();
pScene->mRootNode->mName.Set("<dummy_root>"); pScene->mRootNode->mName.Set("<dummy_root>");
if (1 == pScene->mNumMeshes) if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras)
{ {
pScene->mRootNode->mNumMeshes = 1; pScene->mRootNode->mNumMeshes = 1;
pScene->mRootNode->mMeshes = new unsigned int[1]; pScene->mRootNode->mMeshes = new unsigned int[1];
@ -353,22 +444,59 @@ void PretransformVertices::Execute( aiScene* pScene)
} }
else else
{ {
pScene->mRootNode->mNumChildren = pScene->mNumMeshes; pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras;
pScene->mRootNode->mChildren = new aiNode*[pScene->mNumMeshes]; aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
aiNode* pcNode = pScene->mRootNode->mChildren[i] = new aiNode();
pcNode->mName.length = sprintf(pcNode->mName.data,"dummy_%i",i);
// generate mesh nodes
for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes)
{
aiNode* pcNode = *nodes = new aiNode();
pcNode->mParent = pScene->mRootNode;
pcNode->mName.length = ::sprintf(pcNode->mName.data,"mesh_%i",i);
// setup mesh indices
pcNode->mNumMeshes = 1; pcNode->mNumMeshes = 1;
pcNode->mMeshes = new unsigned int[1]; pcNode->mMeshes = new unsigned int[1];
pcNode->mMeshes[0] = i; pcNode->mMeshes[0] = i;
}
// generate light nodes
for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes)
{
aiNode* pcNode = *nodes = new aiNode();
pcNode->mParent = pScene->mRootNode; pcNode->mParent = pScene->mRootNode;
pcNode->mName.length = ::sprintf(pcNode->mName.data,"light_%i",i);
pScene->mLights[i]->mName = pcNode->mName;
}
// generate camera nodes
for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes)
{
aiNode* pcNode = *nodes = new aiNode();
pcNode->mParent = pScene->mRootNode;
pcNode->mName.length = ::sprintf(pcNode->mName.data,"cam_%i",i);
pScene->mCameras[i]->mName = pcNode->mName;
} }
} }
DefaultLogger::get()->debug("PretransformVerticesProcess finished. All " // print statistics
"vertices are in worldspace now"); if (!DefaultLogger::isNullLogger())
{
char buffer[4096];
DefaultLogger::get()->debug("PretransformVerticesProcess finished");
::sprintf(buffer,"Removed %i nodes and %i animation channels (%i output nodes)",
iOldNodes,iOldAnimationChannels,CountNodes(pScene->mRootNode));
DefaultLogger::get()->info(buffer);
::sprintf(buffer,"Kept %i lights and %i cameras",
pScene->mNumLights,pScene->mNumCameras);
DefaultLogger::get()->info(buffer);
::sprintf(buffer,"Moved %i meshes to WCS (number of output meshes: %i)",
iOldMeshes,pScene->mNumMeshes);
DefaultLogger::get()->info(buffer);
}
return; return;
} }

View File

@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssimpPCH.h" #include "AssimpPCH.h"
#include "RemoveComments.h" #include "RemoveComments.h"
#include "ParsingUtils.h"
namespace Assimp namespace Assimp
{ {
@ -56,17 +57,17 @@ void CommentRemover::RemoveLineComments(const char* szComment,
ai_assert(NULL != szComment && NULL != szBuffer && *szComment); ai_assert(NULL != szComment && NULL != szBuffer && *szComment);
const size_t len = ::strlen(szComment); const size_t len = ::strlen(szComment);
while (*szBuffer) while (*szBuffer)
{ {
if (0 == ::strncmp(szBuffer,szComment,len)) if (!::strncmp(szBuffer,szComment,len))
{ {
while (*szBuffer != '\r' && *szBuffer != '\n' && *szBuffer) while (!IsLineEnd(*szBuffer))
*szBuffer++ = chReplacement; *szBuffer++ = chReplacement;
} }
++szBuffer; ++szBuffer;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void CommentRemover::RemoveMultiLineComments(const char* szCommentStart, void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
const char* szCommentEnd,char* szBuffer, const char* szCommentEnd,char* szBuffer,
@ -74,32 +75,30 @@ void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
{ {
// validate parameters // validate parameters
ai_assert(NULL != szCommentStart && NULL != szCommentEnd && ai_assert(NULL != szCommentStart && NULL != szCommentEnd &&
NULL != szBuffer && '\0' != *szCommentStart && '\0' != *szCommentEnd); NULL != szBuffer && *szCommentStart && *szCommentEnd);
const size_t len = ::strlen(szCommentEnd); const size_t len = ::strlen(szCommentEnd);
const size_t len2 = ::strlen(szCommentStart); const size_t len2 = ::strlen(szCommentStart);
while (*szBuffer) while (*szBuffer)
{ {
if (0 == ::strncmp(szBuffer,szCommentStart,len2)) if (!::strncmp(szBuffer,szCommentStart,len2))
{ {
while (*szBuffer) while (*szBuffer)
{ {
if (!::strncmp(szBuffer,szCommentEnd,len))
if (0 == ::strncmp(szBuffer,szCommentEnd,len))
{ {
for (unsigned int i = 0; i < len;++i) for (unsigned int i = 0; i < len;++i)
*szBuffer++ = chReplacement; *szBuffer++ = chReplacement;
goto __continue_outer; // WUHHHAAAAHHAA!
break;
} }
*szBuffer++ = chReplacement; *szBuffer++ = chReplacement;
} }
return; if (!(*szBuffer))return;
continue;
} }
++szBuffer; ++szBuffer;
__continue_outer:
int i = 4; // NOP dummy
++i;
} }
} }

View File

@ -185,7 +185,30 @@ void RemoveVCProcess::Execute( aiScene* pScene)
bHas = true; bHas = true;
ArrayDelete(pScene->mTextures,pScene->mNumTextures); ArrayDelete(pScene->mTextures,pScene->mNumTextures);
} }
#if 0
// handle materials
if ( configDeleteFlags & aiComponent_MATERIALS && pScene->mNumMaterials)
{
bHas = true;
for (unsigned int i = 1;i < pScene->mNumMaterials;++i)
delete pScene->mMaterials[i];
MaterialHelper* helper = (MaterialHelper*) pScene->mMaterials[0];
helper->Clear();
// gray
aiColor3D clr(0.6f,0.6f,0.6f);
helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
// add a small ambient color value
clr = aiColor3D(0.05f,0.05f,0.05f);
helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT);
aiString s;
s.Set("Dummy_MaterialsRemoved");
helper->AddProperty(&s,AI_MATKEY_NAME);
}
// handle light sources // handle light sources
if ( configDeleteFlags & aiComponent_LIGHTS) if ( configDeleteFlags & aiComponent_LIGHTS)
{ {
@ -198,7 +221,7 @@ void RemoveVCProcess::Execute( aiScene* pScene)
} }
// handle camneras // handle camneras
if ( configDeleteFlags & aiComponent_CAMERA) if ( configDeleteFlags & aiComponent_CAMERAS)
{ {
// mask nodes for removal // mask nodes for removal
MaskNodes(pScene->mRootNode,pScene->mLights,pScene->mNumLights, MaskNodes(pScene->mRootNode,pScene->mLights,pScene->mNumLights,
@ -207,13 +230,12 @@ void RemoveVCProcess::Execute( aiScene* pScene)
bHas = true; bHas = true;
ArrayDelete(pScene->mCameras,pScene->mNumCameras); ArrayDelete(pScene->mCameras,pScene->mNumCameras);
} }
#endif
// handle meshes // handle meshes
if (configDeleteFlags & aiComponent_MESHES) if (configDeleteFlags & aiComponent_MESHES)
{ {
bHas = true; bHas = true;
ArrayDelete(pScene->mMeshes,pScene->mNumMeshes); ArrayDelete(pScene->mMeshes,pScene->mNumMeshes);
pScene->mFlags |= AI_SCENE_FLAGS_ANIM_SKELETON_ONLY;
} }
else else
{ {
@ -232,7 +254,6 @@ void RemoveVCProcess::Execute( aiScene* pScene)
// MSB>>1 means: NO, DON'T REMOVE ME (Veto) // MSB>>1 means: NO, DON'T REMOVE ME (Veto)
if (bMasked) if (bMasked)
{ {
#if 0
if (pScene->mNumLights) if (pScene->mNumLights)
{ {
MaskNodes(pScene->mRootNode,pScene->mLights,pScene->mNumLights, MaskNodes(pScene->mRootNode,pScene->mLights,pScene->mNumLights,
@ -243,7 +264,6 @@ void RemoveVCProcess::Execute( aiScene* pScene)
MaskNodes(pScene->mRootNode,pScene->mCameras,pScene->mNumCameras, MaskNodes(pScene->mRootNode,pScene->mCameras,pScene->mNumCameras,
AI_RC_UINT_MSB_2); AI_RC_UINT_MSB_2);
} }
#endif
if (!(configDeleteFlags & aiComponent_BONEWEIGHTS)) if (!(configDeleteFlags & aiComponent_BONEWEIGHTS))
{ {
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
@ -259,15 +279,14 @@ void RemoveVCProcess::Execute( aiScene* pScene)
std::list<aiNode*> dummy; std::list<aiNode*> dummy;
UpdateNodeGraph(pScene->mRootNode,dummy, true); UpdateNodeGraph(pScene->mRootNode,dummy, true);
// the root node will neever be deleted // the root node will never be deleted
} }
// now check whether the result contains // now check whether the result is still a full scene
// !0 animations (+ the AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag) OR if (!pScene->mNumMeshes || !pScene->mNumMaterials)
// !0 meshes
if (!pScene->mNumAnimations && !pScene->mNumMeshes)
{ {
throw new ImportErrorException("No valid data structure remaining"); pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
DefaultLogger::get()->debug("Setting AI_SCENE_FLAGS_INCOMPLETE flag");
} }
if (bHas)DefaultLogger::get()->info("RemoveVCProcess finished. Data structure cleanup has been done."); if (bHas)DefaultLogger::get()->info("RemoveVCProcess finished. Data structure cleanup has been done.");
@ -291,6 +310,11 @@ bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh)
{ {
bool ret = false; bool ret = false;
// if all materials have been deleted let the material
// index of the mesh point to the created default material
if ( configDeleteFlags & aiComponent_MATERIALS)
pMesh->mMaterialIndex = 0;
// handle normals // handle normals
if (configDeleteFlags & aiComponent_NORMALS && pMesh->mNormals) if (configDeleteFlags & aiComponent_NORMALS && pMesh->mNormals)
{ {

View File

@ -156,7 +156,7 @@ void SMDImporter::InternReadFile(
} }
// 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_ANIM_SKELETON_ONLY; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} }
if (!asBones.empty()) if (!asBones.empty())
@ -179,7 +179,7 @@ void SMDImporter::InternReadFile(
// compute absolute bone transformation matrices // compute absolute bone transformation matrices
ComputeAbsoluteBoneTransformations(); ComputeAbsoluteBoneTransformations();
} }
if (!(pScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY)) if (!(pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{ {
// create output meshes // create output meshes
CreateOutputMeshes(); CreateOutputMeshes();
@ -462,7 +462,7 @@ void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent)
void SMDImporter::CreateOutputNodes() void SMDImporter::CreateOutputNodes()
{ {
pScene->mRootNode = new aiNode(); pScene->mRootNode = new aiNode();
if (!(pScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY)) if (!(pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{ {
// create one root node that renders all meshes // create one root node that renders all meshes
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
@ -475,7 +475,7 @@ void SMDImporter::CreateOutputNodes()
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_ANIM_SKELETON_ONLY && if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE &&
1 == pScene->mRootNode->mNumChildren) 1 == pScene->mRootNode->mNumChildren)
{ {
aiNode* pcOldRoot = pScene->mRootNode; aiNode* pcOldRoot = pScene->mRootNode;

View File

View File

@ -55,7 +55,7 @@ using namespace Assimp;
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
DeterminePTypeHelperProcess ::DeterminePTypeHelperProcess() DeterminePTypeHelperProcess ::DeterminePTypeHelperProcess()
{ {
// nothing to do here bSpeedFlag = false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -73,84 +73,97 @@ 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)
{ {
DefaultLogger::get()->debug("DeterminePTypeHelper begin");
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];
::_itoa(deg,s,10);
DefaultLogger::get()->warn(std::string("Found ") + s + " degenerated primitives");
}
}
if (!mesh->mPrimitiveTypes) if (!mesh->mPrimitiveTypes)
{ {
bool bDeg = false;
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
{ {
aiFace& face = mesh->mFaces[a]; aiFace& face = mesh->mFaces[a];
switch (face.mNumIndices) switch (face.mNumIndices)
{ {
case 3u: case 3u:
mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
break;
// check whether the triangle is degenerated
if (mesh->mVertices[face.mIndices[0]] == mesh->mVertices[face.mIndices[1]] ||
mesh->mVertices[face.mIndices[1]] == mesh->mVertices[face.mIndices[2]])
{
face.mNumIndices = 2;
unsigned int* pi = new unsigned int[2];
pi[0] = face.mIndices[0];
pi[1] = face.mIndices[2];
delete[] face.mIndices;
face.mIndices = pi;
bDeg = true;
}
else if (mesh->mVertices[face.mIndices[2]] == mesh->mVertices[face.mIndices[0]])
{
face.mNumIndices = 2;
unsigned int* pi = new unsigned int[2];
pi[0] = face.mIndices[0];
pi[1] = face.mIndices[1];
delete[] face.mIndices;
face.mIndices = pi;
bDeg = true;
}
else
{
mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
break;
}
case 2u: case 2u:
mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
break;
// check whether the line is degenerated
if (mesh->mVertices[face.mIndices[0]] == mesh->mVertices[face.mIndices[1]])
{
face.mNumIndices = 1;
unsigned int* pi = new unsigned int[1];
pi[0] = face.mIndices[0];
delete[] face.mIndices;
face.mIndices = pi;
bDeg = true;
}
else
{
mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
break;
}
case 1u: case 1u:
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
break; break;
default: default:
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
break; break;
} }
} }
if (bDeg)
{
DefaultLogger::get()->warn("Found degenerated primitives");
}
} }
} }
DefaultLogger::get()->debug("DeterminePTypeHelper finished");
} }
@ -218,7 +231,15 @@ void UpdateNodes(const std::vector<unsigned int>& replaceMeshIndex, aiNode* node
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void SortByPTypeProcess::Execute( aiScene* pScene) void SortByPTypeProcess::Execute( aiScene* pScene)
{ {
if (!pScene->mNumMeshes)return; if (!pScene->mNumMeshes)
{
DefaultLogger::get()->debug("SortByPTypeProcess skipped, there are no meshes");
return;
}
DefaultLogger::get()->debug("SortByPTypeProcess begin");
unsigned int aiNumMeshesPerPType[4] = {0,0,0,0};
std::vector<aiMesh*> outMeshes; std::vector<aiMesh*> outMeshes;
outMeshes.reserve(pScene->mNumMeshes<<1u); outMeshes.reserve(pScene->mNumMeshes<<1u);
@ -232,10 +253,26 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
// if there's just one primitive type in the mesh there's nothing to do for us // if there's just one primitive type in the mesh there's nothing to do for us
unsigned int num = 0; unsigned int num = 0;
if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) ++num; if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT)
if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) ++num; {
if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) ++num; ++aiNumMeshesPerPType[0];
if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) ++num; ++num;
}
if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE)
{
++aiNumMeshesPerPType[1];
++num;
}
if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)
{
++aiNumMeshesPerPType[2];
++num;
}
if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)
{
++aiNumMeshesPerPType[3];
++num;
}
if (1 == num) if (1 == num)
{ {
@ -436,5 +473,17 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
::memcpy(pScene->mMeshes,&outMeshes[0],pScene->mNumMeshes*sizeof(void*)); ::memcpy(pScene->mMeshes,&outMeshes[0],pScene->mNumMeshes*sizeof(void*));
} }
if (!DefaultLogger::isNullLogger())
{
char buffer[1024];
::sprintf(buffer,"Points: %i, Lines: %i, Triangles: %i, Polygons: %i (Meshes)",
aiNumMeshesPerPType[0],
aiNumMeshesPerPType[1],
aiNumMeshesPerPType[2],
aiNumMeshesPerPType[3]);
DefaultLogger::get()->info(buffer);
DefaultLogger::get()->debug("SortByPTypeProcess finished");
}
} }

View File

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

View File

@ -70,11 +70,9 @@ public:
inline StreamReader(IOStream* stream) inline StreamReader(IOStream* stream)
{ {
ai_assert(NULL != stream); ai_assert(NULL != stream);
this->input = input;
this->stream = stream; this->stream = stream;
size_t s = stream->GetFileSize(); size_t s = stream->FileSize();
if (!s)throw new ImportErrorException("File is empty"); if (!s)throw new ImportErrorException("File is empty");
current = buffer = new int8_t[s]; current = buffer = new int8_t[s];
@ -188,4 +186,4 @@ private:
}; };
#endif // !! AI_STREAMREADER_H_INCLUDED #endif // !! AI_STREAMREADER_H_INCLUDED

View File

@ -56,11 +56,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
#if _MSC_VER >= 1400
# define vsprintf vsprintf_s
# define sprintf sprintf_s
#endif
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
ValidateDSProcess::ValidateDSProcess() ValidateDSProcess::ValidateDSProcess()
@ -126,114 +121,200 @@ void ValidateDSProcess::ReportWarning(const char* msg,...)
va_end(args); va_end(args);
DefaultLogger::get()->warn("Validation warning: " + std::string(szBuffer,iLen)); DefaultLogger::get()->warn("Validation warning: " + std::string(szBuffer,iLen));
} }
// ------------------------------------------------------------------------------------------------
inline int HasNameMatch(const aiString& in, aiNode* node)
{
int result = (node->mName == in ? 1 : 0 );
for (unsigned int i = 0; i < node->mNumChildren;++i)
{
result += HasNameMatch(in,node->mChildren[i]);
}
return result;
}
// ------------------------------------------------------------------------------------------------
template <typename T>
inline void ValidateDSProcess::DoValidation(T** parray, unsigned int size,
const char* firstName, const char* secondName)
{
// validate all entries
if (size)
{
if (!parray)
{
ReportError("aiScene::%s is NULL (aiScene::%s is %i)",
firstName, secondName, size);
}
for (unsigned int i = 0; i < size;++i)
{
if (!parray[i])
{
ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)",
firstName,i,secondName,size);
}
Validate(parray[i]);
}
}
}
// ------------------------------------------------------------------------------------------------
template <typename T>
inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size,
const char* firstName, const char* secondName)
{
// validate all entries
if (size)
{
if (!parray)
{
ReportError("aiScene::%s is NULL (aiScene::%s is %i)",
firstName, secondName, size);
}
for (unsigned int i = 0; i < size;++i)
{
if (!parray[i])
{
ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)",
firstName,i,secondName,size);
}
Validate(parray[i]);
// check whether there are duplicate names
for (unsigned int a = i+1; a < size;++a)
{
if (parray[i]->mName == parray[a]->mName)
{
this->ReportError("aiScene::%s[%i] has the same name as "
"aiScene::%s[%i]",firstName, i,secondName, a);
}
}
}
}
}
// ------------------------------------------------------------------------------------------------
template <typename T>
inline void ValidateDSProcess::DoValidationWithNameCheck(T** array,
unsigned int size, const char* firstName,
const char* secondName)
{
// validate all entries
DoValidationEx(array,size,firstName,secondName);
for (unsigned int i = 0; i < size;++i)
{
int res = HasNameMatch(array[i]->mName,mScene->mRootNode);
if (!res)
{
ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)",
firstName,i,array[i]->mName.data);
}
else if (1 != res)
{
ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name",
firstName,i,array[i]->mName.data);
}
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void ValidateDSProcess::Execute( aiScene* pScene) void ValidateDSProcess::Execute( aiScene* pScene)
{ {
this->mScene = pScene; this->mScene = pScene;
DefaultLogger::get()->debug("ValidateDataStructureProcess begin"); DefaultLogger::get()->debug("ValidateDataStructureProcess begin");
// validate the node graph of the scene
Validate(pScene->mRootNode);
// at least one of the mXXX arrays must be non-empty or we'll flag
// the sebe as invalid
bool has = false;
// validate all meshes // validate all meshes
if (pScene->mNumMeshes) if (pScene->mNumMeshes)
{ {
if (!pScene->mMeshes) has = true;
{ DoValidation(pScene->mMeshes,pScene->mNumMeshes,"mMeshes","mNumMeshes");
this->ReportError("aiScene::mMeshes is NULL (aiScene::mNumMeshes is %i)",
pScene->mNumMeshes);
}
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
if (!pScene->mMeshes[i])
{
this->ReportError("aiScene::mMeshes[%i] is NULL (aiScene::mNumMeshes is %i)",
i,pScene->mNumMeshes);
}
this->Validate(pScene->mMeshes[i]);
}
} }
else if (!(this->mScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY)) else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{ {
this->ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there"); ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
} }
// validate all animations // validate all animations
if (pScene->mNumAnimations) if (pScene->mNumAnimations)
{ {
if (!pScene->mAnimations) has = true;
{ DoValidation(pScene->mAnimations,pScene->mNumAnimations,
this->ReportError("aiScene::mAnimations is NULL (aiScene::mNumAnimations is %i)", "mAnimations","mNumAnimations");
pScene->mNumAnimations);
}
for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
{
if (!pScene->mAnimations[i])
{
this->ReportError("aiScene::mAnimations[%i] is NULL (aiScene::mNumAnimations is %i)",
i,pScene->mNumAnimations);
}
this->Validate(pScene->mAnimations[i]);
// check whether there are duplicate animation names
for (unsigned int a = i+1; a < pScene->mNumAnimations;++a)
{
if (pScene->mAnimations[i]->mName == pScene->mAnimations[a]->mName)
{
this->ReportError("aiScene::mAnimations[%i] has the same name as "
"aiScene::mAnimations[%i]",i,a);
}
}
}
} }
else if (this->mScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY)
// validate all cameras
if (pScene->mNumCameras)
{ {
this->ReportError("aiScene::mNumAnimations is 0 and the " has = true;
"AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set."); DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras,
"mCameras","mNumCameras");
} }
// validate all textures // validate all lights
if (pScene->mNumTextures) if (pScene->mNumLights)
{ {
if (!pScene->mTextures) has = true;
{ DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights,
this->ReportError("aiScene::mTextures is NULL (aiScene::mNumTextures is %i)", "mLights","mNumLights");
pScene->mNumTextures);
}
for (unsigned int i = 0; i < pScene->mNumTextures;++i)
{
if (!pScene->mTextures[i])
{
this->ReportError("aiScene::mTextures[%i] is NULL (aiScene::mNumTextures is %i)",
i,pScene->mNumTextures);
}
this->Validate(pScene->mTextures[i]);
}
} }
// validate all materials // validate all materials
if (pScene->mNumMaterials) if (pScene->mNumMaterials)
{ {
if (!pScene->mMaterials) has = true;
{ DoValidation(pScene->mCameras,pScene->mNumCameras,"mMaterials","mNumMaterials");
this->ReportError("aiScene::mMaterials is NULL (aiScene::mNumMaterials is %i)", }
pScene->mNumMaterials); else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
} {
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) ReportError("aiScene::mNumMaterials is 0. At least one material must be there");
{
if (!pScene->mMaterials[i])
{
this->ReportError("aiScene::mMaterials[%i] is NULL (aiScene::mNumMaterials is %i)",
i,pScene->mNumMaterials);
}
this->Validate(pScene->mMaterials[i]);
}
} }
else this->ReportError("aiScene::mNumMaterials is 0. At least one material must be there.");
// validate the node graph of the scene
this->Validate(pScene->mRootNode);
if (!has)ReportError("The aiScene data structure is empty");
DefaultLogger::get()->debug("ValidateDataStructureProcess end"); DefaultLogger::get()->debug("ValidateDataStructureProcess end");
} }
// ------------------------------------------------------------------------------------------------
void ValidateDSProcess::Validate( const aiLight* pLight)
{
if (pLight->mType == aiLightSource_UNDEFINED)
ReportError("aiLight::mType is aiLightSource_UNDEFINED");
if (!pLight->mAttenuationConstant &&
!pLight->mAttenuationLinear &&
!pLight->mAttenuationQuadratic)
{
ReportError("aiLight::mAttenuationXXX - all are zero");
}
if (pLight->mAngleInnerCone > pLight->mAngleOuterCone)
ReportError("aiLight::mAngleInnerCone is larger than aiLight::mAngleOuterCone");
if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack()
&& pLight->mColorSpecular.IsBlack())
{
ReportError("aiLight::mColorXXX - all are black and won't have any influence");
}
}
// ------------------------------------------------------------------------------------------------
void ValidateDSProcess::Validate( const aiCamera* pCamera)
{
if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear)
ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear");
if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI)
ReportError("%f is not a valid value for aiCamera::mHorizontalFOV",pCamera->mHorizontalFOV);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ValidateDSProcess::Validate( const aiMesh* pMesh) void ValidateDSProcess::Validate( const aiMesh* pMesh)
{ {
@ -288,96 +369,91 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
if (!face.mIndices)this->ReportError("aiMesh::mFaces[%i].mIndices is NULL",i); if (!face.mIndices)this->ReportError("aiMesh::mFaces[%i].mIndices is NULL",i);
} }
if (this->mScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY) // positions must always be there ...
if (!pMesh->mNumVertices || !pMesh->mVertices && !mScene->mFlags)
{ {
if (pMesh->mNumVertices || pMesh->mVertices || this->ReportError("The mesh contains no vertices");
pMesh->mNumFaces || pMesh->mFaces) }
// if tangents are there there must also be bitangent vectors ...
if ((pMesh->mTangents != NULL) != (pMesh->mBitangents != NULL))
{
this->ReportError("If there are tangents there must also be bitangent vectors");
}
// faces, too
if (!pMesh->mNumFaces || !pMesh->mFaces && !mScene->mFlags)
{
this->ReportError("The mesh contains no faces");
}
// now check whether the face indexing layout is correct:
// unique vertices, pseudo-indexed.
std::vector<bool> abRefList;
abRefList.resize(pMesh->mNumVertices,false);
for (unsigned int i = 0; i < pMesh->mNumFaces;++i)
{
aiFace& face = pMesh->mFaces[i];
for (unsigned int a = 0; a < face.mNumIndices;++a)
{ {
this->ReportWarning("The mesh contains vertices and faces although " if (face.mIndices[a] >= pMesh->mNumVertices)
"the AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set"); {
this->ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a);
}
// the MSB flag is temporarily used by the extra verbose
// mode to tell us that the JoinVerticesProcess might have
// been executed already.
if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && abRefList[face.mIndices[a]])
{
ReportError("aiMesh::mVertices[%i] is referenced twice - second "
"time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a);
}
abRefList[face.mIndices[a]] = true;
} }
} }
else // check whether there are vertices that aren't referenced by a face
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
{ {
// positions must always be there ... if (!abRefList[i])this->ReportError("aiMesh::mVertices[%i] is not referenced",i);
if (!pMesh->mNumVertices || !pMesh->mVertices)
{
this->ReportError("The mesh contains no vertices");
}
// faces, too
if (!pMesh->mNumFaces || !pMesh->mFaces)
{
this->ReportError("The mesh contains no faces");
}
// now check whether the face indexing layout is correct:
// unique vertices, pseudo-indexed.
std::vector<bool> abRefList;
abRefList.resize(pMesh->mNumVertices,false);
for (unsigned int i = 0; i < pMesh->mNumFaces;++i)
{
aiFace& face = pMesh->mFaces[i];
for (unsigned int a = 0; a < face.mNumIndices;++a)
{
if (face.mIndices[a] >= pMesh->mNumVertices)
{
this->ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a);
}
// the MSB flag is temporarily used by the extra verbose
// mode to tell us that the JoinVerticesProcess might have
// been executed already.
if ( !(this->mScene->mFlags & 0x80000000 ) && abRefList[face.mIndices[a]])
{
this->ReportError("aiMesh::mVertices[%i] is referenced twice - second "
"time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a);
}
abRefList[face.mIndices[a]] = true;
}
}
// check whether there are vertices that aren't referenced by a face
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
{
if (!abRefList[i])this->ReportError("aiMesh::mVertices[%i] is not referenced",i);
}
abRefList.clear();
// texture channel 2 may not be set if channel 1 is zero ...
{
unsigned int i = 0;
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
{
if (!pMesh->HasTextureCoords(i))break;
}
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
if (pMesh->HasTextureCoords(i))
{
this->ReportError("Texture coordinate channel %i is existing, "
"although the previous channel was NULL.",i);
}
}
// the same for the vertex colors
{
unsigned int i = 0;
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
{
if (!pMesh->HasVertexColors(i))break;
}
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
if (pMesh->HasVertexColors(i))
{
this->ReportError("Vertex color channel %i is existing, "
"although the previous channel was NULL.",i);
}
}
} }
abRefList.clear();
// texture channel 2 may not be set if channel 1 is zero ...
{
unsigned int i = 0;
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
{
if (!pMesh->HasTextureCoords(i))break;
}
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
if (pMesh->HasTextureCoords(i))
{
ReportError("Texture coordinate channel %i is existing, "
"although the previous channel was NULL.",i);
}
}
// the same for the vertex colors
{
unsigned int i = 0;
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
{
if (!pMesh->HasVertexColors(i))break;
}
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
if (pMesh->HasVertexColors(i))
{
ReportError("Vertex color channel %i is existing, "
"although the previous channel was NULL.",i);
}
}
// now validate all bones // now validate all bones
if (pMesh->HasBones()) if (pMesh->HasBones())
{ {
if (!pMesh->mBones) if (!pMesh->mBones)
{ {
this->ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)", ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)",
pMesh->mNumBones); pMesh->mNumBones);
} }
float* afSum = NULL; float* afSum = NULL;
@ -397,7 +473,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
this->ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)", this->ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)",
i,pMesh->mNumBones); i,pMesh->mNumBones);
} }
this->Validate(pMesh,pMesh->mBones[i],afSum); Validate(pMesh,pMesh->mBones[i],afSum);
for (unsigned int a = i+1; a < pMesh->mNumBones;++a) for (unsigned int a = i+1; a < pMesh->mNumBones;++a)
{ {
@ -414,7 +490,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
{ {
if (afSum[i] && (afSum[i] <= 0.995 || afSum[i] >= 1.005)) if (afSum[i] && (afSum[i] <= 0.995 || afSum[i] >= 1.005))
{ {
this->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]);
} }
} }
delete[] afSum; delete[] afSum;

View File

@ -145,10 +145,22 @@ protected:
* @param pTexture Input texture * @param pTexture Input texture
*/ */
void Validate( const aiTexture* pTexture); void Validate( const aiTexture* pTexture);
// -------------------------------------------------------------------
/** Validates a light source
* @param pLight Input light
*/
void Validate( const aiLight* pLight);
// -------------------------------------------------------------------
/** Validates a camera
* @param pCamera Input camera
*/
void Validate( const aiCamera* pCamera);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Validates a bone animation channel /** Validates a bone animation channel
* @param pAnimation Input animation * @param pAnimation Animation channel.
* @param pBoneAnim Input bone animation * @param pBoneAnim Input bone animation
*/ */
void Validate( const aiAnimation* pAnimation, void Validate( const aiAnimation* pAnimation,
@ -168,9 +180,28 @@ protected:
private: private:
// template to validate one of the aiScene::mXXX arrays
template <typename T>
inline void DoValidation(T** array, unsigned int size,
const char* firstName, const char* secondName);
// extended version: checks whethr T::mName occurs twice
template <typename T>
inline void DoValidationEx(T** array, unsigned int size,
const char* firstName, const char* secondName);
// extension to the first template which does also search
// the nodegraph for an item with the same name
template <typename T>
inline void DoValidationWithNameCheck(T** array, unsigned int size,
const char* firstName, const char* secondName);
aiScene* mScene; aiScene* mScene;
}; };
} // end of namespace Assimp } // end of namespace Assimp
#endif // AI_VALIDATEPROCESS_H_INC #endif // AI_VALIDATEPROCESS_H_INC

View File

@ -139,7 +139,7 @@ inline unsigned int strtol_cppstyle( const char* in, const char** out=0)
{ {
if ('0' == in[0]) if ('0' == in[0])
{ {
return 'x' == in[1] ? strtol10(in+2,out) : strtol8(in+1,out); return 'x' == in[1] ? strtol16(in+2,out) : strtol8(in+1,out);
} }
return strtol10(in, out); return strtol10(in, out);
} }

View File

@ -74,7 +74,7 @@ all: $(TARGET)
$(TARGET): $(OBJECTS) $(TARGET): $(OBJECTS)
gcc -o $@ $(OBJECTS) -shared -lstdc++ gcc -o $@ $(OBJECTS) -shared -lstdc++
%.o:%.cpp %.o:%.cpp
$(CXX) -g -Wall -c $? -o $@ -I../include -I"C:\Program Files\boost\boost_1_35_0" -I"%BOOST_DIR%" $(CXX) -g -Wall -c $? -o $@ -I../include -I"C:\Program Files\boost\boost_1_35_0"
clean: clean:
del *.o del *.o

View File

@ -67,6 +67,35 @@ struct aiCamera
*/ */
aiString mName; aiString mName;
/** Position of the camera relative to the coordinate space
* defined by the corresponding node.
*
* The default value is 0|0|0.
*/
aiVector3D mPosition;
/** 'Up' - vector of the camera coordinate system relative to
* the coordinate space defined by the corresponding node.
*
* The 'right' vector of the camera coordinate system is
* the cross product of the up and lookAt vectors.
* The default value is 0|1|0. The vector
* may be normalized, but it needn't.
*/
aiVector3D mUp;
/** 'LookAt' - vector of the camera coordinate system relative to
* the coordinate space defined by the corresponding node.
*
* This is the viewing direction of the user.
* The default value is 0|0|1. The vector
* may be normalized, but it needn't.
*/
aiVector3D mLookAt;
/** Half horizontal field of view angle, in radians. /** Half horizontal field of view angle, in radians.
* *
* The field of view angle is the angle between the center * The field of view angle is the angle between the center
@ -105,7 +134,9 @@ struct aiCamera
#ifdef __cplusplus #ifdef __cplusplus
aiCamera() aiCamera()
: mHorizontalFOV (0.25f * (float)AI_MATH_PI) : mUp (0.f,1.f,0.f)
, mLookAt (0.f,0.f,1.f)
, mHorizontalFOV (0.25f * (float)AI_MATH_PI)
, mClipPlaneNear (0.1f) , mClipPlaneNear (0.1f)
, mClipPlaneFar (1000.f) , mClipPlaneFar (1000.f)
, mAspect (0.f) , mAspect (0.f)
@ -120,4 +151,4 @@ struct aiCamera
} }
#endif #endif
#endif // AI_CAMERA_H_INC #endif // AI_CAMERA_H_INC

View File

@ -40,8 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/** @file Defines constants for configurable properties */ /** @file Defines constants for configurable properties */
#ifndef AI_CONFIG_H_INC #ifndef __AI_CONFIG_H_INC__
#define AI_CONFIG_H_INC #define __AI_CONFIG_H_INC__
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** \brief Set the maximum number of vertices in a mesh. /** \brief Set the maximum number of vertices in a mesh.
@ -138,7 +138,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* This applies to the GenSmoothNormals-Step. The angle is specified * This applies to the GenSmoothNormals-Step. The angle is specified
* in degrees, so 180 is PI. The default value is * in degrees, so 180 is PI. The default value is
* 175 degrees (all vertex normals are smoothed). The maximum value is 175 * 175 degrees (all vertex normals are smoothed). The maximum value is 175
* Property type: float. * Property type: float. Warning: seting this option may cause a severe
* loss of performance.
*/ */
#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE "pp.gsn.max_smoothing" #define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE "pp.gsn.max_smoothing"
@ -169,20 +170,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** \brief Sets the colormap (= palette) to be used to decode embedded /** \brief Sets the colormap (= palette) to be used to decode embedded
* textures in MDL files. * textures in MDL (Quake or 3DGS) files.
* *
* This must be a valid path to a file. The file is 768 (256*3) bytes * This must be a valid path to a file. The file is 768 (256*3) bytes
* large and contains RGB tripels for each of the 256 palette entries. * large and contains RGB triplets for each of the 256 palette entries.
* The default value is colormap.lmp. If the file is nto found, * The default value is colormap.lmp. If the file is not found,
* a default palette is used. * a default palette (from Quake 1) is used.
* Property type: string. * Property type: string.
*/ */
#define AI_CONFIG_IMPORT_MDL_COLORMAP "imp.mdl.color_map" #define AI_CONFIG_IMPORT_MDL_COLORMAP "imp.mdl.color_map"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** \brief Enumerates components of the aiScene and aiMesh data structures
* that can be excluded from the import with the RemoveComponent step.
*
* See the documentation to #aiProcess_RemoveComment for more details.
*/
enum aiComponent enum aiComponent
{ {
//! Normal vectors //! Normal vectors
@ -220,9 +224,13 @@ enum aiComponent
//! cameras are removed. //! cameras are removed.
aiComponent_CAMERAS = 0x200, aiComponent_CAMERAS = 0x200,
//! Removes all meshes (aiScene::mMeshes). The //! Removes all meshes (aiScene::mMeshes).
//! #AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set in aiScene::mFlags.
aiComponent_MESHES = 0x400, aiComponent_MESHES = 0x400,
//! Removes all materials. One default material will
//! be generated, so aiScene::mNumMaterials will be 1.
//! This makes no real sense without the aiComponent_TEXTURES flag.
aiComponent_MATERIALS = 0x800
}; };
#define aiComponent_COLORSn(n) (1u << (n+20u)) #define aiComponent_COLORSn(n) (1u << (n+20u))

View File

@ -120,6 +120,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# define AI_FORCE_INLINE __forceinline # define AI_FORCE_INLINE __forceinline
#else #else
# define ASSIMP_API # define ASSIMP_API
# define AI_FORCE_INLINE inline # define AI_FORCE_INLINE inline

View File

@ -70,6 +70,8 @@ enum aiLightSourceType
//! A spot light source emmits light in a specific //! A spot light source emmits light in a specific
//! angle. It has a position and a direction it is pointing to. //! angle. It has a position and a direction it is pointing to.
//! A good example for a spot light is a light spot in
//! sport arenas.
aiLightSource_SPOT = 0x3 aiLightSource_SPOT = 0x3
}; };
@ -82,7 +84,7 @@ enum aiLightSourceType
*/ */
struct aiLight struct aiLight
{ {
/** The name of the light sources. /** The name of the light source.
* *
* There must be a node in the scenegraph with the same name. * There must be a node in the scenegraph with the same name.
* This node specifies the position of the light in the scene * This node specifies the position of the light in the scene
@ -91,20 +93,23 @@ struct aiLight
aiString mName; aiString mName;
/** The type of the light source. /** The type of the light source.
*
* aiLightSource_UNDEFINED is nto a valid value for this member.
*/ */
aiLightSourceType mType; aiLightSourceType mType;
/** Position of the light source in space. Relative to the /** Position of the light source in space. Relative to the
* node corresponding to the light. * transformation of the node corresponding to the light.
* *
* The position is undefined for directional lights. * The position is undefined for directional lights.
*/ */
aiVector3D mPosition; aiVector3D mPosition;
/** Direction of the light source in space. Relative to the /** Direction of the light source in space. Relative to the
* node corresponding to the light. * transformation of the node corresponding to the light.
* *
* The direction is undefined for point lights. * The direction is undefined for point lights. The vector
* may be normalized, but it needn't.
*/ */
aiVector3D mDirection; aiVector3D mDirection;
@ -115,7 +120,7 @@ struct aiLight
* @code * @code
* Atten = 1/( att0 + att1 * d + att2 * d*d) * Atten = 1/( att0 + att1 * d + att2 * d*d)
* @endcode * @endcode
* This member corresponds to the att01 variable in the equation. * This member corresponds to the att0 variable in the equation.
*/ */
float mAttenuationConstant; float mAttenuationConstant;
@ -126,7 +131,7 @@ struct aiLight
* @code * @code
* Atten = 1/( att0 + att1 * d + att2 * d*d) * Atten = 1/( att0 + att1 * d + att2 * d*d)
* @endcode * @endcode
* This member corresponds to the att02 variable in the equation. * This member corresponds to the att1 variable in the equation.
*/ */
float mAttenuationLinear; float mAttenuationLinear;
@ -137,28 +142,33 @@ struct aiLight
* @code * @code
* Atten = 1/( att0 + att1 * d + att2 * d*d) * Atten = 1/( att0 + att1 * d + att2 * d*d)
* @endcode * @endcode
* This member corresponds to the att03 variable in the equation. * This member corresponds to the att2 variable in the equation.
*/ */
float mAttenuationQuadratic; float mAttenuationQuadratic;
/** Diffuse color of the light source /** Diffuse color of the light source
* *
* The color has no alpha component which wouldn't make * The diffuse light color is multiplied with the diffuse
* sense for light sources. * material color to obtain the final color that contributes
* to the diffuse shading term.
*/ */
aiColor3D mColorDiffuse; aiColor3D mColorDiffuse;
/** Specular color of the light source /** Specular color of the light source
* *
* The color has no alpha component which wouldn't make * The specular light color is multiplied with the specular
* sense for light sources. * material color to obtain the final color that contributes
* to the specular shading term.
*/ */
aiColor3D mColorSpecular; aiColor3D mColorSpecular;
/** Ambient color of the light source /** Ambient color of the light source
* *
* The color has no alpha component which wouldn't make * The ambient light color is multiplied with the ambient
* sense for light sources. * material color to obtain the final color that contributes
* to the ambient shading term. Most renderers will ignore
* this value it, is just a remaining of the fixed-function pipeline
* that is still supported by quite many file formats.
*/ */
aiColor3D mColorAmbient; aiColor3D mColorAmbient;
@ -168,18 +178,19 @@ struct aiLight
* angle. The angle is given in radians. It is 2PI for point * angle. The angle is given in radians. It is 2PI for point
* lights and undefined for directional lights. * lights and undefined for directional lights.
*/ */
float mAngleOuterCone; float mAngleInnerCone;
/** Outer angle of a spot light's light cone. /** Outer angle of a spot light's light cone.
* *
* The spot light does not affect objects outside this angle. * The spot light does not affect objects outside this angle.
* The angle is given in radians. It is 2PI for point lights and * The angle is given in radians. It is 2PI for point lights and
* undefined for directional lights. * undefined for directional lights. The outer angle must be
* greater than or equal to the inner angle.
* It is assumed that the application uses a smooth * It is assumed that the application uses a smooth
* interpolation between the inner and the outer cone of the * interpolation between the inner and the outer cone of the
* spot light. * spot light.
*/ */
float mAngleInnerCone; float mAngleOuterCone;
#ifdef __cplusplus #ifdef __cplusplus
@ -188,8 +199,8 @@ struct aiLight
, mAttenuationConstant (0.f) , mAttenuationConstant (0.f)
, mAttenuationLinear (1.f) , mAttenuationLinear (1.f)
, mAttenuationQuadratic (0.f) , mAttenuationQuadratic (0.f)
, mAngleOuterCone ((float)AI_MATH_TWO_PI)
, mAngleInnerCone ((float)AI_MATH_TWO_PI) , mAngleInnerCone ((float)AI_MATH_TWO_PI)
, mAngleOuterCone ((float)AI_MATH_TWO_PI)
{ {
} }
@ -201,4 +212,4 @@ struct aiLight
#endif #endif
#endif // !! __AI_LIGHT_H_INC__ #endif // !! __AI_LIGHT_H_INC__

View File

@ -240,6 +240,20 @@ struct aiMaterialProperty
* is never 0 * is never 0
*/ */
char* mData; char* mData;
#ifdef __cplusplus
aiMaterialProperty()
{
mData = NULL;
}
~aiMaterialProperty()
{
delete[] mData;
}
#endif
}; };
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -173,21 +173,15 @@ inline void aiMatrix4x4::Decompose (aiVector3D& scaling, aiQuaternion& rotation,
// and remove all scaling from the matrix // and remove all scaling from the matrix
if(scaling.x) if(scaling.x)
{ {
vRows[0].x /= scaling.x; vRows[0] /= scaling.x;
vRows[0].y /= scaling.x;
vRows[0].z /= scaling.x;
} }
if(scaling.y) if(scaling.y)
{ {
vRows[1].x /= scaling.y; vRows[1] /= scaling.y;
vRows[1].y /= scaling.y;
vRows[1].z /= scaling.y;
} }
if(scaling.z) if(scaling.z)
{ {
vRows[2].x /= scaling.z; vRows[2] /= scaling.z;
vRows[2].y /= scaling.z;
vRows[2].z /= scaling.z;
} }
// build a 3x3 rotation matrix // build a 3x3 rotation matrix
@ -217,7 +211,7 @@ inline void aiMatrix4x4::FromEulerAngles(float x, float y, float z)
{ {
aiMatrix4x4& _this = *this; aiMatrix4x4& _this = *this;
const float A = ::cos(x); const float A = ::cos(x);
const float B = ::sin(x); const float B = ::sin(x);
const float C = ::cos(y); const float C = ::cos(y);
const float D = ::sin(y); const float D = ::sin(y);

View File

@ -41,8 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file Declares the data structures in which the imported geometry is /** @file Declares the data structures in which the imported geometry is
returned by ASSIMP: aiMesh, aiFace and aiBone data structures. */ returned by ASSIMP: aiMesh, aiFace and aiBone data structures. */
#ifndef AI_MESH_H_INC #ifndef __AI_MESH_H_INC__
#define AI_MESH_H_INC #define __AI_MESH_H_INC__
#include "aiTypes.h" #include "aiTypes.h"
@ -58,7 +58,6 @@ extern "C" {
* Point and line primitives are rarely used and are NOT supported. However, * Point and line primitives are rarely used and are NOT supported. However,
* a load could pass them as degenerated triangles. * a load could pass them as degenerated triangles.
*/ */
// ---------------------------------------------------------------------------
struct aiFace struct aiFace
{ {
//! Number of indices defining this face. 3 for a triangle, >3 for polygon //! Number of indices defining this face. 3 for a triangle, >3 for polygon
@ -130,7 +129,6 @@ struct aiFace
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** A single influence of a bone on a vertex. /** A single influence of a bone on a vertex.
*/ */
// ---------------------------------------------------------------------------
struct aiVertexWeight struct aiVertexWeight
{ {
//! Index of the vertex which is influenced by the bone. //! Index of the vertex which is influenced by the bone.
@ -161,7 +159,6 @@ struct aiVertexWeight
* in the frame hierarchy and by which it can be addressed by animations. * in the frame hierarchy and by which it can be addressed by animations.
* In addition it has a number of influences on vertices. * In addition it has a number of influences on vertices.
*/ */
// ---------------------------------------------------------------------------
struct aiBone struct aiBone
{ {
//! The name of the bone. //! The name of the bone.
@ -218,7 +215,6 @@ struct aiBone
* \note Some internal structures expect (and assert) this value * \note Some internal structures expect (and assert) this value
* to be at least 4 * to be at least 4
*/ */
// ---------------------------------------------------------------------------
# define AI_MAX_NUMBER_OF_COLOR_SETS 0x4 # define AI_MAX_NUMBER_OF_COLOR_SETS 0x4
#endif // !! AI_MAX_NUMBER_OF_COLOR_SETS #endif // !! AI_MAX_NUMBER_OF_COLOR_SETS
@ -234,7 +230,6 @@ struct aiBone
* \note Some internal structures expect (and assert) this value * \note Some internal structures expect (and assert) this value
* to be at least 4 * to be at least 4
*/ */
// ---------------------------------------------------------------------------
# define AI_MAX_NUMBER_OF_TEXTURECOORDS 0x4 # define AI_MAX_NUMBER_OF_TEXTURECOORDS 0x4
// NOTE (Aramis): If you change these values, make sure that you also // NOTE (Aramis): If you change these values, make sure that you also
@ -248,33 +243,34 @@ struct aiBone
#endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS #endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS
#define AI_MESH_SMOOTHING_ANGLE_NOT_SET (10e10f)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Enumerates the types of geometric primitives supported by Assimp. /** Enumerates the types of geometric primitives supported by Assimp.
*/ */
// ---------------------------------------------------------------------------
enum aiPrimitiveType enum aiPrimitiveType
{ {
/** A point primitive. /** A point primitive.
*
* This is just a single vertex in the virtual world, * This is just a single vertex in the virtual world,
* #aiFace contains just one index for such a primitive. * #aiFace contains just one index for such a primitive.
*/ */
aiPrimitiveType_POINT = 0x1, aiPrimitiveType_POINT = 0x1,
/** A line primitive. /** A line primitive.
*
* This is a line defined through a start and an end position. * This is a line defined through a start and an end position.
* #aiFace contains exactly two indices for such a primitive. * #aiFace contains exactly two indices for such a primitive.
*/ */
aiPrimitiveType_LINE = 0x2, aiPrimitiveType_LINE = 0x2,
/** A triangular primitive. /** A triangular primitive.
*
* A triangle consists of three indices. * A triangle consists of three indices.
*/ */
aiPrimitiveType_TRIANGLE = 0x4, aiPrimitiveType_TRIANGLE = 0x4,
/** A higher-level polygon with more than 3 edges. /** A higher-level polygon with more than 3 edges.
*
* A triangle is a polygon, but polygon in this context means * A triangle is a polygon, but polygon in this context means
* "all polygons that are not triangles". The "Triangulate"-Step * "all polygons that are not triangles". The "Triangulate"-Step
* is provided for your convinience, it splits all polygons in * is provided for your convinience, it splits all polygons in
@ -298,9 +294,9 @@ enum aiPrimitiveType
* *
* A Mesh uses only a single material which is referenced by a material ID. * A Mesh uses only a single material which is referenced by a material ID.
* \note The mPositions member is not optional, although a Has()-Method is * \note The mPositions member is not optional, although a Has()-Method is
* provided for it. * provided for it. However, positions *could* be missing if the
* AI_SCENE_FLAGS_INCOMPLETE flag is set in aiScene::mFlags.
*/ */
// ---------------------------------------------------------------------------
struct aiMesh struct aiMesh
{ {
/** Bitwise combination of the members of the #aiPrimitiveType enum. /** Bitwise combination of the members of the #aiPrimitiveType enum.
@ -328,14 +324,23 @@ struct aiMesh
/** Vertex normals. /** Vertex normals.
* The array contains normalized vectors, NULL if not present. * The array contains normalized vectors, NULL if not present.
* The array is mNumVertices in size. * The array is mNumVertices in size. Normals are undefined for
* point and line primitives. A mesh consisting of points and
* lines only may not have normal vectors. Meshes with mixed
* primitive types (i.e. lines and triangles) may have normals,
* but the normals for vertices that are only referenced by
* point or line primitives are undefined and set to QNaN.
*/ */
C_STRUCT aiVector3D* mNormals; C_STRUCT aiVector3D* mNormals;
/** Vertex tangents. /** Vertex tangents.
* The tangent of a vertex points in the direction of the positive * The tangent of a vertex points in the direction of the positive
* X texture axis. The array contains normalized vectors, NULL if * X texture axis. The array contains normalized vectors, NULL if
* not present. The array is mNumVertices in size. * not present. The array is mNumVertices in size. A mesh consisting
* of points and lines only may not have normal vectors. Meshes with
* mixed primitive types (i.e. lines and triangles) may have
* normals, but the normals for vertices that are only referenced by
* point or line primitives are undefined and set to QNaN.
* @note If the mesh contains tangents, it automatically also * @note If the mesh contains tangents, it automatically also
* contains bitangents. * contains bitangents.
*/ */
@ -368,6 +373,7 @@ struct aiMesh
* or cube maps). If the value is 2 for a given channel n, the * or cube maps). If the value is 2 for a given channel n, the
* component p.z of mTextureCoords[n][p] is set to 0.0f. * component p.z of mTextureCoords[n][p] is set to 0.0f.
* If the value is 1 for a given channel, p.y is set to 0.0f, too. * If the value is 1 for a given channel, p.y is set to 0.0f, too.
* If this value is 0, 2 should be assumed.
* @note 4D coords are not supported * @note 4D coords are not supported
*/ */
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
@ -375,7 +381,8 @@ struct aiMesh
/** The faces the mesh is contstructed from. /** The faces the mesh is contstructed from.
* Each face referres to a number of vertices by their indices. * Each face referres to a number of vertices by their indices.
* This array is always present in a mesh, its size is given * This array is always present in a mesh, its size is given
* in mNumFaces. * in mNumFaces. If the AI_SCENE_FLAGS_NON_VERBOSE_FORMAT
* is NOT set each face references an unique set of vertices.
*/ */
C_STRUCT aiFace* mFaces; C_STRUCT aiFace* mFaces;
@ -422,7 +429,7 @@ struct aiMesh
//! Deletes all storage allocated for the mesh //! Deletes all storage allocated for the mesh
~aiMesh() ~aiMesh()
{ {
if ( mNumVertices) // fix to make this work for invalid scenes, too if ( mNumVertices ) // fix to make this work for invalid scenes, too
{ {
delete [] mVertices; delete [] mVertices;
delete [] mNormals; delete [] mNormals;
@ -433,7 +440,7 @@ struct aiMesh
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++)
delete [] mColors[a]; delete [] mColors[a];
} }
if ( mNumBones) // fix to make this work for invalid scenes, too if ( mNumBones && mBones) // fix to make this work for invalid scenes, too
{ {
for( unsigned int a = 0; a < mNumBones; a++) for( unsigned int a = 0; a < mNumBones; a++)
delete mBones[a]; delete mBones[a];
@ -461,6 +468,9 @@ struct aiMesh
{ return mNormals != NULL; } { return mNormals != NULL; }
//! Check whether the mesh contains tangent and bitangent vectors //! Check whether the mesh contains tangent and bitangent vectors
//! It is not possible that it contains tangents and no bitangents
//! (or the other way round). The existence of one of them
//! implies that the second is there, too.
inline bool HasTangentsAndBitangents() const inline bool HasTangentsAndBitangents() const
{ return mTangents != NULL && mBitangents != NULL; } { return mTangents != NULL && mBitangents != NULL; }
@ -478,7 +488,7 @@ struct aiMesh
//! \param pIndex Index of the texture coordinates set //! \param pIndex Index of the texture coordinates set
inline bool HasTextureCoords( unsigned int pIndex) const inline bool HasTextureCoords( unsigned int pIndex) const
{ {
if( pIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) if( pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS)
return false; return false;
else else
return mTextureCoords[pIndex] != NULL; return mTextureCoords[pIndex] != NULL;
@ -494,5 +504,5 @@ struct aiMesh
} }
#endif #endif
#endif // AI_MESH_H_INC #endif // __AI_MESH_H_INC

View File

@ -40,13 +40,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/** @file Defines the data structures in which the imported scene is returned. */ /** @file Defines the data structures in which the imported scene is returned. */
#ifndef AI_SCENE_H_INC #ifndef __AI_SCENE_H_INC__
#define AI_SCENE_H_INC #define __AI_SCENE_H_INC__
#include "aiTypes.h" #include "aiTypes.h"
#include "aiMesh.h"
#include "aiMaterial.h"
#include "aiTexture.h" #include "aiTexture.h"
#include "aiMesh.h"
#include "aiLight.h"
#include "aiCamera.h"
#include "aiMaterial.h"
#include "aiAnim.h" #include "aiAnim.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -80,8 +82,8 @@ struct aiNode
/** The number of child nodes of this node. */ /** The number of child nodes of this node. */
unsigned int mNumChildren; unsigned int mNumChildren;
/** The child nodes of this node. NULL if mNumChildren is 0. */
/** The child nodes of this node. NULL if mNumChildren is 0. */
C_STRUCT aiNode** mChildren; C_STRUCT aiNode** mChildren;
/** The number of meshes of this node. */ /** The number of meshes of this node. */
@ -113,8 +115,9 @@ struct aiNode
/** Destructor */ /** Destructor */
~aiNode() ~aiNode()
{ {
// delete al children recursively // delete all children recursively
if (mChildren) // fix to make the d'tor work for invalid scenes, too // to make sure we won't crash if the data is invalid ...
if (mChildren && mNumChildren)
{ {
for( unsigned int a = 0; a < mNumChildren; a++) for( unsigned int a = 0; a < mNumChildren; a++)
delete mChildren[a]; delete mChildren[a];
@ -122,17 +125,66 @@ struct aiNode
} }
delete [] mMeshes; delete [] mMeshes;
} }
/** Searches for a node with a specific name, beginning at this
* nodes. Normally you will call this method on the root node
* of the scene.
*
* @param name Name to seach for
* @return NULL or a valid Node if the search was successful.
*/
inline aiNode* FindNode(const aiString& name)
{
if (mName == name)return this;
for (unsigned int i = 0; i < mNumChildren;++i)
{
aiNode* p = mChildren[i]->FindNode(name);
if (p)return p;
}
// there is definitely no sub node with this name
return NULL;
}
#endif // __cplusplus #endif // __cplusplus
}; };
//! @def AI_SCENE_FLAGS_ANIM_SKELETON_ONLY
//! Specifies that no full model but only an animation skeleton has been
//! imported. There are no materials in this case. There are no
//! textures in this case. But there is a node graph, animation channels
//! and propably meshes with bones. Validation of meshes is less strict
//! with this flag, so be careful.
#define AI_SCENE_FLAGS_ANIM_SKELETON_ONLY 0x1
// ---------------------------------------------------------------------------
/** @def AI_SCENE_FLAGS_INCOMPLETE
* Specifies that the scene data structure that was imported is not complete.
* This flag bypasses some internal validations and allows the import
* of animation skeletons, material libraries or camera animation paths
* using Assimp. Most applications won't support such data.
*/
#define AI_SCENE_FLAGS_INCOMPLETE 0x1
/** @def AI_SCENE_FLAGS_VALIDATED
* This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS)
* if the validation is successful. In a validated scene you can be sure that
* any cross references in the data structure (e.g. vertex indices) are valid.
*/
#define AI_SCENE_FLAGS_VALIDATED 0x2
/** @def AI_SCENE_FLAGS_VALIDATION_WARNING
* This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS)
* if the validation is successful but some issues have been found.
* This can for example mean that a texture that does not exist is referenced
* by a material or that the bone weights for a vertex don't sum to 1.0 ... .
* In most cases you should still be able to use the import. This flag could
* be useful for applications which don't capture Assimp's log output.
*/
#define AI_SCENE_FLAGS_VALIDATION_WARNING 0x4
/** @def AI_SCENE_FLAGS_NON_VERBOSE_FORMAT
* This flag is currently only set by the aiProcess_JoinIdenticalVertices step.
* It indicates that the vertices of the output meshes aren't in the internal
* verbose format anymore. In the verbose format all vertices are unique,
* no vertex is ever referenced by more than one face.
*/
#define AI_SCENE_FLAGS_NON_VERBOSE_FORMAT 0x8
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** The root structure of the imported data. /** The root structure of the imported data.
@ -143,15 +195,20 @@ struct aiNode
struct aiScene struct aiScene
{ {
/** Any combination of the AI_SCENE_FLAGS_XXX flags */ /** Any combination of the AI_SCENE_FLAGS_XXX flags. By default
* this value is 0, no flags are set. Most applications will
* want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE
* bit set.
*/
unsigned int mFlags; unsigned int mFlags;
/** The root node of the hierarchy. /** The root node of the hierarchy.
* *
* There will always be at least the root node if the import * There will always be at least the root node if the import
* was successful. Presence of further nodes depends on the * was successful (and no special flags have been set).
* format and content of the imported file. * Presence of further nodes depends on the format and content
* of the imported file.
*/ */
C_STRUCT aiNode* mRootNode; C_STRUCT aiNode* mRootNode;
@ -163,7 +220,9 @@ struct aiScene
/** The array of meshes. /** The array of meshes.
* *
* Use the indices given in the aiNode structure to access * Use the indices given in the aiNode structure to access
* this array. The array is mNumMeshes in size. * this array. The array is mNumMeshes in size. If the
* AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always
* be at least ONE material.
*/ */
C_STRUCT aiMesh** mMeshes; C_STRUCT aiMesh** mMeshes;
@ -175,7 +234,9 @@ struct aiScene
/** The array of materials. /** The array of materials.
* *
* Use the index given in each aiMesh structure to access this * Use the index given in each aiMesh structure to access this
* array. The array is mNumMaterials in size. * array. The array is mNumMaterials in size. If the
* AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always
* be at least ONE material.
*/ */
C_STRUCT aiMaterial** mMaterials; C_STRUCT aiMaterial** mMaterials;
@ -200,10 +261,36 @@ struct aiScene
* *
* Not many file formats embedd their textures into the file. * Not many file formats embedd their textures into the file.
* An example is Quake's MDL format (which is also used by * An example is Quake's MDL format (which is also used by
* some GameStudio™ versions) * some GameStudio versions)
*/ */
C_STRUCT aiTexture** mTextures; C_STRUCT aiTexture** mTextures;
/** The number of light sources in the scene. Light sources
are fully optional, in most cases this attribute will be 0 */
unsigned int mNumLights;
/** The array of light sources.
*
* All light sources imported from the given file are
* listed here. The array is mNumLights in size.
*/
C_STRUCT aiLight** mLights;
/** The number of cameras in the scene. Cameras
are fully optional, in most cases this attribute will be 0 */
unsigned int mNumCameras;
/** The array of cameras.
*
* All cameras imported from the given file are listed here.
* The array is mNumCameras in size. The first camera in the
* array (if existing) is the default camera view into
* the scene.
*/
C_STRUCT aiCamera** mCameras;
#ifdef __cplusplus #ifdef __cplusplus
//! Default constructor //! Default constructor
@ -215,6 +302,8 @@ struct aiScene
mNumMaterials = 0; mMaterials = NULL; mNumMaterials = 0; mMaterials = NULL;
mNumAnimations = 0; mAnimations = NULL; mNumAnimations = 0; mAnimations = NULL;
mNumTextures = 0; mTextures = NULL; mNumTextures = 0; mTextures = NULL;
mNumCameras = 0; mCameras = NULL;
mNumLights = 0; mLights = NULL;
mFlags = 0; mFlags = 0;
} }
@ -223,31 +312,74 @@ struct aiScene
{ {
// delete all subobjects recursively // delete all subobjects recursively
delete mRootNode; delete mRootNode;
if (mNumMeshes) // fix to make the d'tor work for invalid scenes, too
// To make sure we won't crash if the data is invalid it's
// mich better to check whether both mNumXXX and mXXX are
// valid instead of relying on just one of them.
if (mNumMeshes && mMeshes)
{ {
for( unsigned int a = 0; a < mNumMeshes; a++) for( unsigned int a = 0; a < mNumMeshes; a++)
delete mMeshes[a]; delete mMeshes[a];
delete [] mMeshes; delete [] mMeshes;
} }
if (mNumMaterials) // fix to make the d'tor work for invalid scenes, too if (mNumMaterials && mMaterials)
{ {
for( unsigned int a = 0; a < mNumMaterials; a++) for( unsigned int a = 0; a < mNumMaterials; a++)
delete mMaterials[a]; delete mMaterials[a];
delete [] mMaterials; delete [] mMaterials;
} }
if (mNumAnimations) // fix to make the d'tor work for invalid scenes, too if (mNumAnimations && mAnimations)
{ {
for( unsigned int a = 0; a < mNumAnimations; a++) for( unsigned int a = 0; a < mNumAnimations; a++)
delete mAnimations[a]; delete mAnimations[a];
delete [] mAnimations; delete [] mAnimations;
} }
if (mNumTextures) // fix to make the d'tor work for invalid scenes, too if (mNumTextures && mTextures)
{ {
for( unsigned int a = 0; a < mNumTextures; a++) for( unsigned int a = 0; a < mNumTextures; a++)
delete mTextures[a]; delete mTextures[a];
delete [] mTextures; delete [] mTextures;
} }
if (mNumLights && mLights)
{
for( unsigned int a = 0; a < mNumLights; a++)
delete mLights[a];
delete [] mLights;
}
if (mNumCameras && mCameras)
{
for( unsigned int a = 0; a < mNumCameras; a++)
delete mCameras[a];
delete [] mCameras;
}
} }
//! Check whether the scene contains meshes
//! Unless no special scene flags are set this will always be true.
inline bool HasMeshes() const
{ return mMeshes != NULL; }
//! Check whether the scene contains materials
//! Unless no special scene flags are set this will always be true.
inline bool HasMaterials() const
{ return mMaterials != NULL; }
//! Check whether the scene contains lights
inline bool HasLights() const
{ return mLights != NULL; }
//! Check whether the scene contains textures
inline bool HasTextures() const
{ return mTextures != NULL; }
//! Check whether the scene contains cameras
inline bool HasCameras() const
{ return mCameras != NULL; }
//! Check whether the scene contains animations
inline bool HasAnimations() const
{ return mAnimations != NULL; }
#endif // __cplusplus #endif // __cplusplus
}; };
@ -255,4 +387,4 @@ struct aiScene
} }
#endif #endif
#endif // AI_SCENE_H_INC #endif // __AI_SCENE_H_INC__

View File

@ -69,15 +69,8 @@ extern "C" {
# define AI_MAKE_EMBEDDED_TEXNAME(_n_) "*" # _n_ # define AI_MAKE_EMBEDDED_TEXNAME(_n_) "*" # _n_
#endif #endif
// ugly compiler dependent packing stuff
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) #include "./Compiler/pushpack1.h"
# pragma pack(push,1)
# define PACK_STRUCT
#elif defined( __GNUC__ )
# define PACK_STRUCT __attribute__((packed))
#else
# error Compiler not supported. Never do this again.
#endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Helper structure to represent a texel in ARGB8888 format /** Helper structure to represent a texel in ARGB8888 format
@ -87,11 +80,9 @@ extern "C" {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
struct aiTexel struct aiTexel
{ {
unsigned char b; uint8_t b,g,r,a;
unsigned char g;
unsigned char r;
unsigned char a;
#ifdef __cplusplus
//! Comparison operator //! Comparison operator
bool operator== (const aiTexel& other) const bool operator== (const aiTexel& other) const
{ {
@ -105,14 +96,11 @@ struct aiTexel
return b != other.b || r != other.r || return b != other.b || r != other.r ||
g != other.g || a != other.a; g != other.g || a != other.a;
} }
#endif // __cplusplus
} PACK_STRUCT; } PACK_STRUCT;
// reset packing to the original value #include "./Compiler/poppack1.h"
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# pragma pack( pop )
#endif
#undef PACK_STRUCT
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Helper structure to describe an embedded texture /** Helper structure to describe an embedded texture
@ -164,12 +152,14 @@ struct aiTexture
// Construction // Construction
aiTexture () aiTexture ()
: mWidth(0), mHeight(0), pcData(NULL) : mWidth (0)
, mHeight (0)
, pcData (NULL)
{ {
achFormatHint[0] = '\0'; achFormatHint[0] = 0;
achFormatHint[1] = '\0'; achFormatHint[1] = 0;
achFormatHint[2] = '\0'; achFormatHint[2] = 0;
achFormatHint[3] = '\0'; achFormatHint[3] = 0;
} }
// Destruction // Destruction

View File

@ -114,19 +114,15 @@ struct aiColor3D
aiColor3D operator*(const aiColor3D& c) const aiColor3D operator*(const aiColor3D& c) const
{return aiColor3D(r*c.r,g*c.g,b*c.b);} {return aiColor3D(r*c.r,g*c.g,b*c.b);}
aiColor3D operator*(float f) aiColor3D operator*(float f) const
{return aiColor3D(r*f,g*f,b*f);} {return aiColor3D(r*f,g*f,b*f);}
// ugly subscript operator ... should better use an union, but inline float operator[](unsigned int i) const {return *(&r + i);}
// hopefully the compiler will optimize the switch away. inline float& operator[](unsigned int i) {return *(&r + i);}
inline float& operator[] (unsigned int sub)
inline bool IsBlack() const
{ {
switch (sub) return !r && !g && !b;
{
case 0: return (float&)r;
case 1: return (float&)g;
default: return (float&)b;
};
} }
#endif // !__cplusplus #endif // !__cplusplus
@ -156,17 +152,13 @@ struct aiColor4D
bool operator != (const aiColor4D& other) const bool operator != (const aiColor4D& other) const
{return r != other.r || g != other.g || b != other.b || a != other.a;} {return r != other.r || g != other.g || b != other.b || a != other.a;}
// ugly subscript operator ... should better use an union, but inline float operator[](unsigned int i) const {return *(&r + i);}
// hopefully the compiler will optimize the switch away. inline float& operator[](unsigned int i) {return *(&r + i);}
inline float& operator[] (unsigned int sub)
inline bool IsBlack() const
{ {
switch (sub) // the alpha component doesn't care here. black is black.
{ return !r && !g && !b;
case 0: return (float&)r;
case 1: return (float&)g;
case 2: return (float&)b;
default: return (float&)a;
};
} }
#endif // !__cplusplus #endif // !__cplusplus

View File

@ -433,8 +433,7 @@ int CreateAssetData()
g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]); g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]);
} }
if (g_pcAsset->pcScene->mMeshes[i]->mPrimitiveTypes == aiPrimitiveType_LINE || if (g_pcAsset->pcScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
g_pcAsset->pcScene->mMeshes[i]->mPrimitiveTypes == aiPrimitiveType_POINT)
{ {
continue; continue;
} }

View File

@ -675,6 +675,14 @@
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"
> >

View File

@ -726,6 +726,10 @@
RelativePath="..\..\include\BoostWorkaround\boost\format.hpp" RelativePath="..\..\include\BoostWorkaround\boost\format.hpp"
> >
</File> </File>
<File
RelativePath="..\..\include\BoostWorkaround\boost\multi_array.hpp"
>
</File>
<File <File
RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp" RelativePath="..\..\include\BoostWorkaround\boost\scoped_ptr.hpp"
> >
@ -867,6 +871,10 @@
RelativePath="..\..\code\StandardShapes.h" RelativePath="..\..\code\StandardShapes.h"
> >
</File> </File>
<File
RelativePath="..\..\code\StreamReader.h"
>
</File>
<File <File
RelativePath="..\..\code\StringComparison.h" RelativePath="..\..\code\StringComparison.h"
> >