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;
std::string extension = pFile.substr( pos);
return !(extension.length() != 3 || extension[0] != '.' ||
extension[1] != 'a' && extension[1] != 'A' ||
extension[2] != 'c' && extension[2] != 'C');
for( std::string::iterator it = extension.begin(); it != extension.end(); ++it)
*it = tolower( *it);
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.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);
float f = 1.f - matSrc.trans;
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[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
{
@ -501,7 +519,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
face.mNumIndices = 2;
face.mIndices = new unsigned int[2];
face.mIndices[0] = cur++;
face.mIndices[1] = cur;
face.mIndices[1] = cur++;
// copy vertex positions
*vertices++ = object.vertices[(*it2).first];
@ -660,6 +678,7 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
if (1 != rootObjects.size())delete root;
// build output arrays
ai_assert(!meshes.empty());
pScene->mNumMeshes = (unsigned int)meshes.size();
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));

View File

@ -162,7 +162,7 @@ protected:
*/
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
#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 <list>
#include <map>
@ -16,7 +79,10 @@
#include <iostream>
#include <algorithm>
// *******************************************************************
// public ASSIMP headers
// *******************************************************************
#include "../include/DefaultLogger.h"
#include "../include/IOStream.h"
#include "../include/IOSystem.h"
@ -24,21 +90,32 @@
#include "../include/aiPostProcess.h"
#include "../include/assimp.hpp"
// *******************************************************************
// internal headers that are nearly always required
// *******************************************************************
#include "MaterialSystem.h"
#include "StringComparison.h"
#include "ByteSwap.h"
#include "StreamReader.h"
#include "qnan.h"
// *******************************************************************
// boost headers - take them from the workaround dir if possible
// *******************************************************************
#ifdef ASSIMP_BUILD_BOOST_WORKAROUND
# include "../include/BoostWorkaround/boost/scoped_ptr.hpp"
# include "../include/BoostWorkaround/boost/format.hpp"
# include "../include/BoostWorkaround/boost/multi_array.hpp"
#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/format.hpp>
# include <boost/multi_array.hpp>
#endif

View File

@ -178,7 +178,7 @@ protected:
* a face is unique. Or the other way round: a vertex index may
* 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 material must be there<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];
// check whether we need four indices here
if (vp[3] != vp[2])
// check whether we need four,three or two indices here
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];
for (unsigned int a = 0; a < face.mNumIndices;++a)
@ -323,7 +327,7 @@ bool DXFImporter::ParseEntities()
{
if (!groupCode)
{
if (!::strcmp(cursor,"3DFACE"))
if (!::strcmp(cursor,"3DFACE") || !::strcmp(cursor,"LINE") || !::strcmp(cursor,"3DLINE"))
if (!Parse3DFace()) return false; else bRepeat = true;
if (!::strcmp(cursor,"POLYLINE") || !::strcmp(cursor,"LWPOLYLINE"))
@ -524,6 +528,10 @@ bool DXFImporter::Parse3DFace()
aiVector3D vip[4]; // -- vectors are initialized to zero
aiColor4D clr(g_clrInvalid);
// this is also used for for parsing line entities
bool bThird = false;
while (GetNextToken())
{
switch (groupCode)
@ -556,22 +564,28 @@ bool DXFImporter::Parse3DFace()
case 31: vip[1].z = fast_atof(cursor);break;
// 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
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
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
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
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
case 33: vip[3].z = fast_atof(cursor);break;
case 33: vip[3].z = fast_atof(cursor);
bThird = true;break;
// color
case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break;
@ -579,6 +593,8 @@ bool DXFImporter::Parse3DFace()
if (ret)break;
}
if (!bThird)vip[2] = vip[1];
// use a default layer if necessary
if (!out)SetDefaultLayer(out);
@ -592,3 +608,5 @@ bool DXFImporter::Parse3DFace()
out->vColors.push_back(clr);
return ret;
}

View File

@ -74,7 +74,10 @@ protected:
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<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
// 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
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 (!b)return "All vectors are identical";
if (!b)
return "All vectors are identical";
return NULL;
}

View File

@ -97,11 +97,31 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
{
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++)
{
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* 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 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];
// compute per-face normals but store them per-vertex
for( unsigned int a = 0; a < pMesh->mNumFaces; 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* pV2 = &pMesh->mVertices[face.mIndices[1]];
@ -167,9 +187,10 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
aiVector3D pcNor;
for (unsigned int a = 0; a < verticesFound.size(); ++a)
{
register unsigned int vidx = verticesFound[a];
pcNor += pMesh->mNormals[vidx];
const aiVector3D& v = pMesh->mNormals[verticesFound[a]];
if (is_not_qnan(v.x))pcNor += v;
}
pcNor.Normalize();
// write the smoothed normal back to all affected normals
@ -183,7 +204,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
}
else
{
const float fLimit = cos(configMaxAngle);
const float fLimit = ::cos(configMaxAngle);
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
{
// get all vertices that share this one ...
@ -192,16 +213,18 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
aiVector3D pcNor;
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
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;
pcNor += pMesh->mNormals[vidx];
pcNor += v;
}
pcNor.Normalize();
pcNew[i] = pcNor;
pcNew[i] = pcNor.Normalize();
}
}

View File

