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)
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())
/// @return true if successful.
bool getNextDataLine( std::vector<T> &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<T> &buffer );
+
private:
IOStream *m_stream;
size_t m_filesize;
return true;
}
+template<class T>
+inline
+bool IOStreamBuffer<T>::getNextBlock( std::vector<T> &buffer) {
+ //just return the last blockvalue if getNextLine was used before
+ if ( m_cachePos != 0) {
+ buffer = std::vector<T>(m_cache.begin() + m_cachePos, m_cache.end());
+ m_cachePos = 0;
+ }
+ else {
+ if ( !readNextBlock() )
+ return false;
+
+ buffer = std::vector<T>(m_cache.begin(), m_cache.end());
+ }
+ return true;
+}
+
} // !ns Assimp
Copyright (c) 2006-2017, assimp team
-
All rights reserved.
Redistribution and use of this software in source and binary forms,
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
// internal headers
#include "PlyLoader.h"
+#include "IOStreamBuffer.h"
#include "Macros.h"
#include <memory>
#include <assimp/IOSystem.hpp>
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"
};
// Internal stuff
namespace
{
- // ------------------------------------------------------------------------------------------------
- // Checks that property index is within range
- template <class T>
- const T &GetProperty(const std::vector<T> &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 <class T>
+ const T &GetProperty(const std::vector<T> &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];
+ }
}
// ------------------------------------------------------------------------------------------------
// 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);
-
- 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 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;
}
// ------------------------------------------------------------------------------------------------
-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<IOStream> file( pIOHandler->Open( pFile));
-
- // Check whether we can read from the file
- if( file.get() == NULL) {
- throw DeadlyImportError( "Failed to open PLY file " + pFile + ".");
+ static const std::string mode = "rb";
+ std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
+ if (!fileStream.get()) {
+ throw DeadlyImportError("Failed to open file " + pFile + ".");
+ }
+
+ // Get the file-size
+ size_t fileSize = fileStream->FileSize();
+
+ IOStreamBuffer<char> streamedBuffer(1024 * 1024);
+ streamedBuffer.open(fileStream.get());
+
+ // the beginning of the file must be PLY - magic, magic
+ std::vector<char> 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<char> 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));
+
+ // 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);
+
+ streamedBuffer.close();
+ throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
+ }
}
+ else
+ {
+ if (mGeneratedMesh != NULL)
+ delete(mGeneratedMesh);
- // allocate storage and copy the contents of the file to a memory buffer
- std::vector<char> mBuffer2;
- TextFileToBuffer(file.get(),mBuffer2);
- mBuffer = (unsigned char*)&mBuffer2[0];
+ streamedBuffer.close();
+ throw DeadlyImportError("Invalid .ply file: Unknown file format");
+ }
+ }
+ else
+ {
+ AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
+ if (mGeneratedMesh != NULL)
+ delete(mGeneratedMesh);
+
+ streamedBuffer.close();
+ throw DeadlyImportError("Invalid .ply file: Missing format specification");
+ }
+
+ //free the file buffer
+ streamedBuffer.close();
+
+ if (mGeneratedMesh == NULL)
+ {
+ throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
+ }
+
+ // 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 (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");
+ streamedBuffer.close();
+ throw DeadlyImportError("Invalid .ply file: Not enough "
+ "vertices to build a proper face list. ");
}
- 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 ) );
+ const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3;
+ mGeneratedMesh->mNumFaces = iNum;
+ mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
- // 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" );
- }
- }
- else
+ for (unsigned int i = 0; i < iNum; ++i)
{
- AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
- throw DeadlyImportError( "Invalid .ply file: Missing format specification");
+ 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;
}
- this->pcDOM = &sPlyDom;
+ }
+
+ // now load a list of all materials
+ std::vector<aiMaterial*> avMaterials;
+ std::string defaultTexture;
+ LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
+
+ // 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];
+ }
+
+ // fill the mesh list
+ pScene->mNumMeshes = 1;
+ pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+ pScene->mMeshes[0] = mGeneratedMesh;
+
+ // 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;
+ }
+}
- // now load a list of vertices. This must be successfully in order to procedure
- std::vector<aiVector3D> avPositions;
- this->LoadVertices(&avPositions,false);
+void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos)
+{
+ ai_assert(NULL != pcElement);
+ ai_assert(NULL != instElement);
- if ( avPositions.empty() ) {
- throw DeadlyImportError( "Invalid .ply file: No vertices found. "
- "Unable to parse the data format of the PLY file." );
- }
+ ai_uint aiPositions[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ PLY::EDataType aiTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
+
+ ai_uint aiNormal[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ PLY::EDataType aiNormalTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
+
+ 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 };
- // now load a list of normals.
- std::vector<aiVector3D> avNormals;
- LoadVertices(&avNormals,true);
+ unsigned int cnt = 0;
- // load the face list
- std::vector<PLY::Face> avFaces;
- LoadFaces(&avFaces);
+ // now check whether which normal components are available
+ unsigned int _a = 0;
+ for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+ a != pcElement->alProperties.end(); ++a, ++_a)
+ {
+ if ((*a).bIsList)continue;
- // if no face list is existing we assume that the vertex
- // list is containing a list of triangles
- if (avFaces.empty())
+ // Positions
+ if (PLY::EST_XCoord == (*a).Semantic)
{
- if (avPositions.size() < 3)
- {
- throw DeadlyImportError( "Invalid .ply file: Not enough "
- "vertices to build a proper face list. ");
- }
+ 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;
+ }
- 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);
- }
+ // 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<ai_real>(
+ GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]);
}
- // now load a list of all materials
- std::vector<aiMaterial*> avMaterials;
- LoadMaterial(&avMaterials);
+ if (0xFFFFFFFF != aiPositions[1])
+ {
+ vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+ GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]);
+ }
- // now load a list of all vertex color channels
- std::vector<aiColor4D> avColors;
- avColors.reserve(avPositions.size());
- LoadVertexColor(&avColors);
+ if (0xFFFFFFFF != aiPositions[2])
+ {
+ vOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
+ GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]);
+ }
- // now try to load texture coordinates
- std::vector<aiVector2D> avTexCoords;
- avTexCoords.reserve(avPositions.size());
- LoadTextureCoordinates(&avTexCoords);
+ // Normals
+ aiVector3D nOut;
+ bool haveNormal = false;
+ if (0xFFFFFFFF != aiNormal[0])
+ {
+ nOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
+ GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]);
+ haveNormal = true;
+ }
- // now replace the default material in all faces and validate all material indices
- ReplaceDefaultMaterial(&avFaces,&avMaterials);
+ if (0xFFFFFFFF != aiNormal[1])
+ {
+ nOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+ GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]);
+ haveNormal = true;
+ }
- // now convert this to a list of aiMesh instances
- std::vector<aiMesh*> avMeshes;
- avMeshes.reserve(avMaterials.size()+1);
- ConvertMeshes(&avFaces,&avPositions,&avNormals,
- &avColors,&avTexCoords,&avMaterials,&avMeshes);
+ if (0xFFFFFFFF != aiNormal[2])
+ {
+ nOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
+ GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]);
+ haveNormal = true;
+ }
- if ( avMeshes.empty() ) {
- throw DeadlyImportError( "Invalid .ply file: Unable to extract mesh data " );
+ //Colors
+ aiColor4D cOut;
+ bool haveColor = false;
+ if (0xFFFFFFFF != aiColors[0])
+ {
+ cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties,
+ aiColors[0]).avList.front(), aiColorsTypes[0]);
+ haveColor = true;
}
- // 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 ];
+ if (0xFFFFFFFF != aiColors[1])
+ {
+ cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties,
+ aiColors[1]).avList.front(), aiColorsTypes[1]);
+ haveColor = true;
}
- // 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 ];
+ if (0xFFFFFFFF != aiColors[2])
+ {
+ cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties,
+ aiColors[2]).avList.front(), aiColorsTypes[2]);
+ haveColor = true;
}
- // generate a simple node structure
- pScene->mRootNode = new aiNode();
- pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
- pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+ // 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]);
- for ( unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i ) {
- pScene->mRootNode->mMeshes[ i ] = i;
+ haveColor = true;
}
-}
-// ------------------------------------------------------------------------------------------------
-// Split meshes by material IDs
-void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
- const std::vector<aiVector3D>* avPositions,
- const std::vector<aiVector3D>* avNormals,
- const std::vector<aiColor4D>* avColors,
- const std::vector<aiVector2D>* avTexCoords,
- const std::vector<aiMaterial*>* avMaterials,
- std::vector<aiMesh*>* avOut)
-{
- ai_assert(NULL != avFaces);
- ai_assert(NULL != avPositions);
- ai_assert(NULL != avMaterials);
+ //Texture coordinates
+ aiVector3D tOut;
+ tOut.z = 0;
+ bool haveTextureCoords = false;
+ if (0xFFFFFFFF != aiTexcoord[0])
+ {
+ tOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
+ GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]);
+ haveTextureCoords = true;
+ }
- // split by materials
- std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[avMaterials->size()];
+ if (0xFFFFFFFF != aiTexcoord[1])
+ {
+ tOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+ GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]);
+ haveTextureCoords = true;
+ }
- unsigned int iNum = 0;
- for (std::vector<PLY::Face>::const_iterator i = avFaces->begin();i != avFaces->end();++i,++iNum)
- aiSplit[(*i).iMaterialIndex].push_back(iNum);
+ //create aiMesh if needed
+ if (mGeneratedMesh == NULL)
+ {
+ mGeneratedMesh = new aiMesh();
+ mGeneratedMesh->mMaterialIndex = 0;
+ }
- // now generate sub-meshes
- for (unsigned int p = 0; p < avMaterials->size();++p)
+ if (mGeneratedMesh->mVertices == NULL)
{
- if (aiSplit[p].size() != 0)
- {
- // allocate the mesh object
- aiMesh* p_pcOut = new aiMesh();
- p_pcOut->mMaterialIndex = p;
+ mGeneratedMesh->mNumVertices = pcElement->NumOccur;
+ mGeneratedMesh->mVertices = new aiVector3D[mGeneratedMesh->mNumVertices];
+ }
- p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
- p_pcOut->mFaces = new aiFace[aiSplit[p].size()];
+ mGeneratedMesh->mVertices[pos] = vOut;
- // 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 (haveNormal)
+ {
+ if (mGeneratedMesh->mNormals == NULL)
+ mGeneratedMesh->mNormals = new aiVector3D[mGeneratedMesh->mNumVertices];
+ mGeneratedMesh->mNormals[pos] = nOut;
+ }
- 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<unsigned int>::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++;
- }
+ if (haveColor)
+ {
+ if (mGeneratedMesh->mColors[0] == NULL)
+ mGeneratedMesh->mColors[0] = new aiColor4D[mGeneratedMesh->mNumVertices];
+ mGeneratedMesh->mColors[0][pos] = cOut;
+ }
- }
- // add the mesh to the output list
- avOut->push_back(p_pcOut);
- }
+ if (haveTextureCoords)
+ {
+ if (mGeneratedMesh->mTextureCoords[0] == NULL)
+ {
+ mGeneratedMesh->mNumUVComponents[0] = 2;
+ mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
+ }
+ mGeneratedMesh->mTextureCoords[0][pos] = tOut;
}
- delete[] aiSplit; // cleanup
+ }
}
+
// ------------------------------------------------------------------------------------------------
-// Generate a default material if none was specified and apply it to all vanilla faces
-void PLYImporter::ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
- std::vector<aiMaterial*>* avMaterials)
+// Convert a color component to [0...1]
+ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val,
+ PLY::EDataType eType)
{
- bool bNeedDefaultMat = false;
+ 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;
+}
- for (std::vector<PLY::Face>::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;
- }
- }
+// ------------------------------------------------------------------------------------------------
+// Try to extract proper faces from the PLY DOM
+void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos)
+{
+ ai_assert(NULL != pcElement);
+ ai_assert(NULL != instElement);
- if (bNeedDefaultMat) {
- // generate a default material
- aiMaterial* pcHelper = new aiMaterial();
+ if (mGeneratedMesh == NULL)
+ throw DeadlyImportError("Invalid .ply file: Vertices shoud be declared before faces");
- // fill in a default material
- int iMode = (int)aiShadingMode_Gouraud;
- pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+ bool bOne = false;
- aiColor3D clr;
- clr.b = clr.g = clr.r = 0.6f;
- pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
- pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
+ // index of the vertex index list
+ unsigned int iProperty = 0xFFFFFFFF;
+ PLY::EDataType eType = EDT_Char;
+ bool bIsTriStrip = false;
- clr.b = clr.g = clr.r = 0.05f;
- pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
+ // index of the material index property
+ //unsigned int iMaterialIndex = 0xFFFFFFFF;
+ //PLY::EDataType eType2 = EDT_Char;
- // 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);
+ // texture coordinates
+ unsigned int iTextureCoord = 0xFFFFFFFF;
+ PLY::EDataType eType3 = EDT_Char;
- avMaterials->push_back(pcHelper);
+ // face = unique number of vertex indices
+ if (PLY::EEST_Face == pcElement->eSemantic)
+ {
+ unsigned int _a = 0;
+ for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+ a != pcElement->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;
+ }*/
+ else if (PLY::EST_TextureCoordinates == (*a).Semantic)
+ {
+ // must be a dynamic list!
+ if (!(*a).bIsList)
+ continue;
+ iTextureCoord = _a;
+ bOne = true;
+ eType3 = (*a).eType;
+ }
}
-}
-
-// ------------------------------------------------------------------------------------------------
-void PLYImporter::LoadTextureCoordinates(std::vector<aiVector2D>* 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<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
- i != pcDOM->alElements.end();++i,++_i)
+ }
+ // triangle strip
+ // TODO: triangle strip and material index support???
+ else if (PLY::EEST_TriStrip == pcElement->eSemantic)
+ {
+ unsigned int _a = 0;
+ for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+ a != pcElement->alProperties.end(); ++a, ++_a)
{
- if (PLY::EEST_Vertex == (*i).eSemantic)
- {
- pcList = &this->pcDOM->alElementData[_i];
+ // must be a dynamic list!
+ if (!(*a).bIsList)
+ continue;
+ iProperty = _a;
+ bOne = true;
+ bIsTriStrip = true;
+ eType = (*a).eType;
+ break;
+ }
+ }
- // now check whether which normal components are available
- unsigned int _a = 0;
- for (std::vector<PLY::Property>::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 at least one per-face information set
+ if (bOne)
+ {
+ if (mGeneratedMesh->mFaces == NULL)
+ {
+ mGeneratedMesh->mNumFaces = pcElement->NumOccur;
+ mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
}
- // check whether we have a valid source for the texture coordinates data
- if (NULL != pcList && 0 != cnt)
+
+ if (!bIsTriStrip)
{
- pvOut->reserve(pcList->alInstances.size());
- for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
- i != pcList->alInstances.end();++i)
- {
- // convert the vertices to sp floats
- aiVector2D vOut;
+ // 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];
- if (0xFFFFFFFF != aiPositions[0])
- {
- vOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
- GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]);
- }
+ std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
+ GetProperty(instElement->alProperties, iProperty).avList.begin();
- if (0xFFFFFFFF != aiPositions[1])
- {
- vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
- GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]);
- }
- // and add them to our nice list
- pvOut->push_back(vOut);
+ for (unsigned int a = 0; a < iNum; ++a, ++p)
+ {
+ mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p, eType);
}
- }
-}
+ }
-// ------------------------------------------------------------------------------------------------
-// Try to extract vertices from the PLY DOM
-void PLYImporter::LoadVertices(std::vector<aiVector3D>* pvOut, bool p_bNormals)
-{
- ai_assert(NULL != pvOut);
+ // parse the material index
+ // cannot be handled without processing the whole file first
+ /*if (0xFFFFFFFF != iMaterialIndex)
+ {
+ mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo<unsigned int>(
+ GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2);
+ }*/
- 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;
+ if (0xFFFFFFFF != iTextureCoord)
+ {
+ const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iTextureCoord).avList.size();
- // search in the DOM for a vertex entry
- unsigned int _i = 0;
- for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
- i != pcDOM->alElements.end();++i,++_i)
- {
- if (PLY::EEST_Vertex == (*i).eSemantic)
- {
- pcList = &pcDOM->alElementData[_i];
+ //should be 6 coords
+ std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
+ GetProperty(instElement->alProperties, iTextureCoord).avList.begin();
- // load normal vectors?
- if (p_bNormals)
- {
- // now check whether which normal components are available
- unsigned int _a = 0;
- for (std::vector<PLY::Property>::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
+ 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)
{
- // now check whether which coordinate sets are available
- unsigned int _a = 0;
- for (std::vector<PLY::Property>::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;
- }
+ 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<ai_real>(*p, eType3);
+ else
+ mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
+
+ mGeneratedMesh->mTextureCoords[0][vindex].z = 0;
}
- break;
+ }
}
+ }
}
- // check whether we have a valid source for the vertex data
- if (NULL != pcList && 0 != cnt)
+ else // triangle strips
{
- pvOut->reserve(pcList->alInstances.size());
- for (std::vector<ElementInstance>::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<ai_real>(
- GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]);
- }
+ // 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<PLY::PropertyInstance::ValueUnion>& 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<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin(); a != quak.end(); ++a) {
+ const int p = PLY::PropertyInstance::ConvertTo<int>(*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 (0xFFFFFFFF != aiPositions[1])
- {
- vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
- GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]);
- }
+ if (mGeneratedMesh->mFaces == NULL)
+ {
+ mGeneratedMesh->mNumFaces = pcElement->NumOccur;
+ mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
+ }
- if (0xFFFFFFFF != aiPositions[2])
- {
- vOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
- GetProperty((*i).alProperties, aiPositions[2]).avList.front(),aiTypes[2]);
- }
+ 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];
- // and add them to our nice list
- pvOut->push_back(vOut);
+ if ((flip = !flip)) {
+ std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]);
}
+
+ aiTable[0] = aiTable[1];
+ aiTable[1] = p;
+ }
}
+ }
}
// ------------------------------------------------------------------------------------------------
-// Convert a color component to [0...1]
-ai_real PLYImporter::NormalizeColorValue (PLY::PropertyInstance::ValueUnion val,
- PLY::EDataType eType)
+// Get a RGBA color in [0...1] range
+void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
+ unsigned int aiPositions[4],
+ PLY::EDataType aiTypes[4],
+ aiColor4D* clrOut)
{
- 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;
+ 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[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]);
+ }
+
+ // 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]);
+ }
}
// ------------------------------------------------------------------------------------------------
-// Try to extract proper vertex colors from the PLY DOM
-void PLYImporter::LoadVertexColor(std::vector<aiColor4D>* pvOut)
+// Extract a material from the PLY DOM
+void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &defaultTexture, const bool pointsOnly)
{
- 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<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
- i != pcDOM->alElements.end();++i,++_i)
+ ai_assert(NULL != pvOut);
+
+ // 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 },
+ };
+
+ 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 iOpacity = 0xFFFFFFFF;
+ PLY::EDataType eOpacity = EDT_Char;
+
+ // search in the DOM for a vertex entry
+ unsigned int _i = 0;
+ for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
+ i != this->pcDOM->alElements.end(); ++i, ++_i)
+ {
+ if (PLY::EEST_Material == (*i).eSemantic)
{
- 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<PLY::Property>::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<PLY::Property>::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;
+ iPhong = _a;
+ ePhong = (*a).eType;
}
- }
- // check whether we have a valid source for the vertex data
- if (NULL != pcList && 0 != cnt)
- {
- pvOut->reserve(pcList->alInstances.size());
- for (std::vector<ElementInstance>::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);
+ // general opacity -----------------------------------
+ if (PLY::EST_Opacity == (*a).Semantic)
+ {
+ iOpacity = _a;
+ eOpacity = (*a).eType;
}
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// Try to extract proper faces from the PLY DOM
-void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
-{
- ai_assert(NULL != pvOut);
- PLY::ElementInstanceList* pcList = NULL;
- bool bOne = false;
-
- // index of the vertex index list
- unsigned int iProperty = 0xFFFFFFFF;
- PLY::EDataType eType = EDT_Char;
- bool bIsTriStrip = false;
-
- // index of the material index property
- unsigned int iMaterialIndex = 0xFFFFFFFF;
- PLY::EDataType eType2 = EDT_Char;
-
- // search in the DOM for a face entry
- unsigned int _i = 0;
- for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
- i != pcDOM->alElements.end();++i,++_i)
- {
- // face = unique number of vertex indices
- if (PLY::EEST_Face == (*i).eSemantic)
+ // diffuse color channels -----------------------------------
+ if (PLY::EST_DiffuseRed == (*a).Semantic)
{
- pcList = &pcDOM->alElementData[_i];
- unsigned int _a = 0;
- for (std::vector<PLY::Property>::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;
+ aaiPositions[0][0] = _a;
+ aaiTypes[0][0] = (*a).eType;
}
- // triangle strip
- // TODO: triangle strip and material index support???
- else if (PLY::EEST_TriStrip == (*i).eSemantic)
+ else if (PLY::EST_DiffuseGreen == (*a).Semantic)
{
- // find a list property in this ...
- pcList = &this->pcDOM->alElementData[_i];
- unsigned int _a = 0;
- for (std::vector<PLY::Property>::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;
+ aaiPositions[0][1] = _a;
+ aaiTypes[0][1] = (*a).eType;
}
- }
- // check whether we have at least one per-face information set
- if (pcList && bOne)
- {
- if (!bIsTriStrip)
+ else if (PLY::EST_DiffuseBlue == (*a).Semantic)
{
- pvOut->reserve(pcList->alInstances.size());
- for (std::vector<ElementInstance>::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<PLY::PropertyInstance::ValueUnion>::const_iterator p =
- GetProperty((*i).alProperties, iProperty).avList.begin();
-
- for (unsigned int a = 0; a < iNum;++a,++p)
- {
- sFace.mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p,eType);
- }
- }
-
- // parse the material index
- if (0xFFFFFFFF != iMaterialIndex)
- {
- sFace.iMaterialIndex = PLY::PropertyInstance::ConvertTo<unsigned int>(
- GetProperty((*i).alProperties, iMaterialIndex).avList.front(),eType2);
- }
- pvOut->push_back(sFace);
- }
+ aaiPositions[0][2] = _a;
+ aaiTypes[0][2] = (*a).eType;
}
- else // triangle strips
+ else if (PLY::EST_DiffuseAlpha == (*a).Semantic)
{
- // 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<ElementInstance>::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) {
- const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty((*i).alProperties, iProperty).avList;
- pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u));
-
- int aiTable[2] = {-1,-1};
- for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin();a != quak.end();++a) {
- const int p = PLY::PropertyInstance::ConvertTo<int>(*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;
- }
- }
+ 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;
}
-}
-
-// ------------------------------------------------------------------------------------------------
-// Get a RGBA color in [0...1] range
-void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
- unsigned int aiPositions[4],
- PLY::EDataType aiTypes[4],
- aiColor4D* clrOut)
-{
- ai_assert(NULL != clrOut);
-
- if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
- else
+ else if (PLY::EEST_TextureFile == (*i).eSemantic)
{
- clrOut->r = NormalizeColorValue(GetProperty(avList,
- aiPositions[0]).avList.front(),aiTypes[0]);
+ defaultTexture = (*i).szName;
}
-
- if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
- else
- {
- clrOut->g = NormalizeColorValue(GetProperty(avList,
- aiPositions[1]).avList.front(),aiTypes[1]);
+ }
+ // check whether we have a valid source for the material data
+ if (NULL != pcList) {
+ for (std::vector<ElementInstance>::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<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE);
+
+ // build the specular material color
+ GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut);
+ pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR);
+
+ // build the ambient material color
+ GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut);
+ pcHelper->AddProperty<aiColor4D>(&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<ai_real>(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<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
+
+ iMode = (int)aiShadingMode_Phong;
+ }
+ }
+ pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+
+ // handle opacity
+ if (0xFFFFFFFF != iOpacity) {
+ ai_real fOpacity = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity);
+ pcHelper->AddProperty<ai_real>(&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);
}
-
- if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
- else
+ }
+ else
+ {
+ // generate a default material
+ aiMaterial* pcHelper = new aiMaterial();
+
+ // fill in a default material
+ int iMode = (int)aiShadingMode_Gouraud;
+ pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+
+ aiColor3D clr;
+ clr.b = clr.g = clr.r = 0.6f;
+ pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
+ pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
+
+ clr.b = clr.g = clr.r = 0.05f;
+ pcHelper->AddProperty<aiColor3D>(&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)
{
- clrOut->b = NormalizeColorValue(GetProperty(avList,
- aiPositions[2]).avList.front(),aiTypes[2]);
+ const int two_sided = 1;
+ pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
}
- // assume 1.0 for the alpha channel ifit is not set
- if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
- else
+ //default texture
+ if (!defaultTexture.empty())
{
- clrOut->a = NormalizeColorValue(GetProperty(avList,
- aiPositions[3]).avList.front(),aiTypes[3]);
+ const aiString name(defaultTexture.c_str());
+ pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
}
-}
-// ------------------------------------------------------------------------------------------------
-// Extract a material from the PLY DOM
-void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut)
-{
- ai_assert(NULL != pvOut);
-
- // 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},
- };
-
- 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 iOpacity = 0xFFFFFFFF;
- PLY::EDataType eOpacity = EDT_Char;
-
- // search in the DOM for a vertex entry
- unsigned int _i = 0;
- for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
- i != this->pcDOM->alElements.end();++i,++_i)
+ //set to wireframe, so when using this material info we can switch to points rendering
+ if (pointsOnly)
{
- 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<PLY::Property>::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;
- }
+ const int wireframe = 1;
+ pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
}
- // check whether we have a valid source for the material data
- if (NULL != pcList) {
- for (std::vector<ElementInstance>::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<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_DIFFUSE);
-
- // build the specular material color
- GetMaterialColor((*i).alProperties,aaiPositions[1],aaiTypes[1],&clrOut);
- pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_SPECULAR);
-
- // build the ambient material color
- GetMaterialColor((*i).alProperties,aaiPositions[2],aaiTypes[2],&clrOut);
- pcHelper->AddProperty<aiColor4D>(&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<ai_real>(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<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
-
- iMode = (int)aiShadingMode_Phong;
- }
- }
- pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
-
- // handle opacity
- if (0xFFFFFFFF != iOpacity) {
- ai_real fOpacity = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(),eOpacity);
- pcHelper->AddProperty<ai_real>(&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);
- }
- }
+ pvOut->push_back(pcHelper);
+ }
}
#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER
PLYImporter();
~PLYImporter();
-
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:
// -------------------------------------------------------------------
IOSystem* pIOHandler);
protected:
-
-
- // -------------------------------------------------------------------
- /** Extract vertices from the DOM
- */
- void LoadVertices(std::vector<aiVector3D>* pvOut,
- bool p_bNormals = false);
-
- // -------------------------------------------------------------------
- /** Extract vertex color channels from the DOM
- */
- void LoadVertexColor(std::vector<aiColor4D>* pvOut);
-
- // -------------------------------------------------------------------
- /** Extract texture coordinate channels from the DOM
- */
- void LoadTextureCoordinates(std::vector<aiVector2D>* pvOut);
-
- // -------------------------------------------------------------------
- /** Extract a face list from the DOM
- */
- void LoadFaces(std::vector<PLY::Face>* pvOut);
-
// -------------------------------------------------------------------
/** Extract a material list from the DOM
*/
- void LoadMaterial(std::vector<aiMaterial*>* pvOut);
-
-
- // -------------------------------------------------------------------
- /** Validate material indices, replace default material identifiers
- */
- void ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
- std::vector<aiMaterial*>* avMaterials);
-
-
- // -------------------------------------------------------------------
- /** Convert all meshes into our ourer representation
- */
- void ConvertMeshes(std::vector<PLY::Face>* avFaces,
- const std::vector<aiVector3D>* avPositions,
- const std::vector<aiVector3D>* avNormals,
- const std::vector<aiColor4D>* avColors,
- const std::vector<aiVector2D>* avTexCoords,
- const std::vector<aiMaterial*>* avMaterials,
- std::vector<aiMesh*>* avOut);
-
+ void LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &defaultTexture, const bool pointsOnly);
// -------------------------------------------------------------------
/** Static helper to parse a color from four single channels in
PLY::EDataType aiTypes[4],
aiColor4D* clrOut);
-
// -------------------------------------------------------------------
/** Static helper to parse a color channel value. The input value
* is normalized to 0-1.
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
Copyright (c) 2006-2017, assimp team
-
All rights reserved.
Redistribution and use of this software in source and binary forms,
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
#ifndef ASSIMP_BUILD_NO_PLY_IMPORTER
-#include "PlyLoader.h"
#include "fast_atof.h"
#include <assimp/DefaultLogger.hpp>
#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 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;
-
- return eOut;
+PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
+ ai_assert(!buffer.empty());
+
+ PLY::EDataType eOut = PLY::EDT_INVALID;
+
+ 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;
}
// ------------------------------------------------------------------------------------------------
-PLY::ESemantic PLY::Property::ParseSemantic(const char* pCur,const char** pCurOut) {
- ai_assert (NULL != pCur );
- ai_assert( NULL != pCurOut );
-
- 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 PLY::Property::ParseSemantic(std::vector<char> &buffer) {
+ ai_assert(!buffer.empty());
+
+ 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<char> &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;
+ // Forms supported:
+ // "property float x"
+ // "property list uchar int vertex_index"
- // skip leading spaces
- if (!SkipSpaces(pCur,&pCur)) {
- return false;
- }
+ // skip leading spaces
+ if (!PLY::DOM::SkipSpaces(buffer)) {
+ return false;
+ }
- // skip the "property" string at the beginning
- if (!TokenMatch(pCur,"property",8))
+ // 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;
+
+ // seems to be a list.
+ if (EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(buffer)))
{
- // seems not to be a valid property entry
- return false;
+ // unable to parse list size data type
+ PLY::DOM::SkipLine(buffer);
+ return false;
}
- // get next word
- if (!SkipSpaces(pCur,&pCur)) {
- return false;
- }
- if (TokenMatch(pCur,"list",4))
+ if (!PLY::DOM::SkipSpaces(buffer))return false;
+ if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer)))
{
- 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
+ // unable to parse list data type
+ PLY::DOM::SkipLine(buffer);
+ return false;
+ }
+ }
+ else
+ {
+ if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer)))
{
- 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;
- }
+ // unable to parse data type. Skip the property
+ PLY::DOM::SkipLine(buffer);
+ 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;
+ if (!PLY::DOM::SkipSpaces(buffer))
+ return false;
- DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK");
- pOut->szName = std::string(szCur,iDiff);
- }
+ pOut->Semantic = PLY::Property::ParseSemantic(buffer);
- SkipSpacesAndLineEnd(pCur,&pCur);
- *pCurOut = pCur;
+ 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]));
+ }
- return true;
+ PLY::DOM::SkipSpacesAndLineEnd(buffer);
+ return true;
}
// ------------------------------------------------------------------------------------------------
-PLY::EElementSemantic PLY::Element::ParseSemantic(const char* pCur,
- const char** pCurOut)
+PLY::EElementSemantic PLY::Element::ParseSemantic(std::vector<char> &buffer)
{
- 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;
- }
+ ai_assert(!buffer.empty());
+
+ 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 (TokenMatch(pCur,"range_grid",10))
- {
- eOut = PLY::EEST_Face;
- }
+ // TODO: maybe implement this?
+ else if (PLY::DOM::TokenMatch(buffer,"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;
+ 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;
+ }
+
+ return eOut;
}
// ------------------------------------------------------------------------------------------------
-bool PLY::Element::ParseElement (const char* pCur,
- const char** pCurOut,
- PLY::Element* pOut)
+bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLY::Element* pOut)
{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
- ai_assert( NULL != pOut );
+ ai_assert(NULL != pOut);
+ // Example format: "element vertex 8"
- // Example format: "element vertex 8"
- *pCurOut = pCur;
+ // skip leading spaces
+ if (!PLY::DOM::SkipSpaces(buffer))
+ {
+ return false;
+ }
- // skip leading spaces
- if (!SkipSpaces(&pCur)) {
- 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;
- // 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
+ 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]));
+ }
- // 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 (!PLY::DOM::SkipSpaces(buffer))
+ return false;
- if (!SkipSpaces(&pCur))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
- pOut->NumOccur = strtoul10(pCur,&pCur);
+ //parse the number of occurrences of this element
+ const char* pCur = (char*)&buffer[0];
+ pOut->NumOccur = strtoul10(pCur, &pCur);
- // go to the next line
- SkipSpacesAndLineEnd(pCur,&pCur);
+ // go to the next line
+ PLY::DOM::SkipSpacesAndLineEnd(buffer);
- // now parse all properties of the element
- while(true)
- {
- // skip all comments
- PLY::DOM::SkipComments(pCur,&pCur);
+ // now parse all properties of the element
+ while (true)
+ {
+ streamBuffer.getNextDataLine(buffer, '\\');
+ pCur = (char*)&buffer[0];
- PLY::Property prop;
- if(!PLY::Property::ParseProperty(pCur,&pCur,&prop))break;
- pOut->alProperties.push_back(prop);
- }
- *pCurOut = pCur;
+ // skip all comments
+ PLY::DOM::SkipComments(buffer);
- return true;
-}
+ PLY::Property prop;
+ if (!PLY::Property::ParseProperty(buffer, &prop))
+ break;
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::SkipComments (const char* pCur,
- const char** pCurOut)
-{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
- *pCurOut = pCur;
+ pOut->alProperties.push_back(prop);
+ }
- // 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;
-
- return false;
+ return true;
}
// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut,bool isBinary) {
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
+bool PLY::DOM::SkipSpaces(std::vector<char> &buffer)
+{
+ const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+ bool ret = false;
+ if (pCur)
+ {
+ const char* szCur = pCur;
+ ret = Assimp::SkipSpaces(pCur, &pCur);
- DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin");
+ uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+ buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+ return ret;
+ }
- // after ply and format line
- *pCurOut = pCur;
+ return ret;
+}
- // parse all elements
- while ((*pCur) != '\0')
- {
- // skip all comments
- PLY::DOM::SkipComments(pCur,&pCur);
+bool PLY::DOM::SkipLine(std::vector<char> &buffer)
+{
+ const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+ bool ret = false;
+ if (pCur)
+ {
+ const char* szCur = pCur;
+ ret = Assimp::SkipLine(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);
- }
- }
- if(!isBinary)
- { // it would occur an error, if binary data start with values as space or line end.
- SkipSpacesAndLineEnd(pCur,&pCur);
- }
- *pCurOut = pCur;
+ uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+ buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+ return ret;
+ }
- DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded");
- return true;
+ return ret;
}
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseElementInstanceLists (
- const char* pCur,
- const char** pCurOut)
+bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char* token, unsigned int len)
{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
+ const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+ bool ret = false;
+ if (pCur)
+ {
+ const char* szCur = pCur;
+ ret = Assimp::TokenMatch(pCur, token, len);
- DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin");
- *pCurOut = pCur;
+ uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+ buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+ return ret;
+ }
- alElementData.resize(alElements.size());
+ return ret;
+}
- std::vector<PLY::Element>::const_iterator i = alElements.begin();
- std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer)
+{
+ const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+ bool ret = false;
+ if (pCur)
+ {
+ const char* szCur = pCur;
+ ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur);
- // parse all element instances
- for (;i != alElements.end();++i,++a)
- {
- (*a).alInstances.resize((*i).NumOccur);
- PLY::ElementInstanceList::ParseInstanceList(pCur,&pCur,&(*i),&(*a));
- }
+ uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+ buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+ return ret;
+ }
- DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded");
- *pCurOut = pCur;
- return true;
+ return ret;
}
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseElementInstanceListsBinary (
- const char* pCur,
- const char** pCurOut,
- bool p_bBE)
+bool PLY::DOM::SkipComments(std::vector<char> &buffer)
{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut);
+ ai_assert(!buffer.empty());
- DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin");
- *pCurOut = pCur;
-
- alElementData.resize(alElements.size());
+ std::vector<char> nbuffer = buffer;
+ // skip spaces
+ if (!SkipSpaces(nbuffer)) {
+ return false;
+ }
- std::vector<PLY::Element>::const_iterator i = alElements.begin();
- std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+ if (TokenMatch(nbuffer, "comment", 7))
+ {
+ if (!SkipSpaces(nbuffer))
+ SkipLine(nbuffer);
- // parse all element instances
- for (;i != alElements.end();++i,++a)
+ if (!TokenMatch(nbuffer, "TextureFile", 11))
{
- (*a).alInstances.resize((*i).NumOccur);
- PLY::ElementInstanceList::ParseInstanceListBinary(pCur,&pCur,&(*i),&(*a),p_bBE);
+ SkipLine(nbuffer);
+ buffer = nbuffer;
+ return true;
}
- DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded");
- *pCurOut = pCur;
return true;
+ }
+
+ return false;
}
// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseInstanceBinary (const char* pCur,DOM* p_pcOut,bool p_bBE)
-{
- ai_assert( NULL != pCur );
- ai_assert( NULL != p_pcOut );
+bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, bool isBinary) {
+ DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin");
- DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin");
+ // parse all elements
+ while (!buffer.empty())
+ {
+ // skip all comments
+ PLY::DOM::SkipComments(buffer);
- if(!p_pcOut->ParseHeader(pCur,&pCur,true))
+ PLY::Element out;
+ if (PLY::Element::ParseElement(streamBuffer, buffer, &out))
{
- DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
- return false;
+ // add the element to the list of elements
+ alElements.push_back(out);
}
- if(!p_pcOut->ParseElementInstanceListsBinary(pCur,&pCur,p_bBE))
+ else if (TokenMatch(buffer, "end_header", 10))
{
- DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
- return false;
+ // we have reached the end of the header
+ break;
}
- DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded");
- return true;
+ 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::ParseInstance (const char* pCur,DOM* p_pcOut)
+bool PLY::DOM::ParseElementInstanceLists(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLYImporter* loader)
{
- ai_assert(NULL != pCur);
- ai_assert(NULL != p_pcOut);
+ DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin");
+ alElementData.resize(alElements.size());
- DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin");
+ std::vector<PLY::Element>::const_iterator i = alElements.begin();
+ std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
-
- if(!p_pcOut->ParseHeader(pCur,&pCur,false))
+ // 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)
{
- DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
- return false;
+ PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), NULL, loader);
}
- if(!p_pcOut->ParseElementInstanceLists(pCur,&pCur))
+ else
{
- DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
- return false;
+ (*a).alInstances.resize((*i).NumOccur);
+ PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), &(*a), NULL);
}
- DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded");
- return true;
+ }
+
+ DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded");
+ return true;
}
// ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstanceList::ParseInstanceList (
- const char* pCur,
- const char** pCurOut,
- const PLY::Element* pcElement,
- PLY::ElementInstanceList* p_pcOut)
+bool PLY::DOM::ParseElementInstanceListsBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+ const char* &pCur,
+ unsigned int &bufferSize,
+ PLYImporter* loader,
+ bool p_bBE)
{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
- ai_assert( NULL != pcElement );
- ai_assert( NULL != p_pcOut );
+ DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin");
+ alElementData.resize(alElements.size());
- if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty())
+ std::vector<PLY::Element>::const_iterator i = alElements.begin();
+ std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+
+ // parse all element instances
+ for (; i != alElements.end(); ++i, ++a)
+ {
+ if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip)
{
- // 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;
-}
+ }
-// ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstanceList::ParseInstanceListBinary (
- const char* pCur,
- const char** pCurOut,
- const PLY::Element* pcElement,
- PLY::ElementInstanceList* p_pcOut,
- bool p_bBE /* = false */)
-{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
- ai_assert( NULL != pcElement );
- ai_assert( NULL != p_pcOut );
-
- // 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;
+ DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded");
+ return true;
}
// ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstance::ParseInstance (
- const char* pCur,
- const char** pCurOut,
- const PLY::Element* pcElement,
- PLY::ElementInstance* p_pcOut)
+bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer<char> &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);
- if (!SkipSpaces(pCur, &pCur)) {
- return false;
- }
-
- // allocate enough storage
- p_pcOut->alProperties.resize(pcElement->alProperties.size());
-
- std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
- std::vector<PLY::Property>::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");
+ std::vector<char> buffer;
+ streamBuffer.getNextDataLine(buffer, '\\');
- // skip the rest of the instance
- SkipLine(pCur, &pCur);
+ DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin");
- PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType);
- (*i).avList.push_back(v);
- }
- }
- *pCurOut = pCur;
- return true;
+ 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::ParseInstanceBinary (
- const char* pCur,
- const char** pCurOut,
- const PLY::Element* pcElement,
- PLY::ElementInstance* p_pcOut,
- bool p_bBE /* = false */)
+bool PLY::DOM::ParseInstance(IOStreamBuffer<char> &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);
- // allocate enough storage
- p_pcOut->alProperties.resize(pcElement->alProperties.size());
+ std::vector<char> buffer;
+ streamBuffer.getNextDataLine(buffer, '\\');
- std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
- std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
- for (;i != p_pcOut->alProperties.end();++i,++a)
- {
- if(!(PLY::PropertyInstance::ParseInstanceBinary(pCur, &pCur,&(*a),&(*i),p_bBE)))
- {
- DefaultLogger::get()->warn("Unable to parse binary property instance. "
- "Skipping this element instance");
+ DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin");
- (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType));
- }
- }
- *pCurOut = pCur;
- return true;
+ if (!p_pcOut->ParseHeader(streamBuffer, buffer, false))
+ {
+ DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
+ return false;
+ }
+
+ //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::PropertyInstance::ParseInstance (const char* pCur,const char** pCurOut,
- const PLY::Property* prop, PLY::PropertyInstance* p_pcOut)
+bool PLY::ElementInstanceList::ParseInstanceList(
+ IOStreamBuffer<char> &streamBuffer,
+ std::vector<char> &buffer,
+ const PLY::Element* pcElement,
+ PLY::ElementInstanceList* p_pcOut,
+ PLYImporter* loader)
{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
- ai_assert( NULL != prop );
- ai_assert( NULL != p_pcOut );
-
- *pCurOut = pCur;
-
- // skip spaces at the beginning
- if (!SkipSpaces(pCur, &pCur)) {
- return false;
- }
-
- if (prop->bIsList)
+ ai_assert(NULL != pcElement);
+ const char* pCur = (const char*)&buffer[0];
+
+ // 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)
{
- // 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<unsigned int>(v,prop->eFirstType);
-
- // parse all list elements
- p_pcOut->avList.resize(iNum);
- for (unsigned int i = 0; i < iNum;++i)
+ PLY::DOM::SkipComments(buffer);
+ PLY::DOM::SkipLine(buffer);
+ streamBuffer.getNextDataLine(buffer, '\\');
+ pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0];
+ }
+ }
+ 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)
{
- if (!SkipSpaces(pCur, &pCur))return false;
- PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&p_pcOut->avList[i]);
+ //call loader instance from here
+ loader->LoadVertex(pcElement, &elt, i);
}
- }
- else
- {
- // parse the property
- PLY::PropertyInstance::ValueUnion v;
+ 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);
+ }
+ }
- PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&v);
- p_pcOut->avList.push_back(v);
+ streamBuffer.getNextDataLine(buffer, '\\');
+ pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0];
}
- 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::ElementInstanceList::ParseInstanceListBinary(
+ IOStreamBuffer<char> &streamBuffer,
+ std::vector<char> &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 );
-
- if (prop->bIsList)
- {
- // parse the number of elements in the list
- PLY::PropertyInstance::ValueUnion v;
- PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eFirstType,&v,p_bBE);
-
- // convert to unsigned int
- unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(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);
- }
- }
+ ai_assert(NULL != pcElement);
+
+ // 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;
- PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&v,p_bBE);
- p_pcOut->avList.push_back(v);
- }
- *pCurOut = pCur;
- return true;
+ ElementInstance elt;
+ PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &elt, p_bBE);
+
+ // 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);
+ }
+ }
+ }
+ return true;
}
// ------------------------------------------------------------------------------------------------
-PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue( PLY::EDataType eType )
+bool PLY::ElementInstance::ParseInstance(const char* &pCur,
+ const PLY::Element* pcElement,
+ PLY::ElementInstance* p_pcOut)
{
- PLY::PropertyInstance::ValueUnion out;
+ ai_assert(NULL != pcElement);
+ ai_assert(NULL != p_pcOut);
- switch (eType)
- {
- case EDT_Float:
- out.fFloat = 0.f;
- return out;
+ // allocate enough storage
+ p_pcOut->alProperties.resize(pcElement->alProperties.size());
- case EDT_Double:
- out.fDouble = 0.;
- return out;
+ std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
+ std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+ for (; i != p_pcOut->alProperties.end(); ++i, ++a)
+ {
+ if (!(PLY::PropertyInstance::ParseInstance(pCur, &(*a), &(*i))))
+ {
+ DefaultLogger::get()->warn("Unable to parse property instance. "
+ "Skipping this element instance");
- default: ;
- };
- out.iUInt = 0;
- return out;
+ PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType);
+ (*i).avList.push_back(v);
+ }
+ }
+ return true;
}
// ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseValue(
- const char* pCur,
- const char** pCurOut,
- PLY::EDataType eType,
- PLY::PropertyInstance::ValueUnion* out)
+bool PLY::ElementInstance::ParseInstanceBinary(
+ IOStreamBuffer<char> &streamBuffer,
+ std::vector<char> &buffer,
+ const char* &pCur,
+ unsigned int &bufferSize,
+ const PLY::Element* pcElement,
+ PLY::ElementInstance* p_pcOut,
+ bool p_bBE /* = false */)
{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
- ai_assert( NULL != out );
+ ai_assert(NULL != pcElement);
+ ai_assert(NULL != p_pcOut);
+
+ // allocate enough storage
+ p_pcOut->alProperties.resize(pcElement->alProperties.size());
- bool ret = true;
- *pCurOut = pCur;
- switch (eType)
+ std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
+ std::vector<PLY::Property>::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_UInt:
- case EDT_UShort:
- case EDT_UChar:
-
- out->iUInt = (uint32_t)strtoul10(pCur, &pCur);
- break;
-
- case EDT_Int:
- case EDT_Short:
- case EDT_Char:
-
- out->iInt = (int32_t)strtol10(pCur, &pCur);
- break;
-
- 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<ai_real>(pCur,f);
- out->fFloat = (ai_real)f;
- break;
-
- case EDT_Double:
- double d;
- pCur = fast_atoreal_move<double>(pCur,d);
- out->fDouble = (double)d;
- break;
-
- default:
- ret = false;
- break;
- }
- *pCurOut = pCur;
+ DefaultLogger::get()->warn("Unable to parse binary property instance. "
+ "Skipping this element instance");
- return ret;
+ (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType));
+ }
+ }
+ return true;
}
// ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseValueBinary(
- const char* pCur,
- const char** pCurOut,
- PLY::EDataType eType,
- PLY::PropertyInstance::ValueUnion* out,
- bool p_bBE)
+bool PLY::PropertyInstance::ParseInstance(const char* &pCur,
+ const PLY::Property* prop, PLY::PropertyInstance* p_pcOut)
{
- ai_assert( NULL != pCur );
- ai_assert( NULL != pCurOut );
- ai_assert( NULL != out );
+ ai_assert(NULL != prop);
+ ai_assert(NULL != p_pcOut);
- bool ret = true;
- switch (eType)
- {
- case EDT_UInt:
- out->iUInt = (uint32_t)*((uint32_t*)pCur);
- pCur += 4;
+ // skip spaces at the beginning
+ if (!SkipSpaces(&pCur))
+ {
+ return false;
+ }
- // Swap endianness
- if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt);
- break;
+ if (prop->bIsList)
+ {
+ // parse the number of elements in the list
+ PLY::PropertyInstance::ValueUnion v;
+ PLY::PropertyInstance::ParseValue(pCur, prop->eFirstType, &v);
- case EDT_UShort:
- {
- uint16_t i = *((uint16_t*)pCur);
+ // convert to unsigned int
+ unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v, prop->eFirstType);
- // Swap endianness
- if (p_bBE)ByteSwap::Swap(&i);
- out->iUInt = (uint32_t)i;
- pCur += 2;
- break;
- }
+ // parse all list elements
+ p_pcOut->avList.resize(iNum);
+ for (unsigned int i = 0; i < iNum; ++i)
+ {
+ if (!SkipSpaces(&pCur))
+ return false;
- case EDT_UChar:
- {
- out->iUInt = (uint32_t)(*((uint8_t*)pCur));
- pCur ++;
- break;
- }
+ PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]);
+ }
+ }
+ else
+ {
+ // parse the property
+ PLY::PropertyInstance::ValueUnion v;
- case EDT_Int:
- out->iInt = *((int32_t*)pCur);
- pCur += 4;
+ PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v);
+ p_pcOut->avList.push_back(v);
+ }
+ SkipSpacesAndLineEnd(&pCur);
+ return true;
+}
- // Swap endianness
- if (p_bBE)ByteSwap::Swap(&out->iInt);
- break;
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &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<unsigned int>(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;
+}
- case EDT_Short:
- {
- int16_t i = *((int16_t*)pCur);
+// ------------------------------------------------------------------------------------------------
+PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue(PLY::EDataType eType)
+{
+ PLY::PropertyInstance::ValueUnion out;
- // Swap endianness
- if (p_bBE)ByteSwap::Swap(&i);
- out->iInt = (int32_t)i;
- pCur += 2;
- break;
- }
+ switch (eType)
+ {
+ case EDT_Float:
+ out.fFloat = 0.f;
+ return out;
- case EDT_Char:
- out->iInt = (int32_t)*((int8_t*)pCur);
- pCur ++;
- break;
+ case EDT_Double:
+ out.fDouble = 0.;
+ return out;
- case EDT_Float:
- {
- out->fFloat = *((float*)pCur);
+ default:;
+ };
+ out.iUInt = 0;
+ return out;
+}
- // Swap endianness
- if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat);
- pCur += 4;
- break;
- }
- case EDT_Double:
- {
- out->fDouble = *((double*)pCur);
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseValue(const char* &pCur,
+ PLY::EDataType eType,
+ PLY::PropertyInstance::ValueUnion* 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;
+
+ 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;
+ }
+
+ bool ret = true;
+ switch (eType)
+ {
+ case EDT_UInt:
+ case EDT_UShort:
+ case EDT_UChar:
+
+ out->iUInt = (uint32_t)strtoul10(pCur, &pCur);
+ break;
+
+ case EDT_Int:
+ case EDT_Short:
+ case EDT_Char:
+
+ out->iInt = (int32_t)strtol10(pCur, &pCur);
+ break;
+
+ 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<ai_real>(pCur, f);
+ out->fFloat = (ai_real)f;
+ break;
+
+ case EDT_Double:
+ double d;
+ pCur = fast_atoreal_move<double>(pCur, d);
+ out->fDouble = (double)d;
+ break;
+
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
- // Swap endianness
- if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble);
- pCur += 8;
- break;
- }
- default:
- ret = false;
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
+ std::vector<char> &buffer,
+ const char* &pCur,
+ unsigned int &bufferSize,
+ PLY::EDataType eType,
+ PLY::PropertyInstance::ValueUnion* out,
+ bool p_bBE)
+{
+ ai_assert(NULL != out);
+
+ //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<char> nbuffer;
+ if (streamBuffer.getNextBlock(nbuffer))
+ {
+ //concat buffer contents
+ buffer = std::vector<char>(buffer.end() - bufferSize, buffer.end());
+ buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end());
+ nbuffer.clear();
+ bufferSize = buffer.size();
+ pCur = (char*)&buffer[0];
}
- *pCurOut = pCur;
-
- return ret;
+ else
+ {
+ throw DeadlyImportError("Invalid .ply file: File corrupted");
+ }
+ }
+
+ 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
----------------------------------------------------------------------
Copyright (c) 2006-2017, assimp team
-
All rights reserved.
Redistribution and use of this software in source and binary forms,
#include "ParsingUtils.h"
+#include "IOStreamBuffer.h"
#include <vector>
-
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
//! The element is a material description
EEST_Material,
+ //! texture path
+ EEST_TextureFile,
+
//! Marks invalid entries
EEST_INVALID
};
//! 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<char> &buffer, Property* pOut);
// -------------------------------------------------------------------
//! Parse a data type from a string
- static EDataType ParseDataType(const char* pCur,const char** pCurOut);
+ static EDataType ParseDataType(std::vector<char> &buffer);
// -------------------------------------------------------------------
//! Parse a semantic from a string
- static ESemantic ParseSemantic(const char* pCur,const char** pCurOut);
+ static ESemantic ParseSemantic(std::vector<char> &buffer);
};
// ---------------------------------------------------------------------------------
//! 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<char> &streamBuffer, std::vector<char> &buffer, Element* pOut);
// -------------------------------------------------------------------
//! Parse a semantic from a string
- static EElementSemantic ParseSemantic(const char* pCur,
- const char** pCurOut);
+ static EElementSemantic ParseSemantic(std::vector<char> &buffer);
};
// ---------------------------------------------------------------------------------
// -------------------------------------------------------------------
//! 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<char> &streamBuffer, std::vector<char> &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
// -------------------------------------------------------------------
//! 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<char> &streamBuffer, std::vector<char> &buffer,
+ const char* &pCur, unsigned int &bufferSize, EDataType eType, ValueUnion* out, bool p_bBE);
// -------------------------------------------------------------------
//! Convert a property value to a given type TYPE
// -------------------------------------------------------------------
//! 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<char> &streamBuffer, std::vector<char> &buffer,
+ const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstance* p_pcOut, bool p_bBE);
};
// ---------------------------------------------------------------------------------
// -------------------------------------------------------------------
//! Parse an element instance list
- static bool ParseInstanceList (const char* pCur,const char** pCurOut,
- const Element* pcElement, ElementInstanceList* p_pcOut);
+ static bool ParseInstanceList(IOStreamBuffer<char> &streamBuffer, std::vector<char> &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<char> &streamBuffer, std::vector<char> &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
//! 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<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader);
+ static bool ParseInstanceBinary(IOStreamBuffer<char> &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<char> &buffer);
+
+ static bool SkipSpaces(std::vector<char> &buffer);
+
+ static bool SkipLine(std::vector<char> &buffer);
+
+ static bool TokenMatch(std::vector<char> &buffer, const char* token, unsigned int len);
+
+ static bool SkipSpacesAndLineEnd(std::vector<char> &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<char> &streamBuffer, std::vector<char> &buffer, bool p_bBE);
// -------------------------------------------------------------------
//! Read in all element instance lists
- bool ParseElementInstanceLists (const char* pCur,const char** pCurOut);
+ bool ParseElementInstanceLists(IOStreamBuffer<char> &streamBuffer, std::vector<char> &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<unsigned int> mIndices;
-
- //! Material index
- unsigned int iMaterialIndex;
+ bool ParseElementInstanceListsBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, const char* &pCur, unsigned int &bufferSize, PLYImporter* loader, bool p_bBE);
};
// ---------------------------------------------------------------------------------
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;
-/*
+/*
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
points_[0]=points_[1]=points_[2] = NULL;
}
-void Triangle::ClearNeighbor(Triangle *triangle )
+void Triangle::ClearNeighbor(const Triangle *triangle )
{
if( neighbors_[0] == triangle )
{
}
else if( neighbors_[1] == triangle )
{
- neighbors_[1] = NULL;
+ neighbors_[1] = NULL;
}
else
{
neighbors_[2] = NULL;
}
}
-
+
void Triangle::ClearNeighbors()
{
neighbors_[0] = NULL;
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);
}
return 2;
}
assert(0);
-
- return 0;
+ return -1;
}
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;
}
}
// 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];
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];
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];
}
// 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];
return neighbors_[1];
}
-bool Triangle::GetConstrainedEdgeCCW(Point& p)
+bool Triangle::GetConstrainedEdgeCCW(const Point& p)
{
if (&p == points_[0]) {
return constrained_edge[2];
return constrained_edge[1];
}
-bool Triangle::GetConstrainedEdgeCW(Point& p)
+bool Triangle::GetConstrainedEdgeCW(const Point& p)
{
if (&p == points_[0]) {
return constrained_edge[1];
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;
}
}
-void Triangle::SetConstrainedEdgeCW(Point& p, bool ce)
+void Triangle::SetConstrainedEdgeCW(const Point& p, bool ce)
{
if (&p == points_[0]) {
constrained_edge[1] = ce;
}
}
-bool Triangle::GetDelunayEdgeCCW(Point& p)
+bool Triangle::GetDelunayEdgeCCW(const Point& p)
{
if (&p == points_[0]) {
return delaunay_edge[2];
return delaunay_edge[1];
}
-bool Triangle::GetDelunayEdgeCW(Point& p)
+bool Triangle::GetDelunayEdgeCW(const Point& p)
{
if (&p == points_[0]) {
return delaunay_edge[1];
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;
}
}
-void Triangle::SetDelunayEdgeCW(Point& p, bool e)
+void Triangle::SetDelunayEdgeCW(const Point& p, bool e)
{
if (&p == points_[0]) {
delaunay_edge[1] = 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];
cout << points_[2]->x << "," << points_[2]->y << endl;
}
-}
-
+}
\ No newline at end of file
/// 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;
/// 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);
-
-bool Contains(Point* p);
+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(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();
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.
/// 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];
}
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);
}
}
-#endif
-
-
+#endif
\ No newline at end of file
-/*
+/*
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
* 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 <exception>
+#include <math.h>
+
+// 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 };
* = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
* </pre>
*/
-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);
return CW;
}
+/*
bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd)
{
double pdx = pd.x;
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
+}
+#endif
-/*
+/*
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
#include "common/shapes.h"
#include "sweep/cdt.h"
-#endif
-
+#endif
\ No newline at end of file
search_node_ = &head;
}
-Node* AdvancingFront::LocateNode(const double& x)
+Node* AdvancingFront::LocateNode(double x)
{
Node* node = search_node_;
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
{
}
-}
-
+}
\ No newline at end of file
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);
Node* head_, *tail_, *search_node_;
-Node* FindSearchNode(const double& x);
+Node* FindSearchNode(double x);
};
inline Node* AdvancingFront::head()
}
-#endif
+#endif
\ No newline at end of file
-/*
+/*
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
namespace p2t {
-CDT::CDT(std::vector<Point*> polyline)
+CDT::CDT(const std::vector<Point*>& polyline)
{
sweep_context_ = new SweepContext(polyline);
sweep_ = new Sweep;
}
-void CDT::AddHole(std::vector<Point*> polyline)
+void CDT::AddHole(const std::vector<Point*>& polyline)
{
sweep_context_->AddHole(polyline);
}
delete sweep_;
}
-}
-
+}
\ No newline at end of file
-/*
+/*
* Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
* 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
#include "sweep.h"
/**
- *
+ *
* @author Mason Green <mason.green@gmail.com>
*
*/
-
+
namespace p2t {
class CDT
/**
* Constructor - add polyline with non repeating points
- *
+ *
* @param polyline
*/
- CDT(std::vector<Point*> polyline);
-
+ CDT(const std::vector<Point*>& polyline);
+
/**
* Destructor - clean up memory
*/
~CDT();
-
+
/**
* Add a hole
- *
+ *
* @param polyline
*/
- void AddHole(std::vector<Point*> polyline);
-
+ void AddHole(const std::vector<Point*>& 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<Triangle*> GetTriangles();
-
+
/**
* Get triangle map
*/
/**
* Internals
*/
-
+
SweepContext* sweep_context_;
Sweep* sweep_;
}
-#endif
+#endif
\ No newline at end of file
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++) {
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);
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);
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);
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;
}
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
* 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);
}
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);
} 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,
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];
}
* 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
struct Edge;
class Triangle;
-class Sweep
+class Sweep
{
public:
/**
* Triangulate
- *
+ *
* @param tcx
*/
void Triangulate(SweepContext& tcx);
-
+
/**
* Destructor - clean up memory
*/
/**
* Start sweeping the Y-sorted point set from bottom to top
- *
+ *
* @param tcx
*/
void SweepPoints(SweepContext& tcx);
Node& PointEvent(SweepContext& tcx, Point& point);
/**
- *
- *
+ *
+ *
* @param tcx
* @param edge
* @param node
/**
* Creates a new front triangle and legalize it
- *
+ *
* @param tcx
* @param point
* @param node
* @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
* n4 n4
* </pre>
*/
- 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
*/
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
/**
* 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
/**
* Scan part of the FlipScan algorithm<br>
- * 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
}
-#endif
+#endif
\ No newline at end of file
namespace p2t {
-SweepContext::SweepContext(std::vector<Point*> polyline)
+SweepContext::SweepContext(const std::vector<Point*>& 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<Point*> polyline)
+void SweepContext::AddHole(const std::vector<Point*>& polyline)
{
InitEdges(polyline);
for(unsigned int i = 0; i < polyline.size(); i++) {
points_.push_back(point);
}
-std::vector<Triangle*> SweepContext::GetTriangles()
+std::vector<Triangle*> &SweepContext::GetTriangles()
{
return triangles_;
}
-std::list<Triangle*> SweepContext::GetMap()
+std::list<Triangle*> &SweepContext::GetMap()
{
return map_;
}
}
-void SweepContext::InitEdges(std::vector<Point*> polyline)
+void SweepContext::InitEdges(const std::vector<Point*>& polyline)
{
- int num_points = static_cast<int>(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];
}
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<Node*> nodes)
+void SweepContext::CreateAdvancingFront(const std::vector<Node*>& nodes)
{
(void) nodes;
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<Triangle *> 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));
+ }
}
}
}
public:
/// Constructor
-SweepContext(std::vector<Point*> polyline);
+SweepContext(const std::vector<Point*>& 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<Node*> nodes);
+void CreateAdvancingFront(const std::vector<Node*>& 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<Point*> polyline);
+void AddHole(const std::vector<Point*>& polyline);
void AddPoint(Point* point);
-AdvancingFront* front();
+AdvancingFront* front() const;
void MeshClean(Triangle& triangle);
-std::vector<Triangle*> GetTriangles();
-std::list<Triangle*> GetMap();
+std::vector<Triangle*> &GetTriangles();
+std::list<Triangle*> &GetMap();
std::vector<Edge*> edge_list;
Node *af_head_, *af_middle_, *af_tail_;
void InitTriangulation();
-void InitEdges(std::vector<Point*> polyline);
+void InitEdges(const std::vector<Point*>& 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<int>(points_.size());
+ return points_.size();
}
inline void SweepContext::set_head(Point* p1)
head_ = p1;
}
-inline Point* SweepContext::head()
+inline Point* SweepContext::head() const
{
return head_;
}
tail_ = p1;
}
-inline Point* SweepContext::tail()
+inline Point* SweepContext::tail() const
{
return tail_;
}