From 350a7feef6e32f4ebd6afca6d29b3ad0562d6585 Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 11 Jun 2008 20:22:00 +0000 Subject: [PATCH] Initial version of fast decimation. --- PolyVoxCore/CMakeLists.txt | 2 + PolyVoxCore/include/SurfaceExtractors.h | 2 - .../include/SurfaceExtractorsDecimated.h | 50 + PolyVoxCore/source/SurfaceExtractors.cpp | 276 +----- .../source/SurfaceExtractorsDecimated.cpp | 912 ++++++++++++++++++ 5 files changed, 965 insertions(+), 277 deletions(-) create mode 100644 PolyVoxCore/include/SurfaceExtractorsDecimated.h create mode 100644 PolyVoxCore/source/SurfaceExtractorsDecimated.cpp diff --git a/PolyVoxCore/CMakeLists.txt b/PolyVoxCore/CMakeLists.txt index 3ac8a155..6455d3e4 100644 --- a/PolyVoxCore/CMakeLists.txt +++ b/PolyVoxCore/CMakeLists.txt @@ -14,6 +14,7 @@ SET(SRC_FILES source/Region.cpp source/RegionGeometry.cpp source/SurfaceExtractors.cpp + source/SurfaceExtractorsDecimated.cpp source/SurfaceVertex.cpp source/Utility.cpp source/VolumeChangeTracker.cpp @@ -39,6 +40,7 @@ SET(INC_FILES include/Region.h include/RegionGeometry.h include/SurfaceExtractors.h + include/SurfaceExtractorsDecimated.h include/SurfaceVertex.h include/TypeDef.h include/Utility.h diff --git a/PolyVoxCore/include/SurfaceExtractors.h b/PolyVoxCore/include/SurfaceExtractors.h index 604c4d05..722bb6d5 100644 --- a/PolyVoxCore/include/SurfaceExtractors.h +++ b/PolyVoxCore/include/SurfaceExtractors.h @@ -49,8 +49,6 @@ namespace PolyVox POLYVOX_API void generateSmoothMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch); POLYVOX_API Vector3DFloat computeSmoothNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod); - - POLYVOX_API void generateDecimatedMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch); } #endif diff --git a/PolyVoxCore/include/SurfaceExtractorsDecimated.h b/PolyVoxCore/include/SurfaceExtractorsDecimated.h new file mode 100644 index 00000000..310fa9b4 --- /dev/null +++ b/PolyVoxCore/include/SurfaceExtractorsDecimated.h @@ -0,0 +1,50 @@ +#pragma region License +/****************************************************************************** +This file is part of the PolyVox library +Copyright (C) 2006 David Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +******************************************************************************/ +#pragma endregion + +#ifndef __PolyVox_SurfaceExtractorsDecimated_H__ +#define __PolyVox_SurfaceExtractorsDecimated_H__ + +#pragma region Headers +#include "Constants.h" +#include "PolyVoxForwardDeclarations.h" +#include "TypeDef.h" + +#include "boost/cstdint.hpp" + +#include +#pragma endregion + +namespace PolyVox +{ + boost::uint32_t getDecimatedIndex(boost::uint32_t x, boost::uint32_t y); + + POLYVOX_API void generateDecimatedMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch); + POLYVOX_API boost::uint32_t computeInitialDecimatedBitmaskForSlice(BlockVolumeIterator& volIter, const Region& regSlice, const Vector3DFloat& offset, boost::uint8_t *bitmask); + POLYVOX_API boost::uint32_t computeDecimatedBitmaskForSliceFromPrevious(BlockVolumeIterator& volIter, const Region& regSlice, const Vector3DFloat& offset, boost::uint8_t *bitmask, boost::uint8_t *previousBitmask); + POLYVOX_API void generateDecimatedIndicesForSlice(BlockVolumeIterator& volIter, const Region& regSlice, IndexedSurfacePatch* singleMaterialPatch, const Vector3DFloat& offset, boost::uint8_t* bitmask0, boost::uint8_t* bitmask1, boost::int32_t vertexIndicesX0[],boost::int32_t vertexIndicesY0[],boost::int32_t vertexIndicesZ0[], boost::int32_t vertexIndicesX1[],boost::int32_t vertexIndicesY1[],boost::int32_t vertexIndicesZ1[]); + POLYVOX_API void generateDecimatedVerticesForSlice(BlockVolumeIterator& volIter, Region& regSlice, const Vector3DFloat& offset, boost::uint8_t* bitmask, IndexedSurfacePatch* singleMaterialPatch,boost::int32_t vertexIndicesX[],boost::int32_t vertexIndicesY[],boost::int32_t vertexIndicesZ[], Vector3DFloat vertlist[], boost::uint8_t vertMaterials[]); + + POLYVOX_API void generateDecimatedMeshDataForRegionSlow(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch); + + POLYVOX_API Vector3DFloat computeDecimatedNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod); +} + +#endif diff --git a/PolyVoxCore/source/SurfaceExtractors.cpp b/PolyVoxCore/source/SurfaceExtractors.cpp index 347da802..a4052397 100644 --- a/PolyVoxCore/source/SurfaceExtractors.cpp +++ b/PolyVoxCore/source/SurfaceExtractors.cpp @@ -1,4 +1,5 @@ #include "SurfaceExtractors.h" +#include "SurfaceExtractorsDecimated.h" #include "BlockVolume.h" #include "GradientEstimators.h" @@ -1167,279 +1168,4 @@ namespace PolyVox } return result; } - - void generateDecimatedMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch) - { - //When generating the mesh for a region we actually look one voxel outside it in the - // back, bottom, right direction. Protect against access violations by cropping region here - Region regVolume = volumeData->getEnclosingRegion(); - //regVolume.setUpperCorner(regVolume.getUpperCorner() - Vector3DInt32(1,1,1)); - region.cropTo(regVolume); - region.setUpperCorner(region.getUpperCorner() - Vector3DInt32(1,1,1)); - - //Offset from lower block corner - const Vector3DFloat offset = static_cast(region.getLowerCorner()); - - Vector3DFloat vertlist[12]; - Vector3DFloat normlist[12]; - uint8_t vertMaterials[12]; - BlockVolumeIterator volIter(*volumeData); - volIter.setValidRegion(region); - - ////////////////////////////////////////////////////////////////////////// - //Get mesh data - ////////////////////////////////////////////////////////////////////////// - - //Iterate over each cell in the region - //volIter.setPosition(region.getLowerCorner().getX(),region.getLowerCorner().getY(), region.getLowerCorner().getZ()); - for(uint16_t z = region.getLowerCorner().getZ(); z <= region.getUpperCorner().getZ(); z += 2) - { - for(uint16_t y = region.getLowerCorner().getY(); y <= region.getUpperCorner().getY(); y += 2) - { - for(uint16_t x = region.getLowerCorner().getX(); x <= region.getUpperCorner().getX(); x += 2) - { - //while(volIter.moveForwardInRegionXYZ()) - //{ - volIter.setPosition(x,y,z); - const uint8_t v000 = volIter.getMaxedVoxel(); - volIter.setPosition(x+2,y,z); - const uint8_t v100 = volIter.getMaxedVoxel(); - volIter.setPosition(x,y+2,z); - const uint8_t v010 = volIter.getMaxedVoxel(); - volIter.setPosition(x+2,y+2,z); - const uint8_t v110 = volIter.getMaxedVoxel(); - volIter.setPosition(x,y,z+2); - const uint8_t v001 = volIter.getMaxedVoxel(); - volIter.setPosition(x+2,y,z+2); - const uint8_t v101 = volIter.getMaxedVoxel(); - volIter.setPosition(x,y+2,z+2); - const uint8_t v011 = volIter.getMaxedVoxel(); - volIter.setPosition(x+2,y+2,z+2); - const uint8_t v111 = volIter.getMaxedVoxel(); - - //Determine the index into the edge table which tells us which vertices are inside of the surface - uint8_t iCubeIndex = 0; - - if (v000 == 0) iCubeIndex |= 1; - if (v100 == 0) iCubeIndex |= 2; - if (v110 == 0) iCubeIndex |= 4; - if (v010 == 0) iCubeIndex |= 8; - if (v001 == 0) iCubeIndex |= 16; - if (v101 == 0) iCubeIndex |= 32; - if (v111 == 0) iCubeIndex |= 64; - if (v011 == 0) iCubeIndex |= 128; - - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] == 0) - { - continue; - } - - /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) - { - vertlist[0].setX(x + 0.5f * 2.0f); - vertlist[0].setY(y); - vertlist[0].setZ(z); - normlist[0] = Vector3DFloat(v000 - v100,0.0,0.0); - vertMaterials[0] = v000 | v100; //Because one of these is 0, the or operation takes the max. - } - if (edgeTable[iCubeIndex] & 2) - { - vertlist[1].setX(x + 1.0f * 2.0f); - vertlist[1].setY(y + 0.5f * 2.0f); - vertlist[1].setZ(z); - vertMaterials[1] = v100 | v110; - normlist[1] = Vector3DFloat(0.0,v100 - v110,0.0); - } - if (edgeTable[iCubeIndex] & 4) - { - vertlist[2].setX(x + 0.5f * 2.0f); - vertlist[2].setY(y + 1.0f * 2.0f); - vertlist[2].setZ(z); - vertMaterials[2] = v010 | v110; - normlist[2] = Vector3DFloat(v010 - v110,0.0,0.0); - } - if (edgeTable[iCubeIndex] & 8) - { - vertlist[3].setX(x); - vertlist[3].setY(y + 0.5f * 2.0f); - vertlist[3].setZ(z); - vertMaterials[3] = v000 | v010; - normlist[3] = Vector3DFloat(0.0,v000 - v010,0.0); - } - if (edgeTable[iCubeIndex] & 16) - { - vertlist[4].setX(x + 0.5f * 2.0f); - vertlist[4].setY(y); - vertlist[4].setZ(z + 1.0f * 2.0f); - vertMaterials[4] = v001 | v101; - normlist[4] = Vector3DFloat(v001 - v101,0.0,0.0); - } - if (edgeTable[iCubeIndex] & 32) - { - vertlist[5].setX(x + 1.0f * 2.0f); - vertlist[5].setY(y + 0.5f * 2.0f); - vertlist[5].setZ(z + 1.0f * 2.0f); - vertMaterials[5] = v101 | v111; - normlist[5] = Vector3DFloat(0.0,v101 - v111,0.0); - } - if (edgeTable[iCubeIndex] & 64) - { - vertlist[6].setX(x + 0.5f * 2.0f); - vertlist[6].setY(y + 1.0f * 2.0f); - vertlist[6].setZ(z + 1.0f * 2.0f); - vertMaterials[6] = v011 | v111; - normlist[6] = Vector3DFloat(v011 - v111,0.0,0.0); - } - if (edgeTable[iCubeIndex] & 128) - { - vertlist[7].setX(x); - vertlist[7].setY(y + 0.5f * 2.0f); - vertlist[7].setZ(z + 1.0f * 2.0f); - vertMaterials[7] = v001 | v011; - normlist[7] = Vector3DFloat(0.0,v001 - v011,0.0); - } - if (edgeTable[iCubeIndex] & 256) - { - vertlist[8].setX(x); - vertlist[8].setY(y); - vertlist[8].setZ(z + 0.5f * 2.0f); - vertMaterials[8] = v000 | v001; - normlist[8] = Vector3DFloat(0.0,0.0,v000 - v001); - } - if (edgeTable[iCubeIndex] & 512) - { - vertlist[9].setX(x + 1.0f * 2.0f); - vertlist[9].setY(y); - vertlist[9].setZ(z + 0.5f * 2.0f); - vertMaterials[9] = v100 | v101; - normlist[9] = Vector3DFloat(0.0,0.0,v100 - v101); - } - if (edgeTable[iCubeIndex] & 1024) - { - vertlist[10].setX(x + 1.0f * 2.0f); - vertlist[10].setY(y + 1.0f * 2.0f); - vertlist[10].setZ(z + 0.5f * 2.0f); - vertMaterials[10] = v110 | v111; - normlist[10] = Vector3DFloat(0.0,0.0,v110 - v111); - } - if (edgeTable[iCubeIndex] & 2048) - { - vertlist[11].setX(x); - vertlist[11].setY(y + 1.0f * 2.0f); - vertlist[11].setZ(z + 0.5f * 2.0f); - vertMaterials[11] = v010 | v011; - normlist[11] = Vector3DFloat(0.0,0.0,v010 - v011); - } - - for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) - { - //The three vertices forming a triangle - Vector3DFloat vertex0 = vertlist[triTable[iCubeIndex][i ]] - offset; - Vector3DFloat vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset; - Vector3DFloat vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset; - - Vector3DFloat normal0 = normlist[triTable[iCubeIndex][i ]]; - Vector3DFloat normal1 = normlist[triTable[iCubeIndex][i+1]]; - Vector3DFloat normal2 = normlist[triTable[iCubeIndex][i+2]]; - - normal0.normalise(); - normal1.normalise(); - normal2.normalise(); - - vertex0 += (normal0); - vertex1 += (normal1); - vertex2 += (normal2); - - //Cast to floats and divide by two. - //const Vector3DFloat vertex0AsFloat = (static_cast(vertex0) / 2.0f) - offset; - //const Vector3DFloat vertex1AsFloat = (static_cast(vertex1) / 2.0f) - offset; - //const Vector3DFloat vertex2AsFloat = (static_cast(vertex2) / 2.0f) - offset; - - const uint8_t material0 = vertMaterials[triTable[iCubeIndex][i ]]; - const uint8_t material1 = vertMaterials[triTable[iCubeIndex][i+1]]; - const uint8_t material2 = vertMaterials[triTable[iCubeIndex][i+2]]; - - - //If all the materials are the same, we just need one triangle for that material with all the alphas set high. - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); - surfaceVertex0Alpha1.setNormal(normal0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); - surfaceVertex1Alpha1.setNormal(normal1); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); - surfaceVertex2Alpha1.setNormal(normal2); - singleMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - }//For each triangle - //}//For each cell - } - } - } - - //FIXME - can it happen that we have no vertices or triangles? Should exit early? - - - //for(std::map::iterator iterPatch = surfacePatchMapResult.begin(); iterPatch != surfacePatchMapResult.end(); ++iterPatch) - { - - /*std::vector::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin(); - while(iterSurfaceVertex != singleMaterialPatch->getVertices().end()) - { - Vector3DFloat tempNormal = computeNormal(volumeData, static_cast(iterSurfaceVertex->getPosition() + offset), SIMPLE); - const_cast(*iterSurfaceVertex).setNormal(tempNormal); - ++iterSurfaceVertex; - }*/ - } - } - -#ifdef BLAH - Vector3DFloat computeDecimatedNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) - { - const float posX = position.getX(); - const float posY = position.getY(); - const float posZ = position.getZ(); - - const uint16_t floorX = static_cast(posX) - 1; - const uint16_t floorY = static_cast(posY) - 1; - const uint16_t floorZ = static_cast(posZ) - 1; - - const uint16_t ceilX = static_cast(posX) + 1; - const uint16_t ceilY = static_cast(posY) + 1; - const uint16_t ceilZ = static_cast(posZ) + 1; - - //Check all corners are within the volume, allowing a boundary for gradient estimation - bool lowerCornerInside = volumeData->containsPoint(Vector3DInt32(floorX, floorY, floorZ),1); - bool upperCornerInside = volumeData->containsPoint(Vector3DInt32(floorX+1, floorY+1, floorZ+1),1); - if((!lowerCornerInside) || (!upperCornerInside)) - { - normalGenerationMethod = SIMPLE; - } - - Vector3DFloat result; - - BlockVolumeIterator volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create? - - if(normalGenerationMethod == SIMPLE) - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); - const uint8_t uFloor = volIter.getVoxel() > 0 ? 1 : 0; - if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel1px0py0pz() > 0 ? 1 : 0; - result = Vector3DFloat(static_cast(uFloor - uCeil),0.0,0.0); - } - else if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel0px1py0pz() > 0 ? 1 : 0; - result = Vector3DFloat(0.0,static_cast(uFloor - uCeil),0.0); - } - else if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0; - result = Vector3DFloat(0.0, 0.0,static_cast(uFloor - uCeil)); - } - } - return result; - } -#endif } diff --git a/PolyVoxCore/source/SurfaceExtractorsDecimated.cpp b/PolyVoxCore/source/SurfaceExtractorsDecimated.cpp new file mode 100644 index 00000000..de3e4e71 --- /dev/null +++ b/PolyVoxCore/source/SurfaceExtractorsDecimated.cpp @@ -0,0 +1,912 @@ +#include "SurfaceExtractorsDecimated.h" + +#include "BlockVolume.h" +#include "GradientEstimators.h" +#include "IndexedSurfacePatch.h" +#include "MarchingCubesTables.h" +#include "Region.h" +#include "RegionGeometry.h" +#include "VolumeChangeTracker.h" +#include "BlockVolumeIterator.h" + +#include + +using namespace boost; + +namespace PolyVox +{ + boost::uint32_t getDecimatedIndex(boost::uint32_t x, boost::uint32_t y) + { + return x + (y * (POLYVOX_REGION_SIDE_LENGTH+1)); + } + + void generateDecimatedMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch) + { + singleMaterialPatch->m_vecVertices.clear(); + singleMaterialPatch->m_vecTriangleIndices.clear(); + + //For edge indices + boost::int32_t* vertexIndicesX0 = new boost::int32_t[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + boost::int32_t* vertexIndicesY0 = new boost::int32_t[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + boost::int32_t* vertexIndicesZ0 = new boost::int32_t[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + boost::int32_t* vertexIndicesX1 = new boost::int32_t[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + boost::int32_t* vertexIndicesY1 = new boost::int32_t[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + boost::int32_t* vertexIndicesZ1 = new boost::int32_t[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + + //Cell bitmasks + boost::uint8_t* bitmask0 = new boost::uint8_t[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + boost::uint8_t* bitmask1 = new boost::uint8_t[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + + //When generating the mesh for a region we actually look one voxel outside it in the + // back, bottom, right direction. Protect against access violations by cropping region here + Region regVolume = volumeData->getEnclosingRegion(); + regVolume.setUpperCorner(regVolume.getUpperCorner() - Vector3DInt32(1,1,1)); + region.cropTo(regVolume); + + //Offset from volume corner + const Vector3DFloat offset = static_cast(region.getLowerCorner()); + + //Temporary space use to store the vertices + Vector3DFloat vertlist[12]; + uint8_t vertMaterials[12]; + + //Create a region corresponding to the first slice + Region regSlice0(region); + regSlice0.setUpperCorner(Vector3DInt32(regSlice0.getUpperCorner().getX(),regSlice0.getUpperCorner().getY(),regSlice0.getLowerCorner().getZ())); + + //Iterator to access the volume data + BlockVolumeIterator volIter(*volumeData); + + //Compute bitmask for initial slice + boost::uint32_t uNoOfNonEmptyCellsForSlice0 = computeInitialDecimatedBitmaskForSlice(volIter, regSlice0, offset, bitmask0); + if(uNoOfNonEmptyCellsForSlice0 != 0) + { + //If there were some non-empty cells then generate initial slice vertices for them + generateDecimatedVerticesForSlice(volIter,regSlice0, offset, bitmask0, singleMaterialPatch, vertexIndicesX0, vertexIndicesY0, vertexIndicesZ0, /*regTwoSlice.getUpperCorner(),*/ vertlist, vertMaterials); + } + + for(boost::uint32_t uSlice = 0; ((uSlice <= POLYVOX_REGION_SIDE_LENGTH-1) && (uSlice + offset.getZ() < region.getUpperCorner().getZ())); uSlice += 2) + { + Region regSlice1(regSlice0); + regSlice1.shift(Vector3DInt32(0,0,2)); + + boost::uint32_t uNoOfNonEmptyCellsForSlice1 = computeDecimatedBitmaskForSliceFromPrevious(volIter, regSlice1, offset, bitmask1, bitmask0); + + if(uNoOfNonEmptyCellsForSlice1 != 0) + { + generateDecimatedVerticesForSlice(volIter,regSlice1, offset, bitmask1, singleMaterialPatch, vertexIndicesX1, vertexIndicesY1, vertexIndicesZ1, vertlist, vertMaterials); + } + + if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0)) + { + generateDecimatedIndicesForSlice(volIter, regSlice0, singleMaterialPatch, offset, bitmask0, bitmask1, vertexIndicesX0, vertexIndicesY0, vertexIndicesZ0, vertexIndicesX1, vertexIndicesY1, vertexIndicesZ1); + } + + std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); + std::swap(bitmask0, bitmask1); + std::swap(vertexIndicesX0, vertexIndicesX1); + std::swap(vertexIndicesY0, vertexIndicesY1); + std::swap(vertexIndicesZ0, vertexIndicesZ1); + + regSlice0 = regSlice1; + } + + delete[] bitmask0; + delete[] bitmask1; + delete[] vertexIndicesX0; + delete[] vertexIndicesX1; + delete[] vertexIndicesY0; + delete[] vertexIndicesY1; + delete[] vertexIndicesZ0; + delete[] vertexIndicesZ1; + + + std::vector::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin(); + while(iterSurfaceVertex != singleMaterialPatch->getVertices().end()) + { + Vector3DFloat tempNormal = computeDecimatedNormal(volumeData, static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); + const_cast(*iterSurfaceVertex).setNormal(tempNormal); + ++iterSurfaceVertex; + } + } + + boost::uint32_t computeInitialDecimatedBitmaskForSlice(BlockVolumeIterator& volIter, const Region& regSlice, const Vector3DFloat& offset, uint8_t* bitmask) + { + boost::uint32_t uNoOfNonEmptyCells = 0; + + //Iterate over each cell in the region + //volIter.setPosition(regSlice.getLowerCorner().getX(),regSlice.getLowerCorner().getY(), regSlice.getLowerCorner().getZ()); + //volIter.setValidRegion(regSlice); + //do + for(uint16_t y = regSlice.getLowerCorner().getY(); y < regSlice.getUpperCorner().getY(); y += 2) + { + for(uint16_t x = regSlice.getLowerCorner().getX(); x < regSlice.getUpperCorner().getX(); x += 2) + { + //Current position + //const uint16_t x = volIter.getPosX() - offset.getX(); + //const uint16_t y = volIter.getPosY() - offset.getY(); + volIter.setPosition(x,y,regSlice.getLowerCorner().getZ()); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = 0; + + if((x==regSlice.getLowerCorner().getX()) && (y==regSlice.getLowerCorner().getY())) + { + volIter.setPosition(x,y,regSlice.getLowerCorner().getZ()); + const uint8_t v000 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y,regSlice.getLowerCorner().getZ()); + const uint8_t v100 = volIter.getMaxedVoxel(); + volIter.setPosition(x,y+2,regSlice.getLowerCorner().getZ()); + const uint8_t v010 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()); + const uint8_t v110 = volIter.getMaxedVoxel(); + + volIter.setPosition(x,y,regSlice.getLowerCorner().getZ()+2); + const uint8_t v001 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y,regSlice.getLowerCorner().getZ()+2); + const uint8_t v101 = volIter.getMaxedVoxel(); + volIter.setPosition(x,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v011 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + if (v000 == 0) iCubeIndex |= 1; + if (v100 == 0) iCubeIndex |= 2; + if (v110 == 0) iCubeIndex |= 4; + if (v010 == 0) iCubeIndex |= 8; + if (v001 == 0) iCubeIndex |= 16; + if (v101 == 0) iCubeIndex |= 32; + if (v111 == 0) iCubeIndex |= 64; + if (v011 == 0) iCubeIndex |= 128; + } + else if((x>regSlice.getLowerCorner().getX()) && y==regSlice.getLowerCorner().getY()) + { + volIter.setPosition(x+2,y,regSlice.getLowerCorner().getZ()); + const uint8_t v100 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()); + const uint8_t v110 = volIter.getMaxedVoxel(); + + volIter.setPosition(x+2,y,regSlice.getLowerCorner().getZ()+2); + const uint8_t v101 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + //x + uint8_t iPreviousCubeIndexX = bitmask[getDecimatedIndex(x- offset.getX()-2,y- offset.getY())]; + uint8_t srcBit6 = iPreviousCubeIndexX & 64; + uint8_t destBit7 = srcBit6 << 1; + + uint8_t srcBit5 = iPreviousCubeIndexX & 32; + uint8_t destBit4 = srcBit5 >> 1; + + uint8_t srcBit2 = iPreviousCubeIndexX & 4; + uint8_t destBit3 = srcBit2 << 1; + + uint8_t srcBit1 = iPreviousCubeIndexX & 2; + uint8_t destBit0 = srcBit1 >> 1; + + iCubeIndex |= destBit0; + if (v100 == 0) iCubeIndex |= 2; + if (v110 == 0) iCubeIndex |= 4; + iCubeIndex |= destBit3; + iCubeIndex |= destBit4; + if (v101 == 0) iCubeIndex |= 32; + if (v111 == 0) iCubeIndex |= 64; + iCubeIndex |= destBit7; + } + else if((x==regSlice.getLowerCorner().getX()) && (y>regSlice.getLowerCorner().getY())) + { + volIter.setPosition(x,y+2,regSlice.getLowerCorner().getZ()); + const uint8_t v010 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()); + const uint8_t v110 = volIter.getMaxedVoxel(); + + volIter.setPosition(x,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v011 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + //y + uint8_t iPreviousCubeIndexY = bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY()-2)]; + uint8_t srcBit7 = iPreviousCubeIndexY & 128; + uint8_t destBit4 = srcBit7 >> 3; + + uint8_t srcBit6 = iPreviousCubeIndexY & 64; + uint8_t destBit5 = srcBit6 >> 1; + + uint8_t srcBit3 = iPreviousCubeIndexY & 8; + uint8_t destBit0 = srcBit3 >> 3; + + uint8_t srcBit2 = iPreviousCubeIndexY & 4; + uint8_t destBit1 = srcBit2 >> 1; + + iCubeIndex |= destBit0; + iCubeIndex |= destBit1; + if (v110 == 0) iCubeIndex |= 4; + if (v010 == 0) iCubeIndex |= 8; + iCubeIndex |= destBit4; + iCubeIndex |= destBit5; + if (v111 == 0) iCubeIndex |= 64; + if (v011 == 0) iCubeIndex |= 128; + } + else + { + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()); + const uint8_t v110 = volIter.getMaxedVoxel(); + + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + //y + uint8_t iPreviousCubeIndexY = bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY()-2)]; + uint8_t srcBit7 = iPreviousCubeIndexY & 128; + uint8_t destBit4 = srcBit7 >> 3; + + uint8_t srcBit6 = iPreviousCubeIndexY & 64; + uint8_t destBit5 = srcBit6 >> 1; + + uint8_t srcBit3 = iPreviousCubeIndexY & 8; + uint8_t destBit0 = srcBit3 >> 3; + + uint8_t srcBit2 = iPreviousCubeIndexY & 4; + uint8_t destBit1 = srcBit2 >> 1; + + //x + uint8_t iPreviousCubeIndexX = bitmask[getDecimatedIndex(x- offset.getX()-2,y- offset.getY())]; + srcBit6 = iPreviousCubeIndexX & 64; + uint8_t destBit7 = srcBit6 << 1; + + srcBit2 = iPreviousCubeIndexX & 4; + uint8_t destBit3 = srcBit2 << 1; + + iCubeIndex |= destBit0; + iCubeIndex |= destBit1; + if (v110 == 0) iCubeIndex |= 4; + iCubeIndex |= destBit3; + iCubeIndex |= destBit4; + iCubeIndex |= destBit5; + if (v111 == 0) iCubeIndex |= 64; + iCubeIndex |= destBit7; + } + + //Save the bitmask + bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())] = iCubeIndex; + + if(edgeTable[iCubeIndex] != 0) + { + ++uNoOfNonEmptyCells; + } + + }//while(volIter.moveForwardInRegionXYZ());//For each cell + } + + return uNoOfNonEmptyCells; + } + + boost::uint32_t computeDecimatedBitmaskForSliceFromPrevious(BlockVolumeIterator& volIter, const Region& regSlice, const Vector3DFloat& offset, uint8_t* bitmask, uint8_t* previousBitmask) + { + boost::uint32_t uNoOfNonEmptyCells = 0; + + //Iterate over each cell in the region + //volIter.setPosition(regSlice.getLowerCorner().getX(),regSlice.getLowerCorner().getY(), regSlice.getLowerCorner().getZ()); + //volIter.setValidRegion(regSlice); + //do + for(uint16_t y = regSlice.getLowerCorner().getY(); y < regSlice.getUpperCorner().getY(); y += 2) + { + for(uint16_t x = regSlice.getLowerCorner().getX(); x < regSlice.getUpperCorner().getX(); x += 2) + { + //Current position + //const uint16_t x = volIter.getPosX() - offset.getX(); + //const uint16_t y = volIter.getPosY() - offset.getY(); + volIter.setPosition(x,y,regSlice.getLowerCorner().getZ()); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = 0; + + if((x==regSlice.getLowerCorner().getX()) && (y==regSlice.getLowerCorner().getY())) + { + volIter.setPosition(x,y,regSlice.getLowerCorner().getZ()+2); + const uint8_t v001 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y,regSlice.getLowerCorner().getZ()+2); + const uint8_t v101 = volIter.getMaxedVoxel(); + volIter.setPosition(x,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v011 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + //z + uint8_t iPreviousCubeIndexZ = previousBitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + if (v001 == 0) iCubeIndex |= 16; + if (v101 == 0) iCubeIndex |= 32; + if (v111 == 0) iCubeIndex |= 64; + if (v011 == 0) iCubeIndex |= 128; + } + else if((x>regSlice.getLowerCorner().getX()) && y==regSlice.getLowerCorner().getY()) + { + volIter.setPosition(x+2,y,regSlice.getLowerCorner().getZ()+2); + const uint8_t v101 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + //z + uint8_t iPreviousCubeIndexZ = previousBitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //x + uint8_t iPreviousCubeIndexX = bitmask[getDecimatedIndex(x- offset.getX()-2,y- offset.getY())]; + uint8_t srcBit6 = iPreviousCubeIndexX & 64; + uint8_t destBit7 = srcBit6 << 1; + + uint8_t srcBit5 = iPreviousCubeIndexX & 32; + uint8_t destBit4 = srcBit5 >> 1; + + iCubeIndex |= destBit4; + if (v101 == 0) iCubeIndex |= 32; + if (v111 == 0) iCubeIndex |= 64; + iCubeIndex |= destBit7; + } + else if((x==regSlice.getLowerCorner().getX()) && (y>regSlice.getLowerCorner().getY())) + { + volIter.setPosition(x,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v011 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + //z + uint8_t iPreviousCubeIndexZ = previousBitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //y + uint8_t iPreviousCubeIndexY = bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY()-2)]; + uint8_t srcBit7 = iPreviousCubeIndexY & 128; + uint8_t destBit4 = srcBit7 >> 3; + + uint8_t srcBit6 = iPreviousCubeIndexY & 64; + uint8_t destBit5 = srcBit6 >> 1; + + iCubeIndex |= destBit4; + iCubeIndex |= destBit5; + if (v111 == 0) iCubeIndex |= 64; + if (v011 == 0) iCubeIndex |= 128; + } + else + { + volIter.setPosition(x+2,y+2,regSlice.getLowerCorner().getZ()+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + //z + uint8_t iPreviousCubeIndexZ = previousBitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //y + uint8_t iPreviousCubeIndexY = bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY()-2)]; + uint8_t srcBit7 = iPreviousCubeIndexY & 128; + uint8_t destBit4 = srcBit7 >> 3; + + uint8_t srcBit6 = iPreviousCubeIndexY & 64; + uint8_t destBit5 = srcBit6 >> 1; + + //x + uint8_t iPreviousCubeIndexX = bitmask[getDecimatedIndex(x- offset.getX()-2,y- offset.getY())]; + srcBit6 = iPreviousCubeIndexX & 64; + uint8_t destBit7 = srcBit6 << 1; + + iCubeIndex |= destBit4; + iCubeIndex |= destBit5; + if (v111 == 0) iCubeIndex |= 64; + iCubeIndex |= destBit7; + } + + //Save the bitmask + bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())] = iCubeIndex; + + if(edgeTable[iCubeIndex] != 0) + { + ++uNoOfNonEmptyCells; + } + + }//while(volIter.moveForwardInRegionXYZ());//For each cell + } + + return uNoOfNonEmptyCells; + } + + void generateDecimatedVerticesForSlice(BlockVolumeIterator& volIter, Region& regSlice, const Vector3DFloat& offset, uint8_t* bitmask, IndexedSurfacePatch* singleMaterialPatch,boost::int32_t vertexIndicesX[],boost::int32_t vertexIndicesY[],boost::int32_t vertexIndicesZ[], Vector3DFloat vertlist[], uint8_t vertMaterials[]) + { + //Iterate over each cell in the region + //volIter.setPosition(regSlice.getLowerCorner().getX(),regSlice.getLowerCorner().getY(), regSlice.getLowerCorner().getZ()); + //volIter.setValidRegion(regSlice); + //while(volIter.moveForwardInRegionXYZ()) + //do + for(uint16_t y = regSlice.getLowerCorner().getY(); y < regSlice.getUpperCorner().getY(); y += 2) + { + for(uint16_t x = regSlice.getLowerCorner().getX(); x < regSlice.getUpperCorner().getX(); x += 2) + { + //Current position + //const uint16_t x = volIter.getPosX() - offset.getX(); + //const uint16_t y = volIter.getPosY() - offset.getY(); + const uint16_t z = regSlice.getLowerCorner().getZ(); + + volIter.setPosition(x,y,z); + const uint8_t v000 = volIter.getMaxedVoxel(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = bitmask[getDecimatedIndex(x - offset.getX(),y - offset.getY())]; + + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] == 0) + { + continue; + } + + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) + { + if((x) != regSlice.getUpperCorner().getX()) + { + vertlist[0].setX(x - offset.getX() + 0.5f * 2.0f); + vertlist[0].setY(y - offset.getY()); + vertlist[0].setZ(z - offset.getZ()); + volIter.setPosition(x+2,y,z); + vertMaterials[0] = v000 | volIter.getMaxedVoxel(); //Because one of these is 0, the or operation takes the max. + SurfaceVertex surfaceVertex(vertlist[0],vertMaterials[0], 1.0); + singleMaterialPatch->m_vecVertices.push_back(surfaceVertex); + vertexIndicesX[getDecimatedIndex(x - offset.getX(),y - offset.getY())] = singleMaterialPatch->m_vecVertices.size()-1; + } + } + if (edgeTable[iCubeIndex] & 8) + { + if((y) != regSlice.getUpperCorner().getY()) + { + vertlist[3].setX(x - offset.getX()); + vertlist[3].setY(y - offset.getY() + 0.5f * 2.0f); + vertlist[3].setZ(z - offset.getZ()); + volIter.setPosition(x,y+2,z); + vertMaterials[3] = v000 | volIter.getMaxedVoxel(); + SurfaceVertex surfaceVertex(vertlist[3],vertMaterials[3], 1.0); + singleMaterialPatch->m_vecVertices.push_back(surfaceVertex); + vertexIndicesY[getDecimatedIndex(x - offset.getX(),y - offset.getY())] = singleMaterialPatch->m_vecVertices.size()-1; + } + } + if (edgeTable[iCubeIndex] & 256) + { + //if((z + offset.getZ()) != upperCorner.getZ()) + { + vertlist[8].setX(x - offset.getX()); + vertlist[8].setY(y - offset.getY()); + vertlist[8].setZ(z - offset.getZ() + 0.5f * 2.0f); + volIter.setPosition(x,y,z+2); + vertMaterials[8] = v000 | volIter.getMaxedVoxel(); + SurfaceVertex surfaceVertex(vertlist[8],vertMaterials[8], 1.0); + singleMaterialPatch->m_vecVertices.push_back(surfaceVertex); + vertexIndicesZ[getDecimatedIndex(x - offset.getX(),y - offset.getY())] = singleMaterialPatch->m_vecVertices.size()-1; + } + } + }//while(volIter.moveForwardInRegionXYZ());//For each cell + } + } + + void generateDecimatedIndicesForSlice(BlockVolumeIterator& volIter, const Region& regSlice, IndexedSurfacePatch* singleMaterialPatch, const Vector3DFloat& offset, uint8_t* bitmask0, uint8_t* bitmask1, boost::int32_t vertexIndicesX0[],boost::int32_t vertexIndicesY0[],boost::int32_t vertexIndicesZ0[], boost::int32_t vertexIndicesX1[],boost::int32_t vertexIndicesY1[],boost::int32_t vertexIndicesZ1[]) + { + boost::uint32_t indlist[12]; + + Region regCroppedSlice(regSlice); + regCroppedSlice.setUpperCorner(regCroppedSlice.getUpperCorner() - Vector3DInt32(2,2,0)); + + //volIter.setPosition(regCroppedSlice.getLowerCorner().getX(),regCroppedSlice.getLowerCorner().getY(), regCroppedSlice.getLowerCorner().getZ()); + //volIter.setValidRegion(regCroppedSlice); + //do + for(uint16_t y = regCroppedSlice.getLowerCorner().getY() - offset.getY(); y < regCroppedSlice.getUpperCorner().getY() - offset.getY(); y += 2) + { + for(uint16_t x = regCroppedSlice.getLowerCorner().getX() - offset.getX(); x < regCroppedSlice.getUpperCorner().getX() - offset.getX(); x += 2) + { + //Current position + //const uint16_t x = volIter.getPosX() - offset.getX(); + //const uint16_t y = volIter.getPosY() - offset.getY(); + const uint16_t z = regCroppedSlice.getLowerCorner().getZ() - offset.getZ(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = bitmask0[getDecimatedIndex(x,y)]; + + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] == 0) + { + continue; + } + + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) + { + indlist[0] = vertexIndicesX0[getDecimatedIndex(x,y)]; + assert(indlist[0] != -1); + } + if (edgeTable[iCubeIndex] & 2) + { + indlist[1] = vertexIndicesY0[getDecimatedIndex(x+2,y)]; + assert(indlist[1] != -1); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = vertexIndicesX0[getDecimatedIndex(x,y+2)]; + assert(indlist[2] != -1); + } + if (edgeTable[iCubeIndex] & 8) + { + indlist[3] = vertexIndicesY0[getDecimatedIndex(x,y)]; + assert(indlist[3] != -1); + } + if (edgeTable[iCubeIndex] & 16) + { + indlist[4] = vertexIndicesX1[getDecimatedIndex(x,y)]; + assert(indlist[4] != -1); + } + if (edgeTable[iCubeIndex] & 32) + { + indlist[5] = vertexIndicesY1[getDecimatedIndex(x+2,y)]; + assert(indlist[5] != -1); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = vertexIndicesX1[getDecimatedIndex(x,y+2)]; + assert(indlist[6] != -1); + } + if (edgeTable[iCubeIndex] & 128) + { + indlist[7] = vertexIndicesY1[getDecimatedIndex(x,y)]; + assert(indlist[7] != -1); + } + if (edgeTable[iCubeIndex] & 256) + { + indlist[8] = vertexIndicesZ0[getDecimatedIndex(x,y)]; + assert(indlist[8] != -1); + } + if (edgeTable[iCubeIndex] & 512) + { + indlist[9] = vertexIndicesZ0[getDecimatedIndex(x+2,y)]; + assert(indlist[9] != -1); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = vertexIndicesZ0[getDecimatedIndex(x+2,y+2)]; + assert(indlist[10] != -1); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = vertexIndicesZ0[getDecimatedIndex(x,y+2)]; + assert(indlist[11] != -1); + } + + for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) + { + boost::uint32_t ind0 = indlist[triTable[iCubeIndex][i ]]; + boost::uint32_t ind1 = indlist[triTable[iCubeIndex][i+1]]; + boost::uint32_t ind2 = indlist[triTable[iCubeIndex][i+2]]; + + singleMaterialPatch->m_vecTriangleIndices.push_back(ind0); + singleMaterialPatch->m_vecTriangleIndices.push_back(ind1); + singleMaterialPatch->m_vecTriangleIndices.push_back(ind2); + }//For each triangle + }//while(volIter.moveForwardInRegionXYZ());//For each cell + } + } + + void generateDecimatedMeshDataForRegionSlow(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch) + { + //When generating the mesh for a region we actually look one voxel outside it in the + // back, bottom, right direction. Protect against access violations by cropping region here + Region regVolume = volumeData->getEnclosingRegion(); + //regVolume.setUpperCorner(regVolume.getUpperCorner() - Vector3DInt32(1,1,1)); + region.cropTo(regVolume); + region.setUpperCorner(region.getUpperCorner() - Vector3DInt32(1,1,1)); + + //Offset from lower block corner + const Vector3DFloat offset = static_cast(region.getLowerCorner()); + + Vector3DFloat vertlist[12]; + Vector3DFloat normlist[12]; + uint8_t vertMaterials[12]; + BlockVolumeIterator volIter(*volumeData); + volIter.setValidRegion(region); + + ////////////////////////////////////////////////////////////////////////// + //Get mesh data + ////////////////////////////////////////////////////////////////////////// + + //Iterate over each cell in the region + //volIter.setPosition(region.getLowerCorner().getX(),region.getLowerCorner().getY(), region.getLowerCorner().getZ()); + for(uint16_t z = region.getLowerCorner().getZ(); z <= region.getUpperCorner().getZ(); z += 2) + { + for(uint16_t y = region.getLowerCorner().getY(); y <= region.getUpperCorner().getY(); y += 2) + { + for(uint16_t x = region.getLowerCorner().getX(); x <= region.getUpperCorner().getX(); x += 2) + { + //while(volIter.moveForwardInRegionXYZ()) + //{ + volIter.setPosition(x,y,z); + const uint8_t v000 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y,z); + const uint8_t v100 = volIter.getMaxedVoxel(); + volIter.setPosition(x,y+2,z); + const uint8_t v010 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,z); + const uint8_t v110 = volIter.getMaxedVoxel(); + volIter.setPosition(x,y,z+2); + const uint8_t v001 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y,z+2); + const uint8_t v101 = volIter.getMaxedVoxel(); + volIter.setPosition(x,y+2,z+2); + const uint8_t v011 = volIter.getMaxedVoxel(); + volIter.setPosition(x+2,y+2,z+2); + const uint8_t v111 = volIter.getMaxedVoxel(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = 0; + + if (v000 == 0) iCubeIndex |= 1; + if (v100 == 0) iCubeIndex |= 2; + if (v110 == 0) iCubeIndex |= 4; + if (v010 == 0) iCubeIndex |= 8; + if (v001 == 0) iCubeIndex |= 16; + if (v101 == 0) iCubeIndex |= 32; + if (v111 == 0) iCubeIndex |= 64; + if (v011 == 0) iCubeIndex |= 128; + + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] == 0) + { + continue; + } + + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) + { + vertlist[0].setX(x + 0.5f * 2.0f); + vertlist[0].setY(y); + vertlist[0].setZ(z); + normlist[0] = Vector3DFloat(v000 - v100,0.0,0.0); + vertMaterials[0] = v000 | v100; //Because one of these is 0, the or operation takes the max. + } + if (edgeTable[iCubeIndex] & 2) + { + vertlist[1].setX(x + 1.0f * 2.0f); + vertlist[1].setY(y + 0.5f * 2.0f); + vertlist[1].setZ(z); + vertMaterials[1] = v100 | v110; + normlist[1] = Vector3DFloat(0.0,v100 - v110,0.0); + } + if (edgeTable[iCubeIndex] & 4) + { + vertlist[2].setX(x + 0.5f * 2.0f); + vertlist[2].setY(y + 1.0f * 2.0f); + vertlist[2].setZ(z); + vertMaterials[2] = v010 | v110; + normlist[2] = Vector3DFloat(v010 - v110,0.0,0.0); + } + if (edgeTable[iCubeIndex] & 8) + { + vertlist[3].setX(x); + vertlist[3].setY(y + 0.5f * 2.0f); + vertlist[3].setZ(z); + vertMaterials[3] = v000 | v010; + normlist[3] = Vector3DFloat(0.0,v000 - v010,0.0); + } + if (edgeTable[iCubeIndex] & 16) + { + vertlist[4].setX(x + 0.5f * 2.0f); + vertlist[4].setY(y); + vertlist[4].setZ(z + 1.0f * 2.0f); + vertMaterials[4] = v001 | v101; + normlist[4] = Vector3DFloat(v001 - v101,0.0,0.0); + } + if (edgeTable[iCubeIndex] & 32) + { + vertlist[5].setX(x + 1.0f * 2.0f); + vertlist[5].setY(y + 0.5f * 2.0f); + vertlist[5].setZ(z + 1.0f * 2.0f); + vertMaterials[5] = v101 | v111; + normlist[5] = Vector3DFloat(0.0,v101 - v111,0.0); + } + if (edgeTable[iCubeIndex] & 64) + { + vertlist[6].setX(x + 0.5f * 2.0f); + vertlist[6].setY(y + 1.0f * 2.0f); + vertlist[6].setZ(z + 1.0f * 2.0f); + vertMaterials[6] = v011 | v111; + normlist[6] = Vector3DFloat(v011 - v111,0.0,0.0); + } + if (edgeTable[iCubeIndex] & 128) + { + vertlist[7].setX(x); + vertlist[7].setY(y + 0.5f * 2.0f); + vertlist[7].setZ(z + 1.0f * 2.0f); + vertMaterials[7] = v001 | v011; + normlist[7] = Vector3DFloat(0.0,v001 - v011,0.0); + } + if (edgeTable[iCubeIndex] & 256) + { + vertlist[8].setX(x); + vertlist[8].setY(y); + vertlist[8].setZ(z + 0.5f * 2.0f); + vertMaterials[8] = v000 | v001; + normlist[8] = Vector3DFloat(0.0,0.0,v000 - v001); + } + if (edgeTable[iCubeIndex] & 512) + { + vertlist[9].setX(x + 1.0f * 2.0f); + vertlist[9].setY(y); + vertlist[9].setZ(z + 0.5f * 2.0f); + vertMaterials[9] = v100 | v101; + normlist[9] = Vector3DFloat(0.0,0.0,v100 - v101); + } + if (edgeTable[iCubeIndex] & 1024) + { + vertlist[10].setX(x + 1.0f * 2.0f); + vertlist[10].setY(y + 1.0f * 2.0f); + vertlist[10].setZ(z + 0.5f * 2.0f); + vertMaterials[10] = v110 | v111; + normlist[10] = Vector3DFloat(0.0,0.0,v110 - v111); + } + if (edgeTable[iCubeIndex] & 2048) + { + vertlist[11].setX(x); + vertlist[11].setY(y + 1.0f * 2.0f); + vertlist[11].setZ(z + 0.5f * 2.0f); + vertMaterials[11] = v010 | v011; + normlist[11] = Vector3DFloat(0.0,0.0,v010 - v011); + } + + for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) + { + //The three vertices forming a triangle + Vector3DFloat vertex0 = vertlist[triTable[iCubeIndex][i ]] - offset; + Vector3DFloat vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset; + Vector3DFloat vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset; + + Vector3DFloat normal0 = normlist[triTable[iCubeIndex][i ]]; + Vector3DFloat normal1 = normlist[triTable[iCubeIndex][i+1]]; + Vector3DFloat normal2 = normlist[triTable[iCubeIndex][i+2]]; + + normal0.normalise(); + normal1.normalise(); + normal2.normalise(); + + vertex0 += (normal0); + vertex1 += (normal1); + vertex2 += (normal2); + + //Cast to floats and divide by two. + //const Vector3DFloat vertex0AsFloat = (static_cast(vertex0) / 2.0f) - offset; + //const Vector3DFloat vertex1AsFloat = (static_cast(vertex1) / 2.0f) - offset; + //const Vector3DFloat vertex2AsFloat = (static_cast(vertex2) / 2.0f) - offset; + + const uint8_t material0 = vertMaterials[triTable[iCubeIndex][i ]]; + const uint8_t material1 = vertMaterials[triTable[iCubeIndex][i+1]]; + const uint8_t material2 = vertMaterials[triTable[iCubeIndex][i+2]]; + + + //If all the materials are the same, we just need one triangle for that material with all the alphas set high. + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); + surfaceVertex0Alpha1.setNormal(normal0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); + surfaceVertex1Alpha1.setNormal(normal1); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); + surfaceVertex2Alpha1.setNormal(normal2); + singleMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + }//For each triangle + //}//For each cell + } + } + } + + //FIXME - can it happen that we have no vertices or triangles? Should exit early? + + + //for(std::map::iterator iterPatch = surfacePatchMapResult.begin(); iterPatch != surfacePatchMapResult.end(); ++iterPatch) + { + + /*std::vector::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin(); + while(iterSurfaceVertex != singleMaterialPatch->getVertices().end()) + { + Vector3DFloat tempNormal = computeNormal(volumeData, static_cast(iterSurfaceVertex->getPosition() + offset), SIMPLE); + const_cast(*iterSurfaceVertex).setNormal(tempNormal); + ++iterSurfaceVertex; + }*/ + } + } + + Vector3DFloat computeDecimatedNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) + { + const float posX = position.getX(); + const float posY = position.getY(); + const float posZ = position.getZ(); + + const uint16_t floorX = static_cast(posX); + const uint16_t floorY = static_cast(posY); + const uint16_t floorZ = static_cast(posZ); + + //Check all corners are within the volume, allowing a boundary for gradient estimation + bool lowerCornerInside = volumeData->containsPoint(Vector3DInt32(floorX, floorY, floorZ),1); + bool upperCornerInside = volumeData->containsPoint(Vector3DInt32(floorX+1, floorY+1, floorZ+1),1); + if((!lowerCornerInside) || (!upperCornerInside)) + { + normalGenerationMethod = SIMPLE; + } + + Vector3DFloat result; + + BlockVolumeIterator volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create? + + + if(normalGenerationMethod == SOBEL) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const Vector3DFloat gradFloor = computeSobelGradient(volIter); + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); + } + if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); + } + if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); + } + const Vector3DFloat gradCeil = computeSobelGradient(volIter); + result = ((gradFloor + gradCeil) * -1.0f); + if(result.lengthSquared() < 0.0001) + { + //Operation failed - fall back on simple gradient estimation + normalGenerationMethod = SIMPLE; + } + } + if(normalGenerationMethod == CENTRAL_DIFFERENCE) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const Vector3DFloat gradFloor = computeCentralDifferenceGradient(volIter); + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); + } + if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); + } + if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); + } + const Vector3DFloat gradCeil = computeCentralDifferenceGradient(volIter); + result = ((gradFloor + gradCeil) * -1.0f); + if(result.lengthSquared() < 0.0001) + { + //Operation failed - fall back on simple gradient estimation + normalGenerationMethod = SIMPLE; + } + } + if(normalGenerationMethod == SIMPLE) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const uint8_t uFloor = volIter.getVoxel() > 0 ? 1 : 0; + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel1px0py0pz() > 0 ? 1 : 0; + result = Vector3DFloat(static_cast(uFloor - uCeil),0.0,0.0); + } + else if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel0px1py0pz() > 0 ? 1 : 0; + result = Vector3DFloat(0.0,static_cast(uFloor - uCeil),0.0); + } + else if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0; + result = Vector3DFloat(0.0, 0.0,static_cast(uFloor - uCeil)); + } + } + return result; + } +}