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
This commit is contained in:
@@ -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);
|
||||
|
||||
matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS);
|
||||
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*));
|
||||
|
||||
@@ -162,7 +162,7 @@ protected:
|
||||
*/
|
||||
void GetExtensionList(std::string& append)
|
||||
{
|
||||
append.append("*.ac");
|
||||
append.append("*.ac;*.acc");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]];
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,105 +488,121 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags
|
||||
// validate the flags
|
||||
ai_assert(ValidateFlags(pFlags));
|
||||
|
||||
// check whether this Importer instance has already loaded
|
||||
// a scene. In this case we need to delete the old one
|
||||
if (this->mScene)
|
||||
// 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
|
||||
{
|
||||
delete mScene;
|
||||
this->mScene = NULL;
|
||||
}
|
||||
|
||||
// first check if the file is accessable at all
|
||||
if( !mIOHandler->Exists( pFile))
|
||||
{
|
||||
mErrorString = "Unable to open file \"" + pFile + "\".";
|
||||
DefaultLogger::get()->error(mErrorString);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find an worker class which can handle the file
|
||||
BaseImporter* imp = NULL;
|
||||
for( unsigned int a = 0; a < mImporter.size(); a++)
|
||||
{
|
||||
if( mImporter[a]->CanRead( pFile, mIOHandler))
|
||||
// check whether this Importer instance has already loaded
|
||||
// a scene. In this case we need to delete the old one
|
||||
if (this->mScene)
|
||||
{
|
||||
imp = mImporter[a];
|
||||
break;
|
||||
DefaultLogger::get()->debug("The previous scene has been deleted");
|
||||
delete mScene;
|
||||
this->mScene = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// put a proper error message if no suitable importer was found
|
||||
if( !imp)
|
||||
{
|
||||
mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
|
||||
DefaultLogger::get()->error(mErrorString);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// dispatch the reading to the worker class for this format
|
||||
imp->SetupProperties( this );
|
||||
mScene = imp->ReadFile( pFile, mIOHandler);
|
||||
|
||||
// if successful, apply all active post processing steps to the imported data
|
||||
if( mScene)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (bExtraVerbose)
|
||||
// first check if the file is accessable at all
|
||||
if( !mIOHandler->Exists( pFile))
|
||||
{
|
||||
mErrorString = "Unable to open file \"" + pFile + "\".";
|
||||
DefaultLogger::get()->error(mErrorString);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find an worker class which can handle the file
|
||||
BaseImporter* imp = NULL;
|
||||
for( unsigned int a = 0; a < mImporter.size(); a++)
|
||||
{
|
||||
if( mImporter[a]->CanRead( pFile, mIOHandler))
|
||||
{
|
||||
imp = mImporter[a];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// put a proper error message if no suitable importer was found
|
||||
if( !imp)
|
||||
{
|
||||
mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
|
||||
DefaultLogger::get()->error(mErrorString);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// dispatch the reading to the worker class for this format
|
||||
DefaultLogger::get()->info("Found a matching importer for this file format");
|
||||
imp->SetupProperties( this );
|
||||
mScene = imp->ReadFile( pFile, mIOHandler);
|
||||
|
||||
// if successful, apply all active post processing steps to the imported data
|
||||
DefaultLogger::get()->info("Import succesful, entering postprocessing-steps");
|
||||
if( mScene)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (bExtraVerbose)
|
||||
{
|
||||
#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS)
|
||||
|
||||
DefaultLogger::get()->error("Extra verbose mode not available, library"
|
||||
" wasn't build with the ValidateDS-Step");
|
||||
DefaultLogger::get()->error("Extra verbose mode not available, library"
|
||||
" wasn't build with the ValidateDS-Step");
|
||||
#endif
|
||||
|
||||
|
||||
pFlags |= aiProcess_ValidateDataStructure;
|
||||
|
||||
// use the MSB to tell the ValidateDS-Step that e're in extra verbose mode
|
||||
// TODO: temporary solution, clean up later
|
||||
mScene->mFlags |= 0x80000000;
|
||||
}
|
||||
#else
|
||||
if (bExtraVerbose)DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
|
||||
#endif // ! DEBUG
|
||||
for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++)
|
||||
{
|
||||
BaseProcess* process = mPostProcessingSteps[a];
|
||||
if( process->IsActive( pFlags))
|
||||
{
|
||||
process->SetupProperties( this );
|
||||
process->ExecuteOnScene ( this );
|
||||
pFlags |= aiProcess_ValidateDataStructure;
|
||||
}
|
||||
if( !mScene)break;
|
||||
#else
|
||||
if (bExtraVerbose)DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
|
||||
#endif // ! DEBUG
|
||||
for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++)
|
||||
{
|
||||
BaseProcess* process = mPostProcessingSteps[a];
|
||||
if( process->IsActive( pFlags))
|
||||
{
|
||||
process->SetupProperties( this );
|
||||
process->ExecuteOnScene ( this );
|
||||
}
|
||||
if( !mScene)break;
|
||||
#ifdef _DEBUG
|
||||
|
||||
#ifndef AI_BUILD_NO_VALIDATEDS_PROCESS
|
||||
continue;
|
||||
continue;
|
||||
#endif
|
||||
|
||||
// if the extra verbose mode is active execute the
|
||||
// VaidateDataStructureStep again after each step
|
||||
if (bExtraVerbose && a)
|
||||
{
|
||||
DefaultLogger::get()->debug("Extra verbose: revalidating data structures");
|
||||
((ValidateDSProcess*)mPostProcessingSteps[0])->ExecuteOnScene (this);
|
||||
if( !mScene)
|
||||
// if the extra verbose mode is active execute the
|
||||
// VaidateDataStructureStep again after each step
|
||||
if (bExtraVerbose && a)
|
||||
{
|
||||
DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures");
|
||||
break;
|
||||
DefaultLogger::get()->debug("Extra verbose: revalidating data structures");
|
||||
((ValidateDSProcess*)mPostProcessingSteps[0])->ExecuteOnScene (this);
|
||||
if( !mScene)
|
||||
{
|
||||
DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // ! DEBUG
|
||||
}
|
||||
#endif // ! DEBUG
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
if (bExtraVerbose)mScene->mFlags &= ~0x80000000;
|
||||
#endif // ! DEBUG
|
||||
}
|
||||
// if failed, extract the error string
|
||||
else if( !mScene)mErrorString = imp->GetErrorText();
|
||||
// if failed, extract the error string
|
||||
else if( !mScene)mErrorString = imp->GetErrorText();
|
||||
|
||||
// clear any data allocated by post-process steps
|
||||
mPPShared->Clean();
|
||||
// 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -109,6 +109,8 @@ void JoinVerticesProcess::Execute( aiScene* pScene)
|
||||
DefaultLogger::get()->info(szBuff);
|
||||
}
|
||||
}
|
||||
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -242,16 +242,16 @@ MaterialHelper::MaterialHelper()
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MaterialHelper::~MaterialHelper()
|
||||
{
|
||||
for (unsigned int i = 0; i < this->mNumProperties;++i)
|
||||
Clear();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MaterialHelper::Clear()
|
||||
{
|
||||
for (unsigned int i = 0; i < mNumProperties;++i)
|
||||
{
|
||||
// be careful ...
|
||||
if(NULL != this->mProperties[i])
|
||||
{
|
||||
delete[] this->mProperties[i]->mData;
|
||||
delete this->mProperties[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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -74,10 +74,19 @@ 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' ||
|
||||
extension[2] != 'f' && extension[2] != 'F' ||
|
||||
extension[3] != 'f' && extension[3] != 'F');
|
||||
// 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');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -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,252 +134,504 @@ 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;
|
||||
|
||||
while (GetNextLine(buffer,line))
|
||||
// lights imported from the file
|
||||
std::vector<Light> lights;
|
||||
|
||||
// check whether this is the NFF2 file format
|
||||
if (TokenMatch(buffer,"nff",3))
|
||||
{
|
||||
if ('p' == line[0])
|
||||
// another NFF file format ... just a raw parser has been implemented
|
||||
// no support for textures yet, I don't think it is worth the effort
|
||||
// http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/nff/nff2.html
|
||||
|
||||
while (GetNextLine(buffer,line))
|
||||
{
|
||||
MeshInfo* out = NULL;
|
||||
// 'pp' - polygon patch primitive
|
||||
if ('p' == line[1])
|
||||
sz = line;
|
||||
if (TokenMatch(sz,"version",7))
|
||||
{
|
||||
if (meshesWithNormals.empty())
|
||||
{
|
||||
meshesWithNormals.push_back(MeshInfo(true));
|
||||
currentMeshWithNormals = &meshesWithNormals.back();
|
||||
}
|
||||
|
||||
sz = &line[2];out = currentMeshWithNormals;
|
||||
DefaultLogger::get()->info("NFF (alt.) file format: " + std::string(sz));
|
||||
}
|
||||
// 'p' - polygon primitive
|
||||
else
|
||||
else if (TokenMatch(sz,"viewpos",7))
|
||||
{
|
||||
if (meshes.empty())
|
||||
{
|
||||
meshes.push_back(MeshInfo(false));
|
||||
currentMesh = &meshes.back();
|
||||
}
|
||||
sz = &line[1];out = currentMesh;
|
||||
AI_NFF_PARSE_TRIPLE(camPos);
|
||||
hasCam = true;
|
||||
}
|
||||
SkipSpaces(sz,&sz);
|
||||
m = strtol10(sz);
|
||||
|
||||
// ---- flip the face order
|
||||
out->vertices.resize(out->vertices.size()+m);
|
||||
if (out == currentMeshWithNormals)
|
||||
else if (TokenMatch(sz,"viewdir",7))
|
||||
{
|
||||
out->normals.resize(out->vertices.size());
|
||||
AI_NFF_PARSE_TRIPLE(camLookAt);
|
||||
hasCam = true;
|
||||
}
|
||||
for (unsigned int n = 0; n < m;++n)
|
||||
else if (TokenMatch(sz,"//",2))
|
||||
{
|
||||
if(!GetNextLine(buffer,line))
|
||||
{
|
||||
DefaultLogger::get()->error("NFF: Unexpected EOF was encountered");
|
||||
continue;
|
||||
}
|
||||
// comment ...
|
||||
DefaultLogger::get()->info(sz);
|
||||
}
|
||||
else if (!IsSpace(*sz))
|
||||
{
|
||||
// must be a new object
|
||||
meshes.push_back(MeshInfo(PatchType_Simple));
|
||||
MeshInfo& mesh = meshes.back();
|
||||
|
||||
aiVector3D v; sz = &line[0];
|
||||
AI_NFF_PARSE_TRIPLE(v);
|
||||
out->vertices[out->vertices.size()-n-1] = v;
|
||||
if (!GetNextLine(buffer,line))
|
||||
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read number of vertices");break;}
|
||||
|
||||
if (out == currentMeshWithNormals)
|
||||
SkipSpaces(line,&sz);
|
||||
unsigned int num = ::strtol10(sz,&sz);
|
||||
|
||||
std::vector<aiVector3D> tempPositions;
|
||||
std::vector<aiVector3D> outPositions;
|
||||
mesh.vertices.reserve(num*3);
|
||||
mesh.colors.reserve (num*3);
|
||||
tempPositions.reserve(num);
|
||||
for (unsigned int i = 0; i < num; ++i)
|
||||
{
|
||||
if (!GetNextLine(buffer,line))
|
||||
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read vertices");break;}
|
||||
|
||||
sz = line;
|
||||
aiVector3D v;
|
||||
AI_NFF_PARSE_TRIPLE(v);
|
||||
out->normals[out->vertices.size()-n-1] = v;
|
||||
tempPositions.push_back(v);
|
||||
}
|
||||
}
|
||||
out->faces.push_back(m);
|
||||
}
|
||||
// 'f' - shading information block
|
||||
else if ('f' == line[0] && IsSpace(line[1]))
|
||||
{
|
||||
SkipSpaces(&line[1],&sz);
|
||||
if (!GetNextLine(buffer,line))
|
||||
{DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read number of faces");break;}
|
||||
|
||||
// read just the RGB colors, the rest is ignored for the moment
|
||||
sz = fast_atof_move(sz, (float&)s.color.r);
|
||||
SkipSpaces(&sz);
|
||||
sz = fast_atof_move(sz, (float&)s.color.g);
|
||||
SkipSpaces(&sz);
|
||||
sz = fast_atof_move(sz, (float&)s.color.b);
|
||||
if (!num)throw new ImportErrorException("NFF2: There are zero vertices");
|
||||
|
||||
// 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;
|
||||
for (std::vector<MeshInfo>::iterator it = meshes.begin(), end = meshes.end();
|
||||
it != end;++it)
|
||||
{
|
||||
if ((*it).bLocked)continue;
|
||||
if ((*it).shader == s)
|
||||
SkipSpaces(line,&sz);
|
||||
num = ::strtol10(sz,&sz);
|
||||
mesh.faces.reserve(num);
|
||||
|
||||
for (unsigned int i = 0; i < num; ++i)
|
||||
{
|
||||
if ((*it).bHasNormals)currentMeshWithNormals = &(*it);
|
||||
else currentMesh = &(*it);
|
||||
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
|
||||
else if ('p' == line[1])
|
||||
{
|
||||
if (meshesWithNormals.empty())
|
||||
{
|
||||
meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
|
||||
currentMeshWithNormals = &meshesWithNormals.back();
|
||||
}
|
||||
|
||||
sz = &line[2];out = currentMeshWithNormals;
|
||||
}
|
||||
// 'p' - polygon primitive
|
||||
else
|
||||
{
|
||||
if (meshes.empty())
|
||||
{
|
||||
meshes.push_back(MeshInfo(PatchType_Simple));
|
||||
currentMesh = &meshes.back();
|
||||
}
|
||||
sz = &line[1];out = currentMesh;
|
||||
}
|
||||
SkipSpaces(sz,&sz);
|
||||
m = strtol10(sz);
|
||||
|
||||
// ---- flip the face order
|
||||
out->vertices.resize(out->vertices.size()+m);
|
||||
if (out != currentMesh)
|
||||
{
|
||||
out->normals.resize(out->vertices.size());
|
||||
}
|
||||
if (out == currentMeshWithUVCoords)
|
||||
{
|
||||
out->uvs.resize(out->vertices.size());
|
||||
}
|
||||
for (unsigned int n = 0; n < m;++n)
|
||||
{
|
||||
if(!GetNextLine(buffer,line))
|
||||
{
|
||||
DefaultLogger::get()->error("NFF: Unexpected EOF was encountered");
|
||||
continue;
|
||||
}
|
||||
|
||||
aiVector3D v; sz = &line[0];
|
||||
AI_NFF_PARSE_TRIPLE(v);
|
||||
out->vertices[out->vertices.size()-n-1] = v;
|
||||
|
||||
if (out != currentMesh)
|
||||
{
|
||||
AI_NFF_PARSE_TRIPLE(v);
|
||||
out->normals[out->vertices.size()-n-1] = v;
|
||||
}
|
||||
if (out == currentMeshWithUVCoords)
|
||||
{
|
||||
// FIX: in one test file this wraps over multiple lines
|
||||
SkipSpaces(&sz);
|
||||
if (IsLineEnd(*sz))
|
||||
{
|
||||
GetNextLine(buffer,line);
|
||||
sz = line;
|
||||
}
|
||||
AI_NFF_PARSE_FLOAT(v.x);
|
||||
SkipSpaces(&sz);
|
||||
if (IsLineEnd(*sz))
|
||||
{
|
||||
GetNextLine(buffer,line);
|
||||
sz = line;
|
||||
}
|
||||
AI_NFF_PARSE_FLOAT(v.y);
|
||||
v.y = 1.f - v.y;
|
||||
out->uvs[out->vertices.size()-n-1] = v;
|
||||
}
|
||||
}
|
||||
out->faces.push_back(m);
|
||||
}
|
||||
// 'f' - shading information block
|
||||
else if (TokenMatch(sz,"f",1))
|
||||
{
|
||||
float d;
|
||||
|
||||
// read the RGB colors
|
||||
AI_NFF_PARSE_TRIPLE(s.color);
|
||||
|
||||
// read the other properties
|
||||
AI_NFF_PARSE_FLOAT(s.diffuse);
|
||||
AI_NFF_PARSE_FLOAT(s.specular);
|
||||
AI_NFF_PARSE_FLOAT(d); // skip shininess and transmittance
|
||||
AI_NFF_PARSE_FLOAT(d);
|
||||
AI_NFF_PARSE_FLOAT(s.refracti);
|
||||
|
||||
// if the next one is NOT a number we assume it is a texture file name
|
||||
// this feature is used by some NFF files on the internet and it has
|
||||
// been implemented as it can be really useful
|
||||
SkipSpaces(&sz);
|
||||
if (!IsNumeric(*sz))
|
||||
{
|
||||
// TODO: Support full file names with spaces and quotation marks ...
|
||||
const char* p = sz;
|
||||
while (!IsSpaceOrNewLine( *sz ))++sz;
|
||||
|
||||
unsigned int diff = (unsigned int)(sz-p);
|
||||
if (diff)
|
||||
{
|
||||
s.texFile = std::string(p,diff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AI_NFF_PARSE_FLOAT(s.ambient); // optional
|
||||
}
|
||||
|
||||
// check whether we have this material already -
|
||||
// although we have the RRM-Step, this is necessary here.
|
||||
// otherwise we would generate hundreds of small meshes
|
||||
// with just a few faces - this is surely never wanted.
|
||||
currentMesh = currentMeshWithNormals = currentMeshWithUVCoords = NULL;
|
||||
for (std::vector<MeshInfo>::iterator it = meshes.begin(), end = meshes.end();
|
||||
it != end;++it)
|
||||
{
|
||||
if ((*it).bLocked)continue;
|
||||
if ((*it).shader == s)
|
||||
{
|
||||
switch ((*it).pType)
|
||||
{
|
||||
case PatchType_Normals:
|
||||
currentMeshWithNormals = &(*it);
|
||||
break;
|
||||
|
||||
case PatchType_Simple:
|
||||
currentMesh = &(*it);
|
||||
break;
|
||||
|
||||
default:
|
||||
currentMeshWithUVCoords = &(*it);
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentMesh)
|
||||
{
|
||||
meshes.push_back(MeshInfo(PatchType_Simple));
|
||||
currentMesh = &meshes.back();
|
||||
currentMesh->shader = s;
|
||||
}
|
||||
|
||||
if (!currentMeshWithNormals)
|
||||
{
|
||||
meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
|
||||
currentMeshWithNormals = &meshesWithNormals.back();
|
||||
currentMeshWithNormals->shader = s;
|
||||
}
|
||||
|
||||
if (!currentMeshWithUVCoords)
|
||||
{
|
||||
meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals));
|
||||
currentMeshWithUVCoords = &meshesWithUVCoords.back();
|
||||
currentMeshWithUVCoords->shader = s;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentMesh)
|
||||
// 'l' - light source
|
||||
else if (TokenMatch(sz,"l",1))
|
||||
{
|
||||
meshes.push_back(MeshInfo(false));
|
||||
currentMesh = &meshes.back();
|
||||
currentMesh->shader = s;
|
||||
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 (TokenMatch(sz,"s",1))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeSphere(iTesselation, currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"sphere_%i",sphere++);
|
||||
}
|
||||
// 'dod' - dodecahedron
|
||||
else if (TokenMatch(sz,"dod",3))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeDodecahedron(currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"dodecahedron_%i",dodecahedron++);
|
||||
}
|
||||
|
||||
if (!currentMeshWithNormals)
|
||||
// 'oct' - octahedron
|
||||
else if (TokenMatch(sz,"oct",3))
|
||||
{
|
||||
meshesWithNormals.push_back(MeshInfo(true));
|
||||
currentMeshWithNormals = &meshesWithNormals.back();
|
||||
currentMeshWithNormals->shader = s;
|
||||
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeOctahedron(currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"octahedron_%i",octahedron++);
|
||||
}
|
||||
}
|
||||
// 's' - sphere
|
||||
else if ('s' == line[0] && IsSpace(line[1]))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(false,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
|
||||
sz = &line[1];
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
// 'tet' - tetrahedron
|
||||
else if (TokenMatch(sz,"tet",3))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeSphere(iTesselation, currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"sphere_%i",sphere++);
|
||||
}
|
||||
// 'dod' - dodecahedron
|
||||
else if (!strncmp(line,"dod",3) && IsSpace(line[3]))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(false,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeTetrahedron(currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
sz = &line[4];
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"tetrahedron_%i",tetrahedron++);
|
||||
}
|
||||
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeDodecahedron(currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
// 'hex' - hexahedron
|
||||
else if (TokenMatch(sz,"hex",3))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"dodecahedron_%i",dodecahedron++);
|
||||
}
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
|
||||
// 'oct' - octahedron
|
||||
else if (!strncmp(line,"oct",3) && IsSpace(line[3]))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(false,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeHexahedron(currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
sz = &line[4];
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"hexahedron_%i",hexahedron++);
|
||||
}
|
||||
// 'c' - cone
|
||||
else if (TokenMatch(sz,"c",1))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
||||
MeshInfo& currentMesh = meshes.back();
|
||||
currentMesh.shader = s;
|
||||
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeOctahedron(currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
aiVector3D center1, center2; float radius1, radius2;
|
||||
AI_NFF_PARSE_TRIPLE(center1);
|
||||
AI_NFF_PARSE_FLOAT(radius1);
|
||||
AI_NFF_PARSE_TRIPLE(center2);
|
||||
AI_NFF_PARSE_FLOAT(radius2);
|
||||
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"octahedron_%i",octahedron++);
|
||||
}
|
||||
// compute the center point of the cone/cylinder
|
||||
center2 = (center2-center1)/2.f;
|
||||
currentMesh.center = center1+center2;
|
||||
center1 = -center2;
|
||||
|
||||
// 'tet' - tetrahedron
|
||||
else if (!strncmp(line,"tet",3) && IsSpace(line[3]))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(false,true));
|
||||
MeshInfo& currentMesh = meshesLocked.back();
|
||||
currentMesh.shader = s;
|
||||
// generate the cone - it consists of simple triangles
|
||||
StandardShapes::MakeCone(center1, radius1, center2, radius2, iTesselation, currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
sz = &line[4];
|
||||
AI_NFF_PARSE_SHAPE_INFORMATION();
|
||||
|
||||
// we don't need scaling or translation here - we do it in the node's transform
|
||||
StandardShapes::MakeTetrahedron(currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
// generate a name for the mesh
|
||||
::sprintf(currentMesh.name,"tetrahedron_%i",tetrahedron++);
|
||||
}
|
||||
|
||||
// 'hex' - hexahedron
|
||||
else if (!strncmp(line,"hex",3) && IsSpace(line[3]))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(false,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
|
||||
StandardShapes::MakeHexahedron(currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
// 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]))
|
||||
{
|
||||
meshesLocked.push_back(MeshInfo(false,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);
|
||||
AI_NFF_PARSE_TRIPLE(center2);
|
||||
AI_NFF_PARSE_FLOAT(radius2);
|
||||
|
||||
// compute the center point of the cone/cylinder
|
||||
center2 = (center2-center1)/2.f;
|
||||
currentMesh.center = center1+center2;
|
||||
center1 = -center2;
|
||||
|
||||
// generate the cone - it consists of simple triangles
|
||||
StandardShapes::MakeCone(center1, radius1, center2, radius2, iTesselation, currentMesh.vertices);
|
||||
currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
||||
|
||||
// generate a name for the mesh
|
||||
if (radius1 != radius2)
|
||||
::sprintf(currentMesh.name,"cone_%i",cone++);
|
||||
else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
|
||||
}
|
||||
// '#' - comment
|
||||
else if ('#' == line[0])
|
||||
{
|
||||
const char* sz;SkipSpaces(&line[1],&sz);
|
||||
if (!IsLineEnd(*sz))DefaultLogger::get()->info(sz);
|
||||
// generate a name for the mesh
|
||||
if (radius1 != radius2)
|
||||
::sprintf(currentMesh.name,"cone_%i",cone++);
|
||||
else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
|
||||
}
|
||||
// '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.insert(meshes.end(),meshesLocked.begin(),meshesLocked.end());
|
||||
meshes.insert(meshes.end(),meshesWithNormals.begin(),meshesWithNormals.end());
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,11 +257,12 @@ 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
|
||||
void GetVFormatList( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
|
||||
std::list<unsigned int>& aiOut)
|
||||
std::list<unsigned int>& aiOut)
|
||||
{
|
||||
for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
|
||||
{
|
||||
@@ -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];
|
||||
pScene->mAnimations = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
0
code/SceneCombiner.h
Normal file
0
code/SceneCombiner.h
Normal 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:
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
break;
|
||||
|
||||
// check whether the triangle is degenerated
|
||||
if (mesh->mVertices[face.mIndices[0]] == mesh->mVertices[face.mIndices[1]] ||
|
||||
mesh->mVertices[face.mIndices[1]] == mesh->mVertices[face.mIndices[2]])
|
||||
{
|
||||
face.mNumIndices = 2;
|
||||
unsigned int* pi = new unsigned int[2];
|
||||
pi[0] = face.mIndices[0];
|
||||
pi[1] = face.mIndices[2];
|
||||
delete[] face.mIndices;
|
||||
face.mIndices = pi;
|
||||
|
||||
bDeg = true;
|
||||
}
|
||||
else if (mesh->mVertices[face.mIndices[2]] == mesh->mVertices[face.mIndices[0]])
|
||||
{
|
||||
face.mNumIndices = 2;
|
||||
unsigned int* pi = new unsigned int[2];
|
||||
pi[0] = face.mIndices[0];
|
||||
pi[1] = face.mIndices[1];
|
||||
delete[] face.mIndices;
|
||||
face.mIndices = pi;
|
||||
|
||||
bDeg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
break;
|
||||
}
|
||||
case 2u:
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
break;
|
||||
|
||||
// check whether the line is degenerated
|
||||
if (mesh->mVertices[face.mIndices[0]] == mesh->mVertices[face.mIndices[1]])
|
||||
{
|
||||
face.mNumIndices = 1;
|
||||
unsigned int* pi = new unsigned int[1];
|
||||
pi[0] = face.mIndices[0];
|
||||
delete[] face.mIndices;
|
||||
face.mIndices = pi;
|
||||
|
||||
bDeg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
break;
|
||||
}
|
||||
case 1u:
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,13 @@ public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
private:
|
||||
|
||||
bool bSpeedFlag;
|
||||
};
|
||||
|
||||
#if (!defined AI_BUILD_NO_SORTBYPTYPE_PROCESS)
|
||||
|
||||
@@ -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];
|
||||
@@ -188,4 +186,4 @@ private:
|
||||
|
||||
};
|
||||
|
||||
#endif // !! AI_STREAMREADER_H_INCLUDED
|
||||
#endif // !! AI_STREAMREADER_H_INCLUDED
|
||||
|
||||
@@ -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,114 +121,200 @@ 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)
|
||||
{
|
||||
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->mNumMeshes)
|
||||
{
|
||||
if (!pScene->mMeshes)
|
||||
{
|
||||
this->ReportError("aiScene::mMeshes is NULL (aiScene::mNumMeshes is %i)",
|
||||
pScene->mNumMeshes);
|
||||
}
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
{
|
||||
if (!pScene->mMeshes[i])
|
||||
{
|
||||
this->ReportError("aiScene::mMeshes[%i] is NULL (aiScene::mNumMeshes is %i)",
|
||||
i,pScene->mNumMeshes);
|
||||
}
|
||||
this->Validate(pScene->mMeshes[i]);
|
||||
}
|
||||
has = true;
|
||||
DoValidation(pScene->mMeshes,pScene->mNumMeshes,"mMeshes","mNumMeshes");
|
||||
}
|
||||
else if (!(this->mScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY))
|
||||
else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
|
||||
{
|
||||
this->ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
|
||||
ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
|
||||
}
|
||||
|
||||
|
||||
// validate all animations
|
||||
if (pScene->mNumAnimations)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
has = true;
|
||||
DoValidation(pScene->mAnimations,pScene->mNumAnimations,
|
||||
"mAnimations","mNumAnimations");
|
||||
}
|
||||
else if (this->mScene->mFlags & AI_SCENE_FLAGS_ANIM_SKELETON_ONLY)
|
||||
|
||||
// validate all cameras
|
||||
if (pScene->mNumCameras)
|
||||
{
|
||||
this->ReportError("aiScene::mNumAnimations is 0 and the "
|
||||
"AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set.");
|
||||
has = true;
|
||||
DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras,
|
||||
"mCameras","mNumCameras");
|
||||
}
|
||||
|
||||
// validate all textures
|
||||
if (pScene->mNumTextures)
|
||||
// validate all lights
|
||||
if (pScene->mNumLights)
|
||||
{
|
||||
if (!pScene->mTextures)
|
||||
{
|
||||
this->ReportError("aiScene::mTextures is NULL (aiScene::mNumTextures is %i)",
|
||||
pScene->mNumTextures);
|
||||
}
|
||||
for (unsigned int i = 0; i < pScene->mNumTextures;++i)
|
||||
{
|
||||
if (!pScene->mTextures[i])
|
||||
{
|
||||
this->ReportError("aiScene::mTextures[%i] is NULL (aiScene::mNumTextures is %i)",
|
||||
i,pScene->mNumTextures);
|
||||
}
|
||||
this->Validate(pScene->mTextures[i]);
|
||||
}
|
||||
has = true;
|
||||
DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights,
|
||||
"mLights","mNumLights");
|
||||
}
|
||||
|
||||
|
||||
// validate all materials
|
||||
if (pScene->mNumMaterials)
|
||||
if (pScene->mNumMaterials)
|
||||
{
|
||||
if (!pScene->mMaterials)
|
||||
{
|
||||
this->ReportError("aiScene::mMaterials is NULL (aiScene::mNumMaterials is %i)",
|
||||
pScene->mNumMaterials);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
has = true;
|
||||
DoValidation(pScene->mCameras,pScene->mNumCameras,"mMaterials","mNumMaterials");
|
||||
}
|
||||
else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE))
|
||||
{
|
||||
ReportError("aiScene::mNumMaterials is 0. At least one material must be there");
|
||||
}
|
||||
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,96 +369,91 @@ 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)
|
||||
// positions must always be there ...
|
||||
if (!pMesh->mNumVertices || !pMesh->mVertices && !mScene->mFlags)
|
||||
{
|
||||
if (pMesh->mNumVertices || pMesh->mVertices ||
|
||||
pMesh->mNumFaces || pMesh->mFaces)
|
||||
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 && !mScene->mFlags)
|
||||
{
|
||||
this->ReportError("The mesh contains no faces");
|
||||
}
|
||||
|
||||
// now check whether the face indexing layout is correct:
|
||||
// unique vertices, pseudo-indexed.
|
||||
std::vector<bool> abRefList;
|
||||
abRefList.resize(pMesh->mNumVertices,false);
|
||||
for (unsigned int i = 0; i < pMesh->mNumFaces;++i)
|
||||
{
|
||||
aiFace& face = pMesh->mFaces[i];
|
||||
for (unsigned int a = 0; a < face.mNumIndices;++a)
|
||||
{
|
||||
this->ReportWarning("The mesh contains vertices and faces although "
|
||||
"the AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set");
|
||||
if (face.mIndices[a] >= pMesh->mNumVertices)
|
||||
{
|
||||
this->ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a);
|
||||
}
|
||||
// the MSB flag is temporarily used by the extra verbose
|
||||
// mode to tell us that the JoinVerticesProcess might have
|
||||
// been executed already.
|
||||
if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && abRefList[face.mIndices[a]])
|
||||
{
|
||||
ReportError("aiMesh::mVertices[%i] is referenced twice - second "
|
||||
"time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a);
|
||||
}
|
||||
abRefList[face.mIndices[a]] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
// check whether there are vertices that aren't referenced by a face
|
||||
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
|
||||
{
|
||||
// positions must always be there ...
|
||||
if (!pMesh->mNumVertices || !pMesh->mVertices)
|
||||
{
|
||||
this->ReportError("The mesh contains no vertices");
|
||||
}
|
||||
|
||||
// faces, too
|
||||
if (!pMesh->mNumFaces || !pMesh->mFaces)
|
||||
{
|
||||
this->ReportError("The mesh contains no faces");
|
||||
}
|
||||
|
||||
// now check whether the face indexing layout is correct:
|
||||
// unique vertices, pseudo-indexed.
|
||||
std::vector<bool> abRefList;
|
||||
abRefList.resize(pMesh->mNumVertices,false);
|
||||
for (unsigned int i = 0; i < pMesh->mNumFaces;++i)
|
||||
{
|
||||
aiFace& face = pMesh->mFaces[i];
|
||||
for (unsigned int a = 0; a < face.mNumIndices;++a)
|
||||
{
|
||||
if (face.mIndices[a] >= pMesh->mNumVertices)
|
||||
{
|
||||
this->ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a);
|
||||
}
|
||||
// the MSB flag is temporarily used by the extra verbose
|
||||
// mode to tell us that the JoinVerticesProcess might have
|
||||
// been executed already.
|
||||
if ( !(this->mScene->mFlags & 0x80000000 ) && abRefList[face.mIndices[a]])
|
||||
{
|
||||
this->ReportError("aiMesh::mVertices[%i] is referenced twice - second "
|
||||
"time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a);
|
||||
}
|
||||
abRefList[face.mIndices[a]] = true;
|
||||
}
|
||||
}
|
||||
// check whether there are vertices that aren't referenced by a face
|
||||
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
|
||||
{
|
||||
if (!abRefList[i])this->ReportError("aiMesh::mVertices[%i] is not referenced",i);
|
||||
}
|
||||
abRefList.clear();
|
||||
|
||||
// texture channel 2 may not be set if channel 1 is zero ...
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
{
|
||||
if (!pMesh->HasTextureCoords(i))break;
|
||||
}
|
||||
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
if (pMesh->HasTextureCoords(i))
|
||||
{
|
||||
this->ReportError("Texture coordinate channel %i is existing, "
|
||||
"although the previous channel was NULL.",i);
|
||||
}
|
||||
}
|
||||
// the same for the vertex colors
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
|
||||
{
|
||||
if (!pMesh->HasVertexColors(i))break;
|
||||
}
|
||||
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
|
||||
if (pMesh->HasVertexColors(i))
|
||||
{
|
||||
this->ReportError("Vertex color channel %i is existing, "
|
||||
"although the previous channel was NULL.",i);
|
||||
}
|
||||
}
|
||||
if (!abRefList[i])this->ReportError("aiMesh::mVertices[%i] is not referenced",i);
|
||||
}
|
||||
abRefList.clear();
|
||||
|
||||
// texture channel 2 may not be set if channel 1 is zero ...
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
{
|
||||
if (!pMesh->HasTextureCoords(i))break;
|
||||
}
|
||||
for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
if (pMesh->HasTextureCoords(i))
|
||||
{
|
||||
ReportError("Texture coordinate channel %i is existing, "
|
||||
"although the previous channel was NULL.",i);
|
||||
}
|
||||
}
|
||||
// the same for the vertex colors
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
|
||||
{
|
||||
if (!pMesh->HasVertexColors(i))break;
|
||||
}
|
||||
for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
|
||||
if (pMesh->HasVertexColors(i))
|
||||
{
|
||||
ReportError("Vertex color channel %i is existing, "
|
||||
"although the previous channel was NULL.",i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// now validate all bones
|
||||
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;
|
||||
|
||||
@@ -145,10 +145,22 @@ protected:
|
||||
* @param pTexture Input texture
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user