@ -176,10 +176,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# include "SortByPTypeProcess.h"
//#endif
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor.
Importer::Importer() :
@ -276,6 +276,9 @@ Importer::Importer() :
mPostProcessingSteps.push_back( new RemoveVCProcess());
#endif
#if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
mPostProcessingSteps.push_back( new PretransformVertices());
#endif
#if (!defined AI_BUILD_NO_TRIANGULATE_PROCESS)
mPostProcessingSteps.push_back( new TriangulateProcess());
#endif
@ -294,9 +297,6 @@ Importer::Importer() :
#if (!defined AI_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
mPostProcessingSteps.push_back( new OptimizeGraphProcess());
#endif
#if (!defined AI_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
mPostProcessingSteps.push_back( new PretransformVertices());
#endif
#if (!defined AI_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
mPostProcessingSteps.push_back( new FixInfacingNormalsProcess());
#endif
@ -488,10 +488,16 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
// validate the flags
ai_assert(ValidateFlags(pFlags));
// put a large try block around everything to catch all std::exception's
// that might be thrown by STL containers or by new().
// ImportErrorException's are throw by ourselves and caught elsewhere.
try
{
// check whether this Importer instance has already loaded
// a scene. In this case we need to delete the old one
if (this->mScene)
{
DefaultLogger::get()->debug("The previous scene has been deleted");
delete mScene;
this->mScene = NULL;
}
@ -524,10 +530,12 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
}
// 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
@ -541,10 +549,6 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
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");
@ -578,9 +582,6 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
}
#endif // ! DEBUG
}
#ifdef _DEBUG
if (bExtraVerbose)mScene->mFlags &= ~0x80000000;
#endif // ! DEBUG
}
// if failed, extract the error string
else if( !mScene)mErrorString = imp->GetErrorText();
@ -588,6 +589,21 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
// clear any data allocated by post-process steps
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
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.
void ImproveCacheLocalityProcess::Execute( aiScene* pScene)
{
if (!pScene->mNumMeshes)
{
DefaultLogger::get()->debug("ImproveCacheLocalityProcess skipped; there are no meshes");
return;
}
DefaultLogger::get()->debug("ImproveCacheLocalityProcess begin");
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 ->
// - there must be vertices and faces (haha)
// - 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 ...
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;
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)
{
bool bInCache = false;

View File

@ -109,6 +109,8 @@ void JoinVerticesProcess::Execute( aiScene* pScene)
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))
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);
mBuffer = &mBuffer2[0];
m_pcHeader = (const MD2::Header*)mBuffer;
m_pcHeader = (BE_NCONST MD2::Header*)mBuffer;
#ifdef AI_BUILD_BIG_ENDIAN
@ -229,7 +229,7 @@ void MD2Importer::InternReadFile( const std::string& pFile,
pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
// 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);
pcFrame += configFrameID;
@ -239,11 +239,11 @@ void MD2Importer::InternReadFile( const std::string& pFile,
m_pcHeader + m_pcHeader->offsetTriangles);
// 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);
// 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
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];
float u,v;
// the texture coordinates are absolute values but we
// need relative values between 0 and 1
u = pcTexCoords[iIndex].s / fDivisorU;
v = pcTexCoords[iIndex].t / fDivisorV;
pcOut.x = u;
pcOut.y = 1.0f - v; // FIXME: Is this correct for MD2?
pcOut.x = pcTexCoords[iIndex].s / fDivisorU;
pcOut.y = 1.f- pcTexCoords[iIndex].t / fDivisorV;
}
}
// FIX: flip the face order for use with OpenGL

View File

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

View File

@ -107,7 +107,7 @@ void MD5Importer::InternReadFile(
if (!bHadMD5Mesh && !bHadMD5Anim)
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)

View File

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

View File

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

View File

