Renamed 'library' folder to 'include' (as it just contains headers now).
This commit is contained in:
79
include/CMakeLists.txt
Normal file
79
include/CMakeLists.txt
Normal file
@ -0,0 +1,79 @@
|
||||
# Copyright (c) 2008-2012 Matt Williams
|
||||
# Copyright (c) 2008-2012 David Williams
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
#
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
#
|
||||
# 3. This notice may not be removed or altered from any source
|
||||
# distribution.
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
|
||||
PROJECT(PolyVox)
|
||||
|
||||
add_subdirectory(PolyVoxCore)
|
||||
|
||||
#Set up install paths e.g. for PolyVoxConfig.cmake
|
||||
if(WIN32)
|
||||
set(CONFIG_FILE_DIR "CMake")
|
||||
set(PolyVoxCore_LIBRARY_INSTALL_DIRS "PolyVoxCore/lib")
|
||||
set(PolyVoxCore_INCLUDE_INSTALL_DIRS "PolyVoxCore/include")
|
||||
set(PolyVox_DOC_INSTALL_DIR "PolyVox/doc")
|
||||
else(WIN32)
|
||||
set(CONFIG_FILE_DIR "share/PolyVox/cmake")
|
||||
set(PolyVoxCore_LIBRARY_INSTALL_DIRS "lib")
|
||||
set(PolyVoxCore_INCLUDE_INSTALL_DIRS "include/PolyVoxCore")
|
||||
set(PolyVox_DOC_INSTALL_DIR "share/doc/packages/polyvox")
|
||||
endif(WIN32)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/PolyVoxConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/PolyVoxConfig.cmake @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/PolyVoxConfig.cmake DESTINATION ${CONFIG_FILE_DIR} COMPONENT development)
|
||||
|
||||
#Documentation
|
||||
if(DOXYGEN_FOUND)
|
||||
#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/polyvox.css ${CMAKE_CURRENT_BINARY_DIR}/polyvox.css)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||
#This is just the default doc target which only runs Doxygen
|
||||
add_custom_target(doc
|
||||
COMMAND ${DOXYGEN_EXECUTABLE}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Building documentation"
|
||||
SOURCES Doxyfile.in polyvox.qhcp.in Mainpage.dox
|
||||
VERBATIM
|
||||
)
|
||||
set_target_properties(doc PROPERTIES PROJECT_LABEL "API Reference") #Set label seen in IDE
|
||||
set_property(TARGET doc PROPERTY FOLDER "Documentation")
|
||||
|
||||
#If we found qcollectiongenerator then do more processing
|
||||
if(QT_QCOLLECTIONGENERATOR_EXECUTABLE)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/polyvox.qhcp.in ${CMAKE_CURRENT_BINARY_DIR}/doc/qthelp/polyvox.qhcp) #The QtHelp config file
|
||||
|
||||
#We attach this command to the doc target so it will be run automatically
|
||||
add_custom_command(TARGET doc POST_BUILD
|
||||
COMMAND ${QT_QCOLLECTIONGENERATOR_EXECUTABLE} polyvox.qhcp -o polyvox.qhc
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/qthelp
|
||||
COMMENT "Compiling API documentation to Qt Help format"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/doc/qthelp/polyvox.qhc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/doc/qthelp/polyvox.qch
|
||||
DESTINATION ${PolyVox_DOC_INSTALL_DIR}/qthelp
|
||||
COMPONENT development
|
||||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
endif()
|
1876
include/Doxyfile.in
Normal file
1876
include/Doxyfile.in
Normal file
File diff suppressed because it is too large
Load Diff
59
include/Mainpage.dox
Normal file
59
include/Mainpage.dox
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
\mainpage PolyVox Framework
|
||||
|
||||
The PolyVox documentation.\n
|
||||
|
||||
See the <a href="../manual/index.html">manual</a> for help and tutorials.
|
||||
|
||||
|
||||
\author David Williams
|
||||
|
||||
\namespace PolyVox
|
||||
\brief Main namespace
|
||||
*/
|
||||
|
||||
/**
|
||||
\page tutorial Tutorial
|
||||
|
||||
This is a basic tutorial covering the essentials of using %PolyVox.
|
||||
|
||||
\note This is a work in progress. For now, the best example is the OpenGL example distributed with %PolyVox in the example/OpenGL/ folder.
|
||||
|
||||
\code
|
||||
#include <Block.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//blah blah
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
\page cmake Finding %PolyVox with CMake
|
||||
|
||||
CMakeLists.txt:
|
||||
\verbatim
|
||||
# Tell CMake the name of you project
|
||||
project(MyApp)
|
||||
|
||||
# Ask CMake to find PolyVox for you
|
||||
find_package(PolyVox REQUIRED)
|
||||
|
||||
# Tell your compiler where to look for the PolyVox headers
|
||||
include_directories(${PolyVox_INCLUDE_DIRS})
|
||||
|
||||
# Create your executable
|
||||
add_executable(myapp main.cpp)
|
||||
|
||||
# Link it to PolyVox
|
||||
target_link_libraries(myapp ${PolyVox_LIBRARIES})
|
||||
\endverbatim
|
||||
|
||||
Then call cmake with
|
||||
\verbatim
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
\endverbatim
|
||||
You may also need to pass an argument to cmake if it can't find %PolyVox. Pass <tt>-DCMAKE_PREFIX_PATH=/path/to/polyvox/root/</tt>.
|
||||
*/
|
39
include/PolyVoxConfig.cmake.in
Normal file
39
include/PolyVoxConfig.cmake.in
Normal file
@ -0,0 +1,39 @@
|
||||
# Find PolyVox includes and library
|
||||
#
|
||||
# This module defines
|
||||
# PolyVox_INCLUDE_DIRS
|
||||
# PolyVox_LIBRARIES, the libraries to link against to use OGRE.
|
||||
# PolyVox_LIBRARY_DIRS, the location of the libraries
|
||||
# PolyVox_FOUND, If false, do not try to use OGRE
|
||||
#
|
||||
# Copyright © 2008, Matt Williams
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
include(FindPackageMessage)
|
||||
|
||||
get_filename_component(THIS_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
if(WIN32)
|
||||
set(PREFIX ${THIS_DIR}/..)
|
||||
else()
|
||||
set(PREFIX ${THIS_DIR}/../../..)
|
||||
endif()
|
||||
|
||||
|
||||
set(PolyVoxCore_LIBRARY_DIRS "${PREFIX}/@PolyVoxCore_LIBRARY_INSTALL_DIRS@")
|
||||
set(PolyVoxUtil_LIBRARY_DIRS "${PREFIX}/@PolyVoxUtil_LIBRARY_INSTALL_DIRS@")
|
||||
set(PolyVox_LIBRARY_DIRS "${PolyVoxCore_LIBRARY_DIRS}" "${PolyVoxUtil_LIBRARY_DIRS}")
|
||||
|
||||
set(PolyVoxCore_INCLUDE_DIRS "${PREFIX}/@PolyVoxCore_INCLUDE_INSTALL_DIRS@")
|
||||
set(PolyVoxUtil_INCLUDE_DIRS "${PREFIX}/@PolyVoxUtil_INCLUDE_INSTALL_DIRS@")
|
||||
set(PolyVox_INCLUDE_DIRS "${PolyVoxCore_INCLUDE_DIRS}" "${PolyVoxUtil_INCLUDE_DIRS}" "${PREFIX}/include")
|
||||
|
||||
set(PolyVoxCore_LIBRARIES "PolyVoxCore")
|
||||
set(PolyVoxUtil_LIBRARIES "PolyVoxUtil")
|
||||
set(PolyVox_LIBRARIES "${PolyVoxCore_LIBRARIES};${PolyVoxUtil_LIBRARIES}")
|
||||
|
||||
message(STATUS "Found PolyVox")
|
||||
message(STATUS " libraries : '${PolyVoxCore_LIBRARIES}' from ${PolyVoxCore_LIBRARY_DIRS}")
|
||||
message(STATUS " : '${PolyVoxUtil_LIBRARIES}' from ${PolyVoxUtil_LIBRARY_DIRS}")
|
||||
message(STATUS " includes : ${PolyVox_INCLUDE_DIRS}")
|
133
include/PolyVoxCore/CMakeLists.txt
Normal file
133
include/PolyVoxCore/CMakeLists.txt
Normal file
@ -0,0 +1,133 @@
|
||||
# Copyright (c) 2008-2012 Matt Williams
|
||||
# Copyright (c) 2008-2012 David Williams
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the authors be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
#
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
#
|
||||
# 3. This notice may not be removed or altered from any source
|
||||
# distribution.
|
||||
|
||||
PROJECT(PolyVoxCore)
|
||||
|
||||
#Projects source files
|
||||
SET(CORE_SRC_FILES
|
||||
#source/AStarPathfinder.cpp
|
||||
)
|
||||
|
||||
#Projects headers files
|
||||
SET(CORE_INC_FILES
|
||||
include/PolyVoxCore/AmbientOcclusionCalculator.h
|
||||
include/PolyVoxCore/AmbientOcclusionCalculator.inl
|
||||
include/PolyVoxCore/Array.h
|
||||
include/PolyVoxCore/AStarPathfinder.h
|
||||
include/PolyVoxCore/AStarPathfinder.inl
|
||||
include/PolyVoxCore/BaseVolume.h
|
||||
include/PolyVoxCore/BaseVolume.inl
|
||||
include/PolyVoxCore/BaseVolumeSampler.inl
|
||||
include/PolyVoxCore/CubicSurfaceExtractor.h
|
||||
include/PolyVoxCore/CubicSurfaceExtractor.inl
|
||||
include/PolyVoxCore/DefaultIsQuadNeeded.h
|
||||
include/PolyVoxCore/DefaultMarchingCubesController.h
|
||||
include/PolyVoxCore/Density.h
|
||||
include/PolyVoxCore/FilePager.h
|
||||
include/PolyVoxCore/GradientEstimators.h
|
||||
include/PolyVoxCore/GradientEstimators.inl
|
||||
include/PolyVoxCore/Interpolation.h
|
||||
include/PolyVoxCore/IteratorController.h
|
||||
include/PolyVoxCore/IteratorController.inl
|
||||
include/PolyVoxCore/LargeVolume.h
|
||||
include/PolyVoxCore/LowPassFilter.h
|
||||
include/PolyVoxCore/LowPassFilter.inl
|
||||
include/PolyVoxCore/MarchingCubesSurfaceExtractor.h
|
||||
include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl
|
||||
include/PolyVoxCore/Material.h
|
||||
include/PolyVoxCore/MaterialDensityPair.h
|
||||
include/PolyVoxCore/Mesh.h
|
||||
include/PolyVoxCore/Mesh.inl
|
||||
include/PolyVoxCore/PagedVolume.h
|
||||
include/PolyVoxCore/PagedVolume.inl
|
||||
include/PolyVoxCore/PagedVolumeChunk.inl
|
||||
include/PolyVoxCore/PagedVolumeSampler.inl
|
||||
include/PolyVoxCore/PolyVoxForwardDeclarations.h
|
||||
include/PolyVoxCore/Picking.h
|
||||
include/PolyVoxCore/Picking.inl
|
||||
include/PolyVoxCore/RawVolume.h
|
||||
include/PolyVoxCore/RawVolume.inl
|
||||
include/PolyVoxCore/RawVolumeSampler.inl
|
||||
include/PolyVoxCore/Raycast.h
|
||||
include/PolyVoxCore/Raycast.inl
|
||||
include/PolyVoxCore/Region.h
|
||||
include/PolyVoxCore/Region.inl
|
||||
include/PolyVoxCore/SimpleVolume.h
|
||||
include/PolyVoxCore/Vector.h
|
||||
include/PolyVoxCore/Vector.inl
|
||||
include/PolyVoxCore/Vertex.h
|
||||
include/PolyVoxCore/VolumeResampler.h
|
||||
include/PolyVoxCore/VolumeResampler.inl
|
||||
include/PolyVoxCore/VoxelFilters.h
|
||||
include/PolyVoxCore/VoxelFilters.inl
|
||||
)
|
||||
|
||||
SET(IMPL_SRC_FILES
|
||||
#source/Impl/ErrorHandling.cpp
|
||||
#source/Impl/Logging.cpp
|
||||
#source/Impl/MarchingCubesTables.cpp
|
||||
#source/Impl/RandomUnitVectors.cpp
|
||||
#source/Impl/RandomVectors.cpp
|
||||
#source/Impl/Timer.cpp
|
||||
#source/Impl/Utility.cpp
|
||||
)
|
||||
|
||||
SET(IMPL_INC_FILES
|
||||
include/PolyVoxCore/Impl/AStarPathfinderImpl.h
|
||||
include/PolyVoxCore/Impl/Config.h
|
||||
include/PolyVoxCore/Impl/ErrorHandling.h
|
||||
include/PolyVoxCore/Impl/Logging.h
|
||||
include/PolyVoxCore/Impl/MarchingCubesTables.h
|
||||
include/PolyVoxCore/Impl/RandomUnitVectors.h
|
||||
include/PolyVoxCore/Impl/RandomVectors.h
|
||||
include/PolyVoxCore/Impl/Timer.h
|
||||
include/PolyVoxCore/Impl/TypeDef.h
|
||||
include/PolyVoxCore/Impl/Utility.h
|
||||
)
|
||||
|
||||
#NOTE: The following line should be uncommented when building shared libs.
|
||||
|
||||
#"Sources" and "Headers" are the group names in Visual Studio.
|
||||
#They may have other uses too...
|
||||
#SOURCE_GROUP("Source Files" FILES ${CORE_SRC_FILES})
|
||||
SOURCE_GROUP("Header Files" FILES ${CORE_INC_FILES})
|
||||
|
||||
#SOURCE_GROUP("Source Files\\Impl" FILES ${IMPL_SRC_FILES})
|
||||
SOURCE_GROUP("Header Files\\Impl" FILES ${IMPL_INC_FILES})
|
||||
|
||||
#Tell CMake the paths
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
#Core
|
||||
|
||||
#Build
|
||||
# Although we don't build anything for PolyVox, we still add this custom target (which
|
||||
# doesn't do anything) so that we can browse the source code from within Visual Studio.
|
||||
ADD_CUSTOM_TARGET(PolyVoxCore SOURCES ${CORE_INC_FILES})
|
||||
|
||||
#Install the core header files, including the ones in the Impl subfolder.
|
||||
IF(WIN32)
|
||||
INSTALL(DIRECTORY include DESTINATION PolyVoxCore COMPONENT development PATTERN "*.svn*" EXCLUDE)
|
||||
ELSE(WIN32)
|
||||
|
||||
INSTALL(DIRECTORY include/ DESTINATION include/PolyVoxCore COMPONENT development PATTERN "*.svn*" EXCLUDE)
|
||||
ENDIF(WIN32)
|
229
include/PolyVoxCore/include/PolyVoxCore/AStarPathfinder.h
Normal file
229
include/PolyVoxCore/include/PolyVoxCore/AStarPathfinder.h
Normal file
@ -0,0 +1,229 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_AStarPathfinder_H__
|
||||
#define __PolyVox_AStarPathfinder_H__
|
||||
|
||||
#include "Impl/AStarPathfinderImpl.h"
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <stdexcept> //For runtime_error
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
const float sqrt_1 = 1.0f;
|
||||
const float sqrt_2 = 1.4143f;
|
||||
const float sqrt_3 = 1.7321f;
|
||||
|
||||
const Vector3DInt32 arrayPathfinderFaces[6] =
|
||||
{
|
||||
Vector3DInt32(0, 0, -1),
|
||||
Vector3DInt32(0, 0, +1),
|
||||
Vector3DInt32(0, -1, 0),
|
||||
Vector3DInt32(0, +1, 0),
|
||||
Vector3DInt32(-1, 0, 0),
|
||||
Vector3DInt32(+1, 0, 0)
|
||||
};
|
||||
|
||||
const Vector3DInt32 arrayPathfinderEdges[12] =
|
||||
{
|
||||
Vector3DInt32(0, -1, -1),
|
||||
Vector3DInt32(0, -1, +1),
|
||||
Vector3DInt32(0, +1, -1),
|
||||
Vector3DInt32(0, +1, +1),
|
||||
Vector3DInt32(-1, 0, -1),
|
||||
Vector3DInt32(-1, 0, +1),
|
||||
Vector3DInt32(+1, 0, -1),
|
||||
Vector3DInt32(+1, 0, +1),
|
||||
Vector3DInt32(-1, -1, 0),
|
||||
Vector3DInt32(-1, +1, 0),
|
||||
Vector3DInt32(+1, -1, 0),
|
||||
Vector3DInt32(+1, +1, 0)
|
||||
};
|
||||
|
||||
const Vector3DInt32 arrayPathfinderCorners[8] =
|
||||
{
|
||||
Vector3DInt32(-1, -1, -1),
|
||||
Vector3DInt32(-1, -1, +1),
|
||||
Vector3DInt32(-1, +1, -1),
|
||||
Vector3DInt32(-1, +1, +1),
|
||||
Vector3DInt32(+1, -1, -1),
|
||||
Vector3DInt32(+1, -1, +1),
|
||||
Vector3DInt32(+1, +1, -1),
|
||||
Vector3DInt32(+1, +1, +1)
|
||||
};
|
||||
|
||||
/// This function provides the default method for checking whether a given voxel
|
||||
/// is valid for the path computed by the AStarPathfinder.
|
||||
template<typename VolumeType>
|
||||
bool aStarDefaultVoxelValidator(const VolumeType* volData, const Vector3DInt32& v3dPos);
|
||||
|
||||
/// Provides a configuration for the AStarPathfinder.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This structure stores the AStarPathfinder%s configuration options, because this
|
||||
/// is simpler than providing a large number of get/set properties within the
|
||||
/// AStarPathfinder itself. In order to create an instance of this structure you
|
||||
/// must provide at least a volume, a start and end point, and a list to store
|
||||
/// the result. All the other option have sensible default values which can
|
||||
/// optionally be changed for more precise control over the pathfinder's behaviour.
|
||||
///
|
||||
/// \sa AStarPathfinder
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VolumeType>
|
||||
struct AStarPathfinderParams
|
||||
{
|
||||
public:
|
||||
AStarPathfinderParams
|
||||
(
|
||||
VolumeType* volData,
|
||||
const Vector3DInt32& v3dStart,
|
||||
const Vector3DInt32& v3dEnd,
|
||||
std::list<Vector3DInt32>* listResult,
|
||||
float fHBias = 1.0,
|
||||
uint32_t uMaxNoOfNodes = 10000,
|
||||
Connectivity requiredConnectivity = TwentySixConnected,
|
||||
std::function<bool (const VolumeType*, const Vector3DInt32&)> funcIsVoxelValidForPath = &aStarDefaultVoxelValidator,
|
||||
std::function<void (float)> funcProgressCallback = nullptr
|
||||
)
|
||||
:volume(volData)
|
||||
,start(v3dStart)
|
||||
,end(v3dEnd)
|
||||
,result(listResult)
|
||||
,connectivity(requiredConnectivity)
|
||||
,hBias(fHBias)
|
||||
,maxNumberOfNodes(uMaxNoOfNodes)
|
||||
,isVoxelValidForPath(funcIsVoxelValidForPath)
|
||||
,progressCallback(funcProgressCallback)
|
||||
{
|
||||
}
|
||||
|
||||
/// This is the volume through which the AStarPathfinder must find a path.
|
||||
VolumeType* volume;
|
||||
|
||||
/// The start point for the pathfinding algorithm.
|
||||
Vector3DInt32 start;
|
||||
|
||||
/// The end point for the pathfinding algorithm.
|
||||
Vector3DInt32 end;
|
||||
|
||||
/// The resulting path will be stored as a series of points in
|
||||
/// this list. Any existing contents will be cleared.
|
||||
std::list<Vector3DInt32>* result;
|
||||
|
||||
/// The AStarPathfinder performs its search by examining the neighbours
|
||||
/// of each voxel it encounters. This property controls the meaning of
|
||||
/// neighbour - e.g. whether two voxels must share a face, edge, or corner.
|
||||
Connectivity connectivity;
|
||||
|
||||
/// For each voxel the pathfinder tracks its distance to the start (known as g())
|
||||
/// and estimates its distance to the end (known as h()). Increasing or decreasing
|
||||
/// h() has an effect on the way the pathfinder behaves. If h() is an underestimate
|
||||
/// of the true distance then the pathfinder will act more like a greedy search -
|
||||
/// always finding the shortest path but taking longer to do so. If h() is an over
|
||||
/// estimate then the pathfinder will behave more like a best-first search - returning
|
||||
/// a potentially suboptimal path but finding it more quickly. The hBias is multiplied
|
||||
/// by the estimated h() value to control this behaviour.
|
||||
float hBias;
|
||||
|
||||
/// Volumes can be pretty huge (millions of voxels) and processing each one of these
|
||||
/// can take a long time. In A* terminology each voxel is a node, and this property
|
||||
/// controls the maximum number of nodes that will be considered when finding the path,
|
||||
/// before giving up and throwing an exception because a path can't be found.
|
||||
uint32_t maxNumberOfNodes;
|
||||
|
||||
/// This function is called to determine whether the path can pass though a given voxel. The
|
||||
/// default behaviour is specified by aStarDefaultVoxelValidator(), but users can specify thier
|
||||
/// own criteria if desired. For example, if you always want a path to follow a surface then
|
||||
/// you could check to ensure that the voxel above is empty and the voxel below is solid.
|
||||
///
|
||||
/// \sa aStarDefaultVoxelValidator
|
||||
std::function<bool (const VolumeType*, const Vector3DInt32&)> isVoxelValidForPath;
|
||||
|
||||
/// This function is called by the AStarPathfinder to report on its progress in getting to
|
||||
/// the goal. The progress is reported by computing the distance from the closest node found
|
||||
/// so far to the end node, and comparing this with the distance from the start node to the
|
||||
/// end node. This progress value is guarenteed to never decrease, but it may stop increasing
|
||||
///for short periods of time. It may even stop increasing altogether if a path cannot be found.
|
||||
std::function<void (float)> progressCallback;
|
||||
};
|
||||
|
||||
/// The AStarPathfinder compute a path from one point in the volume to another.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A* is a well known pathfinding algorithm commonly used in computer games. It
|
||||
/// takes as input a pair of points in the world, and works out a path between
|
||||
/// them which avoids obstacles and adheres to other user defined criteria. The
|
||||
/// resulting path is usually the shortest possible, but a less optimal path can
|
||||
/// be exchanged for reduced computation time.
|
||||
///
|
||||
/// For an excellent overview of the A* algorithm please see Amit Patel's Game
|
||||
/// Programming page here: http://theory.stanford.edu/~amitp/GameProgramming/
|
||||
/// Much of this class is based on the principles described in those pages.
|
||||
///
|
||||
/// Usage of this class if very strightforward. You create an instance of it
|
||||
/// by passing an instance of the AStarPathfinderParams structure to the constructor.
|
||||
/// The details of the AStarPathfinderParams and the options it provides are described
|
||||
/// in the documentation for that class.
|
||||
///
|
||||
/// Next you call the execute() function and wait for it to return. If a path is
|
||||
/// found then this is stored in the list which was set as the 'result' field of
|
||||
/// the AStarPathfinderParams. If a path cannot be found then an exception of type
|
||||
/// std::runtime_error is thrown.
|
||||
///
|
||||
/// \sa AStarPathfinderParams
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VolumeType>
|
||||
class AStarPathfinder
|
||||
{
|
||||
public:
|
||||
AStarPathfinder(const AStarPathfinderParams<VolumeType>& params);
|
||||
|
||||
void execute();
|
||||
|
||||
private:
|
||||
void processNeighbour(const Vector3DInt32& neighbourPos, float neighbourGVal);
|
||||
|
||||
float SixConnectedCost(const Vector3DInt32& a, const Vector3DInt32& b);
|
||||
float EighteenConnectedCost(const Vector3DInt32& a, const Vector3DInt32& b);
|
||||
float TwentySixConnectedCost(const Vector3DInt32& a, const Vector3DInt32& b);
|
||||
float computeH(const Vector3DInt32& a, const Vector3DInt32& b);
|
||||
uint32_t hash(uint32_t a);
|
||||
|
||||
//Node containers
|
||||
AllNodesContainer allNodes;
|
||||
OpenNodesContainer openNodes;
|
||||
ClosedNodesContainer closedNodes;
|
||||
|
||||
//The current node
|
||||
AllNodesContainer::iterator current;
|
||||
|
||||
float m_fProgress;
|
||||
|
||||
AStarPathfinderParams<VolumeType> m_params;
|
||||
};
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/AStarPathfinder.inl"
|
||||
|
||||
#endif //__PolyVox_AStarPathfinder_H__
|
351
include/PolyVoxCore/include/PolyVoxCore/AStarPathfinder.inl
Normal file
351
include/PolyVoxCore/include/PolyVoxCore/AStarPathfinder.inl
Normal file
@ -0,0 +1,351 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/Impl/ErrorHandling.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Using this function, a voxel is considered valid for the path if it is inside the
|
||||
/// volume and if its density is below that returned by the voxel's getDensity() function.
|
||||
/// \return true is the voxel is valid for the path
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VolumeType>
|
||||
bool aStarDefaultVoxelValidator(const VolumeType* volData, const Vector3DInt32& v3dPos)
|
||||
{
|
||||
//Voxels are considered valid candidates for the path if they are inside the volume...
|
||||
if(volData->getEnclosingRegion().containsPoint(v3dPos) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// AStarPathfinder Class
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VolumeType>
|
||||
AStarPathfinder<VolumeType>::AStarPathfinder(const AStarPathfinderParams<VolumeType>& params)
|
||||
:m_params(params)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename VolumeType>
|
||||
void AStarPathfinder<VolumeType>::execute()
|
||||
{
|
||||
//Clear any existing nodes
|
||||
allNodes.clear();
|
||||
openNodes.clear();
|
||||
closedNodes.clear();
|
||||
|
||||
//Clear the result
|
||||
m_params.result->clear();
|
||||
|
||||
//Iterators to start and end node.
|
||||
AllNodesContainer::iterator startNode = allNodes.insert(Node(m_params.start.getX(), m_params.start.getY(), m_params.start.getZ())).first;
|
||||
AllNodesContainer::iterator endNode = allNodes.insert(Node(m_params.end.getX(), m_params.end.getY(), m_params.end.getZ())).first;
|
||||
|
||||
//Regarding the const_cast - normally you should not modify an object which is in an sdt::set.
|
||||
//The reason is that objects in a set are stored sorted in a tree so they can be accessed quickly,
|
||||
//and changing the object directly can break the sorting. However, in our case we have provided a
|
||||
//custom sort operator for the set which we know only uses the position to sort. Hence we can safely
|
||||
//modify other properties of the object while it is in the set.
|
||||
Node* tempStart = const_cast<Node*>(&(*startNode));
|
||||
tempStart->gVal = 0;
|
||||
tempStart->hVal = computeH(startNode->position, endNode->position);
|
||||
|
||||
Node* tempEnd = const_cast<Node*>(&(*endNode));
|
||||
tempEnd->hVal = 0.0f;
|
||||
|
||||
openNodes.insert(startNode);
|
||||
|
||||
float fDistStartToEnd = (endNode->position - startNode->position).length();
|
||||
m_fProgress = 0.0f;
|
||||
if(m_params.progressCallback)
|
||||
{
|
||||
m_params.progressCallback(m_fProgress);
|
||||
}
|
||||
|
||||
while((openNodes.empty() == false) && (openNodes.getFirst() != endNode))
|
||||
{
|
||||
//Move the first node from open to closed.
|
||||
current = openNodes.getFirst();
|
||||
openNodes.removeFirst();
|
||||
closedNodes.insert(current);
|
||||
|
||||
//Update the user on our progress
|
||||
if(m_params.progressCallback)
|
||||
{
|
||||
const float fMinProgresIncreament = 0.001f;
|
||||
float fDistCurrentToEnd = (endNode->position - current->position).length();
|
||||
float fDistNormalised = fDistCurrentToEnd / fDistStartToEnd;
|
||||
float fProgress = 1.0f - fDistNormalised;
|
||||
if(fProgress >= m_fProgress + fMinProgresIncreament)
|
||||
{
|
||||
m_fProgress = fProgress;
|
||||
m_params.progressCallback(m_fProgress);
|
||||
}
|
||||
}
|
||||
|
||||
//The distance from one cell to another connected by face, edge, or corner.
|
||||
const float fFaceCost = sqrt_1;
|
||||
const float fEdgeCost = sqrt_2;
|
||||
const float fCornerCost = sqrt_3;
|
||||
|
||||
//Process the neighbours. Note the deliberate lack of 'break'
|
||||
//statements, larger connectivities include smaller ones.
|
||||
switch(m_params.connectivity)
|
||||
{
|
||||
case TwentySixConnected:
|
||||
processNeighbour(current->position + arrayPathfinderCorners[0], current->gVal + fCornerCost);
|
||||
processNeighbour(current->position + arrayPathfinderCorners[1], current->gVal + fCornerCost);
|
||||
processNeighbour(current->position + arrayPathfinderCorners[2], current->gVal + fCornerCost);
|
||||
processNeighbour(current->position + arrayPathfinderCorners[3], current->gVal + fCornerCost);
|
||||
processNeighbour(current->position + arrayPathfinderCorners[4], current->gVal + fCornerCost);
|
||||
processNeighbour(current->position + arrayPathfinderCorners[5], current->gVal + fCornerCost);
|
||||
processNeighbour(current->position + arrayPathfinderCorners[6], current->gVal + fCornerCost);
|
||||
processNeighbour(current->position + arrayPathfinderCorners[7], current->gVal + fCornerCost);
|
||||
|
||||
case EighteenConnected:
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 0], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 1], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 2], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 3], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 4], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 5], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 6], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 7], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 8], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[ 9], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[10], current->gVal + fEdgeCost);
|
||||
processNeighbour(current->position + arrayPathfinderEdges[11], current->gVal + fEdgeCost);
|
||||
|
||||
case SixConnected:
|
||||
processNeighbour(current->position + arrayPathfinderFaces[0], current->gVal + fFaceCost);
|
||||
processNeighbour(current->position + arrayPathfinderFaces[1], current->gVal + fFaceCost);
|
||||
processNeighbour(current->position + arrayPathfinderFaces[2], current->gVal + fFaceCost);
|
||||
processNeighbour(current->position + arrayPathfinderFaces[3], current->gVal + fFaceCost);
|
||||
processNeighbour(current->position + arrayPathfinderFaces[4], current->gVal + fFaceCost);
|
||||
processNeighbour(current->position + arrayPathfinderFaces[5], current->gVal + fFaceCost);
|
||||
}
|
||||
|
||||
if(allNodes.size() > m_params.maxNumberOfNodes)
|
||||
{
|
||||
//We've reached the specified maximum number
|
||||
//of nodes. Just give up on the search.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if((openNodes.empty()) || (openNodes.getFirst() != endNode))
|
||||
{
|
||||
//In this case we failed to find a valid path.
|
||||
POLYVOX_THROW(std::runtime_error, "No path found");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Regarding the const_cast - normally you should not modify an object which is in an sdt::set.
|
||||
//The reason is that objects in a set are stored sorted in a tree so they can be accessed quickly,
|
||||
//and changing the object directly can break the sorting. However, in our case we have provided a
|
||||
//custom sort operator for the set which we know only uses the position to sort. Hence we can safely
|
||||
//modify other properties of the object while it is in the set.
|
||||
Node* n = const_cast<Node*>(&(*endNode));
|
||||
while(n != 0)
|
||||
{
|
||||
m_params.result->push_front(n->position);
|
||||
n = n->parent;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_params.progressCallback)
|
||||
{
|
||||
m_params.progressCallback(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename VolumeType>
|
||||
void AStarPathfinder<VolumeType>::processNeighbour(const Vector3DInt32& neighbourPos, float neighbourGVal)
|
||||
{
|
||||
bool bIsVoxelValidForPath = m_params.isVoxelValidForPath(m_params.volume, neighbourPos);
|
||||
if(!bIsVoxelValidForPath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float cost = neighbourGVal;
|
||||
|
||||
std::pair<AllNodesContainer::iterator, bool> insertResult = allNodes.insert(Node(neighbourPos.getX(), neighbourPos.getY(), neighbourPos.getZ()));
|
||||
AllNodesContainer::iterator neighbour = insertResult.first;
|
||||
|
||||
if(insertResult.second == true) //New node, compute h.
|
||||
{
|
||||
Node* tempNeighbour = const_cast<Node*>(&(*neighbour));
|
||||
tempNeighbour -> hVal = computeH(neighbour->position, m_params.end);
|
||||
}
|
||||
|
||||
OpenNodesContainer::iterator openIter = openNodes.find(neighbour);
|
||||
if(openIter != openNodes.end())
|
||||
{
|
||||
if(cost < neighbour->gVal)
|
||||
{
|
||||
openNodes.remove(openIter);
|
||||
openIter = openNodes.end();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO - Nodes could keep track of if they are in open or closed? And a pointer to where they are?
|
||||
ClosedNodesContainer::iterator closedIter = closedNodes.find(neighbour);
|
||||
if(closedIter != closedNodes.end())
|
||||
{
|
||||
if(cost < neighbour->gVal)
|
||||
{
|
||||
//Probably shouldn't happen?
|
||||
closedNodes.remove(closedIter);
|
||||
closedIter = closedNodes.end();
|
||||
}
|
||||
}
|
||||
|
||||
if((openIter == openNodes.end()) && (closedIter == closedNodes.end()))
|
||||
{
|
||||
//Regarding the const_cast - normally you should not modify an object which is in an sdt::set.
|
||||
//The reason is that objects in a set are stored sorted in a tree so they can be accessed quickly,
|
||||
//and changing the object directly can break the sorting. However, in our case we have provided a
|
||||
//custom sort operator for the set which we know only uses the position to sort. Hence we can safely
|
||||
//modify other properties of the object while it is in the set.
|
||||
Node* temp = const_cast<Node*>(&(*neighbour));
|
||||
temp->gVal = cost;
|
||||
openNodes.insert(neighbour);
|
||||
temp->parent = const_cast<Node*>(&(*current));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename VolumeType>
|
||||
float AStarPathfinder<VolumeType>::SixConnectedCost(const Vector3DInt32& a, const Vector3DInt32& b)
|
||||
{
|
||||
//This is the only heuristic I'm sure of - just use the manhatten distance for the 6-connected case.
|
||||
uint32_t faceSteps = std::abs(a.getX()-b.getX()) + std::abs(a.getY()-b.getY()) + std::abs(a.getZ()-b.getZ());
|
||||
|
||||
return faceSteps * 1.0f;
|
||||
}
|
||||
|
||||
template<typename VolumeType>
|
||||
float AStarPathfinder<VolumeType>::EighteenConnectedCost(const Vector3DInt32& a, const Vector3DInt32& b)
|
||||
{
|
||||
//I'm not sure of the correct heuristic for the 18-connected case, so I'm just letting it fall through to the
|
||||
//6-connected case. This means 'h' will be bigger than it should be, resulting in a faster path which may not
|
||||
//actually be the shortest one. If you have a correct heuristic for the 18-connected case then please let me know.
|
||||
|
||||
return SixConnectedCost(a,b);
|
||||
}
|
||||
|
||||
template<typename VolumeType>
|
||||
float AStarPathfinder<VolumeType>::TwentySixConnectedCost(const Vector3DInt32& a, const Vector3DInt32& b)
|
||||
{
|
||||
//Can't say I'm certain about this heuristic - if anyone has
|
||||
//a better idea of what it should be then please let me know.
|
||||
uint32_t array[3];
|
||||
array[0] = std::abs(a.getX() - b.getX());
|
||||
array[1] = std::abs(a.getY() - b.getY());
|
||||
array[2] = std::abs(a.getZ() - b.getZ());
|
||||
|
||||
//Maybe this is better implemented directly
|
||||
//using three compares and two swaps... but not
|
||||
//until the profiler says so.
|
||||
std::sort(&array[0], &array[3]);
|
||||
|
||||
uint32_t cornerSteps = array[0];
|
||||
uint32_t edgeSteps = array[1] - array[0];
|
||||
uint32_t faceSteps = array[2] - array[1];
|
||||
|
||||
return cornerSteps * sqrt_3 + edgeSteps * sqrt_2 + faceSteps * sqrt_1;
|
||||
}
|
||||
|
||||
template<typename VolumeType>
|
||||
float AStarPathfinder<VolumeType>::computeH(const Vector3DInt32& a, const Vector3DInt32& b)
|
||||
{
|
||||
float hVal;
|
||||
|
||||
switch(m_params.connectivity)
|
||||
{
|
||||
case TwentySixConnected:
|
||||
hVal = TwentySixConnectedCost(a, b);
|
||||
break;
|
||||
case EighteenConnected:
|
||||
hVal = EighteenConnectedCost(a, b);
|
||||
break;
|
||||
case SixConnected:
|
||||
hVal = SixConnectedCost(a, b);
|
||||
break;
|
||||
default:
|
||||
POLYVOX_THROW(std::invalid_argument, "Connectivity parameter has an unrecognised value.");
|
||||
}
|
||||
|
||||
//Sanity checks in debug mode. These can come out eventually, but I
|
||||
//want to make sure that the heuristics I've come up with make sense.
|
||||
POLYVOX_ASSERT((a-b).length() <= TwentySixConnectedCost(a,b), "A* heuristic error.");
|
||||
POLYVOX_ASSERT(TwentySixConnectedCost(a,b) <= EighteenConnectedCost(a,b), "A* heuristic error.");
|
||||
POLYVOX_ASSERT(EighteenConnectedCost(a,b) <= SixConnectedCost(a,b), "A* heuristic error.");
|
||||
|
||||
//Apply the bias to the computed h value;
|
||||
hVal *= m_params.hBias;
|
||||
|
||||
//Having computed hVal, we now apply some random bias to break ties.
|
||||
//This needs to be deterministic on the input position. This random
|
||||
//bias means it is much les likely that two paths are exactly the same
|
||||
//length, and so far fewer nodes must be expanded to find the shortest path.
|
||||
//See http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#S12
|
||||
|
||||
//Note that if the hash is zero we can have differences between the Linux vs. Windows
|
||||
//(or perhaps GCC vs. VS) versions of the code. This is probably because of the way
|
||||
//sorting inside the std::set works (i.e. one system swaps values which are identical
|
||||
//while the other one doesn't - both approaches are valid). For the same reason we want
|
||||
//to make sure that position (x,y,z) has a differnt hash from e.g. position (x,z,y).
|
||||
uint32_t aX = (a.getX() << 16) & 0x00FF0000;
|
||||
uint32_t aY = (a.getY() << 8) & 0x0000FF00;
|
||||
uint32_t aZ = (a.getZ() ) & 0x000000FF;
|
||||
uint32_t hashVal = hash(aX | aY | aZ);
|
||||
|
||||
//Stop hashVal going over 65535, and divide by 1000000 to make sure it is small.
|
||||
hashVal &= 0x0000FFFF;
|
||||
float fHash = hashVal / 1000000.0f;
|
||||
|
||||
//Apply the hash and return
|
||||
hVal += fHash;
|
||||
return hVal;
|
||||
}
|
||||
|
||||
// Robert Jenkins' 32 bit integer hash function
|
||||
// http://www.burtleburtle.net/bob/hash/integer.html
|
||||
template<typename VolumeType>
|
||||
uint32_t AStarPathfinder<VolumeType>::hash( uint32_t a)
|
||||
{
|
||||
a = (a+0x7ed55d16) + (a<<12);
|
||||
a = (a^0xc761c23c) ^ (a>>19);
|
||||
a = (a+0x165667b1) + (a<<5);
|
||||
a = (a+0xd3a2646c) ^ (a<<9);
|
||||
a = (a+0xfd7046c5) + (a<<3);
|
||||
a = (a^0xb55a4f09) ^ (a>>16);
|
||||
return a;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __AmbientOcclusionCalculator_H__
|
||||
#define __AmbientOcclusionCalculator_H__
|
||||
|
||||
#include "Impl/RandomUnitVectors.h"
|
||||
#include "Impl/RandomVectors.h"
|
||||
|
||||
#include "PolyVoxCore/Array.h"
|
||||
#include "PolyVoxCore/Region.h"
|
||||
#include "PolyVoxCore/Raycast.h"
|
||||
|
||||
//These two should not be here!
|
||||
#include "PolyVoxCore/Material.h"
|
||||
#include "PolyVoxCore/PagedVolume.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Ambient occlusion
|
||||
*/
|
||||
|
||||
template<typename IsVoxelTransparentCallback>
|
||||
class AmbientOcclusionCalculatorRaycastCallback
|
||||
{
|
||||
public:
|
||||
AmbientOcclusionCalculatorRaycastCallback(IsVoxelTransparentCallback isVoxelTransparentCallback) : mIsVoxelTransparentCallback(isVoxelTransparentCallback)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(const PagedVolume<uint8_t>::Sampler& sampler)
|
||||
{
|
||||
uint8_t sample = sampler.getVoxel();
|
||||
bool func = mIsVoxelTransparentCallback(sample);
|
||||
return func;
|
||||
}
|
||||
|
||||
IsVoxelTransparentCallback mIsVoxelTransparentCallback;
|
||||
};
|
||||
|
||||
// NOTE: The callback needs to be a functor not a function. I haven't been
|
||||
// able to work the required template magic to get functions working as well.
|
||||
//
|
||||
// Matt: If you make the function take a "IsVoxelTransparentCallback&&" then
|
||||
// it will forward it on. Works for functors, functions and lambdas.
|
||||
// This will be 'perfect forwarding' using 'universal references'
|
||||
// This will require C++11 rvalue references which is why I haven't made the
|
||||
// change yet.
|
||||
|
||||
/// Calculate the ambient occlusion for the volume
|
||||
template<typename VolumeType, typename IsVoxelTransparentCallback>
|
||||
void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback);
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/AmbientOcclusionCalculator.inl"
|
||||
|
||||
#endif //__AmbientOcclusionCalculator_H__
|
@ -0,0 +1,136 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
* \param volInput The volume to calculate the ambient occlusion for
|
||||
* \param[out] arrayResult The output of the calculator
|
||||
* \param region The region of the volume for which the occlusion should be calculated
|
||||
* \param fRayLength The length for each test ray
|
||||
* \param uNoOfSamplesPerOutputElement The number of samples to calculate the occlusion
|
||||
* \param isVoxelTransparentCallback A callback which takes a \a VoxelType and returns a \a bool whether the voxel is transparent
|
||||
*/
|
||||
template<typename VolumeType, typename IsVoxelTransparentCallback>
|
||||
void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback)
|
||||
{
|
||||
//Make sure that the size of the volume is an exact multiple of the size of the array.
|
||||
if(volInput->getWidth() % arrayResult->getDimension(0) != 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array width.");
|
||||
}
|
||||
if(volInput->getHeight() % arrayResult->getDimension(1) != 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array height.");
|
||||
}
|
||||
if(volInput->getDepth() % arrayResult->getDimension(2) != 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array depth.");
|
||||
}
|
||||
|
||||
uint16_t uRandomUnitVectorIndex = 0;
|
||||
uint16_t uRandomVectorIndex = 0;
|
||||
uint16_t uIndexIncreament;
|
||||
|
||||
//Our initial indices. It doesn't matter exactly what we set here, but the code below makes
|
||||
//sure they are different for different regions which helps reduce tiling patterns in the results.
|
||||
uRandomUnitVectorIndex += region.getLowerX() + region.getLowerY() + region.getLowerZ();
|
||||
uRandomVectorIndex += region.getLowerX() + region.getLowerY() + region.getLowerZ();
|
||||
|
||||
//This value helps us jump around in the array a bit more, so the
|
||||
//nth 'random' value isn't always followed by the n+1th 'random' value.
|
||||
uIndexIncreament = 1;
|
||||
|
||||
const int iRatioX = volInput->getWidth() / arrayResult->getDimension(0);
|
||||
const int iRatioY = volInput->getHeight() / arrayResult->getDimension(1);
|
||||
const int iRatioZ = volInput->getDepth() / arrayResult->getDimension(2);
|
||||
|
||||
const float fRatioX = iRatioX;
|
||||
const float fRatioY = iRatioY;
|
||||
const float fRatioZ = iRatioZ;
|
||||
const Vector3DFloat v3dRatio(fRatioX, fRatioY, fRatioZ);
|
||||
|
||||
const float fHalfRatioX = fRatioX * 0.5f;
|
||||
const float fHalfRatioY = fRatioY * 0.5f;
|
||||
const float fHalfRatioZ = fRatioZ * 0.5f;
|
||||
const Vector3DFloat v3dHalfRatio(fHalfRatioX, fHalfRatioY, fHalfRatioZ);
|
||||
|
||||
const Vector3DFloat v3dOffset(0.5f,0.5f,0.5f);
|
||||
|
||||
//This loop iterates over the bottom-lower-left voxel in each of the cells in the output array
|
||||
for(uint16_t z = region.getLowerZ(); z <= region.getUpperZ(); z += iRatioZ)
|
||||
{
|
||||
for(uint16_t y = region.getLowerY(); y <= region.getUpperY(); y += iRatioY)
|
||||
{
|
||||
for(uint16_t x = region.getLowerX(); x <= region.getUpperX(); x += iRatioX)
|
||||
{
|
||||
//Compute a start position corresponding to
|
||||
//the centre of the cell in the output array.
|
||||
Vector3DFloat v3dStart(x, y, z);
|
||||
v3dStart -= v3dOffset;
|
||||
v3dStart += v3dHalfRatio;
|
||||
|
||||
//Keep track of how many rays did not hit anything
|
||||
uint8_t uVisibleDirections = 0;
|
||||
|
||||
for(int ct = 0; ct < uNoOfSamplesPerOutputElement; ct++)
|
||||
{
|
||||
//We take a random vector with components going from -1 to 1 and scale it to go from -halfRatio to +halfRatio.
|
||||
//This jitter value moves our sample point from the centre of the array cell to somewhere else in the array cell
|
||||
Vector3DFloat v3dJitter = randomVectors[(uRandomVectorIndex += (++uIndexIncreament)) % 1019]; //Prime number helps avoid repetition on successive loops.
|
||||
v3dJitter *= v3dHalfRatio;
|
||||
const Vector3DFloat v3dRayStart = v3dStart + v3dJitter;
|
||||
|
||||
Vector3DFloat v3dRayDirection = randomUnitVectors[(uRandomUnitVectorIndex += (++uIndexIncreament)) % 1021]; //Different prime number.
|
||||
v3dRayDirection *= fRayLength;
|
||||
|
||||
AmbientOcclusionCalculatorRaycastCallback<IsVoxelTransparentCallback> ambientOcclusionCalculatorRaycastCallback(isVoxelTransparentCallback);
|
||||
RaycastResult result = raycastWithDirection(volInput, v3dRayStart, v3dRayDirection, ambientOcclusionCalculatorRaycastCallback);
|
||||
|
||||
// Note - The performance of this could actually be improved it we exited as soon
|
||||
// as the ray left the volume. The raycast test has an example of how to do this.
|
||||
if(result == RaycastResults::Completed)
|
||||
{
|
||||
++uVisibleDirections;
|
||||
}
|
||||
}
|
||||
|
||||
float fVisibility;
|
||||
if(uNoOfSamplesPerOutputElement == 0)
|
||||
{
|
||||
//The user might request zero samples (I've done this in the past while debugging - I don't want to
|
||||
//wait for ambient occlusion but I do want as valid result for rendering). Avoid the divide by zero.
|
||||
fVisibility = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
fVisibility = static_cast<float>(uVisibleDirections) / static_cast<float>(uNoOfSamplesPerOutputElement);
|
||||
POLYVOX_ASSERT((fVisibility >= 0.0f) && (fVisibility <= 1.0f), "Visibility value out of range.");
|
||||
}
|
||||
|
||||
(*arrayResult)(z / iRatioZ, y / iRatioY, x / iRatioX) = static_cast<uint8_t>(255.0f * fVisibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
193
include/PolyVoxCore/include/PolyVoxCore/Array.h
Normal file
193
include/PolyVoxCore/include/PolyVoxCore/Array.h
Normal file
@ -0,0 +1,193 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-20014 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Array_H__
|
||||
#define __PolyVox_Array_H__
|
||||
|
||||
#include <PolyVoxCore/Impl/ErrorHandling.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <uint32_t noOfDims, typename ElementType>
|
||||
class Array
|
||||
{
|
||||
public:
|
||||
|
||||
Array(uint32_t width)
|
||||
:m_pElements(0)
|
||||
{
|
||||
static_assert(noOfDims == 1, "This constructor can only be used with a one-dimensional array");
|
||||
|
||||
m_uDimensions[0] = width;
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
Array(uint32_t width, uint32_t height)
|
||||
:m_pElements(0)
|
||||
{
|
||||
static_assert(noOfDims == 2, "This constructor can only be used with a two-dimensional array");
|
||||
|
||||
m_uDimensions[0] = width;
|
||||
m_uDimensions[1] = height;
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
Array(uint32_t width, uint32_t height, uint32_t depth)
|
||||
:m_pElements(0)
|
||||
{
|
||||
static_assert(noOfDims == 3, "This constructor can only be used with a three-dimensional array");
|
||||
|
||||
m_uDimensions[0] = width;
|
||||
m_uDimensions[1] = height;
|
||||
m_uDimensions[2] = depth;
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
// These are deleted to avoid accidental copying.
|
||||
Array<noOfDims, ElementType>(const Array<noOfDims, ElementType>&) = delete;
|
||||
Array<noOfDims, ElementType>& operator=(const Array<noOfDims, ElementType>&) = delete;
|
||||
|
||||
~Array()
|
||||
{
|
||||
delete[] m_pElements;
|
||||
}
|
||||
|
||||
ElementType& operator()(uint32_t x) const
|
||||
{
|
||||
static_assert(noOfDims == 1, "This accessor can only be used with a one-dimensional array");
|
||||
POLYVOX_ASSERT(x < m_uDimensions[0], "Array access is out-of-range.");
|
||||
return m_pElements[x];
|
||||
}
|
||||
|
||||
ElementType& operator()(uint32_t x, uint32_t y) const
|
||||
{
|
||||
static_assert(noOfDims == 2, "This accessor can only be used with a two-dimensional array");
|
||||
POLYVOX_ASSERT(x < m_uDimensions[0] && y < m_uDimensions[1], "Array access is out-of-range.");
|
||||
return m_pElements[y * m_uDimensions[0] + x];
|
||||
}
|
||||
|
||||
ElementType& operator()(uint32_t x, uint32_t y, uint32_t z) const
|
||||
{
|
||||
static_assert(noOfDims == 3, "This accessor can only be used with a three-dimensional array");
|
||||
POLYVOX_ASSERT(x < m_uDimensions[0] && y < m_uDimensions[1] && z < m_uDimensions[2], "Array access is out-of-range.");
|
||||
return m_pElements[z * m_uDimensions[0] * m_uDimensions[1] + y * m_uDimensions[0] + x];
|
||||
}
|
||||
|
||||
uint32_t getDimension(uint32_t dimension)
|
||||
{
|
||||
return m_uDimensions[dimension];
|
||||
}
|
||||
|
||||
ElementType* getRawData()
|
||||
{
|
||||
return m_pElements;
|
||||
}
|
||||
|
||||
uint32_t getNoOfElements()
|
||||
{
|
||||
return m_uNoOfElements;
|
||||
}
|
||||
|
||||
void swap(Array& other)
|
||||
{
|
||||
ElementType* temp = other.m_pElements;
|
||||
other.m_pElements = m_pElements;
|
||||
m_pElements = temp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void initialize(void)
|
||||
{
|
||||
// Calculate the total number of elements in the array.
|
||||
m_uNoOfElements = 1;
|
||||
for (uint32_t i = 0; i < noOfDims; i++)
|
||||
{
|
||||
m_uNoOfElements *= m_uDimensions[i];
|
||||
}
|
||||
m_pElements = new ElementType[m_uNoOfElements];
|
||||
}
|
||||
|
||||
uint32_t m_uDimensions[noOfDims];
|
||||
uint32_t m_uNoOfElements;
|
||||
ElementType* m_pElements;
|
||||
};
|
||||
|
||||
///A 1D Array of floats.
|
||||
typedef Array<1, float> Array1DFloat;
|
||||
///A 1D Array of doubles.
|
||||
typedef Array<1, double> Array1DDouble;
|
||||
///A 1D Array of signed 8-bit values.
|
||||
typedef Array<1, int8_t> Array1DInt8;
|
||||
///A 1D Array of unsigned 8-bit values.
|
||||
typedef Array<1, uint8_t> Array1DUint8;
|
||||
///A 1D Array of signed 16-bit values.
|
||||
typedef Array<1, int16_t> Array1DInt16;
|
||||
///A 1D Array of unsigned 16-bit values.
|
||||
typedef Array<1, uint16_t> Array1DUint16;
|
||||
///A 1D Array of signed 32-bit values.
|
||||
typedef Array<1, int32_t> Array1DInt32;
|
||||
///A 1D Array of unsigned 32-bit values.
|
||||
typedef Array<1, uint32_t> Array1DUint32;
|
||||
|
||||
///A 2D Array of floats.
|
||||
typedef Array<2, float> Array2DFloat;
|
||||
///A 2D Array of doubles.
|
||||
typedef Array<2, double> Array2DDouble;
|
||||
///A 2D Array of signed 8-bit values.
|
||||
typedef Array<2, int8_t> Array2DInt8;
|
||||
///A 2D Array of unsigned 8-bit values.
|
||||
typedef Array<2, uint8_t> Array2DUint8;
|
||||
///A 2D Array of signed 16-bit values.
|
||||
typedef Array<2, int16_t> Array2DInt16;
|
||||
///A 2D Array of unsigned 16-bit values.
|
||||
typedef Array<2, uint16_t> Array2DUint16;
|
||||
///A 2D Array of signed 32-bit values.
|
||||
typedef Array<2, int32_t> Array2DInt32;
|
||||
///A 2D Array of unsigned 32-bit values.
|
||||
typedef Array<2, uint32_t> Array2DUint32;
|
||||
|
||||
///A 3D Array of floats.
|
||||
typedef Array<3, float> Array3DFloat;
|
||||
///A 3D Array of doubles.
|
||||
typedef Array<3, double> Array3DDouble;
|
||||
///A 3D Array of signed 8-bit values.
|
||||
typedef Array<3, int8_t> Array3DInt8;
|
||||
///A 3D Array of unsigned 8-bit values.
|
||||
typedef Array<3, uint8_t> Array3DUint8;
|
||||
///A 3D Array of signed 16-bit values.
|
||||
typedef Array<3, int16_t> Array3DInt16;
|
||||
///A 3D Array of unsigned 16-bit values.
|
||||
typedef Array<3, uint16_t> Array3DUint16;
|
||||
///A 3D Array of signed 32-bit values.
|
||||
typedef Array<3, int32_t> Array3DInt32;
|
||||
///A 3D Array of unsigned 32-bit values.
|
||||
typedef Array<3, uint32_t> Array3DUint32;
|
||||
}
|
||||
|
||||
#endif //__PolyVox_Array_H__
|
217
include/PolyVoxCore/include/PolyVoxCore/BaseVolume.h
Normal file
217
include/PolyVoxCore/include/PolyVoxCore/BaseVolume.h
Normal file
@ -0,0 +1,217 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_BaseVolume_H__
|
||||
#define __PolyVox_BaseVolume_H__
|
||||
|
||||
#include "PolyVoxCore/Region.h"
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/// The BaseVolume class provides common functionality and an interface for other volume classes to implement. You should not try to create an instance of this
|
||||
/// class directly. Instead you should use RawVolume or PagedVolume.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// More details to come...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace WrapModes
|
||||
{
|
||||
enum WrapMode
|
||||
{
|
||||
Validate = 0,
|
||||
Clamp = 1,
|
||||
Border = 2,
|
||||
AssumeValid = 3
|
||||
};
|
||||
}
|
||||
typedef WrapModes::WrapMode WrapMode;
|
||||
|
||||
// Required for a trick to implement specialization of template member
|
||||
// functions in template classes. See http://stackoverflow.com/a/4951057
|
||||
template <WrapMode W> struct WrapModeType{};
|
||||
|
||||
template <typename _VoxelType>
|
||||
class BaseVolume
|
||||
{
|
||||
public:
|
||||
typedef _VoxelType VoxelType;
|
||||
|
||||
#ifndef SWIG
|
||||
template <typename DerivedVolumeType>
|
||||
class Sampler
|
||||
{
|
||||
public:
|
||||
Sampler(DerivedVolumeType* volume);
|
||||
~Sampler();
|
||||
|
||||
Vector3DInt32 getPosition(void) const;
|
||||
inline VoxelType getVoxel(void) const;
|
||||
|
||||
bool isCurrentPositionValid(void) const;
|
||||
|
||||
void setPosition(const Vector3DInt32& v3dNewPos);
|
||||
void setPosition(int32_t xPos, int32_t yPos, int32_t zPos);
|
||||
inline bool setVoxel(VoxelType tValue);
|
||||
void setWrapMode(WrapMode eWrapMode, VoxelType tBorder = VoxelType());
|
||||
|
||||
void movePositiveX(void);
|
||||
void movePositiveY(void);
|
||||
void movePositiveZ(void);
|
||||
|
||||
void moveNegativeX(void);
|
||||
void moveNegativeY(void);
|
||||
void moveNegativeZ(void);
|
||||
|
||||
inline VoxelType peekVoxel1nx1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py1pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py1pz(void) const;
|
||||
|
||||
inline VoxelType peekVoxel0px1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel0px1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel0px1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel0px0py1nz(void) const;
|
||||
inline VoxelType peekVoxel0px0py0pz(void) const;
|
||||
inline VoxelType peekVoxel0px0py1pz(void) const;
|
||||
inline VoxelType peekVoxel0px1py1nz(void) const;
|
||||
inline VoxelType peekVoxel0px1py0pz(void) const;
|
||||
inline VoxelType peekVoxel0px1py1pz(void) const;
|
||||
|
||||
inline VoxelType peekVoxel1px1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel1px1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel1px1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel1px0py1nz(void) const;
|
||||
inline VoxelType peekVoxel1px0py0pz(void) const;
|
||||
inline VoxelType peekVoxel1px0py1pz(void) const;
|
||||
inline VoxelType peekVoxel1px1py1nz(void) const;
|
||||
inline VoxelType peekVoxel1px1py0pz(void) const;
|
||||
inline VoxelType peekVoxel1px1py1pz(void) const;
|
||||
|
||||
protected:
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
|
||||
|
||||
DerivedVolumeType* mVolume;
|
||||
|
||||
//The current position in the volume
|
||||
int32_t mXPosInVolume;
|
||||
int32_t mYPosInVolume;
|
||||
int32_t mZPosInVolume;
|
||||
|
||||
WrapMode m_eWrapMode;
|
||||
VoxelType m_tBorder;
|
||||
|
||||
//Whether the current position is inside the volume
|
||||
//FIXME - Replace these with flags
|
||||
bool m_bIsCurrentPositionValidInX;
|
||||
bool m_bIsCurrentPositionValidInY;
|
||||
bool m_bIsCurrentPositionValidInZ;
|
||||
};
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// Gets the value used for voxels which are outside the volume
|
||||
VoxelType getBorderValue(void) const;
|
||||
/// Gets a Region representing the extents of the Volume.
|
||||
const Region& getEnclosingRegion(void) const;
|
||||
/// Gets the width of the volume in voxels.
|
||||
int32_t getWidth(void) const;
|
||||
/// Gets the height of the volume in voxels.
|
||||
int32_t getHeight(void) const;
|
||||
/// Gets the depth of the volume in voxels.
|
||||
int32_t getDepth(void) const;
|
||||
/// Gets the length of the longest side in voxels
|
||||
int32_t getLongestSideLength(void) const;
|
||||
/// Gets the length of the shortest side in voxels
|
||||
int32_t getShortestSideLength(void) const;
|
||||
/// Gets the length of the diagonal in voxels
|
||||
float getDiagonalLength(void) const;
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const;
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
|
||||
|
||||
/// Sets the value used for voxels which are outside the volume
|
||||
void setBorderValue(const VoxelType& tBorder);
|
||||
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate);
|
||||
/// Sets the voxel at the position given by a 3D vector
|
||||
void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate);
|
||||
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
|
||||
/// Sets the voxel at the position given by a 3D vector
|
||||
bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue);
|
||||
|
||||
/// Calculates approximatly how many bytes of memory the volume is currently using.
|
||||
uint32_t calculateSizeInBytes(void);
|
||||
|
||||
protected:
|
||||
/// Constructor for creating a fixed size volume.
|
||||
BaseVolume(const Region& regValid);
|
||||
|
||||
/// Copy constructor
|
||||
BaseVolume(const BaseVolume& rhs);
|
||||
|
||||
/// Destructor
|
||||
~BaseVolume();
|
||||
|
||||
/// Assignment operator
|
||||
BaseVolume& operator=(const BaseVolume& rhs);
|
||||
|
||||
//The size of the volume
|
||||
Region m_regValidRegion;
|
||||
|
||||
//Some useful sizes
|
||||
int32_t m_uLongestSideLength;
|
||||
int32_t m_uShortestSideLength;
|
||||
float m_fDiagonalLength;
|
||||
|
||||
//The border value
|
||||
VoxelType m_tBorderValue;
|
||||
};
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/BaseVolume.inl"
|
||||
#include "PolyVoxCore/BaseVolumeSampler.inl"
|
||||
|
||||
#endif //__PolyVox_BaseVolume_H__
|
314
include/PolyVoxCore/include/PolyVoxCore/BaseVolume.inl
Normal file
314
include/PolyVoxCore/include/PolyVoxCore/BaseVolume.inl
Normal file
@ -0,0 +1,314 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This is protected because you should never create a BaseVolume directly, you should instead use one of the derived classes.
|
||||
///
|
||||
/// \sa RawVolume, PagedVolume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
BaseVolume<VoxelType>::BaseVolume(const Region& regValid)
|
||||
:m_regValidRegion(regValid)
|
||||
,m_tBorderValue()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing
|
||||
/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to
|
||||
/// make a copy of a volume and in this case you should look at the VolumeResampler.
|
||||
///
|
||||
/// \sa VolumeResampler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
BaseVolume<VoxelType>::BaseVolume(const BaseVolume<VoxelType>& /*rhs*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Destroys the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
BaseVolume<VoxelType>::~BaseVolume()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing
|
||||
/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to
|
||||
/// make a copy of a volume and in this case you should look at the VolumeResampler.
|
||||
///
|
||||
/// \sa VolumeResampler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
BaseVolume<VoxelType>& BaseVolume<VoxelType>::operator=(const BaseVolume<VoxelType>& /*rhs*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// The border value is returned whenever an attempt is made to read a voxel which
|
||||
/// is outside the extents of the volume.
|
||||
/// \return The value used for voxels outside of the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType BaseVolume<VoxelType>::getBorderValue(void) const
|
||||
{
|
||||
return m_tBorderValue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \return A Region representing the extent of the volume.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
const Region& BaseVolume<VoxelType>::getEnclosingRegion(void) const
|
||||
{
|
||||
return m_regValidRegion;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \return The width of the volume in voxels. Note that this value is inclusive, so that if the valid range is e.g. 0 to 63 then the width is 64.
|
||||
/// \sa getHeight(), getDepth()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
int32_t BaseVolume<VoxelType>::getWidth(void) const
|
||||
{
|
||||
return m_regValidRegion.getUpperX() - m_regValidRegion.getLowerX() + 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \return The height of the volume in voxels. Note that this value is inclusive, so that if the valid range is e.g. 0 to 63 then the height is 64.
|
||||
/// \sa getWidth(), getDepth()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
int32_t BaseVolume<VoxelType>::getHeight(void) const
|
||||
{
|
||||
return m_regValidRegion.getUpperY() - m_regValidRegion.getLowerY() + 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \return The depth of the volume in voxels. Note that this value is inclusive, so that if the valid range is e.g. 0 to 63 then the depth is 64.
|
||||
/// \sa getWidth(), getHeight()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
int32_t BaseVolume<VoxelType>::getDepth(void) const
|
||||
{
|
||||
return m_regValidRegion.getUpperZ() - m_regValidRegion.getLowerZ() + 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \return The length of the shortest side in voxels. For example, if a volume has
|
||||
/// dimensions 256x512x1024 this function will return 256.
|
||||
/// \sa getLongestSideLength(), getDiagonalLength()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
int32_t BaseVolume<VoxelType>::getShortestSideLength(void) const
|
||||
{
|
||||
return m_uShortestSideLength;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \return The length of the longest side in voxels. For example, if a volume has
|
||||
/// dimensions 256x512x1024 this function will return 1024.
|
||||
/// \sa getShortestSideLength(), getDiagonalLength()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
int32_t BaseVolume<VoxelType>::getLongestSideLength(void) const
|
||||
{
|
||||
return m_uLongestSideLength;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \return The length of the diagonal in voxels. For example, if a volume has
|
||||
/// dimensions 256x512x1024 this function will return sqrt(256*256+512*512+1024*1024)
|
||||
/// = 1173.139. This value is computed on volume creation so retrieving it is fast.
|
||||
/// \sa getShortestSideLength(), getLongestSideLength()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
float BaseVolume<VoxelType>::getDiagonalLength(void) const
|
||||
{
|
||||
return m_fDiagonalLength;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function requires the wrap mode to be specified as a
|
||||
/// template parameter, which can provide better performance.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tBorder*/) const
|
||||
{
|
||||
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
|
||||
return VoxelType();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function requires the wrap mode to be specified as a
|
||||
/// template parameter, which can provide better performance.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/, VoxelType /*tBorder*/) const
|
||||
{
|
||||
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
|
||||
return VoxelType();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function is provided so that the wrap mode does not need
|
||||
/// to be specified as a template parameter, as it may be confusing to some users.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const
|
||||
{
|
||||
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
|
||||
return VoxelType();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function is provided so that the wrap mode does not need
|
||||
/// to be specified as a template parameter, as it may be confusing to some users.
|
||||
/// \param v3dPos The 3D position of the voxel
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const
|
||||
{
|
||||
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
|
||||
return VoxelType();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType BaseVolume<VoxelType>::getVoxelAt(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
|
||||
return VoxelType();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos The 3D position of the voxel
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType BaseVolume<VoxelType>::getVoxelAt(const Vector3DInt32& /*v3dPos*/) const
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
|
||||
return VoxelType();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param tBorder The value to use for voxels outside the volume.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void BaseVolume<VoxelType>::setBorderValue(const VoxelType& tBorder)
|
||||
{
|
||||
m_tBorderValue = tBorder;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos the \c x position of the voxel
|
||||
/// \param uYPos the \c y position of the voxel
|
||||
/// \param uZPos the \c z position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void BaseVolume<VoxelType>::setVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tValue*/, WrapMode /*eWrapMode*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos the 3D position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void BaseVolume<VoxelType>::setVoxel(const Vector3DInt32& /*v3dPos*/, VoxelType /*tValue*/, WrapMode /*eWrapMode*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos the \c x position of the voxel
|
||||
/// \param uYPos the \c y position of the voxel
|
||||
/// \param uZPos the \c z position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \return whether the requested position is inside the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
bool BaseVolume<VoxelType>::setVoxelAt(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tValue*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos the 3D position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \return whether the requested position is inside the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
bool BaseVolume<VoxelType>::setVoxelAt(const Vector3DInt32& /*v3dPos*/, VoxelType /*tValue*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Note: This function needs reviewing for accuracy...
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
uint32_t BaseVolume<VoxelType>::calculateSizeInBytes(void)
|
||||
{
|
||||
return getWidth() * getHeight() * getDepth() * sizeof(VoxelType);
|
||||
}
|
||||
}
|
||||
|
366
include/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl
Normal file
366
include/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl
Normal file
@ -0,0 +1,366 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/Impl/Utility.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::Sampler(DerivedVolumeType* volume)
|
||||
:mVolume(volume)
|
||||
,mXPosInVolume(0)
|
||||
,mYPosInVolume(0)
|
||||
,mZPosInVolume(0)
|
||||
,m_eWrapMode(WrapModes::Border)
|
||||
,m_tBorder()
|
||||
,m_bIsCurrentPositionValidInX(false)
|
||||
,m_bIsCurrentPositionValidInY(false)
|
||||
,m_bIsCurrentPositionValidInZ(false)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::~Sampler()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
Vector3DInt32 BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::getPosition(void) const
|
||||
{
|
||||
return Vector3DInt32(mXPosInVolume, mYPosInVolume, mZPosInVolume);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::getVoxel(void) const
|
||||
{
|
||||
return mVolume->getVoxel(mXPosInVolume, mYPosInVolume, mZPosInVolume, WrapModes::Validate); // FIXME - Use templatised version instead but watch for Linux compile errors.
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
bool inline BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::isCurrentPositionValid(void) const
|
||||
{
|
||||
return m_bIsCurrentPositionValidInX && m_bIsCurrentPositionValidInY && m_bIsCurrentPositionValidInZ;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::setPosition(const Vector3DInt32& v3dNewPos)
|
||||
{
|
||||
setPosition(v3dNewPos.getX(), v3dNewPos.getY(), v3dNewPos.getZ());
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::setPosition(int32_t xPos, int32_t yPos, int32_t zPos)
|
||||
{
|
||||
mXPosInVolume = xPos;
|
||||
mYPosInVolume = yPos;
|
||||
mZPosInVolume = zPos;
|
||||
|
||||
m_bIsCurrentPositionValidInX = mVolume->getEnclosingRegion().containsPointInX(xPos);
|
||||
m_bIsCurrentPositionValidInY = mVolume->getEnclosingRegion().containsPointInY(yPos);
|
||||
m_bIsCurrentPositionValidInZ = mVolume->getEnclosingRegion().containsPointInZ(zPos);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
bool BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::setVoxel(VoxelType tValue)
|
||||
{
|
||||
return mVolume->setVoxelAt(mXPosInVolume, mYPosInVolume, mZPosInVolume, tValue);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::setWrapMode(WrapMode eWrapMode, VoxelType tBorder)
|
||||
{
|
||||
m_eWrapMode = eWrapMode;
|
||||
m_tBorder = tBorder;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveX(void)
|
||||
{
|
||||
mXPosInVolume++;
|
||||
m_bIsCurrentPositionValidInX = mVolume->getEnclosingRegion().containsPointInX(mXPosInVolume);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveY(void)
|
||||
{
|
||||
mYPosInVolume++;
|
||||
m_bIsCurrentPositionValidInY = mVolume->getEnclosingRegion().containsPointInY(mYPosInVolume);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveZ(void)
|
||||
{
|
||||
mZPosInVolume++;
|
||||
m_bIsCurrentPositionValidInZ = mVolume->getEnclosingRegion().containsPointInZ(mZPosInVolume);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeX(void)
|
||||
{
|
||||
mXPosInVolume--;
|
||||
m_bIsCurrentPositionValidInX = mVolume->getEnclosingRegion().containsPointInX(mXPosInVolume);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeY(void)
|
||||
{
|
||||
mYPosInVolume--;
|
||||
m_bIsCurrentPositionValidInY = mVolume->getEnclosingRegion().containsPointInY(mYPosInVolume);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeZ(void)
|
||||
{
|
||||
mZPosInVolume--;
|
||||
m_bIsCurrentPositionValidInZ = mVolume->getEnclosingRegion().containsPointInZ(mZPosInVolume);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py1nz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume - 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py0pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume );
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py1pz(void) const
|
||||
{
|
||||
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume + 1);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <typename DerivedVolumeType>
|
||||
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
|
||||
{
|
||||
switch(m_eWrapMode)
|
||||
{
|
||||
case WrapModes::Validate:
|
||||
return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Validate, m_tBorder);
|
||||
case WrapModes::Clamp:
|
||||
return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Clamp, m_tBorder);
|
||||
case WrapModes::Border:
|
||||
return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Border, m_tBorder);
|
||||
case WrapModes::AssumeValid:
|
||||
return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::AssumeValid, m_tBorder);
|
||||
default:
|
||||
// Should never happen
|
||||
POLYVOX_ASSERT(false, "Invalid wrap mode");
|
||||
return VoxelType();
|
||||
}
|
||||
}
|
||||
}
|
228
include/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h
Normal file
228
include/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h
Normal file
@ -0,0 +1,228 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_CubicSurfaceExtractor_H__
|
||||
#define __PolyVox_CubicSurfaceExtractor_H__
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include "PolyVoxForwardDeclarations.h"
|
||||
|
||||
#include "PolyVoxCore/Array.h"
|
||||
#include "PolyVoxCore/BaseVolume.h" //For wrap modes... should move these?
|
||||
#include "PolyVoxCore/DefaultIsQuadNeeded.h"
|
||||
#include "PolyVoxCore/Mesh.h"
|
||||
#include "PolyVoxCore/Vertex.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
#ifdef SWIG
|
||||
struct CubicVertex
|
||||
#else
|
||||
template<typename _DataType>
|
||||
struct POLYVOX_API CubicVertex
|
||||
#endif
|
||||
{
|
||||
typedef _DataType DataType;
|
||||
|
||||
// Each component of the position is stored as a single unsigned byte.
|
||||
// The true position is found by offseting each component by 0.5f.
|
||||
Vector3DUint8 encodedPosition;
|
||||
|
||||
// User data
|
||||
DataType data;
|
||||
};
|
||||
|
||||
// Convienient shorthand for declaring a mesh of 'cubic' vertices
|
||||
// Currently disabled because it requires GCC 4.7
|
||||
//template <typename VertexDataType, typename IndexType = DefaultIndexType>
|
||||
//using CubicMesh = Mesh< CubicVertex<VertexDataType>, IndexType >;
|
||||
|
||||
/// Decodes a position from a CubicVertex
|
||||
inline Vector3DFloat decodePosition(const Vector3DUint8& encodedPosition)
|
||||
{
|
||||
Vector3DFloat result(encodedPosition.getX(), encodedPosition.getY(), encodedPosition.getZ());
|
||||
result -= 0.5f; // Apply the required offset
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Decodes a MarchingCubesVertex by converting it into a regular Vertex which can then be directly used for rendering.
|
||||
template<typename DataType>
|
||||
Vertex<DataType> decodeVertex(const CubicVertex<DataType>& cubicVertex)
|
||||
{
|
||||
Vertex<DataType> result;
|
||||
result.position = decodePosition(cubicVertex.encodedPosition);
|
||||
result.normal.setElements(0.0f, 0.0f, 0.0f); // Currently not calculated
|
||||
result.data = cubicVertex.data; // Data is not encoded
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Do not use this class directly. Use the 'extractCubicSurface' function instead (see examples).
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
|
||||
class CubicSurfaceExtractor
|
||||
{
|
||||
struct IndexAndMaterial
|
||||
{
|
||||
int32_t iIndex;
|
||||
typename VolumeType::VoxelType uMaterial;
|
||||
};
|
||||
|
||||
enum FaceNames
|
||||
{
|
||||
PositiveX,
|
||||
PositiveY,
|
||||
PositiveZ,
|
||||
NegativeX,
|
||||
NegativeY,
|
||||
NegativeZ,
|
||||
NoOfFaces
|
||||
};
|
||||
|
||||
struct Quad
|
||||
{
|
||||
Quad(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3)
|
||||
{
|
||||
vertices[0] = v0;
|
||||
vertices[1] = v1;
|
||||
vertices[2] = v2;
|
||||
vertices[3] = v3;
|
||||
}
|
||||
|
||||
uint32_t vertices[4];
|
||||
};
|
||||
|
||||
public:
|
||||
CubicSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, IsQuadNeeded isQuadNeeded = IsQuadNeeded(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true);
|
||||
|
||||
void execute();
|
||||
|
||||
private:
|
||||
int32_t addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterial, Array<3, IndexAndMaterial>& existingVertices);
|
||||
bool performQuadMerging(std::list<Quad>& quads);
|
||||
bool mergeQuads(Quad& q1, Quad& q2);
|
||||
|
||||
IsQuadNeeded m_funcIsQuadNeededCallback;
|
||||
|
||||
//The volume data and a sampler to access it.
|
||||
VolumeType* m_volData;
|
||||
|
||||
//Information about the region we are currently processing
|
||||
Region m_regSizeInVoxels;
|
||||
|
||||
//The surface patch we are currently filling.
|
||||
MeshType* m_meshCurrent;
|
||||
|
||||
//Used to avoid creating duplicate vertices.
|
||||
Array<3, IndexAndMaterial> m_previousSliceVertices;
|
||||
Array<3, IndexAndMaterial> m_currentSliceVertices;
|
||||
|
||||
//During extraction we create a number of different lists of quads. All the
|
||||
//quads in a given list are in the same plane and facing in the same direction.
|
||||
std::vector< std::list<Quad> > m_vecQuads[NoOfFaces];
|
||||
|
||||
//Controls whether quad merging should be performed. This might be undesirable
|
||||
//is the user needs per-vertex attributes, or to perform per vertex lighting.
|
||||
bool m_bMergeQuads;
|
||||
|
||||
//This constant defines the maximum number of quads which can share a
|
||||
//vertex in a cubic style mesh. See the initialisation for more details.
|
||||
static const uint32_t MaxVerticesPerPosition;
|
||||
|
||||
//The wrap mode
|
||||
WrapMode m_eWrapMode;
|
||||
typename VolumeType::VoxelType m_tBorderValue;
|
||||
};
|
||||
|
||||
// This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically.
|
||||
// There are a few reasons why this might be useful to more advanced users:
|
||||
//
|
||||
// 1. It leaves the user in control of memory allocation and would allow them to implement e.g. a mesh pooling system.
|
||||
// 2. The user-provided mesh could have a different index type (e.g. 16-bit indices) to reduce memory usage.
|
||||
// 3. The user could provide a custom mesh class, e.g a thin wrapper around an openGL VBO to allow direct writing into this structure.
|
||||
//
|
||||
// We don't provide a default MeshType here. If the user doesn't want to provide a MeshType then it probably makes
|
||||
// more sense to use the other variant of this function where the mesh is a return value rather than a parameter.
|
||||
//
|
||||
// Note: This function is called 'extractCubicMeshCustom' rather than 'extractCubicMesh' to avoid ambiguity when only three parameters
|
||||
// are provided (would the third parameter be a controller or a mesh?). It seems this can be fixed by using enable_if/static_assert to emulate concepts,
|
||||
// but this is relatively complex and I haven't done it yet. Could always add it later as another overload.
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> >
|
||||
void extractCubicMeshCustom(VolumeType* volData, Region region, MeshType* result, IsQuadNeeded isQuadNeeded = IsQuadNeeded(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true)
|
||||
{
|
||||
CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded> extractor(volData, region, result, isQuadNeeded, eWrapMode, tBorderValue, bMergeQuads);
|
||||
extractor.execute();
|
||||
}
|
||||
|
||||
/// The CubicSurfaceExtractor creates a mesh in which each voxel appears to be rendered as a cube
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Introduction
|
||||
/// ------------
|
||||
/// Games such as Minecraft and Voxatron have a unique graphical style in which each voxel in the world appears to be rendered as a single cube. Actually rendering a cube for each voxel would be very expensive, but in practice the only faces which need to be drawn are those which lie on the boundary between solid and empty voxels. The CubicSurfaceExtractor can be used to create such a mesh from PolyVox volume data. As an example, images from Minecraft and Voxatron are shown below:
|
||||
///
|
||||
/// \image html MinecraftAndVoxatron.jpg
|
||||
///
|
||||
/// Before we get into the specifics of the CubicSurfaceExtractor, it is useful to understand the principles which apply to *all* PolyVox surface extractors and which are described in the Surface Extraction document (ADD LINK). From here on, it is assumed that you are familier with PolyVox regions and how they are used to limit surface extraction to a particular part of the volume. The principles of allowing dynamic terrain are also common to all surface extractors and are described here (ADD LINK).
|
||||
///
|
||||
/// Basic Operation
|
||||
/// ---------------
|
||||
/// At its core, the CubicSurfaceExtractor works by by looking at pairs of adjacent voxels and determining whether a quad should be placed between then. The most simple situation to imagine is a binary volume where every voxel is either solid or empty. In this case a quad should be generated whenever a solid voxel is next to an empty voxel as this represents part of the surface of the solid object. There is no need to generate a quad between two solid voxels (this quad would never be seen as it is inside the object) and there is no need to generate a quad between two empty voxels (there is no object here). PolyVox allows the principle to be extended far beyond such simple binary volumes but they provide a useful starting point for understanding how the algorithm works.
|
||||
///
|
||||
/// As an example, lets consider the part of a volume shown below. We are going to explain the principles in only two dimensions as this makes it much simpler to illustrate, so you will need to mentally extend the process into the third dimension. Hopefully you will find this intuitive. The diagram below shows a small part of a larger volume (as indicated by the voxel coordinates on the axes) which contains only solid and empty voxels represented by solid and hollow circles respectively. The region on which we are running the surface extractor is marked in pink, and for the purpose of this example it corresponds to the whole of the diagram.
|
||||
///
|
||||
/// \image html CubicSurfaceExtractor1.png
|
||||
///
|
||||
/// The output of the surface extractor is the mesh marked in red. As you can see, this forms a closed object which corrsponds to the shape of the underlying voxel data. We won't describe the rendering of such meshes here - for details of this please see (SOME LINK HERE).
|
||||
///
|
||||
/// Working with Regions
|
||||
/// --------------------
|
||||
/// So far the behaviour is easy to understand, but let's look at what happens when the extraction is limited to a particular region of the volume. The figure below shows the same data set as the previous figure, but the extraction region (still marked in pink) has been limited to 13 to 16 in x and 47 to 51 in y:
|
||||
///
|
||||
/// \image html CubicSurfaceExtractor2.png
|
||||
///
|
||||
/// As you can see, the extractor continues to generate a number of quads as indicated by the solid red lines. However, you can also see that the shape is no longer closed. This is because the solid voxels actually extend outside the region which is being processed, and so the extractor does not encounter a boundary between solid and empty voxels. Although this may initially appear problematic, the hole in the mesh does not actually matter because it will be hidden by the mesh corresponding to the region adjacent to it (see next diagram).
|
||||
///
|
||||
/// More interestingly, the diagram also contains a couple of dotted red lines lying on the bottom and right hand side of the extracted region. These are present to illustrate a common point of confusion, which is that *no quads are generated at this position even though it is a boundary between solid and empty voxels*. This is indeed somewhat counter intuitive but there is a rational reasaoning behind it.
|
||||
/// If you consider the dashed line on the righthand side of the extracted region, then it is clear that this lies on a boundary between solid and empty voxels and so we do need to create quads here. But what is not so clear is whether these quads should be assigned to the mesh which corresponds to the region in pink, or whether they should be assigned to the region to the right of it which is marked in blue in the diagram below:
|
||||
///
|
||||
/// \image html CubicSurfaceExtractor3.png
|
||||
///
|
||||
/// We could choose to add the quads to *both* regions, but this can cause confusion when one of the region is modified (causing the face to disappear or a new one to be created) as *both* regions need to have their mesh regenerated to correctly represent the new state of the volume data. Such pairs of coplanar quads can also cause problems with physics engines, and may prevent transparent voxels from rendering correctly. Therefore we choose to instead only add the quad to one of the the regions and we always choose the one with the greater coordinate value in the direction in which they differ. In the above example the regions differ by the 'x' component of their position, and so the quad is added to the region with the greater 'x' value (the one marked in blue).
|
||||
///
|
||||
/// **Note:** *This behaviour has changed recently (September 2012). Earlier versions of PolyVox tried to be smart about this problem by looking beyond the region which was being processed, but this complicated the code and didn't work very well. Ultimatly we decided to simply stick with the convention outlined above.*
|
||||
///
|
||||
/// One of the practical implications of this is that when you modify a voxel *you may have to re-extract the mesh for regions other than region which actually contains the voxel you modified.* This happens when the voxel lies on the upper x,y or z face of a region. Assuming that you have some management code which can mark a region as needing re-extraction when a voxel changes, you should probably extend this to mark the regions of neighbouring voxels as invalid (this will have no effect when the voxel is well within a region, but will mark the neighbouring region as needing an update if the voxel lies on a region face).
|
||||
///
|
||||
/// Another scenario which sometimes results in confusion is when you wish to extract a region which corresponds to the whole volume, partcularly when solid voxels extend right to the edge of the volume.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VolumeType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> >
|
||||
Mesh<CubicVertex<typename VolumeType::VoxelType> > extractCubicMesh(VolumeType* volData, Region region, IsQuadNeeded isQuadNeeded = IsQuadNeeded(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true)
|
||||
{
|
||||
Mesh< CubicVertex<typename VolumeType::VoxelType> > result;
|
||||
extractCubicMeshCustom(volData, region, &result, isQuadNeeded, eWrapMode, tBorderValue, bMergeQuads);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/CubicSurfaceExtractor.inl"
|
||||
|
||||
#endif
|
@ -0,0 +1,310 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/Impl/Timer.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
// We try to avoid duplicate vertices by checking whether a vertex has already been added at a given position.
|
||||
// However, it is possible that vertices have the same position but different materials. In this case, the
|
||||
// vertices are not true duplicates and both must be added to the mesh. As far as I can tell, it is possible to have
|
||||
// at most eight vertices with the same position but different materials. For example, this worst-case scenario
|
||||
// happens when we have a 2x2x2 group of voxels, all with different materials and some/all partially transparent.
|
||||
// The vertex position at the center of this group is then going to be used by all eight voxels all with different
|
||||
// materials.
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
|
||||
const uint32_t CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::MaxVerticesPerPosition = 8;
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
|
||||
CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::CubicSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, IsQuadNeeded isQuadNeeded, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads)
|
||||
:m_volData(volData)
|
||||
,m_regSizeInVoxels(region)
|
||||
,m_meshCurrent(result)
|
||||
,m_previousSliceVertices(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2, m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2, MaxVerticesPerPosition)
|
||||
,m_currentSliceVertices(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2, m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2, MaxVerticesPerPosition)
|
||||
,m_bMergeQuads(bMergeQuads)
|
||||
,m_eWrapMode(eWrapMode)
|
||||
,m_tBorderValue(tBorderValue)
|
||||
{
|
||||
m_funcIsQuadNeededCallback = isQuadNeeded;
|
||||
|
||||
// This extractor has a limit as to how large the extracted region can be, because the vertex positions are encoded with a single byte per component.
|
||||
int32_t maxReionDimension = 256;
|
||||
POLYVOX_THROW_IF(region.getWidthInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions");
|
||||
POLYVOX_THROW_IF(region.getHeightInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions");
|
||||
POLYVOX_THROW_IF(region.getDepthInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions");
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
|
||||
void CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::execute()
|
||||
{
|
||||
Timer timer;
|
||||
m_meshCurrent->clear();
|
||||
|
||||
//uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2;
|
||||
//uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2;
|
||||
|
||||
//uint32_t arraySize[3]= {uArrayWidth, uArrayHeight, MaxVerticesPerPosition};
|
||||
//m_previousSliceVertices.resize(arraySize);
|
||||
//m_currentSliceVertices.resize(arraySize);
|
||||
memset(m_previousSliceVertices.getRawData(), 0xff, m_previousSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial));
|
||||
memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial));
|
||||
|
||||
m_vecQuads[NegativeX].resize(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2);
|
||||
m_vecQuads[PositiveX].resize(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2);
|
||||
|
||||
m_vecQuads[NegativeY].resize(m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2);
|
||||
m_vecQuads[PositiveY].resize(m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2);
|
||||
|
||||
m_vecQuads[NegativeZ].resize(m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2);
|
||||
m_vecQuads[PositiveZ].resize(m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2);
|
||||
|
||||
typename VolumeType::Sampler volumeSampler(m_volData);
|
||||
volumeSampler.setWrapMode(m_eWrapMode, m_tBorderValue);
|
||||
|
||||
for(int32_t z = m_regSizeInVoxels.getLowerZ(); z <= m_regSizeInVoxels.getUpperZ(); z++)
|
||||
{
|
||||
uint32_t regZ = z - m_regSizeInVoxels.getLowerZ();
|
||||
|
||||
for(int32_t y = m_regSizeInVoxels.getLowerY(); y <= m_regSizeInVoxels.getUpperY(); y++)
|
||||
{
|
||||
uint32_t regY = y - m_regSizeInVoxels.getLowerY();
|
||||
|
||||
volumeSampler.setPosition(m_regSizeInVoxels.getLowerX(),y,z);
|
||||
|
||||
for(int32_t x = m_regSizeInVoxels.getLowerX(); x <= m_regSizeInVoxels.getUpperX(); x++)
|
||||
{
|
||||
uint32_t regX = x - m_regSizeInVoxels.getLowerX();
|
||||
|
||||
typename VolumeType::VoxelType material; //Filled in by callback
|
||||
typename VolumeType::VoxelType currentVoxel = volumeSampler.getVoxel();
|
||||
typename VolumeType::VoxelType negXVoxel = volumeSampler.peekVoxel1nx0py0pz();
|
||||
typename VolumeType::VoxelType negYVoxel = volumeSampler.peekVoxel0px1ny0pz();
|
||||
typename VolumeType::VoxelType negZVoxel = volumeSampler.peekVoxel0px0py1nz();
|
||||
|
||||
// X
|
||||
if(m_funcIsQuadNeededCallback(currentVoxel, negXVoxel, material))
|
||||
{
|
||||
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
|
||||
uint32_t v1 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
|
||||
uint32_t v2 = addVertex(regX , regY + 1, regZ + 1, material, m_currentSliceVertices);
|
||||
uint32_t v3 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
|
||||
|
||||
m_vecQuads[NegativeX][regX].push_back(Quad(v0, v1, v2, v3));
|
||||
}
|
||||
|
||||
if(m_funcIsQuadNeededCallback(negXVoxel, currentVoxel, material))
|
||||
{
|
||||
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
|
||||
uint32_t v1 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
|
||||
uint32_t v2 = addVertex(regX , regY + 1, regZ + 1, material, m_currentSliceVertices);
|
||||
uint32_t v3 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
|
||||
|
||||
m_vecQuads[PositiveX][regX].push_back(Quad(v0, v3, v2, v1));
|
||||
}
|
||||
|
||||
// Y
|
||||
if(m_funcIsQuadNeededCallback(currentVoxel, negYVoxel, material))
|
||||
{
|
||||
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
|
||||
uint32_t v1 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
|
||||
uint32_t v2 = addVertex(regX + 1, regY , regZ + 1, material, m_currentSliceVertices);
|
||||
uint32_t v3 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
|
||||
|
||||
m_vecQuads[NegativeY][regY].push_back(Quad(v0, v1, v2, v3));
|
||||
}
|
||||
|
||||
if(m_funcIsQuadNeededCallback(negYVoxel, currentVoxel, material))
|
||||
{
|
||||
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
|
||||
uint32_t v1 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
|
||||
uint32_t v2 = addVertex(regX + 1, regY , regZ + 1, material, m_currentSliceVertices);
|
||||
uint32_t v3 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
|
||||
|
||||
m_vecQuads[PositiveY][regY].push_back(Quad(v0, v3, v2, v1));
|
||||
}
|
||||
|
||||
// Z
|
||||
if(m_funcIsQuadNeededCallback(currentVoxel, negZVoxel, material))
|
||||
{
|
||||
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
|
||||
uint32_t v1 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
|
||||
uint32_t v2 = addVertex(regX + 1, regY + 1, regZ , material, m_previousSliceVertices);
|
||||
uint32_t v3 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
|
||||
|
||||
m_vecQuads[NegativeZ][regZ].push_back(Quad(v0, v1, v2, v3));
|
||||
}
|
||||
|
||||
if(m_funcIsQuadNeededCallback(negZVoxel, currentVoxel, material))
|
||||
{
|
||||
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
|
||||
uint32_t v1 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
|
||||
uint32_t v2 = addVertex(regX + 1, regY + 1, regZ , material, m_previousSliceVertices);
|
||||
uint32_t v3 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
|
||||
|
||||
m_vecQuads[PositiveZ][regZ].push_back(Quad(v0, v3, v2, v1));
|
||||
}
|
||||
|
||||
volumeSampler.movePositiveX();
|
||||
}
|
||||
}
|
||||
|
||||
m_previousSliceVertices.swap(m_currentSliceVertices);
|
||||
memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial));
|
||||
}
|
||||
|
||||
for(uint32_t uFace = 0; uFace < NoOfFaces; uFace++)
|
||||
{
|
||||
std::vector< std::list<Quad> >& vecListQuads = m_vecQuads[uFace];
|
||||
|
||||
for(uint32_t slice = 0; slice < vecListQuads.size(); slice++)
|
||||
{
|
||||
std::list<Quad>& listQuads = vecListQuads[slice];
|
||||
|
||||
if(m_bMergeQuads)
|
||||
{
|
||||
//Repeatedly call this function until it returns
|
||||
//false to indicate nothing more can be done.
|
||||
while(performQuadMerging(listQuads)){}
|
||||
}
|
||||
|
||||
typename std::list<Quad>::iterator iterEnd = listQuads.end();
|
||||
for(typename std::list<Quad>::iterator quadIter = listQuads.begin(); quadIter != iterEnd; quadIter++)
|
||||
{
|
||||
Quad& quad = *quadIter;
|
||||
m_meshCurrent->addTriangle(quad.vertices[0], quad.vertices[1],quad.vertices[2]);
|
||||
m_meshCurrent->addTriangle(quad.vertices[0], quad.vertices[2],quad.vertices[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner());
|
||||
m_meshCurrent->removeUnusedVertices();
|
||||
|
||||
POLYVOX_LOG_TRACE("Cubic surface extraction took " << timer.elapsedTimeInMilliSeconds()
|
||||
<< "ms (Region size = " << m_regSizeInVoxels.getWidthInVoxels() << "x" << m_regSizeInVoxels.getHeightInVoxels()
|
||||
<< "x" << m_regSizeInVoxels.getDepthInVoxels() << ")");
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
|
||||
int32_t CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial>& existingVertices)
|
||||
{
|
||||
for(uint32_t ct = 0; ct < MaxVerticesPerPosition; ct++)
|
||||
{
|
||||
IndexAndMaterial& rEntry = existingVertices(uX, uY, ct);
|
||||
|
||||
if(rEntry.iIndex == -1)
|
||||
{
|
||||
//No vertices matched and we've now hit an empty space. Fill it by creating a vertex. The 0.5f offset is because vertices set between voxels in order to build cubes around them.
|
||||
CubicVertex<typename VolumeType::VoxelType> cubicVertex;
|
||||
cubicVertex.encodedPosition.setElements(static_cast<uint8_t>(uX), static_cast<uint8_t>(uY), static_cast<uint8_t>(uZ));
|
||||
cubicVertex.data = uMaterialIn;
|
||||
rEntry.iIndex = m_meshCurrent->addVertex(cubicVertex);
|
||||
rEntry.uMaterial = uMaterialIn;
|
||||
|
||||
return rEntry.iIndex;
|
||||
}
|
||||
|
||||
//If we have an existing vertex and the material matches then we can return it.
|
||||
if(rEntry.uMaterial == uMaterialIn)
|
||||
{
|
||||
return rEntry.iIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// If we exit the loop here then apparently all the slots were full but none of them matched.
|
||||
// This shouldn't ever happen, so if it does it is probably a bug in PolyVox. Please report it to us!
|
||||
POLYVOX_THROW(std::runtime_error, "All slots full but no matches during cubic surface extraction. This is probably a bug in PolyVox");
|
||||
return -1; //Should never happen.
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
|
||||
bool CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::performQuadMerging(std::list<Quad>& quads)
|
||||
{
|
||||
bool bDidMerge = false;
|
||||
for(typename std::list<Quad>::iterator outerIter = quads.begin(); outerIter != quads.end(); outerIter++)
|
||||
{
|
||||
typename std::list<Quad>::iterator innerIter = outerIter;
|
||||
innerIter++;
|
||||
while(innerIter != quads.end())
|
||||
{
|
||||
Quad& q1 = *outerIter;
|
||||
Quad& q2 = *innerIter;
|
||||
|
||||
bool result = mergeQuads(q1,q2);
|
||||
|
||||
if(result)
|
||||
{
|
||||
bDidMerge = true;
|
||||
innerIter = quads.erase(innerIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
innerIter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bDidMerge;
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
|
||||
bool CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::mergeQuads(Quad& q1, Quad& q2)
|
||||
{
|
||||
//All four vertices of a given quad have the same data,
|
||||
//so just check that the first pair of vertices match.
|
||||
if (m_meshCurrent->getVertices()[q1.vertices[0]].data == m_meshCurrent->getVertices()[q2.vertices[0]].data)
|
||||
{
|
||||
//Now check whether quad 2 is adjacent to quad one by comparing vertices.
|
||||
//Adjacent quads must share two vertices, and the second quad could be to the
|
||||
//top, bottom, left, of right of the first one. This gives four combinations to test.
|
||||
if((q1.vertices[0] == q2.vertices[1]) && ((q1.vertices[3] == q2.vertices[2])))
|
||||
{
|
||||
q1.vertices[0] = q2.vertices[0];
|
||||
q1.vertices[3] = q2.vertices[3];
|
||||
return true;
|
||||
}
|
||||
else if((q1.vertices[3] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[1])))
|
||||
{
|
||||
q1.vertices[3] = q2.vertices[3];
|
||||
q1.vertices[2] = q2.vertices[2];
|
||||
return true;
|
||||
}
|
||||
else if((q1.vertices[1] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[3])))
|
||||
{
|
||||
q1.vertices[1] = q2.vertices[1];
|
||||
q1.vertices[2] = q2.vertices[2];
|
||||
return true;
|
||||
}
|
||||
else if((q1.vertices[0] == q2.vertices[3]) && ((q1.vertices[1] == q2.vertices[2])))
|
||||
{
|
||||
q1.vertices[0] = q2.vertices[0];
|
||||
q1.vertices[1] = q2.vertices[1];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Quads cannot be merged.
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_DefaultIsQuadNeeded_H__
|
||||
#define __PolyVox_DefaultIsQuadNeeded_H__
|
||||
|
||||
#include "PolyVoxCore/Impl/TypeDef.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template<typename VoxelType>
|
||||
class DefaultIsQuadNeeded
|
||||
{
|
||||
public:
|
||||
bool operator()(VoxelType back, VoxelType front, VoxelType& materialToUse)
|
||||
{
|
||||
if((back > 0) && (front == 0))
|
||||
{
|
||||
materialToUse = static_cast<VoxelType>(back);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //__PolyVox_DefaultIsQuadNeeded_H__
|
@ -0,0 +1,153 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_MarchingCubesController_H__
|
||||
#define __PolyVox_MarchingCubesController_H__
|
||||
|
||||
#include "PolyVoxCore/BaseVolume.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
* This class provides a default implementation of a controller for the MarchingCubesSurfaceExtractor. It controls the behaviour of the
|
||||
* MarchingCubesSurfaceExtractor and provides the required properties from the underlying voxel type.
|
||||
*
|
||||
* PolyVox does not enforce any requirements regarding what data must be present in a voxel, and instead allows any primitive or user-defined
|
||||
* type to be used. However, the Marching Cubes algorithm does have some requirents about the underlying data in that conceptually it operates
|
||||
* on a <i>density field</i>. In addition, the PolyVox implementation of the Marching Cubes algorithm also understands the idea of each voxel
|
||||
* having a material which is copied into the vertex data.
|
||||
*
|
||||
* Because we want the MarchingCubesSurfaceExtractor to work on <i>any</i> voxel type, we use a <i>Marching Cubes controller</i> (passed as
|
||||
* a parameter of the MarchingCubesSurfaceExtractor) to expose the required properties. This parameter defaults to the DefaultMarchingCubesController.
|
||||
* The main implementation of this class is designed to work with primitives data types, and the class is also specialised for the Material,
|
||||
* Density and MaterialdensityPair classes.
|
||||
*
|
||||
* If you create a custom class for your voxel data then you probably want to include a specialisation of DefaultMarchingCubesController,
|
||||
* though you don't have to if you don't want to use the Marching Cubes algorithm or if you prefer to define a seperate Marching Cubes controller
|
||||
* and pass it as an explicit parameter (rather than relying on the default).
|
||||
*
|
||||
* For primitive types, the DefaultMarchingCubesController considers the value of the voxel to represent it's density and just returns a constant
|
||||
* for the material. So you can, for example, run the MarchingCubesSurfaceExtractor on a volume of floats or ints.
|
||||
*
|
||||
* It is possible to customise the behaviour of the controller by providing a threshold value through the constructor. The extracted surface
|
||||
* will pass through the density value specified by the threshold, and so you should make sure that the threshold value you choose is between
|
||||
* the minimum and maximum values found in your volume data. By default it is in the middle of the representable range of the underlying type.
|
||||
*
|
||||
* \sa MarchingCubesSurfaceExtractor
|
||||
*
|
||||
*/
|
||||
template<typename VoxelType>
|
||||
class DefaultMarchingCubesController
|
||||
{
|
||||
public:
|
||||
/// Used to inform the MarchingCubesSurfaceExtractor about which type it should use for representing densities.
|
||||
typedef VoxelType DensityType;
|
||||
/// Used to inform the MarchingCubesSurfaceExtractor about which type it should use for representing materials.
|
||||
typedef VoxelType MaterialType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* This version of the constructor takes no parameters and sets the threshold to the middle of the representable range of the underlying type.
|
||||
* For example, if the voxel type is 'uint8_t' then the representable range is 0-255, and the threshold will be set to 127. On the other hand,
|
||||
* if the voxel type is 'float' then the representable range is -FLT_MAX to FLT_MAX and the threshold will be set to zero.
|
||||
*/
|
||||
DefaultMarchingCubesController(void)
|
||||
{
|
||||
if (std::is_signed<DensityType>())
|
||||
{
|
||||
m_tThreshold = DensityType(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tThreshold = (((std::numeric_limits<DensityType>::min)() + (std::numeric_limits<DensityType>::max)()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the underlying voxel type into a density value.
|
||||
*
|
||||
* The default implementation of this function just returns the voxel type directly and is suitable for primitives types. Specialisations of
|
||||
* this class can modify this behaviour.
|
||||
*/
|
||||
DensityType convertToDensity(VoxelType voxel)
|
||||
{
|
||||
return voxel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the underlying voxel type into a material value.
|
||||
*
|
||||
* The default implementation of this function just returns the constant '1'. There's not much else it can do, as it needs to work with primitive
|
||||
* types and the actual value of the type is already being considered to be the density. Specialisations of this class can modify this behaviour.
|
||||
*/
|
||||
MaterialType convertToMaterial(VoxelType /*voxel*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a material which is in some sense a weighted combination of the supplied materials.
|
||||
*
|
||||
* The Marching Cubes algotithm generates vertices which lie between voxels, and ideally the material of the vertex should be interpolated from the materials
|
||||
* of the voxels. In practice, that material type is often an integer identifier (e.g. 1 = rock, 2 = soil, 3 = grass) and an interpolation doean't make sense
|
||||
* (e.g. soil is not a combination or rock and grass). Therefore this default interpolation just returns whichever material is associated with a voxel of the
|
||||
* higher density, but if more advanced voxel types do support interpolation then it can be implemented in this function.
|
||||
*/
|
||||
MaterialType blendMaterials(VoxelType a, VoxelType b, float /*weight*/)
|
||||
{
|
||||
if(convertToDensity(a) > convertToDensity(b))
|
||||
{
|
||||
return convertToMaterial(a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return convertToMaterial(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the density value which was passed to the constructor.
|
||||
*
|
||||
* As mentioned in the class description, the extracted surface will pass through the density value specified by the threshold, and so you
|
||||
* should make sure that the threshold value you choose is between the minimum and maximum values found in your volume data. By default it
|
||||
* is in the middle of the representable range of the underlying type.
|
||||
*/
|
||||
DensityType getThreshold(void)
|
||||
{
|
||||
return m_tThreshold;
|
||||
}
|
||||
|
||||
void setThreshold(DensityType tThreshold)
|
||||
{
|
||||
m_tThreshold = tThreshold;
|
||||
}
|
||||
|
||||
private:
|
||||
DensityType m_tThreshold;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
191
include/PolyVoxCore/include/PolyVoxCore/Density.h
Normal file
191
include/PolyVoxCore/include/PolyVoxCore/Density.h
Normal file
@ -0,0 +1,191 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Density_H__
|
||||
#define __PolyVox_Density_H__
|
||||
|
||||
#include "PolyVoxCore/DefaultMarchingCubesController.h" //We'll specialise the controller contained in here
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/// This class represents a voxel storing only a density.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Detailed description...
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Type>
|
||||
class Density
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
Density() : m_uDensity(0) {}
|
||||
|
||||
/// Copy constructor
|
||||
Density(Type uDensity) : m_uDensity(uDensity) {}
|
||||
|
||||
// The LowPassFilter uses this to convert between normal and accumulated types.
|
||||
/// Copy constructor with cast
|
||||
template <typename CastType> explicit Density(const Density<CastType>& density)
|
||||
{
|
||||
m_uDensity = static_cast<Type>(density.getDensity());
|
||||
}
|
||||
|
||||
bool operator==(const Density& rhs) const
|
||||
{
|
||||
return (m_uDensity == rhs.m_uDensity);
|
||||
};
|
||||
|
||||
bool operator!=(const Density& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
// For densities we can supply mathematical operators which behave in an intuitive way.
|
||||
// In particular the ability to add and subtract densities is important in order to
|
||||
// apply an averaging filter. The ability to divide by an integer is also needed for
|
||||
// this same purpose.
|
||||
Density<Type>& operator+=(const Density<Type>& rhs)
|
||||
{
|
||||
m_uDensity += rhs.m_uDensity;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Density<Type>& operator-=(const Density<Type>& rhs)
|
||||
{
|
||||
m_uDensity -= rhs.m_uDensity;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Density<Type>& operator/=(uint32_t rhs)
|
||||
{
|
||||
m_uDensity /= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \return The current density of the voxel
|
||||
Type getDensity() const { return m_uDensity; }
|
||||
/**
|
||||
* Set the density of the voxel
|
||||
*
|
||||
* \param uDensity The density to set to
|
||||
*/
|
||||
void setDensity(Type uDensity) { m_uDensity = uDensity; }
|
||||
|
||||
/// \return The maximum allowed density of the voxel
|
||||
static Type getMaxDensity() { return (std::numeric_limits<Type>::max)(); }
|
||||
/// \return The minimum allowed density of the voxel
|
||||
static Type getMinDensity() { return (std::numeric_limits<Type>::min)(); }
|
||||
|
||||
private:
|
||||
Type m_uDensity;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
Density<Type> operator+(const Density<Type>& lhs, const Density<Type>& rhs)
|
||||
{
|
||||
Density<Type> result = lhs;
|
||||
result += rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Density<Type> operator-(const Density<Type>& lhs, const Density<Type>& rhs)
|
||||
{
|
||||
Density<Type> result = lhs;
|
||||
result -= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Density<Type> operator/(const Density<Type>& lhs, uint32_t rhs)
|
||||
{
|
||||
Density<Type> result = lhs;
|
||||
result /= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
// These are the predefined density types. The 8-bit types are sufficient for many purposes (including
|
||||
// most games) but 16-bit and float types do have uses particularly in medical/scientific visualisation.
|
||||
typedef Density<uint8_t> Density8;
|
||||
typedef Density<uint16_t> Density16;
|
||||
typedef Density<uint32_t> Density32;
|
||||
typedef Density<float> DensityFloat;
|
||||
|
||||
/**
|
||||
* This is a specialisation of DefaultMarchingCubesController for the Density voxel type
|
||||
*/
|
||||
template <typename Type>
|
||||
class DefaultMarchingCubesController< Density<Type> >
|
||||
{
|
||||
public:
|
||||
typedef Type DensityType;
|
||||
typedef float MaterialType;
|
||||
|
||||
DefaultMarchingCubesController(void)
|
||||
{
|
||||
// Default to a threshold value halfway between the min and max possible values.
|
||||
m_tThreshold = (Density<Type>::getMinDensity() + Density<Type>::getMaxDensity()) / 2;
|
||||
}
|
||||
|
||||
DefaultMarchingCubesController(DensityType tThreshold)
|
||||
{
|
||||
m_tThreshold = tThreshold;
|
||||
}
|
||||
|
||||
DensityType convertToDensity(Density<Type> voxel)
|
||||
{
|
||||
return voxel.getDensity();
|
||||
}
|
||||
|
||||
MaterialType convertToMaterial(Density<Type> /*voxel*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
MaterialType blendMaterials(Density<Type> /*a*/, Density<Type> /*b*/, float /*weight*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
DensityType getThreshold(void)
|
||||
{
|
||||
return m_tThreshold;
|
||||
}
|
||||
|
||||
void setThreshold(DensityType tThreshold)
|
||||
{
|
||||
m_tThreshold = tThreshold;
|
||||
}
|
||||
|
||||
private:
|
||||
DensityType m_tThreshold;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //__PolyVox_Density_H__
|
167
include/PolyVoxCore/include/PolyVoxCore/FilePager.h
Normal file
167
include/PolyVoxCore/include/PolyVoxCore/FilePager.h
Normal file
@ -0,0 +1,167 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_FilePager_H__
|
||||
#define __PolyVox_FilePager_H__
|
||||
|
||||
#include "PolyVoxCore/Impl/TypeDef.h"
|
||||
|
||||
#include "PolyVoxCore/PagedVolume.h"
|
||||
#include "PolyVoxCore/Region.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
* Provides an interface for performing paging of data.
|
||||
*/
|
||||
template <typename VoxelType>
|
||||
class FilePager : public PagedVolume<VoxelType>::Pager
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
FilePager(const std::string& strFolderName = ".")
|
||||
:PagedVolume<VoxelType>::Pager()
|
||||
,m_strFolderName(strFolderName)
|
||||
{
|
||||
// Add the trailing slash, assuming the user dind't already do it.
|
||||
if ((m_strFolderName.back() != '/') && (m_strFolderName.back() != '\\'))
|
||||
{
|
||||
m_strFolderName.append("/");
|
||||
}
|
||||
|
||||
// Build a unique prefix to avoid multiple pagers using the same filenames.
|
||||
srand(static_cast<unsigned int>(time(0)));
|
||||
int iRandomValue = rand();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::hex << iRandomValue;
|
||||
m_strRandomPrefix = ss.str();
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
virtual ~FilePager()
|
||||
{
|
||||
for(std::vector<std::string>::iterator iter = m_vecCreatedFiles.begin(); iter < m_vecCreatedFiles.end(); iter++)
|
||||
{
|
||||
POLYVOX_LOG_WARNING_IF(std::remove(iter->c_str()) != 0, "Failed to delete '" << *iter << "' when destroying FilePager");
|
||||
}
|
||||
|
||||
m_vecCreatedFiles.clear();
|
||||
}
|
||||
|
||||
virtual void pageIn(const Region& region, typename PagedVolume<VoxelType>::Chunk* pChunk)
|
||||
{
|
||||
POLYVOX_ASSERT(pChunk, "Attempting to page in NULL chunk");
|
||||
POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data");
|
||||
|
||||
std::stringstream ssFilename;
|
||||
ssFilename << m_strFolderName << "/" << m_strRandomPrefix << "-"
|
||||
<< region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_"
|
||||
<< region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ();
|
||||
|
||||
std::string filename = ssFilename.str();
|
||||
|
||||
// FIXME - This should be replaced by C++ style IO, but currently this causes problems with
|
||||
// the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919
|
||||
|
||||
FILE* pFile = fopen(filename.c_str(), "rb");
|
||||
if(pFile)
|
||||
{
|
||||
POLYVOX_LOG_TRACE("Paging in data for " << region);
|
||||
|
||||
/*fseek(pFile, 0L, SEEK_END);
|
||||
size_t fileSizeInBytes = ftell(pFile);
|
||||
fseek(pFile, 0L, SEEK_SET);
|
||||
|
||||
uint8_t* buffer = new uint8_t[fileSizeInBytes];
|
||||
fread(buffer, sizeof(uint8_t), fileSizeInBytes, pFile);
|
||||
pChunk->setData(buffer, fileSizeInBytes);
|
||||
delete[] buffer;*/
|
||||
|
||||
fread(pChunk->getData(), sizeof(uint8_t), pChunk->getDataSizeInBytes(), pFile);
|
||||
|
||||
if(ferror(pFile))
|
||||
{
|
||||
POLYVOX_THROW(std::runtime_error, "Error reading in chunk data, even though a file exists.");
|
||||
}
|
||||
|
||||
fclose(pFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
POLYVOX_LOG_TRACE("No data found for " << region << " during paging in.");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void pageOut(const Region& region, typename PagedVolume<VoxelType>::Chunk* pChunk)
|
||||
{
|
||||
POLYVOX_ASSERT(pChunk, "Attempting to page out NULL chunk");
|
||||
POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data");
|
||||
|
||||
POLYVOX_LOG_TRACE("Paging out data for " << region);
|
||||
|
||||
std::stringstream ssFilename;
|
||||
ssFilename << m_strFolderName << "/" << m_strRandomPrefix << "-"
|
||||
<< region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_"
|
||||
<< region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ();
|
||||
|
||||
std::string filename = ssFilename.str();
|
||||
|
||||
// FIXME - This should be replaced by C++ style IO, but currently this causes problems with
|
||||
// the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919
|
||||
|
||||
FILE* pFile = fopen(filename.c_str(), "wb");
|
||||
if(!pFile)
|
||||
{
|
||||
POLYVOX_THROW(std::runtime_error, "Unable to open file to write out chunk data.");
|
||||
}
|
||||
|
||||
//The file has been created, so add it to the list to delete on shutdown.
|
||||
m_vecCreatedFiles.push_back(filename);
|
||||
|
||||
fwrite(pChunk->getData(), sizeof(uint8_t), pChunk->getDataSizeInBytes(), pFile);
|
||||
|
||||
if(ferror(pFile))
|
||||
{
|
||||
POLYVOX_THROW(std::runtime_error, "Error writing out chunk data.");
|
||||
}
|
||||
|
||||
fclose(pFile);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string m_strFolderName;
|
||||
std::string m_strRandomPrefix;
|
||||
|
||||
std::vector<std::string> m_vecCreatedFiles;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //__PolyVox_FilePager_H__
|
64
include/PolyVoxCore/include/PolyVoxCore/GradientEstimators.h
Normal file
64
include/PolyVoxCore/include/PolyVoxCore/GradientEstimators.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_GradientEstimators_H__
|
||||
#define __PolyVox_GradientEstimators_H__
|
||||
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
#include "PolyVoxCore/VoxelFilters.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
enum NormalGenerationMethod
|
||||
{
|
||||
SIMPLE, ///<Fastest
|
||||
CENTRAL_DIFFERENCE,
|
||||
SOBEL,
|
||||
CENTRAL_DIFFERENCE_SMOOTHED,
|
||||
SOBEL_SMOOTHED ///<Smoothest
|
||||
};
|
||||
|
||||
template<typename VolumeType>
|
||||
Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter);
|
||||
|
||||
template<typename VolumeType>
|
||||
Vector3DFloat computeSmoothCentralDifferenceGradient(typename VolumeType::Sampler& volIter);
|
||||
|
||||
template<typename VolumeType>
|
||||
Vector3DFloat computeDecimatedCentralDifferenceGradient(typename VolumeType::Sampler& volIter);
|
||||
|
||||
template<typename VolumeType>
|
||||
Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter);
|
||||
|
||||
template<typename VolumeType>
|
||||
Vector3DFloat computeSmoothSobelGradient(typename VolumeType::Sampler& volIter);
|
||||
|
||||
//POLYVOX_API void computeNormalsForVertices(VolumeType<uint8_t>* volumeData, Mesh<PositionMaterialNormal>& mesh, NormalGenerationMethod normalGenerationMethod);
|
||||
//POLYVOX_API Vector3DFloat computeNormal(VolumeType<uint8_t>* volumeData, const Vector3DFloat& v3dPos, NormalGenerationMethod normalGenerationMethod);
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/GradientEstimators.inl"
|
||||
|
||||
#endif //__PolyVox_GradientEstimators_H__
|
302
include/PolyVoxCore/include/PolyVoxCore/GradientEstimators.inl
Normal file
302
include/PolyVoxCore/include/PolyVoxCore/GradientEstimators.inl
Normal file
@ -0,0 +1,302 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template<typename VolumeType>
|
||||
Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
|
||||
{
|
||||
//FIXME - bitwise way of doing this?
|
||||
typename VolumeType::VoxelType voxel1nx = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0;
|
||||
typename VolumeType::VoxelType voxel1px = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0;
|
||||
|
||||
typename VolumeType::VoxelType voxel1ny = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0;
|
||||
typename VolumeType::VoxelType voxel1py = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0;
|
||||
|
||||
typename VolumeType::VoxelType voxel1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0;
|
||||
typename VolumeType::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 VolumeType>
|
||||
Vector3DFloat computeDecimatedCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
|
||||
{
|
||||
const int32_t x = volIter.getPosition().getX();
|
||||
const int32_t y = volIter.getPosition().getY();
|
||||
const int32_t z = volIter.getPosition().getZ();
|
||||
|
||||
//FIXME - bitwise way of doing this?
|
||||
typename VolumeType::VoxelType voxel1nx = volIter.getVoxel(x-2, y ,z ) > 0 ? 1: 0;
|
||||
typename VolumeType::VoxelType voxel1px = volIter.getVoxel(x-2, y ,z ) > 0 ? 1: 0;
|
||||
|
||||
typename VolumeType::VoxelType voxel1ny = volIter.getVoxel(x , y-2,z ) > 0 ? 1: 0;
|
||||
typename VolumeType::VoxelType voxel1py = volIter.getVoxel(x , y-2,z ) > 0 ? 1: 0;
|
||||
|
||||
typename VolumeType::VoxelType voxel1nz = volIter.getVoxel(x , y ,z-2) > 0 ? 1: 0;
|
||||
typename VolumeType::VoxelType voxel1pz = volIter.getVoxel(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 VolumeType>
|
||||
Vector3DFloat computeSmoothCentralDifferenceGradient(typename VolumeType::Sampler& volIter)
|
||||
{
|
||||
int32_t initialX = volIter.getPosition().getX();
|
||||
int32_t initialY = volIter.getPosition().getY();
|
||||
int32_t initialZ = volIter.getPosition().getZ();
|
||||
|
||||
//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 VolumeType>
|
||||
Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& 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 typename VolumeType::VoxelType pVoxel1nx1ny1nz = volIter.peekVoxel1nx1ny1nz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1nx1ny0pz = volIter.peekVoxel1nx1ny0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1nx1ny1pz = volIter.peekVoxel1nx1ny1pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1nx0py1nz = volIter.peekVoxel1nx0py1nz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1nx0py0pz = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1nx0py1pz = volIter.peekVoxel1nx0py1pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1nx1py1nz = volIter.peekVoxel1nx1py1nz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1nx1py0pz = volIter.peekVoxel1nx1py0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1nx1py1pz = volIter.peekVoxel1nx1py1pz() > 0 ? 1: 0;
|
||||
|
||||
const typename VolumeType::VoxelType pVoxel0px1ny1nz = volIter.peekVoxel0px1ny1nz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel0px1ny0pz = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel0px1ny1pz = volIter.peekVoxel0px1ny1pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel0px0py1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0;
|
||||
//const VolumeType::VoxelType pVoxel0px0py0pz = volIter.peekVoxel0px0py0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel0px0py1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel0px1py1nz = volIter.peekVoxel0px1py1nz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel0px1py0pz = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel0px1py1pz = volIter.peekVoxel0px1py1pz() > 0 ? 1: 0;
|
||||
|
||||
const typename VolumeType::VoxelType pVoxel1px1ny1nz = volIter.peekVoxel1px1ny1nz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1px1ny0pz = volIter.peekVoxel1px1ny0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1px1ny1pz = volIter.peekVoxel1px1ny1pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1px0py1nz = volIter.peekVoxel1px0py1nz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1px0py0pz = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1px0py1pz = volIter.peekVoxel1px0py1pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1px1py1nz = volIter.peekVoxel1px1py1nz() > 0 ? 1: 0;
|
||||
const typename VolumeType::VoxelType pVoxel1px1py0pz = volIter.peekVoxel1px1py0pz() > 0 ? 1: 0;
|
||||
const typename VolumeType::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));
|
||||
}
|
||||
|
||||
template<typename VolumeType>
|
||||
Vector3DFloat computeSmoothSobelGradient(typename VolumeType::Sampler& 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} } };
|
||||
|
||||
int32_t initialX = volIter.getPosition().getX();
|
||||
int32_t initialY = volIter.getPosition().getY();
|
||||
int32_t initialZ = volIter.getPosition().getZ();
|
||||
|
||||
volIter.setPosition(initialX-1, initialY-1, initialZ-1); const float pVoxel1nx1ny1nz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX-1, initialY-1, initialZ ); const float pVoxel1nx1ny0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX-1, initialY-1, initialZ+1); const float pVoxel1nx1ny1pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX-1, initialY , initialZ-1); const float pVoxel1nx0py1nz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX-1, initialY , initialZ ); const float pVoxel1nx0py0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX-1, initialY , initialZ+1); const float pVoxel1nx0py1pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX-1, initialY+1, initialZ-1); const float pVoxel1nx1py1nz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX-1, initialY+1, initialZ ); const float pVoxel1nx1py0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX-1, initialY+1, initialZ+1); const float pVoxel1nx1py1pz = computeSmoothedVoxel(volIter);
|
||||
|
||||
volIter.setPosition(initialX , initialY-1, initialZ-1); const float pVoxel0px1ny1nz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX , initialY-1, initialZ ); const float pVoxel0px1ny0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX , initialY-1, initialZ+1); const float pVoxel0px1ny1pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX , initialY , initialZ-1); const float pVoxel0px0py1nz = computeSmoothedVoxel(volIter);
|
||||
//volIter.setPosition(initialX , initialY , initialZ ); const float pVoxel0px0py0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX , initialY , initialZ+1); const float pVoxel0px0py1pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX , initialY+1, initialZ-1); const float pVoxel0px1py1nz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX , initialY+1, initialZ ); const float pVoxel0px1py0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX , initialY+1, initialZ+1); const float pVoxel0px1py1pz = computeSmoothedVoxel(volIter);
|
||||
|
||||
volIter.setPosition(initialX+1, initialY-1, initialZ-1); const float pVoxel1px1ny1nz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX+1, initialY-1, initialZ ); const float pVoxel1px1ny0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX+1, initialY-1, initialZ+1); const float pVoxel1px1ny1pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX+1, initialY , initialZ-1); const float pVoxel1px0py1nz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX+1, initialY , initialZ ); const float pVoxel1px0py0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX+1, initialY , initialZ+1); const float pVoxel1px0py1pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX+1, initialY+1, initialZ-1); const float pVoxel1px1py1nz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX+1, initialY+1, initialZ ); const float pVoxel1px1py0pz = computeSmoothedVoxel(volIter);
|
||||
volIter.setPosition(initialX+1, initialY+1, initialZ+1); const float pVoxel1px1py1pz = computeSmoothedVoxel(volIter);
|
||||
|
||||
/*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 float 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 float 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 float 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(-xGrad,-yGrad,-zGrad);
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_AStarPathfinderImpl_H__
|
||||
#define __PolyVox_AStarPathfinderImpl_H__
|
||||
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits> //For numeric_limits
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
class OpenNodesContainer;
|
||||
class ClosedNodesContainer;
|
||||
class ThermiteGameLogic;
|
||||
|
||||
/// The Connectivity of a voxel determines how many neighbours it has.
|
||||
enum Connectivity
|
||||
{
|
||||
/// Each voxel has six neighbours, which are those sharing a face.
|
||||
SixConnected,
|
||||
/// Each voxel has 18 neighbours, which are those sharing a face or an edge.
|
||||
EighteenConnected,
|
||||
/// Each voxel has 26 neighbours, which are those sharing a face, edge, or corner.
|
||||
TwentySixConnected
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
Node(int x, int y, int z)
|
||||
:gVal(std::numeric_limits<float>::quiet_NaN()) //Initilise with NaNs so that we will
|
||||
,hVal(std::numeric_limits<float>::quiet_NaN()) //know if we forget to set these properly.
|
||||
,parent(0)
|
||||
{
|
||||
position.setX(x);
|
||||
position.setY(y);
|
||||
position.setZ(z);
|
||||
}
|
||||
|
||||
bool operator==(const Node& rhs) const
|
||||
{
|
||||
return position == rhs.position;
|
||||
}
|
||||
|
||||
bool operator<(const Node& rhs) const
|
||||
{
|
||||
if (position.getX() < rhs.position.getX())
|
||||
return true;
|
||||
if (rhs.position.getX() < position.getX())
|
||||
return false;
|
||||
|
||||
if (position.getY() < rhs.position.getY())
|
||||
return true;
|
||||
if (rhs.position.getY() < position.getY())
|
||||
return false;
|
||||
|
||||
if (position.getZ() < rhs.position.getZ())
|
||||
return true;
|
||||
if (rhs.position.getZ() < position.getZ())
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PolyVox::Vector3DInt32 position;
|
||||
float gVal;
|
||||
float hVal;
|
||||
Node* parent;
|
||||
|
||||
float f(void) const
|
||||
{
|
||||
return gVal + hVal;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::set<Node> AllNodesContainer;
|
||||
|
||||
class AllNodesContainerIteratorComparator
|
||||
{
|
||||
public:
|
||||
bool operator() (const AllNodesContainer::iterator& lhs, const AllNodesContainer::iterator& rhs) const
|
||||
{
|
||||
return (&(*lhs)) < (&(*rhs));
|
||||
}
|
||||
};
|
||||
|
||||
class NodeSort
|
||||
{
|
||||
public:
|
||||
bool operator() (const AllNodesContainer::iterator& lhs, const AllNodesContainer::iterator& rhs) const
|
||||
{
|
||||
return lhs->f() > rhs->f();
|
||||
}
|
||||
};
|
||||
|
||||
class OpenNodesContainer
|
||||
{
|
||||
public:
|
||||
typedef std::vector<AllNodesContainer::iterator>::iterator iterator;
|
||||
|
||||
public:
|
||||
void clear(void)
|
||||
{
|
||||
open.clear();
|
||||
}
|
||||
|
||||
bool empty(void) const
|
||||
{
|
||||
return open.empty();
|
||||
}
|
||||
|
||||
void insert(AllNodesContainer::iterator node)
|
||||
{
|
||||
open.push_back(node);
|
||||
push_heap(open.begin(), open.end(), NodeSort());
|
||||
}
|
||||
|
||||
AllNodesContainer::iterator getFirst(void)
|
||||
{
|
||||
return open[0];
|
||||
}
|
||||
|
||||
void removeFirst(void)
|
||||
{
|
||||
pop_heap(open.begin(), open.end(), NodeSort());
|
||||
open.pop_back();
|
||||
}
|
||||
|
||||
void remove(iterator iterToRemove)
|
||||
{
|
||||
open.erase(iterToRemove);
|
||||
make_heap(open.begin(), open.end(), NodeSort());
|
||||
}
|
||||
|
||||
iterator begin(void)
|
||||
{
|
||||
return open.begin();
|
||||
}
|
||||
|
||||
iterator end(void)
|
||||
{
|
||||
return open.end();
|
||||
}
|
||||
|
||||
iterator find(AllNodesContainer::iterator node)
|
||||
{
|
||||
std::vector<AllNodesContainer::iterator>::iterator openIter = std::find(open.begin(), open.end(), node);
|
||||
return openIter;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<AllNodesContainer::iterator> open;
|
||||
};
|
||||
|
||||
class ClosedNodesContainer
|
||||
{
|
||||
public:
|
||||
typedef std::set<AllNodesContainer::iterator, AllNodesContainerIteratorComparator>::iterator iterator;
|
||||
|
||||
public:
|
||||
void clear(void)
|
||||
{
|
||||
closed.clear();
|
||||
}
|
||||
|
||||
void insert(AllNodesContainer::iterator node)
|
||||
{
|
||||
closed.insert(node);
|
||||
}
|
||||
|
||||
void remove(iterator iterToRemove)
|
||||
{
|
||||
closed.erase(iterToRemove);
|
||||
}
|
||||
|
||||
iterator begin(void)
|
||||
{
|
||||
return closed.begin();
|
||||
}
|
||||
|
||||
iterator end(void)
|
||||
{
|
||||
return closed.end();
|
||||
}
|
||||
|
||||
iterator find(AllNodesContainer::iterator node)
|
||||
{
|
||||
iterator iter = std::find(closed.begin(), closed.end(), node);
|
||||
return iter;
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<AllNodesContainer::iterator, AllNodesContainerIteratorComparator> closed;
|
||||
};
|
||||
|
||||
|
||||
//bool operator<(const AllNodesContainer::iterator& lhs, const AllNodesContainer::iterator& rhs);
|
||||
}
|
||||
|
||||
#endif //__PolyVox_AStarPathfinderImpl_H__
|
37
include/PolyVoxCore/include/PolyVoxCore/Impl/Config.h
Normal file
37
include/PolyVoxCore/include/PolyVoxCore/Impl/Config.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Config_H__
|
||||
#define __PolyVox_Config_H__
|
||||
|
||||
//#define POLYVOX_LOG_TRACE_ENABLED
|
||||
#define POLYVOX_LOG_DEBUG_ENABLED
|
||||
#define POLYVOX_LOG_INFO_ENABLED
|
||||
#define POLYVOX_LOG_WARNING_ENABLED
|
||||
#define POLYVOX_LOG_ERROR_ENABLED
|
||||
#define POLYVOX_LOG_FATAL_ENABLED
|
||||
|
||||
#define POLYVOX_ASSERTS_ENABLED
|
||||
#define POLYVOX_THROW_ENABLED
|
||||
|
||||
#endif
|
268
include/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h
Normal file
268
include/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h
Normal file
@ -0,0 +1,268 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_ErrorHandling_H__
|
||||
#define __PolyVox_ErrorHandling_H__
|
||||
|
||||
#include "PolyVoxCore/Impl/Config.h"
|
||||
|
||||
#include "PolyVoxCore/Impl/Logging.h"
|
||||
|
||||
#include <cstdlib> // For std::exit
|
||||
#include <iostream> // For std::cerr
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <string.h> // Exception constuctors take strings.
|
||||
#include <csignal>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// In Visual Studio we can use this function to go into the debugger.
|
||||
#define POLYVOX_HALT() __debugbreak()
|
||||
#else
|
||||
// On other platforms we just halt by forcing a crash.
|
||||
// Hopefully this puts us in the debugger if one is running
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#define POLYVOX_HALT() raise(SIGTRAP)
|
||||
#else
|
||||
#define POLYVOX_HALT() *((unsigned int*)0) = 0xDEAD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Macros cannot contain #ifdefs, but some of our macros need to disable warnings and such warning supression is
|
||||
// platform specific. But macros can contain other macros, so we create macros to control the warnings and use
|
||||
// those instead. This set of warning supression macros can be extended to GCC/Clang when required.
|
||||
#if defined(_MSC_VER)
|
||||
#define POLYVOX_MSC_WARNING_PUSH __pragma(warning(push))
|
||||
#define POLYVOX_DISABLE_MSC_WARNING(x) __pragma(warning(disable:x))
|
||||
#define POLYVOX_MSC_WARNING_POP __pragma(warning(pop))
|
||||
#else
|
||||
#define POLYVOX_MSC_WARNING_PUSH
|
||||
#define POLYVOX_DISABLE_MSC_WARNING(x)
|
||||
#define POLYVOX_MSC_WARNING_POP
|
||||
#endif
|
||||
|
||||
#define POLYVOX_UNUSED(x) do { (void)sizeof(x); } while(0)
|
||||
|
||||
/*
|
||||
* Assertions
|
||||
* ----------
|
||||
* The code below implements a custom assert function called POLYVOX_ASSERT which has a number of advantages compared
|
||||
* to the standard C/C++ assert(). It is inspired by http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
|
||||
* which provides code under the MIT license.
|
||||
*/
|
||||
|
||||
#ifdef POLYVOX_ASSERTS_ENABLED
|
||||
|
||||
#define POLYVOX_ASSERT(condition, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if (!(condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << "\n"; \
|
||||
ss << " PolyVox Assertion Failed!"; \
|
||||
ss << " ========================="; \
|
||||
ss << " Condition: " << #condition; \
|
||||
ss << " Message: " << (message); \
|
||||
ss << " Location: " << "Line " << __LINE__ << " of " << __FILE__; \
|
||||
ss << "\n"; \
|
||||
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
|
||||
POLYVOX_HALT(); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#else
|
||||
|
||||
#define POLYVOX_ASSERT(condition, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do { POLYVOX_UNUSED(condition); POLYVOX_UNUSED(message); } while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Exceptions
|
||||
* ----------
|
||||
* ...
|
||||
*/
|
||||
#ifdef POLYVOX_THROW_ENABLED
|
||||
|
||||
#define POLYVOX_THROW_IF(condition, type, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if ((condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
|
||||
throw type(ss.str()); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#define POLYVOX_THROW(type, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
|
||||
throw type(ss.str()); \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#else
|
||||
namespace PolyVox
|
||||
{
|
||||
typedef void (*ThrowHandler)(std::exception& e, const char* file, int line);
|
||||
|
||||
inline void defaultThrowHandler(std::exception& e, const char* file, int line)
|
||||
{
|
||||
std::stringstream ss; \
|
||||
ss << "\n"; \
|
||||
ss << " PolyVox exception thrown!"; \
|
||||
ss << " ========================="; \
|
||||
ss << " PolyVox has tried to throw an exception but it was built without support"; \
|
||||
ss << " for exceptions. In this scenario PolyVox will call a 'throw handler'"; \
|
||||
ss << " and this message is being printed by the default throw handler."; \
|
||||
ss << "\n"; \
|
||||
ss << " If you don't want to enable exceptions then you should try to determine why"; \
|
||||
ss << " this exception was thrown and make sure it doesn't happen again. If it was"; \
|
||||
ss << " due to something like an invalid argument to a function then you should be"; \
|
||||
ss << " able to fix it quite easily by validating parameters as appropriate. More"; \
|
||||
ss << " complex exception scenarios (out of memory, etc) might be harder to fix and"; \
|
||||
ss << " you should replace this default handler with something which is more"; \
|
||||
ss << " meaningful to your users."; \
|
||||
ss << "\n"; \
|
||||
ss << " Exception details"; \
|
||||
ss << " -----------------"; \
|
||||
ss << " Line: " << line; \
|
||||
ss << " File: " << file; \
|
||||
ss << " Message: " << e.what(); \
|
||||
ss << "\n"; \
|
||||
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
|
||||
POLYVOX_HALT(); \
|
||||
}
|
||||
|
||||
inline ThrowHandler& getThrowHandlerInstance()
|
||||
{
|
||||
static ThrowHandler s_fThrowHandler = &defaultThrowHandler;
|
||||
return s_fThrowHandler;
|
||||
}
|
||||
|
||||
inline ThrowHandler getThrowHandler()
|
||||
{
|
||||
return getThrowHandlerInstance();
|
||||
}
|
||||
|
||||
inline void setThrowHandler(ThrowHandler fNewHandler)
|
||||
{
|
||||
getThrowHandlerInstance() = fNewHandler;
|
||||
}
|
||||
}
|
||||
|
||||
#define POLYVOX_THROW_IF(condition, type, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if ((condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
|
||||
type except = (type)(ss.str()); \
|
||||
getThrowHandler()((except), __FILE__, __LINE__); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#define POLYVOX_THROW(type, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
|
||||
type except = (type)(ss.str()); \
|
||||
getThrowHandler()((except), __FILE__, __LINE__); \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#endif
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/// A general purpose exception to indicate that an operation cannot be peformed.
|
||||
class invalid_operation : public std::logic_error
|
||||
{
|
||||
public:
|
||||
explicit invalid_operation(const std::string& message)
|
||||
: logic_error(message.c_str()) {}
|
||||
|
||||
explicit invalid_operation(const char *message)
|
||||
: logic_error(message) {}
|
||||
};
|
||||
|
||||
/// Thrown to indicate that a function is deliberatly not implmented. For example, perhaps you called a function
|
||||
/// in a base class whereas you are supposed to use a derived class which implements the function, or perhaps the
|
||||
/// function is not defined for a particular template parameter. It may be that the function is required to
|
||||
/// compile sucessfully but it should not be called.
|
||||
class not_implemented : public std::logic_error
|
||||
{
|
||||
public:
|
||||
explicit not_implemented(const std::string& message)
|
||||
: logic_error(message.c_str()) {}
|
||||
|
||||
explicit not_implemented(const char *message)
|
||||
: logic_error(message) {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //__PolyVox_ErrorHandling_H__
|
350
include/PolyVoxCore/include/PolyVoxCore/Impl/Logging.h
Normal file
350
include/PolyVoxCore/include/PolyVoxCore/Impl/Logging.h
Normal file
@ -0,0 +1,350 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams and Matthew Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Logging_H__
|
||||
#define __PolyVox_Logging_H__
|
||||
|
||||
#include "PolyVoxCore/Impl/Config.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
/*
|
||||
* Logging
|
||||
* --------
|
||||
* PolyVox provides basic logging facilities which can be redirected by your application.
|
||||
*/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
// Passing zero to the null stream constructor guarentees it will discard all input. See
|
||||
// here http://stackoverflow.com/a/8244052 and here http://stackoverflow.com/a/6240980
|
||||
Logger() {};
|
||||
virtual ~Logger() {};
|
||||
|
||||
virtual void logTraceMessage(const std::string& message) = 0;
|
||||
virtual void logDebugMessage(const std::string& message) = 0;
|
||||
virtual void logInfoMessage(const std::string& message) = 0;
|
||||
virtual void logWarningMessage(const std::string& message) = 0;
|
||||
virtual void logErrorMessage(const std::string& message) = 0;
|
||||
virtual void logFatalMessage(const std::string& message) = 0;
|
||||
};
|
||||
|
||||
class DefaultLogger : public Logger
|
||||
{
|
||||
public:
|
||||
DefaultLogger() : Logger() {}
|
||||
virtual ~DefaultLogger() {}
|
||||
|
||||
// Appending the 'std::endl' forces the stream to be flushed.
|
||||
void logTraceMessage(const std::string& /*message*/) { }
|
||||
void logDebugMessage(const std::string& /*message*/) { }
|
||||
void logInfoMessage(const std::string& message) { std::cout << message << std::endl; }
|
||||
void logWarningMessage(const std::string& message) { std::cerr << message << std::endl; }
|
||||
void logErrorMessage(const std::string& message) { std::cerr << message << std::endl; }
|
||||
void logFatalMessage(const std::string& message) { std::cerr << message << std::endl; }
|
||||
};
|
||||
|
||||
namespace Impl
|
||||
{
|
||||
inline Logger*& getLoggerInstance()
|
||||
{
|
||||
static Logger* s_pLogger = new DefaultLogger;
|
||||
return s_pLogger;
|
||||
}
|
||||
}
|
||||
|
||||
inline void setLogger(Logger* pLogger)
|
||||
{
|
||||
Impl::getLoggerInstance() = pLogger;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef POLYVOX_LOG_TRACE_ENABLED
|
||||
|
||||
#define POLYVOX_LOG_TRACE(message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logTraceMessage(ss.str()); \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#define POLYVOX_LOG_TRACE_IF(condition, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if ((condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logTraceMessage(ss.str()); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#else
|
||||
|
||||
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
|
||||
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
|
||||
// code can just force them to be used itself in addition to calling the logging macro. Basically
|
||||
// we just want to reduce the chance of extra code being generated.
|
||||
#define POLYVOX_LOG_TRACE(message)
|
||||
#define POLYVOX_LOG_TRACE_IF(condition, message)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef POLYVOX_LOG_DEBUG_ENABLED
|
||||
|
||||
#define POLYVOX_LOG_DEBUG(message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logDebugMessage(ss.str()); \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#define POLYVOX_LOG_DEBUG_IF(condition, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if ((condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logDebugMessage(ss.str()); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#else
|
||||
|
||||
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
|
||||
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
|
||||
// code can just force them to be used itself in addition to calling the logging macro. Basically
|
||||
// we just want to reduce the chance of extra code being generated.
|
||||
#define POLYVOX_LOG_DEBUG(message)
|
||||
#define POLYVOX_LOG_DEBUG_IF(condition, message)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef POLYVOX_LOG_INFO_ENABLED
|
||||
|
||||
#define POLYVOX_LOG_INFO(message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logInfoMessage(ss.str()); \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#define POLYVOX_LOG_INFO_IF(condition, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if ((condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logInfoMessage(ss.str()); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#else
|
||||
|
||||
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
|
||||
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
|
||||
// code can just force them to be used itself in addition to calling the logging macro. Basically
|
||||
// we just want to reduce the chance of extra code being generated.
|
||||
#define POLYVOX_LOG_INFO(message)
|
||||
#define POLYVOX_LOG_INFO_IF(condition, message)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef POLYVOX_LOG_WARNING_ENABLED
|
||||
|
||||
#define POLYVOX_LOG_WARNING(message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logWarningMessage(ss.str()); \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#define POLYVOX_LOG_WARNING_IF(condition, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if ((condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logWarningMessage(ss.str()); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#else
|
||||
|
||||
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
|
||||
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
|
||||
// code can just force them to be used itself in addition to calling the logging macro. Basically
|
||||
// we just want to reduce the chance of extra code being generated.
|
||||
#define POLYVOX_LOG_WARNING(message)
|
||||
#define POLYVOX_LOG_WARNING_IF(condition, message)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef POLYVOX_LOG_ERROR_ENABLED
|
||||
|
||||
#define POLYVOX_LOG_ERROR(message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#define POLYVOX_LOG_ERROR_IF(condition, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if ((condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#else
|
||||
|
||||
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
|
||||
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
|
||||
// code can just force them to be used itself in addition to calling the logging macro. Basically
|
||||
// we just want to reduce the chance of extra code being generated.
|
||||
#define POLYVOX_LOG_ERROR(message)
|
||||
#define POLYVOX_LOG_ERROR_IF(condition, message)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef POLYVOX_LOG_FATAL_ENABLED
|
||||
|
||||
#define POLYVOX_LOG_FATAL(message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#define POLYVOX_LOG_FATAL_IF(condition, message) \
|
||||
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
|
||||
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
|
||||
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
|
||||
POLYVOX_MSC_WARNING_PUSH \
|
||||
POLYVOX_DISABLE_MSC_WARNING(4127) \
|
||||
do \
|
||||
{ \
|
||||
if ((condition)) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << message; \
|
||||
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
|
||||
} \
|
||||
} while(0) \
|
||||
POLYVOX_MSC_WARNING_POP
|
||||
|
||||
#else
|
||||
|
||||
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
|
||||
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
|
||||
// code can just force them to be used itself in addition to calling the logging macro. Basically
|
||||
// we just want to reduce the chance of extra code being generated.
|
||||
#define POLYVOX_LOG_FATAL(message)
|
||||
#define POLYVOX_LOG_FATAL_IF(condition, message)
|
||||
|
||||
#endif
|
||||
|
||||
#endif //__PolyVox_Logging_H__
|
@ -0,0 +1,335 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_MarchingCubeTables_H__
|
||||
#define __PolyVox_MarchingCubeTables_H__
|
||||
|
||||
#include "PolyVoxCore/Impl/TypeDef.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
//These tables were based on the article "Polygonising a scalar field".
|
||||
//They have been optimised to allow a more efficient algorithm via bitwise operations.
|
||||
|
||||
// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/index.html
|
||||
|
||||
const uint16_t edgeTable[256] =
|
||||
{
|
||||
0x000, 0x109, 0x203, 0x30a, 0x80c, 0x905, 0xa0f, 0xb06,
|
||||
0x406, 0x50f, 0x605, 0x70c, 0xc0a, 0xd03, 0xe09, 0xf00,
|
||||
0x190, 0x099, 0x393, 0x29a, 0x99c, 0x895, 0xb9f, 0xa96,
|
||||
0x596, 0x49f, 0x795, 0x69c, 0xd9a, 0xc93, 0xf99, 0xe90,
|
||||
0x230, 0x339, 0x033, 0x13a, 0xa3c, 0xb35, 0x83f, 0x936,
|
||||
0x636, 0x73f, 0x435, 0x53c, 0xe3a, 0xf33, 0xc39, 0xd30,
|
||||
0x3a0, 0x2a9, 0x1a3, 0x0aa, 0xbac, 0xaa5, 0x9af, 0x8a6,
|
||||
0x7a6, 0x6af, 0x5a5, 0x4ac, 0xfaa, 0xea3, 0xda9, 0xca0,
|
||||
0x8c0, 0x9c9, 0xac3, 0xbca, 0x0cc, 0x1c5, 0x2cf, 0x3c6,
|
||||
0xcc6, 0xdcf, 0xec5, 0xfcc, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
|
||||
0x950, 0x859, 0xb53, 0xa5a, 0x15c, 0x055, 0x35f, 0x256,
|
||||
0xd56, 0xc5f, 0xf55, 0xe5c, 0x55a, 0x453, 0x759, 0x650,
|
||||
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0x2fc, 0x3f5, 0x0ff, 0x1f6,
|
||||
0xef6, 0xfff, 0xcf5, 0xdfc, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
|
||||
0xb60, 0xa69, 0x963, 0x86a, 0x36c, 0x265, 0x16f, 0x066,
|
||||
0xf66, 0xe6f, 0xd65, 0xc6c, 0x76a, 0x663, 0x569, 0x460,
|
||||
0x460, 0x569, 0x663, 0x76a, 0xc6c, 0xd65, 0xe6f, 0xf66,
|
||||
0x066, 0x16f, 0x265, 0x36c, 0x86a, 0x963, 0xa69, 0xb60,
|
||||
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0xdfc, 0xcf5, 0xfff, 0xef6,
|
||||
0x1f6, 0x0ff, 0x3f5, 0x2fc, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
|
||||
0x650, 0x759, 0x453, 0x55a, 0xe5c, 0xf55, 0xc5f, 0xd56,
|
||||
0x256, 0x35f, 0x055, 0x15c, 0xa5a, 0xb53, 0x859, 0x950,
|
||||
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0xfcc, 0xec5, 0xdcf, 0xcc6,
|
||||
0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xbca, 0xac3, 0x9c9, 0x8c0,
|
||||
0xca0, 0xda9, 0xea3, 0xfaa, 0x4ac, 0x5a5, 0x6af, 0x7a6,
|
||||
0x8a6, 0x9af, 0xaa5, 0xbac, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
|
||||
0xd30, 0xc39, 0xf33, 0xe3a, 0x53c, 0x435, 0x73f, 0x636,
|
||||
0x936, 0x83f, 0xb35, 0xa3c, 0x13a, 0x033, 0x339, 0x230,
|
||||
0xe90, 0xf99, 0xc93, 0xd9a, 0x69c, 0x795, 0x49f, 0x596,
|
||||
0xa96, 0xb9f, 0x895, 0x99c, 0x29a, 0x393, 0x099, 0x190,
|
||||
0xf00, 0xe09, 0xd03, 0xc0a, 0x70c, 0x605, 0x50f, 0x406,
|
||||
0xb06, 0xa0f, 0x905, 0x80c, 0x30a, 0x203, 0x109, 0x000
|
||||
};
|
||||
|
||||
const int8_t 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, },
|
||||
{ 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, },
|
||||
{ 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, },
|
||||
{ 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, 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, },
|
||||
{ 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, }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
1062
include/PolyVoxCore/include/PolyVoxCore/Impl/RandomUnitVectors.h
Normal file
1062
include/PolyVoxCore/include/PolyVoxCore/Impl/RandomUnitVectors.h
Normal file
File diff suppressed because it is too large
Load Diff
1062
include/PolyVoxCore/include/PolyVoxCore/Impl/RandomVectors.h
Normal file
1062
include/PolyVoxCore/include/PolyVoxCore/Impl/RandomVectors.h
Normal file
File diff suppressed because it is too large
Load Diff
73
include/PolyVoxCore/include/PolyVoxCore/Impl/Timer.h
Normal file
73
include/PolyVoxCore/include/PolyVoxCore/Impl/Timer.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-20013 David Williams and Matthew Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Timer_H__
|
||||
#define __PolyVox_Timer_H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer(bool bAutoStart = true)
|
||||
{
|
||||
if (bAutoStart)
|
||||
{
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
void start(void)
|
||||
{
|
||||
m_start = clock::now();
|
||||
}
|
||||
|
||||
float elapsedTimeInSeconds(void)
|
||||
{
|
||||
std::chrono::duration<float> elapsed_seconds = clock::now() - m_start;
|
||||
return elapsed_seconds.count();
|
||||
}
|
||||
|
||||
uint32_t elapsedTimeInMilliSeconds(void)
|
||||
{
|
||||
std::chrono::duration<float, std::milli> elapsed_milliseconds = clock::now() - m_start;
|
||||
return elapsed_milliseconds.count();
|
||||
}
|
||||
|
||||
uint32_t elapsedTimeInMicroSeconds(void)
|
||||
{
|
||||
std::chrono::duration<float, std::micro> elapsed_microseconds = clock::now() - m_start;
|
||||
return elapsed_microseconds.count();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::chrono::system_clock clock;
|
||||
std::chrono::time_point<clock> m_start;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //__PolyVox_Timer_H__
|
74
include/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h
Normal file
74
include/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_TypeDef_H__
|
||||
#define __PolyVox_TypeDef_H__
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1800)
|
||||
#error "Your version of Visual Studio is too old to build PolyVox. You need at least version Visual Stusio 2013"
|
||||
#endif
|
||||
|
||||
//Definitions needed to make library functions accessable
|
||||
// See http://gcc.gnu.org/wiki/Visibility for more info.
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#define POLYVOX_HELPER_IMPORT __declspec(dllimport)
|
||||
#define POLYVOX_HELPER_EXPORT __declspec(dllexport)
|
||||
#define POLYVOX_HELPER_LOCAL
|
||||
#define POLYVOX_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
#define POLYVOX_DEPRECATED __attribute__((deprecated))
|
||||
#if __GNUC__ >= 4
|
||||
#define POLYVOX_HELPER_IMPORT __attribute__ ((visibility("default")))
|
||||
#define POLYVOX_HELPER_EXPORT __attribute__ ((visibility("default")))
|
||||
#define POLYVOX_HELPER_LOCAL __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define POLYVOX_HELPER_IMPORT
|
||||
#define POLYVOX_HELPER_EXPORT
|
||||
#define POLYVOX_HELPER_LOCAL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined SWIG
|
||||
//Do nothing in this case
|
||||
#else
|
||||
#undef POLYVOX_DEPRECATED
|
||||
#define POLYVOX_DEPRECATED //Define it to nothing to avoid warnings
|
||||
#endif
|
||||
|
||||
// Now we use the generic helper definitions above to define POLYVOX_API and POLYVOX_LOCAL.
|
||||
// POLYVOX_API is used for the public API symbols. It either imports or exports (or does nothing for static build)
|
||||
// POLYVOX_LOCAL is used for non-api symbols.
|
||||
|
||||
#ifdef POLYVOX_SHARED // defined if PolyVox is compiled as a shared library
|
||||
#ifdef POLYVOX_SHARED_EXPORTS // defined if we are building the PolyVox shared library (instead of using it)
|
||||
#define POLYVOX_API POLYVOX_HELPER_EXPORT
|
||||
#else
|
||||
#define POLYVOX_API POLYVOX_HELPER_IMPORT
|
||||
#endif // POLYVOX_SHARED_EXPORTS
|
||||
#define POLYVOX_LOCAL POLYVOX_HELPER_LOCAL
|
||||
#else // POLYVOX_SHARED is not defined: this means PolyVox is a static library.
|
||||
#define POLYVOX_API
|
||||
#define POLYVOX_LOCAL
|
||||
#endif // POLYVOX_SHARED
|
||||
|
||||
#endif
|
93
include/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h
Normal file
93
include/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Utility_H__
|
||||
#define __PolyVox_Utility_H__
|
||||
|
||||
#include "PolyVoxCore/Impl/TypeDef.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
inline bool isPowerOf2(uint32_t uInput)
|
||||
{
|
||||
if (uInput == 0)
|
||||
return false;
|
||||
else
|
||||
return ((uInput & (uInput - 1)) == 0);
|
||||
}
|
||||
|
||||
//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.
|
||||
inline uint8_t logBase2(uint32_t uInput)
|
||||
{
|
||||
//Release mode validation
|
||||
if (uInput == 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Cannot compute the log of zero.");
|
||||
}
|
||||
if (!isPowerOf2(uInput))
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Input must be a power of two in order to compute the log.");
|
||||
}
|
||||
|
||||
uint32_t uResult = 0;
|
||||
while ((uInput >> uResult) != 0)
|
||||
{
|
||||
++uResult;
|
||||
}
|
||||
return static_cast<uint8_t>(uResult - 1);
|
||||
}
|
||||
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
inline uint32_t upperPowerOfTwo(uint32_t v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline int32_t roundTowardsNegInf(float r)
|
||||
{
|
||||
return (r >= 0.0) ? static_cast<int32_t>(r) : static_cast<int32_t>(r - 1.0f);
|
||||
}
|
||||
|
||||
inline int32_t roundToNearestInteger(float r)
|
||||
{
|
||||
return (r >= 0.0) ? static_cast<int32_t>(r + 0.5f) : static_cast<int32_t>(r - 0.5f);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type clamp(const Type& value, const Type& low, const Type& high)
|
||||
{
|
||||
return (std::min)(high, (std::max)(low, value));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
72
include/PolyVoxCore/include/PolyVoxCore/Interpolation.h
Normal file
72
include/PolyVoxCore/include/PolyVoxCore/Interpolation.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Interpolation_H__
|
||||
#define __PolyVox_Interpolation_H__
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename Type>
|
||||
Type lerp(
|
||||
const Type& v0,const Type& v1,
|
||||
const float x)
|
||||
{
|
||||
//Interpolate along X
|
||||
Type v0_1 = (v1 - v0) * x + v0;
|
||||
|
||||
return v0_1;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type bilerp(
|
||||
const Type& v00,const Type& v10,const Type& v01,const Type& v11,
|
||||
const float x, const float y)
|
||||
{
|
||||
// Linearly interpolate along x
|
||||
Type v00_10 = lerp(v00, v10, x);
|
||||
Type v01_11 = lerp(v01, v11, x);
|
||||
|
||||
// And linearly interpolate the results along y
|
||||
Type v00_10__v01_11 = lerp(v00_10, v01_11, y);
|
||||
|
||||
return v00_10__v01_11;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type trilerp(
|
||||
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)
|
||||
{
|
||||
// Bilinearly interpolate along Y
|
||||
Type v000_v100__v010_v110 = bilerp(v000, v100, v010, v110, x, y);
|
||||
Type v001_v101__v011_v111 = bilerp(v001, v101, v011, v111, x, y);
|
||||
|
||||
// And linearly interpolate the results along z
|
||||
Type v000_v100__v010_v110____v001_v101__v011_v111 = lerp(v000_v100__v010_v110, v001_v101__v011_v111, z);
|
||||
|
||||
return v000_v100__v010_v110____v001_v101__v011_v111;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //__PolyVox_Interpolation_H__
|
46
include/PolyVoxCore/include/PolyVoxCore/IteratorController.h
Normal file
46
include/PolyVoxCore/include/PolyVoxCore/IteratorController.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_IteratorController_H__
|
||||
#define __PolyVox_IteratorController_H__
|
||||
|
||||
#include "PolyVoxCore/Region.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename IteratorType>
|
||||
class IteratorController
|
||||
{
|
||||
public:
|
||||
void reset(void);
|
||||
bool moveForward(void);
|
||||
|
||||
public:
|
||||
Region m_regValid;
|
||||
IteratorType* m_Iter;
|
||||
};
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/IteratorController.inl"
|
||||
|
||||
#endif //__PolyVox_IteratorController_H__
|
@ -0,0 +1,63 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename IteratorType>
|
||||
void IteratorController<IteratorType>::reset(void)
|
||||
{
|
||||
m_Iter->setPosition(m_regValid.getLowerCorner());
|
||||
}
|
||||
|
||||
template <typename IteratorType>
|
||||
bool IteratorController<IteratorType>::moveForward(void)
|
||||
{
|
||||
Vector3DInt32 v3dInitialPosition(m_Iter->getPosition().getX(), m_Iter->getPosition().getY(), m_Iter->getPosition().getZ());
|
||||
|
||||
if(v3dInitialPosition.getX() < m_regValid.getUpperX())
|
||||
{
|
||||
m_Iter->movePositiveX();
|
||||
return true;
|
||||
}
|
||||
|
||||
v3dInitialPosition.setX(m_regValid.getLowerX());
|
||||
|
||||
if(v3dInitialPosition.getY() < m_regValid.getUpperY())
|
||||
{
|
||||
v3dInitialPosition.setY(v3dInitialPosition.getY() + 1);
|
||||
m_Iter->setPosition(v3dInitialPosition);
|
||||
return true;
|
||||
}
|
||||
|
||||
v3dInitialPosition.setY(m_regValid.getLowerY());
|
||||
|
||||
if(v3dInitialPosition.getZ() < m_regValid.getUpperZ())
|
||||
{
|
||||
v3dInitialPosition.setZ(v3dInitialPosition.getZ() + 1);
|
||||
m_Iter->setPosition(v3dInitialPosition);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
9
include/PolyVoxCore/include/PolyVoxCore/LargeVolume.h
Normal file
9
include/PolyVoxCore/include/PolyVoxCore/LargeVolume.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __PolyVox_LargeVolume_H__
|
||||
#define __PolyVox_LargeVolume_H__
|
||||
|
||||
#pragma message("WARNING - The LargeVolume class has been replaced by PagedVolume. Please use that instead.")
|
||||
|
||||
#include "PagedVolume.h"
|
||||
#include "PolyVoxForwardDeclarations.h"
|
||||
|
||||
#endif //__PolyVox_LargeVolume_H__
|
60
include/PolyVoxCore/include/PolyVoxCore/LowPassFilter.h
Normal file
60
include/PolyVoxCore/include/PolyVoxCore/LowPassFilter.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_LowPassFilter_H__
|
||||
#define __PolyVox_LowPassFilter_H__
|
||||
|
||||
#include "PolyVoxCore/IteratorController.h"
|
||||
#include "PolyVoxCore/RawVolume.h" //Is this desirable?
|
||||
#include "PolyVoxCore/Region.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template< typename SrcVolumeType, typename DstVolumeType, typename AccumulationType>
|
||||
class LowPassFilter
|
||||
{
|
||||
public:
|
||||
LowPassFilter(SrcVolumeType* pVolSrc, Region regSrc, DstVolumeType* pVolDst, Region regDst, uint32_t uKernelSize);
|
||||
|
||||
void execute();
|
||||
void executeSAT();
|
||||
|
||||
private:
|
||||
//Source data
|
||||
SrcVolumeType* m_pVolSrc;
|
||||
Region m_regSrc;
|
||||
|
||||
//Destination data
|
||||
DstVolumeType* m_pVolDst;
|
||||
Region m_regDst;
|
||||
|
||||
//Kernel size
|
||||
uint32_t m_uKernelSize;
|
||||
};
|
||||
|
||||
}//namespace PolyVox
|
||||
|
||||
#include "PolyVoxCore/LowPassFilter.inl"
|
||||
|
||||
#endif //__PolyVox_LowPassFilter_H__
|
||||
|
255
include/PolyVoxCore/include/PolyVoxCore/LowPassFilter.inl
Normal file
255
include/PolyVoxCore/include/PolyVoxCore/LowPassFilter.inl
Normal file
@ -0,0 +1,255 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
* \param pVolSrc
|
||||
* \param regSrc
|
||||
* \param[out] pVolDst
|
||||
* \param regDst
|
||||
* \param uKernelSize
|
||||
*/
|
||||
template< typename SrcVolumeType, typename DstVolumeType, typename AccumulationType>
|
||||
LowPassFilter<SrcVolumeType, DstVolumeType, AccumulationType>::LowPassFilter(SrcVolumeType* pVolSrc, Region regSrc, DstVolumeType* pVolDst, Region regDst, uint32_t uKernelSize)
|
||||
:m_pVolSrc(pVolSrc)
|
||||
,m_regSrc(regSrc)
|
||||
,m_pVolDst(pVolDst)
|
||||
,m_regDst(regDst)
|
||||
,m_uKernelSize(uKernelSize)
|
||||
{
|
||||
//Kernel size must be at least three
|
||||
if(m_uKernelSize < 3)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Kernel size must be at least three");
|
||||
}
|
||||
|
||||
//Kernel size must be odd
|
||||
if(m_uKernelSize % 2 == 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Kernel size must be odd");
|
||||
}
|
||||
}
|
||||
|
||||
template< typename SrcVolumeType, typename DstVolumeType, typename AccumulationType>
|
||||
void LowPassFilter<SrcVolumeType, DstVolumeType, AccumulationType>::execute()
|
||||
{
|
||||
int32_t iSrcMinX = m_regSrc.getLowerX();
|
||||
int32_t iSrcMinY = m_regSrc.getLowerY();
|
||||
int32_t iSrcMinZ = m_regSrc.getLowerZ();
|
||||
|
||||
int32_t iSrcMaxX = m_regSrc.getUpperX();
|
||||
int32_t iSrcMaxY = m_regSrc.getUpperY();
|
||||
int32_t iSrcMaxZ = m_regSrc.getUpperZ();
|
||||
|
||||
int32_t iDstMinX = m_regDst.getLowerX();
|
||||
int32_t iDstMinY = m_regDst.getLowerY();
|
||||
int32_t iDstMinZ = m_regDst.getLowerZ();
|
||||
|
||||
//int32_t iDstMaxX = m_regDst.getUpperX();
|
||||
//int32_t iDstMaxY = m_regDst.getUpperY();
|
||||
//int32_t iDstMaxZ = m_regDst.getUpperZ();
|
||||
|
||||
typename SrcVolumeType::Sampler srcSampler(m_pVolSrc);
|
||||
|
||||
for(int32_t iSrcZ = iSrcMinZ, iDstZ = iDstMinZ; iSrcZ <= iSrcMaxZ; iSrcZ++, iDstZ++)
|
||||
{
|
||||
for(int32_t iSrcY = iSrcMinY, iDstY = iDstMinY; iSrcY <= iSrcMaxY; iSrcY++, iDstY++)
|
||||
{
|
||||
for(int32_t iSrcX = iSrcMinX, iDstX = iDstMinX; iSrcX <= iSrcMaxX; iSrcX++, iDstX++)
|
||||
{
|
||||
AccumulationType tSrcVoxel(0);
|
||||
srcSampler.setPosition(iSrcX, iSrcY, iSrcZ);
|
||||
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx1ny1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx1ny0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx1ny1pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx0py1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx0py0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx0py1pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx1py1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx1py0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1nx1py1pz());
|
||||
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px1ny1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px1ny0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px1ny1pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px0py1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px0py0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px0py1pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px1py1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px1py0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel0px1py1pz());
|
||||
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px1ny1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px1ny0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px1ny1pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px0py1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px0py0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px0py1pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px1py1nz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px1py0pz());
|
||||
tSrcVoxel += static_cast<AccumulationType>(srcSampler.peekVoxel1px1py1pz());
|
||||
|
||||
tSrcVoxel /= 27;
|
||||
|
||||
//tSrcVoxel.setDensity(uDensity);
|
||||
m_pVolDst->setVoxelAt(iSrcX, iSrcY, iSrcZ, static_cast<typename DstVolumeType::VoxelType>(tSrcVoxel));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename SrcVolumeType, typename DstVolumeType, typename AccumulationType>
|
||||
void LowPassFilter<SrcVolumeType, DstVolumeType, AccumulationType>::executeSAT()
|
||||
{
|
||||
const uint32_t border = (m_uKernelSize - 1) / 2;
|
||||
|
||||
Vector3DInt32 satLowerCorner = m_regSrc.getLowerCorner() - Vector3DInt32(border, border, border);
|
||||
Vector3DInt32 satUpperCorner = m_regSrc.getUpperCorner() + Vector3DInt32(border, border, border);
|
||||
|
||||
//Use floats for the SAT volume to ensure it works with negative
|
||||
//densities and with both integral and floating point input volumes.
|
||||
RawVolume<AccumulationType> satVolume(Region(satLowerCorner, satUpperCorner));
|
||||
|
||||
//Clear to zeros (necessary?)
|
||||
//FIXME - use Volume::fill() method. Implemented in base class as below
|
||||
//but with optimised implementations in subclasses?
|
||||
for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++)
|
||||
{
|
||||
for(int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++)
|
||||
{
|
||||
for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++)
|
||||
{
|
||||
satVolume.setVoxelAt(x,y,z,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typename RawVolume<AccumulationType>::Sampler satVolumeIter(&satVolume);
|
||||
|
||||
IteratorController<typename RawVolume<AccumulationType>::Sampler> satIterCont;
|
||||
satIterCont.m_regValid = Region(satLowerCorner, satUpperCorner);
|
||||
satIterCont.m_Iter = &satVolumeIter;
|
||||
satIterCont.reset();
|
||||
|
||||
typename SrcVolumeType::Sampler srcVolumeIter(m_pVolSrc);
|
||||
|
||||
IteratorController<typename SrcVolumeType::Sampler> srcIterCont;
|
||||
srcIterCont.m_regValid = Region(satLowerCorner, satUpperCorner);
|
||||
srcIterCont.m_Iter = &srcVolumeIter;
|
||||
srcIterCont.reset();
|
||||
|
||||
do
|
||||
{
|
||||
AccumulationType previousSum = static_cast<AccumulationType>(satVolumeIter.peekVoxel1nx0py0pz());
|
||||
AccumulationType currentVal = static_cast<AccumulationType>(srcVolumeIter.getVoxel());
|
||||
|
||||
satVolumeIter.setVoxel(previousSum + currentVal);
|
||||
|
||||
srcIterCont.moveForward();
|
||||
|
||||
}while(satIterCont.moveForward());
|
||||
|
||||
//Build SAT in three passes
|
||||
/*for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++)
|
||||
{
|
||||
for(int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++)
|
||||
{
|
||||
for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++)
|
||||
{
|
||||
AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxelAt(x-1,y,z));
|
||||
AccumulationType currentVal = static_cast<AccumulationType>(m_pVolSrc->getVoxelAt(x,y,z));
|
||||
|
||||
satVolume.setVoxelAt(x,y,z,previousSum + currentVal);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++)
|
||||
{
|
||||
for(int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++)
|
||||
{
|
||||
for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++)
|
||||
{
|
||||
AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxel(x,y-1,z, WrapModes::Border));
|
||||
AccumulationType currentSum = static_cast<AccumulationType>(satVolume.getVoxel(x,y,z, WrapModes::Border));
|
||||
|
||||
satVolume.setVoxelAt(x,y,z,previousSum + currentSum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++)
|
||||
{
|
||||
for(int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++)
|
||||
{
|
||||
for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++)
|
||||
{
|
||||
AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxel(x,y,z-1, WrapModes::Border));
|
||||
AccumulationType currentSum = static_cast<AccumulationType>(satVolume.getVoxel(x,y,z, WrapModes::Border));
|
||||
|
||||
satVolume.setVoxelAt(x,y,z,previousSum + currentSum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Now compute the average
|
||||
const Vector3DInt32& v3dDstLowerCorner = m_regDst.getLowerCorner();
|
||||
const Vector3DInt32& v3dDstUpperCorner = m_regDst.getUpperCorner();
|
||||
|
||||
const Vector3DInt32& v3dSrcLowerCorner = m_regSrc.getLowerCorner();
|
||||
|
||||
for(int32_t iDstZ = v3dDstLowerCorner.getZ(), iSrcZ = v3dSrcLowerCorner.getZ(); iDstZ <= v3dDstUpperCorner.getZ(); iDstZ++, iSrcZ++)
|
||||
{
|
||||
for(int32_t iDstY = v3dDstLowerCorner.getY(), iSrcY = v3dSrcLowerCorner.getY(); iDstY <= v3dDstUpperCorner.getY(); iDstY++, iSrcY++)
|
||||
{
|
||||
for(int32_t iDstX = v3dDstLowerCorner.getX(), iSrcX = v3dSrcLowerCorner.getX(); iDstX <= v3dDstUpperCorner.getX(); iDstX++, iSrcX++)
|
||||
{
|
||||
int32_t satLowerX = iSrcX - border - 1;
|
||||
int32_t satLowerY = iSrcY - border - 1;
|
||||
int32_t satLowerZ = iSrcZ - border - 1;
|
||||
|
||||
int32_t satUpperX = iSrcX + border;
|
||||
int32_t satUpperY = iSrcY + border;
|
||||
int32_t satUpperZ = iSrcZ + border;
|
||||
|
||||
AccumulationType a = satVolume.getVoxel(satLowerX,satLowerY,satLowerZ, WrapModes::Border);
|
||||
AccumulationType b = satVolume.getVoxel(satUpperX,satLowerY,satLowerZ, WrapModes::Border);
|
||||
AccumulationType c = satVolume.getVoxel(satLowerX,satUpperY,satLowerZ, WrapModes::Border);
|
||||
AccumulationType d = satVolume.getVoxel(satUpperX,satUpperY,satLowerZ, WrapModes::Border);
|
||||
AccumulationType e = satVolume.getVoxel(satLowerX,satLowerY,satUpperZ, WrapModes::Border);
|
||||
AccumulationType f = satVolume.getVoxel(satUpperX,satLowerY,satUpperZ, WrapModes::Border);
|
||||
AccumulationType g = satVolume.getVoxel(satLowerX,satUpperY,satUpperZ, WrapModes::Border);
|
||||
AccumulationType h = satVolume.getVoxel(satUpperX,satUpperY,satUpperZ, WrapModes::Border);
|
||||
|
||||
AccumulationType sum = h+c-d-g-f-a+b+e;
|
||||
uint32_t sideLength = border * 2 + 1;
|
||||
AccumulationType average = sum / (sideLength*sideLength*sideLength);
|
||||
|
||||
m_pVolDst->setVoxelAt(iDstX, iDstY, iDstZ, static_cast<typename DstVolumeType::VoxelType>(average));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,358 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_SurfaceExtractor_H__
|
||||
#define __PolyVox_SurfaceExtractor_H__
|
||||
|
||||
#include "Impl/MarchingCubesTables.h"
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include "PolyVoxCore/Array.h"
|
||||
#include "PolyVoxCore/BaseVolume.h" //For wrap modes... should move these?
|
||||
#include "PolyVoxCore/Mesh.h"
|
||||
#include "PolyVoxCore/DefaultMarchingCubesController.h"
|
||||
#include "PolyVoxCore/Vertex.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
#ifdef SWIG
|
||||
struct MarchingCubesVertex
|
||||
#else
|
||||
template<typename _DataType>
|
||||
struct POLYVOX_API MarchingCubesVertex
|
||||
#endif
|
||||
{
|
||||
typedef _DataType DataType;
|
||||
|
||||
// Each component of the position is stored using 8.8 fixed-point encoding.
|
||||
Vector3DUint16 encodedPosition;
|
||||
|
||||
// The normal is encoded as a 16-bit unsigned integer using the 'oct16'
|
||||
// encoding described here: http://jcgt.org/published/0003/02/01/
|
||||
uint16_t encodedNormal;
|
||||
|
||||
// User data
|
||||
DataType data;
|
||||
};
|
||||
|
||||
// Convienient shorthand for declaring a mesh of marching cubes vertices
|
||||
// Currently disabled because it requires GCC 4.7
|
||||
//template <typename VertexDataType, typename IndexType = DefaultIndexType>
|
||||
//using MarchingCubesMesh = Mesh< MarchingCubesVertex<VertexDataType>, IndexType >;
|
||||
|
||||
/// Decodes a position from a MarchingCubesVertex
|
||||
inline Vector3DFloat decodePosition(const Vector3DUint16& encodedPosition)
|
||||
{
|
||||
Vector3DFloat result(encodedPosition.getX(), encodedPosition.getY(), encodedPosition.getZ());
|
||||
result *= (1.0f / 256.0f); // Division is compile-time constant
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint16_t encodeNormal(const Vector3DFloat& normal)
|
||||
{
|
||||
// The first part of this function is based off the code in Listing 1 of http://jcgt.org/published/0003/02/01/
|
||||
// It was rewritten in C++ and is restructued for the CPU rather than the GPU.
|
||||
|
||||
// Get the input components
|
||||
float vx = normal.getX();
|
||||
float vy = normal.getY();
|
||||
float vz = normal.getZ();
|
||||
|
||||
// Project the sphere onto the octahedron, and then onto the xy plane
|
||||
float px = vx * (1.0f / (std::abs(vx) + std::abs(vy) + std::abs(vz)));
|
||||
float py = vy * (1.0f / (std::abs(vx) + std::abs(vy) + std::abs(vz)));
|
||||
|
||||
// Reflect the folds of the lower hemisphere over the diagonals.
|
||||
if (vz <= 0.0f)
|
||||
{
|
||||
float refx = ((1.0f - std::abs(py)) * (px >= 0.0f ? +1.0f : -1.0f));
|
||||
float refy = ((1.0f - std::abs(px)) * (py >= 0.0f ? +1.0f : -1.0f));
|
||||
px = refx;
|
||||
py = refy;
|
||||
}
|
||||
|
||||
// The next part was not given in the paper. We map our two
|
||||
// floats into two bytes and store them in a single uint16_t
|
||||
|
||||
// Move from range [-1.0f, 1.0f] to [0.0f, 255.0f]
|
||||
px = (px + 1.0f) * 127.5f;
|
||||
py = (py + 1.0f) * 127.5f;
|
||||
|
||||
// Convert to uints
|
||||
uint16_t resultX = static_cast<uint16_t>(px + 0.5f);
|
||||
uint16_t resultY = static_cast<uint16_t>(py + 0.5f);
|
||||
|
||||
// Make sure only the lower bits are set. Probably
|
||||
// not necessary but we're just being careful really.
|
||||
resultX &= 0xFF;
|
||||
resultY &= 0xFF;
|
||||
|
||||
// Contatenate the bytes and return the result.
|
||||
return (resultX << 8) | resultY;
|
||||
}
|
||||
|
||||
inline Vector3DFloat decodeNormal(const uint16_t& encodedNormal)
|
||||
{
|
||||
// Extract the two bytes from the uint16_t.
|
||||
uint16_t ux = (encodedNormal >> 8) & 0xFF;
|
||||
uint16_t uy = (encodedNormal ) & 0xFF;
|
||||
|
||||
// Convert to floats in the range [-1.0f, +1.0f].
|
||||
float ex = ux / 127.5f - 1.0f;
|
||||
float ey = uy / 127.5f - 1.0f;
|
||||
|
||||
// Reconstruct the origninal vector. This is a C++ implementation
|
||||
// of Listing 2 of http://jcgt.org/published/0003/02/01/
|
||||
float vx = ex;
|
||||
float vy = ey;
|
||||
float vz = 1.0f - std::abs(ex) - std::abs(ey);
|
||||
|
||||
if (vz < 0.0f)
|
||||
{
|
||||
float refX = ((1.0f - std::abs(vy)) * (vx >= 0.0f ? +1.0f : -1.0f));
|
||||
float refY = ((1.0f - std::abs(vx)) * (vy >= 0.0f ? +1.0f : -1.0f));
|
||||
vx = refX;
|
||||
vy = refY;
|
||||
}
|
||||
|
||||
// Normalise and return the result.
|
||||
Vector3DFloat v(vx, vy, vz);
|
||||
v.normalise();
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Decodes a MarchingCubesVertex by converting it into a regular Vertex which can then be directly used for rendering.
|
||||
template<typename DataType>
|
||||
Vertex<DataType> decodeVertex(const MarchingCubesVertex<DataType>& marchingCubesVertex)
|
||||
{
|
||||
Vertex<DataType> result;
|
||||
result.position = decodePosition(marchingCubesVertex.encodedPosition);
|
||||
result.normal = decodeNormal(marchingCubesVertex.encodedNormal);
|
||||
result.data = marchingCubesVertex.data; // Data is not encoded
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Do not use this class directly. Use the 'extractMarchingCubesSurface' function instead (see examples).
|
||||
template< typename VolumeType, typename MeshType, typename ControllerType>
|
||||
class MarchingCubesSurfaceExtractor
|
||||
{
|
||||
public:
|
||||
MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, ControllerType controller, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType());
|
||||
|
||||
void execute();
|
||||
|
||||
private:
|
||||
//Compute the cell bitmask for a particular slice in z.
|
||||
template<bool isPrevZAvail>
|
||||
uint32_t computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask);
|
||||
|
||||
//Compute the cell bitmask for a given cell.
|
||||
template<bool isPrevXAvail, bool isPrevYAvail, bool isPrevZAvail>
|
||||
void computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask, uint32_t uXRegSpace, uint32_t uYRegSpace);
|
||||
|
||||
//Use the cell bitmasks to generate all the vertices needed for that slice
|
||||
void generateVerticesForSlice(const Array2DUint8& pCurrentBitmask,
|
||||
Array2DInt32& m_pCurrentVertexIndicesX,
|
||||
Array2DInt32& m_pCurrentVertexIndicesY,
|
||||
Array2DInt32& m_pCurrentVertexIndicesZ);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010.
|
||||
//See http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 for details.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
|
||||
{
|
||||
//FIXME - Should actually use DensityType here, both in principle and because the maths may be
|
||||
//faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel.
|
||||
//But watch out for when the DensityType is unsigned and the difference could be negative.
|
||||
float voxel1nx = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz()));
|
||||
float voxel1px = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz()));
|
||||
|
||||
float voxel1ny = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz()));
|
||||
float voxel1py = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz()));
|
||||
|
||||
float voxel1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz()));
|
||||
float voxel1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz()));
|
||||
|
||||
return Vector3DFloat
|
||||
(
|
||||
voxel1nx - voxel1px,
|
||||
voxel1ny - voxel1py,
|
||||
voxel1nz - voxel1pz
|
||||
);
|
||||
}
|
||||
|
||||
Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& 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} } };
|
||||
|
||||
//FIXME - Should actually use DensityType here, both in principle and because the maths may be
|
||||
//faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel.
|
||||
//But watch out for when the DensityType is unsigned and the difference could be negative.
|
||||
const float pVoxel1nx1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1nz()));
|
||||
const float pVoxel1nx1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny0pz()));
|
||||
const float pVoxel1nx1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1pz()));
|
||||
const float pVoxel1nx0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py1nz()));
|
||||
const float pVoxel1nx0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz()));
|
||||
const float pVoxel1nx0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py1pz()));
|
||||
const float pVoxel1nx1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py1nz()));
|
||||
const float pVoxel1nx1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py0pz()));
|
||||
const float pVoxel1nx1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py1pz()));
|
||||
|
||||
const float pVoxel0px1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny1nz()));
|
||||
const float pVoxel0px1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz()));
|
||||
const float pVoxel0px1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny1pz()));
|
||||
const float pVoxel0px0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz()));
|
||||
//const float pVoxel0px0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py0pz()));
|
||||
const float pVoxel0px0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz()));
|
||||
const float pVoxel0px1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py1nz()));
|
||||
const float pVoxel0px1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz()));
|
||||
const float pVoxel0px1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py1pz()));
|
||||
|
||||
const float pVoxel1px1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny1nz()));
|
||||
const float pVoxel1px1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny0pz()));
|
||||
const float pVoxel1px1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny1pz()));
|
||||
const float pVoxel1px0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py1nz()));
|
||||
const float pVoxel1px0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz()));
|
||||
const float pVoxel1px0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py1pz()));
|
||||
const float pVoxel1px1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py1nz()));
|
||||
const float pVoxel1px1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py0pz()));
|
||||
const float pVoxel1px1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py1pz()));
|
||||
|
||||
const float 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 float 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 float 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(-xGrad,-yGrad,-zGrad);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// End of compiler bug workaroumd.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//Use the cell bitmasks to generate all the indices needed for that slice
|
||||
void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask,
|
||||
const Array2DInt32& m_pPreviousVertexIndicesX,
|
||||
const Array2DInt32& m_pPreviousVertexIndicesY,
|
||||
const Array2DInt32& m_pPreviousVertexIndicesZ,
|
||||
const Array2DInt32& m_pCurrentVertexIndicesX,
|
||||
const Array2DInt32& m_pCurrentVertexIndicesY);
|
||||
|
||||
//The volume data and a sampler to access it.
|
||||
VolumeType* m_volData;
|
||||
typename VolumeType::Sampler m_sampVolume;
|
||||
|
||||
//Used to return the number of cells in a slice which contain triangles.
|
||||
uint32_t m_uNoOfOccupiedCells;
|
||||
|
||||
//The surface patch we are currently filling.
|
||||
MeshType* m_meshCurrent;
|
||||
|
||||
//Information about the region we are currently processing
|
||||
Region m_regSizeInVoxels;
|
||||
Region m_regSizeInCells;
|
||||
/*Region m_regSizeInVoxelsCropped;
|
||||
Region m_regSizeInVoxelsUncropped;
|
||||
Region m_regVolumeCropped;*/
|
||||
Region m_regSlicePrevious;
|
||||
Region m_regSliceCurrent;
|
||||
|
||||
//Used to convert arbitrary voxel types in densities and materials.
|
||||
ControllerType m_controller;
|
||||
|
||||
//Our threshold value
|
||||
typename ControllerType::DensityType m_tThreshold;
|
||||
};
|
||||
|
||||
// This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically.
|
||||
// There are a few reasons why this might be useful to more advanced users:
|
||||
//
|
||||
// 1. It leaves the user in control of memory allocation and would allow them to implement e.g. a mesh pooling system.
|
||||
// 2. The user-provided mesh could have a different index type (e.g. 16-bit indices) to reduce memory usage.
|
||||
// 3. The user could provide a custom mesh class, e.g a thin wrapper around an openGL VBO to allow direct writing into this structure.
|
||||
//
|
||||
// We don't provide a default MeshType here. If the user doesn't want to provide a MeshType then it probably makes
|
||||
// more sense to use the other variant of this function where the mesh is a return value rather than a parameter.
|
||||
//
|
||||
// Note: This function is called 'extractMarchingCubesMeshCustom' rather than 'extractMarchingCubesMesh' to avoid ambiguity when only three parameters
|
||||
// are provided (would the third parameter be a controller or a mesh?). It seems this can be fixed by using enable_if/static_assert to emulate concepts,
|
||||
// but this is relatively complex and I haven't done it yet. Could always add it later as another overload.
|
||||
template< typename VolumeType, typename MeshType, typename ControllerType = DefaultMarchingCubesController<typename VolumeType::VoxelType> >
|
||||
void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller = ControllerType(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType())
|
||||
{
|
||||
MarchingCubesSurfaceExtractor<VolumeType, MeshType, ControllerType> extractor(volData, region, result, controller, eWrapMode, tBorderValue);
|
||||
extractor.execute();
|
||||
}
|
||||
|
||||
template< typename VolumeType, typename ControllerType = DefaultMarchingCubesController<typename VolumeType::VoxelType> >
|
||||
Mesh<MarchingCubesVertex<typename VolumeType::VoxelType> > extractMarchingCubesMesh(VolumeType* volData, Region region, ControllerType controller = ControllerType(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType())
|
||||
{
|
||||
Mesh<MarchingCubesVertex<typename VolumeType::VoxelType> > result;
|
||||
extractMarchingCubesMeshCustom<VolumeType, Mesh<MarchingCubesVertex<typename VolumeType::VoxelType>, DefaultIndexType > >(volData, region, &result, controller, eWrapMode, tBorderValue);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.inl"
|
||||
|
||||
#endif
|
@ -0,0 +1,637 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/Impl/Timer.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template<typename VolumeType, typename MeshType, typename ControllerType>
|
||||
MarchingCubesSurfaceExtractor<VolumeType, MeshType, ControllerType>::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, ControllerType controller, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue)
|
||||
:m_volData(volData)
|
||||
,m_sampVolume(volData)
|
||||
,m_meshCurrent(result)
|
||||
,m_regSizeInVoxels(region)
|
||||
,m_controller(controller)
|
||||
,m_tThreshold(m_controller.getThreshold())
|
||||
{
|
||||
POLYVOX_THROW_IF(m_meshCurrent == nullptr, std::invalid_argument, "Provided mesh cannot be null");
|
||||
//m_regSizeInVoxels.cropTo(m_volData->getEnclosingRegion());
|
||||
m_regSizeInCells = m_regSizeInVoxels;
|
||||
m_regSizeInCells.setUpperCorner(m_regSizeInCells.getUpperCorner() - Vector3DInt32(1,1,1));
|
||||
|
||||
m_sampVolume.setWrapMode(eWrapMode, tBorderValue);
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename ControllerType>
|
||||
void MarchingCubesSurfaceExtractor<VolumeType, MeshType, ControllerType>::execute()
|
||||
{
|
||||
Timer timer;
|
||||
m_meshCurrent->clear();
|
||||
|
||||
const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 1;
|
||||
const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 1;
|
||||
|
||||
//For edge indices
|
||||
Array2DInt32 m_pPreviousVertexIndicesX(uArrayWidth, uArrayHeight);
|
||||
Array2DInt32 m_pPreviousVertexIndicesY(uArrayWidth, uArrayHeight);
|
||||
Array2DInt32 m_pPreviousVertexIndicesZ(uArrayWidth, uArrayHeight);
|
||||
Array2DInt32 m_pCurrentVertexIndicesX(uArrayWidth, uArrayHeight);
|
||||
Array2DInt32 m_pCurrentVertexIndicesY(uArrayWidth, uArrayHeight);
|
||||
Array2DInt32 m_pCurrentVertexIndicesZ(uArrayWidth, uArrayHeight);
|
||||
|
||||
Array2DUint8 pPreviousBitmask(uArrayWidth, uArrayHeight);
|
||||
Array2DUint8 pCurrentBitmask(uArrayWidth, uArrayHeight);
|
||||
|
||||
//Create a region corresponding to the first slice
|
||||
m_regSlicePrevious = m_regSizeInVoxels;
|
||||
Vector3DInt32 v3dUpperCorner = m_regSlicePrevious.getUpperCorner();
|
||||
v3dUpperCorner.setZ(m_regSlicePrevious.getLowerZ()); //Set the upper z to the lower z to make it one slice thick.
|
||||
m_regSlicePrevious.setUpperCorner(v3dUpperCorner);
|
||||
m_regSliceCurrent = m_regSlicePrevious;
|
||||
|
||||
uint32_t uNoOfNonEmptyCellsForSlice0 = 0;
|
||||
uint32_t uNoOfNonEmptyCellsForSlice1 = 0;
|
||||
|
||||
//Process the first slice (previous slice not available)
|
||||
computeBitmaskForSlice<false>(pPreviousBitmask, pCurrentBitmask);
|
||||
uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells;
|
||||
|
||||
if(uNoOfNonEmptyCellsForSlice1 != 0)
|
||||
{
|
||||
memset(m_pCurrentVertexIndicesX.getRawData(), 0xff, m_pCurrentVertexIndicesX.getNoOfElements() * 4);
|
||||
memset(m_pCurrentVertexIndicesY.getRawData(), 0xff, m_pCurrentVertexIndicesY.getNoOfElements() * 4);
|
||||
memset(m_pCurrentVertexIndicesZ.getRawData(), 0xff, m_pCurrentVertexIndicesZ.getNoOfElements() * 4);
|
||||
generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ);
|
||||
}
|
||||
|
||||
std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1);
|
||||
pPreviousBitmask.swap(pCurrentBitmask);
|
||||
m_pPreviousVertexIndicesX.swap(m_pCurrentVertexIndicesX);
|
||||
m_pPreviousVertexIndicesY.swap(m_pCurrentVertexIndicesY);
|
||||
m_pPreviousVertexIndicesZ.swap(m_pCurrentVertexIndicesZ);
|
||||
|
||||
m_regSlicePrevious = m_regSliceCurrent;
|
||||
m_regSliceCurrent.shift(Vector3DInt32(0,0,1));
|
||||
|
||||
//Process the other slices (previous slice is available)
|
||||
for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++)
|
||||
{
|
||||
computeBitmaskForSlice<true>(pPreviousBitmask, pCurrentBitmask);
|
||||
uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells;
|
||||
|
||||
if(uNoOfNonEmptyCellsForSlice1 != 0)
|
||||
{
|
||||
memset(m_pCurrentVertexIndicesX.getRawData(), 0xff, m_pCurrentVertexIndicesX.getNoOfElements() * 4);
|
||||
memset(m_pCurrentVertexIndicesY.getRawData(), 0xff, m_pCurrentVertexIndicesY.getNoOfElements() * 4);
|
||||
memset(m_pCurrentVertexIndicesZ.getRawData(), 0xff, m_pCurrentVertexIndicesZ.getNoOfElements() * 4);
|
||||
generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ);
|
||||
}
|
||||
|
||||
if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0))
|
||||
{
|
||||
generateIndicesForSlice(pPreviousBitmask, m_pPreviousVertexIndicesX, m_pPreviousVertexIndicesY, m_pPreviousVertexIndicesZ, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY);
|
||||
}
|
||||
|
||||
std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1);
|
||||
pPreviousBitmask.swap(pCurrentBitmask);
|
||||
m_pPreviousVertexIndicesX.swap(m_pCurrentVertexIndicesX);
|
||||
m_pPreviousVertexIndicesY.swap(m_pCurrentVertexIndicesY);
|
||||
m_pPreviousVertexIndicesZ.swap(m_pCurrentVertexIndicesZ);
|
||||
|
||||
m_regSlicePrevious = m_regSliceCurrent;
|
||||
m_regSliceCurrent.shift(Vector3DInt32(0,0,1));
|
||||
}
|
||||
|
||||
m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner());
|
||||
|
||||
POLYVOX_LOG_TRACE("Marching cubes surface extraction took " << timer.elapsedTimeInMilliSeconds()
|
||||
<< "ms (Region size = " << m_regSizeInVoxels.getWidthInVoxels() << "x" << m_regSizeInVoxels.getHeightInVoxels()
|
||||
<< "x" << m_regSizeInVoxels.getDepthInVoxels() << ")");
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename ControllerType>
|
||||
template<bool isPrevZAvail>
|
||||
uint32_t MarchingCubesSurfaceExtractor<VolumeType, MeshType, ControllerType>::computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask)
|
||||
{
|
||||
m_uNoOfOccupiedCells = 0;
|
||||
|
||||
const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperX();
|
||||
const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperY();
|
||||
|
||||
const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ();
|
||||
|
||||
//Process the lower left corner
|
||||
int32_t iYVolSpace = m_regSliceCurrent.getLowerY();
|
||||
int32_t iXVolSpace = m_regSliceCurrent.getLowerX();
|
||||
|
||||
uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
|
||||
uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
|
||||
|
||||
|
||||
m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace);
|
||||
computeBitmaskForCell<false, false, isPrevZAvail>(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace);
|
||||
|
||||
//Process the edge where x is minimal.
|
||||
iXVolSpace = m_regSliceCurrent.getLowerX();
|
||||
m_sampVolume.setPosition(iXVolSpace, m_regSliceCurrent.getLowerY(), iZVolSpace);
|
||||
for(iYVolSpace = m_regSliceCurrent.getLowerY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++)
|
||||
{
|
||||
uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
|
||||
uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
|
||||
|
||||
m_sampVolume.movePositiveY();
|
||||
|
||||
computeBitmaskForCell<false, true, isPrevZAvail>(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace);
|
||||
}
|
||||
|
||||
//Process the edge where y is minimal.
|
||||
iYVolSpace = m_regSliceCurrent.getLowerY();
|
||||
m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace);
|
||||
for(iXVolSpace = m_regSliceCurrent.getLowerX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++)
|
||||
{
|
||||
uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
|
||||
uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
|
||||
|
||||
m_sampVolume.movePositiveX();
|
||||
|
||||
computeBitmaskForCell<true, false, isPrevZAvail>(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace);
|
||||
}
|
||||
|
||||
//Process all remaining elemnents of the slice. In this case, previous x and y values are always available
|
||||
for(iYVolSpace = m_regSliceCurrent.getLowerY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++)
|
||||
{
|
||||
m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace);
|
||||
for(iXVolSpace = m_regSliceCurrent.getLowerX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++)
|
||||
{
|
||||
uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
|
||||
uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
|
||||
|
||||
m_sampVolume.movePositiveX();
|
||||
|
||||
computeBitmaskForCell<true, true, isPrevZAvail>(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace);
|
||||
}
|
||||
}
|
||||
|
||||
return m_uNoOfOccupiedCells;
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename ControllerType>
|
||||
template<bool isPrevXAvail, bool isPrevYAvail, bool isPrevZAvail>
|
||||
void MarchingCubesSurfaceExtractor<VolumeType, MeshType, ControllerType>::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask, uint32_t uXRegSpace, uint32_t uYRegSpace)
|
||||
{
|
||||
uint8_t iCubeIndex = 0;
|
||||
|
||||
typename VolumeType::VoxelType v000;
|
||||
typename VolumeType::VoxelType v100;
|
||||
typename VolumeType::VoxelType v010;
|
||||
typename VolumeType::VoxelType v110;
|
||||
typename VolumeType::VoxelType v001;
|
||||
typename VolumeType::VoxelType v101;
|
||||
typename VolumeType::VoxelType v011;
|
||||
typename VolumeType::VoxelType v111;
|
||||
|
||||
if(isPrevZAvail)
|
||||
{
|
||||
if(isPrevYAvail)
|
||||
{
|
||||
if(isPrevXAvail)
|
||||
{
|
||||
v111 = m_sampVolume.peekVoxel1px1py1pz();
|
||||
|
||||
//z
|
||||
uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace);
|
||||
iPreviousCubeIndexZ >>= 4;
|
||||
|
||||
//y
|
||||
uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1);
|
||||
iPreviousCubeIndexY &= 192; //192 = 128 + 64
|
||||
iPreviousCubeIndexY >>= 2;
|
||||
|
||||
//x
|
||||
uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace);
|
||||
iPreviousCubeIndexX &= 128;
|
||||
iPreviousCubeIndexX >>= 1;
|
||||
|
||||
iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ;
|
||||
|
||||
if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
|
||||
}
|
||||
else //previous X not available
|
||||
{
|
||||
v011 = m_sampVolume.peekVoxel0px1py1pz();
|
||||
v111 = m_sampVolume.peekVoxel1px1py1pz();
|
||||
|
||||
//z
|
||||
uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace);
|
||||
iPreviousCubeIndexZ >>= 4;
|
||||
|
||||
//y
|
||||
uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1);
|
||||
iPreviousCubeIndexY &= 192; //192 = 128 + 64
|
||||
iPreviousCubeIndexY >>= 2;
|
||||
|
||||
iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ;
|
||||
|
||||
if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64;
|
||||
if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
|
||||
}
|
||||
}
|
||||
else //previous Y not available
|
||||
{
|
||||
if(isPrevXAvail)
|
||||
{
|
||||
v101 = m_sampVolume.peekVoxel1px0py1pz();
|
||||
v111 = m_sampVolume.peekVoxel1px1py1pz();
|
||||
|
||||
//z
|
||||
uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace);
|
||||
iPreviousCubeIndexZ >>= 4;
|
||||
|
||||
//x
|
||||
uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace);
|
||||
iPreviousCubeIndexX &= 160; //160 = 128+32
|
||||
iPreviousCubeIndexX >>= 1;
|
||||
|
||||
iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ;
|
||||
|
||||
if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32;
|
||||
if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
|
||||
}
|
||||
else //previous X not available
|
||||
{
|
||||
v001 = m_sampVolume.peekVoxel0px0py1pz();
|
||||
v101 = m_sampVolume.peekVoxel1px0py1pz();
|
||||
v011 = m_sampVolume.peekVoxel0px1py1pz();
|
||||
v111 = m_sampVolume.peekVoxel1px1py1pz();
|
||||
|
||||
//z
|
||||
uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace);
|
||||
iCubeIndex = iPreviousCubeIndexZ >> 4;
|
||||
|
||||
if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16;
|
||||
if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32;
|
||||
if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64;
|
||||
if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
else //previous Z not available
|
||||
{
|
||||
if(isPrevYAvail)
|
||||
{
|
||||
if(isPrevXAvail)
|
||||
{
|
||||
v110 = m_sampVolume.peekVoxel1px1py0pz();
|
||||
v111 = m_sampVolume.peekVoxel1px1py1pz();
|
||||
|
||||
//y
|
||||
uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1);
|
||||
iPreviousCubeIndexY &= 204; //204 = 128+64+8+4
|
||||
iPreviousCubeIndexY >>= 2;
|
||||
|
||||
//x
|
||||
uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace);
|
||||
iPreviousCubeIndexX &= 170; //170 = 128+32+8+2
|
||||
iPreviousCubeIndexX >>= 1;
|
||||
|
||||
iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY;
|
||||
|
||||
if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8;
|
||||
if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
|
||||
}
|
||||
else //previous X not available
|
||||
{
|
||||
v010 = m_sampVolume.peekVoxel0px1py0pz();
|
||||
v110 = m_sampVolume.peekVoxel1px1py0pz();
|
||||
|
||||
v011 = m_sampVolume.peekVoxel0px1py1pz();
|
||||
v111 = m_sampVolume.peekVoxel1px1py1pz();
|
||||
|
||||
//y
|
||||
uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1);
|
||||
iPreviousCubeIndexY &= 204; //204 = 128+64+8+4
|
||||
iPreviousCubeIndexY >>= 2;
|
||||
|
||||
iCubeIndex = iPreviousCubeIndexY;
|
||||
|
||||
if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4;
|
||||
if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8;
|
||||
if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64;
|
||||
if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
|
||||
}
|
||||
}
|
||||
else //previous Y not available
|
||||
{
|
||||
if(isPrevXAvail)
|
||||
{
|
||||
v100 = m_sampVolume.peekVoxel1px0py0pz();
|
||||
v110 = m_sampVolume.peekVoxel1px1py0pz();
|
||||
|
||||
v101 = m_sampVolume.peekVoxel1px0py1pz();
|
||||
v111 = m_sampVolume.peekVoxel1px1py1pz();
|
||||
|
||||
//x
|
||||
uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace);
|
||||
iPreviousCubeIndexX &= 170; //170 = 128+32+8+2
|
||||
iPreviousCubeIndexX >>= 1;
|
||||
|
||||
iCubeIndex = iPreviousCubeIndexX;
|
||||
|
||||
if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2;
|
||||
if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8;
|
||||
if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32;
|
||||
if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
|
||||
}
|
||||
else //previous X not available
|
||||
{
|
||||
v000 = m_sampVolume.getVoxel();
|
||||
v100 = m_sampVolume.peekVoxel1px0py0pz();
|
||||
v010 = m_sampVolume.peekVoxel0px1py0pz();
|
||||
v110 = m_sampVolume.peekVoxel1px1py0pz();
|
||||
|
||||
v001 = m_sampVolume.peekVoxel0px0py1pz();
|
||||
v101 = m_sampVolume.peekVoxel1px0py1pz();
|
||||
v011 = m_sampVolume.peekVoxel0px1py1pz();
|
||||
v111 = m_sampVolume.peekVoxel1px1py1pz();
|
||||
|
||||
if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1;
|
||||
if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2;
|
||||
if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4;
|
||||
if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8;
|
||||
if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16;
|
||||
if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32;
|
||||
if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64;
|
||||
if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Save the bitmask
|
||||
pCurrentBitmask(uXRegSpace, uYRegSpace) = iCubeIndex;
|
||||
|
||||
if(edgeTable[iCubeIndex] != 0)
|
||||
{
|
||||
++m_uNoOfOccupiedCells;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename ControllerType>
|
||||
void MarchingCubesSurfaceExtractor<VolumeType, MeshType, ControllerType>::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask,
|
||||
Array2DInt32& m_pCurrentVertexIndicesX,
|
||||
Array2DInt32& m_pCurrentVertexIndicesY,
|
||||
Array2DInt32& m_pCurrentVertexIndicesZ)
|
||||
{
|
||||
const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ();
|
||||
|
||||
//Iterate over each cell in the region
|
||||
for(int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= m_regSliceCurrent.getUpperY(); iYVolSpace++)
|
||||
{
|
||||
const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
|
||||
|
||||
for(int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= m_regSliceCurrent.getUpperX(); iXVolSpace++)
|
||||
{
|
||||
//Current position
|
||||
const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
|
||||
|
||||
//Determine the index into the edge table which tells us which vertices are inside of the surface
|
||||
const uint8_t iCubeIndex = pCurrentBitmask(uXRegSpace, uYRegSpace);
|
||||
|
||||
/* Cube is entirely in/out of the surface */
|
||||
if (edgeTable[iCubeIndex] == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//Check whether the generated vertex will lie on the edge of the region
|
||||
|
||||
|
||||
m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace);
|
||||
const typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel();
|
||||
const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume);
|
||||
|
||||
/* Find the vertices where the surface intersects the cube */
|
||||
if (edgeTable[iCubeIndex] & 1)
|
||||
{
|
||||
m_sampVolume.movePositiveX();
|
||||
const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel();
|
||||
POLYVOX_ASSERT(v000 != v100, "Attempting to insert vertex between two voxels with the same value");
|
||||
const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume);
|
||||
|
||||
const float fInterp = static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000));
|
||||
|
||||
const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()) + fInterp, static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast<float>(iZVolSpace - m_regSizeInCells.getLowerZ()));
|
||||
const Vector3DUint16 v3dScaledPosition(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
|
||||
|
||||
Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp));
|
||||
|
||||
// The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so
|
||||
// the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels).
|
||||
if(v3dNormal.lengthSquared() > 0.000001f)
|
||||
{
|
||||
v3dNormal.normalise();
|
||||
}
|
||||
|
||||
// Allow the controller to decide how the material should be derived from the voxels.
|
||||
const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v100, fInterp);
|
||||
|
||||
MarchingCubesVertex<typename VolumeType::VoxelType> surfaceVertex;
|
||||
surfaceVertex.encodedPosition = v3dScaledPosition;
|
||||
surfaceVertex.encodedNormal = encodeNormal(v3dNormal);
|
||||
surfaceVertex.data = uMaterial;
|
||||
|
||||
const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex);
|
||||
m_pCurrentVertexIndicesX(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY()) = uLastVertexIndex;
|
||||
|
||||
m_sampVolume.moveNegativeX();
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 8)
|
||||
{
|
||||
m_sampVolume.movePositiveY();
|
||||
const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel();
|
||||
POLYVOX_ASSERT(v000 != v010, "Attempting to insert vertex between two voxels with the same value");
|
||||
const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume);
|
||||
|
||||
const float fInterp = static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000));
|
||||
|
||||
const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()) + fInterp, static_cast<float>(iZVolSpace - m_regSizeInVoxels.getLowerZ()));
|
||||
const Vector3DUint16 v3dScaledPosition(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
|
||||
|
||||
Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp));
|
||||
|
||||
// The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so
|
||||
// the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels).
|
||||
if(v3dNormal.lengthSquared() > 0.000001f)
|
||||
{
|
||||
v3dNormal.normalise();
|
||||
}
|
||||
|
||||
// Allow the controller to decide how the material should be derived from the voxels.
|
||||
const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v010, fInterp);
|
||||
|
||||
MarchingCubesVertex<typename VolumeType::VoxelType> surfaceVertex;
|
||||
surfaceVertex.encodedPosition = v3dScaledPosition;
|
||||
surfaceVertex.encodedNormal = encodeNormal(v3dNormal);
|
||||
surfaceVertex.data = uMaterial;
|
||||
|
||||
uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex);
|
||||
m_pCurrentVertexIndicesY(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY()) = uLastVertexIndex;
|
||||
|
||||
m_sampVolume.moveNegativeY();
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 256)
|
||||
{
|
||||
m_sampVolume.movePositiveZ();
|
||||
const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel();
|
||||
POLYVOX_ASSERT(v000 != v001, "Attempting to insert vertex between two voxels with the same value");
|
||||
const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume);
|
||||
|
||||
const float fInterp = static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000));
|
||||
|
||||
const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast<float>(iZVolSpace - m_regSizeInVoxels.getLowerZ()) + fInterp);
|
||||
const Vector3DUint16 v3dScaledPosition(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
|
||||
|
||||
Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp));
|
||||
// The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so
|
||||
// the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels).
|
||||
if(v3dNormal.lengthSquared() > 0.000001f)
|
||||
{
|
||||
v3dNormal.normalise();
|
||||
}
|
||||
|
||||
// Allow the controller to decide how the material should be derived from the voxels.
|
||||
const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v001, fInterp);
|
||||
|
||||
MarchingCubesVertex<typename VolumeType::VoxelType> surfaceVertex;
|
||||
surfaceVertex.encodedPosition = v3dScaledPosition;
|
||||
surfaceVertex.encodedNormal = encodeNormal(v3dNormal);
|
||||
surfaceVertex.data = uMaterial;
|
||||
|
||||
const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex);
|
||||
m_pCurrentVertexIndicesZ(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY()) = uLastVertexIndex;
|
||||
|
||||
m_sampVolume.moveNegativeZ();
|
||||
}
|
||||
}//For each cell
|
||||
}
|
||||
}
|
||||
|
||||
template<typename VolumeType, typename MeshType, typename ControllerType>
|
||||
void MarchingCubesSurfaceExtractor<VolumeType, MeshType, ControllerType>::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask,
|
||||
const Array2DInt32& m_pPreviousVertexIndicesX,
|
||||
const Array2DInt32& m_pPreviousVertexIndicesY,
|
||||
const Array2DInt32& m_pPreviousVertexIndicesZ,
|
||||
const Array2DInt32& m_pCurrentVertexIndicesX,
|
||||
const Array2DInt32& m_pCurrentVertexIndicesY)
|
||||
{
|
||||
int32_t indlist[12];
|
||||
for(int i = 0; i < 12; i++)
|
||||
{
|
||||
indlist[i] = -1;
|
||||
}
|
||||
|
||||
const int32_t iZVolSpace = m_regSlicePrevious.getLowerZ();
|
||||
|
||||
for(int32_t iYVolSpace = m_regSlicePrevious.getLowerY(); iYVolSpace <= m_regSizeInCells.getUpperY(); iYVolSpace++)
|
||||
{
|
||||
for(int32_t iXVolSpace = m_regSlicePrevious.getLowerX(); iXVolSpace <= m_regSizeInCells.getUpperX(); iXVolSpace++)
|
||||
{
|
||||
m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace);
|
||||
|
||||
//Current position
|
||||
const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerX();
|
||||
const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerY();
|
||||
|
||||
//Determine the index into the edge table which tells us which vertices are inside of the surface
|
||||
const uint8_t iCubeIndex = pPreviousBitmask(uXRegSpace, uYRegSpace);
|
||||
|
||||
/* 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] = m_pPreviousVertexIndicesX(uXRegSpace, uYRegSpace);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 2)
|
||||
{
|
||||
indlist[1] = m_pPreviousVertexIndicesY(uXRegSpace + 1, uYRegSpace);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 4)
|
||||
{
|
||||
indlist[2] = m_pPreviousVertexIndicesX(uXRegSpace, uYRegSpace + 1);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 8)
|
||||
{
|
||||
indlist[3] = m_pPreviousVertexIndicesY(uXRegSpace, uYRegSpace);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 16)
|
||||
{
|
||||
indlist[4] = m_pCurrentVertexIndicesX(uXRegSpace, uYRegSpace);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 32)
|
||||
{
|
||||
indlist[5] = m_pCurrentVertexIndicesY(uXRegSpace + 1, uYRegSpace);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 64)
|
||||
{
|
||||
indlist[6] = m_pCurrentVertexIndicesX(uXRegSpace, uYRegSpace + 1);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 128)
|
||||
{
|
||||
indlist[7] = m_pCurrentVertexIndicesY(uXRegSpace, uYRegSpace);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 256)
|
||||
{
|
||||
indlist[8] = m_pPreviousVertexIndicesZ(uXRegSpace, uYRegSpace);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 512)
|
||||
{
|
||||
indlist[9] = m_pPreviousVertexIndicesZ(uXRegSpace + 1, uYRegSpace);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 1024)
|
||||
{
|
||||
indlist[10] = m_pPreviousVertexIndicesZ(uXRegSpace + 1, uYRegSpace + 1);
|
||||
}
|
||||
if (edgeTable[iCubeIndex] & 2048)
|
||||
{
|
||||
indlist[11] = m_pPreviousVertexIndicesZ(uXRegSpace, uYRegSpace + 1);
|
||||
}
|
||||
|
||||
for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3)
|
||||
{
|
||||
const int32_t ind0 = indlist[triTable[iCubeIndex][i ]];
|
||||
const int32_t ind1 = indlist[triTable[iCubeIndex][i+1]];
|
||||
const int32_t ind2 = indlist[triTable[iCubeIndex][i+2]];
|
||||
|
||||
if((ind0 != -1) && (ind1 != -1) && (ind2 != -1))
|
||||
{
|
||||
m_meshCurrent->addTriangle(ind0, ind1, ind2);
|
||||
}
|
||||
}//For each triangle
|
||||
}//For each cell
|
||||
}
|
||||
}
|
||||
}
|
91
include/PolyVoxCore/include/PolyVoxCore/Material.h
Normal file
91
include/PolyVoxCore/include/PolyVoxCore/Material.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Material_H__
|
||||
#define __PolyVox_Material_H__
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include "PolyVoxCore/DefaultIsQuadNeeded.h" //we'll specialise this function for this voxel type
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
///This class represents a voxel storing only a material.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Detailed description...
|
||||
///
|
||||
/// \sa Density, MaterialDensityPair
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Type>
|
||||
class Material
|
||||
{
|
||||
public:
|
||||
Material() : m_uMaterial(0) {}
|
||||
Material(Type uMaterial) : m_uMaterial(uMaterial) {}
|
||||
|
||||
bool operator==(const Material& rhs) const
|
||||
{
|
||||
return (m_uMaterial == rhs.m_uMaterial);
|
||||
};
|
||||
|
||||
bool operator!=(const Material& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
/// \return The current material value of the voxel
|
||||
Type getMaterial() const { return m_uMaterial; }
|
||||
/**
|
||||
* Set the material value of the voxel
|
||||
*
|
||||
* \param uMaterial The material to set to
|
||||
*/
|
||||
void setMaterial(Type uMaterial) { m_uMaterial = uMaterial; }
|
||||
|
||||
private:
|
||||
Type m_uMaterial;
|
||||
};
|
||||
|
||||
typedef Material<uint8_t> Material8;
|
||||
typedef Material<uint16_t> Material16;
|
||||
|
||||
template<typename Type>
|
||||
class DefaultIsQuadNeeded< Material<Type> >
|
||||
{
|
||||
public:
|
||||
bool operator()(Material<Type> back, Material<Type> front, Material<Type>& materialToUse)
|
||||
{
|
||||
if((back.getMaterial() > 0) && (front.getMaterial() == 0))
|
||||
{
|
||||
materialToUse = back;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //__PolyVox_Material_H__
|
165
include/PolyVoxCore/include/PolyVoxCore/MaterialDensityPair.h
Normal file
165
include/PolyVoxCore/include/PolyVoxCore/MaterialDensityPair.h
Normal file
@ -0,0 +1,165 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_MaterialDensityPair_H__
|
||||
#define __PolyVox_MaterialDensityPair_H__
|
||||
|
||||
#include "PolyVoxCore/DefaultIsQuadNeeded.h" //we'll specialise this function for this voxel type
|
||||
#include "PolyVoxCore/DefaultMarchingCubesController.h" //We'll specialise the controller contained in here
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/// This class represents a voxel storing only a density.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Detailed description...
|
||||
///
|
||||
/// \sa Density, Material
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
|
||||
class MaterialDensityPair
|
||||
{
|
||||
public:
|
||||
MaterialDensityPair() : m_uMaterial(0), m_uDensity(0) {}
|
||||
MaterialDensityPair(Type uMaterial, Type uDensity) : m_uMaterial(uMaterial), m_uDensity(uDensity) {}
|
||||
|
||||
bool operator==(const MaterialDensityPair& rhs) const
|
||||
{
|
||||
return (m_uMaterial == rhs.m_uMaterial) && (m_uDensity == rhs.m_uDensity);
|
||||
};
|
||||
|
||||
bool operator!=(const MaterialDensityPair& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& operator+=(const MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& rhs)
|
||||
{
|
||||
m_uDensity += rhs.m_uDensity;
|
||||
|
||||
// What should we do with the material? Conceptually the idea of adding materials makes no sense, but for our
|
||||
// purposes we consider the 'sum' of two materials to just be the max. At least this way it is commutative.
|
||||
m_uMaterial = (std::max)(m_uMaterial, rhs.m_uMaterial);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& operator/=(uint32_t rhs)
|
||||
{
|
||||
// There's nothing sensible we can do with the material, so this function only affects the density.
|
||||
m_uDensity /= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type getDensity() const { return m_uDensity; }
|
||||
Type getMaterial() const { return m_uMaterial; }
|
||||
|
||||
void setDensity(Type uDensity) { m_uDensity = uDensity; }
|
||||
void setMaterial(Type uMaterial) { m_uMaterial = uMaterial; }
|
||||
|
||||
static Type getMaxDensity() { return (0x01 << NoOfDensityBits) - 1; }
|
||||
static Type getMinDensity() { return 0; }
|
||||
|
||||
private:
|
||||
Type m_uMaterial : NoOfMaterialBits;
|
||||
Type m_uDensity : NoOfDensityBits;
|
||||
};
|
||||
|
||||
template<typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
|
||||
class DefaultIsQuadNeeded< MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> >
|
||||
{
|
||||
public:
|
||||
bool operator()(MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> back, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> front, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& materialToUse)
|
||||
{
|
||||
if((back.getMaterial() > 0) && (front.getMaterial() == 0))
|
||||
{
|
||||
materialToUse = back;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
|
||||
class DefaultMarchingCubesController< MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> >
|
||||
{
|
||||
public:
|
||||
typedef Type DensityType;
|
||||
typedef Type MaterialType;
|
||||
|
||||
DefaultMarchingCubesController(void)
|
||||
{
|
||||
// Default to a threshold value halfway between the min and max possible values.
|
||||
m_tThreshold = (MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::getMinDensity() + MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::getMaxDensity()) / 2;
|
||||
}
|
||||
|
||||
DefaultMarchingCubesController(DensityType tThreshold)
|
||||
{
|
||||
m_tThreshold = tThreshold;
|
||||
}
|
||||
|
||||
DensityType convertToDensity(MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> voxel)
|
||||
{
|
||||
return voxel.getDensity();
|
||||
}
|
||||
|
||||
MaterialType convertToMaterial(MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> voxel)
|
||||
{
|
||||
return voxel.getMaterial();
|
||||
}
|
||||
|
||||
MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> blendMaterials(MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> a, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> b, float /*weight*/)
|
||||
{
|
||||
if(convertToDensity(a) > convertToDensity(b))
|
||||
{
|
||||
return a;
|
||||
}
|
||||
else
|
||||
{
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
DensityType getThreshold(void)
|
||||
{
|
||||
return m_tThreshold;
|
||||
}
|
||||
|
||||
void setThreshold(DensityType tThreshold)
|
||||
{
|
||||
m_tThreshold = tThreshold;
|
||||
}
|
||||
|
||||
private:
|
||||
DensityType m_tThreshold;
|
||||
};
|
||||
|
||||
typedef MaterialDensityPair<uint8_t, 4, 4> MaterialDensityPair44;
|
||||
typedef MaterialDensityPair<uint16_t, 8, 8> MaterialDensityPair88;
|
||||
}
|
||||
|
||||
#endif
|
103
include/PolyVoxCore/include/PolyVoxCore/Mesh.h
Normal file
103
include/PolyVoxCore/include/PolyVoxCore/Mesh.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Mesh_H__
|
||||
#define __PolyVox_Mesh_H__
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include "PolyVoxCore/PolyVoxForwardDeclarations.h"
|
||||
#include "PolyVoxCore/Region.h"
|
||||
#include "PolyVoxCore/Vertex.h" //Should probably do away with this on in the future...
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename _VertexType, typename _IndexType>
|
||||
class Mesh
|
||||
{
|
||||
public:
|
||||
|
||||
typedef _VertexType VertexType;
|
||||
typedef _IndexType IndexType;
|
||||
|
||||
Mesh();
|
||||
~Mesh();
|
||||
|
||||
IndexType getNoOfVertices(void) const;
|
||||
const VertexType& getVertex(IndexType index) const;
|
||||
const VertexType* getRawVertexData(void) const;
|
||||
POLYVOX_DEPRECATED const std::vector<VertexType>& getVertices(void) const;
|
||||
|
||||
uint32_t getNoOfIndices(void) const;
|
||||
IndexType getIndex(uint32_t index) const;
|
||||
const IndexType* getRawIndexData(void);
|
||||
POLYVOX_DEPRECATED const std::vector<IndexType>& getIndices(void) const;
|
||||
|
||||
const Vector3DInt32& getOffset(void) const;
|
||||
void setOffset(const Vector3DInt32& offset);
|
||||
|
||||
IndexType addVertex(const VertexType& vertex);
|
||||
void addTriangle(IndexType index0, IndexType index1, IndexType index2);
|
||||
|
||||
void clear(void);
|
||||
bool isEmpty(void) const;
|
||||
void removeUnusedVertices(void);
|
||||
|
||||
private:
|
||||
std::vector<IndexType> m_vecIndices;
|
||||
std::vector<VertexType> m_vecVertices;
|
||||
Vector3DInt32 m_offset;
|
||||
};
|
||||
|
||||
template <typename MeshType>
|
||||
Mesh< Vertex< typename MeshType::VertexType::DataType >, typename MeshType::IndexType > decodeMesh(const MeshType& encodedMesh)
|
||||
{
|
||||
Mesh< Vertex< typename MeshType::VertexType::DataType >, typename MeshType::IndexType > decodedMesh;
|
||||
|
||||
for (typename MeshType::IndexType ct = 0; ct < encodedMesh.getNoOfVertices(); ct++)
|
||||
{
|
||||
decodedMesh.addVertex(decodeVertex(encodedMesh.getVertex(ct)));
|
||||
}
|
||||
|
||||
POLYVOX_ASSERT(encodedMesh.getNoOfIndices() % 3 == 0, "The number of indices must always be a multiple of three.");
|
||||
for (uint32_t ct = 0; ct < encodedMesh.getNoOfIndices(); ct += 3)
|
||||
{
|
||||
decodedMesh.addTriangle(encodedMesh.getIndex(ct), encodedMesh.getIndex(ct + 1), encodedMesh.getIndex(ct + 2));
|
||||
}
|
||||
|
||||
decodedMesh.setOffset(encodedMesh.getOffset());
|
||||
|
||||
return decodedMesh;
|
||||
}
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/Mesh.inl"
|
||||
|
||||
#endif /* __Mesh_H__ */
|
163
include/PolyVoxCore/include/PolyVoxCore/Mesh.inl
Normal file
163
include/PolyVoxCore/include/PolyVoxCore/Mesh.inl
Normal file
@ -0,0 +1,163 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename VertexType, typename IndexType>
|
||||
Mesh<VertexType, IndexType>::Mesh()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
Mesh<VertexType, IndexType>::~Mesh()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
IndexType Mesh<VertexType, IndexType>::getNoOfVertices(void) const
|
||||
{
|
||||
return m_vecVertices.size();
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
const VertexType& Mesh<VertexType, IndexType>::getVertex(IndexType index) const
|
||||
{
|
||||
return m_vecVertices[index];
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
const VertexType* Mesh<VertexType, IndexType>::getRawVertexData(void) const
|
||||
{
|
||||
return &(m_vecVertices[0]);
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
const std::vector<VertexType>& Mesh<VertexType, IndexType>::getVertices(void) const
|
||||
{
|
||||
return m_vecVertices;
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
uint32_t Mesh<VertexType, IndexType>::getNoOfIndices(void) const
|
||||
{
|
||||
return m_vecIndices.size();
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
IndexType Mesh<VertexType, IndexType>::getIndex(uint32_t index) const
|
||||
{
|
||||
return m_vecIndices[index];
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
const IndexType* Mesh<VertexType, IndexType>::getRawIndexData(void)
|
||||
{
|
||||
return &(m_vecIndices[0]);
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
const std::vector<IndexType>& Mesh<VertexType, IndexType>::getIndices(void) const
|
||||
{
|
||||
return m_vecIndices;
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
const Vector3DInt32& Mesh<VertexType, IndexType>::getOffset(void) const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
void Mesh<VertexType, IndexType>::setOffset(const Vector3DInt32& offset)
|
||||
{
|
||||
m_offset = offset;
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
void Mesh<VertexType, IndexType>::addTriangle(IndexType index0, IndexType index1, IndexType index2)
|
||||
{
|
||||
//Make sure the specified indices correspond to valid vertices.
|
||||
POLYVOX_ASSERT(index0 < m_vecVertices.size(), "Index points at an invalid vertex.");
|
||||
POLYVOX_ASSERT(index1 < m_vecVertices.size(), "Index points at an invalid vertex.");
|
||||
POLYVOX_ASSERT(index2 < m_vecVertices.size(), "Index points at an invalid vertex.");
|
||||
|
||||
m_vecIndices.push_back(index0);
|
||||
m_vecIndices.push_back(index1);
|
||||
m_vecIndices.push_back(index2);
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
IndexType Mesh<VertexType, IndexType>::addVertex(const VertexType& vertex)
|
||||
{
|
||||
// We should not add more vertices than our chosen index type will let us index.
|
||||
POLYVOX_THROW_IF(m_vecVertices.size() >= std::numeric_limits<IndexType>::max(), std::out_of_range, "Mesh has more vertices that the chosen index type allows.");
|
||||
|
||||
m_vecVertices.push_back(vertex);
|
||||
return m_vecVertices.size() - 1;
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
void Mesh<VertexType, IndexType>::clear(void)
|
||||
{
|
||||
m_vecVertices.clear();
|
||||
m_vecIndices.clear();
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
bool Mesh<VertexType, IndexType>::isEmpty(void) const
|
||||
{
|
||||
return (getNoOfVertices() == 0) || (getNoOfIndices() == 0);
|
||||
}
|
||||
|
||||
template <typename VertexType, typename IndexType>
|
||||
void Mesh<VertexType, IndexType>::removeUnusedVertices(void)
|
||||
{
|
||||
std::vector<bool> isVertexUsed(m_vecVertices.size());
|
||||
std::fill(isVertexUsed.begin(), isVertexUsed.end(), false);
|
||||
|
||||
for(uint32_t triCt = 0; triCt < m_vecIndices.size(); triCt++)
|
||||
{
|
||||
int v = m_vecIndices[triCt];
|
||||
isVertexUsed[v] = true;
|
||||
}
|
||||
|
||||
int noOfUsedVertices = 0;
|
||||
std::vector<uint32_t> newPos(m_vecVertices.size());
|
||||
for(IndexType vertCt = 0; vertCt < m_vecVertices.size(); vertCt++)
|
||||
{
|
||||
if(isVertexUsed[vertCt])
|
||||
{
|
||||
m_vecVertices[noOfUsedVertices] = m_vecVertices[vertCt];
|
||||
newPos[vertCt] = noOfUsedVertices;
|
||||
noOfUsedVertices++;
|
||||
}
|
||||
}
|
||||
|
||||
m_vecVertices.resize(noOfUsedVertices);
|
||||
|
||||
for(uint32_t triCt = 0; triCt < m_vecIndices.size(); triCt++)
|
||||
{
|
||||
m_vecIndices[triCt] = newPos[m_vecIndices[triCt]];
|
||||
}
|
||||
}
|
||||
}
|
366
include/PolyVoxCore/include/PolyVoxCore/PagedVolume.h
Normal file
366
include/PolyVoxCore/include/PolyVoxCore/PagedVolume.h
Normal file
@ -0,0 +1,366 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_PagedVolume_H__
|
||||
#define __PolyVox_PagedVolume_H__
|
||||
|
||||
#include "PolyVoxCore/BaseVolume.h"
|
||||
#include "PolyVoxCore/Region.h"
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
#include <limits>
|
||||
#include <cstdlib> //For abort()
|
||||
#include <cstring> //For memcpy
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept> //For invalid_argument
|
||||
#include <vector>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/// The PagedVolume class provides a memory efficient method of storing voxel data while also allowing fast access and modification.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// A PagedVolume is essentially a 3D array in which each element (or <i>voxel</i>) is identified by a three dimensional (x,y,z) coordinate.
|
||||
/// We use the PagedVolume class to store our data in an efficient way, and it is the input to many of the algorithms (such as the surface
|
||||
/// extractors) which form the heart of PolyVox. The PagedVolume class is templatised so that different types of data can be stored within each voxel.
|
||||
///
|
||||
/// Basic usage
|
||||
/// -----------
|
||||
///
|
||||
/// The following code snippet shows how to construct a volume and demonstrates basic usage:
|
||||
///
|
||||
/// \code
|
||||
/// PagedVolume<int> volume(Region(Vector3DInt32(0,0,0), Vector3DInt32(63,127,255)));
|
||||
/// volume.setVoxel(15, 90, 42, int(5));
|
||||
/// std::cout << "Voxel at (15, 90, 42) has value: " << volume.getVoxel(15, 90, 42) << std::endl;
|
||||
/// std::cout << "Width = " << volume.getWidth() << ", Height = " << volume.getHeight() << ", Depth = " << volume.getDepth() << std::endl;
|
||||
/// \endcode
|
||||
///
|
||||
/// The PagedVolume constructor takes a Region as a parameter. This specifies the valid range of voxels which can be held in the volume, so in this
|
||||
/// particular case the valid voxel positions are (0,0,0) to (63, 127, 255). The result of attempts to access voxels outside this range will result
|
||||
/// are defined by the WrapMode). PolyVox also has support for near infinite volumes which will be discussed later.
|
||||
///
|
||||
/// Access to individual voxels is provided via the setVoxel() and getVoxel() member functions. Advanced users may also be interested in
|
||||
/// the Sampler nested class for faster read-only access to a large number of voxels.
|
||||
///
|
||||
/// Lastly the example prints out some properties of the PagedVolume. Note that the dimentsions getWidth(), getHeight(), and getDepth() are inclusive, such
|
||||
/// that the width is 64 when the range of valid x coordinates goes from 0 to 63.
|
||||
///
|
||||
/// Data Representaion
|
||||
/// ------------------
|
||||
/// If stored carelessly, volume data can take up a huge amount of memory. For example, a volume of dimensions 1024x1024x1024 with
|
||||
/// 1 byte per voxel will require 1GB of memory if stored in an uncompressed form. Natuarally our PagedVolume class is much more efficient
|
||||
/// than this and it is worth understanding (at least at a high level) the approach which is used.
|
||||
///
|
||||
/// Essentially, the PagedVolume class stores its data as a collection of chunks. Each of these chunk is much smaller than the whole volume,
|
||||
/// for example a typical size might be 32x32x32 voxels (though is is configurable by the user). In this case, a 256x512x1024 volume
|
||||
/// would contain 8x16x32 = 4096 chunks. Typically these chunks do not need to all be in memory all the time, and the Pager class can
|
||||
/// be used to control how they are loaded and unloaded. This mechanism allows a
|
||||
/// potentially unlimited amount of data to be loaded, provided the user is able to take responsibility for storing any data which PolyVox
|
||||
/// cannot fit in memory, and then returning it back to PolyVox on demand. For example, the user might choose to temporarily store this data
|
||||
/// on disk or stream it to a remote database.
|
||||
///
|
||||
/// Essentially you are providing an extension to the PagedVolume class - a way for data to be stored once PolyVox has run out of memory for it. Note
|
||||
/// that you don't actually have to do anything with the data - you could simply decide that once it gets removed from memory it doesn't matter
|
||||
/// anymore.
|
||||
///
|
||||
/// Cache-aware traversal
|
||||
/// ---------------------
|
||||
/// *NOTE: This needs updating for PagedVolume rather than the old LargeVolume*
|
||||
/// You might be suprised at just how many cache misses can occur when you traverse the volume in a naive manner. Consider a 1024x1024x1024 volume
|
||||
/// with chunks of size 32x32x32. And imagine you iterate over this volume with a simple three-level for loop which iterates over x, the y, then z.
|
||||
/// If you start at position (0,0,0) then ny the time you reach position (1023,0,0) you have touched 1024 voxels along one edge of the volume and
|
||||
/// have pulled 32 chunks into the cache. By the time you reach (1023,1023,0) you have hit 1024x1024 voxels and pulled 32x32 chunks into the cache.
|
||||
/// You are now ready to touch voxel (0,0,1) which is right next to where you started, but unless your cache is at least 32x32 chunks large then this
|
||||
/// initial chunk has already been cleared from the cache.
|
||||
///
|
||||
/// Ensuring you have a large enough cache size can obviously help the above situation, but you might also consider iterating over the voxels in a
|
||||
/// different order. For example, if you replace your three-level loop with a six-level loop then you can first process all the voxels between (0,0,0)
|
||||
/// and (31,31,31), then process all the voxels between (32,0,0) and (63,0,0), and so forth. Using this approach you will have no cache misses even
|
||||
/// is your cache size is only one. Of course the logic is more complex, but writing code in such a cache-aware manner may be beneficial in some situations.
|
||||
///
|
||||
/// Threading
|
||||
/// ---------
|
||||
/// The PagedVolume class does not make any guarentees about thread safety. You should ensure that all accesses are performed from the same thread.
|
||||
/// This is true even if you are only reading data from the volume, as concurrently reading from different threads can invalidate the contents
|
||||
/// of the chunk cache (amoung other problems).
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
class PagedVolume : public BaseVolume<VoxelType>
|
||||
{
|
||||
public:
|
||||
/// The PagedVolume stores it data as a set of Chunk instances which can be loaded and unloaded as memory requirements dictate.
|
||||
class Chunk;
|
||||
/// The Pager class is responsible for the loading and unloading of Chunks, and can be overridden by the user.
|
||||
class Pager;
|
||||
|
||||
class Chunk
|
||||
{
|
||||
friend class PagedVolume;
|
||||
|
||||
public:
|
||||
Chunk(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager* pPager = nullptr);
|
||||
~Chunk();
|
||||
|
||||
VoxelType* getData(void) const;
|
||||
uint32_t getDataSizeInBytes(void) const;
|
||||
|
||||
VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const;
|
||||
VoxelType getVoxel(const Vector3DUint16& v3dPos) const;
|
||||
|
||||
void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue);
|
||||
void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);
|
||||
|
||||
private:
|
||||
/// Private copy constructor to prevent accisdental copying
|
||||
Chunk(const Chunk& /*rhs*/) {};
|
||||
|
||||
/// Private assignment operator to prevent accisdental copying
|
||||
Chunk& operator=(const Chunk& /*rhs*/) {};
|
||||
|
||||
// This is updated by the PagedVolume and used to discard the least recently used chunks.
|
||||
uint32_t m_uChunkLastAccessed;
|
||||
|
||||
// This is so we can tell whether a uncompressed chunk has to be recompressed and whether
|
||||
// a compressed chunk has to be paged back to disk, or whether they can just be discarded.
|
||||
bool m_bDataModified;
|
||||
|
||||
uint32_t calculateSizeInBytes(void);
|
||||
static uint32_t calculateSizeInBytes(uint32_t uSideLength);
|
||||
|
||||
VoxelType* m_tData;
|
||||
uint16_t m_uSideLength;
|
||||
uint8_t m_uSideLengthPower;
|
||||
Pager* m_pPager;
|
||||
|
||||
// Note: Do we really need to store this position here as well as in the block maps?
|
||||
Vector3DInt32 m_v3dChunkSpacePosition;
|
||||
};
|
||||
|
||||
/**
|
||||
* Users can override this class and provide an instance of the derived class to the PagedVolume constructor. This derived class
|
||||
* could then perform tasks such as compression and decompression of the data, and read/writing it to a file, database, network,
|
||||
* or other storage as appropriate. See FilePager for a simple example of such a derived class.
|
||||
*/
|
||||
class Pager
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
Pager() {};
|
||||
/// Destructor
|
||||
virtual ~Pager() {};
|
||||
|
||||
virtual void pageIn(const Region& region, Chunk* pChunk) = 0;
|
||||
virtual void pageOut(const Region& region, Chunk* pChunk) = 0;
|
||||
};
|
||||
|
||||
//There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared.
|
||||
//There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but
|
||||
//which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler
|
||||
//option. For now it seems best to 'fix' it with the preprocessor insstead, but maybe the workaround can be reinstated
|
||||
//in the future
|
||||
//typedef Volume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences.
|
||||
//class Sampler : public VolumeOfVoxelType::template Sampler< PagedVolume<VoxelType> >
|
||||
#ifndef SWIG
|
||||
#if defined(_MSC_VER)
|
||||
class Sampler : public BaseVolume<VoxelType>::Sampler< PagedVolume<VoxelType> > //This line works on VS2010
|
||||
#else
|
||||
class Sampler : public BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> > //This line works on GCC
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
Sampler(PagedVolume<VoxelType>* volume);
|
||||
~Sampler();
|
||||
|
||||
/// \deprecated
|
||||
POLYVOX_DEPRECATED VoxelType getSubSampledVoxel(uint8_t uLevel) const;
|
||||
inline VoxelType getVoxel(void) const;
|
||||
|
||||
void setPosition(const Vector3DInt32& v3dNewPos);
|
||||
void setPosition(int32_t xPos, int32_t yPos, int32_t zPos);
|
||||
inline bool setVoxel(VoxelType tValue);
|
||||
|
||||
void movePositiveX(void);
|
||||
void movePositiveY(void);
|
||||
void movePositiveZ(void);
|
||||
|
||||
void moveNegativeX(void);
|
||||
void moveNegativeY(void);
|
||||
void moveNegativeZ(void);
|
||||
|
||||
inline VoxelType peekVoxel1nx1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py1pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py1pz(void) const;
|
||||
|
||||
inline VoxelType peekVoxel0px1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel0px1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel0px1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel0px0py1nz(void) const;
|
||||
inline VoxelType peekVoxel0px0py0pz(void) const;
|
||||
inline VoxelType peekVoxel0px0py1pz(void) const;
|
||||
inline VoxelType peekVoxel0px1py1nz(void) const;
|
||||
inline VoxelType peekVoxel0px1py0pz(void) const;
|
||||
inline VoxelType peekVoxel0px1py1pz(void) const;
|
||||
|
||||
inline VoxelType peekVoxel1px1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel1px1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel1px1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel1px0py1nz(void) const;
|
||||
inline VoxelType peekVoxel1px0py0pz(void) const;
|
||||
inline VoxelType peekVoxel1px0py1pz(void) const;
|
||||
inline VoxelType peekVoxel1px1py1nz(void) const;
|
||||
inline VoxelType peekVoxel1px1py0pz(void) const;
|
||||
inline VoxelType peekVoxel1px1py1pz(void) const;
|
||||
|
||||
private:
|
||||
//Other current position information
|
||||
VoxelType* mCurrentVoxel;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// Constructor for creating a fixed size volume.
|
||||
PagedVolume
|
||||
(
|
||||
const Region& regValid,
|
||||
Pager* pPager = nullptr,
|
||||
uint16_t uChunkSideLength = 32
|
||||
);
|
||||
/// Destructor
|
||||
~PagedVolume();
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const;
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
|
||||
|
||||
/// Sets the number of chunks for which uncompressed data is stored
|
||||
void setMemoryUsageLimit(uint32_t uMemoryUsageInBytes);
|
||||
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate);
|
||||
/// Sets the voxel at the position given by a 3D vector
|
||||
void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate);
|
||||
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
|
||||
/// Sets the voxel at the position given by a 3D vector
|
||||
bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue);
|
||||
/// Tries to ensure that the voxels within the specified Region are loaded into memory.
|
||||
void prefetch(Region regPrefetch);
|
||||
/// Ensures that any voxels within the specified Region are removed from memory.
|
||||
void flush(Region regFlush);
|
||||
/// Removes all voxels from memory
|
||||
void flushAll();
|
||||
|
||||
/// Calculates approximatly how many bytes of memory the volume is currently using.
|
||||
uint32_t calculateSizeInBytes(void);
|
||||
|
||||
protected:
|
||||
/// Copy constructor
|
||||
PagedVolume(const PagedVolume& rhs);
|
||||
|
||||
/// Assignment operator
|
||||
PagedVolume& operator=(const PagedVolume& rhs);
|
||||
|
||||
private:
|
||||
|
||||
// FIXME - We can probably ove this into the constructor
|
||||
void initialise();
|
||||
|
||||
// A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const;
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const;
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const;
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const;
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType tBorder) const;
|
||||
|
||||
std::shared_ptr<Chunk> getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const;
|
||||
|
||||
void purgeNullPtrsFromAllChunks(void) const;
|
||||
|
||||
// The chunk data is stored in the pair of maps below. This will often hold the same set of chunks but there are occasions
|
||||
// when they can differ (more on that in a moment). The main store is the set of 'recently used chunks' which holds shared_ptr's
|
||||
// to the chunk data. When memory is low chunks can be removed from this list and, assuming there are no more references to
|
||||
// them, they will be deleted. However, it is also possible that a Sampler is pointing at a given chunk, and in this case the
|
||||
// reference counting will ensure that the chunk survives until the sampler has finished with it.
|
||||
//
|
||||
// However, this leaves us open to a subtle bug. If a chunk is removed from the recently used set, continues to exist due to a
|
||||
// sampler using it, and then the user tries to access it through the volume interface, then the volume will page the chunk
|
||||
// back in (not knowing the sampler still has it). This would result in two chunks in memory with the same position is space.
|
||||
// To avoid this, the 'all chunks' set tracks chunks with are used by the volume *and/or* the samplers. It holds weak pointers
|
||||
// so does not cause chunks to persist.
|
||||
//
|
||||
// TODO: Do we really need maps here? It means we are storing the chunk positions in the map, but they are also stored in the
|
||||
// chunks themselves (so they can be passed to the pager from the chunks destructor). Can we use a set here? What is a better approach?
|
||||
typedef std::unordered_map<Vector3DInt32, std::weak_ptr< Chunk > > WeakPtrChunkMap;
|
||||
mutable WeakPtrChunkMap m_pAllChunks;
|
||||
typedef std::unordered_map<Vector3DInt32, std::shared_ptr< Chunk > > SharedPtrChunkMap;
|
||||
mutable SharedPtrChunkMap m_pRecentlyUsedChunks;
|
||||
|
||||
mutable uint32_t m_uTimestamper;
|
||||
mutable Vector3DInt32 m_v3dLastAccessedChunkPos;
|
||||
mutable std::shared_ptr<Chunk> m_pLastAccessedChunk;
|
||||
uint32_t m_uChunkCountLimit;
|
||||
|
||||
// The size of the volume
|
||||
Region m_regValidRegionInChunks;
|
||||
|
||||
// The size of the chunks
|
||||
uint16_t m_uChunkSideLength;
|
||||
uint8_t m_uChunkSideLengthPower;
|
||||
|
||||
Pager* m_pPager;
|
||||
|
||||
// Enough to make sure a chunks and it's neighbours can be loaded, with a few to spare.
|
||||
const uint32_t uMinPracticalNoOfChunks = 32;
|
||||
// Should prevent multi-gigabyte volumes when chunk sizes are reasonable.
|
||||
const uint32_t uMaxPracticalNoOfChunks = 32768;
|
||||
};
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/PagedVolume.inl"
|
||||
#include "PolyVoxCore/PagedVolumeChunk.inl"
|
||||
#include "PolyVoxCore/PagedVolumeSampler.inl"
|
||||
|
||||
#endif //__PolyVox_PagedVolume_H__
|
698
include/PolyVoxCore/include/PolyVoxCore/PagedVolume.inl
Normal file
698
include/PolyVoxCore/include/PolyVoxCore/PagedVolume.inl
Normal file
@ -0,0 +1,698 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/Impl/ErrorHandling.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This constructor creates a volume with a fixed size which is specified as a parameter. By default this constructor will not enable paging but you can override this if desired. If you do wish to enable paging then you are required to provide the call back function (see the other PagedVolume constructor).
|
||||
/// \param regValid Specifies the minimum and maximum valid voxel positions.
|
||||
/// \param dataRequiredHandler The callback function which will be called when PolyVox tries to use data which is not currently in momory.
|
||||
/// \param dataOverflowHandler The callback function which will be called when PolyVox has too much data and needs to remove some from memory.
|
||||
/// \param bPagingEnabled Controls whether or not paging is enabled for this PagedVolume.
|
||||
/// \param uChunkSideLength The size of the chunks making up the volume. Small chunks will compress/decompress faster, but there will also be more of them meaning voxel access could be slower.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
PagedVolume<VoxelType>::PagedVolume
|
||||
(
|
||||
const Region& regValid,
|
||||
Pager* pPager,
|
||||
uint16_t uChunkSideLength
|
||||
)
|
||||
:BaseVolume<VoxelType>(regValid)
|
||||
{
|
||||
m_uChunkSideLength = uChunkSideLength;
|
||||
m_pPager = pPager;
|
||||
|
||||
if (m_pPager)
|
||||
{
|
||||
// If the user is creating a vast (almost infinite) volume then we can bet they will be
|
||||
// expecting a high memory usage and will want a fair number of chunks to play around with.
|
||||
if (regValid == Region::MaxRegion())
|
||||
{
|
||||
m_uChunkCountLimit = 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise we try to choose a chunk count to avoid too much thrashing, particularly when iterating
|
||||
// over the whole volume. This means at least enough chunks to cover one edge of the volume, and ideally
|
||||
// enough for a whole face. Which face? Longest edge by shortest edge seems like a reasonable guess.
|
||||
uint32_t longestSide = (std::max)(regValid.getWidthInVoxels(), (std::max)(regValid.getHeightInVoxels(), regValid.getDepthInVoxels()));
|
||||
uint32_t shortestSide = (std::min)(regValid.getWidthInVoxels(), (std::min)(regValid.getHeightInVoxels(), regValid.getDepthInVoxels()));
|
||||
|
||||
longestSide /= m_uChunkSideLength;
|
||||
shortestSide /= m_uChunkSideLength;
|
||||
|
||||
m_uChunkCountLimit = longestSide * shortestSide;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there is no pager provided then we set the chunk limit to the maximum
|
||||
// value to ensure the system never attempts to page chunks out of memory.
|
||||
m_uChunkCountLimit = (std::numeric_limits<uint32_t>::max)();
|
||||
}
|
||||
|
||||
// Make sure the calculated chunk limit is within practical bounds
|
||||
m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks);
|
||||
m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks);
|
||||
|
||||
uint32_t uChunkSizeInBytes = PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength);
|
||||
POLYVOX_LOG_DEBUG("Memory usage limit for volume initially set to " << (m_uChunkCountLimit * uChunkSizeInBytes) / (1024 * 1024)
|
||||
<< "Mb (" << m_uChunkCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each).");
|
||||
|
||||
initialise();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing
|
||||
/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to
|
||||
/// make a copy of a volume and in this case you should look at the VolumeResampler.
|
||||
///
|
||||
/// \sa VolumeResampler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
PagedVolume<VoxelType>::PagedVolume(const PagedVolume<VoxelType>& /*rhs*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Destroys the volume The destructor will call flushAll() to ensure that a paging volume has the chance to save it's data via the dataOverflowHandler() if desired.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
PagedVolume<VoxelType>::~PagedVolume()
|
||||
{
|
||||
flushAll();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing
|
||||
/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to
|
||||
/// make a copy of a volume and in this case you should look at the Volumeresampler.
|
||||
///
|
||||
/// \sa VolumeResampler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
PagedVolume<VoxelType>& PagedVolume<VoxelType>::operator=(const PagedVolume<VoxelType>& /*rhs*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function requires the wrap mode to be specified as a
|
||||
/// template parameter, which can provide better performance.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const
|
||||
{
|
||||
// Simply call through to the real implementation
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<eWrapMode>(), tBorder);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function requires the wrap mode to be specified as a
|
||||
/// template parameter, which can provide better performance.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const
|
||||
{
|
||||
// Simply call through to the real implementation
|
||||
return getVoxel<eWrapMode>(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function is provided so that the wrap mode does not need
|
||||
/// to be specified as a template parameter, as it may be confusing to some users.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const
|
||||
{
|
||||
switch(eWrapMode)
|
||||
{
|
||||
case WrapModes::Validate:
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Validate>(), tBorder);
|
||||
case WrapModes::Clamp:
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Clamp>(), tBorder);
|
||||
case WrapModes::Border:
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Border>(), tBorder);
|
||||
case WrapModes::AssumeValid:
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder);
|
||||
default:
|
||||
// Should never happen
|
||||
POLYVOX_ASSERT(false, "Invalid wrap mode");
|
||||
return VoxelType();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function is provided so that the wrap mode does not need
|
||||
/// to be specified as a template parameter, as it may be confusing to some users.
|
||||
/// \param v3dPos The 3D position of the voxel
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const
|
||||
{
|
||||
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)))
|
||||
{
|
||||
const int32_t chunkX = uXPos >> m_uChunkSideLengthPower;
|
||||
const int32_t chunkY = uYPos >> m_uChunkSideLengthPower;
|
||||
const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower;
|
||||
|
||||
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (chunkX << m_uChunkSideLengthPower));
|
||||
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower));
|
||||
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower));
|
||||
|
||||
auto pChunk = getChunk(chunkX, chunkY, chunkZ);
|
||||
|
||||
return pChunk->getVoxel(xOffset, yOffset, zOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->getBorderValue();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos The 3D position of the voxel
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxelAt(const Vector3DInt32& v3dPos) const
|
||||
{
|
||||
return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Increasing the size of the chunk cache will increase memory but may improve performance.
|
||||
/// You may want to set this to a large value (e.g. 1024) when you are first loading your
|
||||
/// volume data and then set it to a smaller value (e.g.64) for general processing.
|
||||
/// \param uMaxNumberOfChunks The number of chunks for which uncompressed data can be cached.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::setMemoryUsageLimit(uint32_t uMemoryUsageInBytes)
|
||||
{
|
||||
POLYVOX_THROW_IF(!m_pPager, invalid_operation, "You cannot limit the memory usage of the volume because it was created without a pager attached.");
|
||||
|
||||
// Calculate the number of chunks based on the memory limit and the size of each chunk.
|
||||
uint32_t uChunkSizeInBytes = PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength);
|
||||
m_uChunkCountLimit = uMemoryUsageInBytes / uChunkSizeInBytes;
|
||||
|
||||
// We need at least a few chunks available to avoid thrashing, and in pratice there will probably be hundreds.
|
||||
POLYVOX_LOG_WARNING_IF(m_uChunkCountLimit < uMinPracticalNoOfChunks, "Requested memory usage limit of "
|
||||
<< uMemoryUsageInBytes / (1024 * 1024) << "Mb is too low and cannot be adhered to.");
|
||||
m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks);
|
||||
m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks);
|
||||
|
||||
// If the new limit is less than the number of chunks already loaded then the easiest solution is to flush and start loading again.
|
||||
if (m_pRecentlyUsedChunks.size() > m_uChunkCountLimit)
|
||||
{
|
||||
flushAll();
|
||||
}
|
||||
|
||||
POLYVOX_LOG_DEBUG("Memory usage limit for volume now set to " << (m_uChunkCountLimit * uChunkSizeInBytes) / (1024 * 1024)
|
||||
<< "Mb (" << m_uChunkCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each).");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos the \c x position of the voxel
|
||||
/// \param uYPos the \c y position of the voxel
|
||||
/// \param uZPos the \c z position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode)
|
||||
{
|
||||
if((eWrapMode != WrapModes::Validate) && (eWrapMode != WrapModes::AssumeValid))
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Invalid wrap mode in call to setVoxel(). It must be 'None' or 'DontCheck'.");
|
||||
}
|
||||
|
||||
// This validation is skipped if the wrap mode is 'DontCheck'
|
||||
if(eWrapMode == WrapModes::Validate)
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false)
|
||||
{
|
||||
POLYVOX_THROW(std::out_of_range, "Position is outside valid region");
|
||||
}
|
||||
}
|
||||
|
||||
const int32_t chunkX = uXPos >> m_uChunkSideLengthPower;
|
||||
const int32_t chunkY = uYPos >> m_uChunkSideLengthPower;
|
||||
const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower;
|
||||
|
||||
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (chunkX << m_uChunkSideLengthPower));
|
||||
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower));
|
||||
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower));
|
||||
|
||||
auto pChunk = getChunk(chunkX, chunkY, chunkZ);
|
||||
pChunk->setVoxelAt(xOffset, yOffset, zOffset, tValue);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos the 3D position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode)
|
||||
{
|
||||
setVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue, eWrapMode);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos the \c x position of the voxel
|
||||
/// \param uYPos the \c y position of the voxel
|
||||
/// \param uZPos the \c z position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \return whether the requested position is inside the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
bool PagedVolume<VoxelType>::setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue)
|
||||
{
|
||||
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
|
||||
POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
|
||||
|
||||
const int32_t chunkX = uXPos >> m_uChunkSideLengthPower;
|
||||
const int32_t chunkY = uYPos >> m_uChunkSideLengthPower;
|
||||
const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower;
|
||||
|
||||
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (chunkX << m_uChunkSideLengthPower));
|
||||
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower));
|
||||
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower));
|
||||
|
||||
auto pChunk = getChunk(chunkX, chunkY, chunkZ);
|
||||
|
||||
pChunk->setVoxelAt(xOffset, yOffset, zOffset, tValue);
|
||||
|
||||
//Return true to indicate that we modified a voxel.
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos the 3D position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \return whether the requested position is inside the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
bool PagedVolume<VoxelType>::setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue)
|
||||
{
|
||||
return setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Note that if the memory usage limit is not large enough to support the region this function will only load part of the region. In this case it is undefined which parts will actually be loaded. If all the voxels in the given region are already loaded, this function will not do anything. Other voxels might be unloaded to make space for the new voxels.
|
||||
/// \param regPrefetch The Region of voxels to prefetch into memory.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::prefetch(Region regPrefetch)
|
||||
{
|
||||
// Convert the start and end positions into chunk space coordinates
|
||||
Vector3DInt32 v3dStart;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
v3dStart.setElement(i, regPrefetch.getLowerCorner().getElement(i) >> m_uChunkSideLengthPower);
|
||||
}
|
||||
|
||||
Vector3DInt32 v3dEnd;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
v3dEnd.setElement(i, regPrefetch.getUpperCorner().getElement(i) >> m_uChunkSideLengthPower);
|
||||
}
|
||||
|
||||
// Ensure we don't page in more chunks than the volume can hold.
|
||||
Region region(v3dStart, v3dEnd);
|
||||
uint32_t uNoOfChunks = static_cast<uint32_t>(region.getWidthInVoxels() * region.getHeightInVoxels() * region.getDepthInVoxels());
|
||||
POLYVOX_LOG_WARNING_IF(uNoOfChunks > m_uChunkCountLimit, "Attempting to prefetch more than the maximum number of chunks.");
|
||||
uNoOfChunks = (std::min)(uNoOfChunks, m_uChunkCountLimit);
|
||||
|
||||
// Loops over the specified positions and touch the corresponding chunks.
|
||||
for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++)
|
||||
{
|
||||
for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++)
|
||||
{
|
||||
for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++)
|
||||
{
|
||||
getChunk(x,y,z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Removes all voxels from memory, and calls dataOverflowHandler() to ensure the application has a chance to store the data.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::flushAll()
|
||||
{
|
||||
POLYVOX_LOG_WARNING_IF(!m_pPager, "Data discarded by flush operation as no pager is attached.");
|
||||
|
||||
// Clear this pointer so it doesn't hang on to any chunks.
|
||||
m_pLastAccessedChunk = nullptr;
|
||||
|
||||
// Erase all the most recently used chunks.
|
||||
m_pRecentlyUsedChunks.clear();
|
||||
|
||||
// Remove deleted chunks from the list of all loaded chunks.
|
||||
purgeNullPtrsFromAllChunks();
|
||||
|
||||
// If there are still some chunks left then this is a cause for concern. Perhaps samplers are holding on to them?
|
||||
POLYVOX_LOG_WARNING_IF(m_pAllChunks.size() > 0, "Chunks still exist after performing flushAll()! Perhaps you have samplers attached?");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Removes all voxels in the specified Region from memory, and calls dataOverflowHandler() to ensure the application has a chance to store the data. It is possible that there are no voxels loaded in the Region, in which case the function will have no effect.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::flush(Region regFlush)
|
||||
{
|
||||
POLYVOX_LOG_WARNING_IF(!m_pPager, "Data discarded by flush operation as no pager is attached.");
|
||||
|
||||
// Clear this pointer so it doesn't hang on to any chunks.
|
||||
m_pLastAccessedChunk = nullptr;
|
||||
|
||||
// Convert the start and end positions into chunk space coordinates
|
||||
Vector3DInt32 v3dStart;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
v3dStart.setElement(i, regFlush.getLowerCorner().getElement(i) >> m_uChunkSideLengthPower);
|
||||
}
|
||||
|
||||
Vector3DInt32 v3dEnd;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
v3dEnd.setElement(i, regFlush.getUpperCorner().getElement(i) >> m_uChunkSideLengthPower);
|
||||
}
|
||||
|
||||
// Loops over the specified positions and delete the corresponding chunks.
|
||||
for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++)
|
||||
{
|
||||
for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++)
|
||||
{
|
||||
for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++)
|
||||
{
|
||||
m_pRecentlyUsedChunks.erase(Vector3DInt32(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_pLastAccessedChunk = nullptr;
|
||||
|
||||
// We might now have so null pointers in the 'all chunks' list so clean them up.
|
||||
purgeNullPtrsFromAllChunks();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This function should probably be made internal...
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::initialise()
|
||||
{
|
||||
//Validate parameters
|
||||
if(m_uChunkSideLength == 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Chunk side length cannot be zero.");
|
||||
}
|
||||
|
||||
if(!isPowerOf2(m_uChunkSideLength))
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Chunk side length must be a power of two.");
|
||||
}
|
||||
|
||||
m_uTimestamper = 0;
|
||||
m_v3dLastAccessedChunkPos = Vector3DInt32(0,0,0); //There are no invalid positions, but initially the m_pLastAccessedChunk pointer will be null;
|
||||
m_pLastAccessedChunk = nullptr;
|
||||
|
||||
//Compute the chunk side length
|
||||
m_uChunkSideLengthPower = logBase2(m_uChunkSideLength);
|
||||
|
||||
m_regValidRegionInChunks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uChunkSideLengthPower);
|
||||
m_regValidRegionInChunks.setLowerY(this->m_regValidRegion.getLowerY() >> m_uChunkSideLengthPower);
|
||||
m_regValidRegionInChunks.setLowerZ(this->m_regValidRegion.getLowerZ() >> m_uChunkSideLengthPower);
|
||||
m_regValidRegionInChunks.setUpperX(this->m_regValidRegion.getUpperX() >> m_uChunkSideLengthPower);
|
||||
m_regValidRegionInChunks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uChunkSideLengthPower);
|
||||
m_regValidRegionInChunks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uChunkSideLengthPower);
|
||||
|
||||
//setMaxNumberOfChunks(m_uChunkCountLimit);
|
||||
|
||||
//Clear the previous data
|
||||
m_pRecentlyUsedChunks.clear();
|
||||
|
||||
//Other properties we might find useful later
|
||||
this->m_uLongestSideLength = (std::max)((std::max)(this->getWidth(),this->getHeight()),this->getDepth());
|
||||
this->m_uShortestSideLength = (std::min)((std::min)(this->getWidth(),this->getHeight()),this->getDepth());
|
||||
this->m_fDiagonalLength = sqrtf(static_cast<float>(this->getWidth() * this->getWidth() + this->getHeight() * this->getHeight() + this->getDepth() * this->getDepth()));
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
std::shared_ptr<typename PagedVolume<VoxelType>::Chunk> PagedVolume<VoxelType>::getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const
|
||||
{
|
||||
Vector3DInt32 v3dChunkPos(uChunkX, uChunkY, uChunkZ);
|
||||
|
||||
//Check if we have the same chunk as last time, if so there's no need to even update
|
||||
//the time stamp. If we updated it everytime then that would be every time we touched
|
||||
//a voxel, which would overflow a uint32_t and require us to use a uint64_t instead.
|
||||
//This check should also provide a significant speed boost as usually it is true.
|
||||
if((v3dChunkPos == m_v3dLastAccessedChunkPos) && (m_pLastAccessedChunk != 0))
|
||||
{
|
||||
return m_pLastAccessedChunk;
|
||||
}
|
||||
|
||||
// The chunk was not the same as last time, but we can now hope it is in the set of most recently used chunks.
|
||||
std::shared_ptr<typename PagedVolume<VoxelType>::Chunk> pChunk = nullptr;
|
||||
typename SharedPtrChunkMap::iterator itChunk = m_pRecentlyUsedChunks.find(v3dChunkPos);
|
||||
|
||||
// Check whether the chunk was found.
|
||||
if ((itChunk) != m_pRecentlyUsedChunks.end())
|
||||
{
|
||||
// The chunk was found so we can use it.
|
||||
pChunk = itChunk->second;
|
||||
POLYVOX_ASSERT(pChunk, "Recent chunk list shold never contain a null pointer.");
|
||||
}
|
||||
|
||||
if (!pChunk)
|
||||
{
|
||||
// Although it's not in our recently use chunks, there's some (slim) chance that it
|
||||
// exists in the list of all loaded chunks, because a sampler may be holding on to it.
|
||||
typename WeakPtrChunkMap::iterator itWeakChunk = m_pAllChunks.find(v3dChunkPos);
|
||||
if (itWeakChunk != m_pAllChunks.end())
|
||||
{
|
||||
// We've found an entry in the 'all chunks' list, but it can be null. This happens if a sampler was the
|
||||
// last thing to be keeping it alive and then the sampler let it go. In this case we remove it from the
|
||||
// list, and it will get added again soon when we page it in and fill it with valid data.
|
||||
if (itWeakChunk->second.expired())
|
||||
{
|
||||
m_pAllChunks.erase(itWeakChunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The chunk is valid. We know it's not in the recently used list (we checked earlier) so it should be added.
|
||||
pChunk = std::shared_ptr< PagedVolume<VoxelType>::Chunk >(itWeakChunk->second);
|
||||
m_pRecentlyUsedChunks.insert(std::make_pair(v3dChunkPos, pChunk));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we still haven't found the chunk then it's time to create a new one and page it in from disk.
|
||||
if (!pChunk)
|
||||
{
|
||||
// The chunk was not found so we will create a new one.
|
||||
pChunk = std::make_shared< PagedVolume<VoxelType>::Chunk >(v3dChunkPos, m_uChunkSideLength, m_pPager);
|
||||
|
||||
// As we are loading a new chunk we should try to ensure we don't go over our target memory usage.
|
||||
bool erasedChunk = false;
|
||||
while (m_pRecentlyUsedChunks.size() + 1 > m_uChunkCountLimit) // +1 ready for new chunk we will add next.
|
||||
{
|
||||
// This should never hit, because it should not have been possible for
|
||||
// the user to limit the number of chunks if they did not provide a pager.
|
||||
POLYVOX_ASSERT(m_pPager, "A valid pager is required to limit number of chunks");
|
||||
|
||||
// Find the least recently used chunk. Hopefully this isn't too slow.
|
||||
typename SharedPtrChunkMap::iterator itUnloadChunk = m_pRecentlyUsedChunks.begin();
|
||||
for (typename SharedPtrChunkMap::iterator i = m_pRecentlyUsedChunks.begin(); i != m_pRecentlyUsedChunks.end(); i++)
|
||||
{
|
||||
if (i->second->m_uChunkLastAccessed < itUnloadChunk->second->m_uChunkLastAccessed)
|
||||
{
|
||||
itUnloadChunk = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Erase the least recently used chunk
|
||||
m_pRecentlyUsedChunks.erase(itUnloadChunk);
|
||||
erasedChunk = true;
|
||||
}
|
||||
|
||||
// If we've deleted any chunks from the recently used list then this
|
||||
// seems like a good place to purge the 'all chunks' list as well.
|
||||
if (erasedChunk)
|
||||
{
|
||||
purgeNullPtrsFromAllChunks();
|
||||
}
|
||||
|
||||
// Add our new chunk to the maps.
|
||||
m_pAllChunks.insert(std::make_pair(v3dChunkPos, pChunk));
|
||||
m_pRecentlyUsedChunks.insert(std::make_pair(v3dChunkPos, pChunk));
|
||||
}
|
||||
|
||||
pChunk->m_uChunkLastAccessed = ++m_uTimestamper;
|
||||
m_pLastAccessedChunk = pChunk;
|
||||
m_v3dLastAccessedChunkPos = v3dChunkPos;
|
||||
|
||||
return pChunk;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Calculate the memory usage of the volume.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
uint32_t PagedVolume<VoxelType>::calculateSizeInBytes(void)
|
||||
{
|
||||
// Purge null chunks so we know that all chunks are used.
|
||||
purgeNullPtrsFromAllChunks();
|
||||
|
||||
// Note: We disregard the size of the other class members as they are likely to be very small compared to the size of the
|
||||
// allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier.
|
||||
return PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength) * m_pAllChunks.size();
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::purgeNullPtrsFromAllChunks(void) const
|
||||
{
|
||||
for (auto chunkIter = m_pAllChunks.begin(); chunkIter != m_pAllChunks.end();)
|
||||
{
|
||||
if (chunkIter->second.expired())
|
||||
{
|
||||
chunkIter = m_pAllChunks.erase(chunkIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkIter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const
|
||||
{
|
||||
// This function should never be called because one of the specialisations should always match.
|
||||
POLYVOX_ASSERT(false, "This function is not implemented and should never be called!");
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false)
|
||||
{
|
||||
POLYVOX_THROW(std::out_of_range, "Position is outside valid region");
|
||||
}
|
||||
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const
|
||||
{
|
||||
//Perform clamping
|
||||
uXPos = (std::max)(uXPos, this->m_regValidRegion.getLowerX());
|
||||
uYPos = (std::max)(uYPos, this->m_regValidRegion.getLowerY());
|
||||
uZPos = (std::max)(uZPos, this->m_regValidRegion.getLowerZ());
|
||||
uXPos = (std::min)(uXPos, this->m_regValidRegion.getUpperX());
|
||||
uYPos = (std::min)(uYPos, this->m_regValidRegion.getUpperY());
|
||||
uZPos = (std::min)(uZPos, this->m_regValidRegion.getUpperZ());
|
||||
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
|
||||
{
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
|
||||
}
|
||||
else
|
||||
{
|
||||
return tBorder;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType /*tBorder*/) const
|
||||
{
|
||||
const int32_t chunkX = uXPos >> m_uChunkSideLengthPower;
|
||||
const int32_t chunkY = uYPos >> m_uChunkSideLengthPower;
|
||||
const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower;
|
||||
|
||||
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (chunkX << m_uChunkSideLengthPower));
|
||||
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower));
|
||||
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower));
|
||||
|
||||
auto pChunk = getChunk(chunkX, chunkY, chunkZ);
|
||||
return pChunk->getVoxel(xOffset, yOffset, zOffset);
|
||||
}
|
||||
}
|
||||
|
161
include/PolyVoxCore/include/PolyVoxCore/PagedVolumeChunk.inl
Normal file
161
include/PolyVoxCore/include/PolyVoxCore/PagedVolumeChunk.inl
Normal file
@ -0,0 +1,161 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2013 David Williams and Matthew Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/Impl/Utility.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename VoxelType>
|
||||
PagedVolume<VoxelType>::Chunk::Chunk(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager* pPager)
|
||||
:m_uChunkLastAccessed(0)
|
||||
,m_bDataModified(true)
|
||||
,m_tData(0)
|
||||
,m_uSideLength(0)
|
||||
,m_uSideLengthPower(0)
|
||||
,m_pPager(pPager)
|
||||
,m_v3dChunkSpacePosition(v3dPosition)
|
||||
{
|
||||
// Compute the side length
|
||||
m_uSideLength = uSideLength;
|
||||
m_uSideLengthPower = logBase2(uSideLength);
|
||||
|
||||
// Allocate the data
|
||||
const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
|
||||
m_tData = new VoxelType[uNoOfVoxels];
|
||||
|
||||
// Pass the chunk to the Pager to give it a chance to initialise it with any data
|
||||
if (m_pPager)
|
||||
{
|
||||
// From the coordinates of the chunk we deduce the coordinates of the contained voxels.
|
||||
Vector3DInt32 v3dLower = m_v3dChunkSpacePosition * static_cast<int32_t>(m_uSideLength);
|
||||
Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uSideLength - 1, m_uSideLength - 1, m_uSideLength - 1);
|
||||
Region reg(v3dLower, v3dUpper);
|
||||
|
||||
// Page the data in
|
||||
m_pPager->pageIn(reg, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just fill with zeros
|
||||
std::fill(m_tData, m_tData + uNoOfVoxels, VoxelType());
|
||||
}
|
||||
|
||||
// We'll use this later to decide if data needs to be paged out again.
|
||||
m_bDataModified = false;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
PagedVolume<VoxelType>::Chunk::~Chunk()
|
||||
{
|
||||
if (m_pPager && m_bDataModified)
|
||||
{
|
||||
// From the coordinates of the chunk we deduce the coordinates of the contained voxels.
|
||||
Vector3DInt32 v3dLower = m_v3dChunkSpacePosition * static_cast<int32_t>(m_uSideLength);
|
||||
Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uSideLength - 1, m_uSideLength - 1, m_uSideLength - 1);
|
||||
|
||||
// Page the data out
|
||||
m_pPager->pageOut(Region(v3dLower, v3dUpper), this);
|
||||
}
|
||||
|
||||
delete[] m_tData;
|
||||
m_tData = 0;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType* PagedVolume<VoxelType>::Chunk::getData(void) const
|
||||
{
|
||||
return m_tData;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
uint32_t PagedVolume<VoxelType>::Chunk::getDataSizeInBytes(void) const
|
||||
{
|
||||
return m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Chunk::getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
|
||||
{
|
||||
// This code is not usually expected to be called by the user, with the exception of when implementing paging
|
||||
// of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions.
|
||||
POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the chunk");
|
||||
POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the chunk");
|
||||
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the chunk");
|
||||
POLYVOX_ASSERT(m_tData, "No uncompressed data - chunk must be decompressed before accessing voxels.");
|
||||
|
||||
return m_tData
|
||||
[
|
||||
uXPos +
|
||||
uYPos * m_uSideLength +
|
||||
uZPos * m_uSideLength * m_uSideLength
|
||||
];
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Chunk::getVoxel(const Vector3DUint16& v3dPos) const
|
||||
{
|
||||
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Chunk::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
|
||||
{
|
||||
// This code is not usually expected to be called by the user, with the exception of when implementing paging
|
||||
// of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions.
|
||||
POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the chunk");
|
||||
POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the chunk");
|
||||
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the chunk");
|
||||
POLYVOX_ASSERT(m_tData, "No uncompressed data - chunk must be decompressed before accessing voxels.");
|
||||
|
||||
m_tData
|
||||
[
|
||||
uXPos +
|
||||
uYPos * m_uSideLength +
|
||||
uZPos * m_uSideLength * m_uSideLength
|
||||
] = tValue;
|
||||
|
||||
this->m_bDataModified = true;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Chunk::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue)
|
||||
{
|
||||
setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
uint32_t PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(void)
|
||||
{
|
||||
// Call through to the static version
|
||||
return calculateSizeInBytes(m_uSideLength);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
uint32_t PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(uint32_t uSideLength)
|
||||
{
|
||||
// Note: We disregard the size of the other class members as they are likely to be very small compared to the size of the
|
||||
// allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier.
|
||||
uint32_t uSizeInBytes = uSideLength * uSideLength * uSideLength * sizeof(VoxelType);
|
||||
return uSizeInBytes;
|
||||
}
|
||||
}
|
562
include/PolyVoxCore/include/PolyVoxCore/PagedVolumeSampler.inl
Normal file
562
include/PolyVoxCore/include/PolyVoxCore/PagedVolumeSampler.inl
Normal file
@ -0,0 +1,562 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#define CAN_GO_NEG_X(val) ((val > this->mVolume->getEnclosingRegion().getLowerX()) && (val % this->mVolume->m_uChunkSideLength != 0))
|
||||
#define CAN_GO_POS_X(val) ((val < this->mVolume->getEnclosingRegion().getUpperX()) && ((val + 1) % this->mVolume->m_uChunkSideLength != 0))
|
||||
#define CAN_GO_NEG_Y(val) ((val > this->mVolume->getEnclosingRegion().getLowerY()) && (val % this->mVolume->m_uChunkSideLength != 0))
|
||||
#define CAN_GO_POS_Y(val) ((val < this->mVolume->getEnclosingRegion().getUpperY()) && ((val + 1) % this->mVolume->m_uChunkSideLength != 0))
|
||||
#define CAN_GO_NEG_Z(val) ((val > this->mVolume->getEnclosingRegion().getLowerZ()) && (val % this->mVolume->m_uChunkSideLength != 0))
|
||||
#define CAN_GO_POS_Z(val) ((val < this->mVolume->getEnclosingRegion().getUpperZ()) && ((val + 1) % this->mVolume->m_uChunkSideLength != 0))
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename VoxelType>
|
||||
PagedVolume<VoxelType>::Sampler::Sampler(PagedVolume<VoxelType>* volume)
|
||||
:BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >(volume)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
PagedVolume<VoxelType>::Sampler::~Sampler()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::getSubSampledVoxel(uint8_t uLevel) const
|
||||
{
|
||||
if(uLevel == 0)
|
||||
{
|
||||
return getVoxel();
|
||||
}
|
||||
else if(uLevel == 1)
|
||||
{
|
||||
VoxelType tValue = getVoxel();
|
||||
tValue = (std::min)(tValue, peekVoxel1px0py0pz());
|
||||
tValue = (std::min)(tValue, peekVoxel0px1py0pz());
|
||||
tValue = (std::min)(tValue, peekVoxel1px1py0pz());
|
||||
tValue = (std::min)(tValue, peekVoxel0px0py1pz());
|
||||
tValue = (std::min)(tValue, peekVoxel1px0py1pz());
|
||||
tValue = (std::min)(tValue, peekVoxel0px1py1pz());
|
||||
tValue = (std::min)(tValue, peekVoxel1px1py1pz());
|
||||
return tValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t uSize = 1 << uLevel;
|
||||
|
||||
VoxelType tValue = (std::numeric_limits<VoxelType>::max)();
|
||||
for(uint8_t z = 0; z < uSize; ++z)
|
||||
{
|
||||
for(uint8_t y = 0; y < uSize; ++y)
|
||||
{
|
||||
for(uint8_t x = 0; x < uSize; ++x)
|
||||
{
|
||||
tValue = (std::min)(tValue, this->mVolume->getVoxelAt(this->mXPosInVolume + x, this->mYPosInVolume + y, this->mZPosInVolume + z));
|
||||
}
|
||||
}
|
||||
}
|
||||
return tValue;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::getVoxel(void) const
|
||||
{
|
||||
if(this->isCurrentPositionValid())
|
||||
{
|
||||
return *mCurrentVoxel;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Sampler::setPosition(const Vector3DInt32& v3dNewPos)
|
||||
{
|
||||
setPosition(v3dNewPos.getX(), v3dNewPos.getY(), v3dNewPos.getZ());
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Sampler::setPosition(int32_t xPos, int32_t yPos, int32_t zPos)
|
||||
{
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::setPosition(xPos, yPos, zPos);
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if(this->isCurrentPositionValid())
|
||||
{
|
||||
const int32_t uXChunk = this->mXPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
|
||||
const int32_t uYChunk = this->mYPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
|
||||
const int32_t uZChunk = this->mZPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
|
||||
|
||||
const uint16_t uXPosInChunk = static_cast<uint16_t>(this->mXPosInVolume - (uXChunk << this->mVolume->m_uChunkSideLengthPower));
|
||||
const uint16_t uYPosInChunk = static_cast<uint16_t>(this->mYPosInVolume - (uYChunk << this->mVolume->m_uChunkSideLengthPower));
|
||||
const uint16_t uZPosInChunk = static_cast<uint16_t>(this->mZPosInVolume - (uZChunk << this->mVolume->m_uChunkSideLengthPower));
|
||||
|
||||
const uint32_t uVoxelIndexInChunk = uXPosInChunk +
|
||||
uYPosInChunk * this->mVolume->m_uChunkSideLength +
|
||||
uZPosInChunk * this->mVolume->m_uChunkSideLength * this->mVolume->m_uChunkSideLength;
|
||||
|
||||
auto pCurrentChunk = this->mVolume->getChunk(uXChunk, uYChunk, uZChunk);
|
||||
|
||||
mCurrentVoxel = pCurrentChunk->m_tData + uVoxelIndexInChunk;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentVoxel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
bool PagedVolume<VoxelType>::Sampler::setVoxel(VoxelType tValue)
|
||||
{
|
||||
/*if(m_bIsCurrentPositionValidInX && m_bIsCurrentPositionValidInY && m_bIsCurrentPositionValidInZ)
|
||||
{
|
||||
*mCurrentVoxel = tValue;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}*/
|
||||
|
||||
//Need to think what effect this has on any existing iterators.
|
||||
POLYVOX_THROW(not_implemented, "This function cannot be used on PagedVolume samplers.");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Sampler::movePositiveX(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveX();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume) % this->mVolume->m_uChunkSideLength != 0))
|
||||
{
|
||||
//No need to compute new chunk.
|
||||
++mCurrentVoxel;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We've hit the chunk boundary. Just calling setPosition() is the easiest way to resolve this.
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Sampler::movePositiveY(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveY();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume) % this->mVolume->m_uChunkSideLength != 0))
|
||||
{
|
||||
//No need to compute new chunk.
|
||||
mCurrentVoxel += this->mVolume->m_uChunkSideLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We've hit the chunk boundary. Just calling setPosition() is the easiest way to resolve this.
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Sampler::movePositiveZ(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveZ();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume) % this->mVolume->m_uChunkSideLength != 0))
|
||||
{
|
||||
//No need to compute new chunk.
|
||||
mCurrentVoxel += this->mVolume->m_uChunkSideLength * this->mVolume->m_uChunkSideLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We've hit the chunk boundary. Just calling setPosition() is the easiest way to resolve this.
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Sampler::moveNegativeX(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeX();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume + 1) % this->mVolume->m_uChunkSideLength != 0))
|
||||
{
|
||||
//No need to compute new chunk.
|
||||
--mCurrentVoxel;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We've hit the chunk boundary. Just calling setPosition() is the easiest way to resolve this.
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Sampler::moveNegativeY(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeY();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume + 1) % this->mVolume->m_uChunkSideLength != 0))
|
||||
{
|
||||
//No need to compute new chunk.
|
||||
mCurrentVoxel -= this->mVolume->m_uChunkSideLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We've hit the chunk boundary. Just calling setPosition() is the easiest way to resolve this.
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void PagedVolume<VoxelType>::Sampler::moveNegativeZ(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeZ();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume + 1) % this->mVolume->m_uChunkSideLength != 0))
|
||||
{
|
||||
//No need to compute new chunk.
|
||||
mCurrentVoxel -= this->mVolume->m_uChunkSideLength * this->mVolume->m_uChunkSideLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We've hit the chunk boundary. Just calling setPosition() is the easiest way to resolve this.
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 - this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 - this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 - this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 + this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 + this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 + this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()))
|
||||
{
|
||||
return *mCurrentVoxel;
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 - this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 - this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 - this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 + this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 + this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 + this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
}
|
||||
|
||||
#undef CAN_GO_NEG_X
|
||||
#undef CAN_GO_POS_X
|
||||
#undef CAN_GO_NEG_Y
|
||||
#undef CAN_GO_POS_Y
|
||||
#undef CAN_GO_NEG_Z
|
||||
#undef CAN_GO_POS_Z
|
49
include/PolyVoxCore/include/PolyVoxCore/Picking.h
Normal file
49
include/PolyVoxCore/include/PolyVoxCore/Picking.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2013 Matt Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Picking_H__
|
||||
#define __PolyVox_Picking_H__
|
||||
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
* A structure containing the information about a picking operation
|
||||
*/
|
||||
struct PickResult
|
||||
{
|
||||
PickResult() : didHit(false) {}
|
||||
bool didHit; ///< Did the picking operation hit anything
|
||||
Vector3DInt32 hitVoxel; ///< The location of the solid voxel it hit
|
||||
Vector3DInt32 previousVoxel; ///< The location of the voxel before the one it hit
|
||||
};
|
||||
|
||||
/// Pick the first solid voxel along a vector
|
||||
template<typename VolumeType>
|
||||
PickResult pickVoxel(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, const typename VolumeType::VoxelType& emptyVoxelExample);
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/Picking.inl"
|
||||
|
||||
#endif //__PolyVox_Picking_H__
|
84
include/PolyVoxCore/include/PolyVoxCore/Picking.inl
Normal file
84
include/PolyVoxCore/include/PolyVoxCore/Picking.inl
Normal file
@ -0,0 +1,84 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2013 Matt Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/Raycast.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* This is just an implementation class for the pickVoxel function
|
||||
*
|
||||
* It makes note of the sort of empty voxel you're looking for in the constructor.
|
||||
*
|
||||
* Each time the operator() is called:
|
||||
* * if it's hit a voxel it sets up the result and returns false
|
||||
* * otherwise it preps the result for the next iteration and returns true
|
||||
*/
|
||||
template <typename VolumeType>
|
||||
class RaycastPickingFunctor
|
||||
{
|
||||
public:
|
||||
RaycastPickingFunctor(const typename VolumeType::VoxelType& emptyVoxelExample)
|
||||
:m_emptyVoxelExample(emptyVoxelExample)
|
||||
,m_result()
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(const typename VolumeType::Sampler& sampler)
|
||||
{
|
||||
if(sampler.getVoxel() != m_emptyVoxelExample) //If we've hit something
|
||||
{
|
||||
m_result.didHit = true;
|
||||
m_result.hitVoxel = sampler.getPosition();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_result.previousVoxel = sampler.getPosition();
|
||||
|
||||
return true;
|
||||
}
|
||||
const typename VolumeType::VoxelType& m_emptyVoxelExample;
|
||||
PickResult m_result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \param volData The volume to pass the ray though
|
||||
* \param v3dStart The start position in the volume
|
||||
* \param v3dDirectionAndLength The direction and length of the ray
|
||||
* \param emptyVoxelExample The value used to represent empty voxels in your volume
|
||||
*
|
||||
* \return A PickResult containing the hit information
|
||||
*/
|
||||
template<typename VolumeType>
|
||||
PickResult pickVoxel(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, const typename VolumeType::VoxelType& emptyVoxelExample)
|
||||
{
|
||||
RaycastPickingFunctor<VolumeType> functor(emptyVoxelExample);
|
||||
|
||||
raycastWithDirection(volData, v3dStart, v3dDirectionAndLength, functor);
|
||||
|
||||
return functor.m_result;
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_ForwardDeclarations_H__
|
||||
#define __PolyVox_ForwardDeclarations_H__
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/*template<uint32_t dimensions, typename ElementType> class Array;
|
||||
|
||||
typedef Array<1,float> Array1DFloat;
|
||||
typedef Array<1,double> Array1DDouble;
|
||||
typedef Array<1,int8_t> Array1DInt8;
|
||||
typedef Array<1,uint8_t> Array1DUint8;
|
||||
typedef Array<1,int16_t> Array1DInt16;
|
||||
typedef Array<1,uint16_t> Array1DUint16;
|
||||
typedef Array<1,int32_t> Array1DInt32;
|
||||
typedef Array<1,uint32_t> Array1DUint32;*/
|
||||
|
||||
/*typedef Array<2,float> Array2DFloat;
|
||||
typedef Array<2,double> Array2DDouble;
|
||||
typedef Array<2,int8_t> Array2DInt8;
|
||||
typedef Array<2,uint8_t> Array2DUint8;
|
||||
typedef Array<2,int16_t> Array2DInt16;
|
||||
typedef Array<2,uint16_t> Array2DUint16;
|
||||
typedef Array<2,int32_t> Array2DInt32;
|
||||
typedef Array<2,uint32_t> Array2DUint32;*/
|
||||
|
||||
/*typedef Array<3,float> Array3DFloat;
|
||||
typedef Array<3,double> Array3DDouble;
|
||||
typedef Array<3,int8_t> Array3DInt8;
|
||||
typedef Array<3,uint8_t> Array3DUint8;
|
||||
typedef Array<3,int16_t> Array3DInt16;
|
||||
typedef Array<3,uint16_t> Array3DUint16;
|
||||
typedef Array<3,int32_t> Array3DInt32;
|
||||
typedef Array<3,uint32_t> Array3DUint32;*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Compressor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class Compressor;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CubicSurfaceExtractor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VoxelType> class DefaultIsQuadNeeded;
|
||||
template<typename VolumeType, typename MeshType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> > class CubicSurfaceExtractor;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CubicVertex
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VoxelType> struct CubicVertex;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Density
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Type> class Density;
|
||||
|
||||
typedef Density<int8_t> DensityI8;
|
||||
typedef Density<uint8_t> DensityU8;
|
||||
typedef Density<int16_t> DensityI16;
|
||||
typedef Density<uint16_t> DensityU16;
|
||||
typedef Density<float> DensityFloat;
|
||||
typedef Density<double> DensityDouble;
|
||||
|
||||
typedef DensityU8 Density8; //Backwards compatibility
|
||||
typedef DensityU16 Density16; //Backwards compatibility
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// FilePager
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType> class FilePager;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MarchingCubesSurfaceExtractor
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VolumeType, typename MeshType, typename ControllerType> class MarchingCubesSurfaceExtractor;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MarchingCubesVertex
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename VoxelType> struct MarchingCubesVertex;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Material
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Type> class Material;
|
||||
|
||||
typedef Material<uint8_t> MaterialU8;
|
||||
typedef Material<uint16_t> MaterialU16;
|
||||
typedef Material<uint32_t> MaterialU32;
|
||||
|
||||
typedef MaterialU8 Material8;
|
||||
typedef MaterialU16 Material16;
|
||||
typedef MaterialU32 Material32;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MaterialDensityPair
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits> class MaterialDensityPair;
|
||||
|
||||
typedef MaterialDensityPair<uint8_t, 4, 4> MaterialDensityPair44;
|
||||
typedef MaterialDensityPair<uint16_t, 8, 8> MaterialDensityPair88;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Mesh
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef uint32_t DefaultIndexType;
|
||||
template <typename VertexType, typename IndexType = DefaultIndexType> class Mesh;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// PagedVolume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType> class PagedVolume;
|
||||
template <typename VoxelType>
|
||||
using LargeVolume = PagedVolume<VoxelType>;
|
||||
template <typename VoxelType>
|
||||
using SimpleVolume = PagedVolume<VoxelType>;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Pager
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType> class Pager;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// RawVolume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType> class RawVolume;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Region
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class Region;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Vector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <uint32_t Size, typename StorageType, typename OperationType = StorageType> class Vector;
|
||||
|
||||
typedef Vector<2,float,float> Vector2DFloat;
|
||||
typedef Vector<2,double,double> Vector2DDouble;
|
||||
typedef Vector<2,int8_t,int32_t> Vector2DInt8;
|
||||
typedef Vector<2,uint8_t,int32_t> Vector2DUint8;
|
||||
typedef Vector<2,int16_t,int32_t> Vector2DInt16;
|
||||
typedef Vector<2,uint16_t,int32_t> Vector2DUint16;
|
||||
typedef Vector<2,int32_t,int32_t> Vector2DInt32;
|
||||
typedef Vector<2,uint32_t,int32_t> Vector2DUint32;
|
||||
|
||||
typedef Vector<3,float,float> Vector3DFloat;
|
||||
typedef Vector<3,double,double> Vector3DDouble;
|
||||
typedef Vector<3,int8_t,int32_t> Vector3DInt8;
|
||||
typedef Vector<3,uint8_t,int32_t> Vector3DUint8;
|
||||
typedef Vector<3,int16_t,int32_t> Vector3DInt16;
|
||||
typedef Vector<3,uint16_t,int32_t> Vector3DUint16;
|
||||
typedef Vector<3,int32_t,int32_t> Vector3DInt32;
|
||||
typedef Vector<3,uint32_t,int32_t> Vector3DUint32;
|
||||
|
||||
typedef Vector<4,float,float> Vector4DFloat;
|
||||
typedef Vector<4,double,double> Vector4DDouble;
|
||||
typedef Vector<4,int8_t,int32_t> Vector4DInt8;
|
||||
typedef Vector<4,uint8_t,int32_t> Vector4DUint8;
|
||||
typedef Vector<4,int16_t,int32_t> Vector4DInt16;
|
||||
typedef Vector<4,uint16_t,int32_t> Vector4DUint16;
|
||||
typedef Vector<4,int32_t,int32_t> Vector4DInt32;
|
||||
typedef Vector<4,uint32_t,int32_t> Vector4DUint32;
|
||||
}
|
||||
|
||||
#endif
|
173
include/PolyVoxCore/include/PolyVoxCore/RawVolume.h
Normal file
173
include/PolyVoxCore/include/PolyVoxCore/RawVolume.h
Normal file
@ -0,0 +1,173 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_RawVolume_H__
|
||||
#define __PolyVox_RawVolume_H__
|
||||
|
||||
#include "PolyVoxCore/BaseVolume.h"
|
||||
#include "PolyVoxCore/Region.h"
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
#include <cstdlib> //For abort()
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept> //For invalid_argument
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename VoxelType>
|
||||
class RawVolume : public BaseVolume<VoxelType>
|
||||
{
|
||||
public:
|
||||
#ifndef SWIG
|
||||
//There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared.
|
||||
//There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but
|
||||
//which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler
|
||||
//option. For now it seems best to 'fix' it with the preprocessor insstead, but maybe the workaround can be reinstated
|
||||
//in the future
|
||||
//typedef Volume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences.
|
||||
//class Sampler : public VolumeOfVoxelType::template Sampler< RawVolume<VoxelType> >
|
||||
#if defined(_MSC_VER)
|
||||
class Sampler : public BaseVolume<VoxelType>::Sampler< RawVolume<VoxelType> > //This line works on VS2010
|
||||
#else
|
||||
class Sampler : public BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> > //This line works on GCC
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
Sampler(RawVolume<VoxelType>* volume);
|
||||
~Sampler();
|
||||
|
||||
inline VoxelType getVoxel(void) const;
|
||||
|
||||
void setPosition(const Vector3DInt32& v3dNewPos);
|
||||
void setPosition(int32_t xPos, int32_t yPos, int32_t zPos);
|
||||
inline bool setVoxel(VoxelType tValue);
|
||||
|
||||
void movePositiveX(void);
|
||||
void movePositiveY(void);
|
||||
void movePositiveZ(void);
|
||||
|
||||
void moveNegativeX(void);
|
||||
void moveNegativeY(void);
|
||||
void moveNegativeZ(void);
|
||||
|
||||
inline VoxelType peekVoxel1nx1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx0py1pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py1nz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py0pz(void) const;
|
||||
inline VoxelType peekVoxel1nx1py1pz(void) const;
|
||||
|
||||
inline VoxelType peekVoxel0px1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel0px1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel0px1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel0px0py1nz(void) const;
|
||||
inline VoxelType peekVoxel0px0py0pz(void) const;
|
||||
inline VoxelType peekVoxel0px0py1pz(void) const;
|
||||
inline VoxelType peekVoxel0px1py1nz(void) const;
|
||||
inline VoxelType peekVoxel0px1py0pz(void) const;
|
||||
inline VoxelType peekVoxel0px1py1pz(void) const;
|
||||
|
||||
inline VoxelType peekVoxel1px1ny1nz(void) const;
|
||||
inline VoxelType peekVoxel1px1ny0pz(void) const;
|
||||
inline VoxelType peekVoxel1px1ny1pz(void) const;
|
||||
inline VoxelType peekVoxel1px0py1nz(void) const;
|
||||
inline VoxelType peekVoxel1px0py0pz(void) const;
|
||||
inline VoxelType peekVoxel1px0py1pz(void) const;
|
||||
inline VoxelType peekVoxel1px1py1nz(void) const;
|
||||
inline VoxelType peekVoxel1px1py0pz(void) const;
|
||||
inline VoxelType peekVoxel1px1py1pz(void) const;
|
||||
|
||||
private:
|
||||
|
||||
//Other current position information
|
||||
VoxelType* mCurrentVoxel;
|
||||
};
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// Constructor for creating a fixed size volume.
|
||||
RawVolume(const Region& regValid);
|
||||
|
||||
/// Destructor
|
||||
~RawVolume();
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const;
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
|
||||
|
||||
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate);
|
||||
/// Sets the voxel at the position given by a 3D vector
|
||||
void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate);
|
||||
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
|
||||
/// Sets the voxel at the position given by a 3D vector
|
||||
bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue);
|
||||
|
||||
/// Calculates approximatly how many bytes of memory the volume is currently using.
|
||||
uint32_t calculateSizeInBytes(void);
|
||||
|
||||
protected:
|
||||
/// Copy constructor
|
||||
RawVolume(const RawVolume& rhs);
|
||||
|
||||
/// Assignment operator
|
||||
RawVolume& operator=(const RawVolume& rhs);
|
||||
|
||||
private:
|
||||
void initialise(const Region& regValidRegion);
|
||||
|
||||
// A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const;
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const;
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const;
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const;
|
||||
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType tBorder) const;
|
||||
|
||||
//The voxel data
|
||||
VoxelType* m_pData;
|
||||
};
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/RawVolume.inl"
|
||||
#include "PolyVoxCore/RawVolumeSampler.inl"
|
||||
|
||||
#endif //__PolyVox_RawVolume_H__
|
390
include/PolyVoxCore/include/PolyVoxCore/RawVolume.inl
Normal file
390
include/PolyVoxCore/include/PolyVoxCore/RawVolume.inl
Normal file
@ -0,0 +1,390 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This constructor creates a volume with a fixed size which is specified as a parameter.
|
||||
/// \param regValid Specifies the minimum and maximum valid voxel positions.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
RawVolume<VoxelType>::RawVolume(const Region& regValid)
|
||||
:BaseVolume<VoxelType>(regValid)
|
||||
{
|
||||
this->setBorderValue(VoxelType());
|
||||
|
||||
//Create a volume of the right size.
|
||||
initialise(regValid);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing
|
||||
/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to
|
||||
/// make a copy of a volume and in this case you should look at the Volumeresampler.
|
||||
///
|
||||
/// \sa VolumeResampler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
RawVolume<VoxelType>::RawVolume(const RawVolume<VoxelType>& /*rhs*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Destroys the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
RawVolume<VoxelType>::~RawVolume()
|
||||
{
|
||||
delete[] m_pData;
|
||||
m_pData = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing
|
||||
/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to
|
||||
/// make a copy of a volume and in this case you should look at the Volumeresampler.
|
||||
///
|
||||
/// \sa VolumeResampler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
RawVolume<VoxelType>& RawVolume<VoxelType>::operator=(const RawVolume<VoxelType>& /*rhs*/)
|
||||
{
|
||||
POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function requires the wrap mode to be specified as a
|
||||
/// template parameter, which can provide better performance.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType RawVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const
|
||||
{
|
||||
// Simply call through to the real implementation
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<eWrapMode>(), tBorder);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function requires the wrap mode to be specified as a
|
||||
/// template parameter, which can provide better performance.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType RawVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const
|
||||
{
|
||||
// Simply call through to the real implementation
|
||||
return getVoxel<eWrapMode>(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function is provided so that the wrap mode does not need
|
||||
/// to be specified as a template parameter, as it may be confusing to some users.
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const
|
||||
{
|
||||
switch(eWrapMode)
|
||||
{
|
||||
case WrapModes::Validate:
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Validate>(), tBorder);
|
||||
case WrapModes::Clamp:
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Clamp>(), tBorder);
|
||||
case WrapModes::Border:
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Border>(), tBorder);
|
||||
case WrapModes::AssumeValid:
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder);
|
||||
default:
|
||||
// Should never happen
|
||||
POLYVOX_ASSERT(false, "Invalid wrap mode");
|
||||
return VoxelType();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This version of the function is provided so that the wrap mode does not need
|
||||
/// to be specified as a template parameter, as it may be confusing to some users.
|
||||
/// \param v3dPos The 3D position of the voxel
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const
|
||||
{
|
||||
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos The \c x position of the voxel
|
||||
/// \param uYPos The \c y position of the voxel
|
||||
/// \param uZPos The \c z position of the voxel
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)))
|
||||
{
|
||||
const Vector3DInt32& v3dLowerCorner = this->m_regValidRegion.getLowerCorner();
|
||||
int32_t iLocalXPos = uXPos - v3dLowerCorner.getX();
|
||||
int32_t iLocalYPos = uYPos - v3dLowerCorner.getY();
|
||||
int32_t iLocalZPos = uZPos - v3dLowerCorner.getZ();
|
||||
|
||||
return m_pData
|
||||
[
|
||||
iLocalXPos +
|
||||
iLocalYPos * this->getWidth() +
|
||||
iLocalZPos * this->getWidth() * this->getHeight()
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->getBorderValue();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos The 3D position of the voxel
|
||||
/// \return The voxel value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::getVoxelAt(const Vector3DInt32& v3dPos) const
|
||||
{
|
||||
return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos the \c x position of the voxel
|
||||
/// \param uYPos the \c y position of the voxel
|
||||
/// \param uZPos the \c z position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode)
|
||||
{
|
||||
if((eWrapMode != WrapModes::Validate) && (eWrapMode != WrapModes::AssumeValid))
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Invalid wrap mode in call to setVoxel(). It must be 'None' or 'DontCheck'.");
|
||||
}
|
||||
|
||||
// This validation is skipped if the wrap mode is 'DontCheck'
|
||||
if(eWrapMode == WrapModes::Validate)
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false)
|
||||
{
|
||||
POLYVOX_THROW(std::out_of_range, "Position is outside valid region");
|
||||
}
|
||||
}
|
||||
|
||||
const Vector3DInt32& v3dLowerCorner = this->m_regValidRegion.getLowerCorner();
|
||||
int32_t iLocalXPos = uXPos - v3dLowerCorner.getX();
|
||||
int32_t iLocalYPos = uYPos - v3dLowerCorner.getY();
|
||||
int32_t iLocalZPos = uZPos - v3dLowerCorner.getZ();
|
||||
|
||||
m_pData
|
||||
[
|
||||
iLocalXPos +
|
||||
iLocalYPos * this->getWidth() +
|
||||
iLocalZPos * this->getWidth() * this->getHeight()
|
||||
] = tValue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos the 3D position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
|
||||
/// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode)
|
||||
{
|
||||
setVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue, eWrapMode);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param uXPos the \c x position of the voxel
|
||||
/// \param uYPos the \c y position of the voxel
|
||||
/// \param uZPos the \c z position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \return whether the requested position is inside the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
bool RawVolume<VoxelType>::setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue)
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)))
|
||||
{
|
||||
const Vector3DInt32& v3dLowerCorner = this->m_regValidRegion.getLowerCorner();
|
||||
int32_t iLocalXPos = uXPos - v3dLowerCorner.getX();
|
||||
int32_t iLocalYPos = uYPos - v3dLowerCorner.getY();
|
||||
int32_t iLocalZPos = uZPos - v3dLowerCorner.getZ();
|
||||
|
||||
m_pData
|
||||
[
|
||||
iLocalXPos +
|
||||
iLocalYPos * this->getWidth() +
|
||||
iLocalZPos * this->getWidth() * this->getHeight()
|
||||
] = tValue;
|
||||
|
||||
//Return true to indicate that we modified a voxel.
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \param v3dPos the 3D position of the voxel
|
||||
/// \param tValue the value to which the voxel will be set
|
||||
/// \return whether the requested position is inside the volume
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
bool RawVolume<VoxelType>::setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue)
|
||||
{
|
||||
return setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// This function should probably be made internal...
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::initialise(const Region& regValidRegion)
|
||||
{
|
||||
this->m_regValidRegion = regValidRegion;
|
||||
|
||||
if(this->getWidth() <= 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Volume width must be greater than zero.");
|
||||
}
|
||||
if(this->getHeight() <= 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Volume height must be greater than zero.");
|
||||
}
|
||||
if(this->getDepth() <= 0)
|
||||
{
|
||||
POLYVOX_THROW(std::invalid_argument, "Volume depth must be greater than zero.");
|
||||
}
|
||||
|
||||
//Create the data
|
||||
m_pData = new VoxelType[this->getWidth() * this->getHeight()* this->getDepth()];
|
||||
|
||||
//Other properties we might find useful later
|
||||
this->m_uLongestSideLength = (std::max)((std::max)(this->getWidth(),this->getHeight()),this->getDepth());
|
||||
this->m_uShortestSideLength = (std::min)((std::min)(this->getWidth(),this->getHeight()),this->getDepth());
|
||||
this->m_fDiagonalLength = sqrtf(static_cast<float>(this->getWidth() * this->getWidth() + this->getHeight() * this->getHeight() + this->getDepth() * this->getDepth()));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Note: This function needs reviewing for accuracy...
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
uint32_t RawVolume<VoxelType>::calculateSizeInBytes(void)
|
||||
{
|
||||
return this->getWidth() * this->getHeight() * this->getDepth() * sizeof(VoxelType);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType RawVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const
|
||||
{
|
||||
// This function should never be called because one of the specialisations should always match.
|
||||
POLYVOX_ASSERT(false, "This function is not implemented and should never be called!");
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false)
|
||||
{
|
||||
POLYVOX_THROW(std::out_of_range, "Position is outside valid region");
|
||||
}
|
||||
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const
|
||||
{
|
||||
//Perform clamping
|
||||
uXPos = (std::max)(uXPos, this->m_regValidRegion.getLowerX());
|
||||
uYPos = (std::max)(uYPos, this->m_regValidRegion.getLowerY());
|
||||
uZPos = (std::max)(uZPos, this->m_regValidRegion.getLowerZ());
|
||||
uXPos = (std::min)(uXPos, this->m_regValidRegion.getUpperX());
|
||||
uYPos = (std::min)(uYPos, this->m_regValidRegion.getUpperY());
|
||||
uZPos = (std::min)(uZPos, this->m_regValidRegion.getUpperZ());
|
||||
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
|
||||
{
|
||||
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
|
||||
}
|
||||
else
|
||||
{
|
||||
return tBorder;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType /*tBorder*/) const
|
||||
{
|
||||
const Region& regValidRegion = this->m_regValidRegion;
|
||||
int32_t iLocalXPos = uXPos - regValidRegion.getLowerX();
|
||||
int32_t iLocalYPos = uYPos - regValidRegion.getLowerY();
|
||||
int32_t iLocalZPos = uZPos - regValidRegion.getLowerZ();
|
||||
|
||||
return m_pData
|
||||
[
|
||||
iLocalXPos +
|
||||
iLocalYPos * this->getWidth() +
|
||||
iLocalZPos * this->getWidth() * this->getHeight()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
505
include/PolyVoxCore/include/PolyVoxCore/RawVolumeSampler.inl
Normal file
505
include/PolyVoxCore/include/PolyVoxCore/RawVolumeSampler.inl
Normal file
@ -0,0 +1,505 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#define CAN_GO_NEG_X(val) (val > this->mVolume->getEnclosingRegion().getLowerX())
|
||||
#define CAN_GO_POS_X(val) (val < this->mVolume->getEnclosingRegion().getUpperX())
|
||||
#define CAN_GO_NEG_Y(val) (val > this->mVolume->getEnclosingRegion().getLowerY())
|
||||
#define CAN_GO_POS_Y(val) (val < this->mVolume->getEnclosingRegion().getUpperY())
|
||||
#define CAN_GO_NEG_Z(val) (val > this->mVolume->getEnclosingRegion().getLowerZ())
|
||||
#define CAN_GO_POS_Z(val) (val < this->mVolume->getEnclosingRegion().getUpperZ())
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename VoxelType>
|
||||
RawVolume<VoxelType>::Sampler::Sampler(RawVolume<VoxelType>* volume)
|
||||
:BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >(volume)
|
||||
,mCurrentVoxel(0)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
RawVolume<VoxelType>::Sampler::~Sampler()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::getVoxel(void) const
|
||||
{
|
||||
if(this->isCurrentPositionValid())
|
||||
{
|
||||
return *mCurrentVoxel;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::Sampler::setPosition(const Vector3DInt32& v3dNewPos)
|
||||
{
|
||||
setPosition(v3dNewPos.getX(), v3dNewPos.getY(), v3dNewPos.getZ());
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::Sampler::setPosition(int32_t xPos, int32_t yPos, int32_t zPos)
|
||||
{
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >::setPosition(xPos, yPos, zPos);
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if(this->isCurrentPositionValid())
|
||||
{
|
||||
const Vector3DInt32& v3dLowerCorner = this->mVolume->m_regValidRegion.getLowerCorner();
|
||||
int32_t iLocalXPos = xPos - v3dLowerCorner.getX();
|
||||
int32_t iLocalYPos = yPos - v3dLowerCorner.getY();
|
||||
int32_t iLocalZPos = zPos - v3dLowerCorner.getZ();
|
||||
|
||||
const int32_t uVoxelIndex = iLocalXPos +
|
||||
iLocalYPos * this->mVolume->getWidth() +
|
||||
iLocalZPos * this->mVolume->getWidth() * this->mVolume->getHeight();
|
||||
|
||||
mCurrentVoxel = this->mVolume->m_pData + uVoxelIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentVoxel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
bool RawVolume<VoxelType>::Sampler::setVoxel(VoxelType tValue)
|
||||
{
|
||||
//return m_bIsCurrentPositionValid ? *mCurrentVoxel : this->mVolume->getBorderValue();
|
||||
if(this->m_bIsCurrentPositionValidInX && this->m_bIsCurrentPositionValidInY && this->m_bIsCurrentPositionValidInZ)
|
||||
{
|
||||
*mCurrentVoxel = tValue;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::Sampler::movePositiveX(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >::movePositiveX();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if(this->isCurrentPositionValid() && bIsOldPositionValid )
|
||||
{
|
||||
++mCurrentVoxel;
|
||||
}
|
||||
else
|
||||
{
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::Sampler::movePositiveY(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >::movePositiveY();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if(this->isCurrentPositionValid() && bIsOldPositionValid )
|
||||
{
|
||||
mCurrentVoxel += this->mVolume->getWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::Sampler::movePositiveZ(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >::movePositiveZ();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if(this->isCurrentPositionValid() && bIsOldPositionValid )
|
||||
{
|
||||
mCurrentVoxel += this->mVolume->getWidth() * this->mVolume->getHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::Sampler::moveNegativeX(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >::moveNegativeX();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if(this->isCurrentPositionValid() && bIsOldPositionValid )
|
||||
{
|
||||
--mCurrentVoxel;
|
||||
}
|
||||
else
|
||||
{
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::Sampler::moveNegativeY(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >::moveNegativeY();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if(this->isCurrentPositionValid() && bIsOldPositionValid )
|
||||
{
|
||||
mCurrentVoxel -= this->mVolume->getWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void RawVolume<VoxelType>::Sampler::moveNegativeZ(void)
|
||||
{
|
||||
// We'll need this in a moment...
|
||||
bool bIsOldPositionValid = this->isCurrentPositionValid();
|
||||
|
||||
// Base version updates position and validity flags.
|
||||
BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >::moveNegativeZ();
|
||||
|
||||
// Then we update the voxel pointer
|
||||
if(this->isCurrentPositionValid() && bIsOldPositionValid )
|
||||
{
|
||||
mCurrentVoxel -= this->mVolume->getWidth() * this->mVolume->getHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx1ny1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 - this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx1ny0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 - this->mVolume->getWidth());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx1ny1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 - this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx0py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx0py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx0py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx1py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 + this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx1py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 + this->mVolume->getWidth());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx1py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - 1 + this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1ny1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1ny0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - this->mVolume->getWidth());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1ny1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px0py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px0py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()))
|
||||
{
|
||||
return *mCurrentVoxel;
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px0py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + this->mVolume->getWidth());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px1ny1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 - this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px1ny0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 - this->mVolume->getWidth());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px1ny1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 - this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px0py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px0py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1);
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px0py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px1py1nz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 + this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px1py0pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 + this->mVolume->getWidth());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px1py1pz(void) const
|
||||
{
|
||||
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
|
||||
{
|
||||
return *(mCurrentVoxel + 1 + this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight());
|
||||
}
|
||||
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
|
||||
}
|
||||
}
|
||||
|
||||
#undef CAN_GO_NEG_X
|
||||
#undef CAN_GO_POS_X
|
||||
#undef CAN_GO_NEG_Y
|
||||
#undef CAN_GO_POS_Y
|
||||
#undef CAN_GO_NEG_Z
|
||||
#undef CAN_GO_POS_Z
|
103
include/PolyVoxCore/include/PolyVoxCore/Raycast.h
Normal file
103
include/PolyVoxCore/include/PolyVoxCore/Raycast.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Raycast_H__
|
||||
#define __PolyVox_Raycast_H__
|
||||
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
namespace RaycastResults
|
||||
{
|
||||
/**
|
||||
* The results of a raycast
|
||||
*/
|
||||
enum RaycastResult
|
||||
{
|
||||
Completed, ///< If the ray passed through the volume without being interupted
|
||||
Interupted ///< If the ray was interupted while travelling
|
||||
};
|
||||
}
|
||||
typedef RaycastResults::RaycastResult RaycastResult;
|
||||
|
||||
/// OUT OF DATE SINCE UNCLASSING
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file Raycast.h
|
||||
///
|
||||
/// The principle behind raycasting is to fire a 'ray' through the volume and determine
|
||||
/// what (if anything) that ray hits. This simple test can be used for the purpose of
|
||||
/// picking, visibility checks, lighting calculations, or numerous other applications.
|
||||
///
|
||||
/// A ray is a stright line in space define by a start point and a direction vector.
|
||||
/// The length of the direction vector represents the length of the ray. When you call a
|
||||
/// Raycast object's execute() method it will iterate over each voxel which lies on the ray,
|
||||
/// starting from the defined start point. It will examine each voxel and terminate
|
||||
/// either when it encounters a solid voxel or when it reaches the end of the ray. If a
|
||||
/// solid voxel is encountered then its position is stored in the intersectionVoxel field
|
||||
/// of the RaycastResult structure and the intersectionFound flag is set to true, otherwise
|
||||
/// the intersectionFound flag is set to false.
|
||||
///
|
||||
/// **Important Note:** These has been confusion in the past with people not realising
|
||||
/// that the length of the direction vector is important. Most graphics API can provide
|
||||
/// a camera position and view direction for picking purposes, but the view direction is
|
||||
/// usually normalised (i.e. of length one). If you use this view direction directly you
|
||||
/// will only iterate over a single voxel and won't find what you are looking for. Instead
|
||||
/// you must scale the direction vector so that it's length represents the maximum distance
|
||||
/// over which you want the ray to be cast.
|
||||
///
|
||||
/// The following code snippet shows how the class is used:
|
||||
/// \code
|
||||
/// Vector3DFloat start(rayOrigin.x(), rayOrigin.y(), rayOrigin.z());
|
||||
/// Vector3DFloat direction(rayDir.x(), rayDir.y(), rayDir.z());
|
||||
/// direction.normalise();
|
||||
/// direction *= 1000.0f; //Casts ray of length 1000
|
||||
///
|
||||
/// RaycastResult raycastResult;
|
||||
/// Raycast<Material8> raycast(m_pPolyVoxVolume, start, direction, raycastResult);
|
||||
/// raycast.execute();
|
||||
///
|
||||
/// if(raycastResult.foundIntersection)
|
||||
/// {
|
||||
/// //...
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// Some further notes, the Raycast uses full 26-connectivity, which basically means it
|
||||
/// will examine every voxel the ray touches, even if it just passes through the corner.
|
||||
/// Also, it peforms a simple binary test against a voxel's threshold, rather than making
|
||||
/// use of it's density. Therefore it will work best in conjunction with one of the 'cubic'
|
||||
/// surace extractors. It's behaviour with the Marching Cubes surface extractor has not
|
||||
/// been tested yet.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename VolumeType, typename Callback>
|
||||
RaycastResult raycastWithEndpoints(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dEnd, Callback& callback);
|
||||
|
||||
template<typename VolumeType, typename Callback>
|
||||
RaycastResult raycastWithDirection(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, Callback& callback);
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/Raycast.inl"
|
||||
|
||||
#endif //__PolyVox_Raycast_H__
|
178
include/PolyVoxCore/include/PolyVoxCore/Raycast.inl
Normal file
178
include/PolyVoxCore/include/PolyVoxCore/Raycast.inl
Normal file
@ -0,0 +1,178 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
// This function is based on Christer Ericson's code and description of the 'Uniform Grid Intersection Test' in
|
||||
// 'Real Time Collision Detection'. The following information from the errata on the book website is also relevent:
|
||||
//
|
||||
// pages 326-327. In the function VisitCellsOverlapped() the two lines calculating tx and ty are incorrect.
|
||||
// The less-than sign in each line should be a greater-than sign. That is, the two lines should read:
|
||||
//
|
||||
// float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) / Abs(x2 - x1);
|
||||
// float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) / Abs(y2 - y1);
|
||||
//
|
||||
// Thanks to Jetro Lauha of Fathammer in Helsinki, Finland for reporting this error.
|
||||
//
|
||||
// Jetro also points out that the computations of i, j, iend, and jend are incorrectly rounded if the line
|
||||
// coordinates are allowed to go negative. While that was not really the intent of the code -- that is, I
|
||||
// assumed grids to be numbered from (0, 0) to (m, n) -- I'm at fault for not making my assumption clear.
|
||||
// Where it is important to handle negative line coordinates the computation of these variables should be
|
||||
// changed to something like this:
|
||||
//
|
||||
// // Determine start grid cell coordinates (i, j)
|
||||
// int i = (int)floorf(x1 / CELL_SIDE);
|
||||
// int j = (int)floorf(y1 / CELL_SIDE);
|
||||
//
|
||||
// // Determine end grid cell coordinates (iend, jend)
|
||||
// int iend = (int)floorf(x2 / CELL_SIDE);
|
||||
// int jend = (int)floorf(y2 / CELL_SIDE);
|
||||
//
|
||||
// page 328. The if-statement that reads "if (ty <= tx && ty <= tz)" has a superfluous condition.
|
||||
// It should simply read "if (ty <= tz)".
|
||||
//
|
||||
// This error was reported by Joey Hammer (PixelActive).
|
||||
|
||||
/**
|
||||
* Cast a ray through a volume by specifying the start and end positions
|
||||
*
|
||||
* The ray will move from \a v3dStart to \a v3dEnd, calling \a callback for each
|
||||
* voxel it passes through until \a callback returns \a false. In this case it
|
||||
* returns a RaycastResults::Interupted. If it passes from start to end
|
||||
* without \a callback returning \a false, it returns RaycastResults::Completed.
|
||||
*
|
||||
* \param volData The volume to pass the ray though
|
||||
* \param v3dStart The start position in the volume
|
||||
* \param v3dEnd The end position in the volume
|
||||
* \param callback The callback to call for each voxel
|
||||
*
|
||||
* \return A RaycastResults designating whether the ray hit anything or not
|
||||
*/
|
||||
template<typename VolumeType, typename Callback>
|
||||
RaycastResult raycastWithEndpoints(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dEnd, Callback& callback)
|
||||
{
|
||||
typename VolumeType::Sampler sampler(volData);
|
||||
|
||||
//The doRaycast function is assuming that it is iterating over the areas defined between
|
||||
//voxels. We actually want to define the areas as being centered on voxels (as this is
|
||||
//what the CubicSurfaceExtractor generates). We add 0.5 here to adjust for this.
|
||||
const float x1 = v3dStart.getX() + 0.5f;
|
||||
const float y1 = v3dStart.getY() + 0.5f;
|
||||
const float z1 = v3dStart.getZ() + 0.5f;
|
||||
const float x2 = v3dEnd.getX() + 0.5f;
|
||||
const float y2 = v3dEnd.getY() + 0.5f;
|
||||
const float z2 = v3dEnd.getZ() + 0.5f;
|
||||
|
||||
int i = (int)floorf(x1);
|
||||
int j = (int)floorf(y1);
|
||||
int k = (int)floorf(z1);
|
||||
|
||||
const int iend = (int)floorf(x2);
|
||||
const int jend = (int)floorf(y2);
|
||||
const int kend = (int)floorf(z2);
|
||||
|
||||
const int di = ((x1 < x2) ? 1 : ((x1 > x2) ? -1 : 0));
|
||||
const int dj = ((y1 < y2) ? 1 : ((y1 > y2) ? -1 : 0));
|
||||
const int dk = ((z1 < z2) ? 1 : ((z1 > z2) ? -1 : 0));
|
||||
|
||||
const float deltatx = 1.0f / std::abs(x2 - x1);
|
||||
const float deltaty = 1.0f / std::abs(y2 - y1);
|
||||
const float deltatz = 1.0f / std::abs(z2 - z1);
|
||||
|
||||
const float minx = floorf(x1), maxx = minx + 1.0f;
|
||||
float tx = ((x1 > x2) ? (x1 - minx) : (maxx - x1)) * deltatx;
|
||||
const float miny = floorf(y1), maxy = miny + 1.0f;
|
||||
float ty = ((y1 > y2) ? (y1 - miny) : (maxy - y1)) * deltaty;
|
||||
const float minz = floorf(z1), maxz = minz + 1.0f;
|
||||
float tz = ((z1 > z2) ? (z1 - minz) : (maxz - z1)) * deltatz;
|
||||
|
||||
sampler.setPosition(i,j,k);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(!callback(sampler))
|
||||
{
|
||||
return RaycastResults::Interupted;
|
||||
}
|
||||
|
||||
if(tx <= ty && tx <= tz)
|
||||
{
|
||||
if(i == iend) break;
|
||||
tx += deltatx;
|
||||
i += di;
|
||||
|
||||
if(di == 1) sampler.movePositiveX();
|
||||
if(di == -1) sampler.moveNegativeX();
|
||||
} else if (ty <= tz)
|
||||
{
|
||||
if(j == jend) break;
|
||||
ty += deltaty;
|
||||
j += dj;
|
||||
|
||||
if(dj == 1) sampler.movePositiveY();
|
||||
if(dj == -1) sampler.moveNegativeY();
|
||||
} else
|
||||
{
|
||||
if(k == kend) break;
|
||||
tz += deltatz;
|
||||
k += dk;
|
||||
|
||||
if(dk == 1) sampler.movePositiveZ();
|
||||
if(dk == -1) sampler.moveNegativeZ();
|
||||
}
|
||||
}
|
||||
|
||||
return RaycastResults::Completed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a ray through a volume by specifying the start and a direction
|
||||
*
|
||||
* The ray will move from \a v3dStart along \a v3dDirectionAndLength, calling
|
||||
* \a callback for each voxel it passes through until \a callback returns
|
||||
* \a false. In this case it returns a RaycastResults::Interupted. If it
|
||||
* passes from start to end without \a callback returning \a false, it
|
||||
* returns RaycastResults::Completed.
|
||||
*
|
||||
* \note These has been confusion in the past with people not realising
|
||||
* that the length of the direction vector is important. Most graphics API can provide
|
||||
* a camera position and view direction for picking purposes, but the view direction is
|
||||
* usually normalised (i.e. of length one). If you use this view direction directly you
|
||||
* will only iterate over a single voxel and won't find what you are looking for. Instead
|
||||
* you must scale the direction vector so that it's length represents the maximum distance
|
||||
* over which you want the ray to be cast.
|
||||
*
|
||||
* \param volData The volume to pass the ray though
|
||||
* \param v3dStart The start position in the volume
|
||||
* \param v3dDirectionAndLength The direction and length of the ray
|
||||
* \param callback The callback to call for each voxel
|
||||
*
|
||||
* \return A RaycastResults designating whether the ray hit anything or not
|
||||
*/
|
||||
template<typename VolumeType, typename Callback>
|
||||
RaycastResult raycastWithDirection(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, Callback& callback)
|
||||
{
|
||||
Vector3DFloat v3dEnd = v3dStart + v3dDirectionAndLength;
|
||||
return raycastWithEndpoints<VolumeType, Callback>(volData, v3dStart, v3dEnd, callback);
|
||||
}
|
||||
}
|
463
include/PolyVoxCore/include/PolyVoxCore/Region.h
Normal file
463
include/PolyVoxCore/include/PolyVoxCore/Region.h
Normal file
@ -0,0 +1,463 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Region_H__
|
||||
#define __PolyVox_Region_H__
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/** Represents a part of a Volume.
|
||||
*
|
||||
* Many operations in PolyVox are constrained to only part of a volume. For example, when running the surface extractors
|
||||
* it is unlikely that you will want to run it on the whole volume at once, as this will give a very large mesh which may
|
||||
* be too much to render. Instead you will probably want to run a surface extractor a number of times on different parts
|
||||
* of the volume, there by giving a number of meshes which can be culled and rendered seperately.
|
||||
*
|
||||
* The Region class is used to define these parts (regions) of the volume. Essentially it consists of an upper and lower
|
||||
* bound which specify the range of voxels positions considered to be part of the region. Note that these bounds are
|
||||
* <em>inclusive</em>.
|
||||
*
|
||||
* As well as the expected set of getters and setters, this class also provide utility functions for increasing and decresing
|
||||
* the size of the Region, shifting the Region in 3D space, testing whether it contains a given position, enlarging it so that
|
||||
* it does contain a given position, croppng it to another Region, and various other utility functions.
|
||||
*
|
||||
* \Note The dimensions of a region can be measured either in voxels or in cells. See the manual for more information
|
||||
* about these definitions.
|
||||
*
|
||||
*/
|
||||
#ifdef SWIG
|
||||
class Region
|
||||
#else
|
||||
class POLYVOX_API Region
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
|
||||
/// A Region with the lower corner set as low as possible and the upper corner set as high as possible.
|
||||
static Region MaxRegion();
|
||||
/// A Region with the lower corner set as high as possible and the upper corner set as low as possible.
|
||||
static Region InvertedRegion();
|
||||
|
||||
/// Constructor
|
||||
Region();
|
||||
/// Constructor
|
||||
Region(const Vector3DInt32& v3dLowerCorner, const Vector3DInt32& v3dUpperCorner);
|
||||
/// Constructor
|
||||
Region(int32_t iLowerX, int32_t iLowerY, int32_t iLowerZ, int32_t iUpperX, int32_t iUpperY, int32_t iUpperZ);
|
||||
|
||||
/// Equality Operator.
|
||||
bool operator==(const Region& rhs) const;
|
||||
/// Inequality Operator.
|
||||
bool operator!=(const Region& rhs) const;
|
||||
|
||||
/// Gets the 'x' position of the centre.
|
||||
int32_t getCentreX(void) const;
|
||||
/// Gets the 'y' position of the centre.
|
||||
int32_t getCentreY(void) const;
|
||||
/// Gets the 'z' position of the centrer.
|
||||
int32_t getCentreZ(void) const;
|
||||
/// Gets the 'x' position of the lower corner.
|
||||
int32_t getLowerX(void) const;
|
||||
/// Gets the 'y' position of the lower corner.
|
||||
int32_t getLowerY(void) const;
|
||||
/// Gets the 'z' position of the lower corner.
|
||||
int32_t getLowerZ(void) const;
|
||||
/// Gets the 'x' position of the upper corner.
|
||||
int32_t getUpperX(void) const;
|
||||
/// Gets the 'y' position of the upper corner.
|
||||
int32_t getUpperY(void) const;
|
||||
/// Gets the 'z' position of the upper corner.
|
||||
int32_t getUpperZ(void) const;
|
||||
|
||||
/// Gets the centre of the region
|
||||
Vector3DInt32 getCentre(void) const;
|
||||
/// Gets the position of the lower corner.
|
||||
Vector3DInt32 getLowerCorner(void) const;
|
||||
/// Gets the position of the upper corner.
|
||||
Vector3DInt32 getUpperCorner(void) const;
|
||||
|
||||
/// Gets the width of the region measured in voxels.
|
||||
int32_t getWidthInVoxels(void) const;
|
||||
/// Gets the height of the region measured in voxels.
|
||||
int32_t getHeightInVoxels(void) const;
|
||||
/// Gets the depth of the region measured in voxels.
|
||||
int32_t getDepthInVoxels(void) const;
|
||||
/// Gets the dimensions of the region measured in voxels.
|
||||
Vector3DInt32 getDimensionsInVoxels(void) const;
|
||||
|
||||
/// Gets the width of the region measured in cells.
|
||||
int32_t getWidthInCells(void) const;
|
||||
/// Gets the height of the region measured in cells.
|
||||
int32_t getHeightInCells(void) const;
|
||||
/// Gets the depth of the region measured in cells.
|
||||
int32_t getDepthInCells(void) const;
|
||||
/// Gets the dimensions of the region measured in cells.
|
||||
Vector3DInt32 getDimensionsInCells(void) const;
|
||||
|
||||
/// Sets the 'x' position of the lower corner.
|
||||
void setLowerX(int32_t iX);
|
||||
/// Sets the 'y' position of the lower corner.
|
||||
void setLowerY(int32_t iY);
|
||||
/// Sets the 'z' position of the lower corner.
|
||||
void setLowerZ(int32_t iZ);
|
||||
/// Sets the 'x' position of the upper corner.
|
||||
void setUpperX(int32_t iX);
|
||||
/// Sets the 'y' position of the upper corner.
|
||||
void setUpperY(int32_t iY);
|
||||
/// Sets the 'z' position of the upper corner.
|
||||
void setUpperZ(int32_t iZ);
|
||||
|
||||
/// Sets the position of the lower corner.
|
||||
void setLowerCorner(const Vector3DInt32& v3dLowerCorner);
|
||||
/// Sets the position of the upper corner.
|
||||
void setUpperCorner(const Vector3DInt32& v3dUpperCorner);
|
||||
|
||||
/// Tests whether the given point is contained in this Region.
|
||||
bool containsPoint(float fX, float fY, float fZ, float boundary = 0.0f) const;
|
||||
/// Tests whether the given point is contained in this Region.
|
||||
bool containsPoint(const Vector3DFloat& pos, float boundary = 0.0f) const;
|
||||
/// Tests whether the given point is contained in this Region.
|
||||
bool containsPoint(int32_t iX, int32_t iY, int32_t iZ, uint8_t boundary = 0) const;
|
||||
/// Tests whether the given point is contained in this Region.
|
||||
bool containsPoint(const Vector3DInt32& pos, uint8_t boundary = 0) const;
|
||||
/// Tests whether the given position is contained in the 'x' range of this Region.
|
||||
bool containsPointInX(float pos, float boundary = 0.0f) const;
|
||||
/// Tests whether the given position is contained in the 'x' range of this Region.
|
||||
bool containsPointInX(int32_t pos, uint8_t boundary = 0) const;
|
||||
/// Tests whether the given position is contained in the 'y' range of this Region.
|
||||
bool containsPointInY(float pos, float boundary = 0.0f) const;
|
||||
/// Tests whether the given position is contained in the 'y' range of this Region.
|
||||
bool containsPointInY(int32_t pos, uint8_t boundary = 0) const;
|
||||
/// Tests whether the given position is contained in the 'z' range of this Region.
|
||||
bool containsPointInZ(float pos, float boundary = 0.0f) const;
|
||||
/// Tests whether the given position is contained in the 'z' range of this Region.
|
||||
bool containsPointInZ(int32_t pos, uint8_t boundary = 0) const;
|
||||
|
||||
/// Tests whether the given Region is contained in this Region.
|
||||
bool containsRegion(const Region& reg, uint8_t boundary = 0) const;
|
||||
|
||||
/// Enlarges the Region so that it contains the specified position.
|
||||
void accumulate(int32_t iX, int32_t iY, int32_t iZ);
|
||||
/// Enlarges the Region so that it contains the specified position.
|
||||
void accumulate(const Vector3DInt32& v3dPos);
|
||||
/// Enlarges the Region so that it contains the specified Region.
|
||||
void accumulate(const Region& reg);
|
||||
|
||||
/// Crops the extents of this Region accoring to another Region.
|
||||
void cropTo(const Region& other);
|
||||
|
||||
/// Grows this region by the amount specified.
|
||||
void grow(int32_t iAmount);
|
||||
/// Grows this region by the amounts specified.
|
||||
void grow(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ);
|
||||
/// Grows this region by the amounts specified.
|
||||
void grow(const Vector3DInt32& v3dAmount);
|
||||
|
||||
/// Tests whether all components of the upper corner are at least
|
||||
/// as great as the corresponding components of the lower corner.
|
||||
bool isValid(void) const;
|
||||
|
||||
/// Moves the Region by the amount specified.
|
||||
void shift(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ);
|
||||
/// Moves the Region by the amount specified.
|
||||
void shift(const Vector3DInt32& v3dAmount);
|
||||
/// Moves the lower corner of the Region by the amount specified.
|
||||
void shiftLowerCorner(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ);
|
||||
/// Moves the lower corner of the Region by the amount specified.
|
||||
void shiftLowerCorner(const Vector3DInt32& v3dAmount);
|
||||
/// Moves the upper corner of the Region by the amount specified.
|
||||
void shiftUpperCorner(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ);
|
||||
/// Moves the upper corner of the Region by the amount specified.
|
||||
void shiftUpperCorner(const Vector3DInt32& v3dAmount);
|
||||
|
||||
/// Shrinks this region by the amount specified.
|
||||
void shrink(int32_t iAmount);
|
||||
/// Shrinks this region by the amounts specified.
|
||||
void shrink(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ);
|
||||
/// Shrinks this region by the amounts specified.
|
||||
void shrink(const Vector3DInt32& v3dAmount);
|
||||
|
||||
private:
|
||||
int32_t m_iLowerX;
|
||||
int32_t m_iLowerY;
|
||||
int32_t m_iLowerZ;
|
||||
int32_t m_iUpperX;
|
||||
int32_t m_iUpperY;
|
||||
int32_t m_iUpperZ;
|
||||
};
|
||||
|
||||
// Non-member functions
|
||||
bool intersects(const Region& a, const Region& b);
|
||||
|
||||
// Non-member overloaded operators.
|
||||
/// Stream insertion operator.
|
||||
std::ostream& operator<<(std::ostream& os, const Region& region);
|
||||
|
||||
// Functions to be inlined to to be in the header rather than the .cpp.
|
||||
// 'inline' keyword is used for the definition rather than the declaration.
|
||||
// See also http://www.parashift.com/c++-faq-lite/inline-functions.html
|
||||
|
||||
/**
|
||||
* \return The 'x' position of the centre.
|
||||
*/
|
||||
inline int32_t Region::getCentreX(void) const
|
||||
{
|
||||
return (m_iLowerX + m_iUpperX) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The 'y' position of the centre.
|
||||
*/
|
||||
inline int32_t Region::getCentreY(void) const
|
||||
{
|
||||
return (m_iLowerY + m_iUpperY) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The 'z' position of the centre.
|
||||
*/
|
||||
inline int32_t Region::getCentreZ(void) const
|
||||
{
|
||||
return (m_iLowerZ + m_iUpperZ) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The 'x' position of the lower corner.
|
||||
*/
|
||||
inline int32_t Region::getLowerX(void) const
|
||||
{
|
||||
return m_iLowerX;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The 'y' position of the lower corner.
|
||||
*/
|
||||
inline int32_t Region::getLowerY(void) const
|
||||
{
|
||||
return m_iLowerY;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The 'z' position of the lower corner.
|
||||
*/
|
||||
inline int32_t Region::getLowerZ(void) const
|
||||
{
|
||||
return m_iLowerZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The 'x' position of the upper corner.
|
||||
*/
|
||||
inline int32_t Region::getUpperX(void) const
|
||||
{
|
||||
return m_iUpperX;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The 'y' position of the upper corner.
|
||||
*/
|
||||
inline int32_t Region::getUpperY(void) const
|
||||
{
|
||||
return m_iUpperY;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The 'z' position of the upper corner.
|
||||
*/
|
||||
inline int32_t Region::getUpperZ(void) const
|
||||
{
|
||||
return m_iUpperZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The position of the lower corner.
|
||||
*/
|
||||
inline Vector3DInt32 Region::getCentre(void) const
|
||||
{
|
||||
return Vector3DInt32(getCentreX(), getCentreY(), getCentreZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The position of the lower corner.
|
||||
*/
|
||||
inline Vector3DInt32 Region::getLowerCorner(void) const
|
||||
{
|
||||
return Vector3DInt32(m_iLowerX, m_iLowerY, m_iLowerZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The position of the upper corner.
|
||||
*/
|
||||
inline Vector3DInt32 Region::getUpperCorner(void) const
|
||||
{
|
||||
return Vector3DInt32(m_iUpperX, m_iUpperY, m_iUpperZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The width of the region measured in voxels.
|
||||
* \sa getWidthInCells()
|
||||
*/
|
||||
inline int32_t Region::getWidthInVoxels(void) const
|
||||
{
|
||||
return getWidthInCells() + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The height of the region measured in voxels.
|
||||
* \sa getHeightInCells()
|
||||
*/
|
||||
inline int32_t Region::getHeightInVoxels(void) const
|
||||
{
|
||||
return getHeightInCells() + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The depth of the region measured in voxels.
|
||||
* \sa getDepthInCells()
|
||||
*/
|
||||
inline int32_t Region::getDepthInVoxels(void) const
|
||||
{
|
||||
return getDepthInCells() + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The dimensions of the region measured in voxels.
|
||||
* \sa getDimensionsInCells()
|
||||
*/
|
||||
inline Vector3DInt32 Region::getDimensionsInVoxels(void) const
|
||||
{
|
||||
return getDimensionsInCells() + Vector3DInt32(1, 1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The width of the region measured in cells.
|
||||
* \sa getWidthInVoxels()
|
||||
*/
|
||||
inline int32_t Region::getWidthInCells(void) const
|
||||
{
|
||||
return m_iUpperX - m_iLowerX;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The height of the region measured in cells.
|
||||
* \sa getHeightInVoxels()
|
||||
*/
|
||||
inline int32_t Region::getHeightInCells(void) const
|
||||
{
|
||||
return m_iUpperY - m_iLowerY;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The depth of the region measured in cells.
|
||||
* \sa getDepthInVoxels()
|
||||
*/
|
||||
inline int32_t Region::getDepthInCells(void) const
|
||||
{
|
||||
return m_iUpperZ - m_iLowerZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The dimensions of the region measured in cells.
|
||||
* \sa getDimensionsInVoxels()
|
||||
*/
|
||||
inline Vector3DInt32 Region::getDimensionsInCells(void) const
|
||||
{
|
||||
return Vector3DInt32(getWidthInCells(), getHeightInCells(), getDepthInCells());
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iX The new 'x' position of the lower corner.
|
||||
*/
|
||||
inline void Region::setLowerX(int32_t iX)
|
||||
{
|
||||
m_iLowerX = iX;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iY The new 'y' position of the lower corner.
|
||||
*/
|
||||
inline void Region::setLowerY(int32_t iY)
|
||||
{
|
||||
m_iLowerY = iY;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iZ The new 'z' position of the lower corner.
|
||||
*/
|
||||
inline void Region::setLowerZ(int32_t iZ)
|
||||
{
|
||||
m_iLowerZ = iZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iX The new 'x' position of the upper corner.
|
||||
*/
|
||||
inline void Region::setUpperX(int32_t iX)
|
||||
{
|
||||
m_iUpperX = iX;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iY The new 'y' position of the upper corner.
|
||||
*/
|
||||
inline void Region::setUpperY(int32_t iY)
|
||||
{
|
||||
m_iUpperY = iY;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iZ The new 'z' position of the upper corner.
|
||||
*/
|
||||
inline void Region::setUpperZ(int32_t iZ)
|
||||
{
|
||||
m_iUpperZ = iZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param v3dLowerCorner The new position of the lower corner.
|
||||
*/
|
||||
inline void Region::setLowerCorner(const Vector3DInt32& v3dLowerCorner)
|
||||
{
|
||||
m_iLowerX = v3dLowerCorner.getX();
|
||||
m_iLowerY = v3dLowerCorner.getY();
|
||||
m_iLowerZ = v3dLowerCorner.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* \param v3dUpperCorner The new position of the upper corner.
|
||||
*/
|
||||
inline void Region::setUpperCorner(const Vector3DInt32& v3dUpperCorner)
|
||||
{
|
||||
m_iUpperX = v3dUpperCorner.getX();
|
||||
m_iUpperY = v3dUpperCorner.getY();
|
||||
m_iUpperZ = v3dUpperCorner.getZ();
|
||||
}
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/Region.inl"
|
||||
|
||||
#endif
|
518
include/PolyVoxCore/include/PolyVoxCore/Region.inl
Normal file
518
include/PolyVoxCore/include/PolyVoxCore/Region.inl
Normal file
@ -0,0 +1,518 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
*/
|
||||
inline Region Region::MaxRegion()
|
||||
{
|
||||
return Region(
|
||||
(std::numeric_limits<int32_t>::min)(), (std::numeric_limits<int32_t>::min)(), (std::numeric_limits<int32_t>::min)(),
|
||||
(std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)());
|
||||
}
|
||||
|
||||
/**
|
||||
* This Region is not considered valid as defined by isValid(). It's main application
|
||||
* is to initialise a Region to this value and then() accumulate positions. The result
|
||||
* of this will be a Region which encompasses all positions specified.
|
||||
*/
|
||||
inline Region Region::InvertedRegion()
|
||||
{
|
||||
return Region(
|
||||
(std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)(),
|
||||
(std::numeric_limits<int32_t>::min)(), (std::numeric_limits<int32_t>::min)(), (std::numeric_limits<int32_t>::min)());
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iX The 'x' component of the position to accumulate.
|
||||
* \param iY The 'y' component of the position to accumulate.
|
||||
* \param iZ The 'z' component of the position to accumulate.
|
||||
*/
|
||||
inline void Region::accumulate(int32_t iX, int32_t iY, int32_t iZ)
|
||||
{
|
||||
m_iLowerX = ((std::min)(m_iLowerX, iX));
|
||||
m_iLowerY = ((std::min)(m_iLowerY, iY));
|
||||
m_iLowerZ = ((std::min)(m_iLowerZ, iZ));
|
||||
m_iUpperX = ((std::max)(m_iUpperX, iX));
|
||||
m_iUpperY = ((std::max)(m_iUpperY, iY));
|
||||
m_iUpperZ = ((std::max)(m_iUpperZ, iZ));
|
||||
}
|
||||
|
||||
/**
|
||||
* \param v3dPos The position to accumulate.
|
||||
*/
|
||||
inline void Region::accumulate(const Vector3DInt32& v3dPos)
|
||||
{
|
||||
accumulate(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that this is not the same as computing the union of two Regions (as the result of
|
||||
* such a union may not be a shape which can be exactly represented by a Region). Instead,
|
||||
* the result is simply big enough to contain both this Region and the one passed as a parameter.
|
||||
* \param reg The Region to accumulate. This must be valid as defined by the isValid() function.
|
||||
* \sa isValid()
|
||||
*/
|
||||
inline void Region::accumulate(const Region& reg)
|
||||
{
|
||||
if(!reg.isValid())
|
||||
{
|
||||
POLYVOX_THROW(invalid_operation, "You cannot accumulate an invalid region."); //The result of accumulating an invalid region is not defined.
|
||||
}
|
||||
|
||||
m_iLowerX = ((std::min)(m_iLowerX, reg.getLowerX()));
|
||||
m_iLowerY = ((std::min)(m_iLowerY, reg.getLowerY()));
|
||||
m_iLowerZ = ((std::min)(m_iLowerZ, reg.getLowerZ()));
|
||||
m_iUpperX = ((std::max)(m_iUpperX, reg.getUpperX()));
|
||||
m_iUpperY = ((std::max)(m_iUpperY, reg.getUpperY()));
|
||||
m_iUpperZ = ((std::max)(m_iUpperZ, reg.getUpperZ()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Region and clears all extents to zero.
|
||||
*/
|
||||
inline Region::Region()
|
||||
:m_iLowerX(0)
|
||||
,m_iLowerY(0)
|
||||
,m_iLowerZ(0)
|
||||
,m_iUpperX(0)
|
||||
,m_iUpperY(0)
|
||||
,m_iUpperZ(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Region and sets the lower and upper corners to the specified values.
|
||||
* \param v3dLowerCorner The desired lower corner of the Region.
|
||||
* \param v3dUpperCorner The desired upper corner of the Region.
|
||||
*/
|
||||
inline Region::Region(const Vector3DInt32& v3dLowerCorner, const Vector3DInt32& v3dUpperCorner)
|
||||
:m_iLowerX(v3dLowerCorner.getX())
|
||||
,m_iLowerY(v3dLowerCorner.getY())
|
||||
,m_iLowerZ(v3dLowerCorner.getZ())
|
||||
,m_iUpperX(v3dUpperCorner.getX())
|
||||
,m_iUpperY(v3dUpperCorner.getY())
|
||||
,m_iUpperZ(v3dUpperCorner.getZ())
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Region and sets the extents to the specified values.
|
||||
* \param iLowerX The desired lower 'x' extent of the Region.
|
||||
* \param iLowerY The desired lower 'y' extent of the Region.
|
||||
* \param iLowerZ The desired lower 'z' extent of the Region.
|
||||
* \param iUpperX The desired upper 'x' extent of the Region.
|
||||
* \param iUpperY The desired upper 'y' extent of the Region.
|
||||
* \param iUpperZ The desired upper 'z' extent of the Region.
|
||||
*/
|
||||
inline Region::Region(int32_t iLowerX, int32_t iLowerY, int32_t iLowerZ, int32_t iUpperX, int32_t iUpperY, int32_t iUpperZ)
|
||||
:m_iLowerX(iLowerX)
|
||||
,m_iLowerY(iLowerY)
|
||||
,m_iLowerZ(iLowerZ)
|
||||
,m_iUpperX(iUpperX)
|
||||
,m_iUpperY(iUpperY)
|
||||
,m_iUpperZ(iUpperZ)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Two regions are considered equal if all their extents match.
|
||||
* \param rhs The Region to compare to.
|
||||
* \return true if the Regions match.
|
||||
* \sa operator!=
|
||||
*/
|
||||
inline bool Region::operator==(const Region& rhs) const
|
||||
{
|
||||
return ((m_iLowerX == rhs.m_iLowerX) && (m_iLowerY == rhs.m_iLowerY) && (m_iLowerZ == rhs.m_iLowerZ)
|
||||
&& (m_iUpperX == rhs.m_iUpperX) && (m_iUpperY == rhs.m_iUpperY) && (m_iUpperZ == rhs.m_iUpperZ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Two regions are considered different if any of their extents differ.
|
||||
* \param rhs The Region to compare to.
|
||||
* \return true if the Regions are different.
|
||||
* \sa operator==
|
||||
*/
|
||||
inline bool Region::operator!=(const Region& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in all directions. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param fX The 'x' position of the point to test.
|
||||
* \param fY The 'y' position of the point to test.
|
||||
* \param fZ The 'z' position of the point to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPoint(float fX, float fY, float fZ, float boundary) const
|
||||
{
|
||||
return (fX <= m_iUpperX - boundary)
|
||||
&& (fY <= m_iUpperY - boundary)
|
||||
&& (fZ <= m_iUpperZ - boundary)
|
||||
&& (fX >= m_iLowerX + boundary)
|
||||
&& (fY >= m_iLowerY + boundary)
|
||||
&& (fZ >= m_iLowerZ + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in all directions. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param pos The position to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPoint(const Vector3DFloat& pos, float boundary) const
|
||||
{
|
||||
return containsPoint(pos.getX(), pos.getY(), pos.getZ(), boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in all directions. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param iX The 'x' position of the point to test.
|
||||
* \param iY The 'y' position of the point to test.
|
||||
* \param iZ The 'z' position of the point to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPoint(int32_t iX, int32_t iY, int32_t iZ, uint8_t boundary) const
|
||||
{
|
||||
return (iX <= m_iUpperX - boundary)
|
||||
&& (iY <= m_iUpperY - boundary)
|
||||
&& (iZ <= m_iUpperZ - boundary)
|
||||
&& (iX >= m_iLowerX + boundary)
|
||||
&& (iY >= m_iLowerY + boundary)
|
||||
&& (iZ >= m_iLowerZ + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in all directions. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param pos The position to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPoint(const Vector3DInt32& pos, uint8_t boundary) const
|
||||
{
|
||||
return containsPoint(pos.getX(), pos.getY(), pos.getZ(), boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in the 'x' direction. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param pos The position to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPointInX(float pos, float boundary) const
|
||||
{
|
||||
return (pos <= m_iUpperX - boundary)
|
||||
&& (pos >= m_iLowerX + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in the 'x' direction. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param pos The position to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPointInX(int32_t pos, uint8_t boundary) const
|
||||
{
|
||||
return (pos <= m_iUpperX - boundary)
|
||||
&& (pos >= m_iLowerX + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in the 'y' direction. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param pos The position to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPointInY(float pos, float boundary) const
|
||||
{
|
||||
return (pos <= m_iUpperY - boundary)
|
||||
&& (pos >= m_iLowerY + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in the 'y' direction. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param pos The position to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPointInY(int32_t pos, uint8_t boundary) const
|
||||
{
|
||||
return (pos <= m_iUpperY - boundary)
|
||||
&& (pos >= m_iLowerY + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in the 'z' direction. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param pos The position to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPointInZ(float pos, float boundary) const
|
||||
{
|
||||
return (pos <= m_iUpperZ - boundary)
|
||||
&& (pos >= m_iLowerZ + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a position is only considered to be inside
|
||||
* the Region if it is that far in in the 'z' direction. Also, the test is inclusive such
|
||||
* that positions lying exactly on the edge of the Region are considered to be inside it.
|
||||
* \param pos The position to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsPointInZ(int32_t pos, uint8_t boundary) const
|
||||
{
|
||||
return (pos <= m_iUpperZ - boundary)
|
||||
&& (pos >= m_iLowerZ + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* The boundary value can be used to ensure a region is only considered to be inside
|
||||
* another Region if it is that far in in all directions. Also, the test is inclusive such
|
||||
* that a region is considered to be inside of itself.
|
||||
* \param reg The region to test.
|
||||
* \param boundary The desired boundary value.
|
||||
*/
|
||||
inline bool Region::containsRegion(const Region& reg, uint8_t boundary) const
|
||||
{
|
||||
return (reg.m_iUpperX <= m_iUpperX - boundary)
|
||||
&& (reg.m_iUpperY <= m_iUpperY - boundary)
|
||||
&& (reg.m_iUpperZ <= m_iUpperZ - boundary)
|
||||
&& (reg.m_iLowerX >= m_iLowerX + boundary)
|
||||
&& (reg.m_iLowerY >= m_iLowerY + boundary)
|
||||
&& (reg.m_iLowerZ >= m_iLowerZ + boundary);
|
||||
}
|
||||
|
||||
/**
|
||||
* After calling this functions, the extents of this Region are given by the intersection
|
||||
* of this Region and the one it was cropped to.
|
||||
* \param other The Region to crop to.
|
||||
*/
|
||||
inline void Region::cropTo(const Region& other)
|
||||
{
|
||||
m_iLowerX = ((std::max)(m_iLowerX, other.m_iLowerX));
|
||||
m_iLowerY = ((std::max)(m_iLowerY, other.m_iLowerY));
|
||||
m_iLowerZ = ((std::max)(m_iLowerZ, other.m_iLowerZ));
|
||||
m_iUpperX = ((std::min)(m_iUpperX, other.m_iUpperX));
|
||||
m_iUpperY = ((std::min)(m_iUpperY, other.m_iUpperY));
|
||||
m_iUpperZ = ((std::min)(m_iUpperZ, other.m_iUpperZ));
|
||||
}
|
||||
|
||||
/**
|
||||
* The same amount of growth is applied in all directions. Negative growth
|
||||
* is possible but you should prefer the shrink() function for clarity.
|
||||
* \param iAmount The amount to grow by.
|
||||
*/
|
||||
inline void Region::grow(int32_t iAmount)
|
||||
{
|
||||
m_iLowerX -= iAmount;
|
||||
m_iLowerY -= iAmount;
|
||||
m_iLowerZ -= iAmount;
|
||||
|
||||
m_iUpperX += iAmount;
|
||||
m_iUpperY += iAmount;
|
||||
m_iUpperZ += iAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount can be specified seperatly for each direction. Negative growth
|
||||
* is possible but you should prefer the shrink() function for clarity.
|
||||
* \param iAmountX The amount to grow by in 'x'.
|
||||
* \param iAmountY The amount to grow by in 'y'.
|
||||
* \param iAmountZ The amount to grow by in 'z'.
|
||||
*/
|
||||
inline void Region::grow(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ)
|
||||
{
|
||||
m_iLowerX -= iAmountX;
|
||||
m_iLowerY -= iAmountY;
|
||||
m_iLowerZ -= iAmountZ;
|
||||
|
||||
m_iUpperX += iAmountX;
|
||||
m_iUpperY += iAmountY;
|
||||
m_iUpperZ += iAmountZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount can be specified seperatly for each direction. Negative growth
|
||||
* is possible but you should prefer the shrink() function for clarity.
|
||||
* \param v3dAmount The amount to grow by (one component for each direction).
|
||||
*/
|
||||
inline void Region::grow(const Vector3DInt32& v3dAmount)
|
||||
{
|
||||
grow(v3dAmount.getX(), v3dAmount.getY(), v3dAmount.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
inline bool Region::isValid(void) const
|
||||
{
|
||||
return (m_iUpperX >= m_iLowerX) && (m_iUpperY >= m_iLowerY) && (m_iUpperZ >= m_iLowerZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iAmountX The amount to move the Region by in 'x'.
|
||||
* \param iAmountY The amount to move the Region by in 'y'.
|
||||
* \param iAmountZ The amount to move the Region by in 'z'.
|
||||
*/
|
||||
inline void Region::shift(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ)
|
||||
{
|
||||
shiftLowerCorner(iAmountX, iAmountY, iAmountZ);
|
||||
shiftUpperCorner(iAmountX, iAmountY, iAmountZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param v3dAmount The amount to move the Region by.
|
||||
*/
|
||||
inline void Region::shift(const Vector3DInt32& v3dAmount)
|
||||
{
|
||||
shiftLowerCorner(v3dAmount);
|
||||
shiftUpperCorner(v3dAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iAmountX The amount to move the lower corner by in 'x'.
|
||||
* \param iAmountY The amount to move the lower corner by in 'y'.
|
||||
* \param iAmountZ The amount to move the lower corner by in 'z'.
|
||||
*/
|
||||
inline void Region::shiftLowerCorner(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ)
|
||||
{
|
||||
m_iLowerX += iAmountX;
|
||||
m_iLowerY += iAmountY;
|
||||
m_iLowerZ += iAmountZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param v3dAmount The amount to move the lower corner by.
|
||||
*/
|
||||
inline void Region::shiftLowerCorner(const Vector3DInt32& v3dAmount)
|
||||
{
|
||||
shiftLowerCorner(v3dAmount.getX(), v3dAmount.getY(), v3dAmount.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* \param iAmountX The amount to move the upper corner by in 'x'.
|
||||
* \param iAmountY The amount to move the upper corner by in 'y'.
|
||||
* \param iAmountZ The amount to move the upper corner by in 'z'.
|
||||
*/
|
||||
inline void Region::shiftUpperCorner(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ)
|
||||
{
|
||||
m_iUpperX += iAmountX;
|
||||
m_iUpperY += iAmountY;
|
||||
m_iUpperZ += iAmountZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param v3dAmount The amount to move the upper corner by.
|
||||
*/
|
||||
inline void Region::shiftUpperCorner(const Vector3DInt32& v3dAmount)
|
||||
{
|
||||
shiftUpperCorner(v3dAmount.getX(), v3dAmount.getY(), v3dAmount.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* The same amount of shrinkage is applied in all directions. Negative shrinkage
|
||||
* is possible but you should prefer the grow() function for clarity.
|
||||
* \param iAmount The amount to shrink by.
|
||||
*/
|
||||
inline void Region::shrink(int32_t iAmount)
|
||||
{
|
||||
m_iLowerX += iAmount;
|
||||
m_iLowerY += iAmount;
|
||||
m_iLowerZ += iAmount;
|
||||
|
||||
m_iUpperX -= iAmount;
|
||||
m_iUpperY -= iAmount;
|
||||
m_iUpperZ -= iAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount can be specified seperatly for each direction. Negative shrinkage
|
||||
* is possible but you should prefer the grow() function for clarity.
|
||||
* \param iAmountX The amount to shrink by in 'x'.
|
||||
* \param iAmountY The amount to shrink by in 'y'.
|
||||
* \param iAmountZ The amount to shrink by in 'z'.
|
||||
*/
|
||||
inline void Region::shrink(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ)
|
||||
{
|
||||
m_iLowerX += iAmountX;
|
||||
m_iLowerY += iAmountY;
|
||||
m_iLowerZ += iAmountZ;
|
||||
|
||||
m_iUpperX -= iAmountX;
|
||||
m_iUpperY -= iAmountY;
|
||||
m_iUpperZ -= iAmountZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount can be specified seperatly for each direction. Negative shrinkage
|
||||
* is possible but you should prefer the grow() function for clarity.
|
||||
* \param v3dAmount The amount to shrink by (one component for each direction).
|
||||
*/
|
||||
inline void Region::shrink(const Vector3DInt32& v3dAmount)
|
||||
{
|
||||
shrink(v3dAmount.getX(), v3dAmount.getY(), v3dAmount.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* This function only returns true if the regions are really intersecting and not simply touching.
|
||||
*/
|
||||
inline bool intersects(const Region& a, const Region& b)
|
||||
{
|
||||
// No intersection if seperated along an axis.
|
||||
if(a.getUpperX() < b.getLowerX() || a.getLowerX() > b.getUpperX()) return false;
|
||||
if(a.getUpperY() < b.getLowerY() || a.getLowerY() > b.getUpperY()) return false;
|
||||
if(a.getUpperZ() < b.getLowerZ() || a.getLowerZ() > b.getUpperZ()) return false;
|
||||
|
||||
// Overlapping on all axes means Regions are intersecting.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the Region to be used intuitively with output streams such as cout.
|
||||
* \param os The output stream to write to.
|
||||
* \param region The Region to write to the stream.
|
||||
* \return A reference to the output stream to allow chaining.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& os, const Region& region)
|
||||
{
|
||||
os << "(" << region.getLowerX() << "," << region.getLowerY() << "," << region.getLowerZ() <<
|
||||
") to (" << region.getUpperX() << "," << region.getUpperY() << "," << region.getUpperZ() << ")";
|
||||
return os;
|
||||
}
|
||||
}
|
9
include/PolyVoxCore/include/PolyVoxCore/SimpleVolume.h
Normal file
9
include/PolyVoxCore/include/PolyVoxCore/SimpleVolume.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __PolyVox_SimpleVolume_H__
|
||||
#define __PolyVox_SimpleVolume_H__
|
||||
|
||||
#pragma message("WARNING - The SimpleVolume class has been replaced by PagedVolume. Please use that instead.")
|
||||
|
||||
#include "PagedVolume.h"
|
||||
#include "PolyVoxForwardDeclarations.h"
|
||||
|
||||
#endif //__PolyVox_SimpleVolume_H__
|
248
include/PolyVoxCore/include/PolyVoxCore/Vector.h
Normal file
248
include/PolyVoxCore/include/PolyVoxCore/Vector.h
Normal file
@ -0,0 +1,248 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Vector_H__
|
||||
#define __PolyVox_Vector_H__
|
||||
|
||||
#include "Impl/ErrorHandling.h"
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include "PolyVoxForwardDeclarations.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
* Represents a vector in space.
|
||||
*
|
||||
* This is a generl purpose vector class designed to represent both positions and directions. It is templatised
|
||||
* on both size and data type but 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.
|
||||
*
|
||||
* Every Vector must have at at least two elements, and the first four elements of any vector are known as the
|
||||
* X, Y, Z and W elements. Note that W is last even though it comes before X in the alphabet. These elements can
|
||||
* be accessed through getX(), setX(), getY(), setY(), getZ(), setZ(), getW() and setW(), while other elements
|
||||
* can be accessed through getElemen() and setElement().
|
||||
*
|
||||
* This class includes a number of common mathematical operations (addition, subtraction, etc) as well as vector
|
||||
* specific operations such as the dot and cross products. Note that this class is also templatised on an
|
||||
* OperationType which is used for many internal calculations and some results. For example, the square of a
|
||||
* vector's length will always be an integer if all the elements are integers, but the value might be outside
|
||||
* that which can be represented by the StorageType. You don't need to worry about this as long as you are using
|
||||
* the built in typedefs for common configurations.
|
||||
*
|
||||
* Typedefs are provided for 2, 3 and 4 dimensional vector with int8_t, uint8_t, int16_t, uint6_t, int32_t,
|
||||
* uint32_t, float and double types. These typedefs are used as follows:
|
||||
*
|
||||
* \code
|
||||
* Vector2DInt32 test(1,2); //Declares a 2 dimensional Vector of type int32_t.
|
||||
* \endcode
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
class Vector
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
Vector(void);
|
||||
/// Constructor.
|
||||
Vector(StorageType tFillValue);
|
||||
/// Constructor.
|
||||
Vector(StorageType x, StorageType y);
|
||||
/// Constructor.
|
||||
Vector(StorageType x, StorageType y, StorageType z);
|
||||
/// Constructor.
|
||||
Vector(StorageType x, StorageType y, StorageType z, StorageType w);
|
||||
/// Copy Constructor.
|
||||
Vector(const Vector<Size,StorageType,OperationType>& vector);
|
||||
/// Copy Constructor which performs casting.
|
||||
template <typename CastType> explicit Vector(const Vector<Size,CastType>& vector);
|
||||
/// Destructor.
|
||||
~Vector(void);
|
||||
|
||||
/// Assignment Operator.
|
||||
Vector<Size,StorageType,OperationType>& operator=(const Vector<Size,StorageType,OperationType>& rhs);
|
||||
/// Equality Operator.
|
||||
bool operator==(const Vector<Size,StorageType,OperationType>& rhs) const;
|
||||
/// Inequality Operator.
|
||||
bool operator!=(const Vector<Size,StorageType,OperationType>& rhs) const;
|
||||
/// Comparison Operator.
|
||||
POLYVOX_DEPRECATED bool operator<(const Vector<Size,StorageType,OperationType>& rhs) const;
|
||||
/// Addition and Assignment Operator.
|
||||
Vector<Size,StorageType,OperationType>& operator+=(const Vector<Size,StorageType,OperationType> &rhs);
|
||||
/// Subtraction and Assignment Operator.
|
||||
Vector<Size,StorageType,OperationType>& operator-=(const Vector<Size,StorageType,OperationType> &rhs);
|
||||
/// Multiplication and Assignment Operator.
|
||||
Vector<Size,StorageType,OperationType>& operator*=(const Vector<Size,StorageType,OperationType> &rhs);
|
||||
/// Division and Assignment Operator.
|
||||
Vector<Size,StorageType,OperationType>& operator/=(const Vector<Size,StorageType,OperationType> &rhs);
|
||||
/// Multiplication and Assignment Operator.
|
||||
Vector<Size,StorageType,OperationType>& operator*=(const StorageType& rhs);
|
||||
/// Division and Assignment Operator.
|
||||
Vector<Size,StorageType,OperationType>& operator/=(const StorageType& rhs);
|
||||
|
||||
/// Element Access.
|
||||
StorageType getElement(uint32_t index) const;
|
||||
/// Get the x component of the vector.
|
||||
StorageType getX(void) const;
|
||||
/// Get the y component of the vector.
|
||||
StorageType getY(void) const;
|
||||
/// Get the z component of the vector.
|
||||
StorageType getZ(void) const;
|
||||
/// Get the w component of the vector.
|
||||
StorageType getW(void) const;
|
||||
|
||||
/// Element Access.
|
||||
void setElement(uint32_t index, StorageType tValue);
|
||||
/// Element Access.
|
||||
void setElements(StorageType x, StorageType y);
|
||||
/// Element Access.
|
||||
void setElements(StorageType x, StorageType y, StorageType z);
|
||||
/// Element Access.
|
||||
void setElements(StorageType x, StorageType y, StorageType z, StorageType w);
|
||||
/// Set the x component of the vector.
|
||||
void setX(StorageType tX);
|
||||
/// Set the y component of the vector.
|
||||
void setY(StorageType tY);
|
||||
/// Set the z component of the vector.
|
||||
void setZ(StorageType tZ);
|
||||
/// Set the w component of the vector.
|
||||
void setW(StorageType tW);
|
||||
|
||||
/// Get the length of the vector.
|
||||
float length(void) const;
|
||||
/// Get the squared length of the vector.
|
||||
OperationType lengthSquared(void) const;
|
||||
/// Find the angle between this vector and that which is passed as a parameter.
|
||||
float angleTo(const Vector<Size,StorageType,OperationType>& vector) const;
|
||||
/// Find the cross product between this vector and the vector passed as a parameter.
|
||||
Vector<Size,StorageType,OperationType> cross(const Vector<Size,StorageType,OperationType>& vector) const;
|
||||
/// Find the dot product between this vector and the vector passed as a parameter.
|
||||
OperationType dot(const Vector<Size,StorageType,OperationType>& rhs) const;
|
||||
/// Normalise the vector.
|
||||
void normalise(void);
|
||||
|
||||
private:
|
||||
// Values for the vector
|
||||
StorageType m_tElements[Size];
|
||||
};
|
||||
|
||||
// Non-member overloaded operators.
|
||||
/// Addition operator.
|
||||
template <uint32_t Size,typename StorageType,typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator+(const Vector<Size,StorageType,OperationType>& lhs, const Vector<Size,StorageType,OperationType>& rhs);
|
||||
/// Subtraction operator.
|
||||
template <uint32_t Size,typename StorageType,typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator-(const Vector<Size,StorageType,OperationType>& lhs, const Vector<Size,StorageType,OperationType>& rhs);
|
||||
/// Multiplication operator.
|
||||
template <uint32_t Size,typename StorageType,typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator*(const Vector<Size,StorageType,OperationType>& lhs, const Vector<Size,StorageType,OperationType>& rhs);
|
||||
/// Division operator.
|
||||
template <uint32_t Size,typename StorageType,typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator/(const Vector<Size,StorageType,OperationType>& lhs, const Vector<Size,StorageType,OperationType>& rhs);
|
||||
/// Multiplication operator.
|
||||
template <uint32_t Size,typename StorageType,typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator*(const Vector<Size,StorageType,OperationType>& lhs, const StorageType& rhs);
|
||||
/// Division operator.
|
||||
template <uint32_t Size,typename StorageType,typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator/(const Vector<Size,StorageType,OperationType>& lhs, const StorageType& rhs);
|
||||
/// Stream insertion operator.
|
||||
template <uint32_t Size, typename StorageType,typename OperationType>
|
||||
std::ostream& operator<<(std::ostream& os, const Vector<Size,StorageType,OperationType>& vector);
|
||||
|
||||
//Some handy typedefs
|
||||
|
||||
/// A 2D Vector of floats.
|
||||
typedef Vector<2,float,float> Vector2DFloat;
|
||||
/// A 2D Vector of doubles.
|
||||
typedef Vector<2,double,double> Vector2DDouble;
|
||||
/// A 2D Vector of signed 8-bit values.
|
||||
typedef Vector<2,int8_t,int32_t> Vector2DInt8;
|
||||
/// A 2D Vector of unsigned 8-bit values.
|
||||
typedef Vector<2,uint8_t,int32_t> Vector2DUint8;
|
||||
/// A 2D Vector of signed 16-bit values.
|
||||
typedef Vector<2,int16_t,int32_t> Vector2DInt16;
|
||||
/// A 2D Vector of unsigned 16-bit values.
|
||||
typedef Vector<2,uint16_t,int32_t> Vector2DUint16;
|
||||
/// A 2D Vector of signed 32-bit values.
|
||||
typedef Vector<2,int32_t,int32_t> Vector2DInt32;
|
||||
/// A 2D Vector of unsigned 32-bit values.
|
||||
typedef Vector<2,uint32_t,int32_t> Vector2DUint32;
|
||||
|
||||
/// A 3D Vector of floats.
|
||||
typedef Vector<3,float,float> Vector3DFloat;
|
||||
/// A 3D Vector of doubles.
|
||||
typedef Vector<3,double,double> Vector3DDouble;
|
||||
/// A 3D Vector of signed 8-bit values.
|
||||
typedef Vector<3,int8_t,int32_t> Vector3DInt8;
|
||||
/// A 3D Vector of unsigned 8-bit values.
|
||||
typedef Vector<3,uint8_t,int32_t> Vector3DUint8;
|
||||
/// A 3D Vector of signed 16-bit values.
|
||||
typedef Vector<3,int16_t,int32_t> Vector3DInt16;
|
||||
/// A 3D Vector of unsigned 16-bit values.
|
||||
typedef Vector<3,uint16_t,int32_t> Vector3DUint16;
|
||||
/// A 3D Vector of signed 32-bit values.
|
||||
typedef Vector<3,int32_t,int32_t> Vector3DInt32;
|
||||
/// A 3D Vector of unsigned 32-bit values.
|
||||
typedef Vector<3,uint32_t,int32_t> Vector3DUint32;
|
||||
|
||||
/// A 4D Vector of floats.
|
||||
typedef Vector<4,float,float> Vector4DFloat;
|
||||
/// A 4D Vector of doubles.
|
||||
typedef Vector<4,double,double> Vector4DDouble;
|
||||
/// A 4D Vector of signed 8-bit values.
|
||||
typedef Vector<4,int8_t,int32_t> Vector4DInt8;
|
||||
/// A 4D Vector of unsigned 8-bit values.
|
||||
typedef Vector<4,uint8_t,int32_t> Vector4DUint8;
|
||||
/// A 4D Vector of signed 16-bit values.
|
||||
typedef Vector<4,int16_t,int32_t> Vector4DInt16;
|
||||
/// A 4D Vector of unsigned 16-bit values.
|
||||
typedef Vector<4,uint16_t,int32_t> Vector4DUint16;
|
||||
/// A 4D Vector of signed 32-bit values.
|
||||
typedef Vector<4,int32_t,int32_t> Vector4DInt32;
|
||||
/// A 4D Vector of unsigned 32-bit values.
|
||||
typedef Vector<4,uint32_t,int32_t> Vector4DUint32;
|
||||
|
||||
|
||||
}//namespace PolyVox
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<PolyVox::Vector3DInt32>
|
||||
{
|
||||
std::size_t operator()(const PolyVox::Vector3DInt32& vec) const
|
||||
{
|
||||
return ((vec.getX() & 0xFF)) | ((vec.getY() & 0xFF) << 8) | ((vec.getZ() & 0xFF) << 16);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#include "PolyVoxCore/Vector.inl"
|
||||
|
||||
#endif
|
||||
|
673
include/PolyVoxCore/include/PolyVoxCore/Vector.inl
Normal file
673
include/PolyVoxCore/include/PolyVoxCore/Vector.inl
Normal file
@ -0,0 +1,673 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
//-------------------------- Constructors, etc ---------------------------------
|
||||
/**
|
||||
* Creates a Vector object but does not initialise it.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
Vector<Size, StorageType, OperationType>::Vector(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vector object and initialises all components with the given value.
|
||||
* \param tFillValue The value to write to every component.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType>::Vector(StorageType tFillValue)
|
||||
{
|
||||
for(uint32_t ct = 0; ct < Size; ct++)
|
||||
{
|
||||
m_tElements[ct] = tFillValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vector object and initialises it with given values.
|
||||
* \param x The X component to set.
|
||||
* \param y The Y component to set.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType>::Vector(StorageType x, StorageType y)
|
||||
{
|
||||
static_assert(Size == 2, "This constructor should only be used for vectors with two elements.");
|
||||
|
||||
m_tElements[0] = x;
|
||||
m_tElements[1] = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vector3D object and initialises it with given values.
|
||||
* \param x The X component to set.
|
||||
* \param y The Y component to set.
|
||||
* \param z the Z component to set.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType>::Vector(StorageType x, StorageType y, StorageType z)
|
||||
{
|
||||
static_assert(Size == 3, "This constructor should only be used for vectors with three elements.");
|
||||
|
||||
m_tElements[0] = x;
|
||||
m_tElements[1] = y;
|
||||
m_tElements[2] = z;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vector3D object and initialises it with given values.
|
||||
* \param x The X component to set.
|
||||
* \param y The Y component to set.
|
||||
* \param z The Z component to set.
|
||||
* \param w The W component to set.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType>::Vector(StorageType x, StorageType y, StorageType z, StorageType w)
|
||||
{
|
||||
static_assert(Size == 4, "This constructor should only be used for vectors with four elements.");
|
||||
|
||||
m_tElements[0] = x;
|
||||
m_tElements[1] = y;
|
||||
m_tElements[2] = z;
|
||||
m_tElements[3] = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor builds object based on object passed as parameter.
|
||||
* \param vector A reference to the Vector to be copied.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
Vector<Size, StorageType, OperationType>::Vector(const Vector<Size, StorageType, OperationType>& vector)
|
||||
{
|
||||
std::memcpy(m_tElements, vector.m_tElements, sizeof(StorageType) * Size);
|
||||
}
|
||||
|
||||
/**
|
||||
* This copy constructor allows casting between vectors with different data types.
|
||||
* It makes it 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_t Size, typename StorageType, typename OperationType>
|
||||
template <typename CastType>
|
||||
Vector<Size, StorageType, OperationType>::Vector(const Vector<Size, CastType>& vector)
|
||||
{
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
m_tElements[ct] = static_cast<StorageType>(vector.getElement(ct));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
Vector<Size, StorageType, OperationType>::~Vector(void)
|
||||
{
|
||||
// We put the static asserts in the destructor because there is one one of these,
|
||||
// where as there are multiple constructors.
|
||||
|
||||
// Force a vector to have a length greater than one. There is no need for a
|
||||
// vector with one element, and supporting this would cause confusion over the
|
||||
// behaviour of the constructor taking a single value, as this fills all elements
|
||||
// to that value rather than just the first one.
|
||||
static_assert(Size > 1, "Vector must have a length greater than one.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_t Size, typename StorageType, typename OperationType>
|
||||
Vector<Size, StorageType, OperationType>& Vector<Size, StorageType, OperationType>::operator=(const Vector<Size, StorageType, OperationType>& rhs)
|
||||
{
|
||||
if(this == &rhs)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
std::memcpy(m_tElements, rhs.m_tElements, sizeof(StorageType) * 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_t Size, typename StorageType, typename OperationType>
|
||||
inline bool Vector<Size, StorageType, OperationType>::operator==(const Vector<Size, StorageType, OperationType> &rhs) const
|
||||
{
|
||||
bool equal = true;
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
if(m_tElements[ct] != rhs.m_tElements[ct])
|
||||
{
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two Vectors are not equal.
|
||||
* \param rhs The Vector to compare to.
|
||||
* \return true if the Vectors do not match.
|
||||
* \see operator==
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline bool Vector<Size, StorageType, OperationType>::operator!=(const Vector<Size, StorageType, OperationType> &rhs) const
|
||||
{
|
||||
return !(*this == rhs); //Just call equality operator and invert the result.
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* This function is deprecated. You should specify a seperate comparator to the std:map if you need one.
|
||||
* \param rhs The Vector to compare to.
|
||||
* \return true if this is less than the parameter
|
||||
* \see operator!=
|
||||
* \deprecated
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline bool Vector<Size, StorageType, OperationType>::operator<(const Vector<Size, StorageType, OperationType> &rhs) const
|
||||
{
|
||||
for(uint32_t 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 The Vector to add
|
||||
* \return The resulting Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline Vector<Size, StorageType, OperationType>& Vector<Size, StorageType, OperationType>::operator+=(const Vector<Size, StorageType, OperationType>& rhs)
|
||||
{
|
||||
for(uint32_t 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 rhs The Vector to subtract
|
||||
* \return The resulting Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline Vector<Size, StorageType, OperationType>& Vector<Size, StorageType, OperationType>::operator-=(const Vector<Size, StorageType, OperationType>& rhs)
|
||||
{
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
m_tElements[ct] -= rhs.m_tElements[ct];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplication operator multiplies corresponding elements of the two Vectors.
|
||||
* \param rhs The Vector to multiply by
|
||||
* \return The resulting Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline Vector<Size, StorageType, OperationType>& Vector<Size, StorageType, OperationType>::operator*=(const Vector<Size, StorageType, OperationType>& rhs)
|
||||
{
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
m_tElements[ct] *= rhs.m_tElements[ct];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Division operator divides corresponding elements of one Vector by the other.
|
||||
* \param rhs The Vector to divide by
|
||||
* \return The resulting Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline Vector<Size, StorageType, OperationType>& Vector<Size, StorageType, OperationType>::operator/=(const Vector<Size, StorageType, OperationType>& rhs)
|
||||
{
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
m_tElements[ct] /= rhs.m_tElements[ct];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_t Size, typename StorageType, typename OperationType>
|
||||
inline Vector<Size, StorageType, OperationType>& Vector<Size, StorageType, OperationType>::operator*=(const StorageType& rhs)
|
||||
{
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
m_tElements[ct] *= rhs;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_t Size, typename StorageType, typename OperationType>
|
||||
inline Vector<Size, StorageType, OperationType>& Vector<Size, StorageType, OperationType>::operator/=(const StorageType& rhs)
|
||||
{
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
m_tElements[ct] /= rhs;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition operator adds corresponding elements of the two Vectors.
|
||||
* \param lhs The Vector to add to.
|
||||
* \param rhs The Vector to add.
|
||||
* \return The resulting Vector.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator+(const Vector<Size,StorageType,OperationType>& lhs, const Vector<Size,StorageType,OperationType>& rhs)
|
||||
{
|
||||
Vector<Size,StorageType,OperationType> result = lhs;
|
||||
result += rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtraction operator subtracts corresponding elements of one Vector from the other.
|
||||
* \param lhs The Vector to subtract from.
|
||||
* \param rhs The Vector to subtract.
|
||||
* \return The resulting Vector.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator-(const Vector<Size,StorageType,OperationType>& lhs, const Vector<Size,StorageType,OperationType>& rhs)
|
||||
{
|
||||
Vector<Size,StorageType,OperationType> result = lhs;
|
||||
result -= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplication operator mulitplies corresponding elements of the two Vectors.
|
||||
* \param lhs The Vector to multiply.
|
||||
* \param rhs The Vector to multiply by.
|
||||
* \return The resulting Vector.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator*(const Vector<Size,StorageType,OperationType>& lhs, const Vector<Size,StorageType,OperationType>& rhs)
|
||||
{
|
||||
Vector<Size,StorageType,OperationType> result = lhs;
|
||||
result *= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Division operator divides corresponding elements of one Vector by the other.
|
||||
* \param lhs The Vector to divide.
|
||||
* \param rhs The Vector to divide by.
|
||||
* \return The resulting Vector.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator/(const Vector<Size,StorageType,OperationType>& lhs, const Vector<Size,StorageType,OperationType>& rhs)
|
||||
{
|
||||
Vector<Size,StorageType,OperationType> result = lhs;
|
||||
result /= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator*(const Vector<Size,StorageType,OperationType>& lhs, const StorageType& rhs)
|
||||
{
|
||||
Vector<Size,StorageType,OperationType> result = lhs;
|
||||
result *= rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_t Size,typename StorageType, typename OperationType>
|
||||
Vector<Size,StorageType,OperationType> operator/(const Vector<Size,StorageType,OperationType>& lhs, const StorageType& rhs)
|
||||
{
|
||||
Vector<Size,StorageType,OperationType> 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_t Size, typename StorageType, typename OperationType>
|
||||
std::ostream& operator<<(std::ostream& os, const Vector<Size, StorageType, OperationType>& vector)
|
||||
{
|
||||
os << "(";
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
os << vector.getElement(ct);
|
||||
if(ct < (Size-1))
|
||||
{
|
||||
os << ",";
|
||||
}
|
||||
}
|
||||
os << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element at the given position.
|
||||
* \param index The index of the element to return.
|
||||
* \return The element.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline StorageType Vector<Size, StorageType, OperationType>::getElement(uint32_t index) const
|
||||
{
|
||||
if(index >= Size)
|
||||
{
|
||||
POLYVOX_THROW(std::out_of_range, "Attempted to access invalid vector element.");
|
||||
}
|
||||
|
||||
return m_tElements[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* \return A const reference to the X component of a 1, 2, 3, or 4 dimensional Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline StorageType Vector<Size, StorageType, OperationType>::getX(void) const
|
||||
{
|
||||
return m_tElements[0]; // This is fine, a Vector always contains at least two elements.
|
||||
}
|
||||
|
||||
/**
|
||||
* \return A const reference to the Y component of a 2, 3, or 4 dimensional Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline StorageType Vector<Size, StorageType, OperationType>::getY(void) const
|
||||
{
|
||||
return m_tElements[1]; // This is fine, a Vector always contains at least two elements.
|
||||
}
|
||||
|
||||
/**
|
||||
* \return A const reference to the Z component of a 3 or 4 dimensional Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline StorageType Vector<Size, StorageType, OperationType>::getZ(void) const
|
||||
{
|
||||
static_assert(Size >= 3, "You can only get the 'z' component from a vector with at least three elements.");
|
||||
|
||||
return m_tElements[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* \return A const reference to the W component of a 4 dimensional Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline StorageType Vector<Size, StorageType, OperationType>::getW(void) const
|
||||
{
|
||||
static_assert(Size >= 4, "You can only get the 'w' component from a vector with at least four elements.");
|
||||
|
||||
return m_tElements[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* \param index The index of the element to set.
|
||||
* \param tValue The new value for the element.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline void Vector<Size, StorageType, OperationType>::setElement(uint32_t index, StorageType tValue)
|
||||
{
|
||||
if(index >= Size)
|
||||
{
|
||||
POLYVOX_THROW(std::out_of_range, "Attempted to access invalid vector element.");
|
||||
}
|
||||
|
||||
m_tElements[index] = tValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets several elements of a vector at once.
|
||||
* \param x The X component to set.
|
||||
* \param y The Y component to set.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
inline void Vector<Size,StorageType,OperationType>::setElements(StorageType x, StorageType y)
|
||||
{
|
||||
// This is fine, a Vector always contains at least two elements.
|
||||
m_tElements[0] = x;
|
||||
m_tElements[1] = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets several elements of a vector at once.
|
||||
* \param x The X component to set.
|
||||
* \param y The Y component to set.
|
||||
* \param z The Z component to set.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
inline void Vector<Size,StorageType,OperationType>::setElements(StorageType x, StorageType y, StorageType z)
|
||||
{
|
||||
static_assert(Size >= 3, "You can only use this version of setElements() on a vector with at least three elements.");
|
||||
|
||||
m_tElements[0] = x;
|
||||
m_tElements[1] = y;
|
||||
m_tElements[2] = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets several elements of a vector at once.
|
||||
* \param x The X component to set.
|
||||
* \param y The Y component to set.
|
||||
* \param z The Z component to set.
|
||||
* \param w The W component to set.
|
||||
*/
|
||||
template <uint32_t Size,typename StorageType, typename OperationType>
|
||||
inline void Vector<Size,StorageType,OperationType>::setElements(StorageType x, StorageType y, StorageType z, StorageType w)
|
||||
{
|
||||
static_assert(Size >= 4, "You can only use this version of setElements() on a vector with at least four elements.");
|
||||
|
||||
m_tElements[0] = x;
|
||||
m_tElements[1] = y;
|
||||
m_tElements[2] = z;
|
||||
m_tElements[3] = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param tX The new value for the X component of a 1, 2, 3, or 4 dimensional Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline void Vector<Size, StorageType, OperationType>::setX(StorageType tX)
|
||||
{
|
||||
m_tElements[0] = tX; // This is fine, a Vector always contains at least two elements.
|
||||
}
|
||||
|
||||
/**
|
||||
* \param tY The new value for the Y component of a 2, 3, or 4 dimensional Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline void Vector<Size, StorageType, OperationType>::setY(StorageType tY)
|
||||
{
|
||||
m_tElements[1] = tY; // This is fine, a Vector always contains at least two elements.
|
||||
}
|
||||
|
||||
/**
|
||||
* \param tZ The new value for the Z component of a 3 or 4 dimensional Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline void Vector<Size, StorageType, OperationType>::setZ(StorageType tZ)
|
||||
{
|
||||
static_assert(Size >= 3, "You can only set the 'w' component from a vector with at least three elements.");
|
||||
|
||||
m_tElements[2] = tZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param tW The new value for the W component of a 4 dimensional Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline void Vector<Size, StorageType, OperationType>::setW(StorageType tW)
|
||||
{
|
||||
static_assert(Size >= 4, "You can only set the 'w' component from a vector with at least four elements.");
|
||||
|
||||
m_tElements[3] = tW;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This function always returns a single precision floating point value, even when the StorageType is a double precision floating point value or an integer.
|
||||
* \return The length of the Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline float Vector<Size, StorageType, OperationType>::length(void) const
|
||||
{
|
||||
return sqrt(static_cast<float>(lengthSquared()));
|
||||
}
|
||||
|
||||
/**
|
||||
* \return The squared length of the Vector.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline OperationType Vector<Size, StorageType, OperationType>::lengthSquared(void) const
|
||||
{
|
||||
OperationType tLengthSquared = static_cast<OperationType>(0);
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
tLengthSquared += static_cast<OperationType>(m_tElements[ct]) * static_cast<OperationType>(m_tElements[ct]);
|
||||
}
|
||||
return tLengthSquared;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 always returns a single precision floating point value, even when the StorageType is a double precision floating point value or an integer.
|
||||
*
|
||||
* \param vector The Vector to find the angle to.
|
||||
* \return The angle between them in radians.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline float Vector<Size, StorageType, OperationType>::angleTo(const Vector<Size, StorageType, OperationType>& vector) const
|
||||
{
|
||||
return acos(static_cast<float>(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 vector The vector to cross with this
|
||||
* \return The value of the cross product.
|
||||
* \see dot()
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline Vector<Size, StorageType, OperationType> Vector<Size, StorageType, OperationType>::cross(const Vector<Size, StorageType, OperationType>& vector) const
|
||||
{
|
||||
StorageType i = vector.getZ() * this->getY() - vector.getY() * this->getZ();
|
||||
StorageType j = vector.getX() * this->getZ() - vector.getZ() * this->getX();
|
||||
StorageType k = vector.getY() * this->getX() - vector.getX() * this->getY();
|
||||
return Vector<Size, StorageType, OperationType>(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_t Size, typename StorageType, typename OperationType>
|
||||
inline OperationType Vector<Size, StorageType, OperationType>::dot(const Vector<Size, StorageType, OperationType>& rhs) const
|
||||
{
|
||||
OperationType dotProduct = static_cast<OperationType>(0);
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
dotProduct += static_cast<OperationType>(m_tElements[ct]) * static_cast<OperationType>(rhs.m_tElements[ct]);
|
||||
}
|
||||
return dotProduct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the i, j, and k components by the length to give a Vector of length 1.0. If the vector is
|
||||
* very short (or zero) then a divide by zero may cause elements to take on invalid values. You may
|
||||
* want to check for this before normalising.
|
||||
*
|
||||
* \note You should not attempt to normalise a vector whose StorageType is an integer.
|
||||
*/
|
||||
template <uint32_t Size, typename StorageType, typename OperationType>
|
||||
inline void Vector<Size, StorageType, OperationType>::normalise(void)
|
||||
{
|
||||
float fLength = this->length();
|
||||
|
||||
// We could wait until the NAN occurs before throwing, but then we'd have to add some roll-back code.
|
||||
// This seems like a lot of overhead for a common operation which should rarely go wrong.
|
||||
if(fLength <= 0.0001)
|
||||
{
|
||||
POLYVOX_THROW(invalid_operation, "Cannot normalise a vector with a length of zero");
|
||||
}
|
||||
|
||||
for(uint32_t ct = 0; ct < Size; ++ct)
|
||||
{
|
||||
// Standard float rules apply for divide-by-zero
|
||||
m_tElements[ct] /= fLength;
|
||||
|
||||
//This shouldn't happen as we had the length check earlier. So it's probably a bug if it does happen.
|
||||
POLYVOX_ASSERT(m_tElements[ct] == m_tElements[ct], "Obtained NAN during vector normalisation. Perhaps the input vector was too short?");
|
||||
}
|
||||
}
|
||||
}//namespace PolyVox
|
51
include/PolyVoxCore/include/PolyVoxCore/Vertex.h
Normal file
51
include/PolyVoxCore/include/PolyVoxCore/Vertex.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Vertex_H__
|
||||
#define __PolyVox_Vertex_H__
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
#ifdef SWIG
|
||||
struct Vertex
|
||||
#else
|
||||
template<typename _DataType>
|
||||
struct POLYVOX_API Vertex
|
||||
#endif
|
||||
{
|
||||
typedef _DataType DataType;
|
||||
|
||||
Vector3DFloat position;
|
||||
Vector3DFloat normal;
|
||||
DataType data;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __PolyVox_Vertex_H__
|
57
include/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h
Normal file
57
include/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_VolumeResampler_H__
|
||||
#define __PolyVox_VolumeResampler_H__
|
||||
|
||||
#include "PolyVoxCore/Region.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template< typename SrcVolumeType, typename DstVolumeType>
|
||||
class VolumeResampler
|
||||
{
|
||||
public:
|
||||
VolumeResampler(SrcVolumeType* pVolSrc, const Region& regSrc, DstVolumeType* pVolDst, const Region& regDst);
|
||||
|
||||
void execute();
|
||||
|
||||
private:
|
||||
void resampleSameSize();
|
||||
void resampleArbitrary();
|
||||
|
||||
//Source data
|
||||
SrcVolumeType* m_pVolSrc;
|
||||
Region m_regSrc;
|
||||
|
||||
//Destination data
|
||||
DstVolumeType* m_pVolDst;
|
||||
Region m_regDst;
|
||||
};
|
||||
|
||||
}//namespace PolyVox
|
||||
|
||||
#include "PolyVoxCore/VolumeResampler.inl"
|
||||
|
||||
#endif
|
||||
|
138
include/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl
Normal file
138
include/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl
Normal file
@ -0,0 +1,138 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/Interpolation.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/**
|
||||
* \param pVolSrc
|
||||
* \param regSrc
|
||||
* \param[out] pVolDst
|
||||
* \param regDst
|
||||
*/
|
||||
template< typename SrcVolumeType, typename DstVolumeType>
|
||||
VolumeResampler<SrcVolumeType, DstVolumeType>::VolumeResampler(SrcVolumeType* pVolSrc, const Region ®Src, DstVolumeType* pVolDst, const Region& regDst)
|
||||
:m_pVolSrc(pVolSrc)
|
||||
,m_regSrc(regSrc)
|
||||
,m_pVolDst(pVolDst)
|
||||
,m_regDst(regDst)
|
||||
{
|
||||
}
|
||||
|
||||
template< typename SrcVolumeType, typename DstVolumeType>
|
||||
void VolumeResampler<SrcVolumeType, DstVolumeType>::execute()
|
||||
{
|
||||
int32_t uSrcWidth = m_regSrc.getUpperX() - m_regSrc.getLowerX() + 1;
|
||||
int32_t uSrcHeight = m_regSrc.getUpperY() - m_regSrc.getLowerY() + 1;
|
||||
int32_t uSrcDepth = m_regSrc.getUpperZ() - m_regSrc.getLowerZ() + 1;
|
||||
|
||||
int32_t uDstWidth = m_regDst.getUpperX() - m_regDst.getLowerX() + 1;
|
||||
int32_t uDstHeight = m_regDst.getUpperY() - m_regDst.getLowerY() + 1;
|
||||
int32_t uDstDepth = m_regDst.getUpperZ() - m_regDst.getLowerZ() + 1;
|
||||
|
||||
if((uSrcWidth == uDstWidth) && (uSrcHeight == uDstHeight) && (uSrcDepth == uDstDepth))
|
||||
{
|
||||
resampleSameSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
resampleArbitrary();
|
||||
}
|
||||
}
|
||||
|
||||
template< typename SrcVolumeType, typename DstVolumeType>
|
||||
void VolumeResampler<SrcVolumeType, DstVolumeType>::resampleSameSize()
|
||||
{
|
||||
for(int32_t sz = m_regSrc.getLowerZ(), dz = m_regDst.getLowerZ(); dz <= m_regDst.getUpperZ(); sz++, dz++)
|
||||
{
|
||||
for(int32_t sy = m_regSrc.getLowerY(), dy = m_regDst.getLowerY(); dy <= m_regDst.getUpperY(); sy++, dy++)
|
||||
{
|
||||
for(int32_t sx = m_regSrc.getLowerX(), dx = m_regDst.getLowerX(); dx <= m_regDst.getUpperX(); sx++,dx++)
|
||||
{
|
||||
const typename SrcVolumeType::VoxelType& tSrcVoxel = m_pVolSrc->getVoxel(sx,sy,sz, WrapModes::AssumeValid); // FIXME use templatised version of getVoxel(), but watch out for Linux compile issues.
|
||||
const typename DstVolumeType::VoxelType& tDstVoxel = static_cast<typename DstVolumeType::VoxelType>(tSrcVoxel);
|
||||
m_pVolDst->setVoxelAt(dx,dy,dz,tDstVoxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename SrcVolumeType, typename DstVolumeType>
|
||||
void VolumeResampler<SrcVolumeType, DstVolumeType>::resampleArbitrary()
|
||||
{
|
||||
float srcWidth = m_regSrc.getWidthInCells();
|
||||
float srcHeight = m_regSrc.getHeightInCells();
|
||||
float srcDepth = m_regSrc.getDepthInCells();
|
||||
|
||||
float dstWidth = m_regDst.getWidthInCells();
|
||||
float dstHeight = m_regDst.getHeightInCells();
|
||||
float dstDepth = m_regDst.getDepthInCells();
|
||||
|
||||
float fScaleX = srcWidth / dstWidth;
|
||||
float fScaleY = srcHeight / dstHeight;
|
||||
float fScaleZ = srcDepth / dstDepth;
|
||||
|
||||
typename SrcVolumeType::Sampler sampler(m_pVolSrc);
|
||||
|
||||
for(int32_t dz = m_regDst.getLowerZ(); dz <= m_regDst.getUpperZ(); dz++)
|
||||
{
|
||||
for(int32_t dy = m_regDst.getLowerY(); dy <= m_regDst.getUpperY(); dy++)
|
||||
{
|
||||
for(int32_t dx = m_regDst.getLowerX(); dx <= m_regDst.getUpperX(); dx++)
|
||||
{
|
||||
float sx = (dx - m_regDst.getLowerX()) * fScaleX;
|
||||
float sy = (dy - m_regDst.getLowerY()) * fScaleY;
|
||||
float sz = (dz - m_regDst.getLowerZ()) * fScaleZ;
|
||||
|
||||
sx += m_regSrc.getLowerX();
|
||||
sy += m_regSrc.getLowerY();
|
||||
sz += m_regSrc.getLowerZ();
|
||||
|
||||
sampler.setPosition(sx,sy,sz);
|
||||
const typename SrcVolumeType::VoxelType& voxel000 = sampler.peekVoxel0px0py0pz();
|
||||
const typename SrcVolumeType::VoxelType& voxel001 = sampler.peekVoxel0px0py1pz();
|
||||
const typename SrcVolumeType::VoxelType& voxel010 = sampler.peekVoxel0px1py0pz();
|
||||
const typename SrcVolumeType::VoxelType& voxel011 = sampler.peekVoxel0px1py1pz();
|
||||
const typename SrcVolumeType::VoxelType& voxel100 = sampler.peekVoxel1px0py0pz();
|
||||
const typename SrcVolumeType::VoxelType& voxel101 = sampler.peekVoxel1px0py1pz();
|
||||
const typename SrcVolumeType::VoxelType& voxel110 = sampler.peekVoxel1px1py0pz();
|
||||
const typename SrcVolumeType::VoxelType& voxel111 = sampler.peekVoxel1px1py1pz();
|
||||
|
||||
//FIXME - should accept all float parameters, but GCC complains?
|
||||
double dummy;
|
||||
sx = modf(sx, &dummy);
|
||||
sy = modf(sy, &dummy);
|
||||
sz = modf(sz, &dummy);
|
||||
|
||||
typename SrcVolumeType::VoxelType tInterpolatedValue = trilerp<float>(voxel000,voxel100,voxel010,voxel110,voxel001,voxel101,voxel011,voxel111,sx,sy,sz);
|
||||
|
||||
typename DstVolumeType::VoxelType result = static_cast<typename DstVolumeType::VoxelType>(tInterpolatedValue);
|
||||
m_pVolDst->setVoxelAt(dx,dy,dz,result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
include/PolyVoxCore/include/PolyVoxCore/VoxelFilters.h
Normal file
37
include/PolyVoxCore/include/PolyVoxCore/VoxelFilters.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_VoxelFilters_H__
|
||||
#define __PolyVox_VoxelFilters_H__
|
||||
|
||||
#include "Impl/TypeDef.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template< typename VolumeType >
|
||||
float computeSmoothedVoxel(typename VolumeType::Sampler& volIter);
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/VoxelFilters.inl"
|
||||
|
||||
#endif
|
64
include/PolyVoxCore/include/PolyVoxCore/VoxelFilters.inl
Normal file
64
include/PolyVoxCore/include/PolyVoxCore/VoxelFilters.inl
Normal file
@ -0,0 +1,64 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template< typename VolumeType >
|
||||
float computeSmoothedVoxel(typename VolumeType::Sampler& volIter)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
25
include/polyvox.qhcp.in
Normal file
25
include/polyvox.qhcp.in
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- This file defines a collection of Qt Help files as well as some amount of the build process -->
|
||||
<QHelpCollectionProject version="1.0">
|
||||
<assistant>
|
||||
<title>PolyVox Documentation</title>
|
||||
<homePage>qthelp://com.volumesoffun.polyvox/api/index.html</homePage>
|
||||
<startPage>qthelp://com.volumesoffun.polyvox/api/index.html</startPage>
|
||||
<!-- Disable the documentation manager so that there's no option to add more docs to this shell instance -->
|
||||
<enableDocumentationManager>false</enableDocumentationManager>
|
||||
<cacheDirectory>volumesoffun/polyvox</cacheDirectory>
|
||||
</assistant>
|
||||
<docFiles>
|
||||
<!-- This section says that polyvox.qch will be created from index.qhp when qcollectiongenerator is run -->
|
||||
<generate>
|
||||
<file>
|
||||
<input>../html/index.qhp</input>
|
||||
<output>polyvox.qch</output>
|
||||
</file>
|
||||
</generate>
|
||||
<!-- We then add the Qt Compressed Help file to the collection -->
|
||||
<register>
|
||||
<file>polyvox.qch</file>
|
||||
</register>
|
||||
</docFiles>
|
||||
</QHelpCollectionProject>
|
Reference in New Issue
Block a user