Rearranging files in PolyVox.

This commit is contained in:
David Williams 2008-07-03 19:17:17 +00:00
parent 4f546d1dc4
commit 29ef5f021e
49 changed files with 6623 additions and 10 deletions

View File

@ -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)
ADD_DEPENDENCIES(OpenGLExample PolyVoxCore)

View File

@ -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})

View File

@ -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 <windows.h> // Standard Header For Most Programs
#include <gl/gl.h> // The GL Header File

113
library/CMakeLists.txt Normal file
View File

@ -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)

View File

@ -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 <typename VoxelType>
class Block
{
//Make BlockVolumeIterator a friend
friend class BlockVolumeIterator<VoxelType>;
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

View File

@ -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 <cassert>
#include <cstring> //For memcpy
#include <stdexcept> //for std::invalid_argument
#pragma endregion
namespace PolyVox
{
#pragma region Constructors/Destructors
template <typename VoxelType>
Block<VoxelType>::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 <typename VoxelType>
Block<VoxelType>::Block(const Block<VoxelType>& rhs)
{
*this = rhs;
}
template <typename VoxelType>
Block<VoxelType>::~Block()
{
delete[] m_tData;
m_tData = 0;
}
#pragma endregion
#pragma region Operators
template <typename VoxelType>
Block<VoxelType>& Block<VoxelType>::operator=(const Block<VoxelType>& 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 <typename VoxelType>
uint16 Block<VoxelType>::getSideLength(void) const
{
return m_uSideLength;
}
template <typename VoxelType>
VoxelType Block<VoxelType>::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 <typename VoxelType>
void Block<VoxelType>::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 <typename VoxelType>
void Block<VoxelType>::fill(VoxelType tValue)
{
memset(m_tData, tValue, m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType));
}
#pragma endregion
}

View File

@ -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 <map>
#pragma endregion
namespace PolyVox
{
template <typename VoxelType>
class BlockVolume
{
//Make BlockVolumeIterator a friend
friend class BlockVolumeIterator<VoxelType>;
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<VoxelType> firstVoxel(void);
void idle(uint32 uAmount);
BlockVolumeIterator<VoxelType> lastVoxel(void);
private:
Block<VoxelType>* getHomogenousBlock(VoxelType tHomogenousValue) const;
Block<VoxelType>** m_pBlocks;
bool* m_pIsShared;
bool* m_pIsPotentiallySharable;
VoxelType* m_pHomogenousValue;
mutable std::map<VoxelType, Block<VoxelType>*> 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<float> FloatBlockVolume;
typedef BlockVolume<uint8> UInt8BlockVolume;
typedef BlockVolume<uint16> UInt16BlockVolume;
}
#include "BlockVolume.inl"
#endif

View File

@ -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 <cassert>
#include <cstring> //For memcpy
#pragma endregion
namespace PolyVox
{
#pragma region Constructors/Destructors
template <typename VoxelType>
BlockVolume<VoxelType>::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<VoxelType>*[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<VoxelType>(uBlockSideLengthPower);
m_pIsShared[i] = true;
m_pIsPotentiallySharable[i] = false;
m_pHomogenousValue[i] = 0;
}
}
template <typename VoxelType>
BlockVolume<VoxelType>::BlockVolume(const BlockVolume<VoxelType>& rhs)
{
*this = rhs;
}
template <typename VoxelType>
BlockVolume<VoxelType>::~BlockVolume()
{
for(uint32 i = 0; i < m_uNoOfBlocksInVolume; ++i)
{
delete m_pBlocks[i];
}
}
#pragma endregion
#pragma region Operators
template <typename VoxelType>
BlockVolume<VoxelType>& BlockVolume<VoxelType>::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<Block>(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<Block>(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 <typename VoxelType>
Region BlockVolume<VoxelType>::getEnclosingRegion(void) const
{
return Region(Vector3DInt32(0,0,0), Vector3DInt32(m_uSideLength-1,m_uSideLength-1,m_uSideLength-1));
}
template <typename VoxelType>
uint16 BlockVolume<VoxelType>::getSideLength(void) const
{
return m_uSideLength;
}
template <typename VoxelType>
VoxelType BlockVolume<VoxelType>::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<VoxelType>* block = m_pBlocks
[
blockX +
blockY * m_uSideLengthInBlocks +
blockZ * m_uSideLengthInBlocks * m_uSideLengthInBlocks
];
return block->getVoxelAt(xOffset,yOffset,zOffset);
}
template <typename VoxelType>
VoxelType BlockVolume<VoxelType>::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 <typename VoxelType>
bool BlockVolume<VoxelType>::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 <typename VoxelType>
bool BlockVolume<VoxelType>::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 <typename VoxelType>
BlockVolumeIterator<VoxelType> BlockVolume<VoxelType>::firstVoxel(void)
{
BlockVolumeIterator<VoxelType> iter(*this);
iter.setPosition(0,0,0);
return iter;
}
template <typename VoxelType>
void BlockVolume<VoxelType>::idle(uint32 uAmount)
{
}
template <typename VoxelType>
BlockVolumeIterator<VoxelType> BlockVolume<VoxelType>::lastVoxel(void)
{
BlockVolumeIterator<VoxelType> iter(*this);
iter.setPosition(m_uSideLength-1,m_uSideLength-1,m_uSideLength-1);
return iter;
}
#pragma endregion
#pragma region Private Implementation
template <typename VoxelType>
Block<VoxelType>* BlockVolume<VoxelType>::getHomogenousBlock(VoxelType tHomogenousValue) const
{
typename std::map<VoxelType, Block<VoxelType>*>::iterator iterResult = m_pHomogenousBlocks.find(tHomogenousValue);
if(iterResult == m_pHomogenousBlocks.end())
{
Block<VoxelType>* pBlock = new Block<VoxelType>(m_uBlockSideLengthPower);
pBlock->fill(tHomogenousValue);
m_pHomogenousBlocks.insert(std::make_pair(tHomogenousValue, pBlock));
return pBlock;
}
return iterResult->second;
}
#pragma endregion
}

View File

@ -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 <typename VoxelType>
class BlockVolumeIterator
{
public:
BlockVolumeIterator(BlockVolume<VoxelType>& 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<VoxelType>& 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<VoxelType>& 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

View File

@ -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 <typename VoxelType>
BlockVolumeIterator<VoxelType>::BlockVolumeIterator(BlockVolume<VoxelType>& volume)
:mVolume(volume)
{
}
template <typename VoxelType>
BlockVolumeIterator<VoxelType>::~BlockVolumeIterator()
{
}
#pragma endregion
#pragma region Operators
template <typename VoxelType>
bool BlockVolumeIterator<VoxelType>::operator==(const BlockVolumeIterator<VoxelType>& 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 <typename VoxelType>
bool BlockVolumeIterator<VoxelType>::operator<(const BlockVolumeIterator<VoxelType>& 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 <typename VoxelType>
bool BlockVolumeIterator<VoxelType>::operator>(const BlockVolumeIterator<VoxelType>& rhs)
{
assert(&mVolume == &rhs.mVolume);
return (rhs < *this);
}
template <typename VoxelType>
bool BlockVolumeIterator<VoxelType>::operator<=(const BlockVolumeIterator<VoxelType>& rhs)
{
assert(&mVolume == &rhs.mVolume);
return (rhs > *this);
}
template <typename VoxelType>
bool BlockVolumeIterator<VoxelType>::operator>=(const BlockVolumeIterator<VoxelType>& rhs)
{
assert(&mVolume == &rhs.mVolume);
return (rhs < *this);
}
#pragma endregion
#pragma region Getters
template <typename VoxelType>
uint16 BlockVolumeIterator<VoxelType>::getPosX(void) const
{
return mXPosInVolume;
}
template <typename VoxelType>
uint16 BlockVolumeIterator<VoxelType>::getPosY(void) const
{
return mYPosInVolume;
}
template <typename VoxelType>
uint16 BlockVolumeIterator<VoxelType>::getPosZ(void) const
{
return mZPosInVolume;
}
template <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
const BlockVolume<VoxelType>& BlockVolumeIterator<VoxelType>::getVolume(void) const
{
return mVolume;
}
template <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::getVoxel(void) const
{
return *mCurrentVoxel;
}
#pragma endregion
#pragma region Setters
template <typename VoxelType>
void BlockVolumeIterator<VoxelType>::setPosition(const Vector3DInt16& v3dNewPos)
{
setPosition(v3dNewPos.getX(), v3dNewPos.getY(), v3dNewPos.getZ());
}
template <typename VoxelType>
void BlockVolumeIterator<VoxelType>::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<VoxelType>* currentBlock = mVolume.m_pBlocks[mBlockIndexInVolume];
mVoxelIndexInBlock = mXPosInBlock +
mYPosInBlock * mVolume.m_uBlockSideLength +
mZPosInBlock * mVolume.m_uBlockSideLength * mVolume.m_uBlockSideLength;
mCurrentVoxel = currentBlock->m_tData + mVoxelIndexInBlock;
}
template <typename VoxelType>
void BlockVolumeIterator<VoxelType>::setValidRegion(const Region& region)
{
setValidRegion(region.getLowerCorner().getX(),region.getLowerCorner().getY(),region.getLowerCorner().getZ(),region.getUpperCorner().getX(),region.getUpperCorner().getY(),region.getUpperCorner().getZ());
}
template <typename VoxelType>
void BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
void BlockVolumeIterator<VoxelType>::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<VoxelType>(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 <typename VoxelType>
bool BlockVolumeIterator<VoxelType>::isValidForRegion(void) const
{
return mIsValidForRegion;
}
template <typename VoxelType>
void BlockVolumeIterator<VoxelType>::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<VoxelType>* 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<VoxelType>* 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<VoxelType>* 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 <typename VoxelType>
bool BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::peekVoxel1nx0py0pz(void) const
{
if((mXPosInVolume%mVolume.m_uBlockSideLength != 0))
{
return *(mCurrentVoxel - 1);
}
return mVolume.getVoxelAt(mXPosInVolume-1,mYPosInVolume,mZPosInVolume);
}
template <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::peekVoxel0px1ny0pz(void) const
{
if((mYPosInVolume%mVolume.m_uBlockSideLength != 0))
{
return *(mCurrentVoxel - mVolume.m_uBlockSideLength);
}
return mVolume.getVoxelAt(mXPosInVolume,mYPosInVolume-1,mZPosInVolume);
}
template <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::peekVoxel0px0py0pz(void) const
{
return *mCurrentVoxel;
}
template <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::peekVoxel1px0py0pz(void) const
{
if((mXPosInVolume%mVolume.m_uBlockSideLength != mVolume.m_uBlockSideLength-1))
{
return *(mCurrentVoxel + 1);
}
return mVolume.getVoxelAt(mXPosInVolume+1,mYPosInVolume,mZPosInVolume);
}
template <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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 <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::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
}

View File

@ -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

View File

@ -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

View File

@ -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 <vector>
namespace PolyVox
{
template <typename VoxelType>
Vector3DFloat computeCentralDifferenceGradient(const BlockVolumeIterator<VoxelType>& volIter);
template <typename VoxelType>
Vector3DFloat computeSmoothCentralDifferenceGradient(BlockVolumeIterator<VoxelType>& volIter);
template <typename VoxelType>
Vector3DFloat computeDecimatedCentralDifferenceGradient(BlockVolumeIterator<VoxelType>& volIter);
template <typename VoxelType>
Vector3DFloat computeSobelGradient(const BlockVolumeIterator<VoxelType>& volIter);
POLYVOX_API void computeNormalsForVertices(BlockVolume<uint8>* volumeData, RegionGeometry& regGeom, NormalGenerationMethod normalGenerationMethod);
POLYVOX_API Vector3DFloat computeNormal(BlockVolume<uint8>* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod);
}
#include "GradientEstimators.inl"
#endif //__PolyVox_GradientEstimators_H__

View File

@ -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 <typename VoxelType>
Vector3DFloat computeCentralDifferenceGradient(const BlockVolumeIterator<VoxelType>& 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<float>(voxel1nx) - static_cast<float>(voxel1px),
static_cast<float>(voxel1ny) - static_cast<float>(voxel1py),
static_cast<float>(voxel1nz) - static_cast<float>(voxel1pz)
);
}
template <typename VoxelType>
Vector3DFloat computeDecimatedCentralDifferenceGradient(const BlockVolumeIterator<VoxelType>& 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<float>(voxel1nx) - static_cast<float>(voxel1px),
static_cast<float>(voxel1ny) - static_cast<float>(voxel1py),
static_cast<float>(voxel1nz) - static_cast<float>(voxel1pz)
);
}
template <typename VoxelType>
Vector3DFloat computeSmoothCentralDifferenceGradient(BlockVolumeIterator<VoxelType>& 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 <typename VoxelType>
Vector3DFloat computeSobelGradient(const BlockVolumeIterator<VoxelType>& 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<float>(-xGrad),static_cast<float>(-yGrad),static_cast<float>(-zGrad));
}
}

View File

@ -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 <vector>
#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<SurfaceVertex>& vecVertices, std::vector<uint32>& vecIndices);
const std::vector<SurfaceVertex>& getVertices(void) const;
std::vector<SurfaceVertex>& getVertices(void); //FIXME - non const version should be removed.
const std::vector<uint32>& getIndices(void) const;
unsigned short getNoNonUniformTrianges(void);
unsigned short getNoUniformTrianges(void);
public:
std::vector<uint32> m_vecTriangleIndices;
std::vector<SurfaceVertex> m_vecVertices;
};
}
#endif /* __IndexedSurfacePatch_H__ */