@ -74,11 +74,20 @@ bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
if( pos == std::string::npos)return false;
std::string extension = pFile.substr( pos);
return !(extension.length() != 4 || extension[0] != '.' ||
extension[1] != 'n' && extension[1] != 'N' ||
// extensions: enff and nff
if (!extension.length() || extension[0] != '.')return false;
if (extension.length() == 4)
{
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');
}
// ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_FLOAT(f) \
@ -87,9 +96,9 @@ bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
// ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_TRIPLE(v) \
AI_NFF_PARSE_FLOAT(v.x) \
AI_NFF_PARSE_FLOAT(v.y) \
AI_NFF_PARSE_FLOAT(v.z)
AI_NFF_PARSE_FLOAT(v[0]) \
AI_NFF_PARSE_FLOAT(v[1]) \
AI_NFF_PARSE_FLOAT(v[2])
// ------------------------------------------------------------------------------------------------
#define AI_NFF_PARSE_SHAPE_INFORMATION() \
@ -125,31 +134,170 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// the pointers below easier.
std::vector<MeshInfo> meshes;
std::vector<MeshInfo> meshesWithNormals;
std::vector<MeshInfo> meshesWithUVCoords;
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* currentMesh = NULL;
MeshInfo* currentMeshWithUVCoords = NULL;
ShadingInfo s; // current material info
// degree of tesselation
unsigned int iTesselation = 4;
char line[4096];
const char* sz;
unsigned int sphere = 0,cylinder = 0,cone = 0,numNamed = 0,
dodecahedron = 0,octahedron = 0,tetrahedron = 0, hexahedron = 0;
// some temporary variables we need to parse the file
unsigned int sphere = 0,
cylinder = 0,
cone = 0,
numNamed = 0,
dodecahedron = 0,
octahedron = 0,
tetrahedron = 0,
hexahedron = 0;
// lights imported from the file
std::vector<Light> lights;
// check whether this is the NFF2 file format
if (TokenMatch(buffer,"nff",3))
{
// 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))
{
if ('p' == line[0])
sz = line;
if (TokenMatch(sz,"version",7))
{
DefaultLogger::get()->info("NFF (alt.) file format: " + std::string(sz));
}
else if (TokenMatch(sz,"viewpos",7))
{
AI_NFF_PARSE_TRIPLE(camPos);
hasCam = true;
}
else if (TokenMatch(sz,"viewdir",7))
{
AI_NFF_PARSE_TRIPLE(camLookAt);
hasCam = true;
}
else if (TokenMatch(sz,"//",2))
{
// comment ...
DefaultLogger::get()->info(sz);
}
else if (!IsSpace(*sz))
{
// must be a new object
meshes.push_back(MeshInfo(PatchType_Simple));
MeshInfo& mesh = meshes.back();
if (!GetNextLine(buffer,line))
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read number of vertices");break;}
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);
tempPositions.push_back(v);
}
if (!GetNextLine(buffer,line))
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read number of faces");break;}
if (!num)throw new ImportErrorException("NFF2: There are zero vertices");
SkipSpaces(line,&sz);
num = ::strtol10(sz,&sz);
mesh.faces.reserve(num);
for (unsigned int i = 0; i < num; ++i)
{
if (!GetNextLine(buffer,line))
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read faces");break;}
SkipSpaces(line,&sz);
unsigned int idx, numIdx = ::strtol10(sz,&sz);
if (numIdx)
{
mesh.faces.push_back(numIdx);
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
if ('p' == line[1])
else if ('p' == line[1])
{
if (meshesWithNormals.empty())
{
meshesWithNormals.push_back(MeshInfo(true));
meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
currentMeshWithNormals = &meshesWithNormals.back();
}
@ -160,7 +308,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
{
if (meshes.empty())
{
meshes.push_back(MeshInfo(false));
meshes.push_back(MeshInfo(PatchType_Simple));
currentMesh = &meshes.back();
}
sz = &line[1];out = currentMesh;
@ -170,10 +318,14 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// ---- flip the face order
out->vertices.resize(out->vertices.size()+m);
if (out == currentMeshWithNormals)
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))
@ -186,64 +338,136 @@ void NFFImporter::InternReadFile( const std::string& pFile,
AI_NFF_PARSE_TRIPLE(v);
out->vertices[out->vertices.size()-n-1] = v;
if (out == currentMeshWithNormals)
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 ('f' == line[0] && IsSpace(line[1]))
else if (TokenMatch(sz,"f",1))
{
SkipSpaces(&line[1],&sz);
float d;
// read just the RGB colors, the rest is ignored for the moment
sz = fast_atof_move(sz, (float&)s.color.r);
// 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);
sz = fast_atof_move(sz, (float&)s.color.g);
SkipSpaces(&sz);
sz = fast_atof_move(sz, (float&)s.color.b);
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 = NULL;
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)
{
if ((*it).bHasNormals)currentMeshWithNormals = &(*it);
else currentMesh = &(*it);
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(false));
meshes.push_back(MeshInfo(PatchType_Simple));
currentMesh = &meshes.back();
currentMesh->shader = s;
}
if (!currentMeshWithNormals)
{
meshesWithNormals.push_back(MeshInfo(true));
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
else if (TokenMatch(sz,"l",1))
{
lights.push_back(Light());
Light& light = lights.back();
AI_NFF_PARSE_TRIPLE(light.position);
AI_NFF_PARSE_FLOAT (light.intensity);
AI_NFF_PARSE_TRIPLE(light.color);
}
// 's' - sphere
else if ('s' == line[0] && IsSpace(line[1]))
else if (TokenMatch(sz,"s",1))
{
meshesLocked.push_back(MeshInfo(false,true));
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[1];
AI_NFF_PARSE_SHAPE_INFORMATION();
// we don't need scaling or translation here - we do it in the node's transform
@ -254,13 +478,12 @@ void NFFImporter::InternReadFile( const std::string& pFile,
::sprintf(currentMesh.name,"sphere_%i",sphere++);
}
// 'dod' - dodecahedron
else if (!strncmp(line,"dod",3) && IsSpace(line[3]))
else if (TokenMatch(sz,"dod",3))
{
meshesLocked.push_back(MeshInfo(false,true));
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[4];
AI_NFF_PARSE_SHAPE_INFORMATION();
// we don't need scaling or translation here - we do it in the node's transform
@ -272,13 +495,12 @@ void NFFImporter::InternReadFile( const std::string& pFile,
}
// 'oct' - octahedron
else if (!strncmp(line,"oct",3) && IsSpace(line[3]))
else if (TokenMatch(sz,"oct",3))
{
meshesLocked.push_back(MeshInfo(false,true));
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[4];
AI_NFF_PARSE_SHAPE_INFORMATION();
// we don't need scaling or translation here - we do it in the node's transform
@ -290,13 +512,12 @@ void NFFImporter::InternReadFile( const std::string& pFile,
}
// 'tet' - tetrahedron
else if (!strncmp(line,"tet",3) && IsSpace(line[3]))
else if (TokenMatch(sz,"tet",3))
{
meshesLocked.push_back(MeshInfo(false,true));
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[4];
AI_NFF_PARSE_SHAPE_INFORMATION();
// we don't need scaling or translation here - we do it in the node's transform
@ -308,13 +529,12 @@ void NFFImporter::InternReadFile( const std::string& pFile,
}
// 'hex' - hexahedron
else if (!strncmp(line,"hex",3) && IsSpace(line[3]))
else if (TokenMatch(sz,"hex",3))
{
meshesLocked.push_back(MeshInfo(false,true));
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[4];
AI_NFF_PARSE_SHAPE_INFORMATION();
// we don't need scaling or translation here - we do it in the node's transform
@ -324,21 +544,13 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// generate a name for the mesh
::sprintf(currentMesh.name,"hexahedron_%i",hexahedron++);
}
// 'tess' - tesselation
else if (!strncmp(line,"tess",4) && IsSpace(line[4]))
{
sz = &line[5];SkipSpaces(&sz);
iTesselation = strtol10(sz);
}
// 'c' - cone
else if ('c' == line[0] && IsSpace(line[1]))
else if (TokenMatch(sz,"c",1))
{
meshesLocked.push_back(MeshInfo(false,true));
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
MeshInfo& currentMesh = meshes.back();
currentMesh.shader = s;
sz = &line[1];
aiVector3D center1, center2; float radius1, radius2;
AI_NFF_PARSE_TRIPLE(center1);
AI_NFF_PARSE_FLOAT(radius1);
@ -359,18 +571,67 @@ void NFFImporter::InternReadFile( const std::string& pFile,
::sprintf(currentMesh.name,"cone_%i",cone++);
else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
}
// '#' - comment
// 'tess' - tesselation
else if (TokenMatch(sz,"tess",4))
{
SkipSpaces(&sz);
iTesselation = strtol10(sz);
}
// 'from' - camera position
else if (TokenMatch(sz,"from",4))
{
AI_NFF_PARSE_TRIPLE(camPos);
hasCam = true;
}
// 'at' - camera look-at vector
else if (TokenMatch(sz,"at",2))
{
AI_NFF_PARSE_TRIPLE(camLookAt);
hasCam = true;
}
// 'up' - camera up vector
else if (TokenMatch(sz,"up",2))
{
AI_NFF_PARSE_TRIPLE(camUp);
hasCam = true;
}
// 'angle' - (half?) camera field of view
else if (TokenMatch(sz,"angle",5))
{
AI_NFF_PARSE_FLOAT(angle);
hasCam = true;
}
// 'resolution' - used to compute the screen aspect
else if (TokenMatch(sz,"resolution",10))
{
AI_NFF_PARSE_FLOAT(resolution.x);
AI_NFF_PARSE_FLOAT(resolution.y);
hasCam = true;
}
// 'pb' - bezier patch. Not supported yet
else if (TokenMatch(sz,"pb",2))
{
DefaultLogger::get()->error("NFF: Encountered unsupported ID: bezier patch");
}
// 'pn' - NURBS. Not supported yet
else if (TokenMatch(sz,"pn",2) || TokenMatch(sz,"pnn",3))
{
DefaultLogger::get()->error("NFF: Encountered unsupported ID: NURBS");
}
// '' - 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
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(),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
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.
aiNode* const root = new aiNode();
root->mName.Set("<NFF_Root>");
root->mNumChildren = numNamed;
root->mNumChildren = numNamed + (hasCam ? 1 : 0) + (unsigned int) lights.size();
root->mNumMeshes = pScene->mNumMeshes-numNamed;
aiNode** ppcChildren;
@ -398,6 +659,49 @@ void NFFImporter::InternReadFile( const std::string& pFile,
if (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");
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
@ -436,14 +740,38 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// copy vertex positions
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
::memcpy(mesh->mVertices,&src.vertices[0],sizeof(aiVector3D)*mesh->mNumVertices);
if (src.bHasNormals)
::memcpy(mesh->mVertices,&src.vertices[0],
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());
// copy normal vectors
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
@ -459,8 +787,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
}
// generate a material for the mesh
MaterialHelper* pcMat = (MaterialHelper*)(pScene->
mMaterials[m] = new MaterialHelper());
MaterialHelper* pcMat = (MaterialHelper*)(pScene->mMaterials[m] = new MaterialHelper());
mesh->mMaterialIndex = m++;
@ -468,8 +795,16 @@ void NFFImporter::InternReadFile( const std::string& pFile,
s.Set(AI_DEFAULT_MATERIAL_NAME);
pcMat->AddProperty(&s, AI_MATKEY_NAME);
pcMat->AddProperty(&src.shader.color,1,AI_MATKEY_COLOR_DIFFUSE);
pcMat->AddProperty(&src.shader.color,1,AI_MATKEY_COLOR_SPECULAR);
aiColor3D c = src.shader.color * src.shader.diffuse;
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;
}

View File

@ -78,7 +78,7 @@ protected:
*/
void GetExtensionList(std::string& append)
{
append.append("*.nff");
append.append("*.nff;*.enff");
}
// -------------------------------------------------------------------
@ -95,35 +95,71 @@ private:
struct 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;
//float diffuse, specular; --- not implemented yet
aiColor3D color;
float diffuse, specular, ambient, refracti;
std::string texFile;
// shininess is ignored for the moment
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
struct MeshInfo
{
MeshInfo(bool bHN, bool bL = false)
: bHasNormals(bHN)
MeshInfo(PatchType _pType, bool bL = false)
: pType(_pType)
, bLocked(bL)
{
name[0] = '\0'; // by default meshes are unnamed
}
ShadingInfo shader;
bool bHasNormals, bLocked;
PatchType pType;
bool bLocked;
// for spheres, cones and cylinders: center point of the object
aiVector3D center, radius;
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;
};
};

View File

@ -109,8 +109,6 @@ void OFFImporter::InternReadFile( const std::string& pFile,
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = 1 ];
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];
std::vector<aiVector3D> tempPositions(numVertices);
@ -131,21 +129,43 @@ void OFFImporter::InternReadFile( const std::string& pFile,
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))
{
DefaultLogger::get()->error("OFF: The number of faces in the header is incorrect");
break;
}
unsigned int idx;sz = line;SkipSpaces(&sz);
if(!(faces->mNumIndices = strtol10(sz,&sz)) || faces->mNumIndices > 100)
sz = line;SkipSpaces(&sz);
if(!(faces->mNumIndices = strtol10(sz,&sz)) || faces->mNumIndices > 9)
{
DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed");
--mesh->mNumFaces;
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];
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");
idx = numVertices-1;
}
faces->mIndices[m] = p++;
*verts++ = tempPositions[idx];
}
++i;
++faces;
}

View File

@ -48,23 +48,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
// some array offsets
#define AI_PTVS_VERTEX 0x0
#define AI_PTVS_FACE 0x1
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
PretransformVertices::PretransformVertices()
{
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
PretransformVertices::~PretransformVertices()
{
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool PretransformVertices::IsActive( unsigned int pFlags) const
{
return (pFlags & aiProcess_PreTransformVertices) != 0;
}
// ------------------------------------------------------------------------------------------------
// Count the number of nodes
unsigned int CountNodes( aiNode* pcNode )
@ -76,14 +83,20 @@ unsigned int CountNodes( aiNode* pcNode )
}
return iRet;
}
// ------------------------------------------------------------------------------------------------
// Get a bitwise combination identifying the vertex format of a mesh
unsigned int GetMeshVFormat(aiMesh* pcMesh)
{
if (0xdeadbeef == pcMesh->mNumUVComponents[0])
return pcMesh->mNumUVComponents[1];
// the vertex format is stored in aiMesh::mBones for later retrieval.
// 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;
ai_assert(NULL != pcMesh->mVertices);
// normals
if (pcMesh->HasNormals())iRet |= 0x1;
@ -92,23 +105,25 @@ unsigned int GetMeshVFormat(aiMesh* pcMesh)
// texture coordinates
unsigned int p = 0;
ai_assert(4 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
ai_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
while (pcMesh->HasTextureCoords(p))
{
iRet |= (0x100 << p++);
iRet |= (0x100 << p);
if (3 == pcMesh->mNumUVComponents[p])
iRet |= (0x1000 << p++);
iRet |= (0x10000 << p);
++p;
}
// vertex colors
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
pcMesh->mNumUVComponents[0] = 0xdeadbeef;
pcMesh->mNumUVComponents[1] = iRet;
pcMesh->mBones = (aiBone**)iRet;
return iRet;
}
// ------------------------------------------------------------------------------------------------
// Count the number of vertices in the whole scene and a given
// material index
@ -132,9 +147,6 @@ void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
return;
}
#define AI_PTVS_VERTEX 0x0
#define AI_PTVS_FACE 0x1
// ------------------------------------------------------------------------------------------------
// Collect vertex/face data
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;
mWorldIT.Inverse().Transpose();
// TODO: implement Inverse() for aiMatrix3x3
aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
// copy normals, transform them to worldspace
for (unsigned int n = 0; n < pcMesh->mNumVertices;++n)
{
pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] =
mWorldIT * pcMesh->mNormals[n];
m * pcMesh->mNormals[n];
}
}
if (iVFormat & 0x2)
@ -185,7 +200,7 @@ void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
++p;
}
p = 0;
while (iVFormat & (0x10000 << p))
while (iVFormat & (0x1000000 << p))
{
// copy vertex colors
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
// aiFace destructor ...
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_FACE] += pcMesh->mNumFaces;
@ -225,6 +257,7 @@ void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
}
return;
}
// ------------------------------------------------------------------------------------------------
// Get a list of all vertex formats that occur for a given material index
// The output list contains duplicate elements
@ -245,13 +278,14 @@ void GetVFormatList( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
}
return;
}
// ------------------------------------------------------------------------------------------------
// Compute the absolute transformation matrices of each node
void ComputeAbsoluteTransform( aiNode* pcNode )
{
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)
@ -260,18 +294,37 @@ void ComputeAbsoluteTransform( aiNode* pcNode )
}
return;
}
// ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data.
void PretransformVertices::Execute( aiScene* pScene)
{
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
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
std::vector<aiMesh*> apcOutMeshes;
apcOutMeshes.reserve(pScene->mNumMaterials*2);
apcOutMeshes.reserve(pScene->mNumMaterials<<1u);
std::list<unsigned int> aiVFormats;
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
{
@ -306,12 +359,12 @@ void PretransformVertices::Execute( aiScene* pScene)
while ((*j) & (0x100 << iFaces))
{
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;
iFaces++;
}
iFaces = 0;
while ((*j) & (0x10000 << iFaces))
while ((*j) & (0x1000000 << iFaces))
pcMesh->mColors[iFaces] = new aiColor4D[iVertices];
// fill the mesh ...
@ -324,28 +377,66 @@ void PretransformVertices::Execute( aiScene* pScene)
// remove all animations from the scene
for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
delete pScene->mAnimations[i];
delete[] pScene->mAnimations;
pScene->mAnimations = NULL;
pScene->mNumAnimations = 0;
// now delete all meshes in the scene and build a new mesh list
for (unsigned int i = 0; i < pScene->mNumMeshes;++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;
pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
}
for (unsigned int i = 0; i < pScene->mNumMeshes;++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
// flat node graph with a root node and some level 1 children
delete pScene->mRootNode;
pScene->mRootNode = new aiNode();
pScene->mRootNode->mName.Set("<dummy_root>");
if (1 == pScene->mNumMeshes)
if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras)
{
pScene->mRootNode->mNumMeshes = 1;
pScene->mRootNode->mMeshes = new unsigned int[1];
@ -353,22 +444,59 @@ void PretransformVertices::Execute( aiScene* pScene)
}
else
{
pScene->mRootNode->mNumChildren = pScene->mNumMeshes;
pScene->mRootNode->mChildren = new aiNode*[pScene->mNumMeshes];
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);
pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras;
aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
// 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->mMeshes = new unsigned int[1];
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->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 "
"vertices are in worldspace now");
// print statistics
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;
}

