From f84851e8931fb04e7074d487c91c3b3faa566994 Mon Sep 17 00:00:00 2001 From: Arkeon Date: Fri, 2 Jun 2017 13:24:56 +0200 Subject: [PATCH] PLYImporter: - optimize memory and speed on ply importer / change parser to use a file stream - manage texture path in ply import - manage texture coords on faces in ply import - correction on point cloud faces generation IFC : - update poly2tri to avoid crash on some IFC files Collada : - manage missing texture reference in collada import --- code/ColladaLoader.cpp | 16 +- code/IOStreamBuffer.h | 22 + code/PlyLoader.cpp | 1825 ++++++++--------- code/PlyLoader.h | 61 +- code/PlyParser.cpp | 1792 ++++++++-------- code/PlyParser.h | 95 +- code/STLLoader.cpp | 6 +- contrib/poly2tri/poly2tri/common/shapes.cc | 54 +- contrib/poly2tri/poly2tri/common/shapes.h | 58 +- contrib/poly2tri/poly2tri/common/utils.h | 40 +- contrib/poly2tri/poly2tri/poly2tri.h | 5 +- .../poly2tri/sweep/advancing_front.cc | 7 +- .../poly2tri/poly2tri/sweep/advancing_front.h | 6 +- contrib/poly2tri/poly2tri/sweep/cdt.cc | 9 +- contrib/poly2tri/poly2tri/sweep/cdt.h | 34 +- contrib/poly2tri/poly2tri/sweep/sweep.cc | 133 +- contrib/poly2tri/poly2tri/sweep/sweep.h | 49 +- .../poly2tri/poly2tri/sweep/sweep_context.cc | 53 +- .../poly2tri/poly2tri/sweep/sweep_context.h | 34 +- 19 files changed, 2237 insertions(+), 2062 deletions(-) diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index 457b62c20..5cec0a0c6 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -1726,6 +1726,8 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/) aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser, const Collada::Effect& pEffect, const std::string& pName) { + aiString result; + // recurse through the param references until we end up at an image std::string name = pName; while( 1) @@ -1744,11 +1746,17 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name); if( imIt == pParser.mImageLibrary.end()) { - throw DeadlyImportError( format() << - "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." ); - } + //missing texture should not stop the conversion + //throw DeadlyImportError( format() << + // "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." ); - aiString result; + DefaultLogger::get()->warn("Collada: Unable to resolve effect texture entry \"" + pName + "\", ended up at ID \"" + name + "\"."); + + //set default texture file name + result.Set(name + ".jpg"); + ConvertPath(result); + return result; + } // if this is an embedded texture image setup an aiTexture for it if (imIt->second.mFileName.empty()) diff --git a/code/IOStreamBuffer.h b/code/IOStreamBuffer.h index b80810084..577e3f8a6 100644 --- a/code/IOStreamBuffer.h +++ b/code/IOStreamBuffer.h @@ -100,6 +100,11 @@ public: /// @return true if successful. bool getNextDataLine( std::vector &buffer, T continuationToken ); + /// @brief Will read the next block. + /// @param buffer The buffer for the next block. + /// @return true if successful. + bool getNextBlock( std::vector &buffer ); + private: IOStream *m_stream; size_t m_filesize; @@ -274,4 +279,21 @@ bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationT return true; } +template +inline +bool IOStreamBuffer::getNextBlock( std::vector &buffer) { + //just return the last blockvalue if getNextLine was used before + if ( m_cachePos != 0) { + buffer = std::vector(m_cache.begin() + m_cachePos, m_cache.end()); + m_cachePos = 0; + } + else { + if ( !readNextBlock() ) + return false; + + buffer = std::vector(m_cache.begin(), m_cache.end()); + } + return true; +} + } // !ns Assimp diff --git a/code/PlyLoader.cpp b/code/PlyLoader.cpp index 7cfa06727..d815b2240 100644 --- a/code/PlyLoader.cpp +++ b/code/PlyLoader.cpp @@ -5,7 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2017, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -13,18 +12,18 @@ 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. +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. +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 team. +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -48,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "PlyLoader.h" +#include "IOStreamBuffer.h" #include "Macros.h" #include #include @@ -57,16 +57,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; static const aiImporterDesc desc = { - "Stanford Polygon Library (PLY) Importer", - "", - "", - "", - aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "ply" + "Stanford Polygon Library (PLY) Importer", + "", + "", + "", + aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "ply" }; @@ -74,1040 +74,983 @@ static const aiImporterDesc desc = { // Internal stuff namespace { - // ------------------------------------------------------------------------------------------------ - // Checks that property index is within range - template - const T &GetProperty(const std::vector &props, int idx) - { - if( static_cast< size_t >( idx ) >= props.size() ) { - throw DeadlyImportError( "Invalid .ply file: Property index is out of range." ); - } - - return props[idx]; + // ------------------------------------------------------------------------------------------------ + // Checks that property index is within range + template + const T &GetProperty(const std::vector &props, int idx) + { + if (static_cast(idx) >= props.size()) { + throw DeadlyImportError("Invalid .ply file: Property index is out of range."); } + + return props[idx]; + } } // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer PLYImporter::PLYImporter() -: mBuffer() -, pcDOM(){ - // empty + : mBuffer() + , pcDOM() + , mGeneratedMesh(NULL){ + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well PLYImporter::~PLYImporter() { - // empty + // empty } // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool PLYImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const +bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - const std::string extension = GetExtension(pFile); + const std::string extension = GetExtension(pFile); - if (extension == "ply") - return true; - else if (!extension.length() || checkSig) - { - if (!pIOHandler)return true; - const char* tokens[] = {"ply"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); - } - return false; + if (extension == "ply") + return true; + else if (!extension.length() || checkSig) + { + if (!pIOHandler)return true; + const char* tokens[] = { "ply" }; + return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); + } + return false; } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* PLYImporter::GetInfo () const +const aiImporterDesc* PLYImporter::GetInfo() const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ -static bool isBigEndian( const char* szMe ) { - ai_assert( NULL != szMe ); +static bool isBigEndian(const char* szMe) { + ai_assert(NULL != szMe); - // binary_little_endian - // binary_big_endian - bool isBigEndian( false ); + // binary_little_endian + // binary_big_endian + bool isBigEndian(false); #if (defined AI_BUILD_BIG_ENDIAN) - if ( 'l' == *szMe || 'L' == *szMe ) { - isBigEndian = true; -} + if ( 'l' == *szMe || 'L' == *szMe ) { + isBigEndian = true; + } #else - if ( 'b' == *szMe || 'B' == *szMe ) { - isBigEndian = true; - } + if ('b' == *szMe || 'B' == *szMe) { + isBigEndian = true; + } #endif // ! AI_BUILD_BIG_ENDIAN - return isBigEndian; + return isBigEndian; } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void PLYImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) +void PLYImporter::InternReadFile(const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) { - std::unique_ptr file( pIOHandler->Open( pFile)); + static const std::string mode = "rb"; + std::unique_ptr fileStream(pIOHandler->Open(pFile, mode)); + if (!fileStream.get()) { + throw DeadlyImportError("Failed to open file " + pFile + "."); + } - // Check whether we can read from the file - if( file.get() == NULL) { - throw DeadlyImportError( "Failed to open PLY file " + pFile + "."); + // Get the file-size + size_t fileSize = fileStream->FileSize(); + + IOStreamBuffer streamedBuffer(1024 * 1024); + streamedBuffer.open(fileStream.get()); + + // the beginning of the file must be PLY - magic, magic + std::vector headerCheck; + streamedBuffer.getNextDataLine(headerCheck, '\\'); + + if ((headerCheck.size() >= 3) && (headerCheck[0] != 'P' && headerCheck[0] != 'p') || + (headerCheck[1] != 'L' && headerCheck[1] != 'l') || + (headerCheck[2] != 'Y' && headerCheck[2] != 'y')) + { + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there"); + } + + std::vector mBuffer2; + streamedBuffer.getNextDataLine(mBuffer2, '\\'); + mBuffer = (unsigned char*)&mBuffer2[0]; + + char* szMe = (char*)&this->mBuffer[0]; + SkipSpacesAndLineEnd(szMe, (const char**)&szMe); + + // determine the format of the file data and construct the aimesh + PLY::DOM sPlyDom; + this->pcDOM = &sPlyDom; + + if (TokenMatch(szMe, "format", 6)) { + if (TokenMatch(szMe, "ascii", 5)) { + SkipLine(szMe, (const char**)&szMe); + if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) + { + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); + + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)"); + } } + else if (!::strncmp(szMe, "binary_", 7)) + { + szMe += 7; + const bool bIsBE(isBigEndian(szMe)); - // allocate storage and copy the contents of the file to a memory buffer - std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); - mBuffer = (unsigned char*)&mBuffer2[0]; + // skip the line, parse the rest of the header and build the DOM + if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) + { + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); - // the beginning of the file must be PLY - magic, magic - if ((mBuffer[0] != 'P' && mBuffer[0] != 'p') || - (mBuffer[1] != 'L' && mBuffer[1] != 'l') || - (mBuffer[2] != 'Y' && mBuffer[2] != 'y')) { - throw DeadlyImportError( "Invalid .ply file: Magic number \'ply\' is no there"); - } - - char* szMe = (char*)&this->mBuffer[3]; - SkipSpacesAndLineEnd(szMe,(const char**)&szMe); - - // determine the format of the file data - PLY::DOM sPlyDom; - if (TokenMatch(szMe,"format",6)) { - if (TokenMatch(szMe,"ascii",5)) { - SkipLine(szMe,(const char**)&szMe); - if(!PLY::DOM::ParseInstance(szMe,&sPlyDom)) - throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#1)"); - } else if (!::strncmp(szMe,"binary_",7)) - { - szMe += 7; - const bool bIsBE( isBigEndian( szMe ) ); - - // skip the line, parse the rest of the header and build the DOM - SkipLine(szMe,(const char**)&szMe); - if ( !PLY::DOM::ParseInstanceBinary( szMe, &sPlyDom, bIsBE ) ) { - throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#2)" ); - } - } else { - throw DeadlyImportError( "Invalid .ply file: Unknown file format" ); - } + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)"); + } } else { - AI_DEBUG_INVALIDATE_PTR(this->mBuffer); - throw DeadlyImportError( "Invalid .ply file: Missing format specification"); + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); + + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Unknown file format"); } - this->pcDOM = &sPlyDom; + } + else + { + AI_DEBUG_INVALIDATE_PTR(this->mBuffer); + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); - // now load a list of vertices. This must be successfully in order to procedure - std::vector avPositions; - this->LoadVertices(&avPositions,false); + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Missing format specification"); + } - if ( avPositions.empty() ) { - throw DeadlyImportError( "Invalid .ply file: No vertices found. " - "Unable to parse the data format of the PLY file." ); - } + //free the file buffer + streamedBuffer.close(); - // now load a list of normals. - std::vector avNormals; - LoadVertices(&avNormals,true); + if (mGeneratedMesh == NULL) + { + throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data "); + } - // load the face list - std::vector avFaces; - LoadFaces(&avFaces); - - // if no face list is existing we assume that the vertex - // list is containing a list of triangles - if (avFaces.empty()) + // if no face list is existing we assume that the vertex + // list is containing a list of points + bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false; + if (pointsOnly) + { + if (mGeneratedMesh->mNumVertices < 3) { - if (avPositions.size() < 3) - { - throw DeadlyImportError( "Invalid .ply file: Not enough " - "vertices to build a proper face list. "); - } + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); - const unsigned int iNum = (unsigned int)avPositions.size() / 3; - for (unsigned int i = 0; i< iNum;++i) - { - PLY::Face sFace; - sFace.mIndices.push_back((iNum*3)); - sFace.mIndices.push_back((iNum*3)+1); - sFace.mIndices.push_back((iNum*3)+2); - avFaces.push_back(sFace); - } + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Not enough " + "vertices to build a proper face list. "); } - // now load a list of all materials - std::vector avMaterials; - LoadMaterial(&avMaterials); + const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3; + mGeneratedMesh->mNumFaces = iNum; + mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; - // now load a list of all vertex color channels - std::vector avColors; - avColors.reserve(avPositions.size()); - LoadVertexColor(&avColors); - - // now try to load texture coordinates - std::vector avTexCoords; - avTexCoords.reserve(avPositions.size()); - LoadTextureCoordinates(&avTexCoords); - - // now replace the default material in all faces and validate all material indices - ReplaceDefaultMaterial(&avFaces,&avMaterials); - - // now convert this to a list of aiMesh instances - std::vector avMeshes; - avMeshes.reserve(avMaterials.size()+1); - ConvertMeshes(&avFaces,&avPositions,&avNormals, - &avColors,&avTexCoords,&avMaterials,&avMeshes); - - if ( avMeshes.empty() ) { - throw DeadlyImportError( "Invalid .ply file: Unable to extract mesh data " ); + for (unsigned int i = 0; i < iNum; ++i) + { + mGeneratedMesh->mFaces[i].mNumIndices = 3; + mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3]; + mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3); + mGeneratedMesh->mFaces[i].mIndices[1] = (i * 3) + 1; + mGeneratedMesh->mFaces[i].mIndices[2] = (i * 3) + 2; } + } - // now generate the output scene object. Fill the material list - pScene->mNumMaterials = (unsigned int)avMaterials.size(); - pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; - for ( unsigned int i = 0; i < pScene->mNumMaterials; ++i ) { - pScene->mMaterials[ i ] = avMaterials[ i ]; - } + // now load a list of all materials + std::vector avMaterials; + std::string defaultTexture; + LoadMaterial(&avMaterials, defaultTexture, pointsOnly); - // fill the mesh list - pScene->mNumMeshes = (unsigned int)avMeshes.size(); - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for ( unsigned int i = 0; i < pScene->mNumMeshes; ++i ) { - pScene->mMeshes[ i ] = avMeshes[ i ]; - } + // now generate the output scene object. Fill the material list + pScene->mNumMaterials = (unsigned int)avMaterials.size(); + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) { + pScene->mMaterials[i] = avMaterials[i]; + } - // generate a simple node structure - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; - pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; + // fill the mesh list + pScene->mNumMeshes = 1; + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + pScene->mMeshes[0] = mGeneratedMesh; - for ( unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i ) { - pScene->mRootNode->mMeshes[ i ] = i; - } + // generate a simple node structure + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; + pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; + + for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i) { + pScene->mRootNode->mMeshes[i] = i; + } } -// ------------------------------------------------------------------------------------------------ -// Split meshes by material IDs -void PLYImporter::ConvertMeshes(std::vector* avFaces, - const std::vector* avPositions, - const std::vector* avNormals, - const std::vector* avColors, - const std::vector* avTexCoords, - const std::vector* avMaterials, - std::vector* avOut) +void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) { - ai_assert(NULL != avFaces); - ai_assert(NULL != avPositions); - ai_assert(NULL != avMaterials); + ai_assert(NULL != pcElement); + ai_assert(NULL != instElement); - // split by materials - std::vector* aiSplit = new std::vector[avMaterials->size()]; + ai_uint aiPositions[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiTypes[3] = { EDT_Char, EDT_Char, EDT_Char }; - unsigned int iNum = 0; - for (std::vector::const_iterator i = avFaces->begin();i != avFaces->end();++i,++iNum) - aiSplit[(*i).iMaterialIndex].push_back(iNum); + ai_uint aiNormal[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiNormalTypes[3] = { EDT_Char, EDT_Char, EDT_Char }; - // now generate sub-meshes - for (unsigned int p = 0; p < avMaterials->size();++p) + unsigned int aiColors[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiColorsTypes[4] = { EDT_Char, EDT_Char, EDT_Char, EDT_Char }; + + unsigned int aiTexcoord[2] = { 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiTexcoordTypes[2] = { EDT_Char, EDT_Char }; + + unsigned int cnt = 0; + + // now check whether which normal components are available + unsigned int _a = 0; + for (std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) + { + if ((*a).bIsList)continue; + + // Positions + if (PLY::EST_XCoord == (*a).Semantic) { - if (aiSplit[p].size() != 0) - { - // allocate the mesh object - aiMesh* p_pcOut = new aiMesh(); - p_pcOut->mMaterialIndex = p; - - p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); - p_pcOut->mFaces = new aiFace[aiSplit[p].size()]; - - // at first we need to determine the size of the output vector array - unsigned int iNum = 0; - for (unsigned int i = 0; i < aiSplit[p].size();++i) - { - iNum += (unsigned int)(*avFaces)[aiSplit[p][i]].mIndices.size(); - } - p_pcOut->mNumVertices = iNum; - if( 0 == iNum ) { // nothing to do - delete[] aiSplit; // cleanup - delete p_pcOut; - return; - } - p_pcOut->mVertices = new aiVector3D[iNum]; - - if (!avColors->empty()) - p_pcOut->mColors[0] = new aiColor4D[iNum]; - if (!avTexCoords->empty()) - { - p_pcOut->mNumUVComponents[0] = 2; - p_pcOut->mTextureCoords[0] = new aiVector3D[iNum]; - } - if (!avNormals->empty()) - p_pcOut->mNormals = new aiVector3D[iNum]; - - // add all faces - iNum = 0; - unsigned int iVertex = 0; - for (std::vector::const_iterator i = aiSplit[p].begin(); - i != aiSplit[p].end();++i,++iNum) - { - p_pcOut->mFaces[iNum].mNumIndices = (unsigned int)(*avFaces)[*i].mIndices.size(); - p_pcOut->mFaces[iNum].mIndices = new unsigned int[p_pcOut->mFaces[iNum].mNumIndices]; - - // build an unique set of vertices/colors for this face - for (unsigned int q = 0; q < p_pcOut->mFaces[iNum].mNumIndices;++q) - { - p_pcOut->mFaces[iNum].mIndices[q] = iVertex; - const size_t idx = ( *avFaces )[ *i ].mIndices[ q ]; - if( idx >= ( *avPositions ).size() ) { - // out of border - continue; - } - p_pcOut->mVertices[ iVertex ] = ( *avPositions )[ idx ]; - - if (!avColors->empty()) - p_pcOut->mColors[ 0 ][ iVertex ] = ( *avColors )[ idx ]; - - if (!avTexCoords->empty()) - { - const aiVector2D& vec = ( *avTexCoords )[ idx ]; - p_pcOut->mTextureCoords[0][iVertex].x = vec.x; - p_pcOut->mTextureCoords[0][iVertex].y = vec.y; - } - - if (!avNormals->empty()) - p_pcOut->mNormals[ iVertex ] = ( *avNormals )[ idx ]; - iVertex++; - } - - } - // add the mesh to the output list - avOut->push_back(p_pcOut); - } + cnt++; + aiPositions[0] = _a; + aiTypes[0] = (*a).eType; } - delete[] aiSplit; // cleanup + else if (PLY::EST_YCoord == (*a).Semantic) + { + cnt++; + aiPositions[1] = _a; + aiTypes[1] = (*a).eType; + } + else if (PLY::EST_ZCoord == (*a).Semantic) + { + cnt++; + aiPositions[2] = _a; + aiTypes[2] = (*a).eType; + } + + // Normals + else if (PLY::EST_XNormal == (*a).Semantic) + { + cnt++; + aiNormal[0] = _a; + aiNormalTypes[0] = (*a).eType; + } + else if (PLY::EST_YNormal == (*a).Semantic) + { + cnt++; + aiNormal[1] = _a; + aiNormalTypes[1] = (*a).eType; + } + else if (PLY::EST_ZNormal == (*a).Semantic) + { + cnt++; + aiNormal[2] = _a; + aiNormalTypes[2] = (*a).eType; + } + // Colors + else if (PLY::EST_Red == (*a).Semantic) + { + cnt++; + aiColors[0] = _a; + aiColorsTypes[0] = (*a).eType; + } + else if (PLY::EST_Green == (*a).Semantic) + { + cnt++; + aiColors[1] = _a; + aiColorsTypes[1] = (*a).eType; + } + else if (PLY::EST_Blue == (*a).Semantic) + { + cnt++; + aiColors[2] = _a; + aiColorsTypes[2] = (*a).eType; + } + else if (PLY::EST_Alpha == (*a).Semantic) + { + cnt++; + aiColors[3] = _a; + aiColorsTypes[3] = (*a).eType; + } + // Texture coordinates + else if (PLY::EST_UTextureCoord == (*a).Semantic) + { + cnt++; + aiTexcoord[0] = _a; + aiTexcoordTypes[0] = (*a).eType; + } + else if (PLY::EST_VTextureCoord == (*a).Semantic) + { + cnt++; + aiTexcoord[1] = _a; + aiTexcoordTypes[1] = (*a).eType; + } + } + + // check whether we have a valid source for the vertex data + if (0 != cnt) + { + // Position + aiVector3D vOut; + if (0xFFFFFFFF != aiPositions[0]) + { + vOut.x = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]); + } + + if (0xFFFFFFFF != aiPositions[1]) + { + vOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]); + } + + if (0xFFFFFFFF != aiPositions[2]) + { + vOut.z = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]); + } + + // Normals + aiVector3D nOut; + bool haveNormal = false; + if (0xFFFFFFFF != aiNormal[0]) + { + nOut.x = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]); + haveNormal = true; + } + + if (0xFFFFFFFF != aiNormal[1]) + { + nOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]); + haveNormal = true; + } + + if (0xFFFFFFFF != aiNormal[2]) + { + nOut.z = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]); + haveNormal = true; + } + + //Colors + aiColor4D cOut; + bool haveColor = false; + if (0xFFFFFFFF != aiColors[0]) + { + cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[0]).avList.front(), aiColorsTypes[0]); + haveColor = true; + } + + if (0xFFFFFFFF != aiColors[1]) + { + cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[1]).avList.front(), aiColorsTypes[1]); + haveColor = true; + } + + if (0xFFFFFFFF != aiColors[2]) + { + cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[2]).avList.front(), aiColorsTypes[2]); + haveColor = true; + } + + // assume 1.0 for the alpha channel ifit is not set + if (0xFFFFFFFF == aiColors[3]) + { + cOut.a = 1.0; + } + else + { + cOut.a = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[3]).avList.front(), aiColorsTypes[3]); + + haveColor = true; + } + + //Texture coordinates + aiVector3D tOut; + tOut.z = 0; + bool haveTextureCoords = false; + if (0xFFFFFFFF != aiTexcoord[0]) + { + tOut.x = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]); + haveTextureCoords = true; + } + + if (0xFFFFFFFF != aiTexcoord[1]) + { + tOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]); + haveTextureCoords = true; + } + + //create aiMesh if needed + if (mGeneratedMesh == NULL) + { + mGeneratedMesh = new aiMesh(); + mGeneratedMesh->mMaterialIndex = 0; + } + + if (mGeneratedMesh->mVertices == NULL) + { + mGeneratedMesh->mNumVertices = pcElement->NumOccur; + mGeneratedMesh->mVertices = new aiVector3D[mGeneratedMesh->mNumVertices]; + } + + mGeneratedMesh->mVertices[pos] = vOut; + + if (haveNormal) + { + if (mGeneratedMesh->mNormals == NULL) + mGeneratedMesh->mNormals = new aiVector3D[mGeneratedMesh->mNumVertices]; + mGeneratedMesh->mNormals[pos] = nOut; + } + + if (haveColor) + { + if (mGeneratedMesh->mColors[0] == NULL) + mGeneratedMesh->mColors[0] = new aiColor4D[mGeneratedMesh->mNumVertices]; + mGeneratedMesh->mColors[0][pos] = cOut; + } + + if (haveTextureCoords) + { + if (mGeneratedMesh->mTextureCoords[0] == NULL) + { + mGeneratedMesh->mNumUVComponents[0] = 2; + mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices]; + } + mGeneratedMesh->mTextureCoords[0][pos] = tOut; + } + } } -// ------------------------------------------------------------------------------------------------ -// Generate a default material if none was specified and apply it to all vanilla faces -void PLYImporter::ReplaceDefaultMaterial(std::vector* avFaces, - std::vector* avMaterials) -{ - bool bNeedDefaultMat = false; - - for (std::vector::iterator i = avFaces->begin();i != avFaces->end();++i) { - if (0xFFFFFFFF == (*i).iMaterialIndex) { - bNeedDefaultMat = true; - (*i).iMaterialIndex = (unsigned int)avMaterials->size(); - } - else if ((*i).iMaterialIndex >= avMaterials->size() ) { - // clamp the index - (*i).iMaterialIndex = (unsigned int)avMaterials->size()-1; - } - } - - if (bNeedDefaultMat) { - // generate a default material - aiMaterial* pcHelper = new aiMaterial(); - - // fill in a default material - int iMode = (int)aiShadingMode_Gouraud; - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - aiColor3D clr; - clr.b = clr.g = clr.r = 0.6f; - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_SPECULAR); - - clr.b = clr.g = clr.r = 0.05f; - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); - - // The face order is absolutely undefined for PLY, so we have to - // use two-sided rendering to be sure it's ok. - const int two_sided = 1; - pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED); - - avMaterials->push_back(pcHelper); - } -} - -// ------------------------------------------------------------------------------------------------ -void PLYImporter::LoadTextureCoordinates(std::vector* pvOut) -{ - ai_assert(NULL != pvOut); - - unsigned int aiPositions[2] = {0xFFFFFFFF,0xFFFFFFFF}; - PLY::EDataType aiTypes[2] = {EDT_Char,EDT_Char}; - PLY::ElementInstanceList* pcList = NULL; - unsigned int cnt = 0; - - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - if (PLY::EEST_Vertex == (*i).eSemantic) - { - pcList = &this->pcDOM->alElementData[_i]; - - // now check whether which normal components are available - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - if (PLY::EST_UTextureCoord == (*a).Semantic) - { - cnt++; - aiPositions[0] = _a; - aiTypes[0] = (*a).eType; - } - else if (PLY::EST_VTextureCoord == (*a).Semantic) - { - cnt++; - aiPositions[1] = _a; - aiTypes[1] = (*a).eType; - } - } - } - } - // check whether we have a valid source for the texture coordinates data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - // convert the vertices to sp floats - aiVector2D vOut; - - if (0xFFFFFFFF != aiPositions[0]) - { - vOut.x = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]); - } - - if (0xFFFFFFFF != aiPositions[1]) - { - vOut.y = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]); - } - // and add them to our nice list - pvOut->push_back(vOut); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Try to extract vertices from the PLY DOM -void PLYImporter::LoadVertices(std::vector* pvOut, bool p_bNormals) -{ - ai_assert(NULL != pvOut); - - ai_uint aiPositions[3] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; - PLY::EDataType aiTypes[3] = {EDT_Char,EDT_Char,EDT_Char}; - PLY::ElementInstanceList* pcList = NULL; - unsigned int cnt = 0; - - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - if (PLY::EEST_Vertex == (*i).eSemantic) - { - pcList = &pcDOM->alElementData[_i]; - - // load normal vectors? - if (p_bNormals) - { - // now check whether which normal components are available - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - if (PLY::EST_XNormal == (*a).Semantic) - { - cnt++; - aiPositions[0] = _a; - aiTypes[0] = (*a).eType; - } - else if (PLY::EST_YNormal == (*a).Semantic) - { - cnt++; - aiPositions[1] = _a; - aiTypes[1] = (*a).eType; - } - else if (PLY::EST_ZNormal == (*a).Semantic) - { - cnt++; - aiPositions[2] = _a; - aiTypes[2] = (*a).eType; - } - } - } - // load vertex coordinates - else - { - // now check whether which coordinate sets are available - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - if (PLY::EST_XCoord == (*a).Semantic) - { - cnt++; - aiPositions[0] = _a; - aiTypes[0] = (*a).eType; - } - else if (PLY::EST_YCoord == (*a).Semantic) - { - cnt++; - aiPositions[1] = _a; - aiTypes[1] = (*a).eType; - } - else if (PLY::EST_ZCoord == (*a).Semantic) - { - cnt++; - aiPositions[2] = _a; - aiTypes[2] = (*a).eType; - } - if (3 == cnt)break; - } - } - break; - } - } - // check whether we have a valid source for the vertex data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator - i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - // convert the vertices to sp floats - aiVector3D vOut; - - if (0xFFFFFFFF != aiPositions[0]) - { - vOut.x = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]); - } - - if (0xFFFFFFFF != aiPositions[1]) - { - vOut.y = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]); - } - - if (0xFFFFFFFF != aiPositions[2]) - { - vOut.z = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[2]).avList.front(),aiTypes[2]); - } - - // and add them to our nice list - pvOut->push_back(vOut); - } - } -} // ------------------------------------------------------------------------------------------------ // Convert a color component to [0...1] -ai_real PLYImporter::NormalizeColorValue (PLY::PropertyInstance::ValueUnion val, - PLY::EDataType eType) +ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, + PLY::EDataType eType) { - switch (eType) - { - case EDT_Float: - return val.fFloat; - case EDT_Double: - return (ai_real)val.fDouble; + switch (eType) + { + case EDT_Float: + return val.fFloat; + case EDT_Double: + return (ai_real)val.fDouble; - case EDT_UChar: - return (ai_real)val.iUInt / (ai_real)0xFF; - case EDT_Char: - return (ai_real)(val.iInt+(0xFF/2)) / (ai_real)0xFF; - case EDT_UShort: - return (ai_real)val.iUInt / (ai_real)0xFFFF; - case EDT_Short: - return (ai_real)(val.iInt+(0xFFFF/2)) / (ai_real)0xFFFF; - case EDT_UInt: - return (ai_real)val.iUInt / (ai_real)0xFFFF; - case EDT_Int: - return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f; - default: ; - }; - return 0.0f; -} - -// ------------------------------------------------------------------------------------------------ -// Try to extract proper vertex colors from the PLY DOM -void PLYImporter::LoadVertexColor(std::vector* pvOut) -{ - ai_assert(NULL != pvOut); - - unsigned int aiPositions[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; - PLY::EDataType aiTypes[4] = {EDT_Char, EDT_Char, EDT_Char, EDT_Char}; // silencing gcc - unsigned int cnt = 0; - PLY::ElementInstanceList* pcList = NULL; - - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - if (PLY::EEST_Vertex == (*i).eSemantic) - { - pcList = &this->pcDOM->alElementData[_i]; - - // now check whether which coordinate sets are available - unsigned int _a = 0; - for (std::vector::const_iterator - a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - if (PLY::EST_Red == (*a).Semantic) - { - cnt++; - aiPositions[0] = _a; - aiTypes[0] = (*a).eType; - } - else if (PLY::EST_Green == (*a).Semantic) - { - cnt++; - aiPositions[1] = _a; - aiTypes[1] = (*a).eType; - } - else if (PLY::EST_Blue == (*a).Semantic) - { - cnt++; - aiPositions[2] = _a; - aiTypes[2] = (*a).eType; - } - else if (PLY::EST_Alpha == (*a).Semantic) - { - cnt++; - aiPositions[3] = _a; - aiTypes[3] = (*a).eType; - } - if (4 == cnt)break; - } - break; - } - } - // check whether we have a valid source for the vertex data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - // convert the vertices to sp floats - aiColor4D vOut; - - if (0xFFFFFFFF != aiPositions[0]) - { - vOut.r = NormalizeColorValue(GetProperty((*i).alProperties, - aiPositions[0]).avList.front(),aiTypes[0]); - } - - if (0xFFFFFFFF != aiPositions[1]) - { - vOut.g = NormalizeColorValue(GetProperty((*i).alProperties, - aiPositions[1]).avList.front(),aiTypes[1]); - } - - if (0xFFFFFFFF != aiPositions[2]) - { - vOut.b = NormalizeColorValue(GetProperty((*i).alProperties, - aiPositions[2]).avList.front(),aiTypes[2]); - } - - // assume 1.0 for the alpha channel ifit is not set - if (0xFFFFFFFF == aiPositions[3])vOut.a = 1.0; - else - { - vOut.a = NormalizeColorValue(GetProperty((*i).alProperties, - aiPositions[3]).avList.front(),aiTypes[3]); - } - - // and add them to our nice list - pvOut->push_back(vOut); - } - } + case EDT_UChar: + return (ai_real)val.iUInt / (ai_real)0xFF; + case EDT_Char: + return (ai_real)(val.iInt + (0xFF / 2)) / (ai_real)0xFF; + case EDT_UShort: + return (ai_real)val.iUInt / (ai_real)0xFFFF; + case EDT_Short: + return (ai_real)(val.iInt + (0xFFFF / 2)) / (ai_real)0xFFFF; + case EDT_UInt: + return (ai_real)val.iUInt / (ai_real)0xFFFF; + case EDT_Int: + return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f; + default:; + }; + return 0.0f; } // ------------------------------------------------------------------------------------------------ // Try to extract proper faces from the PLY DOM -void PLYImporter::LoadFaces(std::vector* pvOut) +void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) { - ai_assert(NULL != pvOut); + ai_assert(NULL != pcElement); + ai_assert(NULL != instElement); - PLY::ElementInstanceList* pcList = NULL; - bool bOne = false; + if (mGeneratedMesh == NULL) + throw DeadlyImportError("Invalid .ply file: Vertices shoud be declared before faces"); - // index of the vertex index list - unsigned int iProperty = 0xFFFFFFFF; - PLY::EDataType eType = EDT_Char; - bool bIsTriStrip = false; + bool bOne = false; - // index of the material index property - unsigned int iMaterialIndex = 0xFFFFFFFF; - PLY::EDataType eType2 = EDT_Char; + // index of the vertex index list + unsigned int iProperty = 0xFFFFFFFF; + PLY::EDataType eType = EDT_Char; + bool bIsTriStrip = false; - // search in the DOM for a face entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) + // index of the material index property + //unsigned int iMaterialIndex = 0xFFFFFFFF; + //PLY::EDataType eType2 = EDT_Char; + + // texture coordinates + unsigned int iTextureCoord = 0xFFFFFFFF; + PLY::EDataType eType3 = EDT_Char; + + // face = unique number of vertex indices + if (PLY::EEST_Face == pcElement->eSemantic) + { + unsigned int _a = 0; + for (std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) { - // face = unique number of vertex indices - if (PLY::EEST_Face == (*i).eSemantic) - { - pcList = &pcDOM->alElementData[_i]; - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if (PLY::EST_VertexIndex == (*a).Semantic) - { - // must be a dynamic list! - if (!(*a).bIsList)continue; - iProperty = _a; - bOne = true; - eType = (*a).eType; - } - else if (PLY::EST_MaterialIndex == (*a).Semantic) - { - if ((*a).bIsList)continue; - iMaterialIndex = _a; - bOne = true; - eType2 = (*a).eType; - } - } - break; - } - // triangle strip - // TODO: triangle strip and material index support??? - else if (PLY::EEST_TriStrip == (*i).eSemantic) - { - // find a list property in this ... - pcList = &this->pcDOM->alElementData[_i]; - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - // must be a dynamic list! - if (!(*a).bIsList)continue; - iProperty = _a; - bOne = true; - bIsTriStrip = true; - eType = (*a).eType; - break; - } - break; - } + if (PLY::EST_VertexIndex == (*a).Semantic) + { + // must be a dynamic list! + if (!(*a).bIsList) + continue; + + iProperty = _a; + bOne = true; + eType = (*a).eType; + } + /*else if (PLY::EST_MaterialIndex == (*a).Semantic) + { + if ((*a).bIsList) + continue; + iMaterialIndex = _a; + bOne = true; + eType2 = (*a).eType; + }*/ + else if (PLY::EST_TextureCoordinates == (*a).Semantic) + { + // must be a dynamic list! + if (!(*a).bIsList) + continue; + iTextureCoord = _a; + bOne = true; + eType3 = (*a).eType; + } } - // check whether we have at least one per-face information set - if (pcList && bOne) + } + // triangle strip + // TODO: triangle strip and material index support??? + else if (PLY::EEST_TriStrip == pcElement->eSemantic) + { + unsigned int _a = 0; + for (std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) { - if (!bIsTriStrip) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - PLY::Face sFace; - - // parse the list of vertex indices - if (0xFFFFFFFF != iProperty) - { - const unsigned int iNum = (unsigned int)GetProperty((*i).alProperties, iProperty).avList.size(); - sFace.mIndices.resize(iNum); - - std::vector::const_iterator p = - GetProperty((*i).alProperties, iProperty).avList.begin(); - - for (unsigned int a = 0; a < iNum;++a,++p) - { - sFace.mIndices[a] = PLY::PropertyInstance::ConvertTo(*p,eType); - } - } - - // parse the material index - if (0xFFFFFFFF != iMaterialIndex) - { - sFace.iMaterialIndex = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, iMaterialIndex).avList.front(),eType2); - } - pvOut->push_back(sFace); - } - } - else // triangle strips - { - // normally we have only one triangle strip instance where - // a value of -1 indicates a restart of the strip - bool flip = false; - for (std::vector::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) { - const std::vector& quak = GetProperty((*i).alProperties, iProperty).avList; - pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); - - int aiTable[2] = {-1,-1}; - for (std::vector::const_iterator a = quak.begin();a != quak.end();++a) { - const int p = PLY::PropertyInstance::ConvertTo(*a,eType); - - if (-1 == p) { - // restart the strip ... - aiTable[0] = aiTable[1] = -1; - flip = false; - continue; - } - if (-1 == aiTable[0]) { - aiTable[0] = p; - continue; - } - if (-1 == aiTable[1]) { - aiTable[1] = p; - continue; - } - - pvOut->push_back(PLY::Face()); - PLY::Face& sFace = pvOut->back(); - sFace.mIndices[0] = aiTable[0]; - sFace.mIndices[1] = aiTable[1]; - sFace.mIndices[2] = p; - if ((flip = !flip)) { - std::swap(sFace.mIndices[0],sFace.mIndices[1]); - } - - aiTable[0] = aiTable[1]; - aiTable[1] = p; - } - } - } + // must be a dynamic list! + if (!(*a).bIsList) + continue; + iProperty = _a; + bOne = true; + bIsTriStrip = true; + eType = (*a).eType; + break; } + } + + // check whether we have at least one per-face information set + if (bOne) + { + if (mGeneratedMesh->mFaces == NULL) + { + mGeneratedMesh->mNumFaces = pcElement->NumOccur; + mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; + } + + if (!bIsTriStrip) + { + // parse the list of vertex indices + if (0xFFFFFFFF != iProperty) + { + const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iProperty).avList.size(); + mGeneratedMesh->mFaces[pos].mNumIndices = iNum; + mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[iNum]; + + std::vector::const_iterator p = + GetProperty(instElement->alProperties, iProperty).avList.begin(); + + for (unsigned int a = 0; a < iNum; ++a, ++p) + { + mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo(*p, eType); + } + } + + // parse the material index + // cannot be handled without processing the whole file first + /*if (0xFFFFFFFF != iMaterialIndex) + { + mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2); + }*/ + + if (0xFFFFFFFF != iTextureCoord) + { + const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iTextureCoord).avList.size(); + + //should be 6 coords + std::vector::const_iterator p = + GetProperty(instElement->alProperties, iTextureCoord).avList.begin(); + + if ((iNum / 3) == 2) // X Y coord + { + for (unsigned int a = 0; a < iNum; ++a, ++p) + { + unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2]; + if (vindex < mGeneratedMesh->mNumVertices) + { + if (mGeneratedMesh->mTextureCoords[0] == NULL) + { + mGeneratedMesh->mNumUVComponents[0] = 2; + mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices]; + } + + if (a % 2 == 0) + mGeneratedMesh->mTextureCoords[0][vindex].x = PLY::PropertyInstance::ConvertTo(*p, eType3); + else + mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo(*p, eType3); + + mGeneratedMesh->mTextureCoords[0][vindex].z = 0; + } + } + } + } + } + else // triangle strips + { + // normally we have only one triangle strip instance where + // a value of -1 indicates a restart of the strip + bool flip = false; + const std::vector& quak = GetProperty(instElement->alProperties, iProperty).avList; + //pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); //Limits memory consumption + + int aiTable[2] = { -1, -1 }; + for (std::vector::const_iterator a = quak.begin(); a != quak.end(); ++a) { + const int p = PLY::PropertyInstance::ConvertTo(*a, eType); + + if (-1 == p) { + // restart the strip ... + aiTable[0] = aiTable[1] = -1; + flip = false; + continue; + } + if (-1 == aiTable[0]) { + aiTable[0] = p; + continue; + } + if (-1 == aiTable[1]) { + aiTable[1] = p; + continue; + } + + if (mGeneratedMesh->mFaces == NULL) + { + mGeneratedMesh->mNumFaces = pcElement->NumOccur; + mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; + } + + mGeneratedMesh->mFaces[pos].mNumIndices = 3; + mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[3]; + mGeneratedMesh->mFaces[pos].mIndices[0] = aiTable[0]; + mGeneratedMesh->mFaces[pos].mIndices[1] = aiTable[1]; + mGeneratedMesh->mFaces[pos].mIndices[2] = aiTable[2]; + + if ((flip = !flip)) { + std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]); + } + + aiTable[0] = aiTable[1]; + aiTable[1] = p; + } + } + } } // ------------------------------------------------------------------------------------------------ // Get a RGBA color in [0...1] range void PLYImporter::GetMaterialColor(const std::vector& avList, - unsigned int aiPositions[4], - PLY::EDataType aiTypes[4], - aiColor4D* clrOut) + unsigned int aiPositions[4], + PLY::EDataType aiTypes[4], + aiColor4D* clrOut) { - ai_assert(NULL != clrOut); + ai_assert(NULL != clrOut); - if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f; - else - { - clrOut->r = NormalizeColorValue(GetProperty(avList, - aiPositions[0]).avList.front(),aiTypes[0]); - } + if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f; + else + { + clrOut->r = NormalizeColorValue(GetProperty(avList, + aiPositions[0]).avList.front(), aiTypes[0]); + } - if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f; - else - { - clrOut->g = NormalizeColorValue(GetProperty(avList, - aiPositions[1]).avList.front(),aiTypes[1]); - } + if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f; + else + { + clrOut->g = NormalizeColorValue(GetProperty(avList, + aiPositions[1]).avList.front(), aiTypes[1]); + } - if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f; - else - { - clrOut->b = NormalizeColorValue(GetProperty(avList, - aiPositions[2]).avList.front(),aiTypes[2]); - } + if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f; + else + { + clrOut->b = NormalizeColorValue(GetProperty(avList, + aiPositions[2]).avList.front(), aiTypes[2]); + } - // assume 1.0 for the alpha channel ifit is not set - if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f; - else - { - clrOut->a = NormalizeColorValue(GetProperty(avList, - aiPositions[3]).avList.front(),aiTypes[3]); - } + // assume 1.0 for the alpha channel ifit is not set + if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f; + else + { + clrOut->a = NormalizeColorValue(GetProperty(avList, + aiPositions[3]).avList.front(), aiTypes[3]); + } } // ------------------------------------------------------------------------------------------------ // Extract a material from the PLY DOM -void PLYImporter::LoadMaterial(std::vector* pvOut) +void PLYImporter::LoadMaterial(std::vector* pvOut, std::string &defaultTexture, const bool pointsOnly) { - ai_assert(NULL != pvOut); + ai_assert(NULL != pvOut); - // diffuse[4], specular[4], ambient[4] - // rgba order - unsigned int aaiPositions[3][4] = { + // diffuse[4], specular[4], ambient[4] + // rgba order + unsigned int aaiPositions[3][4] = { - {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}, - {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}, - {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}, - }; + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + }; - PLY::EDataType aaiTypes[3][4] = { - {EDT_Char,EDT_Char,EDT_Char,EDT_Char}, - {EDT_Char,EDT_Char,EDT_Char,EDT_Char}, - {EDT_Char,EDT_Char,EDT_Char,EDT_Char} - }; - PLY::ElementInstanceList* pcList = NULL; + PLY::EDataType aaiTypes[3][4] = { + { EDT_Char, EDT_Char, EDT_Char, EDT_Char }, + { EDT_Char, EDT_Char, EDT_Char, EDT_Char }, + { EDT_Char, EDT_Char, EDT_Char, EDT_Char } + }; + PLY::ElementInstanceList* pcList = NULL; - unsigned int iPhong = 0xFFFFFFFF; - PLY::EDataType ePhong = EDT_Char; + unsigned int iPhong = 0xFFFFFFFF; + PLY::EDataType ePhong = EDT_Char; - unsigned int iOpacity = 0xFFFFFFFF; - PLY::EDataType eOpacity = EDT_Char; + unsigned int iOpacity = 0xFFFFFFFF; + PLY::EDataType eOpacity = EDT_Char; - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = this->pcDOM->alElements.begin(); - i != this->pcDOM->alElements.end();++i,++_i) + // search in the DOM for a vertex entry + unsigned int _i = 0; + for (std::vector::const_iterator i = this->pcDOM->alElements.begin(); + i != this->pcDOM->alElements.end(); ++i, ++_i) + { + if (PLY::EEST_Material == (*i).eSemantic) { - if (PLY::EEST_Material == (*i).eSemantic) + pcList = &this->pcDOM->alElementData[_i]; + + // now check whether which coordinate sets are available + unsigned int _a = 0; + for (std::vector::const_iterator + a = (*i).alProperties.begin(); + a != (*i).alProperties.end(); ++a, ++_a) + { + if ((*a).bIsList)continue; + + // pohng specularity ----------------------------------- + if (PLY::EST_PhongPower == (*a).Semantic) { - pcList = &this->pcDOM->alElementData[_i]; - - // now check whether which coordinate sets are available - unsigned int _a = 0; - for (std::vector::const_iterator - a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - - // pohng specularity ----------------------------------- - if (PLY::EST_PhongPower == (*a).Semantic) - { - iPhong = _a; - ePhong = (*a).eType; - } - - // general opacity ----------------------------------- - if (PLY::EST_Opacity == (*a).Semantic) - { - iOpacity = _a; - eOpacity = (*a).eType; - } - - // diffuse color channels ----------------------------------- - if (PLY::EST_DiffuseRed == (*a).Semantic) - { - aaiPositions[0][0] = _a; - aaiTypes[0][0] = (*a).eType; - } - else if (PLY::EST_DiffuseGreen == (*a).Semantic) - { - aaiPositions[0][1] = _a; - aaiTypes[0][1] = (*a).eType; - } - else if (PLY::EST_DiffuseBlue == (*a).Semantic) - { - aaiPositions[0][2] = _a; - aaiTypes[0][2] = (*a).eType; - } - else if (PLY::EST_DiffuseAlpha == (*a).Semantic) - { - aaiPositions[0][3] = _a; - aaiTypes[0][3] = (*a).eType; - } - // specular color channels ----------------------------------- - else if (PLY::EST_SpecularRed == (*a).Semantic) - { - aaiPositions[1][0] = _a; - aaiTypes[1][0] = (*a).eType; - } - else if (PLY::EST_SpecularGreen == (*a).Semantic) - { - aaiPositions[1][1] = _a; - aaiTypes[1][1] = (*a).eType; - } - else if (PLY::EST_SpecularBlue == (*a).Semantic) - { - aaiPositions[1][2] = _a; - aaiTypes[1][2] = (*a).eType; - } - else if (PLY::EST_SpecularAlpha == (*a).Semantic) - { - aaiPositions[1][3] = _a; - aaiTypes[1][3] = (*a).eType; - } - // ambient color channels ----------------------------------- - else if (PLY::EST_AmbientRed == (*a).Semantic) - { - aaiPositions[2][0] = _a; - aaiTypes[2][0] = (*a).eType; - } - else if (PLY::EST_AmbientGreen == (*a).Semantic) - { - aaiPositions[2][1] = _a; - aaiTypes[2][1] = (*a).eType; - } - else if (PLY::EST_AmbientBlue == (*a).Semantic) - { - aaiPositions[2][2] = _a; - aaiTypes[2][2] = (*a).eType; - } - else if (PLY::EST_AmbientAlpha == (*a).Semantic) - { - aaiPositions[2][3] = _a; - aaiTypes[2][3] = (*a).eType; - } - } - break; + iPhong = _a; + ePhong = (*a).eType; } - } - // check whether we have a valid source for the material data - if (NULL != pcList) { - for (std::vector::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) { - aiColor4D clrOut; - aiMaterial* pcHelper = new aiMaterial(); - // build the diffuse material color - GetMaterialColor((*i).alProperties,aaiPositions[0],aaiTypes[0],&clrOut); - pcHelper->AddProperty(&clrOut,1,AI_MATKEY_COLOR_DIFFUSE); - - // build the specular material color - GetMaterialColor((*i).alProperties,aaiPositions[1],aaiTypes[1],&clrOut); - pcHelper->AddProperty(&clrOut,1,AI_MATKEY_COLOR_SPECULAR); - - // build the ambient material color - GetMaterialColor((*i).alProperties,aaiPositions[2],aaiTypes[2],&clrOut); - pcHelper->AddProperty(&clrOut,1,AI_MATKEY_COLOR_AMBIENT); - - // handle phong power and shading mode - int iMode = (int)aiShadingMode_Gouraud; - if (0xFFFFFFFF != iPhong) { - ai_real fSpec = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(),ePhong); - - // if shininess is 0 (and the pow() calculation would therefore always - // become 1, not depending on the angle), use gouraud lighting - if (fSpec) { - // scale this with 15 ... hopefully this is correct - fSpec *= 15; - pcHelper->AddProperty(&fSpec, 1, AI_MATKEY_SHININESS); - - iMode = (int)aiShadingMode_Phong; - } - } - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - // handle opacity - if (0xFFFFFFFF != iOpacity) { - ai_real fOpacity = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(),eOpacity); - pcHelper->AddProperty(&fOpacity, 1, AI_MATKEY_OPACITY); - } - - // The face order is absolutely undefined for PLY, so we have to - // use two-sided rendering to be sure it's ok. - const int two_sided = 1; - pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED); - - // add the newly created material instance to the list - pvOut->push_back(pcHelper); + // general opacity ----------------------------------- + if (PLY::EST_Opacity == (*a).Semantic) + { + iOpacity = _a; + eOpacity = (*a).eType; } + + // diffuse color channels ----------------------------------- + if (PLY::EST_DiffuseRed == (*a).Semantic) + { + aaiPositions[0][0] = _a; + aaiTypes[0][0] = (*a).eType; + } + else if (PLY::EST_DiffuseGreen == (*a).Semantic) + { + aaiPositions[0][1] = _a; + aaiTypes[0][1] = (*a).eType; + } + else if (PLY::EST_DiffuseBlue == (*a).Semantic) + { + aaiPositions[0][2] = _a; + aaiTypes[0][2] = (*a).eType; + } + else if (PLY::EST_DiffuseAlpha == (*a).Semantic) + { + aaiPositions[0][3] = _a; + aaiTypes[0][3] = (*a).eType; + } + // specular color channels ----------------------------------- + else if (PLY::EST_SpecularRed == (*a).Semantic) + { + aaiPositions[1][0] = _a; + aaiTypes[1][0] = (*a).eType; + } + else if (PLY::EST_SpecularGreen == (*a).Semantic) + { + aaiPositions[1][1] = _a; + aaiTypes[1][1] = (*a).eType; + } + else if (PLY::EST_SpecularBlue == (*a).Semantic) + { + aaiPositions[1][2] = _a; + aaiTypes[1][2] = (*a).eType; + } + else if (PLY::EST_SpecularAlpha == (*a).Semantic) + { + aaiPositions[1][3] = _a; + aaiTypes[1][3] = (*a).eType; + } + // ambient color channels ----------------------------------- + else if (PLY::EST_AmbientRed == (*a).Semantic) + { + aaiPositions[2][0] = _a; + aaiTypes[2][0] = (*a).eType; + } + else if (PLY::EST_AmbientGreen == (*a).Semantic) + { + aaiPositions[2][1] = _a; + aaiTypes[2][1] = (*a).eType; + } + else if (PLY::EST_AmbientBlue == (*a).Semantic) + { + aaiPositions[2][2] = _a; + aaiTypes[2][2] = (*a).eType; + } + else if (PLY::EST_AmbientAlpha == (*a).Semantic) + { + aaiPositions[2][3] = _a; + aaiTypes[2][3] = (*a).eType; + } + } + break; } + else if (PLY::EEST_TextureFile == (*i).eSemantic) + { + defaultTexture = (*i).szName; + } + } + // check whether we have a valid source for the material data + if (NULL != pcList) { + for (std::vector::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i) { + aiColor4D clrOut; + aiMaterial* pcHelper = new aiMaterial(); + + // build the diffuse material color + GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut); + pcHelper->AddProperty(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE); + + // build the specular material color + GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut); + pcHelper->AddProperty(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR); + + // build the ambient material color + GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut); + pcHelper->AddProperty(&clrOut, 1, AI_MATKEY_COLOR_AMBIENT); + + // handle phong power and shading mode + int iMode = (int)aiShadingMode_Gouraud; + if (0xFFFFFFFF != iPhong) { + ai_real fSpec = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(), ePhong); + + // if shininess is 0 (and the pow() calculation would therefore always + // become 1, not depending on the angle), use gouraud lighting + if (fSpec) { + // scale this with 15 ... hopefully this is correct + fSpec *= 15; + pcHelper->AddProperty(&fSpec, 1, AI_MATKEY_SHININESS); + + iMode = (int)aiShadingMode_Phong; + } + } + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + + // handle opacity + if (0xFFFFFFFF != iOpacity) { + ai_real fOpacity = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity); + pcHelper->AddProperty(&fOpacity, 1, AI_MATKEY_OPACITY); + } + + // The face order is absolutely undefined for PLY, so we have to + // use two-sided rendering to be sure it's ok. + const int two_sided = 1; + pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED); + + //default texture + if (!defaultTexture.empty()) + { + const aiString name(defaultTexture.c_str()); + pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0); + } + + if (!pointsOnly) + { + const int two_sided = 1; + pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED); + } + + //set to wireframe, so when using this material info we can switch to points rendering + if (pointsOnly) + { + const int wireframe = 1; + pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME); + } + + // add the newly created material instance to the list + pvOut->push_back(pcHelper); + } + } + else + { + // generate a default material + aiMaterial* pcHelper = new aiMaterial(); + + // fill in a default material + int iMode = (int)aiShadingMode_Gouraud; + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + + aiColor3D clr; + clr.b = clr.g = clr.r = 0.6f; + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); + + clr.b = clr.g = clr.r = 0.05f; + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT); + + // The face order is absolutely undefined for PLY, so we have to + // use two-sided rendering to be sure it's ok. + if (!pointsOnly) + { + const int two_sided = 1; + pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED); + } + + //default texture + if (!defaultTexture.empty()) + { + const aiString name(defaultTexture.c_str()); + pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0); + } + + //set to wireframe, so when using this material info we can switch to points rendering + if (pointsOnly) + { + const int wireframe = 1; + pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME); + } + + pvOut->push_back(pcHelper); + } } #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER diff --git a/code/PlyLoader.h b/code/PlyLoader.h index 6c3825aa4..eb64a9036 100644 --- a/code/PlyLoader.h +++ b/code/PlyLoader.h @@ -68,7 +68,6 @@ public: PLYImporter(); ~PLYImporter(); - public: // ------------------------------------------------------------------- @@ -78,6 +77,16 @@ public: bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; + // ------------------------------------------------------------------- + /** Extract a vertex from the DOM + */ + void LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos); + + // ------------------------------------------------------------------- + /** Extract a face from the DOM + */ + void LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos); + protected: // ------------------------------------------------------------------- @@ -94,53 +103,10 @@ protected: IOSystem* pIOHandler); protected: - - - // ------------------------------------------------------------------- - /** Extract vertices from the DOM - */ - void LoadVertices(std::vector* pvOut, - bool p_bNormals = false); - - // ------------------------------------------------------------------- - /** Extract vertex color channels from the DOM - */ - void LoadVertexColor(std::vector* pvOut); - - // ------------------------------------------------------------------- - /** Extract texture coordinate channels from the DOM - */ - void LoadTextureCoordinates(std::vector* pvOut); - - // ------------------------------------------------------------------- - /** Extract a face list from the DOM - */ - void LoadFaces(std::vector* pvOut); - // ------------------------------------------------------------------- /** Extract a material list from the DOM */ - void LoadMaterial(std::vector* pvOut); - - - // ------------------------------------------------------------------- - /** Validate material indices, replace default material identifiers - */ - void ReplaceDefaultMaterial(std::vector* avFaces, - std::vector* avMaterials); - - - // ------------------------------------------------------------------- - /** Convert all meshes into our ourer representation - */ - void ConvertMeshes(std::vector* avFaces, - const std::vector* avPositions, - const std::vector* avNormals, - const std::vector* avColors, - const std::vector* avTexCoords, - const std::vector* avMaterials, - std::vector* avOut); - + void LoadMaterial(std::vector* pvOut, std::string &defaultTexture, const bool pointsOnly); // ------------------------------------------------------------------- /** Static helper to parse a color from four single channels in @@ -151,7 +117,6 @@ protected: PLY::EDataType aiTypes[4], aiColor4D* clrOut); - // ------------------------------------------------------------------- /** Static helper to parse a color channel value. The input value * is normalized to 0-1. @@ -160,12 +125,14 @@ protected: PLY::PropertyInstance::ValueUnion val, PLY::EDataType eType); - /** Buffer to hold the loaded file */ unsigned char* mBuffer; /** Document object model representation extracted from the file */ PLY::DOM* pcDOM; + + /** Mesh generated by loader */ + aiMesh* mGeneratedMesh; }; } // end of namespace Assimp diff --git a/code/PlyParser.cpp b/code/PlyParser.cpp index 7e5a07d8e..7d47641b6 100644 --- a/code/PlyParser.cpp +++ b/code/PlyParser.cpp @@ -5,7 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2017, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -13,18 +12,18 @@ 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. +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. +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 team. +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -45,916 +44,1093 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_PLY_IMPORTER -#include "PlyLoader.h" #include "fast_atof.h" #include #include "ByteSwapper.h" - +#include "PlyLoader.h" using namespace Assimp; // ------------------------------------------------------------------------------------------------ -PLY::EDataType PLY::Property::ParseDataType(const char* pCur,const char** pCurOut) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); +PLY::EDataType PLY::Property::ParseDataType(std::vector &buffer) { + ai_assert(!buffer.empty()); - PLY::EDataType eOut = PLY::EDT_INVALID; + PLY::EDataType eOut = PLY::EDT_INVALID; - if (TokenMatch(pCur,"char",4) || - TokenMatch(pCur,"int8",4)) - { - eOut = PLY::EDT_Char; - } - else if (TokenMatch(pCur,"uchar",5) || - TokenMatch(pCur,"uint8",5)) - { - eOut = PLY::EDT_UChar; - } - else if (TokenMatch(pCur,"short",5) || - TokenMatch(pCur,"int16",5)) - { - eOut = PLY::EDT_Short; - } - else if (TokenMatch(pCur,"ushort",6) || - TokenMatch(pCur,"uint16",6)) - { - eOut = PLY::EDT_UShort; - } - else if (TokenMatch(pCur,"int32",5) || TokenMatch(pCur,"int",3)) - { - eOut = PLY::EDT_Int; - } - else if (TokenMatch(pCur,"uint32",6) || TokenMatch(pCur,"uint",4)) - { - eOut = PLY::EDT_UInt; - } - else if (TokenMatch(pCur,"float",5) || TokenMatch(pCur,"float32",7)) - { - eOut = PLY::EDT_Float; - } - else if (TokenMatch(pCur,"double64",8) || TokenMatch(pCur,"double",6) || - TokenMatch(pCur,"float64",7)) - { - eOut = PLY::EDT_Double; - } - if (PLY::EDT_INVALID == eOut) - { - DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK"); - } - *pCurOut = pCur; + if (PLY::DOM::TokenMatch(buffer, "char", 4) || + PLY::DOM::TokenMatch(buffer, "int8", 4)) + { + eOut = PLY::EDT_Char; + } + else if (PLY::DOM::TokenMatch(buffer, "uchar", 5) || + PLY::DOM::TokenMatch(buffer, "uint8", 5)) + { + eOut = PLY::EDT_UChar; + } + else if (PLY::DOM::TokenMatch(buffer, "short", 5) || + PLY::DOM::TokenMatch(buffer, "int16", 5)) + { + eOut = PLY::EDT_Short; + } + else if (PLY::DOM::TokenMatch(buffer, "ushort", 6) || + PLY::DOM::TokenMatch(buffer, "uint16", 6)) + { + eOut = PLY::EDT_UShort; + } + else if (PLY::DOM::TokenMatch(buffer, "int32", 5) || PLY::DOM::TokenMatch(buffer, "int", 3)) + { + eOut = PLY::EDT_Int; + } + else if (PLY::DOM::TokenMatch(buffer, "uint32", 6) || PLY::DOM::TokenMatch(buffer, "uint", 4)) + { + eOut = PLY::EDT_UInt; + } + else if (PLY::DOM::TokenMatch(buffer, "float", 5) || PLY::DOM::TokenMatch(buffer, "float32", 7)) + { + eOut = PLY::EDT_Float; + } + else if (PLY::DOM::TokenMatch(buffer, "double64", 8) || PLY::DOM::TokenMatch(buffer, "double", 6) || + PLY::DOM::TokenMatch(buffer, "float64", 7)) + { + eOut = PLY::EDT_Double; + } + if (PLY::EDT_INVALID == eOut) + { + DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK"); + } - return eOut; + return eOut; } // ------------------------------------------------------------------------------------------------ -PLY::ESemantic PLY::Property::ParseSemantic(const char* pCur,const char** pCurOut) { - ai_assert (NULL != pCur ); - ai_assert( NULL != pCurOut ); +PLY::ESemantic PLY::Property::ParseSemantic(std::vector &buffer) { + ai_assert(!buffer.empty()); - PLY::ESemantic eOut = PLY::EST_INVALID; - if (TokenMatch(pCur,"red",3)) { - eOut = PLY::EST_Red; - } else if (TokenMatch(pCur,"green",5)) { - eOut = PLY::EST_Green; - } else if (TokenMatch(pCur,"blue",4)) { - eOut = PLY::EST_Blue; - } else if (TokenMatch(pCur,"alpha",5)) { - eOut = PLY::EST_Alpha; - } else if (TokenMatch(pCur,"vertex_index",12) || TokenMatch(pCur,"vertex_indices",14)) { - eOut = PLY::EST_VertexIndex; - } - else if (TokenMatch(pCur,"material_index",14)) - { - eOut = PLY::EST_MaterialIndex; - } - else if (TokenMatch(pCur,"ambient_red",11)) - { - eOut = PLY::EST_AmbientRed; - } - else if (TokenMatch(pCur,"ambient_green",13)) - { - eOut = PLY::EST_AmbientGreen; - } - else if (TokenMatch(pCur,"ambient_blue",12)) - { - eOut = PLY::EST_AmbientBlue; - } - else if (TokenMatch(pCur,"ambient_alpha",13)) - { - eOut = PLY::EST_AmbientAlpha; - } - else if (TokenMatch(pCur,"diffuse_red",11)) - { - eOut = PLY::EST_DiffuseRed; - } - else if (TokenMatch(pCur,"diffuse_green",13)) - { - eOut = PLY::EST_DiffuseGreen; - } - else if (TokenMatch(pCur,"diffuse_blue",12)) - { - eOut = PLY::EST_DiffuseBlue; - } - else if (TokenMatch(pCur,"diffuse_alpha",13)) - { - eOut = PLY::EST_DiffuseAlpha; - } - else if (TokenMatch(pCur,"specular_red",12)) - { - eOut = PLY::EST_SpecularRed; - } - else if (TokenMatch(pCur,"specular_green",14)) - { - eOut = PLY::EST_SpecularGreen; - } - else if (TokenMatch(pCur,"specular_blue",13)) - { - eOut = PLY::EST_SpecularBlue; - } - else if (TokenMatch(pCur,"specular_alpha",14)) - { - eOut = PLY::EST_SpecularAlpha; - } - else if (TokenMatch(pCur,"opacity",7)) - { - eOut = PLY::EST_Opacity; - } - else if (TokenMatch(pCur,"specular_power",14)) - { - eOut = PLY::EST_PhongPower; - } - else if (TokenMatch(pCur,"r",1)) - { - eOut = PLY::EST_Red; - } - else if (TokenMatch(pCur,"g",1)) - { - eOut = PLY::EST_Green; - } - else if (TokenMatch(pCur,"b",1)) - { - eOut = PLY::EST_Blue; - } - // NOTE: Blender3D exports texture coordinates as s,t tuples - else if (TokenMatch(pCur,"u",1) || TokenMatch(pCur,"s",1) || TokenMatch(pCur,"tx",2) || TokenMatch(pCur,"texture_u",9)) - { - eOut = PLY::EST_UTextureCoord; - } - else if (TokenMatch(pCur,"v",1) || TokenMatch(pCur,"t",1) || TokenMatch(pCur,"ty",2) || TokenMatch(pCur,"texture_v",9)) - { - eOut = PLY::EST_VTextureCoord; - } - else if (TokenMatch(pCur,"x",1)) - { - eOut = PLY::EST_XCoord; - } else if (TokenMatch(pCur,"y",1)) { - eOut = PLY::EST_YCoord; - } else if (TokenMatch(pCur,"z",1)) { - eOut = PLY::EST_ZCoord; - } else if (TokenMatch(pCur,"nx",2)) { - eOut = PLY::EST_XNormal; - } else if (TokenMatch(pCur,"ny",2)) { - eOut = PLY::EST_YNormal; - } else if (TokenMatch(pCur,"nz",2)) { - eOut = PLY::EST_ZNormal; - } else { - DefaultLogger::get()->info("Found unknown property semantic in file. This is ok"); - SkipLine(&pCur); - } - *pCurOut = pCur; - return eOut; + PLY::ESemantic eOut = PLY::EST_INVALID; + if (PLY::DOM::TokenMatch(buffer, "red", 3)) { + eOut = PLY::EST_Red; + } + else if (PLY::DOM::TokenMatch(buffer, "green", 5)) { + eOut = PLY::EST_Green; + } + else if (PLY::DOM::TokenMatch(buffer, "blue", 4)) { + eOut = PLY::EST_Blue; + } + else if (PLY::DOM::TokenMatch(buffer, "alpha", 5)) { + eOut = PLY::EST_Alpha; + } + else if (PLY::DOM::TokenMatch(buffer, "vertex_index", 12) || PLY::DOM::TokenMatch(buffer, "vertex_indices", 14)) { + eOut = PLY::EST_VertexIndex; + } + else if (PLY::DOM::TokenMatch(buffer, "texcoord", 8)) // Manage uv coords on faces + { + eOut = PLY::EST_TextureCoordinates; + } + else if (PLY::DOM::TokenMatch(buffer, "material_index", 14)) + { + eOut = PLY::EST_MaterialIndex; + } + else if (PLY::DOM::TokenMatch(buffer, "ambient_red", 11)) + { + eOut = PLY::EST_AmbientRed; + } + else if (PLY::DOM::TokenMatch(buffer, "ambient_green", 13)) + { + eOut = PLY::EST_AmbientGreen; + } + else if (PLY::DOM::TokenMatch(buffer, "ambient_blue", 12)) + { + eOut = PLY::EST_AmbientBlue; + } + else if (PLY::DOM::TokenMatch(buffer, "ambient_alpha", 13)) + { + eOut = PLY::EST_AmbientAlpha; + } + else if (PLY::DOM::TokenMatch(buffer, "diffuse_red", 11)) + { + eOut = PLY::EST_DiffuseRed; + } + else if (PLY::DOM::TokenMatch(buffer, "diffuse_green", 13)) + { + eOut = PLY::EST_DiffuseGreen; + } + else if (PLY::DOM::TokenMatch(buffer, "diffuse_blue", 12)) + { + eOut = PLY::EST_DiffuseBlue; + } + else if (PLY::DOM::TokenMatch(buffer, "diffuse_alpha", 13)) + { + eOut = PLY::EST_DiffuseAlpha; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_red", 12)) + { + eOut = PLY::EST_SpecularRed; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_green", 14)) + { + eOut = PLY::EST_SpecularGreen; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_blue", 13)) + { + eOut = PLY::EST_SpecularBlue; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_alpha", 14)) + { + eOut = PLY::EST_SpecularAlpha; + } + else if (PLY::DOM::TokenMatch(buffer, "opacity", 7)) + { + eOut = PLY::EST_Opacity; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_power", 14)) + { + eOut = PLY::EST_PhongPower; + } + else if (PLY::DOM::TokenMatch(buffer, "r", 1)) + { + eOut = PLY::EST_Red; + } + else if (PLY::DOM::TokenMatch(buffer, "g", 1)) + { + eOut = PLY::EST_Green; + } + else if (PLY::DOM::TokenMatch(buffer, "b", 1)) + { + eOut = PLY::EST_Blue; + } + + // NOTE: Blender3D exports texture coordinates as s,t tuples + else if (PLY::DOM::TokenMatch(buffer, "u", 1) || PLY::DOM::TokenMatch(buffer, "s", 1) || PLY::DOM::TokenMatch(buffer, "tx", 2)) + { + eOut = PLY::EST_UTextureCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "v", 1) || PLY::DOM::TokenMatch(buffer, "t", 1) || PLY::DOM::TokenMatch(buffer, "ty", 2)) + { + eOut = PLY::EST_VTextureCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "x", 1)) + { + eOut = PLY::EST_XCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "y", 1)) { + eOut = PLY::EST_YCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "z", 1)) { + eOut = PLY::EST_ZCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "nx", 2)) { + eOut = PLY::EST_XNormal; + } + else if (PLY::DOM::TokenMatch(buffer, "ny", 2)) { + eOut = PLY::EST_YNormal; + } + else if (PLY::DOM::TokenMatch(buffer, "nz", 2)) { + eOut = PLY::EST_ZNormal; + } + else { + DefaultLogger::get()->info("Found unknown property semantic in file. This is ok"); + PLY::DOM::SkipLine(buffer); + } + return eOut; } // ------------------------------------------------------------------------------------------------ -bool PLY::Property::ParseProperty (const char* pCur, - const char** pCurOut, - PLY::Property* pOut) +bool PLY::Property::ParseProperty(std::vector &buffer, PLY::Property* pOut) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); + ai_assert(!buffer.empty()); - // Forms supported: - // "property float x" - // "property list uchar int vertex_index" - *pCurOut = pCur; - - // skip leading spaces - if (!SkipSpaces(pCur,&pCur)) { - return false; - } - - // skip the "property" string at the beginning - if (!TokenMatch(pCur,"property",8)) - { - // seems not to be a valid property entry - return false; - } - // get next word - if (!SkipSpaces(pCur,&pCur)) { - return false; - } - if (TokenMatch(pCur,"list",4)) - { - pOut->bIsList = true; - - // seems to be a list. - if(EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(pCur, &pCur))) - { - // unable to parse list size data type - SkipLine(pCur,&pCur); - *pCurOut = pCur; - return false; - } - if (!SkipSpaces(pCur,&pCur))return false; - if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur))) - { - // unable to parse list data type - SkipLine(pCur,&pCur); - *pCurOut = pCur; - return false; - } - } - else - { - if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur))) - { - // unable to parse data type. Skip the property - SkipLine(pCur,&pCur); - *pCurOut = pCur; - return false; - } - } - - if (!SkipSpaces(pCur,&pCur))return false; - const char* szCur = pCur; - pOut->Semantic = PLY::Property::ParseSemantic(pCur, &pCur); - - if (PLY::EST_INVALID == pOut->Semantic) - { - // store the name of the semantic - uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; - - DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK"); - pOut->szName = std::string(szCur,iDiff); - } - - SkipSpacesAndLineEnd(pCur,&pCur); - *pCurOut = pCur; - - return true; -} - -// ------------------------------------------------------------------------------------------------ -PLY::EElementSemantic PLY::Element::ParseSemantic(const char* pCur, - const char** pCurOut) -{ - ai_assert(NULL != pCur && NULL != pCurOut); - PLY::EElementSemantic eOut = PLY::EEST_INVALID; - if (TokenMatch(pCur,"vertex",6)) - { - eOut = PLY::EEST_Vertex; - } - else if (TokenMatch(pCur,"face",4)) - { - eOut = PLY::EEST_Face; - } -#if 0 - // TODO: maybe implement this? - else if (TokenMatch(pCur,"range_grid",10)) - { - eOut = PLY::EEST_Face; - } -#endif - else if (TokenMatch(pCur,"tristrips",9)) - { - eOut = PLY::EEST_TriStrip; - } - else if (TokenMatch(pCur,"edge",4)) - { - eOut = PLY::EEST_Edge; - } - else if (TokenMatch(pCur,"material",8)) - { - eOut = PLY::EEST_Material; - } - *pCurOut = pCur; - - return eOut; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::Element::ParseElement (const char* pCur, - const char** pCurOut, - PLY::Element* pOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pOut ); - - // Example format: "element vertex 8" - *pCurOut = pCur; - - // skip leading spaces - if (!SkipSpaces(&pCur)) { - return false; - } - - // skip the "element" string at the beginning - if (!TokenMatch(pCur,"element",7)) - { - // seems not to be a valid property entry - return false; - } - // get next word - if (!SkipSpaces(&pCur))return false; - - // parse the semantic of the element - const char* szCur = pCur; - pOut->eSemantic = PLY::Element::ParseSemantic(pCur,&pCur); - if (PLY::EEST_INVALID == pOut->eSemantic) - { - // if the exact semantic can't be determined, just store - // the original string identifier - uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; - pOut->szName = std::string(szCur,iDiff); - } - - if (!SkipSpaces(&pCur))return false; - - //parse the number of occurrences of this element - pOut->NumOccur = strtoul10(pCur,&pCur); - - // go to the next line - SkipSpacesAndLineEnd(pCur,&pCur); - - // now parse all properties of the element - while(true) - { - // skip all comments - PLY::DOM::SkipComments(pCur,&pCur); - - PLY::Property prop; - if(!PLY::Property::ParseProperty(pCur,&pCur,&prop))break; - pOut->alProperties.push_back(prop); - } - *pCurOut = pCur; - - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::SkipComments (const char* pCur, - const char** pCurOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - *pCurOut = pCur; - - // skip spaces - if (!SkipSpaces(pCur,&pCur)) { - return false; - } - - if (TokenMatch(pCur,"comment",7)) - { - if ( !IsLineEnd(pCur[-1]) ) - { - SkipLine(pCur,&pCur); - } - SkipComments(pCur,&pCur); - *pCurOut = pCur; - return true; - } - *pCurOut = pCur; + // Forms supported: + // "property float x" + // "property list uchar int vertex_index" + // skip leading spaces + if (!PLY::DOM::SkipSpaces(buffer)) { return false; -} + } -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut,bool isBinary) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); + // skip the "property" string at the beginning + if (!PLY::DOM::TokenMatch(buffer, "property", 8)) + { + // seems not to be a valid property entry + return false; + } + // get next word + if (!PLY::DOM::SkipSpaces(buffer)) { + return false; + } + if (PLY::DOM::TokenMatch(buffer, "list", 4)) + { + pOut->bIsList = true; - DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin"); - - // after ply and format line - *pCurOut = pCur; - - // parse all elements - while ((*pCur) != '\0') + // seems to be a list. + if (EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(buffer))) { - // skip all comments - PLY::DOM::SkipComments(pCur,&pCur); - - PLY::Element out; - if(PLY::Element::ParseElement(pCur,&pCur,&out)) - { - // add the element to the list of elements - alElements.push_back(out); - } - else if (TokenMatch(pCur,"end_header",10)) - { - // we have reached the end of the header - break; - } - else - { - // ignore unknown header elements - SkipLine(&pCur); - } + // unable to parse list size data type + PLY::DOM::SkipLine(buffer); + return false; } - if(!isBinary) - { // it would occur an error, if binary data start with values as space or line end. - SkipSpacesAndLineEnd(pCur,&pCur); + if (!PLY::DOM::SkipSpaces(buffer))return false; + if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer))) + { + // unable to parse list data type + PLY::DOM::SkipLine(buffer); + return false; } - *pCurOut = pCur; + } + else + { + if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer))) + { + // unable to parse data type. Skip the property + PLY::DOM::SkipLine(buffer); + return false; + } + } - DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded"); - return true; + if (!PLY::DOM::SkipSpaces(buffer)) + return false; + + pOut->Semantic = PLY::Property::ParseSemantic(buffer); + + if (PLY::EST_INVALID == pOut->Semantic) + { + DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK"); + std::string(&buffer[0], &buffer[0] + strlen(&buffer[0])); + } + + PLY::DOM::SkipSpacesAndLineEnd(buffer); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseElementInstanceLists ( - const char* pCur, - const char** pCurOut) +PLY::EElementSemantic PLY::Element::ParseSemantic(std::vector &buffer) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); + ai_assert(!buffer.empty()); - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin"); - *pCurOut = pCur; + PLY::EElementSemantic eOut = PLY::EEST_INVALID; + if (PLY::DOM::TokenMatch(buffer, "vertex", 6)) + { + eOut = PLY::EEST_Vertex; + } + else if (PLY::DOM::TokenMatch(buffer, "face", 4)) + { + eOut = PLY::EEST_Face; + } + else if (PLY::DOM::TokenMatch(buffer, "tristrips", 9)) + { + eOut = PLY::EEST_TriStrip; + } +#if 0 + // TODO: maybe implement this? + else if (PLY::DOM::TokenMatch(buffer,"range_grid",10)) + { + eOut = PLY::EEST_Face; + } +#endif + else if (PLY::DOM::TokenMatch(buffer, "edge", 4)) + { + eOut = PLY::EEST_Edge; + } + else if (PLY::DOM::TokenMatch(buffer, "material", 8)) + { + eOut = PLY::EEST_Material; + } + else if (PLY::DOM::TokenMatch(buffer, "TextureFile", 11)) + { + eOut = PLY::EEST_TextureFile; + } - alElementData.resize(alElements.size()); - - std::vector::const_iterator i = alElements.begin(); - std::vector::iterator a = alElementData.begin(); - - // parse all element instances - for (;i != alElements.end();++i,++a) - { - (*a).alInstances.resize((*i).NumOccur); - PLY::ElementInstanceList::ParseInstanceList(pCur,&pCur,&(*i),&(*a)); - } - - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded"); - *pCurOut = pCur; - return true; + return eOut; } // ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseElementInstanceListsBinary ( - const char* pCur, - const char** pCurOut, +bool PLY::Element::ParseElement(IOStreamBuffer &streamBuffer, std::vector &buffer, PLY::Element* pOut) +{ + ai_assert(NULL != pOut); + // Example format: "element vertex 8" + + // skip leading spaces + if (!PLY::DOM::SkipSpaces(buffer)) + { + return false; + } + + // skip the "element" string at the beginning + if (!PLY::DOM::TokenMatch(buffer, "element", 7) && !PLY::DOM::TokenMatch(buffer, "comment", 7)) + { + // seems not to be a valid property entry + return false; + } + // get next word + if (!PLY::DOM::SkipSpaces(buffer)) + return false; + + // parse the semantic of the element + pOut->eSemantic = PLY::Element::ParseSemantic(buffer); + if (PLY::EEST_INVALID == pOut->eSemantic) + { + // if the exact semantic can't be determined, just store + // the original string identifier + pOut->szName = std::string(&buffer[0], &buffer[0] + strlen(&buffer[0])); + } + + if (!PLY::DOM::SkipSpaces(buffer)) + return false; + + if (PLY::EEST_TextureFile == pOut->eSemantic) + { + char* endPos = &buffer[0] + (strlen(&buffer[0]) - 1); + pOut->szName = std::string(&buffer[0], endPos); + } + + //parse the number of occurrences of this element + const char* pCur = (char*)&buffer[0]; + pOut->NumOccur = strtoul10(pCur, &pCur); + + // go to the next line + PLY::DOM::SkipSpacesAndLineEnd(buffer); + + // now parse all properties of the element + while (true) + { + streamBuffer.getNextDataLine(buffer, '\\'); + pCur = (char*)&buffer[0]; + + // skip all comments + PLY::DOM::SkipComments(buffer); + + PLY::Property prop; + if (!PLY::Property::ParseProperty(buffer, &prop)) + break; + + pOut->alProperties.push_back(prop); + } + + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::SkipSpaces(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipSpaces(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipLine(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipLine(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::TokenMatch(std::vector &buffer, const char* token, unsigned int len) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::TokenMatch(pCur, token, len); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipSpacesAndLineEnd(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipComments(std::vector &buffer) +{ + ai_assert(!buffer.empty()); + + std::vector nbuffer = buffer; + // skip spaces + if (!SkipSpaces(nbuffer)) { + return false; + } + + if (TokenMatch(nbuffer, "comment", 7)) + { + if (!SkipSpaces(nbuffer)) + SkipLine(nbuffer); + + if (!TokenMatch(nbuffer, "TextureFile", 11)) + { + SkipLine(nbuffer); + buffer = nbuffer; + return true; + } + + return true; + } + + return false; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::ParseHeader(IOStreamBuffer &streamBuffer, std::vector &buffer, bool isBinary) { + DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin"); + + // parse all elements + while (!buffer.empty()) + { + // skip all comments + PLY::DOM::SkipComments(buffer); + + PLY::Element out; + if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) + { + // add the element to the list of elements + alElements.push_back(out); + } + else if (TokenMatch(buffer, "end_header", 10)) + { + // we have reached the end of the header + break; + } + else + { + // ignore unknown header elements + streamBuffer.getNextDataLine(buffer, '\\'); + } + } + + if (!isBinary) // it would occur an error, if binary data start with values as space or line end. + SkipSpacesAndLineEnd(buffer); + + DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded"); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::ParseElementInstanceLists(IOStreamBuffer &streamBuffer, std::vector &buffer, PLYImporter* loader) +{ + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin"); + alElementData.resize(alElements.size()); + + std::vector::const_iterator i = alElements.begin(); + std::vector::iterator a = alElementData.begin(); + + // parse all element instances + //construct vertices and faces + for (; i != alElements.end(); ++i, ++a) + { + if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip) + { + PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), NULL, loader); + } + else + { + (*a).alInstances.resize((*i).NumOccur); + PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), &(*a), NULL); + } + } + + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded"); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::ParseElementInstanceListsBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + PLYImporter* loader, bool p_bBE) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut); + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin"); + alElementData.resize(alElements.size()); - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin"); - *pCurOut = pCur; + std::vector::const_iterator i = alElements.begin(); + std::vector::iterator a = alElementData.begin(); - alElementData.resize(alElements.size()); - - std::vector::const_iterator i = alElements.begin(); - std::vector::iterator a = alElementData.begin(); - - // parse all element instances - for (;i != alElements.end();++i,++a) + // parse all element instances + for (; i != alElements.end(); ++i, ++a) + { + if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip) { - (*a).alInstances.resize((*i).NumOccur); - PLY::ElementInstanceList::ParseInstanceListBinary(pCur,&pCur,&(*i),&(*a),p_bBE); - } - - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded"); - *pCurOut = pCur; - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseInstanceBinary (const char* pCur,DOM* p_pcOut,bool p_bBE) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != p_pcOut ); - - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin"); - - if(!p_pcOut->ParseHeader(pCur,&pCur,true)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); - return false; - } - if(!p_pcOut->ParseElementInstanceListsBinary(pCur,&pCur,p_bBE)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); - return false; - } - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded"); - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseInstance (const char* pCur,DOM* p_pcOut) -{ - ai_assert(NULL != pCur); - ai_assert(NULL != p_pcOut); - - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin"); - - - if(!p_pcOut->ParseHeader(pCur,&pCur,false)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); - return false; - } - if(!p_pcOut->ParseElementInstanceLists(pCur,&pCur)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); - return false; - } - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded"); - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstanceList::ParseInstanceList ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstanceList* p_pcOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); - - if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty()) - { - // if the element has an unknown semantic we can skip all lines - // However, there could be comments - for (unsigned int i = 0; i < pcElement->NumOccur;++i) - { - PLY::DOM::SkipComments(pCur,&pCur); - SkipLine(pCur,&pCur); - } + PLY::ElementInstanceList::ParseInstanceListBinary(streamBuffer, buffer, pCur, bufferSize, &(*i), NULL, loader, p_bBE); } else { - // be sure to have enough storage - for (unsigned int i = 0; i < pcElement->NumOccur;++i) - { - PLY::DOM::SkipComments(pCur,&pCur); - PLY::ElementInstance::ParseInstance(pCur, &pCur,pcElement, - &p_pcOut->alInstances[i]); - } + (*a).alInstances.resize((*i).NumOccur); + PLY::ElementInstanceList::ParseInstanceListBinary(streamBuffer, buffer, pCur, bufferSize, &(*i), &(*a), NULL, p_bBE); } - *pCurOut = pCur; - return true; + } + + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded"); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstanceList::ParseInstanceListBinary ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstanceList* p_pcOut, - bool p_bBE /* = false */) +bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer &streamBuffer, DOM* p_pcOut, PLYImporter* loader, bool p_bBE) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != p_pcOut); + ai_assert(NULL != loader); - // we can add special handling code for unknown element semantics since - // we can't skip it as a whole block (we don't know its exact size - // due to the fact that lists could be contained in the property list - // of the unknown element) - for (unsigned int i = 0; i < pcElement->NumOccur;++i) - { - PLY::ElementInstance::ParseInstanceBinary(pCur, &pCur,pcElement, - &p_pcOut->alInstances[i], p_bBE); - } - *pCurOut = pCur; - return true; + std::vector buffer; + streamBuffer.getNextDataLine(buffer, '\\'); + + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin"); + + if (!p_pcOut->ParseHeader(streamBuffer, buffer, true)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); + return false; + } + + streamBuffer.getNextBlock(buffer); + unsigned int bufferSize = buffer.size(); + const char* pCur = (char*)&buffer[0]; + if (!p_pcOut->ParseElementInstanceListsBinary(streamBuffer, buffer, pCur, bufferSize, loader, p_bBE)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); + return false; + } + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded"); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstance::ParseInstance ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstance* p_pcOut) +bool PLY::DOM::ParseInstance(IOStreamBuffer &streamBuffer, DOM* p_pcOut, PLYImporter* loader) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != p_pcOut); + ai_assert(NULL != loader); - if (!SkipSpaces(pCur, &pCur)) { - return false; - } + std::vector buffer; + streamBuffer.getNextDataLine(buffer, '\\'); - // allocate enough storage - p_pcOut->alProperties.resize(pcElement->alProperties.size()); + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin"); - std::vector::iterator i = p_pcOut->alProperties.begin(); - std::vector::const_iterator a = pcElement->alProperties.begin(); - for (;i != p_pcOut->alProperties.end();++i,++a) - { - if(!(PLY::PropertyInstance::ParseInstance(pCur, &pCur,&(*a),&(*i)))) - { - DefaultLogger::get()->warn("Unable to parse property instance. " - "Skipping this element instance"); + if (!p_pcOut->ParseHeader(streamBuffer, buffer, false)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); + return false; + } - // skip the rest of the instance - SkipLine(pCur, &pCur); - - PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType); - (*i).avList.push_back(v); - } - } - *pCurOut = pCur; - return true; + //get next line after header + streamBuffer.getNextDataLine(buffer, '\\'); + if (!p_pcOut->ParseElementInstanceLists(streamBuffer, buffer, loader)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); + return false; + } + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded"); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstance::ParseInstanceBinary ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstance* p_pcOut, - bool p_bBE /* = false */) +bool PLY::ElementInstanceList::ParseInstanceList( + IOStreamBuffer &streamBuffer, + std::vector &buffer, + const PLY::Element* pcElement, + PLY::ElementInstanceList* p_pcOut, + PLYImporter* loader) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != pcElement); + const char* pCur = (const char*)&buffer[0]; - // allocate enough storage - p_pcOut->alProperties.resize(pcElement->alProperties.size()); - - std::vector::iterator i = p_pcOut->alProperties.begin(); - std::vector::const_iterator a = pcElement->alProperties.begin(); - for (;i != p_pcOut->alProperties.end();++i,++a) + // parse all elements + if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty()) + { + // if the element has an unknown semantic we can skip all lines + // However, there could be comments + for (unsigned int i = 0; i < pcElement->NumOccur; ++i) { - if(!(PLY::PropertyInstance::ParseInstanceBinary(pCur, &pCur,&(*a),&(*i),p_bBE))) - { - DefaultLogger::get()->warn("Unable to parse binary property instance. " - "Skipping this element instance"); - - (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType)); - } + PLY::DOM::SkipComments(buffer); + PLY::DOM::SkipLine(buffer); + streamBuffer.getNextDataLine(buffer, '\\'); + pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0]; } - *pCurOut = pCur; - return true; + } + else + { + // be sure to have enough storage + for (unsigned int i = 0; i < pcElement->NumOccur; ++i) + { + if (p_pcOut) + PLY::ElementInstance::ParseInstance(pCur, pcElement, &p_pcOut->alInstances[i]); + else + { + ElementInstance elt; + PLY::ElementInstance::ParseInstance(pCur, pcElement, &elt); + + // Create vertex or face + if (pcElement->eSemantic == EEST_Vertex) + { + //call loader instance from here + loader->LoadVertex(pcElement, &elt, i); + } + else if (pcElement->eSemantic == EEST_Face) + { + //call loader instance from here + loader->LoadFace(pcElement, &elt, i); + } + else if (pcElement->eSemantic == EEST_TriStrip) + { + //call loader instance from here + loader->LoadFace(pcElement, &elt, i); + } + } + + streamBuffer.getNextDataLine(buffer, '\\'); + pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0]; + } + } + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseInstance (const char* pCur,const char** pCurOut, - const PLY::Property* prop, PLY::PropertyInstance* p_pcOut) +bool PLY::ElementInstanceList::ParseInstanceListBinary( + IOStreamBuffer &streamBuffer, + std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + const PLY::Element* pcElement, + PLY::ElementInstanceList* p_pcOut, + PLYImporter* loader, + bool p_bBE /* = false */) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != prop ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != pcElement); - *pCurOut = pCur; - - // skip spaces at the beginning - if (!SkipSpaces(pCur, &pCur)) { - return false; - } - - if (prop->bIsList) - { - // parse the number of elements in the list - PLY::PropertyInstance::ValueUnion v; - PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eFirstType,&v); - - // convert to unsigned int - unsigned int iNum = PLY::PropertyInstance::ConvertTo(v,prop->eFirstType); - - // parse all list elements - p_pcOut->avList.resize(iNum); - for (unsigned int i = 0; i < iNum;++i) - { - if (!SkipSpaces(pCur, &pCur))return false; - PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&p_pcOut->avList[i]); - } - } + // we can add special handling code for unknown element semantics since + // we can't skip it as a whole block (we don't know its exact size + // due to the fact that lists could be contained in the property list + // of the unknown element) + for (unsigned int i = 0; i < pcElement->NumOccur; ++i) + { + if (p_pcOut) + PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &p_pcOut->alInstances[i], p_bBE); else { - // parse the property - PLY::PropertyInstance::ValueUnion v; + ElementInstance elt; + PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &elt, p_bBE); - PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&v); - p_pcOut->avList.push_back(v); + // Create vertex or face + if (pcElement->eSemantic == EEST_Vertex) + { + //call loader instance from here + loader->LoadVertex(pcElement, &elt, i); + } + else if (pcElement->eSemantic == EEST_Face) + { + //call loader instance from here + loader->LoadFace(pcElement, &elt, i); + } + else if (pcElement->eSemantic == EEST_TriStrip) + { + //call loader instance from here + loader->LoadFace(pcElement, &elt, i); + } } - SkipSpacesAndLineEnd(pCur, &pCur); - *pCurOut = pCur; - return true; + } + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseInstanceBinary ( - const char* pCur, - const char** pCurOut, - const PLY::Property* prop, - PLY::PropertyInstance* p_pcOut, - bool p_bBE) +bool PLY::ElementInstance::ParseInstance(const char* &pCur, + const PLY::Element* pcElement, + PLY::ElementInstance* p_pcOut) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != prop ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != pcElement); + ai_assert(NULL != p_pcOut); - if (prop->bIsList) + // allocate enough storage + p_pcOut->alProperties.resize(pcElement->alProperties.size()); + + std::vector::iterator i = p_pcOut->alProperties.begin(); + std::vector::const_iterator a = pcElement->alProperties.begin(); + for (; i != p_pcOut->alProperties.end(); ++i, ++a) + { + if (!(PLY::PropertyInstance::ParseInstance(pCur, &(*a), &(*i)))) { - // parse the number of elements in the list - PLY::PropertyInstance::ValueUnion v; - PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eFirstType,&v,p_bBE); + DefaultLogger::get()->warn("Unable to parse property instance. " + "Skipping this element instance"); - // convert to unsigned int - unsigned int iNum = PLY::PropertyInstance::ConvertTo(v,prop->eFirstType); - - // parse all list elements - p_pcOut->avList.resize(iNum); - for (unsigned int i = 0; i < iNum;++i){ - PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&p_pcOut->avList[i],p_bBE); - } + PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType); + (*i).avList.push_back(v); } - else - { - // parse the property - PLY::PropertyInstance::ValueUnion v; - PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&v,p_bBE); - p_pcOut->avList.push_back(v); - } - *pCurOut = pCur; - return true; + } + return true; } // ------------------------------------------------------------------------------------------------ -PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue( PLY::EDataType eType ) +bool PLY::ElementInstance::ParseInstanceBinary( + IOStreamBuffer &streamBuffer, + std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + const PLY::Element* pcElement, + PLY::ElementInstance* p_pcOut, + bool p_bBE /* = false */) { - PLY::PropertyInstance::ValueUnion out; + ai_assert(NULL != pcElement); + ai_assert(NULL != p_pcOut); - switch (eType) + // allocate enough storage + p_pcOut->alProperties.resize(pcElement->alProperties.size()); + + std::vector::iterator i = p_pcOut->alProperties.begin(); + std::vector::const_iterator a = pcElement->alProperties.begin(); + for (; i != p_pcOut->alProperties.end(); ++i, ++a) + { + if (!(PLY::PropertyInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, &(*a), &(*i), p_bBE))) { - case EDT_Float: - out.fFloat = 0.f; - return out; + DefaultLogger::get()->warn("Unable to parse binary property instance. " + "Skipping this element instance"); - case EDT_Double: - out.fDouble = 0.; - return out; + (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType)); + } + } + return true; +} - default: ; - }; - out.iUInt = 0; +// ------------------------------------------------------------------------------------------------ +bool PLY::PropertyInstance::ParseInstance(const char* &pCur, + const PLY::Property* prop, PLY::PropertyInstance* p_pcOut) +{ + ai_assert(NULL != prop); + ai_assert(NULL != p_pcOut); + + // skip spaces at the beginning + if (!SkipSpaces(&pCur)) + { + return false; + } + + if (prop->bIsList) + { + // parse the number of elements in the list + PLY::PropertyInstance::ValueUnion v; + PLY::PropertyInstance::ParseValue(pCur, prop->eFirstType, &v); + + // convert to unsigned int + unsigned int iNum = PLY::PropertyInstance::ConvertTo(v, prop->eFirstType); + + // parse all list elements + p_pcOut->avList.resize(iNum); + for (unsigned int i = 0; i < iNum; ++i) + { + if (!SkipSpaces(&pCur)) + return false; + + PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]); + } + } + else + { + // parse the property + PLY::PropertyInstance::ValueUnion v; + + PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v); + p_pcOut->avList.push_back(v); + } + SkipSpacesAndLineEnd(&pCur); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::PropertyInstance::ParseInstanceBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + const PLY::Property* prop, + PLY::PropertyInstance* p_pcOut, + bool p_bBE) +{ + ai_assert(NULL != prop); + ai_assert(NULL != p_pcOut); + + // parse all elements + if (prop->bIsList) + { + // parse the number of elements in the list + PLY::PropertyInstance::ValueUnion v; + PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eFirstType, &v, p_bBE); + + // convert to unsigned int + unsigned int iNum = PLY::PropertyInstance::ConvertTo(v, prop->eFirstType); + + // parse all list elements + p_pcOut->avList.resize(iNum); + for (unsigned int i = 0; i < iNum; ++i) + { + PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eType, &p_pcOut->avList[i], p_bBE); + } + } + else + { + // parse the property + PLY::PropertyInstance::ValueUnion v; + PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eType, &v, p_bBE); + p_pcOut->avList.push_back(v); + } + return true; +} + +// ------------------------------------------------------------------------------------------------ +PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue(PLY::EDataType eType) +{ + PLY::PropertyInstance::ValueUnion out; + + switch (eType) + { + case EDT_Float: + out.fFloat = 0.f; return out; + + case EDT_Double: + out.fDouble = 0.; + return out; + + default:; + }; + out.iUInt = 0; + return out; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseValue( - const char* pCur, - const char** pCurOut, - PLY::EDataType eType, - PLY::PropertyInstance::ValueUnion* out) +bool PLY::PropertyInstance::ParseValue(const char* &pCur, + PLY::EDataType eType, + PLY::PropertyInstance::ValueUnion* out) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != out ); + ai_assert(NULL != pCur); + ai_assert(NULL != out); + + //calc element size + unsigned int lsize = 0; + switch (eType) + { + case EDT_Char: + case EDT_UChar: + lsize = 1; + break; - bool ret = true; - *pCurOut = pCur; - switch (eType) - { - case EDT_UInt: - case EDT_UShort: - case EDT_UChar: + case EDT_UShort: + case EDT_Short: + lsize = 2; + break; - out->iUInt = (uint32_t)strtoul10(pCur, &pCur); - break; + case EDT_UInt: + case EDT_Int: + case EDT_Float: + lsize = 4; + break; - case EDT_Int: - case EDT_Short: - case EDT_Char: + case EDT_Double: + lsize = 8; + break; + } - out->iInt = (int32_t)strtol10(pCur, &pCur); - break; + bool ret = true; + switch (eType) + { + case EDT_UInt: + case EDT_UShort: + case EDT_UChar: - case EDT_Float: - // technically this should cast to float, but people tend to use float descriptors for double data - // this is the best way to not risk losing precision on import and it doesn't hurt to do this - ai_real f; - pCur = fast_atoreal_move(pCur,f); - out->fFloat = (ai_real)f; - break; + out->iUInt = (uint32_t)strtoul10(pCur, &pCur); + break; - case EDT_Double: - double d; - pCur = fast_atoreal_move(pCur,d); - out->fDouble = (double)d; - break; + case EDT_Int: + case EDT_Short: + case EDT_Char: - default: - ret = false; - break; - } - *pCurOut = pCur; + out->iInt = (int32_t)strtol10(pCur, &pCur); + break; - return ret; + case EDT_Float: + // technically this should cast to float, but people tend to use float descriptors for double data + // this is the best way to not risk losing precision on import and it doesn't hurt to do this + ai_real f; + pCur = fast_atoreal_move(pCur, f); + out->fFloat = (ai_real)f; + break; + + case EDT_Double: + double d; + pCur = fast_atoreal_move(pCur, d); + out->fDouble = (double)d; + break; + + default: + ret = false; + break; + } + + return ret; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseValueBinary( - const char* pCur, - const char** pCurOut, - PLY::EDataType eType, - PLY::PropertyInstance::ValueUnion* out, - bool p_bBE) +bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer &streamBuffer, + std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + PLY::EDataType eType, + PLY::PropertyInstance::ValueUnion* out, + bool p_bBE) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != out ); + ai_assert(NULL != out); - bool ret = true; - switch (eType) + //calc element size + unsigned int lsize = 0; + switch (eType) + { + case EDT_Char: + case EDT_UChar: + lsize = 1; + break; + + case EDT_UShort: + case EDT_Short: + lsize = 2; + break; + + case EDT_UInt: + case EDT_Int: + case EDT_Float: + lsize = 4; + break; + + case EDT_Double: + lsize = 8; + break; + } + + //read the next file block if needed + if (bufferSize < lsize) + { + std::vector nbuffer; + if (streamBuffer.getNextBlock(nbuffer)) { - case EDT_UInt: - out->iUInt = (uint32_t)*((uint32_t*)pCur); - pCur += 4; - - // Swap endianness - if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt); - break; - - case EDT_UShort: - { - uint16_t i = *((uint16_t*)pCur); - - // Swap endianness - if (p_bBE)ByteSwap::Swap(&i); - out->iUInt = (uint32_t)i; - pCur += 2; - break; - } - - case EDT_UChar: - { - out->iUInt = (uint32_t)(*((uint8_t*)pCur)); - pCur ++; - break; - } - - case EDT_Int: - out->iInt = *((int32_t*)pCur); - pCur += 4; - - // Swap endianness - if (p_bBE)ByteSwap::Swap(&out->iInt); - break; - - case EDT_Short: - { - int16_t i = *((int16_t*)pCur); - - // Swap endianness - if (p_bBE)ByteSwap::Swap(&i); - out->iInt = (int32_t)i; - pCur += 2; - break; - } - - case EDT_Char: - out->iInt = (int32_t)*((int8_t*)pCur); - pCur ++; - break; - - case EDT_Float: - { - out->fFloat = *((float*)pCur); - - // Swap endianness - if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat); - pCur += 4; - break; - } - case EDT_Double: - { - out->fDouble = *((double*)pCur); - - // Swap endianness - if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble); - pCur += 8; - break; - } - default: - ret = false; + //concat buffer contents + buffer = std::vector(buffer.end() - bufferSize, buffer.end()); + buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end()); + nbuffer.clear(); + bufferSize = buffer.size(); + pCur = (char*)&buffer[0]; } - *pCurOut = pCur; + else + { + throw DeadlyImportError("Invalid .ply file: File corrupted"); + } + } - return ret; + bool ret = true; + switch (eType) + { + case EDT_UInt: + out->iUInt = (uint32_t)*((uint32_t*)pCur); + pCur += 4; + + // Swap endianness + if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt); + break; + + case EDT_UShort: + { + uint16_t i = *((uint16_t*)pCur); + + // Swap endianness + if (p_bBE)ByteSwap::Swap(&i); + out->iUInt = (uint32_t)i; + pCur += 2; + break; + } + + case EDT_UChar: + { + out->iUInt = (uint32_t)(*((uint8_t*)pCur)); + pCur++; + break; + } + + case EDT_Int: + out->iInt = *((int32_t*)pCur); + pCur += 4; + + // Swap endianness + if (p_bBE)ByteSwap::Swap(&out->iInt); + break; + + case EDT_Short: + { + int16_t i = *((int16_t*)pCur); + + // Swap endianness + if (p_bBE)ByteSwap::Swap(&i); + out->iInt = (int32_t)i; + pCur += 2; + break; + } + + case EDT_Char: + out->iInt = (int32_t)*((int8_t*)pCur); + pCur++; + break; + + case EDT_Float: + { + out->fFloat = *((float*)pCur); + + // Swap endianness + if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat); + pCur += 4; + break; + } + case EDT_Double: + { + out->fDouble = *((double*)pCur); + + // Swap endianness + if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble); + pCur += 8; + break; + } + default: + ret = false; + } + + bufferSize -= lsize; + + return ret; } #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER diff --git a/code/PlyParser.h b/code/PlyParser.h index 930536e2d..b17b07341 100644 --- a/code/PlyParser.h +++ b/code/PlyParser.h @@ -3,7 +3,6 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- Copyright (c) 2006-2017, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -46,19 +45,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ParsingUtils.h" +#include "IOStreamBuffer.h" #include - namespace Assimp { +//pre-declaration +class PLYImporter; + // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ // http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf // http://www.okino.com/conv/exp_ply.htm namespace PLY { - // --------------------------------------------------------------------------------- /* name type number of bytes @@ -197,6 +198,9 @@ enum EElementSemantic //! The element is a material description EEST_Material, + //! texture path + EEST_TextureFile, + //! Marks invalid entries EEST_INVALID }; @@ -238,16 +242,15 @@ public: //! string is either '\n', '\r' or '\0'. Return value is false //! if the input string is NOT a valid property (E.g. does //! not start with the "property" keyword) - static bool ParseProperty (const char* pCur, const char** pCurOut, - Property* pOut); + static bool ParseProperty(std::vector &buffer, Property* pOut); // ------------------------------------------------------------------- //! Parse a data type from a string - static EDataType ParseDataType(const char* pCur,const char** pCurOut); + static EDataType ParseDataType(std::vector &buffer); // ------------------------------------------------------------------- //! Parse a semantic from a string - static ESemantic ParseSemantic(const char* pCur,const char** pCurOut); + static ESemantic ParseSemantic(std::vector &buffer); }; // --------------------------------------------------------------------------------- @@ -285,13 +288,11 @@ public: //! Parse an element from a string. //! The function will parse all properties contained in the //! element, too. - static bool ParseElement (const char* pCur, const char** pCurOut, - Element* pOut); + static bool ParseElement(IOStreamBuffer &streamBuffer, std::vector &buffer, Element* pOut); // ------------------------------------------------------------------- //! Parse a semantic from a string - static EElementSemantic ParseSemantic(const char* pCur, - const char** pCurOut); + static EElementSemantic ParseSemantic(std::vector &buffer); }; // --------------------------------------------------------------------------------- @@ -331,13 +332,13 @@ public: // ------------------------------------------------------------------- //! Parse a property instance - static bool ParseInstance (const char* pCur,const char** pCurOut, + static bool ParseInstance(const char* &pCur, const Property* prop, PropertyInstance* p_pcOut); // ------------------------------------------------------------------- //! Parse a property instance in binary format - static bool ParseInstanceBinary (const char* pCur,const char** pCurOut, - const Property* prop, PropertyInstance* p_pcOut,bool p_bBE); + static bool ParseInstanceBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, unsigned int &bufferSize, const Property* prop, PropertyInstance* p_pcOut, bool p_bBE); // ------------------------------------------------------------------- //! Get the default value for a given data type @@ -345,13 +346,12 @@ public: // ------------------------------------------------------------------- //! Parse a value - static bool ParseValue(const char* pCur,const char** pCurOut, - EDataType eType,ValueUnion* out); + static bool ParseValue(const char* &pCur, EDataType eType, ValueUnion* out); // ------------------------------------------------------------------- //! Parse a binary value - static bool ParseValueBinary(const char* pCur,const char** pCurOut, - EDataType eType,ValueUnion* out,bool p_bBE); + static bool ParseValueBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, unsigned int &bufferSize, EDataType eType, ValueUnion* out, bool p_bBE); // ------------------------------------------------------------------- //! Convert a property value to a given type TYPE @@ -375,13 +375,13 @@ public: // ------------------------------------------------------------------- //! Parse an element instance - static bool ParseInstance (const char* pCur,const char** pCurOut, + static bool ParseInstance(const char* &pCur, const Element* pcElement, ElementInstance* p_pcOut); // ------------------------------------------------------------------- //! Parse a binary element instance - static bool ParseInstanceBinary (const char* pCur,const char** pCurOut, - const Element* pcElement, ElementInstance* p_pcOut,bool p_bBE); + static bool ParseInstanceBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstance* p_pcOut, bool p_bBE); }; // --------------------------------------------------------------------------------- @@ -400,13 +400,13 @@ public: // ------------------------------------------------------------------- //! Parse an element instance list - static bool ParseInstanceList (const char* pCur,const char** pCurOut, - const Element* pcElement, ElementInstanceList* p_pcOut); + static bool ParseInstanceList(IOStreamBuffer &streamBuffer, std::vector &buffer, + const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader); // ------------------------------------------------------------------- //! Parse a binary element instance list - static bool ParseInstanceListBinary (const char* pCur,const char** pCurOut, - const Element* pcElement, ElementInstanceList* p_pcOut,bool p_bBE); + static bool ParseInstanceListBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader, bool p_bBE); }; // --------------------------------------------------------------------------------- /** \brief Class to represent the document object model of an ASCII or binary @@ -428,50 +428,33 @@ public: //! Parse the DOM for a PLY file. The input string is assumed //! to be terminated with zero - static bool ParseInstance (const char* pCur,DOM* p_pcOut); - static bool ParseInstanceBinary (const char* pCur, - DOM* p_pcOut,bool p_bBE); + static bool ParseInstance(IOStreamBuffer &streamBuffer, DOM* p_pcOut, PLYImporter* loader); + static bool ParseInstanceBinary(IOStreamBuffer &streamBuffer, DOM* p_pcOut, PLYImporter* loader, bool p_bBE); //! Skip all comment lines after this - static bool SkipComments (const char* pCur,const char** pCurOut); + static bool SkipComments(std::vector &buffer); + + static bool SkipSpaces(std::vector &buffer); + + static bool SkipLine(std::vector &buffer); + + static bool TokenMatch(std::vector &buffer, const char* token, unsigned int len); + + static bool SkipSpacesAndLineEnd(std::vector &buffer); private: // ------------------------------------------------------------------- //! Handle the file header and read all element descriptions - bool ParseHeader (const char* pCur,const char** pCurOut, bool p_bBE); + bool ParseHeader(IOStreamBuffer &streamBuffer, std::vector &buffer, bool p_bBE); // ------------------------------------------------------------------- //! Read in all element instance lists - bool ParseElementInstanceLists (const char* pCur,const char** pCurOut); + bool ParseElementInstanceLists(IOStreamBuffer &streamBuffer, std::vector &buffer, PLYImporter* loader); // ------------------------------------------------------------------- //! Read in all element instance lists for a binary file format - bool ParseElementInstanceListsBinary (const char* pCur, - const char** pCurOut,bool p_bBE); -}; - -// --------------------------------------------------------------------------------- -/** \brief Helper class to represent a loaded PLY face - */ -class Face -{ -public: - - Face() - : iMaterialIndex(0xFFFFFFFF) - { - // set all indices to zero by default - mIndices.resize(3,0); - } - -public: - - //! List of vertex indices - std::vector mIndices; - - //! Material index - unsigned int iMaterialIndex; + bool ParseElementInstanceListsBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, const char* &pCur, unsigned int &bufferSize, PLYImporter* loader, bool p_bBE); }; // --------------------------------------------------------------------------------- diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index 5c592aaf5..f4d6ddda7 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -211,20 +211,20 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS for (unsigned int i = 0; i < pScene->mNumMeshes; i++) pScene->mRootNode->mMeshes[i] = i; - // create a single default material, using a light gray diffuse color for consistency with + // create a single default material, using a white diffuse color for consistency with // other geometric types (e.g., PLY). aiMaterial* pcMat = new aiMaterial(); aiString s; s.Set(AI_DEFAULT_MATERIAL_NAME); pcMat->AddProperty(&s, AI_MATKEY_NAME); - aiColor4D clrDiffuse(ai_real(0.6),ai_real(0.6),ai_real(0.6),ai_real(1.0)); + aiColor4D clrDiffuse(ai_real(1.0),ai_real(1.0),ai_real(1.0),ai_real(1.0)); if (bMatClr) { clrDiffuse = clrColorDefault; } pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR); - clrDiffuse = aiColor4D( ai_real( 0.05), ai_real( 0.05), ai_real( 0.05), ai_real( 1.0)); + clrDiffuse = aiColor4D( ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0)); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT); pScene->mNumMaterials = 1; diff --git a/contrib/poly2tri/poly2tri/common/shapes.cc b/contrib/poly2tri/poly2tri/common/shapes.cc index 4080445a7..d0de13e64 100644 --- a/contrib/poly2tri/poly2tri/common/shapes.cc +++ b/contrib/poly2tri/poly2tri/common/shapes.cc @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -88,7 +88,7 @@ void Triangle::Clear() points_[0]=points_[1]=points_[2] = NULL; } -void Triangle::ClearNeighbor(Triangle *triangle ) +void Triangle::ClearNeighbor(const Triangle *triangle ) { if( neighbors_[0] == triangle ) { @@ -96,14 +96,14 @@ void Triangle::ClearNeighbor(Triangle *triangle ) } else if( neighbors_[1] == triangle ) { - neighbors_[1] = NULL; + neighbors_[1] = NULL; } else { neighbors_[2] = NULL; } } - + void Triangle::ClearNeighbors() { neighbors_[0] = NULL; @@ -116,13 +116,9 @@ void Triangle::ClearDelunayEdges() delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; } -Point* Triangle::OppositePoint(Triangle& t, Point& p) +Point* Triangle::OppositePoint(Triangle& t, const Point& p) { Point *cw = t.PointCW(p); - //double x = cw->x; - //double y = cw->y; - //x = p.x; - //y = p.y; return PointCW(*cw); } @@ -164,8 +160,7 @@ int Triangle::Index(const Point* p) return 2; } assert(0); - - return 0; + return -1; } int Triangle::EdgeIndex(const Point* p1, const Point* p2) @@ -192,7 +187,7 @@ int Triangle::EdgeIndex(const Point* p1, const Point* p2) return -1; } -void Triangle::MarkConstrainedEdge(const int index) +void Triangle::MarkConstrainedEdge(int index) { constrained_edge[index] = true; } @@ -215,7 +210,7 @@ void Triangle::MarkConstrainedEdge(Point* p, Point* q) } // The point counter-clockwise to given point -Point* Triangle::PointCW(Point& point) +Point* Triangle::PointCW(const Point& point) { if (&point == points_[0]) { return points_[2]; @@ -225,12 +220,11 @@ Point* Triangle::PointCW(Point& point) return points_[1]; } assert(0); - - return 0; + return NULL; } // The point counter-clockwise to given point -Point* Triangle::PointCCW(Point& point) +Point* Triangle::PointCCW(const Point& point) { if (&point == points_[0]) { return points_[1]; @@ -240,12 +234,11 @@ Point* Triangle::PointCCW(Point& point) return points_[0]; } assert(0); - - return 0; + return NULL; } // The neighbor clockwise to given point -Triangle* Triangle::NeighborCW(Point& point) +Triangle* Triangle::NeighborCW(const Point& point) { if (&point == points_[0]) { return neighbors_[1]; @@ -256,7 +249,7 @@ Triangle* Triangle::NeighborCW(Point& point) } // The neighbor counter-clockwise to given point -Triangle* Triangle::NeighborCCW(Point& point) +Triangle* Triangle::NeighborCCW(const Point& point) { if (&point == points_[0]) { return neighbors_[2]; @@ -266,7 +259,7 @@ Triangle* Triangle::NeighborCCW(Point& point) return neighbors_[1]; } -bool Triangle::GetConstrainedEdgeCCW(Point& p) +bool Triangle::GetConstrainedEdgeCCW(const Point& p) { if (&p == points_[0]) { return constrained_edge[2]; @@ -276,7 +269,7 @@ bool Triangle::GetConstrainedEdgeCCW(Point& p) return constrained_edge[1]; } -bool Triangle::GetConstrainedEdgeCW(Point& p) +bool Triangle::GetConstrainedEdgeCW(const Point& p) { if (&p == points_[0]) { return constrained_edge[1]; @@ -286,7 +279,7 @@ bool Triangle::GetConstrainedEdgeCW(Point& p) return constrained_edge[0]; } -void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce) +void Triangle::SetConstrainedEdgeCCW(const Point& p, bool ce) { if (&p == points_[0]) { constrained_edge[2] = ce; @@ -297,7 +290,7 @@ void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce) } } -void Triangle::SetConstrainedEdgeCW(Point& p, bool ce) +void Triangle::SetConstrainedEdgeCW(const Point& p, bool ce) { if (&p == points_[0]) { constrained_edge[1] = ce; @@ -308,7 +301,7 @@ void Triangle::SetConstrainedEdgeCW(Point& p, bool ce) } } -bool Triangle::GetDelunayEdgeCCW(Point& p) +bool Triangle::GetDelunayEdgeCCW(const Point& p) { if (&p == points_[0]) { return delaunay_edge[2]; @@ -318,7 +311,7 @@ bool Triangle::GetDelunayEdgeCCW(Point& p) return delaunay_edge[1]; } -bool Triangle::GetDelunayEdgeCW(Point& p) +bool Triangle::GetDelunayEdgeCW(const Point& p) { if (&p == points_[0]) { return delaunay_edge[1]; @@ -328,7 +321,7 @@ bool Triangle::GetDelunayEdgeCW(Point& p) return delaunay_edge[0]; } -void Triangle::SetDelunayEdgeCCW(Point& p, bool e) +void Triangle::SetDelunayEdgeCCW(const Point& p, bool e) { if (&p == points_[0]) { delaunay_edge[2] = e; @@ -339,7 +332,7 @@ void Triangle::SetDelunayEdgeCCW(Point& p, bool e) } } -void Triangle::SetDelunayEdgeCW(Point& p, bool e) +void Triangle::SetDelunayEdgeCW(const Point& p, bool e) { if (&p == points_[0]) { delaunay_edge[1] = e; @@ -351,7 +344,7 @@ void Triangle::SetDelunayEdgeCW(Point& p, bool e) } // The neighbor across to given point -Triangle& Triangle::NeighborAcross(Point& opoint) +Triangle& Triangle::NeighborAcross(const Point& opoint) { if (&opoint == points_[0]) { return *neighbors_[0]; @@ -369,5 +362,4 @@ void Triangle::DebugPrint() cout << points_[2]->x << "," << points_[2]->y << endl; } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/common/shapes.h b/contrib/poly2tri/poly2tri/common/shapes.h index 4f691838f..ac7389a2d 100644 --- a/contrib/poly2tri/poly2tri/common/shapes.h +++ b/contrib/poly2tri/poly2tri/common/shapes.h @@ -113,7 +113,7 @@ struct Point { /// Convert this point into a unit point. Returns the Length. double Normalize() { - double len = Length(); + const double len = Length(); x /= len; y /= len; return len; @@ -162,50 +162,50 @@ bool constrained_edge[3]; /// Flags to determine if an edge is a Delauney edge bool delaunay_edge[3]; -Point* GetPoint(const int& index); -Point* PointCW(Point& point); -Point* PointCCW(Point& point); -Point* OppositePoint(Triangle& t, Point& p); +Point* GetPoint(int index); +Point* PointCW(const Point& point); +Point* PointCCW(const Point& point); +Point* OppositePoint(Triangle& t, const Point& p); -Triangle* GetNeighbor(const int& index); +Triangle* GetNeighbor(int index); void MarkNeighbor(Point* p1, Point* p2, Triangle* t); void MarkNeighbor(Triangle& t); -void MarkConstrainedEdge(const int index); +void MarkConstrainedEdge(int index); void MarkConstrainedEdge(Edge& edge); void MarkConstrainedEdge(Point* p, Point* q); int Index(const Point* p); int EdgeIndex(const Point* p1, const Point* p2); -Triangle* NeighborCW(Point& point); -Triangle* NeighborCCW(Point& point); -bool GetConstrainedEdgeCCW(Point& p); -bool GetConstrainedEdgeCW(Point& p); -void SetConstrainedEdgeCCW(Point& p, bool ce); -void SetConstrainedEdgeCW(Point& p, bool ce); -bool GetDelunayEdgeCCW(Point& p); -bool GetDelunayEdgeCW(Point& p); -void SetDelunayEdgeCCW(Point& p, bool e); -void SetDelunayEdgeCW(Point& p, bool e); +Triangle* NeighborCW(const Point& point); +Triangle* NeighborCCW(const Point& point); +bool GetConstrainedEdgeCCW(const Point& p); +bool GetConstrainedEdgeCW(const Point& p); +void SetConstrainedEdgeCCW(const Point& p, bool ce); +void SetConstrainedEdgeCW(const Point& p, bool ce); +bool GetDelunayEdgeCCW(const Point& p); +bool GetDelunayEdgeCW(const Point& p); +void SetDelunayEdgeCCW(const Point& p, bool e); +void SetDelunayEdgeCW(const Point& p, bool e); -bool Contains(Point* p); +bool Contains(const Point* p); bool Contains(const Edge& e); -bool Contains(Point* p, Point* q); +bool Contains(const Point* p, const Point* q); void Legalize(Point& point); void Legalize(Point& opoint, Point& npoint); /** * Clears all references to all other triangles and points */ void Clear(); -void ClearNeighbor(Triangle *triangle ); +void ClearNeighbor(const Triangle *triangle); void ClearNeighbors(); void ClearDelunayEdges(); inline bool IsInterior(); inline void IsInterior(bool b); -Triangle& NeighborAcross(Point& opoint); +Triangle& NeighborAcross(const Point& opoint); void DebugPrint(); @@ -258,7 +258,7 @@ inline bool operator ==(const Point& a, const Point& b) inline bool operator !=(const Point& a, const Point& b) { - return a.x != b.x || a.y != b.y; + return !(a.x == b.x) && !(a.y == b.y); } /// Peform the dot product on two vectors. @@ -282,22 +282,22 @@ inline Point Cross(const Point& a, double s) /// Perform the cross product on a scalar and a point. In 2D this produces /// a point. -inline Point Cross(const double s, const Point& a) +inline Point Cross(double s, const Point& a) { return Point(-s * a.y, s * a.x); } -inline Point* Triangle::GetPoint(const int& index) +inline Point* Triangle::GetPoint(int index) { return points_[index]; } -inline Triangle* Triangle::GetNeighbor(const int& index) +inline Triangle* Triangle::GetNeighbor(int index) { return neighbors_[index]; } -inline bool Triangle::Contains(Point* p) +inline bool Triangle::Contains(const Point* p) { return p == points_[0] || p == points_[1] || p == points_[2]; } @@ -307,7 +307,7 @@ inline bool Triangle::Contains(const Edge& e) return Contains(e.p) && Contains(e.q); } -inline bool Triangle::Contains(Point* p, Point* q) +inline bool Triangle::Contains(const Point* p, const Point* q) { return Contains(p) && Contains(q); } @@ -324,6 +324,4 @@ inline void Triangle::IsInterior(bool b) } -#endif - - +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/common/utils.h b/contrib/poly2tri/poly2tri/common/utils.h index f123fedaf..2424c712c 100644 --- a/contrib/poly2tri/poly2tri/common/utils.h +++ b/contrib/poly2tri/poly2tri/common/utils.h @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -28,18 +28,26 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - + #ifndef UTILS_H #define UTILS_H +// Otherwise #defines like M_PI are undeclared under Visual Studio +#define _USE_MATH_DEFINES + #include +#include + +// C99 removes M_PI from math.h +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327 +#endif namespace p2t { -const double PI = 3.1415926535897932384626433832795029; -const double PI_2 = 2 * PI; -const double PI_3div4 = 3 * PI / 4; -const double EPSILON = 1e-15; +const double PI_3div4 = 3 * M_PI / 4; +const double PI_div2 = 1.57079632679489661923; +const double EPSILON = 1e-12; enum Orientation { CW, CCW, COLLINEAR }; @@ -53,7 +61,7 @@ enum Orientation { CW, CCW, COLLINEAR }; * = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3) * */ -Orientation Orient2d(Point& pa, Point& pb, Point& pc) +Orientation Orient2d(const Point& pa, const Point& pb, const Point& pc) { double detleft = (pa.x - pc.x) * (pb.y - pc.y); double detright = (pa.y - pc.y) * (pb.x - pc.x); @@ -66,6 +74,7 @@ Orientation Orient2d(Point& pa, Point& pb, Point& pc) return CW; } +/* bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd) { double pdx = pd.x; @@ -97,7 +106,22 @@ bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd) return true; } +*/ + +bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point& pd) +{ + double oadb = (pa.x - pb.x)*(pd.y - pb.y) - (pd.x - pb.x)*(pa.y - pb.y); + if (oadb >= -EPSILON) { + return false; + } + + double oadc = (pa.x - pc.x)*(pd.y - pc.y) - (pd.x - pc.x)*(pa.y - pc.y); + if (oadc <= EPSILON) { + return false; + } + return true; +} + } #endif - diff --git a/contrib/poly2tri/poly2tri/poly2tri.h b/contrib/poly2tri/poly2tri/poly2tri.h index 487755e2e..29a08d052 100644 --- a/contrib/poly2tri/poly2tri/poly2tri.h +++ b/contrib/poly2tri/poly2tri/poly2tri.h @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -35,5 +35,4 @@ #include "common/shapes.h" #include "sweep/cdt.h" -#endif - +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/advancing_front.cc b/contrib/poly2tri/poly2tri/sweep/advancing_front.cc index 019df4a6e..38723beef 100644 --- a/contrib/poly2tri/poly2tri/sweep/advancing_front.cc +++ b/contrib/poly2tri/poly2tri/sweep/advancing_front.cc @@ -39,7 +39,7 @@ AdvancingFront::AdvancingFront(Node& head, Node& tail) search_node_ = &head; } -Node* AdvancingFront::LocateNode(const double& x) +Node* AdvancingFront::LocateNode(double x) { Node* node = search_node_; @@ -61,7 +61,7 @@ Node* AdvancingFront::LocateNode(const double& x) return NULL; } -Node* AdvancingFront::FindSearchNode(const double& x) +Node* AdvancingFront::FindSearchNode(double x) { (void)x; // suppress compiler warnings "unused parameter 'x'" // TODO: implement BST index @@ -105,5 +105,4 @@ AdvancingFront::~AdvancingFront() { } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/advancing_front.h b/contrib/poly2tri/poly2tri/sweep/advancing_front.h index bab73d449..645dcec97 100644 --- a/contrib/poly2tri/poly2tri/sweep/advancing_front.h +++ b/contrib/poly2tri/poly2tri/sweep/advancing_front.h @@ -74,7 +74,7 @@ Node* search(); void set_search(Node* node); /// Locate insertion point along advancing front -Node* LocateNode(const double& x); +Node* LocateNode(double x); Node* LocatePoint(const Point* point); @@ -82,7 +82,7 @@ private: Node* head_, *tail_, *search_node_; -Node* FindSearchNode(const double& x); +Node* FindSearchNode(double x); }; inline Node* AdvancingFront::head() @@ -115,4 +115,4 @@ inline void AdvancingFront::set_search(Node* node) } -#endif +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/cdt.cc b/contrib/poly2tri/poly2tri/sweep/cdt.cc index d7838257c..09d088ae3 100644 --- a/contrib/poly2tri/poly2tri/sweep/cdt.cc +++ b/contrib/poly2tri/poly2tri/sweep/cdt.cc @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -32,13 +32,13 @@ namespace p2t { -CDT::CDT(std::vector polyline) +CDT::CDT(const std::vector& polyline) { sweep_context_ = new SweepContext(polyline); sweep_ = new Sweep; } -void CDT::AddHole(std::vector polyline) +void CDT::AddHole(const std::vector& polyline) { sweep_context_->AddHole(polyline); } @@ -68,5 +68,4 @@ CDT::~CDT() delete sweep_; } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/cdt.h b/contrib/poly2tri/poly2tri/sweep/cdt.h index 3e6f02408..ea3286d9a 100644 --- a/contrib/poly2tri/poly2tri/sweep/cdt.h +++ b/contrib/poly2tri/poly2tri/sweep/cdt.h @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -28,7 +28,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - + #ifndef CDT_H #define CDT_H @@ -37,11 +37,11 @@ #include "sweep.h" /** - * + * * @author Mason Green * */ - + namespace p2t { class CDT @@ -50,40 +50,40 @@ public: /** * Constructor - add polyline with non repeating points - * + * * @param polyline */ - CDT(std::vector polyline); - + CDT(const std::vector& polyline); + /** * Destructor - clean up memory */ ~CDT(); - + /** * Add a hole - * + * * @param polyline */ - void AddHole(std::vector polyline); - + void AddHole(const std::vector& polyline); + /** * Add a steiner point - * + * * @param point */ void AddPoint(Point* point); - + /** * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points */ void Triangulate(); - + /** * Get CDT triangles */ std::vector GetTriangles(); - + /** * Get triangle map */ @@ -94,7 +94,7 @@ public: /** * Internals */ - + SweepContext* sweep_context_; Sweep* sweep_; @@ -102,4 +102,4 @@ public: } -#endif +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/sweep.cc b/contrib/poly2tri/poly2tri/sweep/sweep.cc index ed7c49ac4..826905ceb 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep.cc +++ b/contrib/poly2tri/poly2tri/sweep/sweep.cc @@ -49,7 +49,7 @@ void Sweep::Triangulate(SweepContext& tcx) void Sweep::SweepPoints(SweepContext& tcx) { - for (int i = 1; i < tcx.point_count(); i++) { + for (size_t i = 1; i < tcx.point_count(); i++) { Point& point = *tcx.GetPoint(i); Node* node = &PointEvent(tcx, point); for (unsigned int i = 0; i < point.edge_list.size(); i++) { @@ -117,7 +117,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl throw std::runtime_error("EdgeEvent - collinear points not supported"); if( triangle->Contains(&eq, p1)) { triangle->MarkConstrainedEdge(&eq, p1 ); - // We are modifying the constraint maybe it would be better to + // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p1; triangle = &triangle->NeighborAcross(point); @@ -137,7 +137,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl if( triangle->Contains(&eq, p2)) { triangle->MarkConstrainedEdge(&eq, p2 ); - // We are modifying the constraint maybe it would be better to + // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p2; triangle = &triangle->NeighborAcross(point); @@ -166,7 +166,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl bool Sweep::IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq) { - int index = triangle.EdgeIndex(&ep, &eq); + const int index = triangle.EdgeIndex(&ep, &eq); if (index != -1) { triangle.MarkConstrainedEdge(index); @@ -230,8 +230,8 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) Node* node = n.next; while (node->next) { - double angle = HoleAngle(*node); - if (angle > PI_2 || angle < -PI_2) break; + // if HoleAngle exceeds 90 degrees then break. + if (LargeHole_DontFill(node)) break; Fill(tcx, *node); node = node->next; } @@ -240,29 +240,81 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) node = n.prev; while (node->prev) { - double angle = HoleAngle(*node); - if (angle > PI_2 || angle < -PI_2) break; + // if HoleAngle exceeds 90 degrees then break. + if (LargeHole_DontFill(node)) break; Fill(tcx, *node); node = node->prev; } // Fill right basins if (n.next && n.next->next) { - double angle = BasinAngle(n); + const double angle = BasinAngle(n); if (angle < PI_3div4) { FillBasin(tcx, n); } } } -double Sweep::BasinAngle(Node& node) +// True if HoleAngle exceeds 90 degrees. +bool Sweep::LargeHole_DontFill(const Node* node) const { + + const Node* nextNode = node->next; + const Node* prevNode = node->prev; + if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point)) + return false; + + // Check additional points on front. + const Node* next2Node = nextNode->next; + // "..Plus.." because only want angles on same side as point being added. + if ((next2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point)) + return false; + + const Node* prev2Node = prevNode->prev; + // "..Plus.." because only want angles on same side as point being added. + if ((prev2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point)) + return false; + + return true; +} + +bool Sweep::AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const { + const double angle = Angle(origin, pa, pb); + return ((angle > PI_div2) || (angle < -PI_div2)); +} + +bool Sweep::AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const { + const double angle = Angle(origin, pa, pb); + return (angle > PI_div2) || (angle < 0); +} + +double Sweep::Angle(const Point* origin, const Point* pa, const Point* pb) const { + /* Complex plane + * ab = cosA +i*sinA + * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) + * atan2(y,x) computes the principal value of the argument function + * applied to the complex number x+iy + * Where x = ax*bx + ay*by + * y = ax*by - ay*bx + */ + const double px = origin->x; + const double py = origin->y; + const double ax = pa->x- px; + const double ay = pa->y - py; + const double bx = pb->x - px; + const double by = pb->y - py; + const double x = ax * by - ay * bx; + const double y = ax * bx + ay * by; + return atan2(x, y); +} + +double Sweep::BasinAngle(const Node& node) const { - double ax = node.point->x - node.next->next->point->x; - double ay = node.point->y - node.next->next->point->y; + const double ax = node.point->x - node.next->next->point->x; + const double ay = node.point->y - node.next->next->point->y; return atan2(ay, ax); } -double Sweep::HoleAngle(Node& node) +double Sweep::HoleAngle(const Node& node) const { /* Complex plane * ab = cosA +i*sinA @@ -272,10 +324,10 @@ double Sweep::HoleAngle(Node& node) * Where x = ax*bx + ay*by * y = ax*by - ay*bx */ - double ax = node.next->point->x - node.point->x; - double ay = node.next->point->y - node.point->y; - double bx = node.prev->point->x - node.point->x; - double by = node.prev->point->y - node.point->y; + const double ax = node.next->point->x - node.point->x; + const double ay = node.next->point->y - node.point->y; + const double bx = node.prev->point->x - node.point->x; + const double by = node.prev->point->y - node.point->y; return atan2(ax * by - ay * bx, ax * bx + ay * by); } @@ -340,43 +392,43 @@ bool Sweep::Legalize(SweepContext& tcx, Triangle& t) return false; } -bool Sweep::Incircle(Point& pa, Point& pb, Point& pc, Point& pd) +bool Sweep::Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const { - double adx = pa.x - pd.x; - double ady = pa.y - pd.y; - double bdx = pb.x - pd.x; - double bdy = pb.y - pd.y; + const double adx = pa.x - pd.x; + const double ady = pa.y - pd.y; + const double bdx = pb.x - pd.x; + const double bdy = pb.y - pd.y; - double adxbdy = adx * bdy; - double bdxady = bdx * ady; - double oabd = adxbdy - bdxady; + const double adxbdy = adx * bdy; + const double bdxady = bdx * ady; + const double oabd = adxbdy - bdxady; if (oabd <= 0) return false; - double cdx = pc.x - pd.x; - double cdy = pc.y - pd.y; + const double cdx = pc.x - pd.x; + const double cdy = pc.y - pd.y; - double cdxady = cdx * ady; - double adxcdy = adx * cdy; - double ocad = cdxady - adxcdy; + const double cdxady = cdx * ady; + const double adxcdy = adx * cdy; + const double ocad = cdxady - adxcdy; if (ocad <= 0) return false; - double bdxcdy = bdx * cdy; - double cdxbdy = cdx * bdy; + const double bdxcdy = bdx * cdy; + const double cdxbdy = cdx * bdy; - double alift = adx * adx + ady * ady; - double blift = bdx * bdx + bdy * bdy; - double clift = cdx * cdx + cdy * cdy; + const double alift = adx * adx + ady * ady; + const double blift = bdx * bdx + bdy * bdy; + const double clift = cdx * cdx + cdy * cdy; - double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; + const double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; return det > 0; } -void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) +void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const { Triangle* n1, *n2, *n3, *n4; n1 = t.NeighborCCW(p); @@ -708,11 +760,8 @@ Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op) } else if (o2d == CCW) { // Left return *ot.PointCW(op); - } else{ - //throw new RuntimeException("[Unsupported] Opposing point on constrained edge"); - // ASSIMP_CHANGE (aramis_acg) - throw std::runtime_error("[Unsupported] Opposing point on constrained edge"); } + throw std::runtime_error("[Unsupported] Opposing point on constrained edge"); } void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, @@ -740,7 +789,7 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& Sweep::~Sweep() { // Clean up memory - for(unsigned int i = 0; i < nodes_.size(); i++) { + for(size_t i = 0; i < nodes_.size(); i++) { delete nodes_[i]; } diff --git a/contrib/poly2tri/poly2tri/sweep/sweep.h b/contrib/poly2tri/poly2tri/sweep/sweep.h index bd98adfc5..33e34a714 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep.h +++ b/contrib/poly2tri/poly2tri/sweep/sweep.h @@ -33,7 +33,7 @@ * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', * International Journal of Geographical Information Science * - * "FlipScan" Constrained Edge Algorithm invented by Thomas Åhlén, thahlen@gmail.com + * "FlipScan" Constrained Edge Algorithm invented by Thomas ?hl?n, thahlen@gmail.com */ #ifndef SWEEP_H @@ -49,17 +49,17 @@ struct Point; struct Edge; class Triangle; -class Sweep +class Sweep { public: /** * Triangulate - * + * * @param tcx */ void Triangulate(SweepContext& tcx); - + /** * Destructor - clean up memory */ @@ -69,7 +69,7 @@ private: /** * Start sweeping the Y-sorted point set from bottom to top - * + * * @param tcx */ void SweepPoints(SweepContext& tcx); @@ -86,8 +86,8 @@ private: Node& PointEvent(SweepContext& tcx, Point& point); /** - * - * + * + * * @param tcx * @param edge * @param node @@ -98,7 +98,7 @@ private: /** * Creates a new front triangle and legalize it - * + * * @param tcx * @param point * @param node @@ -142,7 +142,7 @@ private: * @param d - point opposite a * @return true if d is inside circle, false if on circle edge */ - bool Incircle(Point& pa, Point& pb, Point& pc, Point& pd); + bool Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const; /** * Rotates a triangle pair one vertex CW @@ -158,7 +158,7 @@ private: * n4 n4 * */ - void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op); + void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const; /** * Fills holes in the Advancing Front @@ -169,17 +169,24 @@ private: */ void FillAdvancingFront(SweepContext& tcx, Node& n); + // Decision-making about when to Fill hole. + // Contributed by ToolmakerSteve2 + bool LargeHole_DontFill(const Node* node) const; + bool AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const; + bool AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const; + double Angle(const Point* origin, const Point* pa, const Point* pb) const; + /** * * @param node - middle node * @return the angle between 3 front nodes */ - double HoleAngle(Node& node); + double HoleAngle(const Node& node) const; /** * The basin angle is decided against the horizontal line [1,0] */ - double BasinAngle(Node& node); + double BasinAngle(const Node& node) const; /** * Fills a basin that has formed on the Advancing Front to the right @@ -228,22 +235,22 @@ private: /** * After a flip we have two triangles and know that only one will still be * intersecting the edge. So decide which to contiune with and legalize the other - * + * * @param tcx * @param o - should be the result of an orient2d( eq, op, ep ) * @param t - triangle 1 * @param ot - triangle 2 - * @param p - a point shared by both triangles + * @param p - a point shared by both triangles * @param op - another point shared by both triangles * @return returns the triangle still intersecting the edge */ Triangle& NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op); /** - * When we need to traverse from one triangle to the next we need + * When we need to traverse from one triangle to the next we need * the point in current triangle that is the opposite point to the next - * triangle. - * + * triangle. + * * @param ep * @param eq * @param ot @@ -254,10 +261,10 @@ private: /** * Scan part of the FlipScan algorithm
- * When a triangle pair isn't flippable we will scan for the next - * point that is inside the flip triangle scan area. When found + * When a triangle pair isn't flippable we will scan for the next + * point that is inside the flip triangle scan area. When found * we generate a new flipEdgeEvent - * + * * @param tcx * @param ep - last point on the edge we are traversing * @param eq - first point on the edge we are traversing @@ -275,4 +282,4 @@ private: } -#endif +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/sweep_context.cc b/contrib/poly2tri/poly2tri/sweep/sweep_context.cc index 184457cf2..a9f1fdf8e 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep_context.cc +++ b/contrib/poly2tri/poly2tri/sweep/sweep_context.cc @@ -34,17 +34,18 @@ namespace p2t { -SweepContext::SweepContext(std::vector polyline) +SweepContext::SweepContext(const std::vector& polyline) : points_(polyline), + front_(0), + head_(0), + tail_(0), + af_head_(0), + af_middle_(0), + af_tail_(0) { - basin = Basin(); - edge_event = EdgeEvent(); - - points_ = polyline; - InitEdges(points_); } -void SweepContext::AddHole(std::vector polyline) +void SweepContext::AddHole(const std::vector& polyline) { InitEdges(polyline); for(unsigned int i = 0; i < polyline.size(); i++) { @@ -56,12 +57,12 @@ void SweepContext::AddPoint(Point* point) { points_.push_back(point); } -std::vector SweepContext::GetTriangles() +std::vector &SweepContext::GetTriangles() { return triangles_; } -std::list SweepContext::GetMap() +std::list &SweepContext::GetMap() { return map_; } @@ -94,16 +95,16 @@ void SweepContext::InitTriangulation() } -void SweepContext::InitEdges(std::vector polyline) +void SweepContext::InitEdges(const std::vector& polyline) { - int num_points = static_cast(polyline.size()); - for (int i = 0; i < num_points; i++) { - int j = i < num_points - 1 ? i + 1 : 0; + size_t num_points = polyline.size(); + for (size_t i = 0; i < num_points; i++) { + size_t j = i < num_points - 1 ? i + 1 : 0; edge_list.push_back(new Edge(*polyline[i], *polyline[j])); } } -Point* SweepContext::GetPoint(const int& index) +Point* SweepContext::GetPoint(size_t index) { return points_[index]; } @@ -113,13 +114,13 @@ void SweepContext::AddToMap(Triangle* triangle) map_.push_back(triangle); } -Node& SweepContext::LocateNode(Point& point) +Node& SweepContext::LocateNode(const Point& point) { // TODO implement search tree return *front_->LocateNode(point.x); } -void SweepContext::CreateAdvancingFront(std::vector nodes) +void SweepContext::CreateAdvancingFront(const std::vector& nodes) { (void) nodes; @@ -164,12 +165,20 @@ void SweepContext::RemoveFromMap(Triangle* triangle) void SweepContext::MeshClean(Triangle& triangle) { - if (!triangle.IsInterior()) { - triangle.IsInterior(true); - triangles_.push_back(&triangle); - for (int i = 0; i < 3; i++) { - if (!triangle.constrained_edge[i]) - MeshClean(*triangle.GetNeighbor(i)); + std::vector triangles; + triangles.push_back(&triangle); + + while(!triangles.empty()){ + Triangle *t = triangles.back(); + triangles.pop_back(); + + if (t != NULL && !t->IsInterior()) { + t->IsInterior(true); + triangles_.push_back(t); + for (int i = 0; i < 3; i++) { + if (!t->constrained_edge[i]) + triangles.push_back(t->GetNeighbor(i)); + } } } } diff --git a/contrib/poly2tri/poly2tri/sweep/sweep_context.h b/contrib/poly2tri/poly2tri/sweep/sweep_context.h index 2f7d8e982..ba0d06581 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep_context.h +++ b/contrib/poly2tri/poly2tri/sweep/sweep_context.h @@ -52,47 +52,47 @@ class SweepContext { public: /// Constructor -SweepContext(std::vector polyline); +SweepContext(const std::vector& polyline); /// Destructor ~SweepContext(); void set_head(Point* p1); -Point* head(); +Point* head() const; void set_tail(Point* p1); -Point* tail(); +Point* tail() const; -int point_count(); +size_t point_count() const; -Node& LocateNode(Point& point); +Node& LocateNode(const Point& point); void RemoveNode(Node* node); -void CreateAdvancingFront(std::vector nodes); +void CreateAdvancingFront(const std::vector& nodes); /// Try to map a node to all sides of this triangle that don't have a neighbor void MapTriangleToNodes(Triangle& t); void AddToMap(Triangle* triangle); -Point* GetPoint(const int& index); +Point* GetPoint(size_t index); Point* GetPoints(); void RemoveFromMap(Triangle* triangle); -void AddHole(std::vector polyline); +void AddHole(const std::vector& polyline); void AddPoint(Point* point); -AdvancingFront* front(); +AdvancingFront* front() const; void MeshClean(Triangle& triangle); -std::vector GetTriangles(); -std::list GetMap(); +std::vector &GetTriangles(); +std::list &GetMap(); std::vector edge_list; @@ -147,18 +147,18 @@ Point* tail_; Node *af_head_, *af_middle_, *af_tail_; void InitTriangulation(); -void InitEdges(std::vector polyline); +void InitEdges(const std::vector& polyline); }; -inline AdvancingFront* SweepContext::front() +inline AdvancingFront* SweepContext::front() const { return front_; } -inline int SweepContext::point_count() +inline size_t SweepContext::point_count() const { - return static_cast(points_.size()); + return points_.size(); } inline void SweepContext::set_head(Point* p1) @@ -166,7 +166,7 @@ inline void SweepContext::set_head(Point* p1) head_ = p1; } -inline Point* SweepContext::head() +inline Point* SweepContext::head() const { return head_; } @@ -176,7 +176,7 @@ inline void SweepContext::set_tail(Point* p1) tail_ = p1; } -inline Point* SweepContext::tail() +inline Point* SweepContext::tail() const { return tail_; }