View File

@ -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 <typename VoxelType>
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

View File

@ -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 <cstring>
namespace PolyVox
{
template <typename VoxelType>
LinearVolume<VoxelType>::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 <typename VoxelType>
LinearVolume<VoxelType>::LinearVolume(const LinearVolume<VoxelType>& rhs)
{
*this = rhs;
}
template <typename VoxelType>
LinearVolume<VoxelType>::~LinearVolume()
{
delete[] m_tData;
m_tData = 0;
}
template <typename VoxelType>
LinearVolume<VoxelType>& LinearVolume<VoxelType>::operator=(const LinearVolume<VoxelType>& rhs)
{
if (this == &rhs)
{
return *this;
}
memcpy(m_tData,rhs.m_tData,getNoOfVoxels());
return *this;
}
template <typename VoxelType>
VoxelType LinearVolume<VoxelType>::getVoxelAt(const uint16 xPosition, const uint16 yPosition, const uint16 zPosition) const
{
return m_tData
[
xPosition +
yPosition * m_uSideLength +
zPosition * m_uSideLength * m_uSideLength
];
}
template <typename VoxelType>
void LinearVolume<VoxelType>::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 <typename VoxelType>
uint16 LinearVolume<VoxelType>::getSideLength(void)
{
return m_uSideLength;
}
template <typename VoxelType>
uint32 LinearVolume<VoxelType>::getNoOfVoxels(void)
{
return m_uSideLength * m_uSideLength * m_uSideLength;
}
}