View File

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

View File

@ -185,7 +185,30 @@ void RemoveVCProcess::Execute( aiScene* pScene)
bHas = true;
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
if ( configDeleteFlags & aiComponent_LIGHTS)
{
@ -198,7 +221,7 @@ void RemoveVCProcess::Execute( aiScene* pScene)
}
// handle camneras
if ( configDeleteFlags & aiComponent_CAMERA)
if ( configDeleteFlags & aiComponent_CAMERAS)
{
// mask nodes for removal
MaskNodes(pScene->mRootNode,pScene->mLights,pScene->mNumLights,
@ -207,13 +230,12 @@ void RemoveVCProcess::Execute( aiScene* pScene)
bHas = true;
ArrayDelete(pScene->mCameras,pScene->mNumCameras);
}
#endif
// handle meshes
if (configDeleteFlags & aiComponent_MESHES)
{
bHas = true;
ArrayDelete(pScene->mMeshes,pScene->mNumMeshes);
pScene->mFlags |= AI_SCENE_FLAGS_ANIM_SKELETON_ONLY;
}
else
{
@ -232,7 +254,6 @@ void RemoveVCProcess::Execute( aiScene* pScene)
// MSB>>1 means: NO, DON'T REMOVE ME (Veto)
if (bMasked)
{
#if 0
if (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,
AI_RC_UINT_MSB_2);
}
#endif
if (!(configDeleteFlags & aiComponent_BONEWEIGHTS))
{
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
@ -259,15 +279,14 @@ void RemoveVCProcess::Execute( aiScene* pScene)
std::list<aiNode*> dummy;
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
// !0 animations (+ the AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag) OR
// !0 meshes
if (!pScene->mNumAnimations && !pScene->mNumMeshes)
// now check whether the result is still a full scene
if (!pScene->mNumMeshes || !pScene->mNumMaterials)
{
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.");
@ -291,6 +310,11 @@ bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh)
{
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
if (configDeleteFlags & aiComponent_NORMALS && pMesh->mNormals)
{

View File

@ -156,7 +156,7 @@ void SMDImporter::InternReadFile(
}
// set the flag in the scene structure which indicates
// 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())
@ -179,7 +179,7 @@ void SMDImporter::InternReadFile(
// compute absolute bone transformation matrices
ComputeAbsoluteBoneTransformations();
}
if (!(pScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY))
if (!(pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{
// create output meshes
CreateOutputMeshes();
@ -462,7 +462,7 @@ void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent)
void SMDImporter::CreateOutputNodes()
{
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
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
@ -475,7 +475,7 @@ void SMDImporter::CreateOutputNodes()
AddBoneChildren(pScene->mRootNode,(uint32_t)-1);
// if we have only one bone we can even remove the root node
if (pScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY &&
if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE &&
1 == pScene->mRootNode->mNumChildren)
{
aiNode* pcOldRoot = pScene->mRootNode;

View File

View File

@ -55,7 +55,7 @@ using namespace Assimp;
// Constructor to be privately used by Importer
DeterminePTypeHelperProcess ::DeterminePTypeHelperProcess()
{
// nothing to do here
bSpeedFlag = false;
}
// ------------------------------------------------------------------------------------------------
@ -73,84 +73,97 @@ bool DeterminePTypeHelperProcess::IsActive( unsigned int pFlags) const
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.
void DeterminePTypeHelperProcess::Execute( aiScene* pScene)
{
DefaultLogger::get()->debug("DeterminePTypeHelper begin");
for (unsigned int i = 0; i < pScene->mNumMeshes;++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)
{
bool bDeg = false;
for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
{
aiFace& face = mesh->mFaces[a];
switch (face.mNumIndices)
{
case 3u:
// 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:
// 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:
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
break;
default:
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
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.
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;
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
unsigned int num = 0;
if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) ++num;
if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) ++num;
if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) ++num;
if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) ++num;
if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT)
{
++aiNumMeshesPerPType[0];
++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)
{
@ -436,5 +473,17 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
::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 SetupProperties(const Importer* pImp);
private:
bool bSpeedFlag;
};
#if (!defined AI_BUILD_NO_SORTBYPTYPE_PROCESS)

View File

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

View File

@ -56,11 +56,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
#if _MSC_VER >= 1400
# define vsprintf vsprintf_s
# define sprintf sprintf_s
#endif
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
ValidateDSProcess::ValidateDSProcess()
@ -126,6 +121,103 @@ void ValidateDSProcess::ReportWarning(const char* msg,...)
va_end(args);
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.
void ValidateDSProcess::Execute( aiScene* pScene)
@ -133,107 +225,96 @@ void ValidateDSProcess::Execute( aiScene* pScene)
this->mScene = pScene;
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
if (pScene->mNumMeshes)
{
if (!pScene->mMeshes)
{
this->ReportError("aiScene::mMeshes is NULL (aiScene::mNumMeshes is %i)",
pScene->mNumMeshes);
has = true;
DoValidation(pScene->mMeshes,pScene->mNumMeshes,"mMeshes","mNumMeshes");
}
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{
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))
{
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
if (pScene->mNumAnimations)
{
if (!pScene->mAnimations)
{
this->ReportError("aiScene::mAnimations is NULL (aiScene::mNumAnimations is %i)",
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)
{
this->ReportError("aiScene::mNumAnimations is 0 and the "
"AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set.");
has = true;
DoValidation(pScene->mAnimations,pScene->mNumAnimations,
"mAnimations","mNumAnimations");
}
// validate all textures
if (pScene->mNumTextures)
// validate all cameras
if (pScene->mNumCameras)
{
if (!pScene->mTextures)
{
this->ReportError("aiScene::mTextures is NULL (aiScene::mNumTextures is %i)",
pScene->mNumTextures);
has = true;
DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras,
"mCameras","mNumCameras");
}
for (unsigned int i = 0; i < pScene->mNumTextures;++i)
// validate all lights
if (pScene->mNumLights)
{
if (!pScene->mTextures[i])
{
this->ReportError("aiScene::mTextures[%i] is NULL (aiScene::mNumTextures is %i)",
i,pScene->mNumTextures);
}
this->Validate(pScene->mTextures[i]);
}
has = true;
DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights,
"mLights","mNumLights");
}
// validate all materials
if (pScene->mNumMaterials)
{
if (!pScene->mMaterials)
has = true;
DoValidation(pScene->mCameras,pScene->mNumCameras,"mMaterials","mNumMaterials");
}
else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
{
this->ReportError("aiScene::mMaterials is NULL (aiScene::mNumMaterials is %i)",
pScene->mNumMaterials);
ReportError("aiScene::mNumMaterials is 0. At least one material must be there");
}
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
{
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");
}
// ------------------------------------------------------------------------------------------------
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)
{
@ -288,25 +369,20 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
if (!face.mIndices)this->ReportError("aiMesh::mFaces[%i].mIndices is NULL",i);
}
if (this->mScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY)
{
if (pMesh->mNumVertices || pMesh->mVertices ||
pMesh->mNumFaces || pMesh->mFaces)
{
this->ReportWarning("The mesh contains vertices and faces although "
"the AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set");
}
}
else
{
// positions must always be there ...
if (!pMesh->mNumVertices || !pMesh->mVertices)
if (!pMesh->mNumVertices || !pMesh->mVertices && !mScene->mFlags)
{
this->ReportError("The mesh contains no vertices");
}
// 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)
if (!pMesh->mNumFaces || !pMesh->mFaces && !mScene->mFlags)
{
this->ReportError("The mesh contains no faces");
}
@ -327,9 +403,9 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
// 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]])
if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && abRefList[face.mIndices[a]])
{
this->ReportError("aiMesh::mVertices[%i] is referenced twice - second "
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;
@ -352,7 +428,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
if (pMesh->HasTextureCoords(i))
{
this->ReportError("Texture coordinate channel %i is existing, "
ReportError("Texture coordinate channel %i is existing, "
"although the previous channel was NULL.",i);
}
}
@ -366,18 +442,18 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
if (pMesh->HasVertexColors(i))
{
this->ReportError("Vertex color channel %i is existing, "
ReportError("Vertex color channel %i is existing, "
"although the previous channel was NULL.",i);
}
}
}
// now validate all bones
if (pMesh->HasBones())
{
if (!pMesh->mBones)
{
this->ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)",
ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)",
pMesh->mNumBones);
}
float* afSum = NULL;
@ -397,7 +473,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
this->ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)",
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)
{
@ -414,7 +490,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
{
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;

View File

@ -146,9 +146,21 @@ protected:
*/
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
* @param pAnimation Input animation
* @param pAnimation Animation channel.
* @param pBoneAnim Input bone animation
*/
void Validate( const aiAnimation* pAnimation,
@ -168,9 +180,28 @@ protected:
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;
};
} // end of namespace Assimp
#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])
{
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);
}

View File

@ -74,7 +74,7 @@ all: $(TARGET)
$(TARGET): $(OBJECTS)
gcc -o $@ $(OBJECTS) -shared -lstdc++
%.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:
del *.o

View File

@ -67,6 +67,35 @@ struct aiCamera
*/
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.
*
* The field of view angle is the angle between the center
@ -105,7 +134,9 @@ struct aiCamera
#ifdef __cplusplus
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)
, mClipPlaneFar (1000.f)
, mAspect (0.f)

View File

@ -40,8 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @file Defines constants for configurable properties */
#ifndef AI_CONFIG_H_INC
#define AI_CONFIG_H_INC
#ifndef __AI_CONFIG_H_INC__
#define __AI_CONFIG_H_INC__
// ---------------------------------------------------------------------------
/** \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
* in degrees, so 180 is PI. The default value is
* 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"
@ -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
* 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
* large and contains RGB tripels for each of the 256 palette entries.
* The default value is colormap.lmp. If the file is nto found,
* a default palette is used.
* large and contains RGB triplets for each of the 256 palette entries.
* The default value is colormap.lmp. If the file is not found,
* a default palette (from Quake 1) is used.
* Property type: string.
*/
#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
{
//! Normal vectors
@ -220,9 +224,13 @@ enum aiComponent
//! cameras are removed.
aiComponent_CAMERAS = 0x200,
//! Removes all meshes (aiScene::mMeshes). The
//! #AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set in aiScene::mFlags.
//! Removes all meshes (aiScene::mMeshes).
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))

View File

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

View File

@ -70,6 +70,8 @@ enum aiLightSourceType
//! A spot light source emmits light in a specific
//! 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
};
@ -82,7 +84,7 @@ enum aiLightSourceType
*/
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.
* This node specifies the position of the light in the scene
@ -91,20 +93,23 @@ struct aiLight
aiString mName;
/** The type of the light source.
*
* aiLightSource_UNDEFINED is nto a valid value for this member.
*/
aiLightSourceType mType;
/** 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.
*/
aiVector3D mPosition;
/** 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;
@ -115,7 +120,7 @@ struct aiLight
* @code
* Atten = 1/( att0 + att1 * d + att2 * d*d)
* @endcode
* This member corresponds to the att01 variable in the equation.
* This member corresponds to the att0 variable in the equation.
*/
float mAttenuationConstant;
@ -126,7 +131,7 @@ struct aiLight
* @code
* Atten = 1/( att0 + att1 * d + att2 * d*d)
* @endcode
* This member corresponds to the att02 variable in the equation.
* This member corresponds to the att1 variable in the equation.
*/
float mAttenuationLinear;
@ -137,28 +142,33 @@ struct aiLight
* @code
* Atten = 1/( att0 + att1 * d + att2 * d*d)
* @endcode
* This member corresponds to the att03 variable in the equation.
* This member corresponds to the att2 variable in the equation.
*/
float mAttenuationQuadratic;
/** Diffuse color of the light source
*
* The color has no alpha component which wouldn't make
* sense for light sources.
* The diffuse light color is multiplied with the diffuse
* material color to obtain the final color that contributes
* to the diffuse shading term.
*/
aiColor3D mColorDiffuse;
/** Specular color of the light source
*
* The color has no alpha component which wouldn't make
* sense for light sources.
* The specular light color is multiplied with the specular
* material color to obtain the final color that contributes
* to the specular shading term.
*/
aiColor3D mColorSpecular;
/** Ambient color of the light source
*
* The color has no alpha component which wouldn't make
* sense for light sources.
* The ambient light color is multiplied with the ambient
* 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;
@ -168,18 +178,19 @@ struct aiLight
* angle. The angle is given in radians. It is 2PI for point
* lights and undefined for directional lights.
*/
float mAngleOuterCone;
float mAngleInnerCone;
/** Outer angle of a spot light's light cone.
*
* The spot light does not affect objects outside this angle.
* 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
* interpolation between the inner and the outer cone of the
* spot light.
*/
float mAngleInnerCone;
float mAngleOuterCone;
#ifdef __cplusplus
@ -188,8 +199,8 @@ struct aiLight
, mAttenuationConstant (0.f)
, mAttenuationLinear (1.f)
, mAttenuationQuadratic (0.f)
, mAngleOuterCone ((float)AI_MATH_TWO_PI)
, mAngleInnerCone ((float)AI_MATH_TWO_PI)
, mAngleOuterCone ((float)AI_MATH_TWO_PI)
{
}

View File

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

View File

@ -173,21 +173,15 @@ inline void aiMatrix4x4::Decompose (aiVector3D& scaling, aiQuaternion& rotation,
// and remove all scaling from the matrix
if(scaling.x)
{
vRows[0].x /= scaling.x;
vRows[0].y /= scaling.x;
vRows[0].z /= scaling.x;
vRows[0] /= scaling.x;
}
if(scaling.y)
{
vRows[1].x /= scaling.y;
vRows[1].y /= scaling.y;
vRows[1].z /= scaling.y;
vRows[1] /= scaling.y;
}
if(scaling.z)
{
vRows[2].x /= scaling.z;
vRows[2].y /= scaling.z;
vRows[2].z /= scaling.z;
vRows[2] /= scaling.z;
}
// build a 3x3 rotation matrix

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
returned by ASSIMP: aiMesh, aiFace and aiBone data structures. */
#ifndef AI_MESH_H_INC
#define AI_MESH_H_INC
#ifndef __AI_MESH_H_INC__
#define __AI_MESH_H_INC__
#include "aiTypes.h"
@ -58,7 +58,6 @@ extern "C" {
* Point and line primitives are rarely used and are NOT supported. However,
* a load could pass them as degenerated triangles.
*/
// ---------------------------------------------------------------------------
struct aiFace
{
//! 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.
*/
// ---------------------------------------------------------------------------
struct aiVertexWeight
{
//! 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 addition it has a number of influences on vertices.
*/
// ---------------------------------------------------------------------------
struct aiBone
{
//! The name of the bone.
@ -218,7 +215,6 @@ struct aiBone
* \note Some internal structures expect (and assert) this value
* to be at least 4
*/
// ---------------------------------------------------------------------------
# define AI_MAX_NUMBER_OF_COLOR_SETS 0x4
#endif // !! AI_MAX_NUMBER_OF_COLOR_SETS
@ -234,7 +230,6 @@ struct aiBone
* \note Some internal structures expect (and assert) this value
* to be at least 4
*/
// ---------------------------------------------------------------------------
# define AI_MAX_NUMBER_OF_TEXTURECOORDS 0x4
// NOTE (Aramis): If you change these values, make sure that you also
@ -248,33 +243,34 @@ struct aiBone
#endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS
#define AI_MESH_SMOOTHING_ANGLE_NOT_SET (10e10f)
// ---------------------------------------------------------------------------
/** Enumerates the types of geometric primitives supported by Assimp.
*/
// ---------------------------------------------------------------------------
enum aiPrimitiveType
{
/** A point primitive.
*
* This is just a single vertex in the virtual world,
* #aiFace contains just one index for such a primitive.
*/
aiPrimitiveType_POINT = 0x1,
/** A line primitive.
*
* This is a line defined through a start and an end position.
* #aiFace contains exactly two indices for such a primitive.
*/
aiPrimitiveType_LINE = 0x2,
/** A triangular primitive.
*
* A triangle consists of three indices.
*/
aiPrimitiveType_TRIANGLE = 0x4,
/** A higher-level polygon with more than 3 edges.
*
* A triangle is a polygon, but polygon in this context means
* "all polygons that are not triangles". The "Triangulate"-Step
* 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.
* \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
{
/** Bitwise combination of the members of the #aiPrimitiveType enum.
@ -328,14 +324,23 @@ struct aiMesh
/** Vertex normals.
* 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;
/** Vertex tangents.
* The tangent of a vertex points in the direction of the positive
* 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
* contains bitangents.
*/
@ -368,6 +373,7 @@ struct aiMesh
* 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.
* 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
*/
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
@ -375,7 +381,8 @@ struct aiMesh
/** The faces the mesh is contstructed from.
* Each face referres to a number of vertices by their indices.
* 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;
@ -433,7 +440,7 @@ struct aiMesh
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; 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++)
delete mBones[a];
@ -461,6 +468,9 @@ struct aiMesh
{ return mNormals != NULL; }
//! 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
{ return mTangents != NULL && mBitangents != NULL; }
@ -478,7 +488,7 @@ struct aiMesh
//! \param pIndex Index of the texture coordinates set
inline bool HasTextureCoords( unsigned int pIndex) const
{
if( pIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS)
if( pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS)
return false;
else
return mTextureCoords[pIndex] != NULL;
@ -494,5 +504,5 @@ struct aiMesh
}
#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. */
#ifndef AI_SCENE_H_INC
#define AI_SCENE_H_INC
#ifndef __AI_SCENE_H_INC__
#define __AI_SCENE_H_INC__
#include "aiTypes.h"
#include "aiMesh.h"
#include "aiMaterial.h"
#include "aiTexture.h"
#include "aiMesh.h"
#include "aiLight.h"
#include "aiCamera.h"
#include "aiMaterial.h"
#include "aiAnim.h"
#ifdef __cplusplus
@ -80,8 +82,8 @@ struct aiNode
/** The number of child nodes of this node. */
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;
/** The number of meshes of this node. */
@ -113,8 +115,9 @@ struct aiNode
/** Destructor */
~aiNode()
{
// delete al children recursively
if (mChildren) // fix to make the d'tor work for invalid scenes, too
// delete all children recursively
// to make sure we won't crash if the data is invalid ...
if (mChildren && mNumChildren)
{
for( unsigned int a = 0; a < mNumChildren; a++)
delete mChildren[a];
@ -122,17 +125,66 @@ struct aiNode
}
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
};
//! @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.
@ -143,15 +195,20 @@ struct aiNode
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;
/** The root node of the hierarchy.
*
* There will always be at least the root node if the import
* was successful. Presence of further nodes depends on the
* format and content of the imported file.
* was successful (and no special flags have been set).
* Presence of further nodes depends on the format and content
* of the imported file.
*/
C_STRUCT aiNode* mRootNode;
@ -163,7 +220,9 @@ struct aiScene
/** The array of meshes.
*
* 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;
@ -175,7 +234,9 @@ struct aiScene
/** The array of materials.
*
* 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;
@ -200,10 +261,36 @@ struct aiScene
*
* Not many file formats embedd their textures into the file.
* An example is Quake's MDL format (which is also used by
* some GameStudio™ versions)
* some GameStudio versions)
*/
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
//! Default constructor
@ -215,6 +302,8 @@ struct aiScene
mNumMaterials = 0; mMaterials = NULL;
mNumAnimations = 0; mAnimations = NULL;
mNumTextures = 0; mTextures = NULL;
mNumCameras = 0; mCameras = NULL;
mNumLights = 0; mLights = NULL;
mFlags = 0;
}
@ -223,31 +312,74 @@ struct aiScene
{
// delete all subobjects recursively
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++)
delete mMeshes[a];
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++)
delete mMaterials[a];
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++)
delete mAnimations[a];
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++)
delete mTextures[a];
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
};
@ -255,4 +387,4 @@ struct aiScene
}
#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_
#endif
// ugly compiler dependent packing stuff
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# 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
#include "./Compiler/pushpack1.h"
// ---------------------------------------------------------------------------
/** Helper structure to represent a texel in ARGB8888 format
@ -87,11 +80,9 @@ extern "C" {
// ---------------------------------------------------------------------------
struct aiTexel
{
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char a;
uint8_t b,g,r,a;
#ifdef __cplusplus
//! Comparison operator
bool operator== (const aiTexel& other) const
{
@ -105,14 +96,11 @@ struct aiTexel
return b != other.b || r != other.r ||
g != other.g || a != other.a;
}
#endif // __cplusplus
} PACK_STRUCT;
// reset packing to the original value
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# pragma pack( pop )
#endif
#undef PACK_STRUCT
#include "./Compiler/poppack1.h"
// ---------------------------------------------------------------------------
/** Helper structure to describe an embedded texture
@ -164,12 +152,14 @@ struct aiTexture
// Construction
aiTexture ()
: mWidth(0), mHeight(0), pcData(NULL)
: mWidth (0)
, mHeight (0)
, pcData (NULL)
{
achFormatHint[0] = '\0';
achFormatHint[1] = '\0';
achFormatHint[2] = '\0';
achFormatHint[3] = '\0';
achFormatHint[0] = 0;
achFormatHint[1] = 0;
achFormatHint[2] = 0;
achFormatHint[3] = 0;
}
// Destruction

View File

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

View File

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

View File

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

View File

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