From 0cd7e5f7b15ff8d645c05905145995ea60e04e76 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 9 May 2011 22:36:33 +0100 Subject: [PATCH] Initial checkin of ImprovedCubicSurfaceExtractor --- .../include/ImprovedCubicSurfaceExtractor.h | 128 +++++ .../include/ImprovedCubicSurfaceExtractor.inl | 516 ++++++++++++++++++ 2 files changed, 644 insertions(+) create mode 100644 library/PolyVoxCore/include/ImprovedCubicSurfaceExtractor.h create mode 100644 library/PolyVoxCore/include/ImprovedCubicSurfaceExtractor.inl diff --git a/library/PolyVoxCore/include/ImprovedCubicSurfaceExtractor.h b/library/PolyVoxCore/include/ImprovedCubicSurfaceExtractor.h new file mode 100644 index 00000000..6088db1f --- /dev/null +++ b/library/PolyVoxCore/include/ImprovedCubicSurfaceExtractor.h @@ -0,0 +1,128 @@ +/******************************************************************************* +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 "Array.h" +#include "PolyVoxForwardDeclarations.h" +#include "LargeVolume.h" + +#include "PolyVoxImpl/TypeDef.h" + +namespace PolyVox +{ + struct IndexAndMaterial + { + int32_t iIndex : 24; + int32_t uMaterial : 8; + }; + + enum FaceNames + { + PositiveX, + PositiveY, + PositiveZ, + NegativeX, + NegativeY, + NegativeZ, + NoOfFaces + }; + + struct Quad + { + uint32_t vertices[4]; + uint8_t material; //Shouldn't hard code to uint8_t type? + }; + + template< template class VolumeType, typename VoxelType> + class ImprovedCubicSurfaceExtractor + { + public: + ImprovedCubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result); + + void execute(); + + int32_t addVertex(float fX, float fY, float fZ, uint8_t uMaterial, Array<3, IndexAndMaterial>& existingVertices); + + private: + //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; + + //The surface patch we are currently filling. + SurfaceMesh* m_meshCurrent; + + //Array<4, IndexAndMaterial> m_vertices; + Array<3, IndexAndMaterial> m_previousSliceVertices; + Array<3, IndexAndMaterial> m_currentSliceVertices; + + Array<4, uint8_t> m_faces; + + std::vector< std::list > m_vecNegXQuads; + std::vector< std::list > m_vecPosXQuads; + + std::vector< std::list > m_vecNegYQuads; + std::vector< std::list > m_vecPosYQuads; + + std::vector< std::list > m_vecNegZQuads; + std::vector< std::list > m_vecPosZQuads; + + //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; + + //////////////////////////////////////////////////////////////////////////////// + // Decimation + //////////////////////////////////////////////////////////////////////////////// + + /*class Triangle + { + uint32_t v0; + uint32_t v1; + uint32_t v2; + } + + std::vector triangles; + std::vector< std::vector > trianglesUsingVertex;*/ + + //std::vector decimate(const std::vector& quads); + + bool decimate(std::list& quads); + + Quad mergeQuads(Quad q1, Quad q2); + + bool canMergeQuads(Quad q1, Quad q2); + + int32_t quadContainsVertex(const Quad& quad, uint32_t uVertexIndex); + + }; +} + +#include "ImprovedCubicSurfaceExtractor.inl" + +#endif diff --git a/library/PolyVoxCore/include/ImprovedCubicSurfaceExtractor.inl b/library/PolyVoxCore/include/ImprovedCubicSurfaceExtractor.inl new file mode 100644 index 00000000..bdf8c666 --- /dev/null +++ b/library/PolyVoxCore/include/ImprovedCubicSurfaceExtractor.inl @@ -0,0 +1,516 @@ +/******************************************************************************* +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 "Array.h" +#include "MaterialDensityPair.h" +#include "SurfaceMesh.h" +#include "PolyVoxImpl/MarchingCubesTables.h" +#include "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) + :m_volData(volData) + ,m_sampVolume(volData) + ,m_regSizeInVoxels(region) + ,m_meshCurrent(result) + { + 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_faces.resize(ArraySizes(uRegionWidth)(uRegionHeight)(uRegionDepth)(NoOfFaces)); + memset(m_faces.getRawData(), 0x00, m_faces.getNoOfElements() * sizeof(uint8_t)); //Note: hard-coded type uint8_t + + m_vecNegXQuads.resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); + m_vecPosXQuads.resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); + + m_vecNegYQuads.resize(m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2); + m_vecPosYQuads.resize(m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2); + + m_vecNegZQuads.resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2); + m_vecPosZQuads.resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2); + + + for(int32_t z = m_regSizeInVoxels.getLowerCorner().getZ(); z <= m_regSizeInVoxels.getUpperCorner().getZ() + 1; z++) + { + for(int32_t y = m_regSizeInVoxels.getLowerCorner().getY(); y <= m_regSizeInVoxels.getUpperCorner().getY() + 1; y++) + { + 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 finalY = (y == m_regSizeInVoxels.getUpperCorner().getY() + 1); + bool finalZ = (z == m_regSizeInVoxels.getUpperCorner().getZ() + 1); + + VoxelType currentVoxel = m_volData->getVoxelAt(x,y,z); + bool currentVoxelIsSolid = currentVoxel.getDensity() >= VoxelType::getThreshold(); + + VoxelType negXVoxel = m_volData->getVoxelAt(x-1,y,z); + 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_previousSliceVertices); + 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_currentSliceVertices); + + if(currentVoxelIsSolid > negXVoxelIsSolid) + { + //m_meshCurrent->addTriangleCubic(v0,v1,v2); + //m_meshCurrent->addTriangleCubic(v1,v3,v2); + + //m_faces[x][y][z][NegativeX] = material; + + Quad quad; + quad.vertices[0] = v0; + quad.vertices[1] = v1; + quad.vertices[2] = v2; + quad.vertices[3] = v3; + quad.material = material; + + m_vecNegXQuads[regX].push_back(quad); + + /*m_vecNegXIndices[x].push_back(v0); + m_vecNegXIndices[x].push_back(v1); + m_vecNegXIndices[x].push_back(v2); + m_vecNegXIndices[x].push_back(v3);*/ + } + else + { + + Quad quad; + quad.vertices[0] = v0; + quad.vertices[1] = v3; + quad.vertices[2] = v2; + quad.vertices[3] = v1; + quad.material = material; + + m_vecPosXQuads[regX].push_back(quad); + + //m_meshCurrent->addTriangleCubic(v0,v2,v1); + //m_meshCurrent->addTriangleCubic(v1,v2,v3); + + /*m_vecPosXIndices[x-1].push_back(v0); + m_vecPosXIndices[x-1].push_back(v2); + m_vecPosXIndices[x-1].push_back(v1); + m_vecPosXIndices[x-1].push_back(v1); + m_vecPosXIndices[x-1].push_back(v2); + m_vecPosXIndices[x-1].push_back(v3);*/ + + //m_faces[x-1][y][z][PositiveX] = material; + } + + } + } + + VoxelType negYVoxel = m_volData->getVoxelAt(x,y-1,z); + 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_previousSliceVertices); + 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_currentSliceVertices); + + + + if(currentVoxelIsSolid > negYVoxelIsSolid) + { + //NOTE: For some reason y windong is opposite of X and Z. Investigate this... + Quad quad; + quad.vertices[0] = v0; + quad.vertices[1] = v3; + quad.vertices[2] = v2; + quad.vertices[3] = v1; + quad.material = material; + + m_vecNegYQuads[regY].push_back(quad); + //m_meshCurrent->addTriangleCubic(v0,v2,v1); + //m_meshCurrent->addTriangleCubic(v1,v2,v3); + + //m_faces[x][y][z][NegativeY] = material; + } + else + { + //NOTE: For some reason y windong is opposite of X and Z. Investigate this... + Quad quad; + quad.vertices[0] = v0; + quad.vertices[1] = v1; + quad.vertices[2] = v2; + quad.vertices[3] = v3; + quad.material = material; + + m_vecPosYQuads[regY].push_back(quad); + //m_meshCurrent->addTriangleCubic(v0,v1,v2); + //m_meshCurrent->addTriangleCubic(v1,v3,v2); + + //m_faces[x][y-1][z][PositiveY] = material; + } + } + } + + VoxelType negZVoxel = m_volData->getVoxelAt(x,y,z-1); + 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 quad; + quad.vertices[0] = v0; + quad.vertices[1] = v1; + quad.vertices[2] = v2; + quad.vertices[3] = v3; + quad.material = material; + + m_vecNegZQuads[regZ].push_back(quad); + //m_meshCurrent->addTriangleCubic(v0,v1,v2); + //m_meshCurrent->addTriangleCubic(v1,v3,v2); + + //m_faces[x][y][z][NegativeZ] = material; + } + else + { + Quad quad; + quad.vertices[0] = v0; + quad.vertices[1] = v3; + quad.vertices[2] = v2; + quad.vertices[3] = v1; + quad.material = material; + + m_vecPosZQuads[regZ].push_back(quad); + //m_meshCurrent->addTriangleCubic(v0,v2,v1); + //m_meshCurrent->addTriangleCubic(v1,v2,v3); + + //m_faces[x][y][z-1][PositiveZ] = material; + } + } + } + } + } + + m_previousSliceVertices.swap(m_currentSliceVertices); + memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); + } + + for(uint32_t slice = 0; slice < m_vecNegXQuads.size(); slice++) + { + while(decimate(m_vecNegXQuads[slice])){} + + for(std::list::iterator quadIter = m_vecNegXQuads[slice].begin(); quadIter != m_vecNegXQuads[slice].end(); quadIter++) + { + //m_meshCurrent->addTriangleCubic(m_vecPosXIndices[slice][index], m_vecPosXIndices[slice][index+1], m_vecPosXIndices[slice][index+2]); + + 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]); + } + } + + for(uint32_t slice = 0; slice < m_vecPosXQuads.size(); slice++) + { + while(decimate(m_vecPosXQuads[slice])){} + + for(std::list::iterator quadIter = m_vecPosXQuads[slice].begin(); quadIter != m_vecPosXQuads[slice].end(); quadIter++) + { + //m_meshCurrent->addTriangleCubic(m_vecPosXIndices[slice][index], m_vecPosXIndices[slice][index+1], m_vecPosXIndices[slice][index+2]); + + 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]); + } + } + + for(uint32_t slice = 0; slice < m_vecNegYQuads.size(); slice++) + { + while(decimate(m_vecNegYQuads[slice])){} + + for(std::list::iterator quadIter = m_vecNegYQuads[slice].begin(); quadIter != m_vecNegYQuads[slice].end(); quadIter++) + { + //m_meshCurrent->addTriangleCubic(m_vecPosXIndices[slice][index], m_vecPosXIndices[slice][index+1], m_vecPosXIndices[slice][index+2]); + + 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]); + } + } + + for(uint32_t slice = 0; slice < m_vecPosYQuads.size(); slice++) + { + while(decimate(m_vecPosYQuads[slice])){} + + for(std::list::iterator quadIter = m_vecPosYQuads[slice].begin(); quadIter != m_vecPosYQuads[slice].end(); quadIter++) + { + //m_meshCurrent->addTriangleCubic(m_vecPosXIndices[slice][index], m_vecPosXIndices[slice][index+1], m_vecPosXIndices[slice][index+2]); + + 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]); + } + } + + for(uint32_t slice = 0; slice < m_vecNegZQuads.size(); slice++) + { + while(decimate(m_vecNegZQuads[slice])){} + + for(std::list::iterator quadIter = m_vecNegZQuads[slice].begin(); quadIter != m_vecNegZQuads[slice].end(); quadIter++) + { + //m_meshCurrent->addTriangleCubic(m_vecPosXIndices[slice][index], m_vecPosXIndices[slice][index+1], m_vecPosXIndices[slice][index+2]); + + 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]); + } + } + + for(uint32_t slice = 0; slice < m_vecPosZQuads.size(); slice++) + { + while(decimate(m_vecPosZQuads[slice])){} + + for(std::list::iterator quadIter = m_vecPosZQuads[slice].begin(); quadIter != m_vecPosZQuads[slice].end(); quadIter++) + { + //m_meshCurrent->addTriangleCubic(m_vecPosXIndices[slice][index], m_vecPosXIndices[slice][index+1], m_vecPosXIndices[slice][index+2]); + + 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->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]; + + 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 + { + //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.uMaterial = uMaterialIn; + + return temp; + } + } + + //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::decimate(std::list& quads) + { + 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; + + if(canMergeQuads(q1, q2)) + { + //std::cout << "Can merge" << std::endl; + Quad result = mergeQuads(q1,q2); + + quads.erase(innerIter); + quads.erase(outerIter); + + quads.push_back(result); + + return true; + } + + innerIter++; + } + } + + return false; + //std::cout << "Can not merge" << std::endl; + } + + template< template class VolumeType, typename VoxelType> + Quad ImprovedCubicSurfaceExtractor::mergeQuads(Quad q1, Quad q2) + { + /*Quad* pCurrentQuad = &q1; + Quad* pOtherQuad = &q2; + uint32_t uCurrentInputIndex = 0; + uint32_t uCurrentOutputIndex = 0; + + Quad result; + result.material = q1.material; + + do + { + uint32_t uIndexInOtherQuad = quadContainsVertex(*pOtherQuad, (*(pCurrentQuad)).vertices[uCurrentInputIndex]); + if(uIndexInOtherQuad != -1) + { + std::swap(pCurrentQuad, pOtherQuad); + uCurrentInputIndex = (uIndexInOtherQuad + 1) % 4; + } + else + { + result.vertices[uCurrentOutputIndex] = pCurrentQuad->vertices[uCurrentInputIndex]; + uCurrentOutputIndex++; + uCurrentInputIndex = (uCurrentInputIndex + 1) % 4; + } + } while(uCurrentOutputIndex < 4); + + return result;*/ + + Quad result; + result.material = q1.material; + + for(uint32_t vertex = 0; vertex < 4; vertex++) + { + uint32_t quad1vertex = q1.vertices[vertex]; + uint32_t quad2vertex = q2.vertices[vertex]; + + if(quadContainsVertex(q2, quad1vertex) != -1) + { + result.vertices[vertex] = quad2vertex; + } + else + { + result.vertices[vertex] = quad1vertex; + } + } + + return result; + } + + template< template class VolumeType, typename VoxelType> + bool ImprovedCubicSurfaceExtractor::canMergeQuads(Quad q1, Quad q2) + { + if(q1.material != q2.material) + { + return false; + } + + uint32_t uNoOfMatchingVertices = 0; + for(uint32_t uQuad1Index = 0; uQuad1Index < 4; uQuad1Index++) + { + if(quadContainsVertex(q2, q1.vertices[uQuad1Index]) != -1) + { + uNoOfMatchingVertices++; + } + } + + return uNoOfMatchingVertices == 2; + } + + template< template class VolumeType, typename VoxelType> + int32_t ImprovedCubicSurfaceExtractor::quadContainsVertex(const Quad& quad, uint32_t uVertexIndex) + { + for(uint32_t ct = 0; ct < 4; ct++) + { + if(quad.vertices[ct] == uVertexIndex) + { + //We've found a matching vertex. + return ct; + } + } + + //Vertex not found. + return -1; + } +} \ No newline at end of file