View File

@ -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

View File

@ -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 <cstdint> 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

View File

@ -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 <typename VoxelType> class Block;
//---------- BlockVolume ----------
template <typename VoxelType> class BlockVolume;
typedef BlockVolume<float> FloatBlockVolume;
typedef BlockVolume<uint8> UInt8BlockVolume;
typedef BlockVolume<uint16> UInt16BlockVolume;
//---------------------------------
class IndexedSurfacePatch;
class IntegrealVector3;
template <typename VoxelType> class LinearVolume;
class Region;
class RegionGeometry;
class SurfaceVertex;
//---------- Vector ----------
template <uint32 Size, typename Type> 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 <typename VoxelType> class BlockVolumeIterator;
}
#endif

View File

@ -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

View File

@ -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

View File

@ -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<uint8>* volumeData, RegionGeometry& regGeom);
POLYVOX_API void adjustDecimatedGeometry(BlockVolume<uint8>* volumeData, RegionGeometry& regGeom, uint8 val);
}
#endif

View File

@ -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

View File

@ -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 <list>
#pragma endregion
namespace PolyVox
{
uint32 getIndex(uint32 x, uint32 y);
POLYVOX_API void generateRoughMeshDataForRegion(BlockVolume<uint8>* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch);
POLYVOX_API uint32 computeInitialRoughBitmaskForSlice(BlockVolumeIterator<uint8>& volIter, const Region& regSlice, const Vector3DFloat& offset, uint8 *bitmask);
POLYVOX_API uint32 computeRoughBitmaskForSliceFromPrevious(BlockVolumeIterator<uint8>& volIter, const Region& regSlice, const Vector3DFloat& offset, uint8 *bitmask, uint8 *previousBitmask);
POLYVOX_API void generateRoughIndicesForSlice(BlockVolumeIterator<uint8>& 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<uint8>& volIter, Region& regSlice, const Vector3DFloat& offset, uint8* bitmask, IndexedSurfacePatch* singleMaterialPatch,int32 vertexIndicesX[],int32 vertexIndicesY[],int32 vertexIndicesZ[]);
POLYVOX_API void generateReferenceMeshDataForRegion(BlockVolume<uint8>* 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

View File

@ -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 <list>
#pragma endregion
namespace PolyVox
{
uint32 getDecimatedIndex(uint32 x, uint32 y);
POLYVOX_API void generateDecimatedMeshDataForRegion(BlockVolume<uint8>* volumeData, uint8 uLevel, Region region, IndexedSurfacePatch* singleMaterialPatch);
POLYVOX_API uint32 computeInitialDecimatedBitmaskForSlice(BlockVolumeIterator<uint8>& volIter, uint8 uLevel, const Region& regSlice, const Vector3DFloat& offset, uint8 *bitmask);
POLYVOX_API uint32 computeDecimatedBitmaskForSliceFromPrevious(BlockVolumeIterator<uint8>& volIter, uint8 uLevel, const Region& regSlice, const Vector3DFloat& offset, uint8 *bitmask, uint8 *previousBitmask);
POLYVOX_API void generateDecimatedIndicesForSlice(BlockVolumeIterator<uint8>& 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<uint8>& volIter, uint8 uLevel, Region& regSlice, const Vector3DFloat& offset, uint8* bitmask, IndexedSurfacePatch* singleMaterialPatch,int32 vertexIndicesX[],int32 vertexIndicesY[],int32 vertexIndicesZ[]);
POLYVOX_API void generateDecimatedMeshDataForRegionSlow(BlockVolume<uint8>* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch);
POLYVOX_API Vector3DFloat computeDecimatedNormal(BlockVolume<uint8>* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod);
}
#endif

View File

@ -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

View File

@ -0,0 +1,19 @@
#ifndef __PolyVox_SurfaceTypes_H__
#define __PolyVox_SurfaceTypes_H__
#include <set>
namespace PolyVox
{
class SurfaceVertex;
typedef std::set<SurfaceVertex>::iterator SurfaceVertexIterator;
typedef std::set<SurfaceVertex>::const_iterator SurfaceVertexConstIterator;
class SurfaceTriangle;
typedef std::set<SurfaceTriangle>::iterator SurfaceTriangleIterator;
typedef std::set<SurfaceTriangle>::const_iterator SurfaceTriangleConstIterator;
class SurfaceEdge;
typedef std::set<SurfaceEdge>::iterator SurfaceEdgeIterator;
typedef std::set<SurfaceEdge>::const_iterator SurfaceEdgeConstIterator;
}
#endif

View File

@ -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

View File

@ -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

View File

@ -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 <typename Type>
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

View File

@ -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 <iostream>
#pragma endregion
namespace PolyVox
{
///Represents a vector in space.
template <uint32 Size, typename Type>
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<Size,Type>& vector) throw();
///Copy Constructor which performs casting.
template <typename CastType> explicit Vector(const Vector<Size,CastType>& vector) throw();
///Destructor.
~Vector(void) throw();
///Assignment Operator.
Vector<Size,Type>& operator=(const Vector<Size,Type>& rhs) throw();
///Equality Operator.
bool operator==(const Vector<Size,Type>& rhs) const throw();
///Comparison Operator.
bool operator<(const Vector<Size,Type>& rhs) const throw();
///Addition and Assignment Operator.
Vector<Size,Type>& operator+=(const Vector<Size,Type> &rhs) throw();
///Subtraction and Assignment Operator.
Vector<Size,Type>& operator-=(const Vector<Size,Type> &rhs) throw();
///Multiplication and Assignment Operator.
Vector<Size,Type>& operator*=(const Type& rhs) throw();
///Division and Assignment Operator.
Vector<Size,Type>& 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<Size,Type>& vector) const throw();
///Find the cross product between this vector and the vector passed as a parameter.
Vector<Size,Type> cross(const Vector<Size,Type>& vector) const throw();
///Find the dot product between this vector and the vector passed as a parameter.
Type dot(const Vector<Size,Type>& 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 <uint32 Size,typename Type>
Vector<Size,Type> operator+(const Vector<Size,Type>& lhs, const Vector<Size,Type>& rhs) throw();
///Subtraction operator.
template <uint32 Size,typename Type>
Vector<Size,Type> operator-(const Vector<Size,Type>& lhs, const Vector<Size,Type>& rhs) throw();
///Multiplication operator.
template <uint32 Size,typename Type>
Vector<Size,Type> operator*(const Vector<Size,Type>& lhs, const Type& rhs) throw();
///Division operator.
template <uint32 Size,typename Type>
Vector<Size,Type> operator/(const Vector<Size,Type>& lhs, const Type& rhs) throw();
///Stream insertion operator.
template <uint32 Size, typename Type>
std::ostream& operator<<(std::ostream& os, const Vector<Size,Type>& 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

View File

@ -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 <cassert>
#include <cmath>
#include <string>
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 <uint32 Size,typename Type>
Vector<Size,Type>::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 <uint32 Size,typename Type>
Vector<Size,Type>::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 <uint32 Size,typename Type>
Vector<Size,Type>::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 <uint32 Size, typename Type>
Vector<Size, Type>::Vector(void) throw()
{
}
/**
Copy constructor builds object based on object passed as parameter.
\param vector A reference to the Vector to be copied.
*/
template <uint32 Size, typename Type>
Vector<Size, Type>::Vector(const Vector<Size, Type>& 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<Vector3DFloat>(v3dDouble); //Casting
\param vector A reference to the Vector to be copied.
*/
template <uint32 Size, typename Type>
template <typename CastType>
Vector<Size, Type>::Vector(const Vector<Size, CastType>& vector) throw()
{
for(uint32 ct = 0; ct < Size; ++ct)
{
m_tElements[ct] = static_cast<CastType>(vector.getElement(ct));
}
}
/**
Destroys the Vector.
*/
template <uint32 Size, typename Type>
Vector<Size, Type>::~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 <uint32 Size, typename Type>
Vector<Size, Type>& Vector<Size, Type>::operator=(const Vector<Size, Type>& 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 <uint32 Size, typename Type>
inline bool Vector<Size, Type>::operator==(const Vector<Size, Type> &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 <uint32 Size, typename Type>
inline bool Vector<Size, Type>::operator<(const Vector<Size, Type> &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 <uint32 Size, typename Type>
inline Vector<Size, Type>& Vector<Size, Type>::operator+=(const Vector<Size, Type>& 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 <uint32 Size,typename Type>
Vector<Size,Type> operator+(const Vector<Size,Type>& lhs, const Vector<Size,Type>& rhs) throw()
{
Vector<Size,Type> 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 <uint32 Size, typename Type>
inline Vector<Size, Type>& Vector<Size, Type>::operator-=(const Vector<Size, Type>& 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 <uint32 Size,typename Type>
Vector<Size,Type> operator-(const Vector<Size,Type>& lhs, const Vector<Size,Type>& rhs) throw()
{
Vector<Size,Type> 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 <uint32 Size, typename Type>
inline Vector<Size, Type>& Vector<Size, Type>::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 <uint32 Size,typename Type>
Vector<Size,Type> operator*(const Vector<Size,Type>& lhs, const Type& rhs) throw()
{
Vector<Size,Type> 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 <uint32 Size, typename Type>
inline Vector<Size, Type>& Vector<Size, Type>::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 <uint32 Size,typename Type>
Vector<Size,Type> operator/(const Vector<Size,Type>& lhs, const Type& rhs) throw()
{
Vector<Size,Type> 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 <uint32 Size, typename Type>
std::ostream& operator<<(std::ostream& os, const Vector<Size, Type>& 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 <uint32 Size, typename Type>
inline Type Vector<Size, Type>::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 <uint32 Size, typename Type>
inline Type Vector<Size, Type>::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 <uint32 Size, typename Type>
inline Type Vector<Size, Type>::getY(void) const throw()
{
return m_tElements[1];
}
/**
\return A const reference to the Z component of a 3 or 4 dimensional Vector.
*/
template <uint32 Size, typename Type>
inline Type Vector<Size, Type>::getZ(void) const throw()
{
return m_tElements[2];
}
/**
\return A const reference to the W component of a 4 dimensional Vector.
*/
template <uint32 Size, typename Type>
inline Type Vector<Size, Type>::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 <uint32 Size, typename Type>
inline void Vector<Size, Type>::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 <uint32 Size, typename Type>
inline void Vector<Size, Type>::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 <uint32 Size, typename Type>
inline void Vector<Size, Type>::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 <uint32 Size, typename Type>
inline void Vector<Size, Type>::setZ(Type tZ) throw()
{
m_tElements[2] = tZ;
}
/**
\param tX The new value for the W component of a 4 dimensional Vector.
*/
template <uint32 Size, typename Type>
inline void Vector<Size, Type>::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 <uint32 Size, typename Type>
inline double Vector<Size, Type>::length(void) const throw()
{
return sqrt(lengthSquared());
}
/**
\return Squared length of the Vector.
*/
template <uint32 Size, typename Type>
inline double Vector<Size, Type>::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 <uint32 Size, typename Type>
inline double Vector<Size, Type>::angleTo(const Vector<Size, Type>& 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 <uint32 Size, typename Type>
inline Vector<Size, Type> Vector<Size, Type>::cross(const Vector<Size, Type>& 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<Size, Type>(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 <uint32 Size, typename Type>
inline Type Vector<Size, Type>::dot(const Vector<Size, Type>& rhs) const throw()
{
Type dotProduct = static_cast<Type>(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 <uint32 Size, typename Type>
inline void Vector<Size, Type>::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<Type>(length);
}
}
#pragma endregion
}//namespace Thermite

View File

@ -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<uint8>& volIter);
}
#endif

View File

@ -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 <list>
#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<Region>& listToFill) const;
Region getEnclosingRegion(void) const;
uint16 getSideLength(void);
BlockVolume<uint8>* 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<uint8>* 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<uint8>* volumeData;
LinearVolume<bool>* volRegionUpToDate;
};
}
#endif

View File

@ -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<uint8>* volumeData, RegionGeometry& regGeom, NormalGenerationMethod normalGenerationMethod)
{
std::vector<SurfaceVertex>& vecVertices = regGeom.m_patchSingleMaterial->m_vecVertices;
std::vector<SurfaceVertex>::iterator iterSurfaceVertex = vecVertices.begin();
while(iterSurfaceVertex != vecVertices.end())
{
const Vector3DFloat& v3dPos = iterSurfaceVertex->getPosition() + static_cast<Vector3DFloat>(regGeom.m_v3dRegionPosition);
const Vector3DInt32 v3dFloor = static_cast<Vector3DInt32>(v3dPos);
BlockVolumeIterator<uint8> 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<Vector3DInt16>(v3dFloor));
const Vector3DFloat gradFloor = computeSobelGradient(volIter);
if((v3dPos.getX() - v3dFloor.getX()) > 0.001)
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor+Vector3DInt32(1,0,0)));
}
if((v3dPos.getY() - v3dFloor.getY()) > 0.001)
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor+Vector3DInt32(0,1,0)));
}
if((v3dPos.getZ() - v3dFloor.getZ()) > 0.001)
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor+Vector3DInt32(0,0,1)));
}
const Vector3DFloat gradCeil = computeSobelGradient(volIter);
v3dGradient = (gradFloor + gradCeil);
}
if(normalGenerationMethod == CENTRAL_DIFFERENCE)
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor));
const Vector3DFloat gradFloor = computeCentralDifferenceGradient(volIter);
if((v3dPos.getX() - v3dFloor.getX()) > 0.001)
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor+Vector3DInt32(1,0,0)));
}
if((v3dPos.getY() - v3dFloor.getY()) > 0.001)
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor+Vector3DInt32(0,1,0)));
}
if((v3dPos.getZ() - v3dFloor.getZ()) > 0.001)
{
volIter.setPosition(static_cast<Vector3DInt16>(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<uint8>* 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<uint16>(posX);
const uint16 floorY = static_cast<uint16>(posY);
const uint16 floorZ = static_cast<uint16>(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<uint8> volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create?
if(normalGenerationMethod == SOBEL)
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(posZ));
const Vector3DFloat gradFloor = computeSobelGradient(volIter);
if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX+1.0),static_cast<uint16>(posY),static_cast<uint16>(posZ));
}
if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY+1.0),static_cast<uint16>(posZ));
}
if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(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<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(posZ));
const Vector3DFloat gradFloor = computeCentralDifferenceGradient(volIter);
if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX+1.0),static_cast<uint16>(posY),static_cast<uint16>(posZ));
}
if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY+1.0),static_cast<uint16>(posZ));
}
if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(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<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(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<float>(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<float>(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<float>(uFloor - uCeil));
}
}
return result;
}
}

