diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index b9d7c4f2..1d5d18d2 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -33,8 +33,6 @@ SET(CORE_INC_FILES include/PolyVoxCore/Filters.inl include/PolyVoxCore/GradientEstimators.h include/PolyVoxCore/GradientEstimators.inl - include/PolyVoxCore/ImprovedCubicSurfaceExtractor.h - include/PolyVoxCore/ImprovedCubicSurfaceExtractor.inl include/PolyVoxCore/LargeVolume.h include/PolyVoxCore/LargeVolume.inl include/PolyVoxCore/LargeVolumeSampler.inl diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h index 7722de8e..1beb6cb2 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h @@ -32,26 +32,43 @@ freely, subject to the following restrictions: namespace PolyVox { - struct IndexAndMaterial - { - int32_t iIndex : 24; - int32_t uMaterial : 8; - }; - template< template class VolumeType, typename VoxelType> class CubicSurfaceExtractor { + struct IndexAndMaterial + { + int32_t iIndex; + int32_t uMaterial; //Should actually use the material type here, but this is ok for now. + }; + + enum FaceNames + { + PositiveX, + PositiveY, + PositiveZ, + NegativeX, + NegativeY, + NegativeZ, + NoOfFaces + }; + + struct Quad + { + uint32_t vertices[4]; + }; + public: - CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result); + CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, bool bMergeQuads = true); - void execute(); - - int32_t addVertex(float fX, float fY, float fZ, uint8_t uMaterial, Array<3, IndexAndMaterial>& existingVertices); + void execute(); private: + int32_t addVertex(float fX, float fY, float fZ, uint8_t uMaterial, Array<3, IndexAndMaterial>& existingVertices); + bool performQuadMerging(std::list& quads); + bool mergeQuads(Quad& q1, Quad& q2); + //The volume data and a sampler to access it. VolumeType* m_volData; - typename VolumeType::Sampler m_sampVolume; //Information about the region we are currently processing Region m_regSizeInVoxels; @@ -59,14 +76,22 @@ namespace PolyVox //The surface patch we are currently filling. SurfaceMesh* m_meshCurrent; - //Array<4, IndexAndMaterial> m_vertices; + //Used to avoid creating duplicate vertices. Array<3, IndexAndMaterial> m_previousSliceVertices; Array<3, IndexAndMaterial> m_currentSliceVertices; + //During extraction we create a number of different lists of quads. All the + //quads in a given list are in the same plane and facing in the same direction. + std::vector< std::list > m_vecQuads[NoOfFaces]; + + //Controls whether quad merging should be performed. This might be undesirable + //is the user needs per-vertex attributes, or to perform per vertex lighting. + bool m_bMergeQuads; + //Although we try to avoid creating multiple vertices at the same location, sometimes this is unavoidable //if they have different materials. For example, four different materials next to each other would mean //four quads (though more triangles) sharing the vertex. As far as I can tell, four is the worst case scenario. - static const uint32_t MaxQuadsSharingVertex; + static const uint32_t MaxQuadsSharingVertex; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl index 89615384..efc46652 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl @@ -33,11 +33,11 @@ namespace PolyVox const uint32_t CubicSurfaceExtractor::MaxQuadsSharingVertex = 4; template< template class VolumeType, typename VoxelType> - CubicSurfaceExtractor::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result) + CubicSurfaceExtractor::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, bool bMergeQuads) :m_volData(volData) - ,m_sampVolume(volData) ,m_regSizeInVoxels(region) ,m_meshCurrent(result) + ,m_bMergeQuads(bMergeQuads) { m_meshCurrent->clear(); } @@ -53,60 +53,81 @@ namespace PolyVox m_currentSliceVertices.resize(arraySize); memset(m_previousSliceVertices.getRawData(), 0xff, m_previousSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); - + + uint32_t uRegionWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; + uint32_t uRegionHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; + uint32_t uRegionDepth = m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 1; + + m_vecQuads[NegativeX].resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); + m_vecQuads[PositiveX].resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); + + m_vecQuads[NegativeY].resize(m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2); + m_vecQuads[PositiveY].resize(m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2); + + m_vecQuads[NegativeZ].resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2); + m_vecQuads[PositiveZ].resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2); + + VolumeType::Sampler volumeSampler(m_volData); + Quad quad; for(int32_t z = m_regSizeInVoxels.getLowerCorner().getZ(); z <= m_regSizeInVoxels.getUpperCorner().getZ() + 1; z++) { + uint32_t regZ = z - m_regSizeInVoxels.getLowerCorner().getZ(); + bool finalZ = (z == m_regSizeInVoxels.getUpperCorner().getZ() + 1); + for(int32_t y = m_regSizeInVoxels.getLowerCorner().getY(); y <= m_regSizeInVoxels.getUpperCorner().getY() + 1; y++) { + uint32_t regY = y - m_regSizeInVoxels.getLowerCorner().getY(); + bool finalY = (y == m_regSizeInVoxels.getUpperCorner().getY() + 1); + for(int32_t x = m_regSizeInVoxels.getLowerCorner().getX(); x <= m_regSizeInVoxels.getUpperCorner().getX() + 1; x++) { - // these are always positive anyway uint32_t regX = x - m_regSizeInVoxels.getLowerCorner().getX(); - uint32_t regY = y - m_regSizeInVoxels.getLowerCorner().getY(); - uint32_t regZ = z - m_regSizeInVoxels.getLowerCorner().getZ(); + bool finalX = (x == m_regSizeInVoxels.getUpperCorner().getX() + 1); - bool finalX = (x == m_regSizeInVoxels.getUpperCorner().getX() + 1); - bool finalY = (y == m_regSizeInVoxels.getUpperCorner().getY() + 1); - bool finalZ = (z == m_regSizeInVoxels.getUpperCorner().getZ() + 1); + volumeSampler.setPosition(x,y,z); - VoxelType currentVoxel = m_volData->getVoxelAt(x,y,z); + VoxelType currentVoxel = volumeSampler.getVoxel(); bool currentVoxelIsSolid = currentVoxel.getDensity() >= VoxelType::getThreshold(); - VoxelType negXVoxel = m_volData->getVoxelAt(x-1,y,z); + VoxelType negXVoxel = volumeSampler.peekVoxel1nx0py0pz(); bool negXVoxelIsSolid = negXVoxel.getDensity() >= VoxelType::getThreshold(); if((currentVoxelIsSolid != negXVoxelIsSolid) && (finalY == false) && (finalZ == false)) { int material = (std::max)(currentVoxel.getMaterial(), negXVoxel.getMaterial()); - /*uint32_t v0 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ - 0.5f), material)); - uint32_t v1 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), material)); - uint32_t v2 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), material)); - uint32_t v3 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), material));*/ - // Check to ensure that when a voxel solid/non-solid change is right on a region border, the vertices are generated on the solid side of the region border if(((currentVoxelIsSolid > negXVoxelIsSolid) && finalX == false) || ((currentVoxelIsSolid < negXVoxelIsSolid) && regX != 0)) { uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v2 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v3 = addVertex(regX - 0.5f, regY + 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v2 = addVertex(regX - 0.5f, regY + 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); if(currentVoxelIsSolid > negXVoxelIsSolid) - { - m_meshCurrent->addTriangleCubic(v0,v1,v2); - m_meshCurrent->addTriangleCubic(v1,v3,v2); + { + quad.vertices[0] = v0; + quad.vertices[1] = v1; + quad.vertices[2] = v2; + quad.vertices[3] = v3; + + m_vecQuads[NegativeX][regX].push_back(quad); } else { - m_meshCurrent->addTriangleCubic(v0,v2,v1); - m_meshCurrent->addTriangleCubic(v1,v2,v3); + quad.vertices[0] = v0; + quad.vertices[1] = v3; + quad.vertices[2] = v2; + quad.vertices[3] = v1; + + m_vecQuads[PositiveX][regX].push_back(quad); } + } } - VoxelType negYVoxel = m_volData->getVoxelAt(x,y-1,z); + VoxelType negYVoxel = volumeSampler.peekVoxel0px1ny0pz(); bool negYVoxelIsSolid = negYVoxel.getDensity() >= VoxelType::getThreshold(); if((currentVoxelIsSolid != negYVoxelIsSolid) && (finalX == false) && (finalZ == false)) @@ -116,24 +137,34 @@ namespace PolyVox if(((currentVoxelIsSolid > negYVoxelIsSolid) && finalY == false) || ((currentVoxelIsSolid < negYVoxelIsSolid) && regY != 0)) { uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v2 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v2 = addVertex(regX + 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); if(currentVoxelIsSolid > negYVoxelIsSolid) { - m_meshCurrent->addTriangleCubic(v0,v2,v1); - m_meshCurrent->addTriangleCubic(v1,v2,v3); + //NOTE: For some reason y windong is opposite of X and Z. Investigate this... + quad.vertices[0] = v0; + quad.vertices[1] = v3; + quad.vertices[2] = v2; + quad.vertices[3] = v1; + + m_vecQuads[NegativeY][regY].push_back(quad); } else { - m_meshCurrent->addTriangleCubic(v0,v1,v2); - m_meshCurrent->addTriangleCubic(v1,v3,v2); + //NOTE: For some reason y windong is opposite of X and Z. Investigate this... + quad.vertices[0] = v0; + quad.vertices[1] = v1; + quad.vertices[2] = v2; + quad.vertices[3] = v3; + + m_vecQuads[PositiveY][regY].push_back(quad); } } } - VoxelType negZVoxel = m_volData->getVoxelAt(x,y,z-1); + VoxelType negZVoxel = volumeSampler.peekVoxel0px0py1nz(); bool negZVoxelIsSolid = negZVoxel.getDensity() >= VoxelType::getThreshold(); if((currentVoxelIsSolid != negZVoxelIsSolid) && (finalX == false) && (finalY == false)) @@ -144,18 +175,26 @@ namespace PolyVox { uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); uint32_t v1 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v3 = addVertex(regX + 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(regX + 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); if(currentVoxelIsSolid > negZVoxelIsSolid) { - m_meshCurrent->addTriangleCubic(v0,v1,v2); - m_meshCurrent->addTriangleCubic(v1,v3,v2); + quad.vertices[0] = v0; + quad.vertices[1] = v1; + quad.vertices[2] = v2; + quad.vertices[3] = v3; + + m_vecQuads[NegativeZ][regZ].push_back(quad); } else { - m_meshCurrent->addTriangleCubic(v0,v2,v1); - m_meshCurrent->addTriangleCubic(v1,v2,v3); + quad.vertices[0] = v0; + quad.vertices[1] = v3; + quad.vertices[2] = v2; + quad.vertices[3] = v1; + + m_vecQuads[PositiveZ][regZ].push_back(quad); } } } @@ -166,7 +205,33 @@ namespace PolyVox memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); } + for(uint32_t uFace = 0; uFace < NoOfFaces; uFace++) + { + std::vector< std::list >& vecListQuads = m_vecQuads[uFace]; + + for(uint32_t slice = 0; slice < vecListQuads.size(); slice++) + { + std::list& listQuads = vecListQuads[slice]; + + if(m_bMergeQuads) + { + //Repeatedly call this function until it returns + //false to indicate nothing more can be done. + while(performQuadMerging(listQuads)){} + } + + std::list::iterator iterEnd = listQuads.end(); + for(std::list::iterator quadIter = listQuads.begin(); quadIter != iterEnd; quadIter++) + { + Quad& quad = *quadIter; + m_meshCurrent->addTriangleCubic(quad.vertices[0], quad.vertices[1],quad.vertices[2]); + m_meshCurrent->addTriangleCubic(quad.vertices[0], quad.vertices[2],quad.vertices[3]); + } + } + } + m_meshCurrent->m_Region = m_regSizeInVoxels; + m_meshCurrent->removeUnusedVertices(); m_meshCurrent->m_vecLodRecords.clear(); LodRecord lodRecord; @@ -185,25 +250,19 @@ namespace PolyVox { IndexAndMaterial& rEntry = existingVertices[uX][uY][ct]; - int32_t iIndex = static_cast(rEntry.iIndex); - uint8_t uMaterial = static_cast(rEntry.uMaterial); - - //If we have an existing vertex and the material matches then we can return it. - if((iIndex != -1) && (uMaterial == uMaterialIn)) - { - return iIndex; - } - else + if(rEntry.iIndex == -1) { //No vertices matched and we've now hit an empty space. Fill it by creating a vertex. - uint32_t temp = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(fX, fY, fZ), uMaterialIn)); - - //Note - Slightly dodgy casting taking place here. No proper way to convert to 24-bit int though? - //If problematic in future then fix IndexAndMaterial to contain variables rather than bitfield. - rEntry.iIndex = temp; + rEntry.iIndex = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(fX, fY, fZ), uMaterialIn)); rEntry.uMaterial = uMaterialIn; - return temp; + return rEntry.iIndex; + } + + //If we have an existing vertex and the material matches then we can return it. + if(rEntry.uMaterial == uMaterialIn) + { + return rEntry.iIndex; } } @@ -212,4 +271,74 @@ namespace PolyVox assert(false); return 0; } + + template< template class VolumeType, typename VoxelType> + bool CubicSurfaceExtractor::performQuadMerging(std::list& quads) + { + bool bDidMerge = false; + for(std::list::iterator outerIter = quads.begin(); outerIter != quads.end(); outerIter++) + { + std::list::iterator innerIter = outerIter; + innerIter++; + while(innerIter != quads.end()) + { + Quad& q1 = *outerIter; + Quad& q2 = *innerIter; + + bool result = mergeQuads(q1,q2); + + if(result) + { + bDidMerge = true; + innerIter = quads.erase(innerIter); + } + else + { + innerIter++; + } + } + } + + return bDidMerge; + } + + template< template class VolumeType, typename VoxelType> + bool CubicSurfaceExtractor::mergeQuads(Quad& q1, Quad& q2) + { + //All four vertices of a given quad have the same material, + //so just check that the first pair or vertices match. + if(fabs(m_meshCurrent->getVertices()[q1.vertices[0]].getMaterial() - m_meshCurrent->getVertices()[q2.vertices[0]].getMaterial()) < 0.001) + { + //Now check whether quad 2 is adjacent to quad one by comparing vertices. + //Adjacent quads must share two vertices, and the second quad could be to the + //top, bottom, left, of right of the first one. This gives four combinations to test. + if((q1.vertices[0] == q2.vertices[1]) && ((q1.vertices[3] == q2.vertices[2]))) + { + q1.vertices[0] = q2.vertices[0]; + q1.vertices[3] = q2.vertices[3]; + return true; + } + else if((q1.vertices[3] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[1]))) + { + q1.vertices[3] = q2.vertices[3]; + q1.vertices[2] = q2.vertices[2]; + return true; + } + else if((q1.vertices[1] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[3]))) + { + q1.vertices[1] = q2.vertices[1]; + q1.vertices[2] = q2.vertices[2]; + return true; + } + else if((q1.vertices[0] == q2.vertices[3]) && ((q1.vertices[1] == q2.vertices[2]))) + { + q1.vertices[0] = q2.vertices[0]; + q1.vertices[1] = q2.vertices[1]; + return true; + } + } + + //Quads cannot be merged. + return false; + } } \ No newline at end of file diff --git a/library/PolyVoxCore/include/PolyVoxCore/ImprovedCubicSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/ImprovedCubicSurfaceExtractor.h deleted file mode 100644 index 6c60a317..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/ImprovedCubicSurfaceExtractor.h +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#ifndef __PolyVox_ImprovedCubicSurfaceExtractor_H__ -#define __PolyVox_ImprovedCubicSurfaceExtractor_H__ - -#include "PolyVoxCore/Array.h" -#include "PolyVoxCore/PolyVoxForwardDeclarations.h" -#include "PolyVoxCore/LargeVolume.h" - -#include "PolyVoxImpl/TypeDef.h" - -namespace PolyVox -{ - template< template class VolumeType, typename VoxelType> - class ImprovedCubicSurfaceExtractor - { - struct IndexAndMaterial - { - int32_t iIndex; - int32_t uMaterial; //Should actually use the material type here, but this is ok for now. - }; - - enum FaceNames - { - PositiveX, - PositiveY, - PositiveZ, - NegativeX, - NegativeY, - NegativeZ, - NoOfFaces - }; - - struct Quad - { - uint32_t vertices[4]; - }; - - public: - ImprovedCubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, bool bMergeQuads = true); - - void execute(); - - private: - int32_t addVertex(float fX, float fY, float fZ, uint8_t uMaterial, Array<3, IndexAndMaterial>& existingVertices); - bool performQuadMerging(std::list& quads); - bool mergeQuads(Quad& q1, Quad& q2); - - //The volume data and a sampler to access it. - VolumeType* m_volData; - - //Information about the region we are currently processing - Region m_regSizeInVoxels; - - //The surface patch we are currently filling. - SurfaceMesh* m_meshCurrent; - - //Used to avoid creating duplicate vertices. - Array<3, IndexAndMaterial> m_previousSliceVertices; - Array<3, IndexAndMaterial> m_currentSliceVertices; - - //During extraction we create a number of different lists of quads. All the - //quads in a given list are in the same plane and facing in the same direction. - std::vector< std::list > m_vecQuads[NoOfFaces]; - - //Controls whether quad merging should be performed. This might be undesirable - //is the user needs per-vertex attributes, or to perform per vertex lighting. - bool m_bMergeQuads; - - //Although we try to avoid creating multiple vertices at the same location, sometimes this is unavoidable - //if they have different materials. For example, four different materials next to each other would mean - //four quads (though more triangles) sharing the vertex. As far as I can tell, four is the worst case scenario. - static const uint32_t MaxQuadsSharingVertex; - }; -} - -#include "PolyVoxCore/ImprovedCubicSurfaceExtractor.inl" - -#endif diff --git a/library/PolyVoxCore/include/PolyVoxCore/ImprovedCubicSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/ImprovedCubicSurfaceExtractor.inl deleted file mode 100644 index 80cd8fa5..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/ImprovedCubicSurfaceExtractor.inl +++ /dev/null @@ -1,344 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#include "PolyVoxCore/Array.h" -#include "PolyVoxCore/MaterialDensityPair.h" -#include "PolyVoxCore/SurfaceMesh.h" -#include "PolyVoxImpl/MarchingCubesTables.h" -#include "PolyVoxCore/VertexTypes.h" - -namespace PolyVox -{ - template< template class VolumeType, typename VoxelType> - const uint32_t ImprovedCubicSurfaceExtractor::MaxQuadsSharingVertex = 4; - - template< template class VolumeType, typename VoxelType> - ImprovedCubicSurfaceExtractor::ImprovedCubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, bool bMergeQuads) - :m_volData(volData) - ,m_regSizeInVoxels(region) - ,m_meshCurrent(result) - ,m_bMergeQuads(bMergeQuads) - { - m_meshCurrent->clear(); - } - - template< template class VolumeType, typename VoxelType> - void ImprovedCubicSurfaceExtractor::execute() - { - uint32_t uArrayWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2; - uint32_t uArrayHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2; - - uint32_t arraySize[3]= {uArrayWidth, uArrayHeight, MaxQuadsSharingVertex}; - m_previousSliceVertices.resize(arraySize); - m_currentSliceVertices.resize(arraySize); - memset(m_previousSliceVertices.getRawData(), 0xff, m_previousSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); - memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); - - uint32_t uRegionWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; - uint32_t uRegionHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; - uint32_t uRegionDepth = m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 1; - - m_vecQuads[NegativeX].resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); - m_vecQuads[PositiveX].resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); - - m_vecQuads[NegativeY].resize(m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2); - m_vecQuads[PositiveY].resize(m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2); - - m_vecQuads[NegativeZ].resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2); - m_vecQuads[PositiveZ].resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2); - - VolumeType::Sampler volumeSampler(m_volData); - Quad quad; - - for(int32_t z = m_regSizeInVoxels.getLowerCorner().getZ(); z <= m_regSizeInVoxels.getUpperCorner().getZ() + 1; z++) - { - uint32_t regZ = z - m_regSizeInVoxels.getLowerCorner().getZ(); - bool finalZ = (z == m_regSizeInVoxels.getUpperCorner().getZ() + 1); - - for(int32_t y = m_regSizeInVoxels.getLowerCorner().getY(); y <= m_regSizeInVoxels.getUpperCorner().getY() + 1; y++) - { - uint32_t regY = y - m_regSizeInVoxels.getLowerCorner().getY(); - bool finalY = (y == m_regSizeInVoxels.getUpperCorner().getY() + 1); - - for(int32_t x = m_regSizeInVoxels.getLowerCorner().getX(); x <= m_regSizeInVoxels.getUpperCorner().getX() + 1; x++) - { - uint32_t regX = x - m_regSizeInVoxels.getLowerCorner().getX(); - bool finalX = (x == m_regSizeInVoxels.getUpperCorner().getX() + 1); - - volumeSampler.setPosition(x,y,z); - - VoxelType currentVoxel = volumeSampler.getVoxel(); - bool currentVoxelIsSolid = currentVoxel.getDensity() >= VoxelType::getThreshold(); - - VoxelType negXVoxel = volumeSampler.peekVoxel1nx0py0pz(); - bool negXVoxelIsSolid = negXVoxel.getDensity() >= VoxelType::getThreshold(); - - if((currentVoxelIsSolid != negXVoxelIsSolid) && (finalY == false) && (finalZ == false)) - { - int material = (std::max)(currentVoxel.getMaterial(), negXVoxel.getMaterial()); - - // Check to ensure that when a voxel solid/non-solid change is right on a region border, the vertices are generated on the solid side of the region border - if(((currentVoxelIsSolid > negXVoxelIsSolid) && finalX == false) || ((currentVoxelIsSolid < negXVoxelIsSolid) && regX != 0)) - { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v2 = addVertex(regX - 0.5f, regY + 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - - if(currentVoxelIsSolid > negXVoxelIsSolid) - { - quad.vertices[0] = v0; - quad.vertices[1] = v1; - quad.vertices[2] = v2; - quad.vertices[3] = v3; - - m_vecQuads[NegativeX][regX].push_back(quad); - } - else - { - quad.vertices[0] = v0; - quad.vertices[1] = v3; - quad.vertices[2] = v2; - quad.vertices[3] = v1; - - m_vecQuads[PositiveX][regX].push_back(quad); - } - - } - } - - VoxelType negYVoxel = volumeSampler.peekVoxel0px1ny0pz(); - bool negYVoxelIsSolid = negYVoxel.getDensity() >= VoxelType::getThreshold(); - - if((currentVoxelIsSolid != negYVoxelIsSolid) && (finalX == false) && (finalZ == false)) - { - int material = (std::max)(currentVoxel.getMaterial(),negYVoxel.getMaterial()); - - if(((currentVoxelIsSolid > negYVoxelIsSolid) && finalY == false) || ((currentVoxelIsSolid < negYVoxelIsSolid) && regY != 0)) - { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v2 = addVertex(regX + 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - - if(currentVoxelIsSolid > negYVoxelIsSolid) - { - //NOTE: For some reason y windong is opposite of X and Z. Investigate this... - quad.vertices[0] = v0; - quad.vertices[1] = v3; - quad.vertices[2] = v2; - quad.vertices[3] = v1; - - m_vecQuads[NegativeY][regY].push_back(quad); - } - else - { - //NOTE: For some reason y windong is opposite of X and Z. Investigate this... - quad.vertices[0] = v0; - quad.vertices[1] = v1; - quad.vertices[2] = v2; - quad.vertices[3] = v3; - - m_vecQuads[PositiveY][regY].push_back(quad); - } - } - } - - VoxelType negZVoxel = volumeSampler.peekVoxel0px0py1nz(); - bool negZVoxelIsSolid = negZVoxel.getDensity() >= VoxelType::getThreshold(); - - if((currentVoxelIsSolid != negZVoxelIsSolid) && (finalX == false) && (finalY == false)) - { - int material = (std::max)(currentVoxel.getMaterial(), negZVoxel.getMaterial()); - - if(((currentVoxelIsSolid > negZVoxelIsSolid) && finalZ == false) || ((currentVoxelIsSolid < negZVoxelIsSolid) && regZ != 0)) - { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(regX + 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - - if(currentVoxelIsSolid > negZVoxelIsSolid) - { - quad.vertices[0] = v0; - quad.vertices[1] = v1; - quad.vertices[2] = v2; - quad.vertices[3] = v3; - - m_vecQuads[NegativeZ][regZ].push_back(quad); - } - else - { - quad.vertices[0] = v0; - quad.vertices[1] = v3; - quad.vertices[2] = v2; - quad.vertices[3] = v1; - - m_vecQuads[PositiveZ][regZ].push_back(quad); - } - } - } - } - } - - m_previousSliceVertices.swap(m_currentSliceVertices); - memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); - } - - for(uint32_t uFace = 0; uFace < NoOfFaces; uFace++) - { - std::vector< std::list >& vecListQuads = m_vecQuads[uFace]; - - for(uint32_t slice = 0; slice < vecListQuads.size(); slice++) - { - std::list& listQuads = vecListQuads[slice]; - - if(m_bMergeQuads) - { - //Repeatedly call this function until it returns - //false to indicate nothing more can be done. - while(performQuadMerging(listQuads)){} - } - - std::list::iterator iterEnd = listQuads.end(); - for(std::list::iterator quadIter = listQuads.begin(); quadIter != iterEnd; quadIter++) - { - Quad& quad = *quadIter; - m_meshCurrent->addTriangleCubic(quad.vertices[0], quad.vertices[1],quad.vertices[2]); - m_meshCurrent->addTriangleCubic(quad.vertices[0], quad.vertices[2],quad.vertices[3]); - } - } - } - - m_meshCurrent->m_Region = m_regSizeInVoxels; - m_meshCurrent->removeUnusedVertices(); - - m_meshCurrent->m_vecLodRecords.clear(); - LodRecord lodRecord; - lodRecord.beginIndex = 0; - lodRecord.endIndex = m_meshCurrent->getNoOfIndices(); - m_meshCurrent->m_vecLodRecords.push_back(lodRecord); - } - - template< template class VolumeType, typename VoxelType> - int32_t ImprovedCubicSurfaceExtractor::addVertex(float fX, float fY, float fZ, uint8_t uMaterialIn, Array<3, IndexAndMaterial>& existingVertices) - { - uint32_t uX = static_cast(fX + 0.75f); - uint32_t uY = static_cast(fY + 0.75f); - - for(uint32_t ct = 0; ct < MaxQuadsSharingVertex; ct++) - { - IndexAndMaterial& rEntry = existingVertices[uX][uY][ct]; - - if(rEntry.iIndex == -1) - { - //No vertices matched and we've now hit an empty space. Fill it by creating a vertex. - rEntry.iIndex = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(fX, fY, fZ), uMaterialIn)); - rEntry.uMaterial = uMaterialIn; - - return rEntry.iIndex; - } - - //If we have an existing vertex and the material matches then we can return it. - if(rEntry.uMaterial == uMaterialIn) - { - return rEntry.iIndex; - } - } - - //If we exit the loop here then apparently all the slots were full but none of - //them matched. I don't think this can happen so let's put an assert to make sure. - assert(false); - return 0; - } - - template< template class VolumeType, typename VoxelType> - bool ImprovedCubicSurfaceExtractor::performQuadMerging(std::list& quads) - { - bool bDidMerge = false; - for(std::list::iterator outerIter = quads.begin(); outerIter != quads.end(); outerIter++) - { - std::list::iterator innerIter = outerIter; - innerIter++; - while(innerIter != quads.end()) - { - Quad& q1 = *outerIter; - Quad& q2 = *innerIter; - - bool result = mergeQuads(q1,q2); - - if(result) - { - bDidMerge = true; - innerIter = quads.erase(innerIter); - } - else - { - innerIter++; - } - } - } - - return bDidMerge; - } - - template< template class VolumeType, typename VoxelType> - bool ImprovedCubicSurfaceExtractor::mergeQuads(Quad& q1, Quad& q2) - { - //All four vertices of a given quad have the same material, - //so just check that the first pair or vertices match. - if(fabs(m_meshCurrent->getVertices()[q1.vertices[0]].getMaterial() - m_meshCurrent->getVertices()[q2.vertices[0]].getMaterial()) < 0.001) - { - //Now check whether quad 2 is adjacent to quad one by comparing vertices. - //Adjacent quads must share two vertices, and the second quad could be to the - //top, bottom, left, of right of the first one. This gives four combinations to test. - if((q1.vertices[0] == q2.vertices[1]) && ((q1.vertices[3] == q2.vertices[2]))) - { - q1.vertices[0] = q2.vertices[0]; - q1.vertices[3] = q2.vertices[3]; - return true; - } - else if((q1.vertices[3] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[1]))) - { - q1.vertices[3] = q2.vertices[3]; - q1.vertices[2] = q2.vertices[2]; - return true; - } - else if((q1.vertices[1] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[3]))) - { - q1.vertices[1] = q2.vertices[1]; - q1.vertices[2] = q2.vertices[2]; - return true; - } - else if((q1.vertices[0] == q2.vertices[3]) && ((q1.vertices[1] == q2.vertices[2]))) - { - q1.vertices[0] = q2.vertices[0]; - q1.vertices[1] = q2.vertices[1]; - return true; - } - } - - //Quads cannot be merged. - return false; - } -} \ No newline at end of file