diff --git a/code/ACLoader.cpp b/code/ACLoader.cpp index 1dcd7af88..558d2351f 100644 --- a/code/ACLoader.cpp +++ b/code/ACLoader.cpp @@ -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(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE); matDest.AddProperty(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR); - float f = 1.f - matSrc.trans; + int n; + if (matSrc.shin) + { + n = aiShadingMode_Phong; + matDest.AddProperty(&matSrc.shin,1,AI_MATKEY_SHININESS); + } + else n = aiShadingMode_Gouraud; + matDest.AddProperty(&n,1,AI_MATKEY_SHADING_MODEL); - matDest.AddProperty(&matSrc.shin,1,AI_MATKEY_SHININESS); + float f = 1.f - matSrc.trans; matDest.AddProperty(&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*)); diff --git a/code/ACLoader.h b/code/ACLoader.h index fb13fbf66..a3ce9e94f 100644 --- a/code/ACLoader.h +++ b/code/ACLoader.h @@ -162,7 +162,7 @@ protected: */ void GetExtensionList(std::string& append) { - append.append("*.ac"); + append.append("*.ac;*.acc"); } // ------------------------------------------------------------------- diff --git a/code/AssimpPCH.h b/code/AssimpPCH.h index 463c75337..b48b1b0f1 100644 --- a/code/AssimpPCH.h +++ b/code/AssimpPCH.h @@ -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 #include #include @@ -16,7 +79,10 @@ #include #include + +// ******************************************************************* // 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 # include +# include #endif diff --git a/code/BaseImporter.h b/code/BaseImporter.h index 835f43645..822e1cc6d 100644 --- a/code/BaseImporter.h +++ b/code/BaseImporter.h @@ -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:
+ * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:
* - at least one mesh must be there
* - at least one material must be there
* - there may be no meshes with 0 vertices or faces
diff --git a/code/DXFLoader.cpp b/code/DXFLoader.cpp index 0dff1d753..07b459f32 100644 --- a/code/DXFLoader.cpp +++ b/code/DXFLoader.cpp @@ -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; } + + diff --git a/code/DXFLoader.h b/code/DXFLoader.h index 901c04d1e..f20cd3f71 100644 --- a/code/DXFLoader.h +++ b/code/DXFLoader.h @@ -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 vPositions; std::vector vColors; }; diff --git a/code/FindInvalidDataProcess.cpp b/code/FindInvalidDataProcess.cpp index ab388a577..fc8a5a328 100644 --- a/code/FindInvalidDataProcess.cpp +++ b/code/FindInvalidDataProcess.cpp @@ -91,7 +91,11 @@ void UpdateMeshReferences(aiNode* node, const std::vector& 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(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; } diff --git a/code/GenFaceNormalsProcess.cpp b/code/GenFaceNormalsProcess.cpp index 63956139f..5ad484729 100644 --- a/code/GenFaceNormalsProcess.cpp +++ b/code/GenFaceNormalsProcess.cpp @@ -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::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]]; diff --git a/code/GenVertexNormalsProcess.cpp b/code/GenVertexNormalsProcess.cpp index a9d4072ec..8a3e89a88 100644 --- a/code/GenVertexNormalsProcess.cpp +++ b/code/GenVertexNormalsProcess.cpp @@ -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::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(); } } diff --git a/code/Importer.cpp b/code/Importer.cpp index f2a09e038..5792d210f 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -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; diff --git a/code/ImproveCacheLocality.cpp b/code/ImproveCacheLocality.cpp index 21cff2944..81270ad79 100644 --- a/code/ImproveCacheLocality.cpp +++ b/code/ImproveCacheLocality.cpp @@ -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; diff --git a/code/JoinVerticesProcess.cpp b/code/JoinVerticesProcess.cpp index 0f41e803d..301960e58 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/JoinVerticesProcess.cpp @@ -109,6 +109,8 @@ void JoinVerticesProcess::Execute( aiScene* pScene) DefaultLogger::get()->info(szBuff); } } + + pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; } // ------------------------------------------------------------------------------------------------ diff --git a/code/MD2Loader.cpp b/code/MD2Loader.cpp index 2a756d9ac..909bddde6 100644 --- a/code/MD2Loader.cpp +++ b/code/MD2Loader.cpp @@ -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 mBuffer2(fileSize); + std::vector 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 diff --git a/code/MD2Loader.h b/code/MD2Loader.h index b0c38073e..faeaeb8e2 100644 --- a/code/MD2Loader.h +++ b/code/MD2Loader.h @@ -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; diff --git a/code/MD5Loader.cpp b/code/MD5Loader.cpp index 9944a81de..799e7d2e3 100644 --- a/code/MD5Loader.cpp +++ b/code/MD5Loader.cpp @@ -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) diff --git a/code/MaterialSystem.cpp b/code/MaterialSystem.cpp index 480cc6aee..da512dc1c 100644 --- a/code/MaterialSystem.cpp +++ b/code/MaterialSystem.cpp @@ -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; diff --git a/code/MaterialSystem.h b/code/MaterialSystem.h index e9ca949cb..5a92b210e 100644 --- a/code/MaterialSystem.h +++ b/code/MaterialSystem.h @@ -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 diff --git a/code/NFFLoader.cpp b/code/NFFLoader.cpp index d074f6193..030bac373 100644 --- a/code/NFFLoader.cpp +++ b/code/NFFLoader.cpp @@ -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 meshes; std::vector meshesWithNormals; + std::vector meshesWithUVCoords; std::vector 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 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 tempPositions; + std::vector 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::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::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::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(""); - 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(""); + 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,"",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; } diff --git a/code/NFFLoader.h b/code/NFFLoader.h index 2c2421d93..579d8886d 100644 --- a/code/NFFLoader.h +++ b/code/NFFLoader.h @@ -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 vertices, normals; + std::vector vertices, normals, uvs; + std::vector colors; // for NFF2 std::vector faces; }; }; diff --git a/code/OFFLoader.cpp b/code/OFFLoader.cpp index c0405c9ba..2a375a498 100644 --- a/code/OFFLoader.cpp +++ b/code/OFFLoader.cpp @@ -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 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; } diff --git a/code/PretransformVertices.cpp b/code/PretransformVertices.cpp index 3d8fdafe3..5ec467139 100644 --- a/code/PretransformVertices.cpp +++ b/code/PretransformVertices.cpp @@ -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& aiOut) + std::list& 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 apcOutMeshes; - apcOutMeshes.reserve(pScene->mNumMaterials*2); + apcOutMeshes.reserve(pScene->mNumMaterials<<1u); std::list 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(""); - 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; } diff --git a/code/RemoveComments.cpp b/code/RemoveComments.cpp index cf8ccc895..fc40cf9aa 100644 --- a/code/RemoveComments.cpp +++ b/code/RemoveComments.cpp @@ -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; } } diff --git a/code/RemoveVCProcess.cpp b/code/RemoveVCProcess.cpp index 168e6134b..62d0897c6 100644 --- a/code/RemoveVCProcess.cpp +++ b/code/RemoveVCProcess.cpp @@ -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 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) { diff --git a/code/SMDLoader.cpp b/code/SMDLoader.cpp index bd1f56455..df3050a38 100644 --- a/code/SMDLoader.cpp +++ b/code/SMDLoader.cpp @@ -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; diff --git a/code/FaceEdgeAdjacency.h b/code/SceneCombiner.cpp similarity index 100% rename from code/FaceEdgeAdjacency.h rename to code/SceneCombiner.cpp diff --git a/code/SceneCombiner.h b/code/SceneCombiner.h new file mode 100644 index 000000000..e69de29bb diff --git a/code/SortByPTypeProcess.cpp b/code/SortByPTypeProcess.cpp index b7b9f2613..7f1fb742f 100644 --- a/code/SortByPTypeProcess.cpp +++ b/code/SortByPTypeProcess.cpp @@ -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& 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 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"); + } } diff --git a/code/SortByPTypeProcess.h b/code/SortByPTypeProcess.h index 0d174f116..2a0e4e693 100644 --- a/code/SortByPTypeProcess.h +++ b/code/SortByPTypeProcess.h @@ -72,6 +72,13 @@ public: // ------------------------------------------------------------------- void Execute( aiScene* pScene); + + // ------------------------------------------------------------------- + void SetupProperties(const Importer* pImp); + +private: + + bool bSpeedFlag; }; #if (!defined AI_BUILD_NO_SORTBYPTYPE_PROCESS) diff --git a/code/StreamReader.h b/code/StreamReader.h index 88aea62db..dcabc90c3 100644 --- a/code/StreamReader.h +++ b/code/StreamReader.h @@ -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 \ No newline at end of file +#endif // !! AI_STREAMREADER_H_INCLUDED diff --git a/code/ValidateDataStructure.cpp b/code/ValidateDataStructure.cpp index 98a208e54..32dcec314 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/ValidateDataStructure.cpp @@ -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 +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 +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 +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 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 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; diff --git a/code/ValidateDataStructure.h b/code/ValidateDataStructure.h index 342ffb5e9..491f05176 100644 --- a/code/ValidateDataStructure.h +++ b/code/ValidateDataStructure.h @@ -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 + inline void DoValidation(T** array, unsigned int size, + const char* firstName, const char* secondName); + + // extended version: checks whethr T::mName occurs twice + template + 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 + 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 diff --git a/code/fast_atof.h b/code/fast_atof.h index 4903de574..819345e68 100644 --- a/code/fast_atof.h +++ b/code/fast_atof.h @@ -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); } diff --git a/code/makefile.mingw b/code/makefile.mingw index c9201ee70..97a293ec2 100644 --- a/code/makefile.mingw +++ b/code/makefile.mingw @@ -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 diff --git a/include/BoostWorkaround/boost/multi_array.hpp b/include/BoostWorkaround/boost/multi_array.hpp new file mode 100644 index 000000000..e69de29bb diff --git a/include/aiCamera.h b/include/aiCamera.h index a02acb2e5..cfba52ddf 100644 --- a/include/aiCamera.h +++ b/include/aiCamera.h @@ -67,6 +67,35 @@ struct aiCamera */ aiString mName; + /** Position of the camera relative to the coordinate space + * defined by the corresponding node. + * + * The default value is 0|0|0. + */ + aiVector3D mPosition; + + + /** 'Up' - vector of the camera coordinate system relative to + * the coordinate space defined by the corresponding node. + * + * The 'right' vector of the camera coordinate system is + * the cross product of the up and lookAt vectors. + * The default value is 0|1|0. The vector + * may be normalized, but it needn't. + */ + aiVector3D mUp; + + + /** 'LookAt' - vector of the camera coordinate system relative to + * the coordinate space defined by the corresponding node. + * + * This is the viewing direction of the user. + * The default value is 0|0|1. The vector + * may be normalized, but it needn't. + */ + aiVector3D mLookAt; + + /** Half horizontal field of view angle, in radians. * * The field of view angle is the angle between the center @@ -105,7 +134,9 @@ struct aiCamera #ifdef __cplusplus aiCamera() - : mHorizontalFOV (0.25f * (float)AI_MATH_PI) + : mUp (0.f,1.f,0.f) + , mLookAt (0.f,0.f,1.f) + , mHorizontalFOV (0.25f * (float)AI_MATH_PI) , mClipPlaneNear (0.1f) , mClipPlaneFar (1000.f) , mAspect (0.f) @@ -120,4 +151,4 @@ struct aiCamera } #endif -#endif // AI_CAMERA_H_INC \ No newline at end of file +#endif // AI_CAMERA_H_INC diff --git a/include/aiConfig.h b/include/aiConfig.h index 09b9e3de5..f2cc82e47 100644 --- a/include/aiConfig.h +++ b/include/aiConfig.h @@ -40,8 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Defines constants for configurable properties */ -#ifndef AI_CONFIG_H_INC -#define AI_CONFIG_H_INC +#ifndef __AI_CONFIG_H_INC__ +#define __AI_CONFIG_H_INC__ // --------------------------------------------------------------------------- /** \brief Set the maximum number of vertices in a mesh. @@ -138,7 +138,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * This applies to the GenSmoothNormals-Step. The angle is specified * in degrees, so 180 is PI. The default value is * 175 degrees (all vertex normals are smoothed). The maximum value is 175 - * Property type: float. + * Property type: float. Warning: seting this option may cause a severe + * loss of performance. */ #define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE "pp.gsn.max_smoothing" @@ -169,20 +170,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --------------------------------------------------------------------------- /** \brief Sets the colormap (= palette) to be used to decode embedded - * textures in MDL files. + * textures in MDL (Quake or 3DGS) files. * * This must be a valid path to a file. The file is 768 (256*3) bytes - * large and contains RGB tripels for each of the 256 palette entries. - * The default value is colormap.lmp. If the file is nto found, - * a default palette is used. + * large and contains RGB triplets for each of the 256 palette entries. + * The default value is colormap.lmp. If the file is not found, + * a default palette (from Quake 1) is used. * Property type: string. */ #define AI_CONFIG_IMPORT_MDL_COLORMAP "imp.mdl.color_map" - - // --------------------------------------------------------------------------- +/** \brief Enumerates components of the aiScene and aiMesh data structures + * that can be excluded from the import with the RemoveComponent step. + * + * See the documentation to #aiProcess_RemoveComment for more details. + */ enum aiComponent { //! Normal vectors @@ -220,9 +224,13 @@ enum aiComponent //! cameras are removed. aiComponent_CAMERAS = 0x200, - //! Removes all meshes (aiScene::mMeshes). The - //! #AI_SCENE_FLAGS_ANIM_SKELETON_ONLY flag is set in aiScene::mFlags. + //! Removes all meshes (aiScene::mMeshes). aiComponent_MESHES = 0x400, + + //! Removes all materials. One default material will + //! be generated, so aiScene::mNumMaterials will be 1. + //! This makes no real sense without the aiComponent_TEXTURES flag. + aiComponent_MATERIALS = 0x800 }; #define aiComponent_COLORSn(n) (1u << (n+20u)) diff --git a/include/aiDefines.h b/include/aiDefines.h index 86298bcac..dc6046ab5 100644 --- a/include/aiDefines.h +++ b/include/aiDefines.h @@ -120,6 +120,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # define AI_FORCE_INLINE __forceinline + #else # define ASSIMP_API # define AI_FORCE_INLINE inline diff --git a/include/aiLight.h b/include/aiLight.h index 76e271d01..20fae683b 100644 --- a/include/aiLight.h +++ b/include/aiLight.h @@ -70,6 +70,8 @@ enum aiLightSourceType //! A spot light source emmits light in a specific //! angle. It has a position and a direction it is pointing to. + //! A good example for a spot light is a light spot in + //! sport arenas. aiLightSource_SPOT = 0x3 }; @@ -82,7 +84,7 @@ enum aiLightSourceType */ struct aiLight { - /** The name of the light sources. + /** The name of the light source. * * There must be a node in the scenegraph with the same name. * This node specifies the position of the light in the scene @@ -91,20 +93,23 @@ struct aiLight aiString mName; /** The type of the light source. + * + * aiLightSource_UNDEFINED is nto a valid value for this member. */ aiLightSourceType mType; /** Position of the light source in space. Relative to the - * node corresponding to the light. + * transformation of the node corresponding to the light. * * The position is undefined for directional lights. */ aiVector3D mPosition; /** Direction of the light source in space. Relative to the - * node corresponding to the light. + * transformation of the node corresponding to the light. * - * The direction is undefined for point lights. + * The direction is undefined for point lights. The vector + * may be normalized, but it needn't. */ aiVector3D mDirection; @@ -115,7 +120,7 @@ struct aiLight * @code * Atten = 1/( att0 + att1 * d + att2 * d*d) * @endcode - * This member corresponds to the att01 variable in the equation. + * This member corresponds to the att0 variable in the equation. */ float mAttenuationConstant; @@ -126,7 +131,7 @@ struct aiLight * @code * Atten = 1/( att0 + att1 * d + att2 * d*d) * @endcode - * This member corresponds to the att02 variable in the equation. + * This member corresponds to the att1 variable in the equation. */ float mAttenuationLinear; @@ -137,28 +142,33 @@ struct aiLight * @code * Atten = 1/( att0 + att1 * d + att2 * d*d) * @endcode - * This member corresponds to the att03 variable in the equation. + * This member corresponds to the att2 variable in the equation. */ float mAttenuationQuadratic; /** Diffuse color of the light source * - * The color has no alpha component which wouldn't make - * sense for light sources. + * The diffuse light color is multiplied with the diffuse + * material color to obtain the final color that contributes + * to the diffuse shading term. */ aiColor3D mColorDiffuse; /** Specular color of the light source * - * The color has no alpha component which wouldn't make - * sense for light sources. + * The specular light color is multiplied with the specular + * material color to obtain the final color that contributes + * to the specular shading term. */ aiColor3D mColorSpecular; /** Ambient color of the light source * - * The color has no alpha component which wouldn't make - * sense for light sources. + * The ambient light color is multiplied with the ambient + * material color to obtain the final color that contributes + * to the ambient shading term. Most renderers will ignore + * this value it, is just a remaining of the fixed-function pipeline + * that is still supported by quite many file formats. */ aiColor3D mColorAmbient; @@ -168,18 +178,19 @@ struct aiLight * angle. The angle is given in radians. It is 2PI for point * lights and undefined for directional lights. */ - float mAngleOuterCone; + float mAngleInnerCone; /** Outer angle of a spot light's light cone. * * The spot light does not affect objects outside this angle. * The angle is given in radians. It is 2PI for point lights and - * undefined for directional lights. + * undefined for directional lights. The outer angle must be + * greater than or equal to the inner angle. * It is assumed that the application uses a smooth * interpolation between the inner and the outer cone of the * spot light. */ - float mAngleInnerCone; + float mAngleOuterCone; #ifdef __cplusplus @@ -188,8 +199,8 @@ struct aiLight , mAttenuationConstant (0.f) , mAttenuationLinear (1.f) , mAttenuationQuadratic (0.f) - , mAngleOuterCone ((float)AI_MATH_TWO_PI) , mAngleInnerCone ((float)AI_MATH_TWO_PI) + , mAngleOuterCone ((float)AI_MATH_TWO_PI) { } @@ -201,4 +212,4 @@ struct aiLight #endif -#endif // !! __AI_LIGHT_H_INC__ \ No newline at end of file +#endif // !! __AI_LIGHT_H_INC__ diff --git a/include/aiMaterial.h b/include/aiMaterial.h index 2243ca4b3..3bac27502 100644 --- a/include/aiMaterial.h +++ b/include/aiMaterial.h @@ -240,6 +240,20 @@ struct aiMaterialProperty * is never 0 */ char* mData; + +#ifdef __cplusplus + + aiMaterialProperty() + { + mData = NULL; + } + + ~aiMaterialProperty() + { + delete[] mData; + } + +#endif }; #ifdef __cplusplus diff --git a/include/aiMatrix4x4.inl b/include/aiMatrix4x4.inl index b863ead78..4eca01d6f 100644 --- a/include/aiMatrix4x4.inl +++ b/include/aiMatrix4x4.inl @@ -173,21 +173,15 @@ inline void aiMatrix4x4::Decompose (aiVector3D& scaling, aiQuaternion& rotation, // and remove all scaling from the matrix if(scaling.x) { - vRows[0].x /= scaling.x; - vRows[0].y /= scaling.x; - vRows[0].z /= scaling.x; + vRows[0] /= scaling.x; } if(scaling.y) { - vRows[1].x /= scaling.y; - vRows[1].y /= scaling.y; - vRows[1].z /= scaling.y; + vRows[1] /= scaling.y; } if(scaling.z) { - vRows[2].x /= scaling.z; - vRows[2].y /= scaling.z; - vRows[2].z /= scaling.z; + vRows[2] /= scaling.z; } // build a 3x3 rotation matrix @@ -217,7 +211,7 @@ inline void aiMatrix4x4::FromEulerAngles(float x, float y, float z) { aiMatrix4x4& _this = *this; - const float A = ::cos(x); + const float A = ::cos(x); const float B = ::sin(x); const float C = ::cos(y); const float D = ::sin(y); diff --git a/include/aiMesh.h b/include/aiMesh.h index ff0984d35..66564eee7 100644 --- a/include/aiMesh.h +++ b/include/aiMesh.h @@ -41,8 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Declares the data structures in which the imported geometry is returned by ASSIMP: aiMesh, aiFace and aiBone data structures. */ -#ifndef AI_MESH_H_INC -#define AI_MESH_H_INC +#ifndef __AI_MESH_H_INC__ +#define __AI_MESH_H_INC__ #include "aiTypes.h" @@ -58,7 +58,6 @@ extern "C" { * Point and line primitives are rarely used and are NOT supported. However, * a load could pass them as degenerated triangles. */ -// --------------------------------------------------------------------------- struct aiFace { //! Number of indices defining this face. 3 for a triangle, >3 for polygon @@ -130,7 +129,6 @@ struct aiFace // --------------------------------------------------------------------------- /** A single influence of a bone on a vertex. */ -// --------------------------------------------------------------------------- struct aiVertexWeight { //! Index of the vertex which is influenced by the bone. @@ -161,7 +159,6 @@ struct aiVertexWeight * in the frame hierarchy and by which it can be addressed by animations. * In addition it has a number of influences on vertices. */ -// --------------------------------------------------------------------------- struct aiBone { //! The name of the bone. @@ -218,7 +215,6 @@ struct aiBone * \note Some internal structures expect (and assert) this value * to be at least 4 */ -// --------------------------------------------------------------------------- # define AI_MAX_NUMBER_OF_COLOR_SETS 0x4 #endif // !! AI_MAX_NUMBER_OF_COLOR_SETS @@ -234,7 +230,6 @@ struct aiBone * \note Some internal structures expect (and assert) this value * to be at least 4 */ -// --------------------------------------------------------------------------- # define AI_MAX_NUMBER_OF_TEXTURECOORDS 0x4 // NOTE (Aramis): If you change these values, make sure that you also @@ -248,33 +243,34 @@ struct aiBone #endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS -#define AI_MESH_SMOOTHING_ANGLE_NOT_SET (10e10f) - // --------------------------------------------------------------------------- /** Enumerates the types of geometric primitives supported by Assimp. */ -// --------------------------------------------------------------------------- enum aiPrimitiveType { /** A point primitive. + * * This is just a single vertex in the virtual world, * #aiFace contains just one index for such a primitive. */ aiPrimitiveType_POINT = 0x1, /** A line primitive. + * * This is a line defined through a start and an end position. * #aiFace contains exactly two indices for such a primitive. */ aiPrimitiveType_LINE = 0x2, /** A triangular primitive. + * * A triangle consists of three indices. */ aiPrimitiveType_TRIANGLE = 0x4, /** A higher-level polygon with more than 3 edges. + * * A triangle is a polygon, but polygon in this context means * "all polygons that are not triangles". The "Triangulate"-Step * is provided for your convinience, it splits all polygons in @@ -298,9 +294,9 @@ enum aiPrimitiveType * * A Mesh uses only a single material which is referenced by a material ID. * \note The mPositions member is not optional, although a Has()-Method is -* provided for it. +* provided for it. However, positions *could* be missing if the +* AI_SCENE_FLAGS_INCOMPLETE flag is set in aiScene::mFlags. */ -// --------------------------------------------------------------------------- struct aiMesh { /** Bitwise combination of the members of the #aiPrimitiveType enum. @@ -328,14 +324,23 @@ struct aiMesh /** Vertex normals. * The array contains normalized vectors, NULL if not present. - * The array is mNumVertices in size. + * The array is mNumVertices in size. Normals are undefined for + * point and line primitives. A mesh consisting of points and + * lines only may not have normal vectors. Meshes with mixed + * primitive types (i.e. lines and triangles) may have normals, + * but the normals for vertices that are only referenced by + * point or line primitives are undefined and set to QNaN. */ C_STRUCT aiVector3D* mNormals; /** Vertex tangents. * The tangent of a vertex points in the direction of the positive * X texture axis. The array contains normalized vectors, NULL if - * not present. The array is mNumVertices in size. + * not present. The array is mNumVertices in size. A mesh consisting + * of points and lines only may not have normal vectors. Meshes with + * mixed primitive types (i.e. lines and triangles) may have + * normals, but the normals for vertices that are only referenced by + * point or line primitives are undefined and set to QNaN. * @note If the mesh contains tangents, it automatically also * contains bitangents. */ @@ -368,6 +373,7 @@ struct aiMesh * or cube maps). If the value is 2 for a given channel n, the * component p.z of mTextureCoords[n][p] is set to 0.0f. * If the value is 1 for a given channel, p.y is set to 0.0f, too. + * If this value is 0, 2 should be assumed. * @note 4D coords are not supported */ unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; @@ -375,7 +381,8 @@ struct aiMesh /** The faces the mesh is contstructed from. * Each face referres to a number of vertices by their indices. * This array is always present in a mesh, its size is given - * in mNumFaces. + * in mNumFaces. If the AI_SCENE_FLAGS_NON_VERBOSE_FORMAT + * is NOT set each face references an unique set of vertices. */ C_STRUCT aiFace* mFaces; @@ -422,7 +429,7 @@ struct aiMesh //! Deletes all storage allocated for the mesh ~aiMesh() { - if ( mNumVertices) // fix to make this work for invalid scenes, too + if ( mNumVertices ) // fix to make this work for invalid scenes, too { delete [] mVertices; delete [] mNormals; @@ -433,7 +440,7 @@ struct aiMesh for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) delete [] mColors[a]; } - if ( mNumBones) // fix to make this work for invalid scenes, too + if ( mNumBones && mBones) // fix to make this work for invalid scenes, too { for( unsigned int a = 0; a < mNumBones; a++) delete mBones[a]; @@ -461,6 +468,9 @@ struct aiMesh { return mNormals != NULL; } //! Check whether the mesh contains tangent and bitangent vectors + //! It is not possible that it contains tangents and no bitangents + //! (or the other way round). The existence of one of them + //! implies that the second is there, too. inline bool HasTangentsAndBitangents() const { return mTangents != NULL && mBitangents != NULL; } @@ -478,7 +488,7 @@ struct aiMesh //! \param pIndex Index of the texture coordinates set inline bool HasTextureCoords( unsigned int pIndex) const { - if( pIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) + if( pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) return false; else return mTextureCoords[pIndex] != NULL; @@ -494,5 +504,5 @@ struct aiMesh } #endif -#endif // AI_MESH_H_INC +#endif // __AI_MESH_H_INC diff --git a/include/aiScene.h b/include/aiScene.h index 05c490890..8f6a0b9ee 100644 --- a/include/aiScene.h +++ b/include/aiScene.h @@ -40,13 +40,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Defines the data structures in which the imported scene is returned. */ -#ifndef AI_SCENE_H_INC -#define AI_SCENE_H_INC +#ifndef __AI_SCENE_H_INC__ +#define __AI_SCENE_H_INC__ #include "aiTypes.h" -#include "aiMesh.h" -#include "aiMaterial.h" #include "aiTexture.h" +#include "aiMesh.h" +#include "aiLight.h" +#include "aiCamera.h" +#include "aiMaterial.h" #include "aiAnim.h" #ifdef __cplusplus @@ -80,8 +82,8 @@ struct aiNode /** The number of child nodes of this node. */ unsigned int mNumChildren; - /** The child nodes of this node. NULL if mNumChildren is 0. */ + /** The child nodes of this node. NULL if mNumChildren is 0. */ C_STRUCT aiNode** mChildren; /** The number of meshes of this node. */ @@ -113,8 +115,9 @@ struct aiNode /** Destructor */ ~aiNode() { - // delete al children recursively - if (mChildren) // fix to make the d'tor work for invalid scenes, too + // delete all children recursively + // to make sure we won't crash if the data is invalid ... + if (mChildren && mNumChildren) { for( unsigned int a = 0; a < mNumChildren; a++) delete mChildren[a]; @@ -122,17 +125,66 @@ struct aiNode } delete [] mMeshes; } + + /** Searches for a node with a specific name, beginning at this + * nodes. Normally you will call this method on the root node + * of the scene. + * + * @param name Name to seach for + * @return NULL or a valid Node if the search was successful. + */ + inline aiNode* FindNode(const aiString& name) + { + if (mName == name)return this; + for (unsigned int i = 0; i < mNumChildren;++i) + { + aiNode* p = mChildren[i]->FindNode(name); + if (p)return p; + } + // there is definitely no sub node with this name + return NULL; + } + #endif // __cplusplus }; -//! @def AI_SCENE_FLAGS_ANIM_SKELETON_ONLY -//! Specifies that no full model but only an animation skeleton has been -//! imported. There are no materials in this case. There are no -//! textures in this case. But there is a node graph, animation channels -//! and propably meshes with bones. Validation of meshes is less strict -//! with this flag, so be careful. -#define AI_SCENE_FLAGS_ANIM_SKELETON_ONLY 0x1 +// --------------------------------------------------------------------------- +/** @def AI_SCENE_FLAGS_INCOMPLETE + * Specifies that the scene data structure that was imported is not complete. + * This flag bypasses some internal validations and allows the import + * of animation skeletons, material libraries or camera animation paths + * using Assimp. Most applications won't support such data. + */ +#define AI_SCENE_FLAGS_INCOMPLETE 0x1 + + +/** @def AI_SCENE_FLAGS_VALIDATED + * This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS) + * if the validation is successful. In a validated scene you can be sure that + * any cross references in the data structure (e.g. vertex indices) are valid. + */ +#define AI_SCENE_FLAGS_VALIDATED 0x2 + + +/** @def AI_SCENE_FLAGS_VALIDATION_WARNING + * This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS) + * if the validation is successful but some issues have been found. + * This can for example mean that a texture that does not exist is referenced + * by a material or that the bone weights for a vertex don't sum to 1.0 ... . + * In most cases you should still be able to use the import. This flag could + * be useful for applications which don't capture Assimp's log output. + */ +#define AI_SCENE_FLAGS_VALIDATION_WARNING 0x4 + + +/** @def AI_SCENE_FLAGS_NON_VERBOSE_FORMAT + * This flag is currently only set by the aiProcess_JoinIdenticalVertices step. + * It indicates that the vertices of the output meshes aren't in the internal + * verbose format anymore. In the verbose format all vertices are unique, + * no vertex is ever referenced by more than one face. + */ +#define AI_SCENE_FLAGS_NON_VERBOSE_FORMAT 0x8 // --------------------------------------------------------------------------- /** The root structure of the imported data. @@ -143,15 +195,20 @@ struct aiNode struct aiScene { - /** Any combination of the AI_SCENE_FLAGS_XXX flags */ + /** Any combination of the AI_SCENE_FLAGS_XXX flags. By default + * this value is 0, no flags are set. Most applications will + * want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE + * bit set. + */ unsigned int mFlags; /** The root node of the hierarchy. * * There will always be at least the root node if the import - * was successful. Presence of further nodes depends on the - * format and content of the imported file. + * was successful (and no special flags have been set). + * Presence of further nodes depends on the format and content + * of the imported file. */ C_STRUCT aiNode* mRootNode; @@ -163,7 +220,9 @@ struct aiScene /** The array of meshes. * * Use the indices given in the aiNode structure to access - * this array. The array is mNumMeshes in size. + * this array. The array is mNumMeshes in size. If the + * AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always + * be at least ONE material. */ C_STRUCT aiMesh** mMeshes; @@ -175,7 +234,9 @@ struct aiScene /** The array of materials. * * Use the index given in each aiMesh structure to access this - * array. The array is mNumMaterials in size. + * array. The array is mNumMaterials in size. If the + * AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always + * be at least ONE material. */ C_STRUCT aiMaterial** mMaterials; @@ -200,10 +261,36 @@ struct aiScene * * Not many file formats embedd their textures into the file. * An example is Quake's MDL format (which is also used by - * some GameStudio™ versions) + * some GameStudio versions) */ C_STRUCT aiTexture** mTextures; + + /** The number of light sources in the scene. Light sources + are fully optional, in most cases this attribute will be 0 */ + unsigned int mNumLights; + + /** The array of light sources. + * + * All light sources imported from the given file are + * listed here. The array is mNumLights in size. + */ + C_STRUCT aiLight** mLights; + + + /** The number of cameras in the scene. Cameras + are fully optional, in most cases this attribute will be 0 */ + unsigned int mNumCameras; + + /** The array of cameras. + * + * All cameras imported from the given file are listed here. + * The array is mNumCameras in size. The first camera in the + * array (if existing) is the default camera view into + * the scene. + */ + C_STRUCT aiCamera** mCameras; + #ifdef __cplusplus //! Default constructor @@ -215,6 +302,8 @@ struct aiScene mNumMaterials = 0; mMaterials = NULL; mNumAnimations = 0; mAnimations = NULL; mNumTextures = 0; mTextures = NULL; + mNumCameras = 0; mCameras = NULL; + mNumLights = 0; mLights = NULL; mFlags = 0; } @@ -223,31 +312,74 @@ struct aiScene { // delete all subobjects recursively delete mRootNode; - if (mNumMeshes) // fix to make the d'tor work for invalid scenes, too + + // To make sure we won't crash if the data is invalid it's + // mich better to check whether both mNumXXX and mXXX are + // valid instead of relying on just one of them. + if (mNumMeshes && mMeshes) { for( unsigned int a = 0; a < mNumMeshes; a++) delete mMeshes[a]; delete [] mMeshes; } - if (mNumMaterials) // fix to make the d'tor work for invalid scenes, too + if (mNumMaterials && mMaterials) { for( unsigned int a = 0; a < mNumMaterials; a++) delete mMaterials[a]; delete [] mMaterials; } - if (mNumAnimations) // fix to make the d'tor work for invalid scenes, too + if (mNumAnimations && mAnimations) { for( unsigned int a = 0; a < mNumAnimations; a++) delete mAnimations[a]; delete [] mAnimations; } - if (mNumTextures) // fix to make the d'tor work for invalid scenes, too + if (mNumTextures && mTextures) { for( unsigned int a = 0; a < mNumTextures; a++) delete mTextures[a]; delete [] mTextures; } + if (mNumLights && mLights) + { + for( unsigned int a = 0; a < mNumLights; a++) + delete mLights[a]; + delete [] mLights; + } + if (mNumCameras && mCameras) + { + for( unsigned int a = 0; a < mNumCameras; a++) + delete mCameras[a]; + delete [] mCameras; + } } + + //! Check whether the scene contains meshes + //! Unless no special scene flags are set this will always be true. + inline bool HasMeshes() const + { return mMeshes != NULL; } + + //! Check whether the scene contains materials + //! Unless no special scene flags are set this will always be true. + inline bool HasMaterials() const + { return mMaterials != NULL; } + + //! Check whether the scene contains lights + inline bool HasLights() const + { return mLights != NULL; } + + //! Check whether the scene contains textures + inline bool HasTextures() const + { return mTextures != NULL; } + + //! Check whether the scene contains cameras + inline bool HasCameras() const + { return mCameras != NULL; } + + //! Check whether the scene contains animations + inline bool HasAnimations() const + { return mAnimations != NULL; } + #endif // __cplusplus }; @@ -255,4 +387,4 @@ struct aiScene } #endif -#endif // AI_SCENE_H_INC +#endif // __AI_SCENE_H_INC__ diff --git a/include/aiTexture.h b/include/aiTexture.h index b63b607aa..2df57f57f 100644 --- a/include/aiTexture.h +++ b/include/aiTexture.h @@ -69,15 +69,8 @@ extern "C" { # define AI_MAKE_EMBEDDED_TEXNAME(_n_) "*" # _n_ #endif -// ugly compiler dependent packing stuff -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack(push,1) -# define PACK_STRUCT -#elif defined( __GNUC__ ) -# define PACK_STRUCT __attribute__((packed)) -#else -# error Compiler not supported. Never do this again. -#endif + +#include "./Compiler/pushpack1.h" // --------------------------------------------------------------------------- /** Helper structure to represent a texel in ARGB8888 format @@ -87,11 +80,9 @@ extern "C" { // --------------------------------------------------------------------------- struct aiTexel { - unsigned char b; - unsigned char g; - unsigned char r; - unsigned char a; + uint8_t b,g,r,a; +#ifdef __cplusplus //! Comparison operator bool operator== (const aiTexel& other) const { @@ -105,14 +96,11 @@ struct aiTexel return b != other.b || r != other.r || g != other.g || a != other.a; } +#endif // __cplusplus } PACK_STRUCT; -// reset packing to the original value -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack( pop ) -#endif -#undef PACK_STRUCT +#include "./Compiler/poppack1.h" // --------------------------------------------------------------------------- /** Helper structure to describe an embedded texture @@ -164,12 +152,14 @@ struct aiTexture // Construction aiTexture () - : mWidth(0), mHeight(0), pcData(NULL) + : mWidth (0) + , mHeight (0) + , pcData (NULL) { - achFormatHint[0] = '\0'; - achFormatHint[1] = '\0'; - achFormatHint[2] = '\0'; - achFormatHint[3] = '\0'; + achFormatHint[0] = 0; + achFormatHint[1] = 0; + achFormatHint[2] = 0; + achFormatHint[3] = 0; } // Destruction diff --git a/include/aiTypes.h b/include/aiTypes.h index 96dd907d0..7fdd73868 100644 --- a/include/aiTypes.h +++ b/include/aiTypes.h @@ -114,19 +114,15 @@ struct aiColor3D aiColor3D operator*(const aiColor3D& c) const {return aiColor3D(r*c.r,g*c.g,b*c.b);} - aiColor3D operator*(float f) + aiColor3D operator*(float f) const {return aiColor3D(r*f,g*f,b*f);} - // ugly subscript operator ... should better use an union, but - // hopefully the compiler will optimize the switch away. - inline float& operator[] (unsigned int sub) + inline float operator[](unsigned int i) const {return *(&r + i);} + inline float& operator[](unsigned int i) {return *(&r + i);} + + inline bool IsBlack() const { - switch (sub) - { - case 0: return (float&)r; - case 1: return (float&)g; - default: return (float&)b; - }; + return !r && !g && !b; } #endif // !__cplusplus @@ -156,17 +152,13 @@ struct aiColor4D bool operator != (const aiColor4D& other) const {return r != other.r || g != other.g || b != other.b || a != other.a;} - // ugly subscript operator ... should better use an union, but - // hopefully the compiler will optimize the switch away. - inline float& operator[] (unsigned int sub) + inline float operator[](unsigned int i) const {return *(&r + i);} + inline float& operator[](unsigned int i) {return *(&r + i);} + + inline bool IsBlack() const { - switch (sub) - { - case 0: return (float&)r; - case 1: return (float&)g; - case 2: return (float&)b; - default: return (float&)a; - }; + // the alpha component doesn't care here. black is black. + return !r && !g && !b; } #endif // !__cplusplus diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index 0431e73c9..d8545c49c 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -433,8 +433,7 @@ int CreateAssetData() g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]); } - if (g_pcAsset->pcScene->mMeshes[i]->mPrimitiveTypes == aiPrimitiveType_LINE || - g_pcAsset->pcScene->mMeshes[i]->mPrimitiveTypes == aiPrimitiveType_POINT) + if (g_pcAsset->pcScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) { continue; } diff --git a/workspaces/vc8/UnitTest.vcproj b/workspaces/vc8/UnitTest.vcproj index 0cdb59663..547e77392 100644 --- a/workspaces/vc8/UnitTest.vcproj +++ b/workspaces/vc8/UnitTest.vcproj @@ -675,6 +675,14 @@ RelativePath="..\..\test\unit\Main.cpp" > + + + + diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index c529723c2..22e92bc04 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -726,6 +726,10 @@ RelativePath="..\..\include\BoostWorkaround\boost\format.hpp" > + + @@ -867,6 +871,10 @@ RelativePath="..\..\code\StandardShapes.h" > + +