View File

@ -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<SurfaceVertex>& vecVertices, std::vector<uint32>& 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<SurfaceVertexIterator>::iterator iterVertices = m_vecTriangleIndices.begin(); iterVertices != m_vecTriangleIndices.end(); ++iterVertices)
{
std::vector<SurfaceVertex>::iterator iterVertex = lower_bound(vecVertices.begin(), vecVertices.end(), **iterVertices);
vecIndices.push_back(iterVertex - vecVertices.begin());
}*/
}
const std::vector<SurfaceVertex>& IndexedSurfacePatch::getVertices(void) const
{
return m_vecVertices;
}
std::vector<SurfaceVertex>& IndexedSurfacePatch::getVertices(void)
{
return m_vecVertices;
}
const std::vector<uint32>& 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;
}
}

View File

@ -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}
};
}

View File

@ -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;
}
}

View File

@ -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()
{
}
}

View File

@ -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 <vector>
using namespace std;
namespace PolyVox
{
void smoothRegionGeometry(BlockVolume<uint8>* volumeData, RegionGeometry& regGeom)
{
const uint8 uSmoothingFactor = 2;
const float fThreshold = 0.5f;
BlockVolumeIterator<uint8> volIter(*volumeData);
std::vector<SurfaceVertex>& vecVertices = regGeom.m_patchSingleMaterial->m_vecVertices;
std::vector<SurfaceVertex>::iterator iterSurfaceVertex = vecVertices.begin();
while(iterSurfaceVertex != vecVertices.end())
{
for(int ct = 0; ct < uSmoothingFactor; ++ct)
{
const Vector3DFloat& v3dPos = iterSurfaceVertex->getPosition() + static_cast<Vector3DFloat>(regGeom.m_v3dRegionPosition);
const Vector3DInt32 v3dFloor = static_cast<Vector3DInt32>(v3dPos);
const Vector3DFloat& v3dRem = v3dPos - static_cast<Vector3DFloat>(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<Vector3DInt16>(v3dFloor + Vector3DInt32(0,0,0)));
const float v000 = computeSmoothedVoxel(volIter);
Vector3DFloat grad000 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(1,0,0)));
const float v100 = computeSmoothedVoxel(volIter);
Vector3DFloat grad100 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(0,1,0)));
const float v010 = computeSmoothedVoxel(volIter);
Vector3DFloat grad010 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(1,1,0)));
const float v110 = computeSmoothedVoxel(volIter);
Vector3DFloat grad110 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(0,0,1)));
const float v001 = computeSmoothedVoxel(volIter);
Vector3DFloat grad001 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(1,0,1)));
const float v101 = computeSmoothedVoxel(volIter);
Vector3DFloat grad101 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(0,1,1)));
const float v011 = computeSmoothedVoxel(volIter);
Vector3DFloat grad011 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(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<uint8>* volumeData, RegionGeometry& regGeom, uint8 val)
{
BlockVolumeIterator<uint8> volIter(*volumeData);
std::vector<SurfaceVertex>& vecVertices = regGeom.m_patchSingleMaterial->m_vecVertices;
std::vector<SurfaceVertex>::iterator iterSurfaceVertex = vecVertices.begin();
while(iterSurfaceVertex != vecVertices.end())
{
Vector3DFloat v3dPos = iterSurfaceVertex->getPosition() + static_cast<Vector3DFloat>(regGeom.m_v3dRegionPosition);
Vector3DInt32 v3dFloor = static_cast<Vector3DInt32>(v3dPos);
BlockVolumeIterator<uint8> 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<Vector3DInt16>(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<Vector3DInt16>(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<Vector3DFloat>(regGeom.m_v3dRegionPosition);
v3dFloor = static_cast<Vector3DInt32>(v3dPos);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor));
const uint8 uFloor = volIter.getVoxel();
uint8 uCeil;
if((iterSurfaceVertex->getNormal().getX() > 0.5f) || (iterSurfaceVertex->getNormal().getX() < -0.5f))
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor+Vector3DInt32(1,0,0)));
uCeil = volIter.getVoxel();
}
if((iterSurfaceVertex->getNormal().getY() > 0.5f) || (iterSurfaceVertex->getNormal().getY() < -0.5f))
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor+Vector3DInt32(0,1,0)));
uCeil = volIter.getVoxel();
}
if((iterSurfaceVertex->getNormal().getZ() > 0.5f) || (iterSurfaceVertex->getNormal().getZ() < -0.5f))
{
volIter.setPosition(static_cast<Vector3DInt16>(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())
}
}

