nuclear@0: /* nuclear@0: --------------------------------------------------------------------------- nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the following nuclear@0: conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: --------------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file FindDegenerates.cpp nuclear@0: * @brief Implementation of the FindDegenerates post-process step. nuclear@0: */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: nuclear@0: // internal headers nuclear@0: #include "ProcessHelper.h" nuclear@0: #include "FindDegenerates.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Constructor to be privately used by Importer nuclear@0: FindDegeneratesProcess::FindDegeneratesProcess() nuclear@0: : configRemoveDegenerates (false) nuclear@0: {} nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Destructor, private as well nuclear@0: FindDegeneratesProcess::~FindDegeneratesProcess() nuclear@0: { nuclear@0: // nothing to do here nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns whether the processing step is present in the given flag field. nuclear@0: bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const nuclear@0: { nuclear@0: return 0 != (pFlags & aiProcess_FindDegenerates); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Setup import configuration nuclear@0: void FindDegeneratesProcess::SetupProperties(const Importer* pImp) nuclear@0: { nuclear@0: // Get the current value of AI_CONFIG_PP_FD_REMOVE nuclear@0: configRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0)); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Executes the post processing step on the given imported data. nuclear@0: void FindDegeneratesProcess::Execute( aiScene* pScene) nuclear@0: { nuclear@0: DefaultLogger::get()->debug("FindDegeneratesProcess begin"); nuclear@0: for (unsigned int i = 0; i < pScene->mNumMeshes;++i){ nuclear@0: ExecuteOnMesh( pScene->mMeshes[i]); nuclear@0: } nuclear@0: DefaultLogger::get()->debug("FindDegeneratesProcess finished"); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Executes the post processing step on the given imported mesh nuclear@0: void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) nuclear@0: { nuclear@0: mesh->mPrimitiveTypes = 0; nuclear@0: nuclear@0: std::vector remove_me; nuclear@0: if (configRemoveDegenerates) nuclear@0: remove_me.resize(mesh->mNumFaces,false); nuclear@0: nuclear@0: unsigned int deg = 0, limit; nuclear@0: for (unsigned int a = 0; a < mesh->mNumFaces; ++a) nuclear@0: { nuclear@0: aiFace& face = mesh->mFaces[a]; nuclear@0: bool first = true; nuclear@0: nuclear@0: // check whether the face contains degenerated entries nuclear@0: for (register unsigned int i = 0; i < face.mNumIndices; ++i) nuclear@0: { nuclear@0: // Polygons with more than 4 points are allowed to have double points, that is nuclear@0: // simulating polygons with holes just with concave polygons. However, nuclear@0: // double points may not come directly after another. nuclear@0: limit = face.mNumIndices; nuclear@0: if (face.mNumIndices > 4) nuclear@0: limit = std::min(limit,i+2); nuclear@0: nuclear@0: for (register unsigned int t = i+1; t < limit; ++t) nuclear@0: { nuclear@0: if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) nuclear@0: { nuclear@0: // we have found a matching vertex position nuclear@0: // remove the corresponding index from the array nuclear@0: --face.mNumIndices;--limit; nuclear@0: for (unsigned int m = t; m < face.mNumIndices; ++m) nuclear@0: { nuclear@0: face.mIndices[m] = face.mIndices[m+1]; nuclear@0: } nuclear@0: --t; nuclear@0: nuclear@0: // NOTE: we set the removed vertex index to an unique value nuclear@0: // to make sure the developer gets notified when his nuclear@0: // application attemps to access this data. nuclear@0: face.mIndices[face.mNumIndices] = 0xdeadbeef; nuclear@0: nuclear@0: if(first) nuclear@0: { nuclear@0: ++deg; nuclear@0: first = false; nuclear@0: } nuclear@0: nuclear@0: if (configRemoveDegenerates) { nuclear@0: remove_me[a] = true; nuclear@0: goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby! nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // We need to update the primitive flags array of the mesh. nuclear@0: switch (face.mNumIndices) nuclear@0: { nuclear@0: case 1u: nuclear@0: mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; nuclear@0: break; nuclear@0: case 2u: nuclear@0: mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; nuclear@0: break; nuclear@0: case 3u: nuclear@0: mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; nuclear@0: break; nuclear@0: default: nuclear@0: mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; nuclear@0: break; nuclear@0: }; nuclear@0: evil_jump_outside: nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import nuclear@0: if (configRemoveDegenerates && deg) { nuclear@0: unsigned int n = 0; nuclear@0: for (unsigned int a = 0; a < mesh->mNumFaces; ++a) nuclear@0: { nuclear@0: aiFace& face_src = mesh->mFaces[a]; nuclear@0: if (!remove_me[a]) { nuclear@0: aiFace& face_dest = mesh->mFaces[n++]; nuclear@0: nuclear@0: // Do a manual copy, keep the index array nuclear@0: face_dest.mNumIndices = face_src.mNumIndices; nuclear@0: face_dest.mIndices = face_src.mIndices; nuclear@0: nuclear@0: if (&face_src != &face_dest) { nuclear@0: // clear source nuclear@0: face_src.mNumIndices = 0; nuclear@0: face_src.mIndices = NULL; nuclear@0: } nuclear@0: } nuclear@0: else { nuclear@0: // Otherwise delete it if we don't need this face nuclear@0: delete[] face_src.mIndices; nuclear@0: face_src.mIndices = NULL; nuclear@0: face_src.mNumIndices = 0; nuclear@0: } nuclear@0: } nuclear@0: // Just leave the rest of the array unreferenced, we don't care for now nuclear@0: mesh->mNumFaces = n; nuclear@0: if (!mesh->mNumFaces) { nuclear@0: // WTF!? nuclear@0: // OK ... for completeness and because I'm not yet tired, nuclear@0: // let's write code that willl hopefully never be called nuclear@0: // (famous last words) nuclear@0: nuclear@0: // OK ... bad idea. nuclear@0: throw DeadlyImportError("Mesh is empty after removal of degenerated primitives ... WTF!?"); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (deg && !DefaultLogger::isNullLogger()) nuclear@0: { nuclear@0: char s[64]; nuclear@0: ASSIMP_itoa10(s,deg); nuclear@0: DefaultLogger::get()->warn(std::string("Found ") + s + " degenerated primitives"); nuclear@0: } nuclear@0: }