From 29ef5f021ed835671ae88e7a7356fde08d97b83c Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 3 Jul 2008 19:17:17 +0000 Subject: [PATCH] Rearranging files in PolyVox. --- CMakeLists.txt | 7 +- examples/OpenGL/CMakeLists.txt | 4 +- examples/OpenGL/main.cpp | 10 +- library/CMakeLists.txt | 113 +++ library/include/PolyVoxCore/Block.h | 61 ++ library/include/PolyVoxCore/Block.inl | 124 +++ library/include/PolyVoxCore/BlockVolume.h | 86 ++ library/include/PolyVoxCore/BlockVolume.inl | 231 +++++ .../include/PolyVoxCore/BlockVolumeIterator.h | 138 +++ .../PolyVoxCore/BlockVolumeIterator.inl | 684 ++++++++++++++ library/include/PolyVoxCore/Constants.h | 45 + library/include/PolyVoxCore/Enums.h | 35 + .../include/PolyVoxCore/GradientEstimators.h | 49 + .../PolyVoxCore/GradientEstimators.inl | 185 ++++ .../include/PolyVoxCore/IndexedSurfacePatch.h | 59 ++ library/include/PolyVoxCore/LinearVolume.h | 64 ++ library/include/PolyVoxCore/LinearVolume.inl | 102 ++ .../include/PolyVoxCore/MarchingCubesTables.h | 31 + library/include/PolyVoxCore/PolyVoxCStdInt.h | 38 + .../PolyVoxCore/PolyVoxForwardDeclarations.h | 61 ++ library/include/PolyVoxCore/Region.h | 55 ++ library/include/PolyVoxCore/RegionGeometry.h | 44 + .../include/PolyVoxCore/SurfaceAdjusters.h | 39 + library/include/PolyVoxCore/SurfaceEdge.h | 65 ++ .../include/PolyVoxCore/SurfaceExtractors.h | 51 + .../PolyVoxCore/SurfaceExtractorsDecimated.h | 50 + library/include/PolyVoxCore/SurfaceTriangle.h | 50 + library/include/PolyVoxCore/SurfaceTypes.h | 19 + library/include/PolyVoxCore/SurfaceVertex.h | 60 ++ library/include/PolyVoxCore/TypeDef.h | 37 + library/include/PolyVoxCore/Utility.h | 60 ++ library/include/PolyVoxCore/Vector.h | 150 +++ library/include/PolyVoxCore/Vector.inl | 536 +++++++++++ library/include/PolyVoxCore/VoxelFilters.h | 36 + .../include/PolyVoxUtil/VolumeChangeTracker.h | 69 ++ .../source/PolyVoxCore/GradientEstimators.cpp | 174 ++++ .../PolyVoxCore/IndexedSurfacePatch.cpp | 106 +++ .../PolyVoxCore/MarchingCubesTables.cpp | 326 +++++++ library/source/PolyVoxCore/Region.cpp | 72 ++ library/source/PolyVoxCore/RegionGeometry.cpp | 30 + .../source/PolyVoxCore/SurfaceAdjusters.cpp | 151 +++ library/source/PolyVoxCore/SurfaceEdge.cpp | 106 +++ .../source/PolyVoxCore/SurfaceExtractors.cpp | 853 +++++++++++++++++ .../SurfaceExtractorsDecimated.cpp | 892 ++++++++++++++++++ .../source/PolyVoxCore/SurfaceTriangle.cpp | 59 ++ library/source/PolyVoxCore/SurfaceVertex.cpp | 83 ++ library/source/PolyVoxCore/Utility.cpp | 51 + library/source/PolyVoxCore/VoxelFilters.cpp | 51 + .../PolyVoxUtil/VolumeChangeTracker.cpp | 231 +++++ 49 files changed, 6623 insertions(+), 10 deletions(-) create mode 100644 library/CMakeLists.txt create mode 100644 library/include/PolyVoxCore/Block.h create mode 100644 library/include/PolyVoxCore/Block.inl create mode 100644 library/include/PolyVoxCore/BlockVolume.h create mode 100644 library/include/PolyVoxCore/BlockVolume.inl create mode 100644 library/include/PolyVoxCore/BlockVolumeIterator.h create mode 100644 library/include/PolyVoxCore/BlockVolumeIterator.inl create mode 100644 library/include/PolyVoxCore/Constants.h create mode 100644 library/include/PolyVoxCore/Enums.h create mode 100644 library/include/PolyVoxCore/GradientEstimators.h create mode 100644 library/include/PolyVoxCore/GradientEstimators.inl create mode 100644 library/include/PolyVoxCore/IndexedSurfacePatch.h create mode 100644 library/include/PolyVoxCore/LinearVolume.h create mode 100644 library/include/PolyVoxCore/LinearVolume.inl create mode 100644 library/include/PolyVoxCore/MarchingCubesTables.h create mode 100644 library/include/PolyVoxCore/PolyVoxCStdInt.h create mode 100644 library/include/PolyVoxCore/PolyVoxForwardDeclarations.h create mode 100644 library/include/PolyVoxCore/Region.h create mode 100644 library/include/PolyVoxCore/RegionGeometry.h create mode 100644 library/include/PolyVoxCore/SurfaceAdjusters.h create mode 100644 library/include/PolyVoxCore/SurfaceEdge.h create mode 100644 library/include/PolyVoxCore/SurfaceExtractors.h create mode 100644 library/include/PolyVoxCore/SurfaceExtractorsDecimated.h create mode 100644 library/include/PolyVoxCore/SurfaceTriangle.h create mode 100644 library/include/PolyVoxCore/SurfaceTypes.h create mode 100644 library/include/PolyVoxCore/SurfaceVertex.h create mode 100644 library/include/PolyVoxCore/TypeDef.h create mode 100644 library/include/PolyVoxCore/Utility.h create mode 100644 library/include/PolyVoxCore/Vector.h create mode 100644 library/include/PolyVoxCore/Vector.inl create mode 100644 library/include/PolyVoxCore/VoxelFilters.h create mode 100644 library/include/PolyVoxUtil/VolumeChangeTracker.h create mode 100644 library/source/PolyVoxCore/GradientEstimators.cpp create mode 100644 library/source/PolyVoxCore/IndexedSurfacePatch.cpp create mode 100644 library/source/PolyVoxCore/MarchingCubesTables.cpp create mode 100644 library/source/PolyVoxCore/Region.cpp create mode 100644 library/source/PolyVoxCore/RegionGeometry.cpp create mode 100644 library/source/PolyVoxCore/SurfaceAdjusters.cpp create mode 100644 library/source/PolyVoxCore/SurfaceEdge.cpp create mode 100644 library/source/PolyVoxCore/SurfaceExtractors.cpp create mode 100644 library/source/PolyVoxCore/SurfaceExtractorsDecimated.cpp create mode 100644 library/source/PolyVoxCore/SurfaceTriangle.cpp create mode 100644 library/source/PolyVoxCore/SurfaceVertex.cpp create mode 100644 library/source/PolyVoxCore/Utility.cpp create mode 100644 library/source/PolyVoxCore/VoxelFilters.cpp create mode 100644 library/source/PolyVoxUtil/VolumeChangeTracker.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 48b62a80..c8a24dbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,9 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(PolyVox) -ADD_SUBDIRECTORY(PolyVoxCore) -ADD_SUBDIRECTORY(PolyVoxUtil) +#ADD_SUBDIRECTORY(PolyVoxCore) +#ADD_SUBDIRECTORY(PolyVoxUtil) +ADD_SUBDIRECTORY(library) ADD_SUBDIRECTORY(examples/OpenGL) -ADD_DEPENDENCIES(OpenGLExample PolyVoxCore PolyVoxUtil) \ No newline at end of file +ADD_DEPENDENCIES(OpenGLExample PolyVoxCore) \ No newline at end of file diff --git a/examples/OpenGL/CMakeLists.txt b/examples/OpenGL/CMakeLists.txt index 407caa8c..2cc544c9 100644 --- a/examples/OpenGL/CMakeLists.txt +++ b/examples/OpenGL/CMakeLists.txt @@ -26,9 +26,9 @@ IF (WIN32) #Also, glut32.dll goes in C:\Windows\System. Using C:\Windows\System32 doesn't seem to work #Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location) - INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} "../../PolyVoxCore/include") + INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} "../../library/include") #No idea why we have to look three levels up for build and only two for include. They should be the same level?! - LINK_DIRECTORIES("../../../build/PolyVoxCore") + LINK_DIRECTORIES("../../../build/library") #Build ADD_EXECUTABLE(OpenGLExample ${SRC_FILES}) diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index 64308b71..f43c60be 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -1,8 +1,8 @@ -#include "BlockVolume.h" -#include "BlockVolumeIterator.h" -#include "IndexedSurfacePatch.h" -#include "SurfaceExtractors.h" -#include "Utility.h" +#include "PolyVoxCore/BlockVolume.h" +#include "PolyVoxCore/BlockVolumeIterator.h" +#include "PolyVoxCore/IndexedSurfacePatch.h" +#include "PolyVoxCore/SurfaceExtractors.h" +#include "PolyVoxCore/Utility.h" #include // Standard Header For Most Programs #include // The GL Header File diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt new file mode 100644 index 00000000..b8054add --- /dev/null +++ b/library/CMakeLists.txt @@ -0,0 +1,113 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +PROJECT(PolyVoxCore) + +SET(POLYVOX_VERSION_MAJOR "0") +SET(POLYVOX_VERSION_MINOR "1") +SET(POLYVOX_VERSION_PATCH "0") +SET(POLYVOX_VERSION "${POLYVOX_VERSION_MAJOR}.${POLYVOX_VERSION_MINOR}.${POLYVOX_VERSION_PATCH}") + +#Projects source files +SET(CORE_SRC_FILES + source/PolyVoxCore/GradientEstimators.cpp + source/PolyVoxCore/IndexedSurfacePatch.cpp + source/PolyVoxCore/MarchingCubesTables.cpp + source/PolyVoxCore/Region.cpp + source/PolyVoxCore/RegionGeometry.cpp + source/PolyVoxCore/SurfaceAdjusters.cpp + source/PolyVoxCore/SurfaceExtractors.cpp + source/PolyVoxCore/SurfaceExtractorsDecimated.cpp + source/PolyVoxCore/SurfaceVertex.cpp + source/PolyVoxCore/Utility.cpp + source/PolyVoxCore/VoxelFilters.cpp +) + +#Projects headers files +SET(CORE_INC_FILES + include/PolyVoxCore/Block.h + include/PolyVoxCore/Block.inl + include/PolyVoxCore/BlockVolume.h + include/PolyVoxCore/BlockVolume.inl + include/PolyVoxCore/BlockVolumeIterator.h + include/PolyVoxCore/BlockVolumeIterator.inl + include/PolyVoxCore/Constants.h + include/PolyVoxCore/Enums.h + include/PolyVoxCore/GradientEstimators.h + include/PolyVoxCore/GradientEstimators.inl + include/PolyVoxCore/LinearVolume.h + include/PolyVoxCore/LinearVolume.inl + include/PolyVoxCore/IndexedSurfacePatch.h + include/PolyVoxCore/MarchingCubesTables.h + include/PolyVoxCore/PolyVoxForwardDeclarations.h + include/PolyVoxCore/PolyVoxCStdInt.h + include/PolyVoxCore/Region.h + include/PolyVoxCore/RegionGeometry.h + include/PolyVoxCore/SurfaceAdjusters.h + include/PolyVoxCore/SurfaceExtractors.h + include/PolyVoxCore/SurfaceExtractorsDecimated.h + include/PolyVoxCore/SurfaceVertex.h + include/PolyVoxCore/TypeDef.h + include/PolyVoxCore/Utility.h + include/PolyVoxCore/Vector.h + include/PolyVoxCore/Vector.inl + include/PolyVoxCore/VoxelFilters.h +) + +#Projects source files +SET(UTIL_SRC_FILES + source/PolyVoxUtil/VolumeChangeTracker.cpp +) + +#Projects headers files +SET(UTIL_INC_FILES + include/PolyVoxUtil/VolumeChangeTracker.h +) + +ADD_DEFINITIONS(-DPOLYVOX_EXPORT) #Export symbols in the .dll + +#Appends "_d" to the generated library when in debug mode +SET(CMAKE_DEBUG_POSTFIX "_d") + +#"Sources" and "Headers" are the group names in Visual Studio. +#They may have other uses too... +SOURCE_GROUP("CoreSources" FILES ${CORE_SRC_FILES}) +SOURCE_GROUP("CoreHeaders" FILES ${CORE_INC_FILES}) + +SOURCE_GROUP("UtilSources" FILES ${UTIL_SRC_FILES}) +SOURCE_GROUP("UtilHeaders" FILES ${UTIL_INC_FILES}) + +#Tell CMake the paths +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +#Build +ADD_LIBRARY(PolyVoxCore SHARED ${CORE_SRC_FILES} ${CORE_INC_FILES}) +SET_TARGET_PROPERTIES(PolyVoxCore PROPERTIES VERSION ${POLYVOX_VERSION} SOVERSION ${POLYVOX_VERSION_MAJOR}) +IF(WIN32) + SET_TARGET_PROPERTIES(PolyVoxCore PROPERTIES COMPILE_FLAGS "/wd4251") #Disable warning on STL exports +ENDIF(WIN32) + +#Install +INSTALL(TARGETS PolyVoxCore + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) + +INSTALL(FILES ${CORE_INC_FILES} DESTINATION include/PolyVoxCore) + +#Build +ADD_LIBRARY(PolyVoxUtil SHARED ${UTIL_SRC_FILES} ${UTIL_INC_FILES}) +TARGET_LINK_LIBRARIES(PolyVoxUtil PolyVoxCore) +SET_TARGET_PROPERTIES(PolyVoxUtil PROPERTIES VERSION ${POLYVOX_VERSION} SOVERSION ${POLYVOX_VERSION_MAJOR}) +IF(WIN32) + SET_TARGET_PROPERTIES(PolyVoxUtil PROPERTIES COMPILE_FLAGS "/wd4251") #Disable warning on STL exports +ENDIF(WIN32) + +#Install +INSTALL(TARGETS PolyVoxUtil + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) + +INSTALL(FILES ${UTIL_INC_FILES} DESTINATION include/PolyVoxUtil) diff --git a/library/include/PolyVoxCore/Block.h b/library/include/PolyVoxCore/Block.h new file mode 100644 index 00000000..2c55fe5c --- /dev/null +++ b/library/include/PolyVoxCore/Block.h @@ -0,0 +1,61 @@ +#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_Block_H__ +#define __PolyVox_Block_H__ + +#pragma region Headers +#include "PolyVoxForwardDeclarations.h" + +#include "PolyVoxCStdInt.h" +#pragma endregion + +namespace PolyVox +{ + template + class Block + { + //Make BlockVolumeIterator a friend + friend class BlockVolumeIterator; + public: + Block(uint8 uSideLengthPower); + Block(const Block& rhs); + ~Block(); + + Block& operator=(const Block& rhs); + + uint16 getSideLength(void) const; + VoxelType getVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos) const; + + void setVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos, VoxelType tValue); + + void fill(VoxelType tValue); + + private: + uint8 m_uSideLengthPower; + uint16 m_uSideLength; + VoxelType* m_tData; + }; +} + +#include "Block.inl" + +#endif diff --git a/library/include/PolyVoxCore/Block.inl b/library/include/PolyVoxCore/Block.inl new file mode 100644 index 00000000..2b0f81d7 --- /dev/null +++ b/library/include/PolyVoxCore/Block.inl @@ -0,0 +1,124 @@ +#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 + +#pragma region Headers +#include +#include //For memcpy +#include //for std::invalid_argument +#pragma endregion + +namespace PolyVox +{ + #pragma region Constructors/Destructors + template + Block::Block(uint8 uSideLengthPower) + :m_tData(0) + { + //Check the block size is sensible. This corresponds to a side length of 256 voxels + if(uSideLengthPower > 8) + { + throw std::invalid_argument("Block side length power must be less than or equal to eight"); + } + + //Compute the side length + m_uSideLengthPower = uSideLengthPower; + m_uSideLength = 0x01 << uSideLengthPower; + + //If this fails an exception will be thrown. Memory is not + //allocated and there is nothing else in this class to clean up + m_tData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; + } + + template + Block::Block(const Block& rhs) + { + *this = rhs; + } + + template + Block::~Block() + { + delete[] m_tData; + m_tData = 0; + } + #pragma endregion + + #pragma region Operators + template + Block& Block::operator=(const Block& rhs) + { + if (this == &rhs) + { + return *this; + } + memcpy(m_tData, rhs.m_tData, m_uSideLength * m_uSideLength * m_uSideLength); + return *this; + } + #pragma endregion + + #pragma region Getters + template + uint16 Block::getSideLength(void) const + { + return m_uSideLength; + } + + template + VoxelType Block::getVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos) const + { + assert(uXPos < m_uSideLength); + assert(uYPos < m_uSideLength); + assert(uZPos < m_uSideLength); + + return m_tData + [ + uXPos + + uYPos * m_uSideLength + + uZPos * m_uSideLength * m_uSideLength + ]; + } + #pragma endregion + + #pragma region Setters + template + void Block::setVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos, VoxelType tValue) + { + assert(uXPos < m_uSideLength); + assert(uYPos < m_uSideLength); + assert(uZPos < m_uSideLength); + + m_tData + [ + uXPos + + uYPos * m_uSideLength + + uZPos * m_uSideLength * m_uSideLength + ] = tValue; + } + #pragma endregion + + #pragma region Other + template + void Block::fill(VoxelType tValue) + { + memset(m_tData, tValue, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType)); + } + #pragma endregion +} diff --git a/library/include/PolyVoxCore/BlockVolume.h b/library/include/PolyVoxCore/BlockVolume.h new file mode 100644 index 00000000..2229a20d --- /dev/null +++ b/library/include/PolyVoxCore/BlockVolume.h @@ -0,0 +1,86 @@ +#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_BlockVolume_H__ +#define __PolyVox_BlockVolume_H__ + +#pragma region Headers +#include "PolyVoxForwardDeclarations.h" + +#include "PolyVoxCStdInt.h" + +#include +#pragma endregion + +namespace PolyVox +{ + template + class BlockVolume + { + //Make BlockVolumeIterator a friend + friend class BlockVolumeIterator; + + public: + BlockVolume(uint8 uSideLengthPower, uint8 uBlockSideLengthPower = 5); + BlockVolume(const BlockVolume& rhs); + ~BlockVolume(); + + BlockVolume& operator=(const BlockVolume& rhs); + + Region getEnclosingRegion(void) const; + uint16 getSideLength(void) const; + VoxelType getVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos) const; + VoxelType getVoxelAt(const Vector3DUint16& v3dPos) const; + + bool containsPoint(const Vector3DFloat& pos, float boundary) const; + bool containsPoint(const Vector3DInt32& pos, uint16 boundary) const; + BlockVolumeIterator firstVoxel(void); + void idle(uint32 uAmount); + BlockVolumeIterator lastVoxel(void); + + private: + Block* getHomogenousBlock(VoxelType tHomogenousValue) const; + + Block** m_pBlocks; + bool* m_pIsShared; + bool* m_pIsPotentiallySharable; + VoxelType* m_pHomogenousValue; + mutable std::map*> m_pHomogenousBlocks; + + uint32 m_uNoOfBlocksInVolume; + uint16 m_uSideLengthInBlocks; + + uint8 m_uSideLengthPower; + uint16 m_uSideLength; + + uint8 m_uBlockSideLengthPower; + uint16 m_uBlockSideLength; + }; + + //Some handy typedefs + typedef BlockVolume FloatBlockVolume; + typedef BlockVolume UInt8BlockVolume; + typedef BlockVolume UInt16BlockVolume; +} + +#include "BlockVolume.inl" + +#endif diff --git a/library/include/PolyVoxCore/BlockVolume.inl b/library/include/PolyVoxCore/BlockVolume.inl new file mode 100644 index 00000000..edc389aa --- /dev/null +++ b/library/include/PolyVoxCore/BlockVolume.inl @@ -0,0 +1,231 @@ +#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 + +#pragma region Headers +#include "Block.h" +#include "Region.h" +#include "Vector.h" + +#include +#include //For memcpy +#pragma endregion + +namespace PolyVox +{ + #pragma region Constructors/Destructors + template + BlockVolume::BlockVolume(uint8 uSideLengthPower, uint8 uBlockSideLengthPower) + :m_pBlocks(0) + { + //Check the volume size is sensible. This corresponds to a side length of 65536 voxels + if(uSideLengthPower > 16) + { + throw std::invalid_argument("Volume side length power must be less than or equal to 16"); + } + + //Compute the volume side length + m_uSideLengthPower = uSideLengthPower; + m_uSideLength = 0x01 << uSideLengthPower; + + //Compute the block side length + m_uBlockSideLengthPower = uBlockSideLengthPower; + m_uBlockSideLength = 0x01 << uBlockSideLengthPower; + + //Compute the side length in blocks + m_uSideLengthInBlocks = m_uSideLength / m_uBlockSideLength; + + //Compute number of blocks in the volume + m_uNoOfBlocksInVolume = m_uSideLengthInBlocks * m_uSideLengthInBlocks * m_uSideLengthInBlocks; + + //Create the blocks + m_pBlocks = new Block*[m_uNoOfBlocksInVolume]; + m_pIsShared = new bool[m_uNoOfBlocksInVolume]; + m_pIsPotentiallySharable = new bool[m_uNoOfBlocksInVolume]; + m_pHomogenousValue = new VoxelType[m_uNoOfBlocksInVolume]; + for(uint32 i = 0; i < m_uNoOfBlocksInVolume; ++i) + { + m_pBlocks[i] = getHomogenousBlock(0); //new Block(uBlockSideLengthPower); + m_pIsShared[i] = true; + m_pIsPotentiallySharable[i] = false; + m_pHomogenousValue[i] = 0; + } + } + + template + BlockVolume::BlockVolume(const BlockVolume& rhs) + { + *this = rhs; + } + + template + BlockVolume::~BlockVolume() + { + for(uint32 i = 0; i < m_uNoOfBlocksInVolume; ++i) + { + delete m_pBlocks[i]; + } + } + #pragma endregion + + #pragma region Operators + template + BlockVolume& BlockVolume::operator=(const BlockVolume& rhs) + { + if (this == &rhs) + { + return *this; + } + + /*for(uint16 i = 0; i < POLYVOX_NO_OF_BLOCKS_IN_VOLUME; ++i) + { + //FIXME - Add checking... + m_pBlocks[i] = SharedPtr(new Block); + }*/ + + for(uint32 i = 0; i < m_uNoOfBlocksInVolume; ++i) + { + //I think this is OK... If a block is in the homogeneous array it's ref count will be greater + //than 1 as there will be the pointer in the volume and the pointer in the static homogeneous array. + /*if(rhs.m_pBlocks[i].unique()) + { + m_pBlocks[i] = SharedPtr(new Block(*(rhs.m_pBlocks[i]))); + } + else + {*/ + //we have a block in the homogeneous array - just copy the pointer. + m_pBlocks[i] = rhs.m_pBlocks[i]; + //} + } + + return *this; + } + #pragma endregion + + #pragma region Getters + template + Region BlockVolume::getEnclosingRegion(void) const + { + return Region(Vector3DInt32(0,0,0), Vector3DInt32(m_uSideLength-1,m_uSideLength-1,m_uSideLength-1)); + } + + template + uint16 BlockVolume::getSideLength(void) const + { + return m_uSideLength; + } + + template + VoxelType BlockVolume::getVoxelAt(uint16 uXPos, uint16 uYPos, uint16 uZPos) const + { + assert(uXPos < getSideLength()); + assert(uYPos < getSideLength()); + assert(uZPos < getSideLength()); + + const uint16 blockX = uXPos >> m_uBlockSideLengthPower; + const uint16 blockY = uYPos >> m_uBlockSideLengthPower; + const uint16 blockZ = uZPos >> m_uBlockSideLengthPower; + + const uint16 xOffset = uXPos - (blockX << m_uBlockSideLengthPower); + const uint16 yOffset = uYPos - (blockY << m_uBlockSideLengthPower); + const uint16 zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); + + const Block* block = m_pBlocks + [ + blockX + + blockY * m_uSideLengthInBlocks + + blockZ * m_uSideLengthInBlocks * m_uSideLengthInBlocks + ]; + + return block->getVoxelAt(xOffset,yOffset,zOffset); + } + + template + VoxelType BlockVolume::getVoxelAt(const Vector3DUint16& v3dPos) const + { + assert(v3dPos.getX() < m_uSideLength); + assert(v3dPos.getY() < m_uSideLength); + assert(v3dPos.getZ() < m_uSideLength); + + return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + } + #pragma endregion + + #pragma region Other + template + bool BlockVolume::containsPoint(const Vector3DFloat& pos, float boundary) const + { + return (pos.getX() <= m_uSideLength - 1 - boundary) + && (pos.getY() <= m_uSideLength - 1 - boundary) + && (pos.getZ() <= m_uSideLength - 1 - boundary) + && (pos.getX() >= boundary) + && (pos.getY() >= boundary) + && (pos.getZ() >= boundary); + } + + template + bool BlockVolume::containsPoint(const Vector3DInt32& pos, uint16 boundary) const + { + return (pos.getX() <= m_uSideLength - 1 - boundary) + && (pos.getY() <= m_uSideLength - 1 - boundary) + && (pos.getZ() <= m_uSideLength - 1 - boundary) + && (pos.getX() >= boundary) + && (pos.getY() >= boundary) + && (pos.getZ() >= boundary); + } + + template + BlockVolumeIterator BlockVolume::firstVoxel(void) + { + BlockVolumeIterator iter(*this); + iter.setPosition(0,0,0); + return iter; + } + + template + void BlockVolume::idle(uint32 uAmount) + { + } + + template + BlockVolumeIterator BlockVolume::lastVoxel(void) + { + BlockVolumeIterator iter(*this); + iter.setPosition(m_uSideLength-1,m_uSideLength-1,m_uSideLength-1); + return iter; + } + #pragma endregion + + #pragma region Private Implementation + template + Block* BlockVolume::getHomogenousBlock(VoxelType tHomogenousValue) const + { + typename std::map*>::iterator iterResult = m_pHomogenousBlocks.find(tHomogenousValue); + if(iterResult == m_pHomogenousBlocks.end()) + { + Block* pBlock = new Block(m_uBlockSideLengthPower); + pBlock->fill(tHomogenousValue); + m_pHomogenousBlocks.insert(std::make_pair(tHomogenousValue, pBlock)); + return pBlock; + } + return iterResult->second; + } + #pragma endregion +} diff --git a/library/include/PolyVoxCore/BlockVolumeIterator.h b/library/include/PolyVoxCore/BlockVolumeIterator.h new file mode 100644 index 00000000..939ded5e --- /dev/null +++ b/library/include/PolyVoxCore/BlockVolumeIterator.h @@ -0,0 +1,138 @@ +#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 __VolumeIterator_H__ +#define __VolumeIterator_H__ + +#pragma region Headers +#include "PolyVoxForwardDeclarations.h" + +#include "PolyVoxCStdInt.h" +#pragma endregion + +namespace PolyVox +{ + template + class BlockVolumeIterator + { + public: + BlockVolumeIterator(BlockVolume& volume); + ~BlockVolumeIterator(); + + bool operator==(const BlockVolumeIterator& rhs); + bool operator<(const BlockVolumeIterator& rhs); + bool operator>(const BlockVolumeIterator& rhs); + bool operator<=(const BlockVolumeIterator& rhs); + bool operator>=(const BlockVolumeIterator& rhs); + + uint16 getPosX(void) const; + uint16 getPosY(void) const; + uint16 getPosZ(void) const; + VoxelType getSubSampledVoxel(uint8 uLevel) const; + const BlockVolume& getVolume(void) const; + VoxelType getVoxel(void) const; + + void setPosition(const Vector3DInt16& v3dNewPos); + void setPosition(uint16 xPos, uint16 yPos, uint16 zPos); + void setValidRegion(const Region& region); + void setValidRegion(uint16 xFirst, uint16 yFirst, uint16 zFirst, uint16 xLast, uint16 yLast, uint16 zLast); + void setVoxel(VoxelType tValue); + + bool isValidForRegion(void) const; + void moveForwardInRegionFast(void); + bool moveForwardInRegionXYZ(void); + + VoxelType peekVoxel1nx1ny1nz(void) const; + VoxelType peekVoxel1nx1ny0pz(void) const; + VoxelType peekVoxel1nx1ny1pz(void) const; + VoxelType peekVoxel1nx0py1nz(void) const; + VoxelType peekVoxel1nx0py0pz(void) const; + VoxelType peekVoxel1nx0py1pz(void) const; + VoxelType peekVoxel1nx1py1nz(void) const; + VoxelType peekVoxel1nx1py0pz(void) const; + VoxelType peekVoxel1nx1py1pz(void) const; + + VoxelType peekVoxel0px1ny1nz(void) const; + VoxelType peekVoxel0px1ny0pz(void) const; + VoxelType peekVoxel0px1ny1pz(void) const; + VoxelType peekVoxel0px0py1nz(void) const; + VoxelType peekVoxel0px0py0pz(void) const; + VoxelType peekVoxel0px0py1pz(void) const; + VoxelType peekVoxel0px1py1nz(void) const; + VoxelType peekVoxel0px1py0pz(void) const; + VoxelType peekVoxel0px1py1pz(void) const; + + VoxelType peekVoxel1px1ny1nz(void) const; + VoxelType peekVoxel1px1ny0pz(void) const; + VoxelType peekVoxel1px1ny1pz(void) const; + VoxelType peekVoxel1px0py1nz(void) const; + VoxelType peekVoxel1px0py0pz(void) const; + VoxelType peekVoxel1px0py1pz(void) const; + VoxelType peekVoxel1px1py1nz(void) const; + VoxelType peekVoxel1px1py0pz(void) const; + VoxelType peekVoxel1px1py1pz(void) const; + + private: + + //The current volume + BlockVolume& mVolume; + + //The current position in the volume + uint16 mXPosInVolume; + uint16 mYPosInVolume; + uint16 mZPosInVolume; + + //The position of the current block + uint16 mXBlock; + uint16 mYBlock; + uint16 mZBlock; + + //The offset into the current block + uint16 mXPosInBlock; + uint16 mYPosInBlock; + uint16 mZPosInBlock; + + //Other current position information + VoxelType* mCurrentVoxel; + uint32 mBlockIndexInVolume; + uint32 mVoxelIndexInBlock; + + uint16 mXRegionFirst; + uint16 mYRegionFirst; + uint16 mZRegionFirst; + uint16 mXRegionLast; + uint16 mYRegionLast; + uint16 mZRegionLast; + + uint16 mXRegionFirstBlock; + uint16 mYRegionFirstBlock; + uint16 mZRegionFirstBlock; + uint16 mXRegionLastBlock; + uint16 mYRegionLastBlock; + uint16 mZRegionLastBlock; + + bool mIsValidForRegion; + }; +} + +#include "BlockVolumeIterator.inl" + +#endif diff --git a/library/include/PolyVoxCore/BlockVolumeIterator.inl b/library/include/PolyVoxCore/BlockVolumeIterator.inl new file mode 100644 index 00000000..bc117e15 --- /dev/null +++ b/library/include/PolyVoxCore/BlockVolumeIterator.inl @@ -0,0 +1,684 @@ +#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 + +#pragma region Headers +#include "Block.h" +#include "BlockVolume.h" +#include "Vector.h" +#pragma endregion + +namespace PolyVox +{ + #pragma region Constructors/Destructors + template + BlockVolumeIterator::BlockVolumeIterator(BlockVolume& volume) + :mVolume(volume) + { + } + + template + BlockVolumeIterator::~BlockVolumeIterator() + { + } + #pragma endregion + + #pragma region Operators + template + bool BlockVolumeIterator::operator==(const BlockVolumeIterator& rhs) + { + //We could just check whether the two mCurrentVoxel pointers are equal, but this may not + //be safe in the future if we decide to allow blocks to be shared between volumes + //So we really check whether the positions are the same. + //NOTE: With all iterator comparisons it is the users job to ensure they at least point + //to the same volume. Otherwise they are not comparible. + assert(&mVolume == &rhs.mVolume); + return + ( + (mXPosInVolume == rhs.mXPosInVolume) && + (mYPosInVolume == rhs.mYPosInVolume) && + (mZPosInVolume == rhs.mZPosInVolume) + ); + } + + template + bool BlockVolumeIterator::operator<(const BlockVolumeIterator& rhs) + { + assert(&mVolume == &rhs.mVolume); + + if(mZPosInVolume < rhs.mZPosInVolume) + return true; + if(mZPosInVolume > rhs.mZPosInVolume) + return false; + + if(mYPosInVolume < rhs.mYPosInVolume) + return true; + if(mYPosInVolume > rhs.mYPosInVolume) + return false; + + if(mXPosInVolume < rhs.mXPosInVolume) + return true; + if(mXPosInVolume > rhs.mXPosInVolume) + return false; + + return false; + } + + template + bool BlockVolumeIterator::operator>(const BlockVolumeIterator& rhs) + { + assert(&mVolume == &rhs.mVolume); + return (rhs < *this); + } + + template + bool BlockVolumeIterator::operator<=(const BlockVolumeIterator& rhs) + { + assert(&mVolume == &rhs.mVolume); + return (rhs > *this); + } + + template + bool BlockVolumeIterator::operator>=(const BlockVolumeIterator& rhs) + { + assert(&mVolume == &rhs.mVolume); + return (rhs < *this); + } + #pragma endregion + + #pragma region Getters + template + uint16 BlockVolumeIterator::getPosX(void) const + { + return mXPosInVolume; + } + + template + uint16 BlockVolumeIterator::getPosY(void) const + { + return mYPosInVolume; + } + + template + uint16 BlockVolumeIterator::getPosZ(void) const + { + return mZPosInVolume; + } + + template + VoxelType BlockVolumeIterator::getSubSampledVoxel(uint8 uLevel) const + { + if(uLevel == 0) + { + return getVoxel(); + } + else if(uLevel == 1) + { + VoxelType tValue = getVoxel(); + tValue = (std::max)(tValue, peekVoxel1px0py0pz()); + tValue = (std::max)(tValue, peekVoxel0px1py0pz()); + tValue = (std::max)(tValue, peekVoxel1px1py0pz()); + tValue = (std::max)(tValue, peekVoxel0px0py1pz()); + tValue = (std::max)(tValue, peekVoxel1px0py1pz()); + tValue = (std::max)(tValue, peekVoxel0px1py1pz()); + tValue = (std::max)(tValue, peekVoxel1px1py1pz()); + return tValue; + } + else + { + const uint8 uSize = 1 << uLevel; + + VoxelType tValue = 0; + for(uint8 z = 0; z < uSize; ++z) + { + for(uint8 y = 0; y < uSize; ++y) + { + for(uint8 x = 0; x < uSize; ++x) + { + tValue = (std::max)(tValue, mVolume.getVoxelAt(mXPosInVolume + x, mYPosInVolume + y, mZPosInVolume + z)); + } + } + } + return tValue; + } + } + + template + const BlockVolume& BlockVolumeIterator::getVolume(void) const + { + return mVolume; + } + + template + VoxelType BlockVolumeIterator::getVoxel(void) const + { + return *mCurrentVoxel; + } + #pragma endregion + + #pragma region Setters + template + void BlockVolumeIterator::setPosition(const Vector3DInt16& v3dNewPos) + { + setPosition(v3dNewPos.getX(), v3dNewPos.getY(), v3dNewPos.getZ()); + } + + template + void BlockVolumeIterator::setPosition(uint16 xPos, uint16 yPos, uint16 zPos) + { + mXPosInVolume = xPos; + mYPosInVolume = yPos; + mZPosInVolume = zPos; + + mXBlock = mXPosInVolume >> mVolume.m_uBlockSideLengthPower; + mYBlock = mYPosInVolume >> mVolume.m_uBlockSideLengthPower; + mZBlock = mZPosInVolume >> mVolume.m_uBlockSideLengthPower; + + mXPosInBlock = mXPosInVolume - (mXBlock << mVolume.m_uBlockSideLengthPower); + mYPosInBlock = mYPosInVolume - (mYBlock << mVolume.m_uBlockSideLengthPower); + mZPosInBlock = mZPosInVolume - (mZBlock << mVolume.m_uBlockSideLengthPower); + + mBlockIndexInVolume = mXBlock + + mYBlock * mVolume.m_uSideLengthInBlocks + + mZBlock * mVolume.m_uSideLengthInBlocks * mVolume.m_uSideLengthInBlocks; + Block* currentBlock = mVolume.m_pBlocks[mBlockIndexInVolume]; + + mVoxelIndexInBlock = mXPosInBlock + + mYPosInBlock * mVolume.m_uBlockSideLength + + mZPosInBlock * mVolume.m_uBlockSideLength * mVolume.m_uBlockSideLength; + + mCurrentVoxel = currentBlock->m_tData + mVoxelIndexInBlock; + } + + template + void BlockVolumeIterator::setValidRegion(const Region& region) + { + setValidRegion(region.getLowerCorner().getX(),region.getLowerCorner().getY(),region.getLowerCorner().getZ(),region.getUpperCorner().getX(),region.getUpperCorner().getY(),region.getUpperCorner().getZ()); + } + + template + void BlockVolumeIterator::setValidRegion(uint16 xFirst, uint16 yFirst, uint16 zFirst, uint16 xLast, uint16 yLast, uint16 zLast) + { + mXRegionFirst = xFirst; + mYRegionFirst = yFirst; + mZRegionFirst = zFirst; + + mXRegionLast = xLast; + mYRegionLast = yLast; + mZRegionLast = zLast; + + mXRegionFirstBlock = mXRegionFirst >> mVolume.m_uBlockSideLengthPower; + mYRegionFirstBlock = mYRegionFirst >> mVolume.m_uBlockSideLengthPower; + mZRegionFirstBlock = mZRegionFirst >> mVolume.m_uBlockSideLengthPower; + + mXRegionLastBlock = mXRegionLast >> mVolume.m_uBlockSideLengthPower; + mYRegionLastBlock = mYRegionLast >> mVolume.m_uBlockSideLengthPower; + mZRegionLastBlock = mZRegionLast >> mVolume.m_uBlockSideLengthPower; + } + + template + void BlockVolumeIterator::setVoxel(VoxelType tValue) + { + const uint32 uBlockIndex = + mXBlock + + mYBlock * mVolume.m_uSideLengthInBlocks + + mZBlock * mVolume.m_uSideLengthInBlocks * mVolume.m_uSideLengthInBlocks; + + const bool bIsShared = mVolume.m_pIsShared[uBlockIndex]; + const VoxelType tHomogenousValue = mVolume.m_pHomogenousValue[uBlockIndex]; + if(bIsShared) + { + if(tHomogenousValue != tValue) + { + mVolume.m_pBlocks[uBlockIndex] = new Block(mVolume.m_uBlockSideLengthPower); + mVolume.m_pIsShared[uBlockIndex] = false; + mVolume.m_pBlocks[uBlockIndex]->fill(tHomogenousValue); + mCurrentVoxel = mVolume.m_pBlocks[uBlockIndex]->m_tData + mVoxelIndexInBlock; + *mCurrentVoxel = tValue; + } + } + else + { + //There is a chance that setting this voxel makes the block homogenous and therefore shareable. + mVolume.m_pIsPotentiallySharable[uBlockIndex] = true; + *mCurrentVoxel = tValue; + } + } + #pragma endregion + + #pragma region Other + template + bool BlockVolumeIterator::isValidForRegion(void) const + { + return mIsValidForRegion; + } + + template + void BlockVolumeIterator::moveForwardInRegionFast(void) + { + mXPosInBlock++; + mCurrentVoxel++; + mXPosInVolume++; + if((mXPosInBlock == mVolume.m_uBlockSideLength) || (mXPosInVolume > mXRegionLast)) + { + mXPosInVolume = (std::max)(mXRegionFirst,uint16(mXBlock * mVolume.m_uBlockSideLength)); + mXPosInBlock = mXPosInVolume - (mXBlock << mVolume.m_uBlockSideLengthPower); + mVoxelIndexInBlock = mXPosInBlock + + mYPosInBlock * mVolume.m_uBlockSideLength + + mZPosInBlock * mVolume.m_uBlockSideLength * mVolume.m_uBlockSideLength; + Block* currentBlock = mVolume.m_pBlocks[mBlockIndexInVolume]; + mCurrentVoxel = currentBlock->m_tData + mVoxelIndexInBlock; + + mYPosInBlock++; + mYPosInVolume++; + mCurrentVoxel += mVolume.m_uBlockSideLength; + if((mYPosInBlock == mVolume.m_uBlockSideLength) || (mYPosInVolume > mYRegionLast)) + { + mYPosInVolume = (std::max)(mYRegionFirst,uint16(mYBlock * mVolume.m_uBlockSideLength)); + mYPosInBlock = mYPosInVolume - (mYBlock << mVolume.m_uBlockSideLengthPower); + mVoxelIndexInBlock = mXPosInBlock + + mYPosInBlock * mVolume.m_uBlockSideLength + + mZPosInBlock * mVolume.m_uBlockSideLength * mVolume.m_uBlockSideLength; + Block* currentBlock = mVolume.m_pBlocks[mBlockIndexInVolume]; + mCurrentVoxel = currentBlock->m_tData + mVoxelIndexInBlock; + + mZPosInBlock++; + mZPosInVolume++; + mCurrentVoxel += mVolume.m_uBlockSideLength * mVolume.m_uBlockSideLength; + + if((mZPosInBlock == mVolume.m_uBlockSideLength) || (mZPosInVolume > mZRegionLast)) + { + //At this point we've left the current block. Find a new one... + + ++mXBlock; + ++mBlockIndexInVolume; + if(mXBlock > mXRegionLastBlock) + { + mXBlock = mXRegionFirstBlock; + mBlockIndexInVolume = mXBlock + + mYBlock * mVolume.m_uSideLengthInBlocks + + mZBlock * mVolume.m_uSideLengthInBlocks * mVolume.m_uSideLengthInBlocks; + + ++mYBlock; + mBlockIndexInVolume += mVolume.m_uSideLengthInBlocks; + if(mYBlock > mYRegionLastBlock) + { + mYBlock = mYRegionFirstBlock; + mBlockIndexInVolume = mXBlock + + mYBlock * mVolume.m_uSideLengthInBlocks + + mZBlock * mVolume.m_uSideLengthInBlocks * mVolume.m_uSideLengthInBlocks; + + ++mZBlock; + mBlockIndexInVolume += mVolume.m_uSideLengthInBlocks * mVolume.m_uSideLengthInBlocks; + if(mZBlock > mZRegionLastBlock) + { + mIsValidForRegion = false; + return; + } + } + } + + Block* currentBlock = mVolume.m_pBlocks[mBlockIndexInVolume]; + //mCurrentBlock = mVolume->m_pBlocks[mBlockIndexInVolume]; + + mXPosInVolume = (std::max)(mXRegionFirst,uint16(mXBlock * mVolume.m_uBlockSideLength)); + mYPosInVolume = (std::max)(mYRegionFirst,uint16(mYBlock * mVolume.m_uBlockSideLength)); + mZPosInVolume = (std::max)(mZRegionFirst,uint16(mZBlock * mVolume.m_uBlockSideLength)); + + mXPosInBlock = mXPosInVolume - (mXBlock << mVolume.m_uBlockSideLengthPower); + mYPosInBlock = mYPosInVolume - (mYBlock << mVolume.m_uBlockSideLengthPower); + mZPosInBlock = mZPosInVolume - (mZBlock << mVolume.m_uBlockSideLengthPower); + + mVoxelIndexInBlock = mXPosInBlock + + mYPosInBlock * mVolume.m_uBlockSideLength + + mZPosInBlock * mVolume.m_uBlockSideLength * mVolume.m_uBlockSideLength; + + mCurrentVoxel = currentBlock->m_tData + mVoxelIndexInBlock; + } + } + } + } + + template + bool BlockVolumeIterator::moveForwardInRegionXYZ(void) + { + if(mXPosInVolume < mXRegionLast) + { + ++mXPosInVolume; + if(mXPosInVolume % mVolume.m_uBlockSideLength != 0) + { + //No need to compute new block. + ++mVoxelIndexInBlock; + ++mCurrentVoxel; + } + else + { + //A more complex situation. Just call setPosition(). + setPosition(mXPosInVolume, mYPosInVolume, mZPosInVolume); + } + } + else + { + mXPosInVolume = mXRegionFirst; + if(mYPosInVolume < mYRegionLast) + { + ++mYPosInVolume; + //In the case of 'X' we used a trick to avoid calling this evey time. It's hard to use the same + //trick here because the x position has been reset and so is likely to be in a different block. + setPosition(mXPosInVolume, mYPosInVolume, mZPosInVolume); + } + else + { + mYPosInVolume = mYRegionFirst; + if(mZPosInVolume < mZRegionLast) + { + ++mZPosInVolume; + //In the case of 'X' we used a trick to avoid calling this evey time. It's hard to use the same + //trick here because the x position has been reset and so is likely to be in a different block. + setPosition(mXPosInVolume, mYPosInVolume, mZPosInVolume); + } + else + { + //We've hit the end of the region. Reset x and y positions to where they were. + mXPosInVolume = mXRegionLast; + mYPosInVolume = mYRegionLast; + + //Return false to indicate we failed to move forward. + return false; + } + } + } + + return true; + } + #pragma endregion + + #pragma region Peekers + template + VoxelType BlockVolumeIterator::peekVoxel1nx1ny1nz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0) && (mYPosInVolume%mVolume.m_uBlockSideLength != 0) && (mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel - 1 - mVolume.m_uBlockSideLength - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume-1,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1nx1ny0pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0) && (mYPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel - 1 - mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume-1,mZPosInVolume); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1nx1ny1pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0) && (mYPosInVolume%mVolume.m_uBlockSideLength != 0) && (mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel - 1 - mVolume.m_uBlockSideLength + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume-1,mZPosInVolume+1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1nx0py1nz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0) && (mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel - 1 - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1nx0py0pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel - 1); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume,mZPosInVolume); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1nx0py1pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0) && (mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel - 1 + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume,mZPosInVolume+1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1nx1py1nz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0) && (mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel - 1 + mVolume.m_uBlockSideLength - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume+1,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1nx1py0pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0) && (mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel - 1 + mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume+1,mZPosInVolume); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1nx1py1pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != 0) && (mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel - 1 + mVolume.m_uBlockSideLength + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume+1,mZPosInVolume+1); + } + + ////////////////////////////////////////////////////////////////////////// + + template + VoxelType BlockVolumeIterator::peekVoxel0px1ny1nz(void) const + { + if((mYPosInVolume%mVolume.m_uBlockSideLength != 0) && (mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel - mVolume.m_uBlockSideLength - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume-1,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel0px1ny0pz(void) const + { + if((mYPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel - mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume-1,mZPosInVolume); + } + + template + VoxelType BlockVolumeIterator::peekVoxel0px1ny1pz(void) const + { + if((mYPosInVolume%mVolume.m_uBlockSideLength != 0) && (mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel - mVolume.m_uBlockSideLength + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume-1,mZPosInVolume+1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel0px0py1nz(void) const + { + if((mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel0px0py0pz(void) const + { + return *mCurrentVoxel; + } + + template + VoxelType BlockVolumeIterator::peekVoxel0px0py1pz(void) const + { + if((mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume,mZPosInVolume+1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel0px1py1nz(void) const + { + if((mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel + mVolume.m_uBlockSideLength - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume+1,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel0px1py0pz(void) const + { + if((mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel + mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume+1,mZPosInVolume); + } + + template + VoxelType BlockVolumeIterator::peekVoxel0px1py1pz(void) const + { + if((mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel + mVolume.m_uBlockSideLength + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume+1,mZPosInVolume+1); + } + + ////////////////////////////////////////////////////////////////////////// + + template + VoxelType BlockVolumeIterator::peekVoxel1px1ny1nz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mYPosInVolume%mVolume.m_uBlockSideLength != 0) && (mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel + 1 - mVolume.m_uBlockSideLength - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume-1,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1px1ny0pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mYPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel + 1 - mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume-1,mZPosInVolume); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1px1ny1pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mYPosInVolume%mVolume.m_uBlockSideLength != 0) && (mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel + 1 - mVolume.m_uBlockSideLength + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume-1,mZPosInVolume+1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1px0py1nz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel + 1 - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1px0py0pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel + 1); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume,mZPosInVolume); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1px0py1pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel + 1 + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume,mZPosInVolume+1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1px1py1nz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mZPosInVolume%mVolume.m_uBlockSideLength != 0)) + { + return *(mCurrentVoxel + 1 + mVolume.m_uBlockSideLength - mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume+1,mZPosInVolume-1); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1px1py0pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel + 1 + mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume+1,mZPosInVolume); + } + + template + VoxelType BlockVolumeIterator::peekVoxel1px1py1pz(void) const + { + if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mYPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1) && (mZPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1)) + { + return *(mCurrentVoxel + 1 + mVolume.m_uBlockSideLength + mVolume.m_uBlockSideLength*mVolume.m_uBlockSideLength); + } + return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume+1,mZPosInVolume+1); + } + #pragma endregion +} diff --git a/library/include/PolyVoxCore/Constants.h b/library/include/PolyVoxCore/Constants.h new file mode 100644 index 00000000..6bfe2e23 --- /dev/null +++ b/library/include/PolyVoxCore/Constants.h @@ -0,0 +1,45 @@ +#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_Constants_H__ +#define __PolyVox_Constants_H__ + +#include "PolyVoxForwardDeclarations.h" + +namespace PolyVox +{ + //FIXME - i think we can define mod using a bitmask which flattens the upper bits. Should define that here. + //const uint32 POLYVOX_BLOCK_SIDE_LENGTH_POWER = 5; + //const uint32 POLYVOX_BLOCK_SIDE_LENGTH = (0x0001 << POLYVOX_BLOCK_SIDE_LENGTH_POWER); + //const uint32 POLYVOX_NO_OF_VOXELS_IN_BLOCK = (POLYVOX_BLOCK_SIDE_LENGTH * POLYVOX_BLOCK_SIDE_LENGTH * POLYVOX_BLOCK_SIDE_LENGTH); + + const uint16 POLYVOX_VOLUME_SIDE_LENGTH_POWER = 8; + const uint16 POLYVOX_VOLUME_SIDE_LENGTH = (0x0001 << POLYVOX_VOLUME_SIDE_LENGTH_POWER); + //const uint32 POLYVOX_VOLUME_SIDE_LENGTH_IN_BLOCKS = (POLYVOX_VOLUME_SIDE_LENGTH >> POLYVOX_BLOCK_SIDE_LENGTH_POWER); + //const uint32 POLYVOX_NO_OF_BLOCKS_IN_VOLUME = (POLYVOX_VOLUME_SIDE_LENGTH_IN_BLOCKS * POLYVOX_VOLUME_SIDE_LENGTH_IN_BLOCKS * POLYVOX_VOLUME_SIDE_LENGTH_IN_BLOCKS); + //const uint32 POLYVOX_NO_OF_VOXELS_IN_VOLUME = (POLYVOX_VOLUME_SIDE_LENGTH * POLYVOX_VOLUME_SIDE_LENGTH * POLYVOX_VOLUME_SIDE_LENGTH); + + const uint16 POLYVOX_REGION_SIDE_LENGTH_POWER = 4; + const uint16 POLYVOX_REGION_SIDE_LENGTH = (0x0001 << POLYVOX_REGION_SIDE_LENGTH_POWER); + const uint16 POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS = (POLYVOX_VOLUME_SIDE_LENGTH >> POLYVOX_REGION_SIDE_LENGTH_POWER); +} + +#endif diff --git a/library/include/PolyVoxCore/Enums.h b/library/include/PolyVoxCore/Enums.h new file mode 100644 index 00000000..fd2e8722 --- /dev/null +++ b/library/include/PolyVoxCore/Enums.h @@ -0,0 +1,35 @@ +#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_Enums_H__ +#define __PolyVox_Enums_H__ + +namespace PolyVox +{ + enum NormalGenerationMethod + { + SIMPLE, + CENTRAL_DIFFERENCE, + SOBEL + }; +} + +#endif diff --git a/library/include/PolyVoxCore/GradientEstimators.h b/library/include/PolyVoxCore/GradientEstimators.h new file mode 100644 index 00000000..8289bbf4 --- /dev/null +++ b/library/include/PolyVoxCore/GradientEstimators.h @@ -0,0 +1,49 @@ +#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_GradientEstimators_H__ +#define __PolyVox_GradientEstimators_H__ + +#include "BlockVolumeIterator.h" + +#include + +namespace PolyVox +{ + template + Vector3DFloat computeCentralDifferenceGradient(const BlockVolumeIterator& volIter); + + template + Vector3DFloat computeSmoothCentralDifferenceGradient(BlockVolumeIterator& volIter); + + template + Vector3DFloat computeDecimatedCentralDifferenceGradient(BlockVolumeIterator& volIter); + + template + Vector3DFloat computeSobelGradient(const BlockVolumeIterator& volIter); + + POLYVOX_API void computeNormalsForVertices(BlockVolume* volumeData, RegionGeometry& regGeom, NormalGenerationMethod normalGenerationMethod); + POLYVOX_API Vector3DFloat computeNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod); +} + +#include "GradientEstimators.inl" + +#endif //__PolyVox_GradientEstimators_H__ diff --git a/library/include/PolyVoxCore/GradientEstimators.inl b/library/include/PolyVoxCore/GradientEstimators.inl new file mode 100644 index 00000000..333f79b0 --- /dev/null +++ b/library/include/PolyVoxCore/GradientEstimators.inl @@ -0,0 +1,185 @@ +#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 + +#include "VoxelFilters.h" + +namespace PolyVox +{ + template + Vector3DFloat computeCentralDifferenceGradient(const BlockVolumeIterator& volIter) + { + //FIXME - bitwise way of doing this? + VoxelType voxel1nx = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0; + VoxelType voxel1px = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0; + + VoxelType voxel1ny = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0; + VoxelType voxel1py = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0; + + VoxelType voxel1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0; + VoxelType voxel1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0; + + return Vector3DFloat + ( + static_cast(voxel1nx) - static_cast(voxel1px), + static_cast(voxel1ny) - static_cast(voxel1py), + static_cast(voxel1nz) - static_cast(voxel1pz) + ); + } + + template + Vector3DFloat computeDecimatedCentralDifferenceGradient(const BlockVolumeIterator& volIter) + { + const uint16 x = volIter.getPosX(); + const uint16 y = volIter.getPosY(); + const uint16 z = volIter.getPosZ(); + + //FIXME - bitwise way of doing this? + VoxelType voxel1nx = volIter.getVoxelAt(x-2, y ,z ) > 0 ? 1: 0; + VoxelType voxel1px = volIter.getVoxelAt(x-2, y ,z ) > 0 ? 1: 0; + + VoxelType voxel1ny = volIter.getVoxelAt(x , y-2,z ) > 0 ? 1: 0; + VoxelType voxel1py = volIter.getVoxelAt(x , y-2,z ) > 0 ? 1: 0; + + VoxelType voxel1nz = volIter.getVoxelAt(x , y ,z-2) > 0 ? 1: 0; + VoxelType voxel1pz = volIter.getVoxelAt(x , y ,z-2) > 0 ? 1: 0; + + return Vector3DFloat + ( + static_cast(voxel1nx) - static_cast(voxel1px), + static_cast(voxel1ny) - static_cast(voxel1py), + static_cast(voxel1nz) - static_cast(voxel1pz) + ); + } + + template + Vector3DFloat computeSmoothCentralDifferenceGradient(BlockVolumeIterator& volIter) + { + uint16 initialX = volIter.getPosX(); + uint16 initialY = volIter.getPosY(); + uint16 initialZ = volIter.getPosZ(); + + //FIXME - bitwise way of doing this? + volIter.setPosition(initialX-1, initialY, initialZ); + float voxel1nx = computeSmoothedVoxel(volIter); + volIter.setPosition(initialX+1, initialY, initialZ); + float voxel1px = computeSmoothedVoxel(volIter); + + volIter.setPosition(initialX, initialY-1, initialZ); + float voxel1ny = computeSmoothedVoxel(volIter); + volIter.setPosition(initialX, initialY+1, initialZ); + float voxel1py = computeSmoothedVoxel(volIter); + + volIter.setPosition(initialX, initialY, initialZ-1); + float voxel1nz = computeSmoothedVoxel(volIter); + volIter.setPosition(initialX, initialY, initialZ+1); + float voxel1pz = computeSmoothedVoxel(volIter); + + return Vector3DFloat + ( + voxel1nx - voxel1px, + voxel1ny - voxel1py, + voxel1nz - voxel1pz + ); + } + + template + Vector3DFloat computeSobelGradient(const BlockVolumeIterator& volIter) + { + static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, { + {3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } }; + + const VoxelType pVoxel1nx1ny1nz = volIter.peekVoxel1nx1ny1nz() > 0 ? 1: 0; + const VoxelType pVoxel1nx1ny0pz = volIter.peekVoxel1nx1ny0pz() > 0 ? 1: 0; + const VoxelType pVoxel1nx1ny1pz = volIter.peekVoxel1nx1ny1pz() > 0 ? 1: 0; + const VoxelType pVoxel1nx0py1nz = volIter.peekVoxel1nx0py1nz() > 0 ? 1: 0; + const VoxelType pVoxel1nx0py0pz = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0; + const VoxelType pVoxel1nx0py1pz = volIter.peekVoxel1nx0py1pz() > 0 ? 1: 0; + const VoxelType pVoxel1nx1py1nz = volIter.peekVoxel1nx1py1nz() > 0 ? 1: 0; + const VoxelType pVoxel1nx1py0pz = volIter.peekVoxel1nx1py0pz() > 0 ? 1: 0; + const VoxelType pVoxel1nx1py1pz = volIter.peekVoxel1nx1py1pz() > 0 ? 1: 0; + + const VoxelType pVoxel0px1ny1nz = volIter.peekVoxel0px1ny1nz() > 0 ? 1: 0; + const VoxelType pVoxel0px1ny0pz = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0; + const VoxelType pVoxel0px1ny1pz = volIter.peekVoxel0px1ny1pz() > 0 ? 1: 0; + const VoxelType pVoxel0px0py1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0; + //const VoxelType pVoxel0px0py0pz = volIter.peekVoxel0px0py0pz() > 0 ? 1: 0; + const VoxelType pVoxel0px0py1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0; + const VoxelType pVoxel0px1py1nz = volIter.peekVoxel0px1py1nz() > 0 ? 1: 0; + const VoxelType pVoxel0px1py0pz = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0; + const VoxelType pVoxel0px1py1pz = volIter.peekVoxel0px1py1pz() > 0 ? 1: 0; + + const VoxelType pVoxel1px1ny1nz = volIter.peekVoxel1px1ny1nz() > 0 ? 1: 0; + const VoxelType pVoxel1px1ny0pz = volIter.peekVoxel1px1ny0pz() > 0 ? 1: 0; + const VoxelType pVoxel1px1ny1pz = volIter.peekVoxel1px1ny1pz() > 0 ? 1: 0; + const VoxelType pVoxel1px0py1nz = volIter.peekVoxel1px0py1nz() > 0 ? 1: 0; + const VoxelType pVoxel1px0py0pz = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0; + const VoxelType pVoxel1px0py1pz = volIter.peekVoxel1px0py1pz() > 0 ? 1: 0; + const VoxelType pVoxel1px1py1nz = volIter.peekVoxel1px1py1nz() > 0 ? 1: 0; + const VoxelType pVoxel1px1py0pz = volIter.peekVoxel1px1py0pz() > 0 ? 1: 0; + const VoxelType pVoxel1px1py1pz = volIter.peekVoxel1px1py1pz() > 0 ? 1: 0; + + const int xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - + weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * + pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz - + weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] * + pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz - + weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] * + pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz + + weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] * + pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz + + weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] * + pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz + + weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * + pVoxel1px1py1pz); + + const int yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - + weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * + pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz + + weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] * + pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz - + weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] * + pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz + + weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] * + pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz - + weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] * + pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz + + weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * + pVoxel1px1py1pz); + + const int zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz + + weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] * + pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz - + weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] * + pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz + + weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] * + pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz - + weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] * + pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz + + weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] * + pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz - + weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] * + pVoxel1px1py1pz); + + //Note: The above actually give gradients going from low density to high density. + //For our normals we want the the other way around, so we switch the components as we return them. + return Vector3DFloat(static_cast(-xGrad),static_cast(-yGrad),static_cast(-zGrad)); + } +} diff --git a/library/include/PolyVoxCore/IndexedSurfacePatch.h b/library/include/PolyVoxCore/IndexedSurfacePatch.h new file mode 100644 index 00000000..8058df72 --- /dev/null +++ b/library/include/PolyVoxCore/IndexedSurfacePatch.h @@ -0,0 +1,59 @@ +#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_IndexedSurfacePatch_H__ +#define __PolyVox_IndexedSurfacePatch_H__ + +#include + +#include "PolyVoxCStdInt.h" + +#include "Constants.h" +#include "PolyVoxForwardDeclarations.h" +#include "SurfaceVertex.h" +#include "TypeDef.h" + +namespace PolyVox +{ + class POLYVOX_API IndexedSurfacePatch + { + public: + IndexedSurfacePatch(); + ~IndexedSurfacePatch(); + + void addTriangle(const SurfaceVertex& v0,const SurfaceVertex& v1,const SurfaceVertex& v2); + void fillVertexAndIndexData(std::vector& vecVertices, std::vector& vecIndices); + + const std::vector& getVertices(void) const; + std::vector& getVertices(void); //FIXME - non const version should be removed. + const std::vector& getIndices(void) const; + + unsigned short getNoNonUniformTrianges(void); + unsigned short getNoUniformTrianges(void); + + public: + std::vector m_vecTriangleIndices; + std::vector m_vecVertices; + }; + +} + +#endif /* __IndexedSurfacePatch_H__ */ diff --git a/library/include/PolyVoxCore/LinearVolume.h b/library/include/PolyVoxCore/LinearVolume.h new file mode 100644 index 00000000..a4c9975b --- /dev/null +++ b/library/include/PolyVoxCore/LinearVolume.h @@ -0,0 +1,64 @@ +#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_LinearVolume_H__ +#define __PolyVox_LinearVolume_H__ + +#pragma region Headers +#include "Constants.h" +#include "PolyVoxForwardDeclarations.h" +#include "TypeDef.h" + +#include "PolyVoxCStdInt.h" +#pragma endregion + +namespace PolyVox +{ + template + class LinearVolume + { + public: + LinearVolume(uint8 uSideLengthPower); + LinearVolume(const LinearVolume& rhs); + ~LinearVolume(); + + LinearVolume& operator=(const LinearVolume& rhs); + + //bool isHomogeneous(void); + + uint16 getSideLength(void); + + VoxelType getVoxelAt(const uint16 xPosition, const uint16 yPosition, const uint16 zPosition) const; + void setVoxelAt(const uint16 xPosition, const uint16 yPosition, const uint16 zPosition, const VoxelType value); + + //void fillWithValue(const VoxelType value); + + private: + uint32 getNoOfVoxels(void); + uint8 m_uSideLengthPower; + uint16 m_uSideLength; + VoxelType* m_tData; + }; +} + +#include "LinearVolume.inl" + +#endif diff --git a/library/include/PolyVoxCore/LinearVolume.inl b/library/include/PolyVoxCore/LinearVolume.inl new file mode 100644 index 00000000..3e3a9b54 --- /dev/null +++ b/library/include/PolyVoxCore/LinearVolume.inl @@ -0,0 +1,102 @@ +#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 + +#include + +namespace PolyVox +{ + + template + LinearVolume::LinearVolume(uint8 uSideLengthPower) + :m_tData(0) + { + //Check the block size is sensible. This corresponds to a side length of 256 voxels + assert(uSideLengthPower <= 8); + + //Compute the side length + m_uSideLengthPower = uSideLengthPower; + m_uSideLength = 0x01 << uSideLengthPower; + + //If this fails an exception will be thrown. Memory is not + //allocated and there is nothing else in this class to clean up + m_tData = new VoxelType[getNoOfVoxels()]; + } + + template + LinearVolume::LinearVolume(const LinearVolume& rhs) + { + *this = rhs; + } + + template + LinearVolume::~LinearVolume() + { + delete[] m_tData; + m_tData = 0; + } + + template + LinearVolume& LinearVolume::operator=(const LinearVolume& rhs) + { + if (this == &rhs) + { + return *this; + } + + memcpy(m_tData,rhs.m_tData,getNoOfVoxels()); + + return *this; + } + + template + VoxelType LinearVolume::getVoxelAt(const uint16 xPosition, const uint16 yPosition, const uint16 zPosition) const + { + return m_tData + [ + xPosition + + yPosition * m_uSideLength + + zPosition * m_uSideLength * m_uSideLength + ]; + } + + template + void LinearVolume::setVoxelAt(const uint16 xPosition, const uint16 yPosition, const uint16 zPosition, const VoxelType value) + { + m_tData + [ + xPosition + + yPosition * m_uSideLength + + zPosition * m_uSideLength * m_uSideLength + ] = value; + } + + template + uint16 LinearVolume::getSideLength(void) + { + return m_uSideLength; + } + + template + uint32 LinearVolume::getNoOfVoxels(void) + { + return m_uSideLength * m_uSideLength * m_uSideLength; + } +} diff --git a/library/include/PolyVoxCore/MarchingCubesTables.h b/library/include/PolyVoxCore/MarchingCubesTables.h new file mode 100644 index 00000000..ca93972e --- /dev/null +++ b/library/include/PolyVoxCore/MarchingCubesTables.h @@ -0,0 +1,31 @@ +#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_MarchingCubeTables_H__ +#define __PolyVox_MarchingCubeTables_H__ + +namespace PolyVox +{ + extern int edgeTable[256]; + extern int triTable[256][16]; +} + +#endif diff --git a/library/include/PolyVoxCore/PolyVoxCStdInt.h b/library/include/PolyVoxCore/PolyVoxCStdInt.h new file mode 100644 index 00000000..1714c7e9 --- /dev/null +++ b/library/include/PolyVoxCore/PolyVoxCStdInt.h @@ -0,0 +1,38 @@ +#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_CStdInt_H__ +#define __PolyVox_CStdInt_H__ + +//Adding things to the std namespace in not actually allowed, but Microsoft +//have still not added to thier standard library. +namespace PolyVox +{ + typedef char int8; + typedef short int16; + typedef long int32; + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned long uint32; +} + + +#endif \ No newline at end of file diff --git a/library/include/PolyVoxCore/PolyVoxForwardDeclarations.h b/library/include/PolyVoxCore/PolyVoxForwardDeclarations.h new file mode 100644 index 00000000..1e8afd7b --- /dev/null +++ b/library/include/PolyVoxCore/PolyVoxForwardDeclarations.h @@ -0,0 +1,61 @@ +#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_ForwardDeclarations_H__ +#define __PolyVox_ForwardDeclarations_H__ + +#include "Enums.h" +#include "PolyVoxCStdInt.h" + +namespace PolyVox +{ + template class Block; + + //---------- BlockVolume ---------- + template class BlockVolume; + typedef BlockVolume FloatBlockVolume; + typedef BlockVolume UInt8BlockVolume; + typedef BlockVolume UInt16BlockVolume; + //--------------------------------- + + class IndexedSurfacePatch; + class IntegrealVector3; + template class LinearVolume; + class Region; + class RegionGeometry; + class SurfaceVertex; + + //---------- Vector ---------- + template class Vector; + typedef Vector<3,float> Vector3DFloat; + typedef Vector<3,double> Vector3DDouble; + typedef Vector<3,int8> Vector3DInt8; + typedef Vector<3,uint8> Vector3DUint8; + typedef Vector<3,int16> Vector3DInt16; + typedef Vector<3,uint16> Vector3DUint16; + typedef Vector<3,int32> Vector3DInt32; + typedef Vector<3,uint32> Vector3DUint32; + //---------------------------- + + template class BlockVolumeIterator; +} + +#endif diff --git a/library/include/PolyVoxCore/Region.h b/library/include/PolyVoxCore/Region.h new file mode 100644 index 00000000..91150166 --- /dev/null +++ b/library/include/PolyVoxCore/Region.h @@ -0,0 +1,55 @@ +#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_Region_H__ +#define __PolyVox_Region_H__ + +#pragma region Headers +#include "TypeDef.h" +#include "Vector.h" +#pragma endregion + +namespace PolyVox +{ + class POLYVOX_API Region + { + public: + Region(); + Region(const Vector3DInt32& v3dLowerCorner, const Vector3DInt32& v3dUpperCorner); + + const Vector3DInt32& getLowerCorner(void) const; + const Vector3DInt32& getUpperCorner(void) const; + + void setLowerCorner(const Vector3DInt32& v3dLowerCorner); + void setUpperCorner(const Vector3DInt32& v3dUpperCorner); + + bool containsPoint(const Vector3DFloat& pos, float boundary) const; + bool containsPoint(const Vector3DInt32& pos, uint8 boundary) const; + void cropTo(const Region& other); + void shift(const Vector3DInt32& amount); + + private: + Vector3DInt32 m_v3dLowerCorner; + Vector3DInt32 m_v3dUpperCorner; + }; +} + +#endif diff --git a/library/include/PolyVoxCore/RegionGeometry.h b/library/include/PolyVoxCore/RegionGeometry.h new file mode 100644 index 00000000..78d43715 --- /dev/null +++ b/library/include/PolyVoxCore/RegionGeometry.h @@ -0,0 +1,44 @@ +#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_RegionGeometry_H__ +#define __PolyVox_RegionGeometry_H__ + +#include "PolyVoxForwardDeclarations.h" +#include "TypeDef.h" +#include "Vector.h" + +namespace PolyVox +{ + class POLYVOX_API RegionGeometry + { + public: + RegionGeometry(); + + bool m_bIsEmpty; + bool m_bContainsSingleMaterialPatch; + + Vector3DInt32 m_v3dRegionPosition; + IndexedSurfacePatch* m_patchSingleMaterial; + }; +} + +#endif diff --git a/library/include/PolyVoxCore/SurfaceAdjusters.h b/library/include/PolyVoxCore/SurfaceAdjusters.h new file mode 100644 index 00000000..39561947 --- /dev/null +++ b/library/include/PolyVoxCore/SurfaceAdjusters.h @@ -0,0 +1,39 @@ +#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_SurfaceAdjusters_H__ +#define __PolyVox_SurfaceAdjusters_H__ + +#pragma region Headers +#include "Constants.h" +#include "PolyVoxForwardDeclarations.h" +#include "TypeDef.h" + +#include "PolyVoxCStdInt.h" +#pragma endregion + +namespace PolyVox +{ + POLYVOX_API void smoothRegionGeometry(BlockVolume* volumeData, RegionGeometry& regGeom); + POLYVOX_API void adjustDecimatedGeometry(BlockVolume* volumeData, RegionGeometry& regGeom, uint8 val); +} + +#endif \ No newline at end of file diff --git a/library/include/PolyVoxCore/SurfaceEdge.h b/library/include/PolyVoxCore/SurfaceEdge.h new file mode 100644 index 00000000..a020592d --- /dev/null +++ b/library/include/PolyVoxCore/SurfaceEdge.h @@ -0,0 +1,65 @@ +/****************************************************************************** +This file is part of a voxel plugin for OGRE +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. +******************************************************************************/ + +#ifndef __PolyVox_SurfaceEdge_H__ +#define __PolyVox_SurfaceEdge_H__ + +#include "SurfaceTypes.h" + +namespace PolyVox +{ + class SurfaceEdge + { + public: + SurfaceEdge(const SurfaceVertexIterator& targetToSet,const SurfaceVertexIterator& sourceToSet); + + friend bool operator == (const SurfaceEdge& lhs, const SurfaceEdge& rhs); + friend bool operator < (const SurfaceEdge& lhs, const SurfaceEdge& rhs); + + + std::string tostring(void); + + bool isDegenerate(void); + + const SurfaceVertexIterator& getTarget(void) const; + const SurfaceVertexIterator& getSource(void) const; + const SurfaceEdgeIterator& getOtherHalfEdge(void) const; + const SurfaceEdgeIterator& getPreviousHalfEdge(void) const; + const SurfaceEdgeIterator& getNextHalfEdge(void) const; + const SurfaceTriangleIterator& getTriangle(void) const; + + void setPreviousHalfEdge(const SurfaceEdgeIterator& previousHalfEdgeToSet); + void setNextHalfEdge(const SurfaceEdgeIterator& nextHalfEdgeToSet); + void setTriangle(const SurfaceTriangleIterator& triangleToSet); + + void pairWithOtherHalfEdge(const SurfaceEdgeIterator& otherHalfEdgeToPair); + + private: + SurfaceVertexIterator target; + SurfaceVertexIterator source; + + SurfaceEdgeIterator previousHalfEdge; + SurfaceEdgeIterator nextHalfEdge; + SurfaceEdgeIterator otherHalfEdge; + + SurfaceTriangleIterator triangle; + }; +} + +#endif diff --git a/library/include/PolyVoxCore/SurfaceExtractors.h b/library/include/PolyVoxCore/SurfaceExtractors.h new file mode 100644 index 00000000..95255c8b --- /dev/null +++ b/library/include/PolyVoxCore/SurfaceExtractors.h @@ -0,0 +1,51 @@ +#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_SurfaceExtractors_H__ +#define __PolyVox_SurfaceExtractors_H__ + +#pragma region Headers +#include "Constants.h" +#include "PolyVoxForwardDeclarations.h" +#include "TypeDef.h" + +#include "PolyVoxCStdInt.h" + +#include +#pragma endregion + +namespace PolyVox +{ + uint32 getIndex(uint32 x, uint32 y); + + POLYVOX_API void generateRoughMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch); + POLYVOX_API uint32 computeInitialRoughBitmaskForSlice(BlockVolumeIterator& volIter, const Region& regSlice, const Vector3DFloat& offset, uint8 *bitmask); + POLYVOX_API uint32 computeRoughBitmaskForSliceFromPrevious(BlockVolumeIterator& volIter, const Region& regSlice, const Vector3DFloat& offset, uint8 *bitmask, uint8 *previousBitmask); + POLYVOX_API void generateRoughIndicesForSlice(BlockVolumeIterator& volIter, const Region& regSlice, IndexedSurfacePatch* singleMaterialPatch, const Vector3DFloat& offset, uint8* bitmask0, uint8* bitmask1, int32 vertexIndicesX0[],int32 vertexIndicesY0[],int32 vertexIndicesZ0[], int32 vertexIndicesX1[],int32 vertexIndicesY1[],int32 vertexIndicesZ1[]); + POLYVOX_API void generateRoughVerticesForSlice(BlockVolumeIterator& volIter, Region& regSlice, const Vector3DFloat& offset, uint8* bitmask, IndexedSurfacePatch* singleMaterialPatch,int32 vertexIndicesX[],int32 vertexIndicesY[],int32 vertexIndicesZ[]); + + POLYVOX_API void generateReferenceMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch); + + int32 getIndexFor(const Vector3DFloat& pos, int32 vertexIndicesX[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1], int32 vertexIndicesY[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1], int32 vertexIndicesZ[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1]); + void setIndexFor(const Vector3DFloat& pos, int32 newIndex, int32 vertexIndicesX[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1], int32 vertexIndicesY[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1], int32 vertexIndicesZ[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1]); +} + +#endif diff --git a/library/include/PolyVoxCore/SurfaceExtractorsDecimated.h b/library/include/PolyVoxCore/SurfaceExtractorsDecimated.h new file mode 100644 index 00000000..95c5e43a --- /dev/null +++ b/library/include/PolyVoxCore/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 "PolyVoxCStdInt.h" + +#include +#pragma endregion + +namespace PolyVox +{ + uint32 getDecimatedIndex(uint32 x, uint32 y); + + POLYVOX_API void generateDecimatedMeshDataForRegion(BlockVolume* volumeData, uint8 uLevel, Region region, IndexedSurfacePatch* singleMaterialPatch); + POLYVOX_API uint32 computeInitialDecimatedBitmaskForSlice(BlockVolumeIterator& volIter, uint8 uLevel, const Region& regSlice, const Vector3DFloat& offset, uint8 *bitmask); + POLYVOX_API uint32 computeDecimatedBitmaskForSliceFromPrevious(BlockVolumeIterator& volIter, uint8 uLevel, const Region& regSlice, const Vector3DFloat& offset, uint8 *bitmask, uint8 *previousBitmask); + POLYVOX_API void generateDecimatedIndicesForSlice(BlockVolumeIterator& volIter, uint8 uLevel, const Region& regSlice, IndexedSurfacePatch* singleMaterialPatch, const Vector3DFloat& offset, uint8* bitmask0, uint8* bitmask1, int32 vertexIndicesX0[],int32 vertexIndicesY0[],int32 vertexIndicesZ0[], int32 vertexIndicesX1[],int32 vertexIndicesY1[],int32 vertexIndicesZ1[]); + POLYVOX_API void generateDecimatedVerticesForSlice(BlockVolumeIterator& volIter, uint8 uLevel, Region& regSlice, const Vector3DFloat& offset, uint8* bitmask, IndexedSurfacePatch* singleMaterialPatch,int32 vertexIndicesX[],int32 vertexIndicesY[],int32 vertexIndicesZ[]); + + 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/library/include/PolyVoxCore/SurfaceTriangle.h b/library/include/PolyVoxCore/SurfaceTriangle.h new file mode 100644 index 00000000..5f9756e8 --- /dev/null +++ b/library/include/PolyVoxCore/SurfaceTriangle.h @@ -0,0 +1,50 @@ +/****************************************************************************** +This file is part of a voxel plugin for OGRE +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. +******************************************************************************/ + +#ifndef __PolyVox_SurfaceTriangle_H__ +#define __PolyVox_SurfaceTriangle_H__ + +#include "SurfaceTypes.h" + +namespace PolyVox +{ + class SurfaceTriangle + { + public: + SurfaceTriangle(); + + friend bool operator == (const SurfaceTriangle& lhs, const SurfaceTriangle& rhs); + friend bool operator < (const SurfaceTriangle& lhs, const SurfaceTriangle& rhs); + + const SurfaceEdgeIterator& getEdge(void) const; + + void setEdge(const SurfaceEdgeIterator& edgeToSet); + + //std::string tostring(void); + + private: + SurfaceEdgeIterator edge; + }; + + + + //bool operator < (const SurfaceTriangleIterator& lhs, const SurfaceTriangleIterator& rhs); +} + +#endif diff --git a/library/include/PolyVoxCore/SurfaceTypes.h b/library/include/PolyVoxCore/SurfaceTypes.h new file mode 100644 index 00000000..a7a4aa22 --- /dev/null +++ b/library/include/PolyVoxCore/SurfaceTypes.h @@ -0,0 +1,19 @@ +#ifndef __PolyVox_SurfaceTypes_H__ +#define __PolyVox_SurfaceTypes_H__ + +#include + +namespace PolyVox +{ + class SurfaceVertex; + typedef std::set::iterator SurfaceVertexIterator; + typedef std::set::const_iterator SurfaceVertexConstIterator; + class SurfaceTriangle; + typedef std::set::iterator SurfaceTriangleIterator; + typedef std::set::const_iterator SurfaceTriangleConstIterator; + class SurfaceEdge; + typedef std::set::iterator SurfaceEdgeIterator; + typedef std::set::const_iterator SurfaceEdgeConstIterator; +} + +#endif diff --git a/library/include/PolyVoxCore/SurfaceVertex.h b/library/include/PolyVoxCore/SurfaceVertex.h new file mode 100644 index 00000000..3d5f46fe --- /dev/null +++ b/library/include/PolyVoxCore/SurfaceVertex.h @@ -0,0 +1,60 @@ +#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_SurfaceVertex_H__ +#define __PolyVox_SurfaceVertex_H__ + +#include "TypeDef.h" +#include "Vector.h" + +namespace PolyVox +{ + class POLYVOX_API SurfaceVertex + { + public: + SurfaceVertex(); + SurfaceVertex(Vector3DFloat positionToSet, float materialToSet); + SurfaceVertex(Vector3DFloat positionToSet, Vector3DFloat normalToSet, float materialToSet); + + float getMaterial(void) const; + const Vector3DFloat& getNormal(void) const; + const Vector3DFloat& getPosition(void) const; + + void setMaterial(float materialToSet); + void setNormal(const Vector3DFloat& normalToSet); + void setPosition(const Vector3DFloat& positionToSet); + + std::string tostring(void) const; + + private: + Vector3DFloat position; + Vector3DFloat normal; + float material; + + }; + + + + + //bool operator < (const SurfaceVertexIterator& lhs, const SurfaceVertexIterator& rhs); +} + +#endif diff --git a/library/include/PolyVoxCore/TypeDef.h b/library/include/PolyVoxCore/TypeDef.h new file mode 100644 index 00000000..38a863d1 --- /dev/null +++ b/library/include/PolyVoxCore/TypeDef.h @@ -0,0 +1,37 @@ +#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 + +//Dave, maybe make use of OgrePlatform.h instead? +// I think use _OgreExport instead of POLYVOX_API and define OGRE_NONCLIENT_BUILD instead of POLYVOX_EXPORT? +#ifndef __PolyVox_TypeDef_H__ +#define __PolyVox_TypeDef_H__ + +#ifdef WIN32 + #ifdef POLYVOX_EXPORT + #define POLYVOX_API __declspec(dllexport) + #else + #define POLYVOX_API __declspec(dllimport) + #endif +#else + #define POLYVOX_API __attribute__ ((visibility("default"))) +#endif + +#endif diff --git a/library/include/PolyVoxCore/Utility.h b/library/include/PolyVoxCore/Utility.h new file mode 100644 index 00000000..a2c5b655 --- /dev/null +++ b/library/include/PolyVoxCore/Utility.h @@ -0,0 +1,60 @@ +#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_Utility_H__ +#define __PolyVox_Utility_H__ + +#include "TypeDef.h" + +#include "PolyVoxForwardDeclarations.h" + +namespace PolyVox +{ + POLYVOX_API uint8 logBase2(uint32 uInput); + POLYVOX_API bool isPowerOf2(uint32 uInput); + + template + Type trilinearlyInterpolate( + const Type& v000,const Type& v100,const Type& v010,const Type& v110, + const Type& v001,const Type& v101,const Type& v011,const Type& v111, + const float x, const float y, const float z) + { + assert((x >= 0.0f) && (y >= 0.0f) && (z >= 0.0f) && + (x <= 1.0f) && (y <= 1.0f) && (z <= 1.0f)); + + //Interpolate along X + Type v000_v100 = (v100 - v000) * x + v000; + Type v001_v101 = (v101 - v001) * x + v001; + Type v010_v110 = (v110 - v010) * x + v010; + Type v011_v111 = (v111 - v011) * x + v011; + + //Interpolate along Y + Type v000_v100__v010_v110 = (v010_v110 - v000_v100) * y + v000_v100; + Type v001_v101__v011_v111 = (v011_v111 - v001_v101) * y + v001_v101; + + //Interpolate along Z + Type v000_v100__v010_v110____v001_v101__v011_v111 = (v001_v101__v011_v111 - v000_v100__v010_v110) * z + v000_v100__v010_v110; + + return v000_v100__v010_v110____v001_v101__v011_v111; + } +} + +#endif diff --git a/library/include/PolyVoxCore/Vector.h b/library/include/PolyVoxCore/Vector.h new file mode 100644 index 00000000..c5a16cba --- /dev/null +++ b/library/include/PolyVoxCore/Vector.h @@ -0,0 +1,150 @@ +#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_Vector_H__ +#define __PolyVox_Vector_H__ + +#pragma region Headers +#include "PolyVoxForwardDeclarations.h" + +#include +#pragma endregion + +namespace PolyVox +{ + ///Represents a vector in space. + template + class Vector + { + public: + ///Constructor. + Vector(Type x, Type y) throw(); + ///Constructor. + Vector(Type x, Type y, Type z) throw(); + ///Constructor. + Vector(Type x, Type y, Type z, Type w) throw(); + ///Constructor + Vector(void) throw(); + ///Copy Constructor. + Vector(const Vector& vector) throw(); + ///Copy Constructor which performs casting. + template explicit Vector(const Vector& vector) throw(); + ///Destructor. + ~Vector(void) throw(); + + ///Assignment Operator. + Vector& operator=(const Vector& rhs) throw(); + ///Equality Operator. + bool operator==(const Vector& rhs) const throw(); + ///Comparison Operator. + bool operator<(const Vector& rhs) const throw(); + ///Addition and Assignment Operator. + Vector& operator+=(const Vector &rhs) throw(); + ///Subtraction and Assignment Operator. + Vector& operator-=(const Vector &rhs) throw(); + ///Multiplication and Assignment Operator. + Vector& operator*=(const Type& rhs) throw(); + ///Division and Assignment Operator. + Vector& operator/=(const Type& rhs) throw(); + + ///Element Access + Type getElement(uint32 index) const throw(); + ///Get the x component of the vector. + Type getX(void) const throw(); + ///Get the y component of the vector. + Type getY(void) const throw(); + ///Get the z component of the vector. + Type getZ(void) const throw(); + ///Get the w component of the vector. + Type getW(void) const throw(); + + ///Element Access + void setElement(uint32 index, Type tValue) throw(); + ///Set the x component of the vector. + void setX(Type tX) throw(); + ///Set the y component of the vector. + void setY(Type tY) throw(); + ///Set the z component of the vector. + void setZ(Type tZ) throw(); + ///Set the w component of the vector. + void setW(Type tW) throw(); + + ///Get the length of the vector. + double length(void) const throw(); + ///Get the squared length of the vector. + double lengthSquared(void) const throw(); + ///Find the angle between this vector and that which is passed as a parameter. + double angleTo(const Vector& vector) const throw(); + ///Find the cross product between this vector and the vector passed as a parameter. + Vector cross(const Vector& vector) const throw(); + ///Find the dot product between this vector and the vector passed as a parameter. + Type dot(const Vector& rhs) const throw(); + ///Normalise the vector. + void normalise(void) throw(); + + private: + //Values for the vector + Type m_tElements[Size]; + }; + + //Non-member overloaded operators. + ///Addition operator. + template + Vector operator+(const Vector& lhs, const Vector& rhs) throw(); + ///Subtraction operator. + template + Vector operator-(const Vector& lhs, const Vector& rhs) throw(); + ///Multiplication operator. + template + Vector operator*(const Vector& lhs, const Type& rhs) throw(); + ///Division operator. + template + Vector operator/(const Vector& lhs, const Type& rhs) throw(); + ///Stream insertion operator. + template + std::ostream& operator<<(std::ostream& os, const Vector& vector) throw(); + + //Some handy typedefs + ///A 3D Vector of floats. + typedef Vector<3,float> Vector3DFloat; + ///A 3D Vector of doubles. + typedef Vector<3,double> Vector3DDouble; + ///A 3D Vector of signed 8-bit values. + typedef Vector<3,int8> Vector3DInt8; + ///A 3D Vector of unsigned 8-bit values. + typedef Vector<3,uint8> Vector3DUint8; + ///A 3D Vector of signed 16-bit values. + typedef Vector<3,int16> Vector3DInt16; + ///A 3D Vector of unsigned 16-bit values. + typedef Vector<3,uint16> Vector3DUint16; + ///A 3D Vector of signed 32-bit values. + typedef Vector<3,int32> Vector3DInt32; + ///A 3D Vector of unsigned 32-bit values. + typedef Vector<3,uint32> Vector3DUint32; + + + +}//namespace Thermite + +#include "Vector.inl" + +#endif + diff --git a/library/include/PolyVoxCore/Vector.inl b/library/include/PolyVoxCore/Vector.inl new file mode 100644 index 00000000..e21dfd2e --- /dev/null +++ b/library/include/PolyVoxCore/Vector.inl @@ -0,0 +1,536 @@ +#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 + +#include +#include +#include + +namespace PolyVox +{ + /** + This Vector class is templated on both size and data type. It is designed to be + generic but so far had only been tested with vectors of size 2 and 3. Also note + that some of the operations do not make sense with integer types, for example it + does not make conceptual sense to try and normalise an integer Vector. + + The elements of the Vector are accessed via the overloaded () operator which takes + an index indicating the element to fetch. They are set using the set() function which + takes an index indicating the element to set and a new value for that element. For + convienience, the functions getX(), setX(), getY(), setY(), getZ(), setZ, w() and setW() + do the same thing for the first 4 elements of the Vector. + + A variety of overloaded operators are also provided for comparison and arithmetic + operations. For most of these arithmetic operators only the unary versions are + documented below - however often binary versions are also generated by std::operators. + + Lastly, note that for convienience a set of typedefs are included for 2 and 3 dimentionsal + vectors with type float, double, int32, and uint32. They are used as follows: + + Vector2DInt4 test(1,2); //Declares a 2 dimensional Vector of type int4. + */ + + #pragma region Constructors/Destructors + //-------------------------- Constructors, etc --------------------------------- + /** + Creates a Vector object and initialises it with given values. + \param x x component to set. + \param y y component to set. + */ + template + Vector::Vector(Type x, Type y) throw() + { + m_tElements[0] = x; + m_tElements[1] = y; + + } + + /** + Creates a Vector3D object and initialises it with given values. + \param x x component to set. + \param y y component to set. + \param z z component to set. + */ + template + Vector::Vector(Type x, Type y, Type z) throw() + { + m_tElements[0] = x; + m_tElements[1] = y; + m_tElements[2] = z; + + } + + /** + Creates a Vector3D object and initialises it with given values. + \param x x component to set. + \param y y component to set. + \param z z component to set. + \param w w component to set. + */ + template + Vector::Vector(Type x, Type y, Type z, Type w) throw() + { + m_tElements[0] = x; + m_tElements[1] = y; + m_tElements[2] = z; + m_tElements[3] = w; + } + + /** + Creates a Vector object but does not initialise it. + */ + template + Vector::Vector(void) throw() + { + } + + /** + Copy constructor builds object based on object passed as parameter. + \param vector A reference to the Vector to be copied. + */ + template + Vector::Vector(const Vector& vector) throw() + { + std::memcpy(m_tElements, vector.m_tElements, sizeof(Type) * Size); + } + + /** + This copy constructor allows casting between vectors with different data types. + It is now possible to use code such as: + + Vector3DDouble v3dDouble(1.0,2.0,3.0); + Vector3DFloat v3dFloat = static_cast(v3dDouble); //Casting + + \param vector A reference to the Vector to be copied. + */ + template + template + Vector::Vector(const Vector& vector) throw() + { + for(uint32 ct = 0; ct < Size; ++ct) + { + m_tElements[ct] = static_cast(vector.getElement(ct)); + } + } + + /** + Destroys the Vector. + */ + template + Vector::~Vector(void) throw() + { + } + #pragma endregion + + #pragma region Operators + /** + Assignment operator copies each element of first Vector to the second. + \param rhs Vector to assign to. + \return A reference to the result to allow chaining. + */ + template + Vector& Vector::operator=(const Vector& rhs) throw() + { + if(this == &rhs) + { + return *this; + } + std::memcpy(m_tElements, rhs.m_tElements, sizeof(Type) * Size); + return *this; + } + + /** + Checks whether two Vectors are equal. + \param rhs The Vector to compare to. + \return true if the Vectors match. + \see operator!= + */ + template + inline bool Vector::operator==(const Vector &rhs) const throw() + { + bool equal = true; + for(uint32 ct = 0; ct < Size; ++ct) + { + if(m_tElements[ct] != rhs(ct)) + { + equal = false; + break; + } + } + return equal; + } + + /** + Checks whether this vector is less than the parameter. The metric is + meaningless but it allows Vectors to me used as key in sdt::map, etc. + \param rhs The Vector to compare to. + \return true if this is less than the parameter + \see operator!= + */ + template + inline bool Vector::operator<(const Vector &rhs) const throw() + { + for(int ct = 0; ct < Size; ++ct) + { + if (m_tElements[ct] < rhs.m_tElements[ct]) + return true; + if (rhs.m_tElements[ct] < m_tElements[ct]) + return false; + } + return false; + } + + /** + Addition operator adds corresponding elements of the two Vectors. + \param rhs Vector to add + \return The resulting Vector. + */ + template + inline Vector& Vector::operator+=(const Vector& rhs) throw() + { + for(uint32 ct = 0; ct < Size; ++ct) + { + m_tElements[ct] += rhs.m_tElements[ct]; + } + return *this; + } + + /** + Addition operator adds corresponding elements of the two Vectors. + \param lhs Vector to add to. + \param rhs Vector to add. + \return The resulting Vector. + */ + template + Vector operator+(const Vector& lhs, const Vector& rhs) throw() + { + Vector result = lhs; + result += rhs; + return result; + } + + /** + Subtraction operator subtracts corresponding elements of one Vector from the other. + \param rhs Vector to subtract + \return The resulting Vector. + */ + template + inline Vector& Vector::operator-=(const Vector& rhs) throw() + { + for(uint32 ct = 0; ct < Size; ++ct) + { + m_tElements[ct] -= rhs.m_tElements[ct]; + } + return *this; + } + + /** + Subtraction operator subtracts corresponding elements of one Vector from the other. + \param lhs Vector to subtract from. + \param rhs Vector to subtract. + \return The resulting Vector. + */ + template + Vector operator-(const Vector& lhs, const Vector& rhs) throw() + { + Vector result = lhs; + result -= rhs; + return result; + } + + /** + Multiplication operator multiplies each element of the Vector by a number. + \param rhs the number the Vector is multiplied by. + \return The resulting Vector. + */ + template + inline Vector& Vector::operator*=(const Type& rhs) throw() + { + for(uint32 ct = 0; ct < Size; ++ct) + { + m_tElements[ct] *= rhs; + } + return *this; + } + + /** + Multiplication operator multiplies each element of the Vector by a number. + \param lhs the Vector to multiply. + \param rhs the number the Vector is multiplied by. + \return The resulting Vector. + */ + template + Vector operator*(const Vector& lhs, const Type& rhs) throw() + { + Vector result = lhs; + result *= rhs; + return result; + } + + /** + Division operator divides each element of the Vector by a number. + \param rhs the number the Vector is divided by. + \return The resulting Vector. + */ + template + inline Vector& Vector::operator/=(const Type& rhs) throw() + { + for(uint32 ct = 0; ct < Size; ++ct) + { + m_tElements[ct] /= rhs; + } + return *this; + } + + /** + Division operator divides each element of the Vector by a number. + \param lhs the Vector to divide. + \param rhs the number the Vector is divided by. + \return The resulting Vector. + */ + template + Vector operator/(const Vector& lhs, const Type& rhs) throw() + { + Vector result = lhs; + result /= rhs; + return result; + } + + /** + Enables the Vector to be used intuitively with output streams such as cout. + \param os The output stream to write to. + \param vector The Vector to write to the stream. + \return A reference to the output stream to allow chaining. + */ + template + std::ostream& operator<<(std::ostream& os, const Vector& vector) throw() + { + os << "("; + for(uint32 ct = 0; ct < Size; ++ct) + { + os << vector.getElement(ct); + if(ct < (Size-1)) + { + os << ","; + } + } + os << ")"; + return os; + } + #pragma endregion + + #pragma region Getters + /** + Returns the element at the given position. + \param index The index of the element to return. + \return The element. + */ + template + inline Type Vector::getElement(uint32 index) const throw() + { + return m_tElements[index]; + } + + /** + \return A const reference to the X component of a 1, 2, 3, or 4 dimensional Vector. + */ + template + inline Type Vector::getX(void) const throw() + { + return m_tElements[0]; + } + + /** + \return A const reference to the Y component of a 2, 3, or 4 dimensional Vector. + */ + template + inline Type Vector::getY(void) const throw() + { + return m_tElements[1]; + } + + /** + \return A const reference to the Z component of a 3 or 4 dimensional Vector. + */ + template + inline Type Vector::getZ(void) const throw() + { + return m_tElements[2]; + } + + /** + \return A const reference to the W component of a 4 dimensional Vector. + */ + template + inline Type Vector::getW(void) const throw() + { + return m_tElements[3]; + } + #pragma endregion + + #pragma region Setters + /** + \param index The index of the element to set. + \param tValue The new value for the element. + */ + template + inline void Vector::setElement(uint32 index, Type tValue) throw() + { + m_tElements[index] = tValue; + } + + /** + \param tX The new value for the X component of a 1, 2, 3, or 4 dimensional Vector. + */ + template + inline void Vector::setX(Type tX) throw() + { + m_tElements[0] = tX; + } + + /** + \param tX The new value for the Y component of a 2, 3, or 4 dimensional Vector. + */ + template + inline void Vector::setY(Type tY) throw() + { + m_tElements[1] = tY; + } + + /** + \param tX The new value for the Z component of a 3 or 4 dimensional Vector. + */ + template + inline void Vector::setZ(Type tZ) throw() + { + m_tElements[2] = tZ; + } + + /** + \param tX The new value for the W component of a 4 dimensional Vector. + */ + template + inline void Vector::setW(Type tW) throw() + { + m_tElements[3] = tW; + } + #pragma endregion + + #pragma region Others + /** + NOTE: This function does not make much sense on integer Vectors. + \return Length of the Vector. + */ + template + inline double Vector::length(void) const throw() + { + return sqrt(lengthSquared()); + } + + /** + \return Squared length of the Vector. + */ + template + inline double Vector::lengthSquared(void) const throw() + { + double result = 0.0f; + for(uint32 ct = 0; ct < Size; ++ct) + { + result += m_tElements[ct] * m_tElements[ct]; + } + return result; + } + + /** + This function is commutative, such that a.angleTo(b) == b.angleTo(a). The angle + returned is in radians and varies between 0 and 3.14(pi). It is always positive. + + NOTE: This function does not make much sense on integer Vectors. + + \param Vector3D The Vector to find the angle to. + \return The angle between them in radians. + */ + template + inline double Vector::angleTo(const Vector& vector) const throw() + { + return acos(dot(vector) / (vector.length() * this->length())); + } + + /** + This function is used to calculate the cross product of two Vectors. + The cross product is the Vector which is perpendicular to the two + given Vectors. It is worth remembering that, unlike the dot product, + it is not commutative. E.g a.b != b.a. The cross product obeys the + right-hand rule such that if the two vectors are given by the index + finger and middle finger respectively then the cross product is given + by the thumb. + \param a first Vector. + \param b Second Vector. + \return The value of the cross product. + \see dot() + */ + template + inline Vector Vector::cross(const Vector& vector) const throw() + { + Type i = vector.getZ() * this->getY() - vector.getY() * this->getZ(); + Type j = vector.getX() * this->getZ() - vector.getZ() * this->getX(); + Type k = vector.getY() * this->getX() - vector.getX() * this->getY(); + return Vector(i,j,k); + } + + /** + Calculates the dot product of the Vector and the parameter. + This function is commutative, such that a.dot(b) == b.dot(a). + \param rhs The Vector to find the dot product with. + \return The value of the dot product. + \see cross() + */ + template + inline Type Vector::dot(const Vector& rhs) const throw() + { + Type dotProduct = static_cast(0); + for(uint32 ct = 0; ct < Size; ++ct) + { + dotProduct += m_tElements[ct] * rhs.m_tElements[ct]; + } + return dotProduct; + } + + /** + Divides the i, j, and k components by the length to give a Vector of length 1.0. + + NOTE: This function does not make much sense on integer Vectors. + */ + template + inline void Vector::normalise(void) throw() + { + double length = this->length(); + //FIXME - throw div by zero exception? + if(length < 0.0001f) + { + return; + } + for(uint32 ct = 0; ct < Size; ++ct) + { + m_tElements[ct] /= static_cast(length); + } + } + #pragma endregion +}//namespace Thermite diff --git a/library/include/PolyVoxCore/VoxelFilters.h b/library/include/PolyVoxCore/VoxelFilters.h new file mode 100644 index 00000000..5d52c823 --- /dev/null +++ b/library/include/PolyVoxCore/VoxelFilters.h @@ -0,0 +1,36 @@ +#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_VoxelFilters_H__ +#define __PolyVox_VoxelFilters_H__ + +#pragma region Headers +#include "Constants.h" +#include "PolyVoxForwardDeclarations.h" +#include "TypeDef.h" +#pragma endregion + +namespace PolyVox +{ + float computeSmoothedVoxel(BlockVolumeIterator& volIter); +} + +#endif \ No newline at end of file diff --git a/library/include/PolyVoxUtil/VolumeChangeTracker.h b/library/include/PolyVoxUtil/VolumeChangeTracker.h new file mode 100644 index 00000000..8fdb263e --- /dev/null +++ b/library/include/PolyVoxUtil/VolumeChangeTracker.h @@ -0,0 +1,69 @@ +#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_VolumeChangeTracker_H__ +#define __PolyVox_VolumeChangeTracker_H__ + +#include + +#include "PolyVoxCore/Constants.h" +#include "PolyVoxCore/PolyVoxForwardDeclarations.h" +#include "PolyVoxCore/Region.h" +#include "PolyVoxCore/TypeDef.h" + +namespace PolyVox +{ + /// Voxel scene manager + class POLYVOX_API VolumeChangeTracker + { + public: + //Constructors, etc + VolumeChangeTracker(); + ~VolumeChangeTracker(); + + //Getters + void getChangedRegions(std::list& listToFill) const; + Region getEnclosingRegion(void) const; + uint16 getSideLength(void); + BlockVolume* getVolumeData(void) const; + uint8 getVoxelAt(const Vector3DUint16& pos); + uint8 getVoxelAt(uint16 uX, uint16 uY, uint16 uZ); + + //Setters + void setAllRegionsUpToDate(bool newUpToDateValue); + void setLockedVoxelAt(uint16 x, uint16 y, uint16 z, uint8 value); + void setVolumeData(BlockVolume* volumeDataToSet); + void setVoxelAt(uint16 x, uint16 y, uint16 z, uint8 value); + + //Others + void lockRegion(const Region& regToLock); + void unlockRegion(void); + //void markRegionChanged(uint16 firstX, uint16 firstY, uint16 firstZ, uint16 lastX, uint16 lastY, uint16 lastZ); + + private: + bool m_bIsLocked; + Region m_regLastLocked; + BlockVolume* volumeData; + LinearVolume* volRegionUpToDate; + }; +} + +#endif diff --git a/library/source/PolyVoxCore/GradientEstimators.cpp b/library/source/PolyVoxCore/GradientEstimators.cpp new file mode 100644 index 00000000..565b5f8c --- /dev/null +++ b/library/source/PolyVoxCore/GradientEstimators.cpp @@ -0,0 +1,174 @@ +#include "PolyVoxCore/GradientEstimators.h" +#include "PolyVoxCore/IndexedSurfacePatch.h" +#include "PolyVoxCore/RegionGeometry.h" +#include "PolyVoxCore/SurfaceVertex.h" + +#include "PolyVoxCore/PolyVoxCStdInt.h" + +using namespace std; + +namespace PolyVox +{ + POLYVOX_API void computeNormalsForVertices(BlockVolume* volumeData, RegionGeometry& regGeom, NormalGenerationMethod normalGenerationMethod) + { + std::vector& vecVertices = regGeom.m_patchSingleMaterial->m_vecVertices; + std::vector::iterator iterSurfaceVertex = vecVertices.begin(); + while(iterSurfaceVertex != vecVertices.end()) + { + const Vector3DFloat& v3dPos = iterSurfaceVertex->getPosition() + static_cast(regGeom.m_v3dRegionPosition); + const Vector3DInt32 v3dFloor = static_cast(v3dPos); + + BlockVolumeIterator volIter(*volumeData); + + //Check all corners are within the volume, allowing a boundary for gradient estimation + bool lowerCornerInside = volumeData->containsPoint(v3dFloor,1); + bool upperCornerInside = volumeData->containsPoint(v3dFloor+Vector3DInt32(1,1,1),1); + + if(lowerCornerInside && upperCornerInside) //If this test fails the vertex will be left as it was + { + Vector3DFloat v3dGradient; //To store the result + + if(normalGenerationMethod == SOBEL) + { + volIter.setPosition(static_cast(v3dFloor)); + const Vector3DFloat gradFloor = computeSobelGradient(volIter); + if((v3dPos.getX() - v3dFloor.getX()) > 0.001) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(1,0,0))); + } + if((v3dPos.getY() - v3dFloor.getY()) > 0.001) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(0,1,0))); + } + if((v3dPos.getZ() - v3dFloor.getZ()) > 0.001) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(0,0,1))); + } + const Vector3DFloat gradCeil = computeSobelGradient(volIter); + v3dGradient = (gradFloor + gradCeil); + } + if(normalGenerationMethod == CENTRAL_DIFFERENCE) + { + volIter.setPosition(static_cast(v3dFloor)); + const Vector3DFloat gradFloor = computeCentralDifferenceGradient(volIter); + if((v3dPos.getX() - v3dFloor.getX()) > 0.001) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(1,0,0))); + } + if((v3dPos.getY() - v3dFloor.getY()) > 0.001) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(0,1,0))); + } + if((v3dPos.getZ() - v3dFloor.getZ()) > 0.001) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(0,0,1))); + } + const Vector3DFloat gradCeil = computeCentralDifferenceGradient(volIter); + v3dGradient = (gradFloor + gradCeil); + } + if(v3dGradient.lengthSquared() > 0.0001) + { + //If we got a normal of significant length then update it. + //Otherwise leave it as it was (should be the 'simple' version) + v3dGradient.normalise(); + iterSurfaceVertex->setNormal(v3dGradient); + } + } //(lowerCornerInside && upperCornerInside) + ++iterSurfaceVertex; + } + } + + Vector3DFloat computeNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) + { + const float posX = position.getX(); + const float posY = position.getY(); + const float posZ = position.getZ(); + + const uint16 floorX = static_cast(posX); + const uint16 floorY = static_cast(posY); + const uint16 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 uFloor = volIter.getVoxel() > 0 ? 1 : 0; + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + uint8 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 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 uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0; + result = Vector3DFloat(0.0, 0.0,static_cast(uFloor - uCeil)); + } + } + return result; + } +} diff --git a/library/source/PolyVoxCore/IndexedSurfacePatch.cpp b/library/source/PolyVoxCore/IndexedSurfacePatch.cpp new file mode 100644 index 00000000..c03c3cde --- /dev/null +++ b/library/source/PolyVoxCore/IndexedSurfacePatch.cpp @@ -0,0 +1,106 @@ +#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 + +#include "PolyVoxCore/IndexedSurfacePatch.h" + +using namespace std; + +namespace PolyVox +{ + IndexedSurfacePatch::IndexedSurfacePatch() + { + } + + IndexedSurfacePatch::~IndexedSurfacePatch() + { + } + + void IndexedSurfacePatch::addTriangle(const SurfaceVertex& v0,const SurfaceVertex& v1,const SurfaceVertex& v2) + { + m_vecVertices.push_back(v0); + m_vecTriangleIndices.push_back(m_vecVertices.size()-1); + m_vecVertices.push_back(v1); + m_vecTriangleIndices.push_back(m_vecVertices.size()-1); + m_vecVertices.push_back(v2); + m_vecTriangleIndices.push_back(m_vecVertices.size()-1); + } + + void IndexedSurfacePatch::fillVertexAndIndexData(std::vector& vecVertices, std::vector& vecIndices) + { + vecVertices.resize(m_vecVertices.size()); + std::copy(m_vecVertices.begin(), m_vecVertices.end(), vecVertices.begin()); + + vecIndices.resize(m_vecTriangleIndices.size()); + std::copy(m_vecTriangleIndices.begin(), m_vecTriangleIndices.end(), vecIndices.begin()); + + /*for(std::vector::iterator iterVertices = m_vecTriangleIndices.begin(); iterVertices != m_vecTriangleIndices.end(); ++iterVertices) + { + std::vector::iterator iterVertex = lower_bound(vecVertices.begin(), vecVertices.end(), **iterVertices); + vecIndices.push_back(iterVertex - vecVertices.begin()); + }*/ + } + + const std::vector& IndexedSurfacePatch::getVertices(void) const + { + return m_vecVertices; + } + + std::vector& IndexedSurfacePatch::getVertices(void) + { + return m_vecVertices; + } + + const std::vector& IndexedSurfacePatch::getIndices(void) const + { + return m_vecTriangleIndices; + } + + unsigned short IndexedSurfacePatch::getNoNonUniformTrianges(void) + { + unsigned short result = 0; + for(int i = 0; i < m_vecTriangleIndices.size() - 2; i += 3) + { + if((m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+1]].getMaterial()) + && (m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+2]].getMaterial())) + { + } + else + { + result++; + } + } + return result; + } + + unsigned short IndexedSurfacePatch::getNoUniformTrianges(void) + { + unsigned short result = 0; + for(int i = 0; i < m_vecTriangleIndices.size() - 2; i += 3) + { + if((m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+1]].getMaterial()) + && (m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+2]].getMaterial())) + { + result++; + } + } + return result; + } +} diff --git a/library/source/PolyVoxCore/MarchingCubesTables.cpp b/library/source/PolyVoxCore/MarchingCubesTables.cpp new file mode 100644 index 00000000..64e4a290 --- /dev/null +++ b/library/source/PolyVoxCore/MarchingCubesTables.cpp @@ -0,0 +1,326 @@ +#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 + +//Based on code by Paul Bourke +//From the article "Polygonising a scalar field" + +// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/index.html + +#include "PolyVoxCore/MarchingCubesTables.h" + +namespace PolyVox +{ + int edgeTable[256]= + { + 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, + 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, + 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, + 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, + 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, + 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, + 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, + 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, + 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, + 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, + 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, + 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, + 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, + 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, + 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , + 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, + 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, + 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, + 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, + 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, + 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, + 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, + 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, + 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, + 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, + 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, + 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, + 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, + 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, + 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, + 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, + 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 + }; + + int triTable[256][16] = + { + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, + {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, + {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, + {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, + {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, + {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, + {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, + {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, + {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, + {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, + {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, + {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, + {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, + {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, + {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, + {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, + {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, + {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, + {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, + {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, + {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, + {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, + {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, + {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, + {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, + {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, + {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, + {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, + {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, + {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, + {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, + {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, + {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, + {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, + {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, + {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, + {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, + {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, + {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, + {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, + {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, + {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, + {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, + {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, + {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, + {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, + {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, + {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, + {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, + {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, + {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, + {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, + {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, + {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, + {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, + {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, + {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, + {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, + {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, + {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, + {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, + {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, + {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, + {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, + {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, + {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, + {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, + {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, + {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, + {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, + {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, + {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, + {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, + {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, + {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, + {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, + {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, + {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, + {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, + {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, + {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, + {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, + {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, + {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, + {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, + {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, + {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, + {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, + {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, + {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, + {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, + {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, + {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, + {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, + {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, + {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, + {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, + {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, + {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, + {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, + {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, + {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, + {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, + {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, + {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, + {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, + {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, + {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, + {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, + {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, + {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, + {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, + {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, + {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, + {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, + {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} + }; +} diff --git a/library/source/PolyVoxCore/Region.cpp b/library/source/PolyVoxCore/Region.cpp new file mode 100644 index 00000000..202e1e3d --- /dev/null +++ b/library/source/PolyVoxCore/Region.cpp @@ -0,0 +1,72 @@ +#include "PolyVoxCore/Region.h" + +namespace PolyVox +{ + Region::Region() + :m_v3dLowerCorner(0,0,0) + ,m_v3dUpperCorner(0,0,0) + { + } + + Region::Region(const Vector3DInt32& v3dLowerCorner, const Vector3DInt32& v3dUpperCorner) + :m_v3dLowerCorner(v3dLowerCorner) + ,m_v3dUpperCorner(v3dUpperCorner) + { + } + + const Vector3DInt32& Region::getLowerCorner(void) const + { + return m_v3dLowerCorner; + } + + const Vector3DInt32& Region::getUpperCorner(void) const + { + return m_v3dUpperCorner; + } + + void Region::setLowerCorner(const Vector3DInt32& v3dLowerCorner) + { + m_v3dLowerCorner = v3dLowerCorner; + } + + void Region::setUpperCorner(const Vector3DInt32& v3dUpperCorner) + { + m_v3dUpperCorner = v3dUpperCorner; + } + + bool Region::containsPoint(const Vector3DFloat& pos, float boundary) const + { + return (pos.getX() <= m_v3dUpperCorner.getX() - boundary) + && (pos.getY() <= m_v3dUpperCorner.getY() - boundary) + && (pos.getZ() <= m_v3dUpperCorner.getZ() - boundary) + && (pos.getX() >= m_v3dLowerCorner.getX() + boundary) + && (pos.getY() >= m_v3dLowerCorner.getY() + boundary) + && (pos.getZ() >= m_v3dLowerCorner.getZ() + boundary); + } + + bool Region::containsPoint(const Vector3DInt32& pos, uint8 boundary) const + { + return (pos.getX() <= m_v3dUpperCorner.getX() - boundary) + && (pos.getY() <= m_v3dUpperCorner.getY() - boundary) + && (pos.getZ() <= m_v3dUpperCorner.getZ() - boundary) + && (pos.getX() >= m_v3dLowerCorner.getX() + boundary) + && (pos.getY() >= m_v3dLowerCorner.getY() + boundary) + && (pos.getZ() >= m_v3dLowerCorner.getZ() + boundary); + } + + void Region::cropTo(const Region& other) + { + m_v3dLowerCorner.setX((std::max)(m_v3dLowerCorner.getX(), other.m_v3dLowerCorner.getX())); + m_v3dLowerCorner.setY((std::max)(m_v3dLowerCorner.getY(), other.m_v3dLowerCorner.getY())); + m_v3dLowerCorner.setZ((std::max)(m_v3dLowerCorner.getZ(), other.m_v3dLowerCorner.getZ())); + m_v3dUpperCorner.setX((std::min)(m_v3dUpperCorner.getX(), other.m_v3dUpperCorner.getX())); + m_v3dUpperCorner.setY((std::min)(m_v3dUpperCorner.getY(), other.m_v3dUpperCorner.getY())); + m_v3dUpperCorner.setZ((std::min)(m_v3dUpperCorner.getZ(), other.m_v3dUpperCorner.getZ())); + } + + void Region::shift(const Vector3DInt32& amount) + { + m_v3dLowerCorner += amount; + m_v3dUpperCorner += amount; + } +} diff --git a/library/source/PolyVoxCore/RegionGeometry.cpp b/library/source/PolyVoxCore/RegionGeometry.cpp new file mode 100644 index 00000000..6a9dc08e --- /dev/null +++ b/library/source/PolyVoxCore/RegionGeometry.cpp @@ -0,0 +1,30 @@ +#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 + +#include "PolyVoxCore/IndexedSurfacePatch.h" +#include "PolyVoxCore/RegionGeometry.h" + +namespace PolyVox +{ + RegionGeometry::RegionGeometry() + { + } +} diff --git a/library/source/PolyVoxCore/SurfaceAdjusters.cpp b/library/source/PolyVoxCore/SurfaceAdjusters.cpp new file mode 100644 index 00000000..a1362e63 --- /dev/null +++ b/library/source/PolyVoxCore/SurfaceAdjusters.cpp @@ -0,0 +1,151 @@ +#include "PolyVoxCore/SurfaceAdjusters.h" + +#include "PolyVoxCore/BlockVolumeIterator.h" +#include "PolyVoxCore/GradientEstimators.h" +#include "PolyVoxCore/IndexedSurfacePatch.h" +#include "PolyVoxCore/RegionGeometry.h" +#include "PolyVoxCore/Utility.h" +#include "PolyVoxCore/VoxelFilters.h" + +#include + +using namespace std; + +namespace PolyVox +{ + void smoothRegionGeometry(BlockVolume* volumeData, RegionGeometry& regGeom) + { + const uint8 uSmoothingFactor = 2; + const float fThreshold = 0.5f; + + BlockVolumeIterator volIter(*volumeData); + + std::vector& vecVertices = regGeom.m_patchSingleMaterial->m_vecVertices; + std::vector::iterator iterSurfaceVertex = vecVertices.begin(); + while(iterSurfaceVertex != vecVertices.end()) + { + for(int ct = 0; ct < uSmoothingFactor; ++ct) + { + const Vector3DFloat& v3dPos = iterSurfaceVertex->getPosition() + static_cast(regGeom.m_v3dRegionPosition); + const Vector3DInt32 v3dFloor = static_cast(v3dPos); + const Vector3DFloat& v3dRem = v3dPos - static_cast(v3dFloor); + + //Check all corners are within the volume, allowing a boundary for gradient estimation + bool lowerCornerInside = volumeData->containsPoint(v3dFloor,2); + bool upperCornerInside = volumeData->containsPoint(v3dFloor+Vector3DInt32(1,1,1),2); + + if(lowerCornerInside && upperCornerInside) //If this test fails the vertex will be left as it was + { + volIter.setPosition(static_cast(v3dFloor + Vector3DInt32(0,0,0))); + const float v000 = computeSmoothedVoxel(volIter); + Vector3DFloat grad000 = computeSmoothCentralDifferenceGradient(volIter); + volIter.setPosition(static_cast(v3dFloor + Vector3DInt32(1,0,0))); + const float v100 = computeSmoothedVoxel(volIter); + Vector3DFloat grad100 = computeSmoothCentralDifferenceGradient(volIter); + + volIter.setPosition(static_cast(v3dFloor + Vector3DInt32(0,1,0))); + const float v010 = computeSmoothedVoxel(volIter); + Vector3DFloat grad010 = computeSmoothCentralDifferenceGradient(volIter); + volIter.setPosition(static_cast(v3dFloor + Vector3DInt32(1,1,0))); + const float v110 = computeSmoothedVoxel(volIter); + Vector3DFloat grad110 = computeSmoothCentralDifferenceGradient(volIter); + + volIter.setPosition(static_cast(v3dFloor + Vector3DInt32(0,0,1))); + const float v001 = computeSmoothedVoxel(volIter); + Vector3DFloat grad001 = computeSmoothCentralDifferenceGradient(volIter); + volIter.setPosition(static_cast(v3dFloor + Vector3DInt32(1,0,1))); + const float v101 = computeSmoothedVoxel(volIter); + Vector3DFloat grad101 = computeSmoothCentralDifferenceGradient(volIter); + + volIter.setPosition(static_cast(v3dFloor + Vector3DInt32(0,1,1))); + const float v011 = computeSmoothedVoxel(volIter); + Vector3DFloat grad011 = computeSmoothCentralDifferenceGradient(volIter); + volIter.setPosition(static_cast(v3dFloor + Vector3DInt32(1,1,1))); + const float v111 = computeSmoothedVoxel(volIter); + Vector3DFloat grad111 = computeSmoothCentralDifferenceGradient(volIter); + + float fInterVal = trilinearlyInterpolate(v000,v100,v010,v110,v001,v101,v011,v111,v3dRem.getX(),v3dRem.getY(),v3dRem.getZ()); + Vector3DFloat fInterGrad = trilinearlyInterpolate(grad000,grad100,grad010,grad110,grad001,grad101,grad011,grad111,v3dRem.getX(),v3dRem.getY(),v3dRem.getZ()); + + fInterGrad.normalise(); + float fDiff = fInterVal - fThreshold; + iterSurfaceVertex->setPosition(iterSurfaceVertex->getPosition() + (fInterGrad * fDiff)); + iterSurfaceVertex->setNormal(fInterGrad); //This is actually the gradient for the previous position, but it won't have moved much. + } //if(lowerCornerInside && upperCornerInside) + } //for(int ct = 0; ct < uSmoothingFactor; ++ct) + ++iterSurfaceVertex; + } //while(iterSurfaceVertex != vecVertices.end()) + } + + void adjustDecimatedGeometry(BlockVolume* volumeData, RegionGeometry& regGeom, uint8 val) + { + BlockVolumeIterator volIter(*volumeData); + + std::vector& vecVertices = regGeom.m_patchSingleMaterial->m_vecVertices; + std::vector::iterator iterSurfaceVertex = vecVertices.begin(); + while(iterSurfaceVertex != vecVertices.end()) + { + Vector3DFloat v3dPos = iterSurfaceVertex->getPosition() + static_cast(regGeom.m_v3dRegionPosition); + Vector3DInt32 v3dFloor = static_cast(v3dPos); + + BlockVolumeIterator volIter(*volumeData); + + //Check all corners are within the volume, allowing a boundary for gradient estimation + bool lowerCornerInside = volumeData->containsPoint(v3dFloor,1); + bool upperCornerInside = volumeData->containsPoint(v3dFloor+Vector3DInt32(1,1,1),1); + + if(lowerCornerInside && upperCornerInside) //If this test fails the vertex will be left as it was + { + //volIter.setPosition(static_cast(v3dFloor)); + //const uint8 uFloor = volIter.getVoxel(); + if(((v3dPos.getX() - v3dFloor.getX()) < 0.001) && ((v3dPos.getY() - v3dFloor.getY()) < 0.001) && ((v3dPos.getZ() - v3dFloor.getZ()) < 0.001)) + //int x = v3dPos.getX(); + //if(x % 2 != 0) + //if((iterSurfaceVertex->getNormal().getX() > 0.5f) || (iterSurfaceVertex->getNormal().getX() < -0.5f)) + { + //exit(0); + //volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(1,0,0))); + //const uint8 uCeil = volIter.getVoxel(); + //if(uFloor == uCeil) //In this case they must both be zero + { + //if(iterSurfaceVertex->getNormal().getX() > 0) + { + iterSurfaceVertex->setPosition(iterSurfaceVertex->getPosition() - iterSurfaceVertex->getNormal() * 0.5f); + v3dPos = iterSurfaceVertex->getPosition() + static_cast(regGeom.m_v3dRegionPosition); + v3dFloor = static_cast(v3dPos); + + volIter.setPosition(static_cast(v3dFloor)); + const uint8 uFloor = volIter.getVoxel(); + + uint8 uCeil; + if((iterSurfaceVertex->getNormal().getX() > 0.5f) || (iterSurfaceVertex->getNormal().getX() < -0.5f)) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(1,0,0))); + uCeil = volIter.getVoxel(); + } + if((iterSurfaceVertex->getNormal().getY() > 0.5f) || (iterSurfaceVertex->getNormal().getY() < -0.5f)) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(0,1,0))); + uCeil = volIter.getVoxel(); + } + if((iterSurfaceVertex->getNormal().getZ() > 0.5f) || (iterSurfaceVertex->getNormal().getZ() < -0.5f)) + { + volIter.setPosition(static_cast(v3dFloor+Vector3DInt32(0,0,1))); + uCeil = volIter.getVoxel(); + } + + if(uFloor == uCeil) + { + //NOTE: The normal should actually be multiplied by 1.0f. This works + //for the simple cube but causes depth fighting on more complex shapes. + iterSurfaceVertex->setPosition(iterSurfaceVertex->getPosition() - iterSurfaceVertex->getNormal() * 0.5f); + } + } + } + } + } + + ++iterSurfaceVertex; + } //while(iterSurfaceVertex != vecVertices.end()) + } +} \ No newline at end of file diff --git a/library/source/PolyVoxCore/SurfaceEdge.cpp b/library/source/PolyVoxCore/SurfaceEdge.cpp new file mode 100644 index 00000000..e491c0ba --- /dev/null +++ b/library/source/PolyVoxCore/SurfaceEdge.cpp @@ -0,0 +1,106 @@ +#include + +#include "SurfaceEdge.h" +#include "SurfaceTriangle.h" +#include "SurfaceVertex.h" + +namespace PolyVox +{ + SurfaceEdge::SurfaceEdge(const SurfaceVertexIterator& targetToSet,const SurfaceVertexIterator& sourceToSet) + { + target = targetToSet; + source = sourceToSet; + } + + std::string SurfaceEdge::tostring(void) + { + std::stringstream ss; + ss << "SurfaceEdge: Target Vertex = " << target->tostring() << "Source Vertex = " << source->tostring(); + return ss.str(); + } + + bool operator == (const SurfaceEdge& lhs, const SurfaceEdge& rhs) + { + //Vertices are unique in the set, so if the two positions are the same the + //two iterators must also be the same. So we just check the iterators. + return + ( + (lhs.target == rhs.target) && + (lhs.source == rhs.source) + ); + } + + bool SurfaceEdge::isDegenerate(void) + { + return (target == source); + } + + bool operator < (const SurfaceEdge& lhs, const SurfaceEdge& rhs) + { + //Unlike the equality operator, we can't compare iterators. + //So dereference and compare the results. + if ((*lhs.target) < (*rhs.target)) + return true; + if ((*rhs.target) < (*lhs.target)) + return false; + + if ((*lhs.source) < (*rhs.source)) + return true; + if ((*rhs.source) < (*lhs.source)) + return false; + + return false; + } + + const SurfaceVertexIterator& SurfaceEdge::getTarget(void) const + { + return target; + } + + const SurfaceVertexIterator& SurfaceEdge::getSource(void) const + { + return source; + } + + void SurfaceEdge::pairWithOtherHalfEdge(const SurfaceEdgeIterator& otherHalfEdgeToPair) + { + otherHalfEdge = otherHalfEdgeToPair; + previousHalfEdge = otherHalfEdgeToPair; + nextHalfEdge = otherHalfEdgeToPair; + } + + const SurfaceEdgeIterator& SurfaceEdge::getOtherHalfEdge(void) const + { + return otherHalfEdge; + } + + const SurfaceEdgeIterator& SurfaceEdge::getPreviousHalfEdge(void) const + { + return previousHalfEdge; + } + + const SurfaceEdgeIterator& SurfaceEdge::getNextHalfEdge(void) const + { + return nextHalfEdge; + } + + const SurfaceTriangleIterator& SurfaceEdge::getTriangle(void) const + { + return triangle; + } + + void SurfaceEdge::setPreviousHalfEdge(const SurfaceEdgeIterator& previousHalfEdgeToSet) + { + previousHalfEdge = previousHalfEdgeToSet; + } + + void SurfaceEdge::setNextHalfEdge(const SurfaceEdgeIterator& nextHalfEdgeToSet) + { + nextHalfEdge = nextHalfEdgeToSet; + } + + void SurfaceEdge::setTriangle(const SurfaceTriangleIterator& triangleToSet) + { + triangle = triangleToSet; + } +} diff --git a/library/source/PolyVoxCore/SurfaceExtractors.cpp b/library/source/PolyVoxCore/SurfaceExtractors.cpp new file mode 100644 index 00000000..9d132df3 --- /dev/null +++ b/library/source/PolyVoxCore/SurfaceExtractors.cpp @@ -0,0 +1,853 @@ +#include "PolyVoxCore/SurfaceExtractors.h" + +#include "PolyVoxCore/BlockVolume.h" +#include "PolyVoxCore/GradientEstimators.h" +#include "PolyVoxCore/IndexedSurfacePatch.h" +#include "PolyVoxCore/MarchingCubesTables.h" +#include "PolyVoxCore/Region.h" +#include "PolyVoxCore/RegionGeometry.h" +#include "PolyVoxCore/SurfaceAdjusters.h" +#include "PolyVoxCore/SurfaceExtractorsDecimated.h" +#include "PolyVoxCore/BlockVolumeIterator.h" + +#include + +using namespace std; + +namespace PolyVox +{ + uint32 getIndex(uint32 x, uint32 y) + { + return x + (y * (POLYVOX_REGION_SIDE_LENGTH+1)); + } + + void generateRoughMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch) + { + singleMaterialPatch->m_vecVertices.clear(); + singleMaterialPatch->m_vecTriangleIndices.clear(); + + //For edge indices + int32* vertexIndicesX0 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesY0 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesZ0 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesX1 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesY1 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesZ1 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + + //Cell bitmasks + uint8* bitmask0 = new uint8[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + uint8* bitmask1 = new uint8[(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()); + + //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 + uint32 uNoOfNonEmptyCellsForSlice0 = computeInitialRoughBitmaskForSlice(volIter, regSlice0, offset, bitmask0); + if(uNoOfNonEmptyCellsForSlice0 != 0) + { + //If there were some non-empty cells then generate initial slice vertices for them + generateRoughVerticesForSlice(volIter,regSlice0, offset, bitmask0, singleMaterialPatch, vertexIndicesX0, vertexIndicesY0, vertexIndicesZ0); + } + + for(uint32 uSlice = 0; ((uSlice <= POLYVOX_REGION_SIDE_LENGTH-1) && (uSlice + offset.getZ() < region.getUpperCorner().getZ())); ++uSlice) + { + Region regSlice1(regSlice0); + regSlice1.shift(Vector3DInt32(0,0,1)); + + uint32 uNoOfNonEmptyCellsForSlice1 = computeRoughBitmaskForSliceFromPrevious(volIter, regSlice1, offset, bitmask1, bitmask0); + + if(uNoOfNonEmptyCellsForSlice1 != 0) + { + generateRoughVerticesForSlice(volIter,regSlice1, offset, bitmask1, singleMaterialPatch, vertexIndicesX1, vertexIndicesY1, vertexIndicesZ1); + } + + if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0)) + { + generateRoughIndicesForSlice(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; + } + + uint32 computeInitialRoughBitmaskForSlice(BlockVolumeIterator& volIter, const Region& regSlice, const Vector3DFloat& offset, uint8* bitmask) + { + uint32 uNoOfNonEmptyCells = 0; + + //Iterate over each cell in the region + volIter.setPosition(regSlice.getLowerCorner().getX(),regSlice.getLowerCorner().getY(), regSlice.getLowerCorner().getZ()); + volIter.setValidRegion(regSlice); + do + { + //Current position + const uint16 x = volIter.getPosX() - offset.getX(); + const uint16 y = volIter.getPosY() - offset.getY(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8 iCubeIndex = 0; + + if((x==0) && (y==0)) + { + const uint8 v000 = volIter.getVoxel(); + const uint8 v100 = volIter.peekVoxel1px0py0pz(); + const uint8 v010 = volIter.peekVoxel0px1py0pz(); + const uint8 v110 = volIter.peekVoxel1px1py0pz(); + + const uint8 v001 = volIter.peekVoxel0px0py1pz(); + const uint8 v101 = volIter.peekVoxel1px0py1pz(); + const uint8 v011 = volIter.peekVoxel0px1py1pz(); + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + 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>0) && y==0) + { + const uint8 v100 = volIter.peekVoxel1px0py0pz(); + const uint8 v110 = volIter.peekVoxel1px1py0pz(); + + const uint8 v101 = volIter.peekVoxel1px0py1pz(); + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + //x + uint8 iPreviousCubeIndexX = bitmask[getIndex(x-1,y)]; + uint8 srcBit6 = iPreviousCubeIndexX & 64; + uint8 destBit7 = srcBit6 << 1; + + uint8 srcBit5 = iPreviousCubeIndexX & 32; + uint8 destBit4 = srcBit5 >> 1; + + uint8 srcBit2 = iPreviousCubeIndexX & 4; + uint8 destBit3 = srcBit2 << 1; + + uint8 srcBit1 = iPreviousCubeIndexX & 2; + uint8 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==0) && (y>0)) + { + const uint8 v010 = volIter.peekVoxel0px1py0pz(); + const uint8 v110 = volIter.peekVoxel1px1py0pz(); + + const uint8 v011 = volIter.peekVoxel0px1py1pz(); + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + //y + uint8 iPreviousCubeIndexY = bitmask[getIndex(x,y-1)]; + uint8 srcBit7 = iPreviousCubeIndexY & 128; + uint8 destBit4 = srcBit7 >> 3; + + uint8 srcBit6 = iPreviousCubeIndexY & 64; + uint8 destBit5 = srcBit6 >> 1; + + uint8 srcBit3 = iPreviousCubeIndexY & 8; + uint8 destBit0 = srcBit3 >> 3; + + uint8 srcBit2 = iPreviousCubeIndexY & 4; + uint8 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 + { + const uint8 v110 = volIter.peekVoxel1px1py0pz(); + + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + //y + uint8 iPreviousCubeIndexY = bitmask[getIndex(x,y-1)]; + uint8 srcBit7 = iPreviousCubeIndexY & 128; + uint8 destBit4 = srcBit7 >> 3; + + uint8 srcBit6 = iPreviousCubeIndexY & 64; + uint8 destBit5 = srcBit6 >> 1; + + uint8 srcBit3 = iPreviousCubeIndexY & 8; + uint8 destBit0 = srcBit3 >> 3; + + uint8 srcBit2 = iPreviousCubeIndexY & 4; + uint8 destBit1 = srcBit2 >> 1; + + //x + uint8 iPreviousCubeIndexX = bitmask[getIndex(x-1,y)]; + srcBit6 = iPreviousCubeIndexX & 64; + uint8 destBit7 = srcBit6 << 1; + + srcBit2 = iPreviousCubeIndexX & 4; + uint8 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[getIndex(x,y)] = iCubeIndex; + + if(edgeTable[iCubeIndex] != 0) + { + ++uNoOfNonEmptyCells; + } + + }while(volIter.moveForwardInRegionXYZ());//For each cell + + return uNoOfNonEmptyCells; + } + + uint32 computeRoughBitmaskForSliceFromPrevious(BlockVolumeIterator& volIter, const Region& regSlice, const Vector3DFloat& offset, uint8* bitmask, uint8* previousBitmask) + { + uint32 uNoOfNonEmptyCells = 0; + + //Iterate over each cell in the region + volIter.setPosition(regSlice.getLowerCorner().getX(),regSlice.getLowerCorner().getY(), regSlice.getLowerCorner().getZ()); + volIter.setValidRegion(regSlice); + do + { + //Current position + const uint16 x = volIter.getPosX() - offset.getX(); + const uint16 y = volIter.getPosY() - offset.getY(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8 iCubeIndex = 0; + + if((x==0) && (y==0)) + { + const uint8 v001 = volIter.peekVoxel0px0py1pz(); + const uint8 v101 = volIter.peekVoxel1px0py1pz(); + const uint8 v011 = volIter.peekVoxel0px1py1pz(); + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + //z + uint8 iPreviousCubeIndexZ = previousBitmask[getIndex(x,y)]; + 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>0) && y==0) + { + const uint8 v101 = volIter.peekVoxel1px0py1pz(); + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + //z + uint8 iPreviousCubeIndexZ = previousBitmask[getIndex(x,y)]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //x + uint8 iPreviousCubeIndexX = bitmask[getIndex(x-1,y)]; + uint8 srcBit6 = iPreviousCubeIndexX & 64; + uint8 destBit7 = srcBit6 << 1; + + uint8 srcBit5 = iPreviousCubeIndexX & 32; + uint8 destBit4 = srcBit5 >> 1; + + iCubeIndex |= destBit4; + if (v101 == 0) iCubeIndex |= 32; + if (v111 == 0) iCubeIndex |= 64; + iCubeIndex |= destBit7; + } + else if((x==0) && (y>0)) + { + const uint8 v011 = volIter.peekVoxel0px1py1pz(); + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + //z + uint8 iPreviousCubeIndexZ = previousBitmask[getIndex(x,y)]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //y + uint8 iPreviousCubeIndexY = bitmask[getIndex(x,y-1)]; + uint8 srcBit7 = iPreviousCubeIndexY & 128; + uint8 destBit4 = srcBit7 >> 3; + + uint8 srcBit6 = iPreviousCubeIndexY & 64; + uint8 destBit5 = srcBit6 >> 1; + + iCubeIndex |= destBit4; + iCubeIndex |= destBit5; + if (v111 == 0) iCubeIndex |= 64; + if (v011 == 0) iCubeIndex |= 128; + } + else + { + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + //z + uint8 iPreviousCubeIndexZ = previousBitmask[getIndex(x,y)]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //y + uint8 iPreviousCubeIndexY = bitmask[getIndex(x,y-1)]; + uint8 srcBit7 = iPreviousCubeIndexY & 128; + uint8 destBit4 = srcBit7 >> 3; + + uint8 srcBit6 = iPreviousCubeIndexY & 64; + uint8 destBit5 = srcBit6 >> 1; + + //x + uint8 iPreviousCubeIndexX = bitmask[getIndex(x-1,y)]; + srcBit6 = iPreviousCubeIndexX & 64; + uint8 destBit7 = srcBit6 << 1; + + iCubeIndex |= destBit4; + iCubeIndex |= destBit5; + if (v111 == 0) iCubeIndex |= 64; + iCubeIndex |= destBit7; + } + + //Save the bitmask + bitmask[getIndex(x,y)] = iCubeIndex; + + if(edgeTable[iCubeIndex] != 0) + { + ++uNoOfNonEmptyCells; + } + + }while(volIter.moveForwardInRegionXYZ());//For each cell + + return uNoOfNonEmptyCells; + } + + void generateRoughVerticesForSlice(BlockVolumeIterator& volIter, Region& regSlice, const Vector3DFloat& offset, uint8* bitmask, IndexedSurfacePatch* singleMaterialPatch,int32 vertexIndicesX[],int32 vertexIndicesY[],int32 vertexIndicesZ[]) + { + //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 + { + //Current position + const uint16 x = volIter.getPosX() - offset.getX(); + const uint16 y = volIter.getPosY() - offset.getY(); + const uint16 z = volIter.getPosZ() - offset.getZ(); + + const uint8 v000 = volIter.getVoxel(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8 iCubeIndex = bitmask[getIndex(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) + { + if((x + offset.getX()) != regSlice.getUpperCorner().getX()) + { + const uint8 v100 = volIter.peekVoxel1px0py0pz(); + const Vector3DFloat v3dPosition(x + 0.5f, y, z); + const Vector3DFloat v3dNormal(v000 > v100 ? 1.0f : -1.0f, 0.0f, 0.0f); + const uint8 uMaterial = v000 | v100; //Because one of these is 0, the or operation takes the max. + const SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); + singleMaterialPatch->m_vecVertices.push_back(surfaceVertex); + vertexIndicesX[getIndex(x,y)] = singleMaterialPatch->m_vecVertices.size()-1; + } + } + if (edgeTable[iCubeIndex] & 8) + { + if((y + offset.getY()) != regSlice.getUpperCorner().getY()) + { + const uint8 v010 = volIter.peekVoxel0px1py0pz(); + const Vector3DFloat v3dPosition(x, y + 0.5f, z); + const Vector3DFloat v3dNormal(0.0f, v000 > v010 ? 1.0f : -1.0f, 0.0f); + const uint8 uMaterial = v000 | v010; + SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); + singleMaterialPatch->m_vecVertices.push_back(surfaceVertex); + vertexIndicesY[getIndex(x,y)] = singleMaterialPatch->m_vecVertices.size()-1; + } + } + if (edgeTable[iCubeIndex] & 256) + { + //if((z + offset.getZ()) != upperCorner.getZ()) + { + const uint8 v001 = volIter.peekVoxel0px0py1pz(); + const Vector3DFloat v3dPosition(x, y, z + 0.5f); + const Vector3DFloat v3dNormal(0.0f, 0.0f, v000 > v001 ? 1.0f : -1.0f); + const uint8 uMaterial = v000 | v001; + SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); + singleMaterialPatch->m_vecVertices.push_back(surfaceVertex); + vertexIndicesZ[getIndex(x,y)] = singleMaterialPatch->m_vecVertices.size()-1; + } + } + }while(volIter.moveForwardInRegionXYZ());//For each cell + } + + void generateRoughIndicesForSlice(BlockVolumeIterator& volIter, const Region& regSlice, IndexedSurfacePatch* singleMaterialPatch, const Vector3DFloat& offset, uint8* bitmask0, uint8* bitmask1, int32 vertexIndicesX0[],int32 vertexIndicesY0[],int32 vertexIndicesZ0[], int32 vertexIndicesX1[],int32 vertexIndicesY1[],int32 vertexIndicesZ1[]) + { + uint32 indlist[12]; + + Region regCroppedSlice(regSlice); + regCroppedSlice.setUpperCorner(regCroppedSlice.getUpperCorner() - Vector3DInt32(1,1,0)); + + volIter.setPosition(regCroppedSlice.getLowerCorner().getX(),regCroppedSlice.getLowerCorner().getY(), regCroppedSlice.getLowerCorner().getZ()); + volIter.setValidRegion(regCroppedSlice); + do + { + //Current position + const uint16 x = volIter.getPosX() - offset.getX(); + const uint16 y = volIter.getPosY() - offset.getY(); + const uint16 z = volIter.getPosZ() - offset.getZ(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8 iCubeIndex = bitmask0[getIndex(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[getIndex(x,y)]; + assert(indlist[0] != -1); + } + if (edgeTable[iCubeIndex] & 2) + { + indlist[1] = vertexIndicesY0[getIndex(x+1,y)]; + assert(indlist[1] != -1); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = vertexIndicesX0[getIndex(x,y+1)]; + assert(indlist[2] != -1); + } + if (edgeTable[iCubeIndex] & 8) + { + indlist[3] = vertexIndicesY0[getIndex(x,y)]; + assert(indlist[3] != -1); + } + if (edgeTable[iCubeIndex] & 16) + { + indlist[4] = vertexIndicesX1[getIndex(x,y)]; + assert(indlist[4] != -1); + } + if (edgeTable[iCubeIndex] & 32) + { + indlist[5] = vertexIndicesY1[getIndex(x+1,y)]; + assert(indlist[5] != -1); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = vertexIndicesX1[getIndex(x,y+1)]; + assert(indlist[6] != -1); + } + if (edgeTable[iCubeIndex] & 128) + { + indlist[7] = vertexIndicesY1[getIndex(x,y)]; + assert(indlist[7] != -1); + } + if (edgeTable[iCubeIndex] & 256) + { + indlist[8] = vertexIndicesZ0[getIndex(x,y)]; + assert(indlist[8] != -1); + } + if (edgeTable[iCubeIndex] & 512) + { + indlist[9] = vertexIndicesZ0[getIndex(x+1,y)]; + assert(indlist[9] != -1); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = vertexIndicesZ0[getIndex(x+1,y+1)]; + assert(indlist[10] != -1); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = vertexIndicesZ0[getIndex(x,y+1)]; + assert(indlist[11] != -1); + } + + for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) + { + uint32 ind0 = indlist[triTable[iCubeIndex][i ]]; + uint32 ind1 = indlist[triTable[iCubeIndex][i+1]]; + uint32 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 generateReferenceMeshDataForRegion(BlockVolume* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch) + { + static int32 vertexIndicesX[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1]; + static int32 vertexIndicesY[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1]; + static int32 vertexIndicesZ[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1]; + + memset(vertexIndicesX,0xFF,sizeof(vertexIndicesX)); //0xFF is -1 as two's complement - this may not be portable... + memset(vertexIndicesY,0xFF,sizeof(vertexIndicesY)); + memset(vertexIndicesZ,0xFF,sizeof(vertexIndicesZ)); + + //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 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()); + while(volIter.moveForwardInRegionXYZ()) + { + //Current position + const uint16 x = volIter.getPosX(); + const uint16 y = volIter.getPosY(); + const uint16 z = volIter.getPosZ(); + + //Voxels values + const uint8 v000 = volIter.getVoxel(); + const uint8 v100 = volIter.peekVoxel1px0py0pz(); + const uint8 v010 = volIter.peekVoxel0px1py0pz(); + const uint8 v110 = volIter.peekVoxel1px1py0pz(); + const uint8 v001 = volIter.peekVoxel0px0py1pz(); + const uint8 v101 = volIter.peekVoxel1px0py1pz(); + const uint8 v011 = volIter.peekVoxel0px1py1pz(); + const uint8 v111 = volIter.peekVoxel1px1py1pz(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8 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); + vertlist[0].setY(y); + vertlist[0].setZ(z); + normlist[0].setX(v000 > v100 ? 1.0f : -1.0f); + normlist[0].setY(0.0f); + normlist[0].setZ(0.0f); + 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); + vertlist[1].setY(y + 0.5f); + vertlist[1].setZ(z); + normlist[1].setX(0.0f); + normlist[1].setY(v100 > v110 ? 1.0f : -1.0f); + normlist[1].setZ(0.0f); + vertMaterials[1] = v100 | v110; + } + if (edgeTable[iCubeIndex] & 4) + { + vertlist[2].setX(x + 0.5f); + vertlist[2].setY(y + 1.0f); + vertlist[2].setZ(z); + normlist[2].setX(v010 > v110 ? 1.0f : -1.0f); + normlist[2].setY(0.0f); + normlist[2].setZ(0.0f); + vertMaterials[2] = v010 | v110; + } + if (edgeTable[iCubeIndex] & 8) + { + vertlist[3].setX(x); + vertlist[3].setY(y + 0.5f); + vertlist[3].setZ(z); + normlist[3].setX(0.0f); + normlist[3].setY(v000 > v010 ? 1.0f : -1.0f); + normlist[3].setZ(0.0f); + vertMaterials[3] = v000 | v010; + } + if (edgeTable[iCubeIndex] & 16) + { + vertlist[4].setX(x + 0.5f); + vertlist[4].setY(y); + vertlist[4].setZ(z + 1.0f); + normlist[4].setX(v001 > v101 ? 1.0f : -1.0f); + normlist[4].setY(0.0f); + normlist[4].setZ(0.0f); + vertMaterials[4] = v001 | v101; + } + if (edgeTable[iCubeIndex] & 32) + { + vertlist[5].setX(x + 1.0f); + vertlist[5].setY(y + 0.5f); + vertlist[5].setZ(z + 1.0f); + normlist[5].setX(0.0f); + normlist[5].setY(v101 > v111 ? 1.0f : -1.0f); + normlist[5].setZ(0.0f); + vertMaterials[5] = v101 | v111; + } + if (edgeTable[iCubeIndex] & 64) + { + vertlist[6].setX(x + 0.5f); + vertlist[6].setY(y + 1.0f); + vertlist[6].setZ(z + 1.0f); + normlist[6].setX(v011 > v111 ? 1.0f : -1.0f); + normlist[6].setY(0.0f); + normlist[6].setZ(0.0f); + vertMaterials[6] = v011 | v111; + } + if (edgeTable[iCubeIndex] & 128) + { + vertlist[7].setX(x); + vertlist[7].setY(y + 0.5f); + vertlist[7].setZ(z + 1.0f); + normlist[7].setX(0.0f); + normlist[7].setY(v001 > v011 ? 1.0f : -1.0f); + normlist[7].setZ(0.0f); + vertMaterials[7] = v001 | v011; + } + if (edgeTable[iCubeIndex] & 256) + { + vertlist[8].setX(x); + vertlist[8].setY(y); + vertlist[8].setZ(z + 0.5f); + normlist[8].setX(0.0f); + normlist[8].setY(0.0f); + normlist[8].setZ(v000 > v001 ? 1.0f : -1.0f); + vertMaterials[8] = v000 | v001; + } + if (edgeTable[iCubeIndex] & 512) + { + vertlist[9].setX(x + 1.0f); + vertlist[9].setY(y); + vertlist[9].setZ(z + 0.5f); + normlist[9].setX(0.0f); + normlist[9].setY(0.0f); + normlist[9].setZ(v100 > v101 ? 1.0f : -1.0f); + vertMaterials[9] = v100 | v101; + } + if (edgeTable[iCubeIndex] & 1024) + { + vertlist[10].setX(x + 1.0f); + vertlist[10].setY(y + 1.0f); + vertlist[10].setZ(z + 0.5f); + normlist[10].setX(0.0f); + normlist[10].setY(0.0f); + normlist[10].setZ(v110 > v111 ? 1.0f : -1.0f); + vertMaterials[10] = v110 | v111; + } + if (edgeTable[iCubeIndex] & 2048) + { + vertlist[11].setX(x); + vertlist[11].setY(y + 1.0f); + vertlist[11].setZ(z + 0.5f); + normlist[11].setX(0.0f); + normlist[11].setY(0.0f); + normlist[11].setZ(v010 > v011 ? 1.0f : -1.0f); + vertMaterials[11] = v010 | v011; + } + + for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) + { + //The three vertices forming a triangle + const Vector3DFloat vertex0 = vertlist[triTable[iCubeIndex][i ]] - offset; + const Vector3DFloat vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset; + const Vector3DFloat vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset; + + const Vector3DFloat normal0 = normlist[triTable[iCubeIndex][i ]]; + const Vector3DFloat normal1 = normlist[triTable[iCubeIndex][i+1]]; + const Vector3DFloat normal2 = normlist[triTable[iCubeIndex][i+2]]; + + //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 material0 = vertMaterials[triTable[iCubeIndex][i ]]; + const uint8 material1 = vertMaterials[triTable[iCubeIndex][i+1]]; + const uint8 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 v0(vertex0, normal0, material0 + 0.1f); + SurfaceVertex v1(vertex1, normal1, material1 + 0.1f); + SurfaceVertex v2(vertex2, normal2, material2 + 0.1f); + + //singleMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + + int32 index = getIndexFor(v0.getPosition(), vertexIndicesX, vertexIndicesY, vertexIndicesZ); + if(index == -1) + { + singleMaterialPatch->m_vecVertices.push_back(v0); + singleMaterialPatch->m_vecTriangleIndices.push_back(singleMaterialPatch->m_vecVertices.size()-1); + setIndexFor(v0.getPosition(), singleMaterialPatch->m_vecVertices.size()-1, vertexIndicesX, vertexIndicesY, vertexIndicesZ); + } + else + { + singleMaterialPatch->m_vecTriangleIndices.push_back(index); + } + + index = getIndexFor(v1.getPosition(), vertexIndicesX, vertexIndicesY, vertexIndicesZ); + if(index == -1) + { + singleMaterialPatch->m_vecVertices.push_back(v1); + singleMaterialPatch->m_vecTriangleIndices.push_back(singleMaterialPatch->m_vecVertices.size()-1); + setIndexFor(v1.getPosition(), singleMaterialPatch->m_vecVertices.size()-1, vertexIndicesX, vertexIndicesY, vertexIndicesZ); + } + else + { + singleMaterialPatch->m_vecTriangleIndices.push_back(index); + } + + index = getIndexFor(v2.getPosition(), vertexIndicesX, vertexIndicesY, vertexIndicesZ); + if(index == -1) + { + singleMaterialPatch->m_vecVertices.push_back(v2); + singleMaterialPatch->m_vecTriangleIndices.push_back(singleMaterialPatch->m_vecVertices.size()-1); + setIndexFor(v2.getPosition(), singleMaterialPatch->m_vecVertices.size()-1, vertexIndicesX, vertexIndicesY, vertexIndicesZ); + } + else + { + singleMaterialPatch->m_vecTriangleIndices.push_back(index); + } + }//For each triangle + }//For each cell + } + + int32 getIndexFor(const Vector3DFloat& pos, int32 vertexIndicesX[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1], int32 vertexIndicesY[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1], int32 vertexIndicesZ[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1]) + { + assert(pos.getX() >= 0.0f); + assert(pos.getY() >= 0.0f); + assert(pos.getZ() >= 0.0f); + assert(pos.getX() <= POLYVOX_REGION_SIDE_LENGTH); + assert(pos.getY() <= POLYVOX_REGION_SIDE_LENGTH); + assert(pos.getZ() <= POLYVOX_REGION_SIDE_LENGTH); + + float xIntPart; + float xFracPart = std::modf(pos.getX(), &xIntPart); + float yIntPart; + float yFracPart = std::modf(pos.getY(), &yIntPart); + float zIntPart; + float zFracPart = std::modf(pos.getZ(), &zIntPart); + + //Of all the fractional parts, two should be zero and one should have a value. + if(xFracPart > 0.000001f) + { + return vertexIndicesX[static_cast(xIntPart)][static_cast(yIntPart)][static_cast(zIntPart)]; + } + if(yFracPart > 0.000001f) + { + return vertexIndicesY[static_cast(xIntPart)][static_cast(yIntPart)][static_cast(zIntPart)]; + } + if(zFracPart > 0.000001f) + { + return vertexIndicesZ[static_cast(xIntPart)][static_cast(yIntPart)][static_cast(zIntPart)]; + } + while(true); + } + + void setIndexFor(const Vector3DFloat& pos, int32 newIndex, int32 vertexIndicesX[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1], int32 vertexIndicesY[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1], int32 vertexIndicesZ[POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1][POLYVOX_REGION_SIDE_LENGTH+1]) + { + assert(pos.getX() >= 0.0f); + assert(pos.getY() >= 0.0f); + assert(pos.getZ() >= 0.0f); + assert(pos.getX() <= POLYVOX_REGION_SIDE_LENGTH); + assert(pos.getY() <= POLYVOX_REGION_SIDE_LENGTH); + assert(pos.getZ() <= POLYVOX_REGION_SIDE_LENGTH); + + assert(newIndex < 10000); + + float xIntPart; + float xFracPart = std::modf(pos.getX(), &xIntPart); + float yIntPart; + float yFracPart = std::modf(pos.getY(), &yIntPart); + float zIntPart; + float zFracPart = std::modf(pos.getZ(), &zIntPart); + + //Of all the fractional parts, two should be zero and one should have a value. + if(xFracPart > 0.000001f) + { + vertexIndicesX[static_cast(xIntPart)][static_cast(yIntPart)][static_cast(zIntPart)] = newIndex; + } + if(yFracPart > 0.000001f) + { + vertexIndicesY[static_cast(xIntPart)][static_cast(yIntPart)][static_cast(zIntPart)] = newIndex; + } + if(zFracPart > 0.000001f) + { + vertexIndicesZ[static_cast(xIntPart)][static_cast(yIntPart)][static_cast(zIntPart)] = newIndex; + } + } +} diff --git a/library/source/PolyVoxCore/SurfaceExtractorsDecimated.cpp b/library/source/PolyVoxCore/SurfaceExtractorsDecimated.cpp new file mode 100644 index 00000000..dc8f8cd7 --- /dev/null +++ b/library/source/PolyVoxCore/SurfaceExtractorsDecimated.cpp @@ -0,0 +1,892 @@ +#include "PolyVoxCore/SurfaceExtractorsDecimated.h" + +#include "PolyVoxCore/BlockVolume.h" +#include "PolyVoxCore/GradientEstimators.h" +#include "PolyVoxCore/IndexedSurfacePatch.h" +#include "PolyVoxCore/MarchingCubesTables.h" +#include "PolyVoxCore/Region.h" +#include "PolyVoxCore/RegionGeometry.h" +#include "PolyVoxCore/BlockVolumeIterator.h" + +#include + +using namespace std; + +namespace PolyVox +{ + uint32 getDecimatedIndex(uint32 x, uint32 y) + { + return x + (y * (POLYVOX_REGION_SIDE_LENGTH+1)); + } + + void generateDecimatedMeshDataForRegion(BlockVolume* volumeData, uint8 uLevel, Region region, IndexedSurfacePatch* singleMaterialPatch) + { + singleMaterialPatch->m_vecVertices.clear(); + singleMaterialPatch->m_vecTriangleIndices.clear(); + + //For edge indices + int32* vertexIndicesX0 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesY0 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesZ0 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesX1 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesY1 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + int32* vertexIndicesZ1 = new int32[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + + //Cell bitmasks + uint8* bitmask0 = new uint8[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + uint8* bitmask1 = new uint8[(POLYVOX_REGION_SIDE_LENGTH+1) * (POLYVOX_REGION_SIDE_LENGTH+1)]; + + const uint8 uStepSize = uLevel == 0 ? 1 : 1 << uLevel; + + //When generating the mesh for a region we actually look 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(2*uStepSize-1,2*uStepSize-1,2*uStepSize-1)); + region.cropTo(regVolume); + + //Offset from volume corner + const Vector3DFloat offset = static_cast(region.getLowerCorner()); + + //Create a region corresponding to the first slice + Region regSlice0(region); + Vector3DInt32 v3dUpperCorner = regSlice0.getUpperCorner(); + v3dUpperCorner.setZ(regSlice0.getLowerCorner().getZ()); //Set the upper z to the lower z to make it one slice thick. + regSlice0.setUpperCorner(v3dUpperCorner); + + //Iterator to access the volume data + BlockVolumeIterator volIter(*volumeData); + + //Compute bitmask for initial slice + uint32 uNoOfNonEmptyCellsForSlice0 = computeInitialDecimatedBitmaskForSlice(volIter, uLevel, regSlice0, offset, bitmask0); + if(uNoOfNonEmptyCellsForSlice0 != 0) + { + //If there were some non-empty cells then generate initial slice vertices for them + generateDecimatedVerticesForSlice(volIter, uLevel, regSlice0, offset, bitmask0, singleMaterialPatch, vertexIndicesX0, vertexIndicesY0, vertexIndicesZ0); + } + + for(uint32 uSlice = 1; ((uSlice <= POLYVOX_REGION_SIDE_LENGTH) && (uSlice + offset.getZ() <= regVolume.getUpperCorner().getZ())); uSlice += uStepSize) + { + Region regSlice1(regSlice0); + regSlice1.shift(Vector3DInt32(0,0,uStepSize)); + + uint32 uNoOfNonEmptyCellsForSlice1 = computeDecimatedBitmaskForSliceFromPrevious(volIter, uLevel, regSlice1, offset, bitmask1, bitmask0); + + if(uNoOfNonEmptyCellsForSlice1 != 0) + { + generateDecimatedVerticesForSlice(volIter, uLevel, regSlice1, offset, bitmask1, singleMaterialPatch, vertexIndicesX1, vertexIndicesY1, vertexIndicesZ1); + } + + if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0)) + { + generateDecimatedIndicesForSlice(volIter, uLevel, 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; + }*/ + } + + uint32 computeInitialDecimatedBitmaskForSlice(BlockVolumeIterator& volIter, uint8 uLevel, const Region& regSlice, const Vector3DFloat& offset, uint8* bitmask) + { + const uint8 uStepSize = uLevel == 0 ? 1 : 1 << uLevel; + uint32 uNoOfNonEmptyCells = 0; + + //Iterate over each cell in the region + for(uint16 y = regSlice.getLowerCorner().getY(); y <= regSlice.getUpperCorner().getY(); y += uStepSize) + { + for(uint16 x = regSlice.getLowerCorner().getX(); x <= regSlice.getUpperCorner().getX(); x += uStepSize) + { + //Current position + 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 iCubeIndex = 0; + + if((x==regSlice.getLowerCorner().getX()) && (y==regSlice.getLowerCorner().getY())) + { + volIter.setPosition(x,y,regSlice.getLowerCorner().getZ()); + const uint8 v000 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y,regSlice.getLowerCorner().getZ()); + const uint8 v100 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x,y+uStepSize,regSlice.getLowerCorner().getZ()); + const uint8 v010 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()); + const uint8 v110 = volIter.getSubSampledVoxel(uLevel); + + volIter.setPosition(x,y,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v001 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v101 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v011 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v111 = volIter.getSubSampledVoxel(uLevel); + + 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+uStepSize,y,regSlice.getLowerCorner().getZ()); + const uint8 v100 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()); + const uint8 v110 = volIter.getSubSampledVoxel(uLevel); + + volIter.setPosition(x+uStepSize,y,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v101 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v111 = volIter.getSubSampledVoxel(uLevel); + + //x + uint8 iPreviousCubeIndexX = bitmask[getDecimatedIndex(x- offset.getX()-uStepSize,y- offset.getY())]; + uint8 srcBit6 = iPreviousCubeIndexX & 64; + uint8 destBit7 = srcBit6 << 1; + + uint8 srcBit5 = iPreviousCubeIndexX & 32; + uint8 destBit4 = srcBit5 >> 1; + + uint8 srcBit2 = iPreviousCubeIndexX & 4; + uint8 destBit3 = srcBit2 << 1; + + uint8 srcBit1 = iPreviousCubeIndexX & 2; + uint8 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+uStepSize,regSlice.getLowerCorner().getZ()); + const uint8 v010 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()); + const uint8 v110 = volIter.getSubSampledVoxel(uLevel); + + volIter.setPosition(x,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v011 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v111 = volIter.getSubSampledVoxel(uLevel); + + //y + uint8 iPreviousCubeIndexY = bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY()-uStepSize)]; + uint8 srcBit7 = iPreviousCubeIndexY & 128; + uint8 destBit4 = srcBit7 >> 3; + + uint8 srcBit6 = iPreviousCubeIndexY & 64; + uint8 destBit5 = srcBit6 >> 1; + + uint8 srcBit3 = iPreviousCubeIndexY & 8; + uint8 destBit0 = srcBit3 >> 3; + + uint8 srcBit2 = iPreviousCubeIndexY & 4; + uint8 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+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()); + const uint8 v110 = volIter.getSubSampledVoxel(uLevel); + + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v111 = volIter.getSubSampledVoxel(uLevel); + + //y + uint8 iPreviousCubeIndexY = bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY()-uStepSize)]; + uint8 srcBit7 = iPreviousCubeIndexY & 128; + uint8 destBit4 = srcBit7 >> 3; + + uint8 srcBit6 = iPreviousCubeIndexY & 64; + uint8 destBit5 = srcBit6 >> 1; + + uint8 srcBit3 = iPreviousCubeIndexY & 8; + uint8 destBit0 = srcBit3 >> 3; + + uint8 srcBit2 = iPreviousCubeIndexY & 4; + uint8 destBit1 = srcBit2 >> 1; + + //x + uint8 iPreviousCubeIndexX = bitmask[getDecimatedIndex(x- offset.getX()-uStepSize,y- offset.getY())]; + srcBit6 = iPreviousCubeIndexX & 64; + uint8 destBit7 = srcBit6 << 1; + + srcBit2 = iPreviousCubeIndexX & 4; + uint8 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; + } + + } + } + + return uNoOfNonEmptyCells; + } + + uint32 computeDecimatedBitmaskForSliceFromPrevious(BlockVolumeIterator& volIter, uint8 uLevel, const Region& regSlice, const Vector3DFloat& offset, uint8* bitmask, uint8* previousBitmask) + { + const uint8 uStepSize = uLevel == 0 ? 1 : 1 << uLevel; + uint32 uNoOfNonEmptyCells = 0; + + //Iterate over each cell in the region + for(uint16 y = regSlice.getLowerCorner().getY(); y <= regSlice.getUpperCorner().getY(); y += uStepSize) + { + for(uint16 x = regSlice.getLowerCorner().getX(); x <= regSlice.getUpperCorner().getX(); x += uStepSize) + { + //Current position + 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 iCubeIndex = 0; + + if((x==regSlice.getLowerCorner().getX()) && (y==regSlice.getLowerCorner().getY())) + { + volIter.setPosition(x,y,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v001 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v101 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v011 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v111 = volIter.getSubSampledVoxel(uLevel); + + //z + uint8 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+uStepSize,y,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v101 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v111 = volIter.getSubSampledVoxel(uLevel); + + //z + uint8 iPreviousCubeIndexZ = previousBitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //x + uint8 iPreviousCubeIndexX = bitmask[getDecimatedIndex(x- offset.getX()-uStepSize,y- offset.getY())]; + uint8 srcBit6 = iPreviousCubeIndexX & 64; + uint8 destBit7 = srcBit6 << 1; + + uint8 srcBit5 = iPreviousCubeIndexX & 32; + uint8 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+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v011 = volIter.getSubSampledVoxel(uLevel); + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v111 = volIter.getSubSampledVoxel(uLevel); + + //z + uint8 iPreviousCubeIndexZ = previousBitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //y + uint8 iPreviousCubeIndexY = bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY()-uStepSize)]; + uint8 srcBit7 = iPreviousCubeIndexY & 128; + uint8 destBit4 = srcBit7 >> 3; + + uint8 srcBit6 = iPreviousCubeIndexY & 64; + uint8 destBit5 = srcBit6 >> 1; + + iCubeIndex |= destBit4; + iCubeIndex |= destBit5; + if (v111 == 0) iCubeIndex |= 64; + if (v011 == 0) iCubeIndex |= 128; + } + else + { + volIter.setPosition(x+uStepSize,y+uStepSize,regSlice.getLowerCorner().getZ()+uStepSize); + const uint8 v111 = volIter.getSubSampledVoxel(uLevel); + + //z + uint8 iPreviousCubeIndexZ = previousBitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY())]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + //y + uint8 iPreviousCubeIndexY = bitmask[getDecimatedIndex(x- offset.getX(),y- offset.getY()-uStepSize)]; + uint8 srcBit7 = iPreviousCubeIndexY & 128; + uint8 destBit4 = srcBit7 >> 3; + + uint8 srcBit6 = iPreviousCubeIndexY & 64; + uint8 destBit5 = srcBit6 >> 1; + + //x + uint8 iPreviousCubeIndexX = bitmask[getDecimatedIndex(x- offset.getX()-uStepSize,y- offset.getY())]; + srcBit6 = iPreviousCubeIndexX & 64; + uint8 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; + } + + }//For each cell + } + + return uNoOfNonEmptyCells; + } + + void generateDecimatedVerticesForSlice(BlockVolumeIterator& volIter, uint8 uLevel, Region& regSlice, const Vector3DFloat& offset, uint8* bitmask, IndexedSurfacePatch* singleMaterialPatch,int32 vertexIndicesX[],int32 vertexIndicesY[],int32 vertexIndicesZ[]) + { + const uint8 uStepSize = uLevel == 0 ? 1 : 1 << uLevel; + + //Iterate over each cell in the region + for(uint16 y = regSlice.getLowerCorner().getY(); y <= regSlice.getUpperCorner().getY(); y += uStepSize) + { + for(uint16 x = regSlice.getLowerCorner().getX(); x <= regSlice.getUpperCorner().getX(); x += uStepSize) + { + //Current position + const uint16 z = regSlice.getLowerCorner().getZ(); + + volIter.setPosition(x,y,z); + const uint8 v000 = volIter.getSubSampledVoxel(uLevel); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8 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()) + { + volIter.setPosition(x + uStepSize,y,z); + const uint8 v100 = volIter.getSubSampledVoxel(uLevel); + const Vector3DFloat v3dPosition(x - offset.getX() + 0.5f * uStepSize, y - offset.getY(), z - offset.getZ()); + const Vector3DFloat v3dNormal(v000 > v100 ? 1.0f : -1.0f,0.0,0.0); + const uint8 uMaterial = v000 | v100; //Because one of these is 0, the or operation takes the max. + SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); + 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()) + { + volIter.setPosition(x,y + uStepSize,z); + const uint8 v010 = volIter.getSubSampledVoxel(uLevel); + const Vector3DFloat v3dPosition(x - offset.getX(), y - offset.getY() + 0.5f * uStepSize, z - offset.getZ()); + const Vector3DFloat v3dNormal(0.0,v000 > v010 ? 1.0f : -1.0f,0.0); + const uint8 uMaterial = v000 | v010; //Because one of these is 0, the or operation takes the max. + SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); + 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 != regSlice.getUpperCorner.getZ()) + { + volIter.setPosition(x,y,z + uStepSize); + const uint8 v001 = volIter.getSubSampledVoxel(uLevel); + const Vector3DFloat v3dPosition(x - offset.getX(), y - offset.getY(), z - offset.getZ() + 0.5f * uStepSize); + const Vector3DFloat v3dNormal(0.0,0.0,v000 > v001 ? 1.0f : -1.0f); + const uint8 uMaterial = v000 | v001; //Because one of these is 0, the or operation takes the max. + const SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); + singleMaterialPatch->m_vecVertices.push_back(surfaceVertex); + vertexIndicesZ[getDecimatedIndex(x - offset.getX(),y - offset.getY())] = singleMaterialPatch->m_vecVertices.size()-1; + } + } + }//For each cell + } + } + + void generateDecimatedIndicesForSlice(BlockVolumeIterator& volIter, uint8 uLevel, const Region& regSlice, IndexedSurfacePatch* singleMaterialPatch, const Vector3DFloat& offset, uint8* bitmask0, uint8* bitmask1, int32 vertexIndicesX0[],int32 vertexIndicesY0[],int32 vertexIndicesZ0[], int32 vertexIndicesX1[],int32 vertexIndicesY1[],int32 vertexIndicesZ1[]) + { + const uint8 uStepSize = uLevel == 0 ? 1 : 1 << uLevel; + uint32 indlist[12]; + + for(uint16 y = regSlice.getLowerCorner().getY() - offset.getY(); y < regSlice.getUpperCorner().getY() - offset.getY(); y += uStepSize) + { + for(uint16 x = regSlice.getLowerCorner().getX() - offset.getX(); x < regSlice.getUpperCorner().getX() - offset.getX(); x += uStepSize) + { + //Current position + const uint16 z = regSlice.getLowerCorner().getZ() - offset.getZ(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8 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+uStepSize,y)]; + assert(indlist[1] != -1); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = vertexIndicesX0[getDecimatedIndex(x,y+uStepSize)]; + 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+uStepSize,y)]; + assert(indlist[5] != -1); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = vertexIndicesX1[getDecimatedIndex(x,y+uStepSize)]; + 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+uStepSize,y)]; + assert(indlist[9] != -1); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = vertexIndicesZ0[getDecimatedIndex(x+uStepSize,y+uStepSize)]; + assert(indlist[10] != -1); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = vertexIndicesZ0[getDecimatedIndex(x,y+uStepSize)]; + assert(indlist[11] != -1); + } + + for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) + { + uint32 ind0 = indlist[triTable[iCubeIndex][i ]]; + uint32 ind1 = indlist[triTable[iCubeIndex][i+1]]; + uint32 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 + }//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 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 z = region.getLowerCorner().getZ(); z <= region.getUpperCorner().getZ(); z += 2) + { + for(uint16 y = region.getLowerCorner().getY(); y <= region.getUpperCorner().getY(); y += 2) + { + for(uint16 x = region.getLowerCorner().getX(); x <= region.getUpperCorner().getX(); x += 2) + { + //while(volIter.moveForwardInRegionXYZ()) + //{ + volIter.setPosition(x,y,z); + const uint8 v000 = volIter.getSubSampledVoxel(1); + volIter.setPosition(x+2,y,z); + const uint8 v100 = volIter.getSubSampledVoxel(1); + volIter.setPosition(x,y+2,z); + const uint8 v010 = volIter.getSubSampledVoxel(1); + volIter.setPosition(x+2,y+2,z); + const uint8 v110 = volIter.getSubSampledVoxel(1); + volIter.setPosition(x,y,z+2); + const uint8 v001 = volIter.getSubSampledVoxel(1); + volIter.setPosition(x+2,y,z+2); + const uint8 v101 = volIter.getSubSampledVoxel(1); + volIter.setPosition(x,y+2,z+2); + const uint8 v011 = volIter.getSubSampledVoxel(1); + volIter.setPosition(x+2,y+2,z+2); + const uint8 v111 = volIter.getSubSampledVoxel(1); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8 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 material0 = vertMaterials[triTable[iCubeIndex][i ]]; + const uint8 material1 = vertMaterials[triTable[iCubeIndex][i+1]]; + const uint8 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); + surfaceVertex0Alpha1.setNormal(normal0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f); + surfaceVertex1Alpha1.setNormal(normal1); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f); + 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 floorX = static_cast(posX); + const uint16 floorY = static_cast(posY); + const uint16 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 uFloor = volIter.getVoxel() > 0 ? 1 : 0; + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + uint8 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 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 uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0; + result = Vector3DFloat(0.0, 0.0,static_cast(uFloor - uCeil)); + } + } + return result; + } +} diff --git a/library/source/PolyVoxCore/SurfaceTriangle.cpp b/library/source/PolyVoxCore/SurfaceTriangle.cpp new file mode 100644 index 00000000..e9b703a4 --- /dev/null +++ b/library/source/PolyVoxCore/SurfaceTriangle.cpp @@ -0,0 +1,59 @@ +#include "SurfaceTriangle.h" +#include "SurfaceVertex.h" +#include "SurfaceEdge.h" + +namespace PolyVox +{ + SurfaceTriangle::SurfaceTriangle() + { + } + + const SurfaceEdgeIterator& SurfaceTriangle::getEdge(void) const + { + return edge; + } + + void SurfaceTriangle::setEdge(const SurfaceEdgeIterator& edgeToSet) + { + edge = edgeToSet; + } + + /*std::string SurfaceTriangle::tostring(void) + { + std::stringstream ss; + + uint16_t ct = 0; + SurfaceEdgeIterator edgeIter = edge; + ss << "SurfaceTriangle:"; + do + { + ss << "\n Edge " << ct << " = " << edgeIter->tostring(); + if(edgeIter->hasOtherHalfEdge) + { + ss << "\n Opp Edge " << ct << " = " << edgeIter->otherHalfEdge->tostring(); + } + else + { + ss << "\n No Other Half"; + } + edgeIter = edgeIter->nextHalfEdge; + ++ct; + } + while(edgeIter != edge); + return ss.str(); + }*/ + + bool operator == (const SurfaceTriangle& lhs, const SurfaceTriangle& rhs) + { + //Edges are unique in the set, so if the two positions are the same the + //two iterators must also be the same. So we just check the iterators. + return (lhs.edge == rhs.edge); + } + + bool operator < (const SurfaceTriangle& lhs, const SurfaceTriangle& rhs) + { + //Unlike the equality operator, we can't compare iterators. + //So dereference and compare the results. + return (*lhs.edge < *rhs.edge); + } +} diff --git a/library/source/PolyVoxCore/SurfaceVertex.cpp b/library/source/PolyVoxCore/SurfaceVertex.cpp new file mode 100644 index 00000000..f96918c3 --- /dev/null +++ b/library/source/PolyVoxCore/SurfaceVertex.cpp @@ -0,0 +1,83 @@ +#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 + +#include + +#include "PolyVoxCore/Constants.h" +#include "PolyVoxCore/SurfaceVertex.h" + +namespace PolyVox +{ + SurfaceVertex::SurfaceVertex() + { + } + + SurfaceVertex::SurfaceVertex(Vector3DFloat positionToSet, float materialToSet) + :position(positionToSet) + ,material(materialToSet) + { + + } + + SurfaceVertex::SurfaceVertex(Vector3DFloat positionToSet, Vector3DFloat normalToSet, float materialToSet) + :position(positionToSet) + ,normal(normalToSet) + ,material(materialToSet) + { + } + + float SurfaceVertex::getMaterial(void) const + { + return material; + } + + const Vector3DFloat& SurfaceVertex::getNormal(void) const + { + return normal; + } + + const Vector3DFloat& SurfaceVertex::getPosition(void) const + { + return position; + } + + void SurfaceVertex::setMaterial(float materialToSet) + { + material = materialToSet; + } + + void SurfaceVertex::setNormal(const Vector3DFloat& normalToSet) + { + normal = normalToSet; + } + + void SurfaceVertex::setPosition(const Vector3DFloat& positionToSet) + { + position = positionToSet; + } + + std::string SurfaceVertex::tostring(void) const + { + std::stringstream ss; + ss << "SurfaceVertex: Position = (" << position.getX() << "," << position.getY() << "," << position.getZ() << "), Normal = " << normal; + return ss.str(); + } +} diff --git a/library/source/PolyVoxCore/Utility.cpp b/library/source/PolyVoxCore/Utility.cpp new file mode 100644 index 00000000..4fc738f4 --- /dev/null +++ b/library/source/PolyVoxCore/Utility.cpp @@ -0,0 +1,51 @@ +#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 + +#include "PolyVoxCore/Utility.h" + +#include + +namespace PolyVox +{ + //Note: this function only works for inputs which are a power of two and not zero + //If this is not the case then the output is undefined. + uint8 logBase2(uint32 uInput) + { + assert(uInput != 0); + assert(isPowerOf2(uInput)); + + uint32 uResult = 0; + while( (uInput >> uResult) != 0) + { + ++uResult; + } + return static_cast(uResult-1); + } + + + bool isPowerOf2(uint32 uInput) + { + if(uInput == 0) + return false; + else + return ((uInput & (uInput-1)) == 0); + } +} diff --git a/library/source/PolyVoxCore/VoxelFilters.cpp b/library/source/PolyVoxCore/VoxelFilters.cpp new file mode 100644 index 00000000..49720c8a --- /dev/null +++ b/library/source/PolyVoxCore/VoxelFilters.cpp @@ -0,0 +1,51 @@ +#include "PolyVoxCore/VoxelFilters.h" + +#include "PolyVoxCore/BlockVolumeIterator.h" + +namespace PolyVox +{ + float computeSmoothedVoxel(BlockVolumeIterator& volIter) + { + assert(volIter.getPosX() >= 1); + assert(volIter.getPosY() >= 1); + assert(volIter.getPosZ() >= 1); + assert(volIter.getPosX() < volIter.getVolume().getSideLength() - 2); + assert(volIter.getPosY() < volIter.getVolume().getSideLength() - 2); + assert(volIter.getPosZ() < volIter.getVolume().getSideLength() - 2); + + float sum = 0.0; + + if(volIter.peekVoxel1nx1ny1nz() != 0) sum += 1.0f; + if(volIter.peekVoxel1nx1ny0pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1nx1ny1pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1nx0py1nz() != 0) sum += 1.0f; + if(volIter.peekVoxel1nx0py0pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1nx0py1pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1nx1py1nz() != 0) sum += 1.0f; + if(volIter.peekVoxel1nx1py0pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1nx1py1pz() != 0) sum += 1.0f; + + if(volIter.peekVoxel0px1ny1nz() != 0) sum += 1.0f; + if(volIter.peekVoxel0px1ny0pz() != 0) sum += 1.0f; + if(volIter.peekVoxel0px1ny1pz() != 0) sum += 1.0f; + if(volIter.peekVoxel0px0py1nz() != 0) sum += 1.0f; + if(volIter.getVoxel() != 0) sum += 1.0f; + if(volIter.peekVoxel0px0py1pz() != 0) sum += 1.0f; + if(volIter.peekVoxel0px1py1nz() != 0) sum += 1.0f; + if(volIter.peekVoxel0px1py0pz() != 0) sum += 1.0f; + if(volIter.peekVoxel0px1py1pz() != 0) sum += 1.0f; + + if(volIter.peekVoxel1px1ny1nz() != 0) sum += 1.0f; + if(volIter.peekVoxel1px1ny0pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1px1ny1pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1px0py1nz() != 0) sum += 1.0f; + if(volIter.peekVoxel1px0py0pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1px0py1pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1px1py1nz() != 0) sum += 1.0f; + if(volIter.peekVoxel1px1py0pz() != 0) sum += 1.0f; + if(volIter.peekVoxel1px1py1pz() != 0) sum += 1.0f; + + sum /= 27.0f; + return sum; + } +} \ No newline at end of file diff --git a/library/source/PolyVoxUtil/VolumeChangeTracker.cpp b/library/source/PolyVoxUtil/VolumeChangeTracker.cpp new file mode 100644 index 00000000..d46e814b --- /dev/null +++ b/library/source/PolyVoxUtil/VolumeChangeTracker.cpp @@ -0,0 +1,231 @@ +#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 + +#include "PolyVoxUtil/VolumeChangeTracker.h" + +#include "PolyVoxCore/GradientEstimators.h" +#include "PolyVoxCore/IndexedSurfacePatch.h" +#include "PolyVoxCore/LinearVolume.h" +#include "PolyVoxCore/MarchingCubesTables.h" +#include "PolyVoxCore/RegionGeometry.h" +#include "PolyVoxCore/SurfaceExtractors.h" +#include "PolyVoxCore/SurfaceVertex.h" +#include "PolyVoxCore/Utility.h" +#include "PolyVoxCore/Vector.h" +#include "PolyVoxCore/BlockVolume.h" +#include "PolyVoxCore/BlockVolumeIterator.h" + +using namespace std; + +namespace PolyVox +{ + + ////////////////////////////////////////////////////////////////////////// + // VolumeChangeTracker + ////////////////////////////////////////////////////////////////////////// + VolumeChangeTracker::VolumeChangeTracker() + :m_bIsLocked(false) + ,volumeData(0) + { + } + + VolumeChangeTracker::~VolumeChangeTracker() + { + } + + void VolumeChangeTracker::setVolumeData(BlockVolume* volumeDataToSet) + { + volumeData = volumeDataToSet; + volRegionUpToDate = new LinearVolume(PolyVox::logBase2(POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS)); + } + + + + void VolumeChangeTracker::getChangedRegions(std::list& listToFill) const + { + //Clear the list + listToFill.clear(); + + //Regenerate meshes. + for(uint16 regionZ = 0; regionZ < POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS; ++regionZ) + //for(uint16 regionZ = 0; regionZ < 1; ++regionZ) + { + for(uint16 regionY = 0; regionY < POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS; ++regionY) + //for(uint16 regionY = 0; regionY < 2; ++regionY) + { + for(uint16 regionX = 0; regionX < POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS; ++regionX) + //for(uint16 regionX = 0; regionX < 2; ++regionX) + { + if(volRegionUpToDate->getVoxelAt(regionX, regionY, regionZ) == false) + { + const uint16 firstX = regionX * POLYVOX_REGION_SIDE_LENGTH; + const uint16 firstY = regionY * POLYVOX_REGION_SIDE_LENGTH; + const uint16 firstZ = regionZ * POLYVOX_REGION_SIDE_LENGTH; + const uint16 lastX = firstX + POLYVOX_REGION_SIDE_LENGTH; + const uint16 lastY = firstY + POLYVOX_REGION_SIDE_LENGTH; + const uint16 lastZ = firstZ + POLYVOX_REGION_SIDE_LENGTH; + + listToFill.push_back(Region(Vector3DInt32(firstX, firstY, firstZ), Vector3DInt32(lastX, lastY, lastZ))); + } + } + } + } + } + + void VolumeChangeTracker::setAllRegionsUpToDate(bool newUpToDateValue) + { + for(uint16 blockZ = 0; blockZ < POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS; ++blockZ) + { + for(uint16 blockY = 0; blockY < POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS; ++blockY) + { + for(uint16 blockX = 0; blockX < POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS; ++blockX) + { + volRegionUpToDate->setVoxelAt(blockX, blockY, blockZ, newUpToDateValue); + } + } + } + } + + uint16 VolumeChangeTracker::getSideLength(void) + { + return volumeData->getSideLength(); + } + + Region VolumeChangeTracker::getEnclosingRegion(void) const + { + return volumeData->getEnclosingRegion(); + } + + uint8 VolumeChangeTracker::getVoxelAt(const Vector3DUint16& pos) + { + return getVoxelAt(pos.getX(), pos.getY(), pos.getZ()); + } + + uint8 VolumeChangeTracker::getVoxelAt(uint16 uX, uint16 uY, uint16 uZ) + { + assert(uX < volumeData->getSideLength()); + assert(uY < volumeData->getSideLength()); + assert(uZ < volumeData->getSideLength()); + + BlockVolumeIterator volIter(*volumeData); + volIter.setPosition(uX,uY,uZ); + return volIter.getVoxel(); + } + + BlockVolume* VolumeChangeTracker::getVolumeData(void) const + { + return volumeData; + } + + void VolumeChangeTracker::setVoxelAt(uint16 x, uint16 y, uint16 z, uint8 value) + { + //FIXME - rather than creating a iterator each time we should have one stored + BlockVolumeIterator iterVol(*volumeData); + iterVol.setPosition(x,y,z); + iterVol.setVoxel(value); + + //If we are not on a boundary, just mark one region. + if((x % POLYVOX_REGION_SIDE_LENGTH != 0) && + (x % POLYVOX_REGION_SIDE_LENGTH != POLYVOX_REGION_SIDE_LENGTH-1) && + (y % POLYVOX_REGION_SIDE_LENGTH != 0) && + (y % POLYVOX_REGION_SIDE_LENGTH != POLYVOX_REGION_SIDE_LENGTH-1) && + (z % POLYVOX_REGION_SIDE_LENGTH != 0) && + (z % POLYVOX_REGION_SIDE_LENGTH != POLYVOX_REGION_SIDE_LENGTH-1)) + { + volRegionUpToDate->setVoxelAt(x >> POLYVOX_REGION_SIDE_LENGTH_POWER, y >> POLYVOX_REGION_SIDE_LENGTH_POWER, z >> POLYVOX_REGION_SIDE_LENGTH_POWER, false); + } + else //Mark surrounding regions as well + { + const uint16 regionX = x >> POLYVOX_REGION_SIDE_LENGTH_POWER; + const uint16 regionY = y >> POLYVOX_REGION_SIDE_LENGTH_POWER; + const uint16 regionZ = z >> POLYVOX_REGION_SIDE_LENGTH_POWER; + + const uint16 minRegionX = (std::max)(uint16(0),uint16(regionX-1)); + const uint16 minRegionY = (std::max)(uint16(0),uint16(regionY-1)); + const uint16 minRegionZ = (std::max)(uint16(0),uint16(regionZ-1)); + + const uint16 maxRegionX = (std::min)(uint16(POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS-1),uint16(regionX+1)); + const uint16 maxRegionY = (std::min)(uint16(POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS-1),uint16(regionY+1)); + const uint16 maxRegionZ = (std::min)(uint16(POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS-1),uint16(regionZ+1)); + + for(uint16 zCt = minRegionZ; zCt <= maxRegionZ; zCt++) + { + for(uint16 yCt = minRegionY; yCt <= maxRegionY; yCt++) + { + for(uint16 xCt = minRegionX; xCt <= maxRegionX; xCt++) + { + volRegionUpToDate->setVoxelAt(xCt,yCt,zCt,false); + } + } + } + } + } + + void VolumeChangeTracker::setLockedVoxelAt(uint16 x, uint16 y, uint16 z, uint8 value) + { + assert(m_bIsLocked); + + //FIXME - rather than creating a iterator each time we should have one stored + BlockVolumeIterator iterVol(*volumeData); + iterVol.setPosition(x,y,z); + iterVol.setVoxel(value); + } + + void VolumeChangeTracker::lockRegion(const Region& regToLock) + { + if(m_bIsLocked) + { + throw std::logic_error("A region is already locked. Please unlock it before locking another."); + } + + m_regLastLocked = regToLock; + m_bIsLocked = true; + } + + void VolumeChangeTracker::unlockRegion(void) + { + if(!m_bIsLocked) + { + throw std::logic_error("No region is locked. You must lock a region before you can unlock it."); + } + + const uint16 firstRegionX = m_regLastLocked.getLowerCorner().getX() >> POLYVOX_REGION_SIDE_LENGTH_POWER; + const uint16 firstRegionY = m_regLastLocked.getLowerCorner().getY() >> POLYVOX_REGION_SIDE_LENGTH_POWER; + const uint16 firstRegionZ = m_regLastLocked.getLowerCorner().getZ() >> POLYVOX_REGION_SIDE_LENGTH_POWER; + + const uint16 lastRegionX = m_regLastLocked.getUpperCorner().getX() >> POLYVOX_REGION_SIDE_LENGTH_POWER; + const uint16 lastRegionY = m_regLastLocked.getUpperCorner().getY() >> POLYVOX_REGION_SIDE_LENGTH_POWER; + const uint16 lastRegionZ = m_regLastLocked.getUpperCorner().getZ() >> POLYVOX_REGION_SIDE_LENGTH_POWER; + + for(uint16 zCt = firstRegionZ; zCt <= lastRegionZ; zCt++) + { + for(uint16 yCt = firstRegionY; yCt <= lastRegionY; yCt++) + { + for(uint16 xCt = firstRegionX; xCt <= lastRegionX; xCt++) + { + volRegionUpToDate->setVoxelAt(xCt,yCt,zCt,false); + } + } + } + + m_bIsLocked = false; + } +}