View File

@ -0,0 +1,106 @@
#include <sstream>
#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;
}
}

View File

@ -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 <algorithm>
using namespace std;
namespace PolyVox
{
uint32 getIndex(uint32 x, uint32 y)
{
return x + (y * (POLYVOX_REGION_SIDE_LENGTH+1));
}
void generateRoughMeshDataForRegion(BlockVolume<uint8>* 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<Vector3DFloat>(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<uint8> 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<uint8>& 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<uint8>& 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<uint8>& 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<uint8>& 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<uint8>* 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<Vector3DFloat>(region.getLowerCorner());
Vector3DFloat vertlist[12];
Vector3DFloat normlist[12];
uint8 vertMaterials[12];
BlockVolumeIterator<uint8> 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<Vector3DFloat>(vertex0) / 2.0f) - offset;
//const Vector3DFloat vertex1AsFloat = (static_cast<Vector3DFloat>(vertex1) / 2.0f) - offset;
//const Vector3DFloat vertex2AsFloat = (static_cast<Vector3DFloat>(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<uint16>(xIntPart)][static_cast<uint16>(yIntPart)][static_cast<uint16>(zIntPart)];
}
if(yFracPart > 0.000001f)
{
return vertexIndicesY[static_cast<uint16>(xIntPart)][static_cast<uint16>(yIntPart)][static_cast<uint16>(zIntPart)];
}
if(zFracPart > 0.000001f)
{
return vertexIndicesZ[static_cast<uint16>(xIntPart)][static_cast<uint16>(yIntPart)][static_cast<uint16>(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<uint16>(xIntPart)][static_cast<uint16>(yIntPart)][static_cast<uint16>(zIntPart)] = newIndex;
}
if(yFracPart > 0.000001f)
{
vertexIndicesY[static_cast<uint16>(xIntPart)][static_cast<uint16>(yIntPart)][static_cast<uint16>(zIntPart)] = newIndex;
}
if(zFracPart > 0.000001f)
{
vertexIndicesZ[static_cast<uint16>(xIntPart)][static_cast<uint16>(yIntPart)][static_cast<uint16>(zIntPart)] = newIndex;
}
}
}

View File

@ -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 <algorithm>
using namespace std;
namespace PolyVox
{
uint32 getDecimatedIndex(uint32 x, uint32 y)
{
return x + (y * (POLYVOX_REGION_SIDE_LENGTH+1));
}
void generateDecimatedMeshDataForRegion(BlockVolume<uint8>* 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<Vector3DFloat>(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<uint8> 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<SurfaceVertex>::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin();
while(iterSurfaceVertex != singleMaterialPatch->getVertices().end())
{
Vector3DFloat tempNormal = computeDecimatedNormal(volumeData, static_cast<Vector3DFloat>(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE);
const_cast<SurfaceVertex&>(*iterSurfaceVertex).setNormal(tempNormal);
++iterSurfaceVertex;
}*/
}
uint32 computeInitialDecimatedBitmaskForSlice(BlockVolumeIterator<uint8>& 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<uint8>& 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<uint8>& 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<uint8>& 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<uint8>* 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<Vector3DFloat>(region.getLowerCorner());
Vector3DFloat vertlist[12];
Vector3DFloat normlist[12];
uint8 vertMaterials[12];
BlockVolumeIterator<uint8> 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<Vector3DFloat>(vertex0) / 2.0f) - offset;
//const Vector3DFloat vertex1AsFloat = (static_cast<Vector3DFloat>(vertex1) / 2.0f) - offset;
//const Vector3DFloat vertex2AsFloat = (static_cast<Vector3DFloat>(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<uint8, IndexedSurfacePatch*>::iterator iterPatch = surfacePatchMapResult.begin(); iterPatch != surfacePatchMapResult.end(); ++iterPatch)
{
/*std::vector<SurfaceVertex>::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin();
while(iterSurfaceVertex != singleMaterialPatch->getVertices().end())
{
Vector3DFloat tempNormal = computeNormal(volumeData, static_cast<Vector3DFloat>(iterSurfaceVertex->getPosition() + offset), SIMPLE);
const_cast<SurfaceVertex&>(*iterSurfaceVertex).setNormal(tempNormal);
++iterSurfaceVertex;
}*/
}
}
Vector3DFloat computeDecimatedNormal(BlockVolume<uint8>* 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<uint16>(posX);
const uint16 floorY = static_cast<uint16>(posY);
const uint16 floorZ = static_cast<uint16>(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<uint8> volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create?
if(normalGenerationMethod == SOBEL)
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(posZ));
const Vector3DFloat gradFloor = computeSobelGradient(volIter);
if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX+1.0),static_cast<uint16>(posY),static_cast<uint16>(posZ));
}
if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY+1.0),static_cast<uint16>(posZ));
}
if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(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<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(posZ));
const Vector3DFloat gradFloor = computeCentralDifferenceGradient(volIter);
if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX+1.0),static_cast<uint16>(posY),static_cast<uint16>(posZ));
}
if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY+1.0),static_cast<uint16>(posZ));
}
if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(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<uint16>(posX),static_cast<uint16>(posY),static_cast<uint16>(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<float>(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<float>(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<float>(uFloor - uCeil));
}
}
return result;
}
}

View File

@ -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);
}
}

View File

@ -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 <sstream>
#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();
}
}

View File

@ -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 <cassert>
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<uint8>(uResult-1);
}
bool isPowerOf2(uint32 uInput)
{
if(uInput == 0)
return false;
else
return ((uInput & (uInput-1)) == 0);
}
}

View File

@ -0,0 +1,51 @@
#include "PolyVoxCore/VoxelFilters.h"
#include "PolyVoxCore/BlockVolumeIterator.h"
namespace PolyVox
{
float computeSmoothedVoxel(BlockVolumeIterator<uint8>& 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;
}
}

View File

@ -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<uint8>* volumeDataToSet)
{
volumeData = volumeDataToSet;
volRegionUpToDate = new LinearVolume<bool>(PolyVox::logBase2(POLYVOX_VOLUME_SIDE_LENGTH_IN_REGIONS));
}
void VolumeChangeTracker::getChangedRegions(std::list<Region>& 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<uint8> volIter(*volumeData);
volIter.setPosition(uX,uY,uZ);
return volIter.getVoxel();
}
BlockVolume<uint8>* 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<uint8> 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<uint8> 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;
}
}