Merge branch 'develop' into feature/cmake-cxx11-detect

Conflicts:
	examples/Basic/CMakeLists.txt
	examples/OpenGL/CMakeLists.txt
	examples/Paging/CMakeLists.txt
	examples/SmoothLOD/CMakeLists.txt
	library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h
This commit is contained in:
David Williams 2012-12-24 20:08:31 +00:00
commit 74f25eac23
90 changed files with 2808 additions and 114487 deletions

View File

@ -1,3 +1,40 @@
Changes for PolyVox version 0.3
===============================
This release has focused on... (some introduction here).
Volume wrap modes
-----------------
This release has seen a overhaul of the way PolyVox handles voxel positions which are outside of the volume. It used to be the case that you could specify a border value which would be returned whenever an out-of-volume access was performed, but this was not flexible enough for all use cases. You can now choose between different wrapping modes (border, clamp, etc) and apply them to both the volume itself or to samplers. If you have multiple samplers pointing at the same volume then you can choose to have different wrap modes for each of them.
Within the Volume class the getVoxelAt() and setBorderValue() functions have been deprecated. You should now call getVoxel() (which does not perform range checking and will crash when out of range) or getVoxelWithWrapping() (which does perform bounds checks and implements the required wrapping). When you call getVoxelWithWrapping() you are able to specify the required wrap mode for that particular call. For a Sampler you can set the wrap mode once with setWrapMode() and it will persist until you set it again.
Various algorithms have also been updated to allow wrap modes to be specified when executing them.
Region class
------------
The Region class has been tidied up and enhanced with new functionality. It now contains functions for growing and shrinking regions, as well as 'accumulate()' functions which ensure the Region contains a given point. The concept of an invalid region has also been introduced - this is one whose lower corner is greater than it's upper corner.
Vector class
------------
The Vector class has been tidied up. Most notably it now makes use of an 'OperationType' which is used for internal calculations and some results. The documentation has also been updated.
Deprecated functionality
------------------------
Vector::operator<() has been deprecated. It was only present to allow Vectors to be used as the key to an std::map, but it makes more sense for this to be specified seperatly as a std::map comparison function. This is now done in the OpenGLExample (search for VectorCompare).
getVoxelAt() and setBorderValue() have been deprecated in the Volume class. See the section of this file on 'Volume wrap modes' for details.
Removed functionality
--------------------
Functionality deprecated for the previous release has now been removed. This includes:
- Region::getWidth() and related functions. You should now use Region::getWidthInVoxels() or Region::getWidthInCells.
- The MeshDecimator. We don't have a direct replacement for this so you should consider an alternative such as downsampling the volume or using an external mesh processing library.
- The SimpleInterface. This was primarily for the bindings, and we are making other efforts to get those working.
- Serialisation. You should implement any required serialisation yourself.
- This had a number of problems and was a little too high-level for PolyVox. You should implement change tracking yourself.
Changes for PolyVox version 0.2
===============================
This is the first revision for which we have produced a changelog, as we are now trying to streamline our development and release process. Hence this changelog entry is not going to be as structured as we hope they will be in the future. We're writing it from memory, rather than having carefully kept track of all the relevant changes as we made them.

View File

@ -75,6 +75,7 @@ ADD_SUBDIRECTORY(library)
OPTION(ENABLE_EXAMPLES "Should the examples be built" ON)
IF(ENABLE_EXAMPLES AND QT_QTOPENGL_FOUND)
ADD_SUBDIRECTORY(examples/common)
ADD_SUBDIRECTORY(examples/Basic)
ADD_SUBDIRECTORY(examples/Paging)
ADD_SUBDIRECTORY(examples/OpenGL)

View File

@ -1,4 +1,5 @@
PolyVox - The voxel management and manipulation library
=======================================================
PolyVox is the core technology which lies behind our games. It is a fast, lightweight C++ library for the storage and processing of volumetric (voxel-based) environments. It has applications in both games and medical/scientific visualisation, and is released under the terms of the `zlib license <http://www.tldrlegal.com/l/ZLIB>`_.
For installation instructions, please see INSTALL.txt
PolyVox is a relatively low-level library, and you will need experience in C++ and computer graphics/shaders to use it effectively. It is designed to be easily integrated into existing applications and is independent of your chosen graphics API. For more details please see `this page <http://www.volumesoffun.com/polyvox-about/>`_ on our website.

View File

@ -25,22 +25,16 @@ PROJECT(BasicExample)
#Projects source files
SET(SRC_FILES
glew/glew.cpp
main.cpp
OpenGLWidget.cpp
)
)
#Projects headers files
SET(INC_FILES
glew/glew.h
glew/glxew.h
glew/wglew.h
OpenGLWidget.h
)
)
ADD_DEFINITIONS(-DGLEW_STATIC)
add_definitions(-DGLEW_STATIC)
#"Sources" and "Headers" are the group names in Visual Studio.
#They may have other uses too...
@ -50,7 +44,7 @@ SOURCE_GROUP("Headers" FILES ${INC_FILES})
FIND_PACKAGE(OpenGL REQUIRED)
#Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include ${GLEW_SOURCE_DIR})
LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR})
#Build
@ -58,7 +52,7 @@ ADD_EXECUTABLE(BasicExample ${SRC_FILES})
IF(MSVC)
SET_TARGET_PROPERTIES(BasicExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127")
ENDIF(MSVC)
TARGET_LINK_LIBRARIES(BasicExample ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore)
TARGET_LINK_LIBRARIES(BasicExample glew ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore)
SET_PROPERTY(TARGET BasicExample PROPERTY FOLDER "Examples")
#Install - Only install the example in Windows

View File

@ -25,7 +25,6 @@ PROJECT(OpenGLExample)
#Projects source files
SET(SRC_FILES
glew/glew.cpp
main.cpp
OpenGLImmediateModeSupport.cpp
OpenGLSupport.cpp
@ -36,17 +35,14 @@ SET(SRC_FILES
#Projects headers files
SET(INC_FILES
glew/glew.h
glew/glxew.h
glew/wglew.h
OpenGLImmediateModeSupport.h
OpenGLSupport.h
OpenGLVertexBufferObjectSupport.h
OpenGLWidget.h
Shapes.h
)
)
ADD_DEFINITIONS(-DGLEW_STATIC)
add_definitions(-DGLEW_STATIC)
#"Sources" and "Headers" are the group names in Visual Studio.
#They may have other uses too...
@ -56,7 +52,7 @@ SOURCE_GROUP("Headers" FILES ${INC_FILES})
FIND_PACKAGE(OpenGL REQUIRED)
#Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include ${GLEW_SOURCE_DIR})
LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR})
#Build
@ -64,7 +60,7 @@ ADD_EXECUTABLE(OpenGLExample ${SRC_FILES})
IF(MSVC)
SET_TARGET_PROPERTIES(OpenGLExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127")
ENDIF(MSVC)
TARGET_LINK_LIBRARIES(OpenGLExample ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore)
TARGET_LINK_LIBRARIES(OpenGLExample glew ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore)
SET_PROPERTY(TARGET OpenGLExample PROPERTY FOLDER "Examples")
#Install - Only install the example in Windows

View File

@ -39,6 +39,22 @@ freely, subject to the following restrictions:
const int32_t g_uVolumeSideLength = 128;
struct Vector3DUint8Compare
{
bool operator() (const PolyVox::Vector3DUint8& a, const PolyVox::Vector3DUint8& b)
{
const uint32_t size = 3;
for(uint32_t ct = 0; ct < size; ++ct)
{
if (a.getElement(ct) < b.getElement(ct))
return true;
if (b.getElement(ct) < a.getElement(ct))
return false;
}
return false;
}
};
class OpenGLWidget : public QGLWidget
{
@ -71,8 +87,8 @@ class OpenGLWidget : public QGLWidget
PolyVox::LargeVolume<PolyVox::MaterialDensityPair44>* m_volData;
//Rather than storing one big mesh, the volume is broken into regions and a mesh is stored for each region
std::map<PolyVox::Vector3DUint8, OpenGLSurfaceMesh> m_mapOpenGLSurfaceMeshes;
std::map<PolyVox::Vector3DUint8, polyvox_shared_ptr<PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> > > m_mapSurfaceMeshes;
std::map<PolyVox::Vector3DUint8, OpenGLSurfaceMesh, Vector3DUint8Compare> m_mapOpenGLSurfaceMeshes;
std::map<PolyVox::Vector3DUint8, polyvox_shared_ptr<PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> >, Vector3DUint8Compare> m_mapSurfaceMeshes;
unsigned int m_uRegionSideLength;
unsigned int m_uVolumeWidthInRegions;

View File

@ -1,73 +0,0 @@
The OpenGL Extension Wrangler Library
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
Copyright (C) 2002, Lev Povalahev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Mesa 3-D graphics library
Version: 7.0
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,24 +25,18 @@ PROJECT(PagingExample)
#Projects source files
SET(SRC_FILES
glew/glew.cpp
main.cpp
OpenGLWidget.cpp
Perlin.cpp
)
)
#Projects headers files
SET(INC_FILES
glew/glew.h
glew/glxew.h
glew/wglew.h
OpenGLWidget.h
Perlin.h
)
)
ADD_DEFINITIONS(-DGLEW_STATIC)
add_definitions(-DGLEW_STATIC)
#"Sources" and "Headers" are the group names in Visual Studio.
#They may have other uses too...
@ -52,7 +46,7 @@ SOURCE_GROUP("Headers" FILES ${INC_FILES})
FIND_PACKAGE(OpenGL REQUIRED)
#Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include ${GLEW_SOURCE_DIR})
LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR})
#Build
@ -60,7 +54,7 @@ ADD_EXECUTABLE(PagingExample ${SRC_FILES})
IF(MSVC)
SET_TARGET_PROPERTIES(PagingExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127")
ENDIF(MSVC)
TARGET_LINK_LIBRARIES(PagingExample ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore)
TARGET_LINK_LIBRARIES(PagingExample glew ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore)
SET_PROPERTY(TARGET PagingExample PROPERTY FOLDER "Examples")
#Install - Only install the example in Windows

View File

@ -1,73 +0,0 @@
The OpenGL Extension Wrangler Library
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
Copyright (C) 2002, Lev Povalahev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Mesa 3-D graphics library
Version: 7.0
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,22 +25,16 @@ PROJECT(SmoothLODExample)
#Projects source files
SET(SRC_FILES
glew/glew.cpp
main.cpp
OpenGLWidget.cpp
)
)
#Projects headers files
SET(INC_FILES
glew/glew.h
glew/glxew.h
glew/wglew.h
OpenGLWidget.h
)
)
ADD_DEFINITIONS(-DGLEW_STATIC)
add_definitions(-DGLEW_STATIC)
#"Sources" and "Headers" are the group names in Visual Studio.
#They may have other uses too...
@ -50,7 +44,7 @@ SOURCE_GROUP("Headers" FILES ${INC_FILES})
FIND_PACKAGE(OpenGL REQUIRED)
#Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include)
INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include ${GLEW_SOURCE_DIR})
LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR})
#Build
@ -58,7 +52,7 @@ ADD_EXECUTABLE(SmoothLODExample ${SRC_FILES})
IF(MSVC)
SET_TARGET_PROPERTIES(SmoothLODExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127") #All warnings
ENDIF(MSVC)
TARGET_LINK_LIBRARIES(SmoothLODExample ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore)
TARGET_LINK_LIBRARIES(SmoothLODExample glew ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore)
SET_PROPERTY(TARGET SmoothLODExample PROPERTY FOLDER "Examples")
#Install - Only install the example in Windows

View File

@ -1,73 +0,0 @@
The OpenGL Extension Wrangler Library
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
Copyright (C) 2002, Lev Povalahev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Mesa 3-D graphics library
Version: 7.0
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
# Copyright (c) 2010-2012 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.
project(GLEW)
set(SRC_FILES ../common/glew/glew.cpp)
add_definitions(-DGLEW_STATIC)
#find_package(OpenGL REQUIRED)
#include_directories(${OPENGL_INCLUDE_DIR})
add_library(glew STATIC ${SRC_FILES})
SET_PROPERTY(TARGET glew PROPERTY FOLDER "Examples/Common")

View File

@ -32,9 +32,7 @@ SET(CORE_SRC_FILES
source/ArraySizes.cpp
source/AStarPathfinder.cpp
source/Log.cpp
source/MeshDecimator.cpp
source/Region.cpp
source/SimpleInterface.cpp
source/VertexTypes.cpp
)
@ -73,8 +71,6 @@ SET(CORE_INC_FILES
include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl
include/PolyVoxCore/Material.h
include/PolyVoxCore/MaterialDensityPair.h
include/PolyVoxCore/MeshDecimator.h
include/PolyVoxCore/MeshDecimator.inl
include/PolyVoxCore/PolyVoxForwardDeclarations.h
include/PolyVoxCore/RawVolume.h
include/PolyVoxCore/RawVolume.inl
@ -82,7 +78,6 @@ SET(CORE_INC_FILES
include/PolyVoxCore/Raycast.h
include/PolyVoxCore/Raycast.inl
include/PolyVoxCore/Region.h
include/PolyVoxCore/SimpleInterface.h
include/PolyVoxCore/SimpleVolume.h
include/PolyVoxCore/SimpleVolume.inl
include/PolyVoxCore/SimpleVolumeBlock.inl

View File

@ -98,6 +98,8 @@ namespace PolyVox
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;

View File

@ -38,6 +38,16 @@ namespace PolyVox
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// More details to come...
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace WrapModes
{
enum WrapMode
{
Clamp = 0,
Border = 1
};
}
typedef WrapModes::WrapMode WrapMode;
template <typename _VoxelType>
class BaseVolume
{
@ -55,9 +65,12 @@ namespace PolyVox
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(0));
void movePositiveX(void);
void movePositiveY(void);
@ -98,12 +111,23 @@ namespace PolyVox
inline VoxelType peekVoxel1px1py1pz(void) const;
protected:
VoxelType getVoxelAt(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
@ -111,7 +135,7 @@ namespace PolyVox
/// Gets the value used for voxels which are outside the volume
VoxelType getBorderValue(void) const;
/// Gets a Region representing the extents of the Volume.
Region getEnclosingRegion(void) const;
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.
@ -125,9 +149,17 @@ namespace PolyVox
/// 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
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxel(const Vector3DInt32& v3dPos) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType(0)) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType(0)) const;
/// Sets the value used for voxels which are outside the volume
void setBorderValue(const VoxelType& tBorder);
@ -159,6 +191,9 @@ namespace PolyVox
int32_t m_uLongestSideLength;
int32_t m_uShortestSideLength;
float m_fDiagonalLength;
//The border value
VoxelType m_tBorderValue;
};
}

View File

@ -31,6 +31,7 @@ namespace PolyVox
template <typename VoxelType>
BaseVolume<VoxelType>::BaseVolume(const Region& regValid)
:m_regValidRegion(regValid)
,m_tBorderValue(0)
{
}
@ -76,15 +77,14 @@ namespace PolyVox
template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getBorderValue(void) const
{
assert(false);
return VoxelType();
return m_tBorderValue;
}
////////////////////////////////////////////////////////////////////////////////
/// \return A Region representing the extent of the volume.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
Region BaseVolume<VoxelType>::getEnclosingRegion(void) const
const Region& BaseVolume<VoxelType>::getEnclosingRegion(void) const
{
return m_regValidRegion;
}
@ -153,6 +153,30 @@ namespace PolyVox
return m_fDiagonalLength;
}
////////////////////////////////////////////////////////////////////////////////
/// \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>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const
{
assert(false);
return VoxelType();
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/) const
{
assert(false);
return VoxelType();
}
////////////////////////////////////////////////////////////////////////////////
/// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel
@ -177,13 +201,37 @@ namespace PolyVox
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>::getVoxelWithWrapping(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const
{
assert(false);
return VoxelType();
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxelWithWrapping(const Vector3DInt32& /*v3dPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const
{
assert(false);
return VoxelType();
}
////////////////////////////////////////////////////////////////////////////////
/// \param tBorder The value to use for voxels outside the volume.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
void BaseVolume<VoxelType>::setBorderValue(const VoxelType& /*tBorder*/)
void BaseVolume<VoxelType>::setBorderValue(const VoxelType& tBorder)
{
assert(false);
m_tBorderValue = tBorder;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -21,6 +21,8 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#include "PolyVoxCore/Impl/Utility.h"
namespace PolyVox
{
template <typename VoxelType>
@ -30,6 +32,11 @@ namespace PolyVox
,mXPosInVolume(0)
,mYPosInVolume(0)
,mZPosInVolume(0)
,m_eWrapMode(WrapModes::Border)
,m_tBorder(0)
,m_bIsCurrentPositionValidInX(false)
,m_bIsCurrentPositionValidInY(false)
,m_bIsCurrentPositionValidInZ(false)
{
}
@ -53,13 +60,18 @@ namespace PolyVox
return mVolume->getVoxelAt(mXPosInVolume, mYPosInVolume, mZPosInVolume);
}
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)
{
mXPosInVolume = v3dNewPos.getX();
mYPosInVolume = v3dNewPos.getY();
mZPosInVolume = v3dNewPos.getZ();
setPosition(v3dNewPos.getX(), v3dNewPos.getY(), v3dNewPos.getZ());
}
template <typename VoxelType>
@ -69,6 +81,10 @@ namespace PolyVox
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>
@ -78,11 +94,20 @@ namespace PolyVox
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>
@ -90,6 +115,7 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveY(void)
{
mYPosInVolume++;
m_bIsCurrentPositionValidInY = mVolume->getEnclosingRegion().containsPointInY(mYPosInVolume);
}
template <typename VoxelType>
@ -97,6 +123,7 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveZ(void)
{
mZPosInVolume++;
m_bIsCurrentPositionValidInZ = mVolume->getEnclosingRegion().containsPointInZ(mZPosInVolume);
}
template <typename VoxelType>
@ -104,6 +131,7 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeX(void)
{
mXPosInVolume--;
m_bIsCurrentPositionValidInX = mVolume->getEnclosingRegion().containsPointInX(mXPosInVolume);
}
template <typename VoxelType>
@ -111,6 +139,7 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeY(void)
{
mYPosInVolume--;
m_bIsCurrentPositionValidInY = mVolume->getEnclosingRegion().containsPointInY(mYPosInVolume);
}
template <typename VoxelType>
@ -118,69 +147,70 @@ namespace PolyVox
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 mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume );
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume + 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py1nz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume );
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume + 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py1nz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume );
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume + 1);
}
//////////////////////////////////////////////////////////////////////////
@ -189,63 +219,63 @@ namespace PolyVox
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny1nz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume );
return getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume + 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py1nz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume );
return getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume + 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py1nz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume );
return getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume + 1);
}
//////////////////////////////////////////////////////////////////////////
@ -254,62 +284,101 @@ namespace PolyVox
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny1nz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume );
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume + 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py1nz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume );
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume + 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py1nz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume - 1);
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume - 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py0pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume );
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume );
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py1pz(void) const
{
return mVolume->getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume + 1);
return getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume + 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{
if(mVolume->getEnclosingRegion().containsPoint(uXPos, uYPos, uZPos))
{
return mVolume->getVoxelAt(uXPos, uYPos, uZPos);
}
else
{
switch(m_eWrapMode)
{
case WrapModes::Clamp:
{
const Vector3DInt32& lowerCorner = mVolume->m_regValidRegion.getLowerCorner();
const Vector3DInt32& upperCorner = mVolume->m_regValidRegion.getUpperCorner();
int32_t iClampedX = clamp(uXPos, lowerCorner.getX(), upperCorner.getX());
int32_t iClampedY = clamp(uYPos, lowerCorner.getY(), upperCorner.getY());
int32_t iClampedZ = clamp(uZPos, lowerCorner.getZ(), upperCorner.getZ());
return mVolume->getVoxelAt(iClampedX, iClampedY, iClampedZ);
//No need to break as we've returned
}
case WrapModes::Border:
{
return m_tBorder;
//No need to break as we've returned
}
default:
{
//Should never happen
assert(false);
return VoxelType(0);
}
}
}
}
}

View File

@ -29,6 +29,7 @@ freely, subject to the following restrictions:
#include "PolyVoxForwardDeclarations.h"
#include "PolyVoxCore/Array.h"
#include "PolyVoxCore/BaseVolume.h" //For wrap modes... should move these?
#include "PolyVoxCore/DefaultIsQuadNeeded.h"
#include "PolyVoxCore/SurfaceMesh.h"
@ -109,7 +110,7 @@ namespace PolyVox
};
public:
CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterial>* result, bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded());
CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterial>* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(0), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded());
void execute();
@ -145,6 +146,10 @@ namespace PolyVox
//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;
};
}

View File

@ -35,11 +35,13 @@ namespace PolyVox
const uint32_t CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::MaxVerticesPerPosition = 6;
template<typename VolumeType, typename IsQuadNeeded>
CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterial>* result, bool bMergeQuads, IsQuadNeeded isQuadNeeded)
CubicSurfaceExtractor<VolumeType, IsQuadNeeded>::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterial>* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads, IsQuadNeeded isQuadNeeded)
:m_volData(volData)
,m_regSizeInVoxels(region)
,m_meshCurrent(result)
,m_bMergeQuads(bMergeQuads)
,m_eWrapMode(eWrapMode)
,m_tBorderValue(tBorderValue)
{
m_funcIsQuadNeededCallback = isQuadNeeded;
}
@ -68,6 +70,7 @@ namespace PolyVox
m_vecQuads[PositiveZ].resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2);
typename VolumeType::Sampler volumeSampler(m_volData);
volumeSampler.setWrapMode(m_eWrapMode, m_tBorderValue);
for(int32_t z = m_regSizeInVoxels.getLowerCorner().getZ(); z <= m_regSizeInVoxels.getUpperCorner().getZ(); z++)
{

View File

@ -27,6 +27,7 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/DefaultIsQuadNeeded.h"
#include "PolyVoxCore/Array.h"
#include "PolyVoxCore/BaseVolume.h" //For wrap modes... should move these?
#include "PolyVoxCore/SurfaceMesh.h"
namespace PolyVox
@ -35,7 +36,7 @@ namespace PolyVox
class CubicSurfaceExtractorWithNormals
{
public:
CubicSurfaceExtractorWithNormals(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, IsQuadNeeded isQuadNeeded = IsQuadNeeded());
CubicSurfaceExtractorWithNormals(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(0), IsQuadNeeded isQuadNeeded = IsQuadNeeded());
void execute();
@ -51,6 +52,10 @@ namespace PolyVox
//Information about the region we are currently processing
Region m_regSizeInVoxels;
//The wrap mode
WrapMode m_eWrapMode;
typename VolumeType::VoxelType m_tBorderValue;
};
}

View File

@ -24,11 +24,13 @@ freely, subject to the following restrictions:
namespace PolyVox
{
template<typename VolumeType, typename IsQuadNeeded>
CubicSurfaceExtractorWithNormals<VolumeType, IsQuadNeeded>::CubicSurfaceExtractorWithNormals(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, IsQuadNeeded isQuadNeeded)
CubicSurfaceExtractorWithNormals<VolumeType, IsQuadNeeded>::CubicSurfaceExtractorWithNormals(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, IsQuadNeeded isQuadNeeded)
:m_volData(volData)
,m_sampVolume(volData)
,m_meshCurrent(result)
,m_regSizeInVoxels(region)
,m_eWrapMode(eWrapMode)
,m_tBorderValue(tBorderValue)
{
m_funcIsQuadNeededCallback = isQuadNeeded;
}
@ -51,7 +53,7 @@ namespace PolyVox
uint32_t material = 0;
if(m_funcIsQuadNeededCallback(m_volData->getVoxelAt(x,y,z), m_volData->getVoxelAt(x+1,y,z), material))
if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x+1,y,z,m_eWrapMode,m_tBorderValue), material))
{
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), static_cast<float>(material)));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), static_cast<float>(material)));
@ -61,7 +63,7 @@ namespace PolyVox
m_meshCurrent->addTriangleCubic(v0,v2,v1);
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
if(m_funcIsQuadNeededCallback(m_volData->getVoxelAt(x+1,y,z), m_volData->getVoxelAt(x,y,z), material))
if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x+1,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), material))
{
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), static_cast<float>(material)));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), static_cast<float>(material)));
@ -72,7 +74,7 @@ namespace PolyVox
m_meshCurrent->addTriangleCubic(v1,v3,v2);
}
if(m_funcIsQuadNeededCallback(m_volData->getVoxelAt(x,y,z), m_volData->getVoxelAt(x,y+1,z), material))
if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y+1,z,m_eWrapMode,m_tBorderValue), material))
{
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), static_cast<float>(material)));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), static_cast<float>(material)));
@ -82,7 +84,7 @@ namespace PolyVox
m_meshCurrent->addTriangleCubic(v0,v1,v2);
m_meshCurrent->addTriangleCubic(v1,v3,v2);
}
if(m_funcIsQuadNeededCallback(m_volData->getVoxelAt(x,y+1,z), m_volData->getVoxelAt(x,y,z), material))
if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y+1,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), material))
{
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), static_cast<float>(material)));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), static_cast<float>(material)));
@ -93,7 +95,7 @@ namespace PolyVox
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
if(m_funcIsQuadNeededCallback(m_volData->getVoxelAt(x,y,z), m_volData->getVoxelAt(x,y,z+1), material))
if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y,z+1,m_eWrapMode,m_tBorderValue), material))
{
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), static_cast<float>(material)));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), static_cast<float>(material)));
@ -103,7 +105,7 @@ namespace PolyVox
m_meshCurrent->addTriangleCubic(v0,v2,v1);
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
if(m_funcIsQuadNeededCallback(m_volData->getVoxelAt(x,y,z+1), m_volData->getVoxelAt(x,y,z), material))
if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y,z+1,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), material))
{
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), static_cast<float>(material)));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), static_cast<float>(material)));

View File

@ -24,7 +24,7 @@ freely, subject to the following restrictions:
#ifndef __PolyVox_DefaultIsQuadNeeded_H__
#define __PolyVox_DefaultIsQuadNeeded_H__
#include <cstdint>
#include "PolyVoxCore/Impl/TypeDef.h"
namespace PolyVox
{

View File

@ -24,38 +24,40 @@ freely, subject to the following restrictions:
#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
///
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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
{
@ -67,63 +69,57 @@ namespace PolyVox
/// but this is not really desirable on modern hardware. We'll probably come back to material representation in the future.
typedef float 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.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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)
:m_tThreshold(((std::numeric_limits<DensityType>::min)() + (std::numeric_limits<DensityType>::max)()) / 2)
{
m_tThreshold = ((std::numeric_limits<DensityType>::min)() + (std::numeric_limits<DensityType>::max)()) / 2;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Constructor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// This version of the constructor allows you to set a custom threshold.
/// \param tThreshold The threshold to use.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DefaultMarchingCubesController(DensityType tThreshold)
{
m_tThreshold = tThreshold;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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 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.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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;
};

View File

@ -177,6 +177,11 @@ namespace PolyVox
return m_tThreshold;
}
void setThreshold(DensityType tThreshold)
{
m_tThreshold = tThreshold;
}
private:
DensityType m_tThreshold;
};

View File

@ -46,6 +46,13 @@ freely, subject to the following restrictions:
#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.
@ -95,7 +102,7 @@ freely, subject to the following restrictions:
//In this case we can just use static_assert
#else
#include <boost/static_assert.hpp>
#define static_assert BOOST_STATIC_ASSERT
#define static_assert(condition, message) BOOST_STATIC_ASSERT(condition)
#endif
#if defined(HAS_CXX11_CSTDINT_H)

View File

@ -32,6 +32,27 @@ namespace PolyVox
{
POLYVOX_API uint8_t logBase2(uint32_t uInput);
POLYVOX_API bool isPowerOf2(uint32_t uInput);
int32_t roundTowardsNegInf(float r);
int32_t roundToInteger(float r);
template <typename Type>
Type clamp(const Type& value, const Type& low, const Type& high);
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

View File

@ -166,6 +166,7 @@ namespace PolyVox
//in the future
//typedef Volume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences.
//class Sampler : public VolumeOfVoxelType::template Sampler< LargeVolume<VoxelType> >
#ifndef SWIG
#if defined(_MSC_VER)
class Sampler : public BaseVolume<VoxelType>::Sampler< LargeVolume<VoxelType> > //This line works on VS2010
#else
@ -176,9 +177,8 @@ namespace PolyVox
Sampler(LargeVolume<VoxelType>* volume);
~Sampler();
Sampler& operator=(const Sampler& rhs);
VoxelType getSubSampledVoxel(uint8_t uLevel) const;
/// \deprecated
POLYVOX_DEPRECATED VoxelType getSubSampledVoxel(uint8_t uLevel) const;
inline VoxelType getVoxel(void) const;
void setPosition(const Vector3DInt32& v3dNewPos);
@ -243,6 +243,7 @@ namespace PolyVox
Block<VoxelType> block;
uint32_t timestamp;
};
#endif
public:
/// Constructor for creating a very large paging volume.
@ -264,12 +265,18 @@ namespace PolyVox
/// Destructor
~LargeVolume();
/// Gets the value used for voxels which are outside the volume
VoxelType getBorderValue(void) 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) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxel(const Vector3DInt32& v3dPos) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType(0)) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType(0)) const;
//Sets whether or not blocks are compressed in memory
void setCompressionEnabled(bool bCompressionEnabled);
@ -277,8 +284,6 @@ namespace PolyVox
void setMaxNumberOfUncompressedBlocks(uint32_t uMaxNumberOfUncompressedBlocks);
/// Sets the number of blocks which can be in memory before the paging system starts unloading them
void setMaxNumberOfBlocksInMemory(uint32_t uMaxNumberOfBlocksInMemory);
/// 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
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
/// Sets the voxel at the position given by a 3D vector
@ -305,6 +310,22 @@ namespace PolyVox
LargeVolume& operator=(const LargeVolume& rhs);
private:
struct BlockPositionCompare
{
bool operator() (const PolyVox::Vector3DInt32& a, const PolyVox::Vector3DInt32& b)
{
const uint32_t size = 3;
for(uint32_t ct = 0; ct < size; ++ct)
{
if (a.getElement(ct) < b.getElement(ct))
return true;
if (b.getElement(ct) < a.getElement(ct))
return false;
}
return false;
}
};
void initialise(const Region& regValidRegion, uint16_t uBlockSideLength);
/// gets called when a new region is allocated and needs to be filled
@ -318,12 +339,12 @@ namespace PolyVox
polyvox_function<void(const ConstVolumeProxy<VoxelType>&, const Region&)> m_funcDataOverflowHandler;
Block<VoxelType>* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const;
void eraseBlock(typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock) const;
void eraseBlock(typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator itBlock) const;
/// this function can be called by m_funcDataRequiredHandler without causing any weird effects
bool setVoxelAtConst(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const;
//The block data
mutable std::map<Vector3DInt32, LoadedBlock > m_pBlocks;
mutable std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare> m_pBlocks;
//The cache of uncompressed blocks. The uncompressed block data and the timestamps are stored here rather
//than in the Block class. This is so that in the future each VolumeIterator might to maintain its own cache
@ -336,12 +357,6 @@ namespace PolyVox
uint32_t m_uMaxNumberOfUncompressedBlocks;
uint32_t m_uMaxNumberOfBlocksInMemory;
//We don't store an actual Block for the border, just the uncompressed data. This is partly because the border
//block does not have a position (so can't be passed to getUncompressedBlock()) and partly because there's a
//good chance we'll often hit it anyway. It's a chunk of homogenous data (rather than a single value) so that
//the VolumeIterator can do it's usual pointer arithmetic without needing to know it's gone outside the volume.
VoxelType* m_pUncompressedBorderData;
//The size of the volume
Region m_regValidRegionInBlocks;

View File

@ -95,7 +95,6 @@ namespace PolyVox
LargeVolume<VoxelType>::~LargeVolume()
{
flushAll();
delete[] m_pUncompressedBorderData;
}
////////////////////////////////////////////////////////////////////////////////
@ -112,14 +111,37 @@ namespace PolyVox
}
////////////////////////////////////////////////////////////////////////////////
/// The border value is returned whenever an atempt is made to read a voxel which
/// is outside the extents of the volume.
/// \return The value used for voxels outside of the volume
/// \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 LargeVolume<VoxelType>::getBorderValue(void) const
VoxelType LargeVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{
return *m_pUncompressedBorderData;
assert(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)));
const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
const int32_t blockY = uYPos >> m_uBlockSideLengthPower;
const int32_t blockZ = uZPos >> m_uBlockSideLengthPower;
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (blockX << m_uBlockSideLengthPower));
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower));
Block<VoxelType>* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset);
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos) const
{
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
}
////////////////////////////////////////////////////////////////////////////////
@ -147,7 +169,7 @@ namespace PolyVox
}
else
{
return getBorderValue();
return this->getBorderValue();
}
}
@ -161,6 +183,62 @@ namespace PolyVox
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
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const
{
switch(eWrapMode)
{
case WrapModes::Clamp:
{
//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());
//Get the voxel value
return getVoxel(uXPos, uYPos, uZPos);
//No need to break as we've returned
}
case WrapModes::Border:
{
if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
{
return getVoxel(uXPos, uYPos, uZPos);
}
else
{
return tBorder;
}
//No need to break as we've returned
}
default:
{
//Should never happen
assert(false);
return VoxelType(0);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const
{
return getVoxelWithWrapping(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
}
////////////////////////////////////////////////////////////////////////////////
/// Enabling compression allows significantly more data to be stored in memory.
/// \param bCompressionEnabled Specifies whether compression is enabled.
@ -213,17 +291,6 @@ namespace PolyVox
m_uMaxNumberOfBlocksInMemory = uMaxNumberOfBlocksInMemory;
}
////////////////////////////////////////////////////////////////////////////////
/// \param tBorder The value to use for voxels outside the volume.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
void LargeVolume<VoxelType>::setBorderValue(const VoxelType& tBorder)
{
/*Block<VoxelType>* pUncompressedBorderBlock = getUncompressedBlock(&m_pBorderBlock);
return pUncompressedBorderBlock->fill(tBorder);*/
std::fill(m_pUncompressedBorderData, m_pUncompressedBorderData + m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength, tBorder);
}
////////////////////////////////////////////////////////////////////////////////
/// \param uXPos the \c x position of the voxel
/// \param uYPos the \c y position of the voxel
@ -297,7 +364,7 @@ namespace PolyVox
for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++)
{
Vector3DInt32 pos(x,y,z);
typename std::map<Vector3DInt32, LoadedBlock>::iterator itBlock = m_pBlocks.find(pos);
typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(pos);
if(itBlock != m_pBlocks.end())
{
@ -328,7 +395,7 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::flushAll()
{
typename std::map<Vector3DInt32, LoadedBlock >::iterator i;
typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator i;
//Replaced the for loop here as the call to
//eraseBlock was invalidating the iterator.
while(m_pBlocks.size() > 0)
@ -362,7 +429,7 @@ namespace PolyVox
for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++)
{
Vector3DInt32 pos(x,y,z);
typename std::map<Vector3DInt32, LoadedBlock>::iterator itBlock = m_pBlocks.find(pos);
typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(pos);
if(itBlock == m_pBlocks.end())
{
// not loaded, not unloading
@ -414,7 +481,6 @@ namespace PolyVox
m_uTimestamper = 0;
m_uMaxNumberOfUncompressedBlocks = 16;
m_uBlockSideLength = uBlockSideLength;
m_pUncompressedBorderData = 0;
m_uMaxNumberOfBlocksInMemory = 1024;
m_v3dLastAccessedBlockPos = Vector3DInt32(0,0,0); //There are no invalid positions, but initially the m_pLastAccessedBlock pointer will be null;
m_pLastAccessedBlock = 0;
@ -422,25 +488,25 @@ namespace PolyVox
this->m_regValidRegion = regValidRegion;
m_regValidRegionInBlocks.setLowerCorner(this->m_regValidRegion.getLowerCorner() / static_cast<int32_t>(uBlockSideLength));
m_regValidRegionInBlocks.setUpperCorner(this->m_regValidRegion.getUpperCorner() / static_cast<int32_t>(uBlockSideLength));
//Compute the block side length
m_uBlockSideLength = uBlockSideLength;
m_uBlockSideLengthPower = logBase2(m_uBlockSideLength);
m_regValidRegionInBlocks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setLowerY(this->m_regValidRegion.getLowerY() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setLowerZ(this->m_regValidRegion.getLowerZ() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setUpperX(this->m_regValidRegion.getUpperX() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uBlockSideLengthPower);
setMaxNumberOfUncompressedBlocks(m_uMaxNumberOfUncompressedBlocks);
//Clear the previous data
m_pBlocks.clear();
//Compute the block side length
m_uBlockSideLength = uBlockSideLength;
m_uBlockSideLengthPower = logBase2(m_uBlockSideLength);
//Clear the previous data
m_pBlocks.clear();
//Create the border block
m_pUncompressedBorderData = new VoxelType[m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength];
std::fill(m_pUncompressedBorderData, m_pUncompressedBorderData + m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength, VoxelType());
//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());
@ -448,7 +514,7 @@ namespace PolyVox
}
template <typename VoxelType>
void LargeVolume<VoxelType>::eraseBlock(typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock) const
void LargeVolume<VoxelType>::eraseBlock(typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator itBlock) const
{
if(m_funcDataOverflowHandler)
{
@ -519,7 +585,7 @@ namespace PolyVox
return m_pLastAccessedBlock;
}
typename std::map<Vector3DInt32, LoadedBlock >::iterator itBlock = m_pBlocks.find(v3dBlockPos);
typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(v3dBlockPos);
// check whether the block is already loaded
if(itBlock == m_pBlocks.end())
{
@ -532,8 +598,8 @@ namespace PolyVox
if(m_pBlocks.size() == m_uMaxNumberOfBlocksInMemory)
{
// find the least recently used block
typename std::map<Vector3DInt32, LoadedBlock >::iterator i;
typename std::map<Vector3DInt32, LoadedBlock >::iterator itUnloadBlock = m_pBlocks.begin();
typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator i;
typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator itUnloadBlock = m_pBlocks.begin();
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{
if(i->second.timestamp < itUnloadBlock->second.timestamp)
@ -622,8 +688,8 @@ namespace PolyVox
template <typename VoxelType>
float LargeVolume<VoxelType>::calculateCompressionRatio(void)
{
float fRawSize = m_pBlocks.size() * m_uBlockSideLength * m_uBlockSideLength* m_uBlockSideLength * sizeof(VoxelType);
float fCompressedSize = calculateSizeInBytes();
float fRawSize = static_cast<float>(m_pBlocks.size() * m_uBlockSideLength * m_uBlockSideLength* m_uBlockSideLength * sizeof(VoxelType));
float fCompressedSize = static_cast<float>(calculateSizeInBytes());
return fCompressedSize/fRawSize;
}
@ -636,7 +702,7 @@ namespace PolyVox
uint32_t uSizeInBytes = sizeof(LargeVolume);
//Memory used by the blocks
typename std::map<Vector3DInt32, LoadedBlock >::iterator i;
typename std::map<Vector3DInt32, LoadedBlock, BlockPositionCompare>::iterator i;
for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++)
{
//Inaccurate - account for rest of loaded block.
@ -647,12 +713,6 @@ namespace PolyVox
uSizeInBytes += m_vecUncompressedBlockCache.capacity() * sizeof(LoadedBlock);
uSizeInBytes += m_vecUncompressedBlockCache.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
//Memory used by border data.
if(m_pUncompressedBorderData)
{
uSizeInBytes += m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType);
}
return uSizeInBytes;
}

View File

@ -21,10 +21,12 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#define BORDER_LOW(x) ((( x >> this->mVolume->m_uBlockSideLengthPower) << this->mVolume->m_uBlockSideLengthPower) != x)
#define BORDER_HIGH(x) ((( (x+1) >> this->mVolume->m_uBlockSideLengthPower) << this->mVolume->m_uBlockSideLengthPower) != (x+1))
//#define BORDER_LOW(x) (( x % mVolume->m_uBlockSideLength) != 0)
//#define BORDER_HIGH(x) (( x % mVolume->m_uBlockSideLength) != mVolume->m_uBlockSideLength - 1)
#define CAN_GO_NEG_X(val) ((val > this->mVolume->getEnclosingRegion().getLowerCorner().getX()) && (val % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_POS_X(val) ((val < this->mVolume->getEnclosingRegion().getUpperCorner().getX()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_NEG_Y(val) ((val > this->mVolume->getEnclosingRegion().getLowerCorner().getY()) && (val % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_POS_Y(val) ((val < this->mVolume->getEnclosingRegion().getUpperCorner().getY()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_NEG_Z(val) ((val > this->mVolume->getEnclosingRegion().getLowerCorner().getZ()) && (val % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_POS_Z(val) ((val < this->mVolume->getEnclosingRegion().getUpperCorner().getZ()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0))
namespace PolyVox
{
@ -39,21 +41,6 @@ namespace PolyVox
{
}
template <typename VoxelType>
typename LargeVolume<VoxelType>::Sampler& LargeVolume<VoxelType>::Sampler::operator=(const typename LargeVolume<VoxelType>::Sampler& rhs)
{
if(this == &rhs)
{
return *this;
}
this->mVolume = rhs.mVolume;
this->mXPosInVolume = rhs.mXPosInVolume;
this->mYPosInVolume = rhs.mYPosInVolume;
this->mZPosInVolume = rhs.mZPosInVolume;
mCurrentVoxel = rhs.mCurrentVoxel;
return *this;
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::getSubSampledVoxel(uint8_t uLevel) const
{
@ -94,9 +81,16 @@ namespace PolyVox
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::getVoxel(void) const
{
if(this->isCurrentPositionValid())
{
return *mCurrentVoxel;
}
else
{
return getVoxelAt(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType>
void LargeVolume<VoxelType>::Sampler::setPosition(const Vector3DInt32& v3dNewPos)
@ -107,10 +101,12 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::Sampler::setPosition(int32_t xPos, int32_t yPos, int32_t zPos)
{
this->mXPosInVolume = xPos;
this->mYPosInVolume = yPos;
this->mZPosInVolume = zPos;
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< LargeVolume<VoxelType> >::setPosition(xPos, yPos, zPos);
// Then we update the voxel pointer
if(this->isCurrentPositionValid())
{
const int32_t uXBlock = this->mXPosInVolume >> this->mVolume->m_uBlockSideLengthPower;
const int32_t uYBlock = this->mYPosInVolume >> this->mVolume->m_uBlockSideLengthPower;
const int32_t uZBlock = this->mZPosInVolume >> this->mVolume->m_uBlockSideLengthPower;
@ -123,22 +119,29 @@ namespace PolyVox
uYPosInBlock * this->mVolume->m_uBlockSideLength +
uZPosInBlock * this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength;
if(this->mVolume->m_regValidRegionInBlocks.containsPoint(Vector3DInt32(uXBlock, uYBlock, uZBlock)))
{
Block<VoxelType>* pUncompressedCurrentBlock = this->mVolume->getUncompressedBlock(uXBlock, uYBlock, uZBlock);
mCurrentVoxel = pUncompressedCurrentBlock->m_tUncompressedData + uVoxelIndexInBlock;
}
else
{
mCurrentVoxel = this->mVolume->m_pUncompressedBorderData + uVoxelIndexInBlock;
mCurrentVoxel = 0;
}
}
template <typename VoxelType>
bool LargeVolume<VoxelType>::Sampler::setVoxel(VoxelType tValue)
{
//*mCurrentVoxel = 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.
assert(false);
return false;
@ -147,8 +150,14 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::Sampler::movePositiveX(void)
{
//Note the *pre* increament here
if((++this->mXPosInVolume) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< LargeVolume<VoxelType> >::movePositiveX();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
++mCurrentVoxel;
@ -163,8 +172,14 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::Sampler::movePositiveY(void)
{
//Note the *pre* increament here
if((++this->mYPosInVolume) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< LargeVolume<VoxelType> >::movePositiveY();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
mCurrentVoxel += this->mVolume->m_uBlockSideLength;
@ -179,8 +194,14 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::Sampler::movePositiveZ(void)
{
//Note the *pre* increament here
if((++this->mZPosInVolume) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< LargeVolume<VoxelType> >::movePositiveZ();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
mCurrentVoxel += this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength;
@ -195,8 +216,14 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::Sampler::moveNegativeX(void)
{
//Note the *post* decreament here
if((this->mXPosInVolume--) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< LargeVolume<VoxelType> >::moveNegativeX();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
--mCurrentVoxel;
@ -211,8 +238,14 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::Sampler::moveNegativeY(void)
{
//Note the *post* decreament here
if((this->mYPosInVolume--) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< LargeVolume<VoxelType> >::moveNegativeY();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
mCurrentVoxel -= this->mVolume->m_uBlockSideLength;
@ -227,8 +260,14 @@ namespace PolyVox
template <typename VoxelType>
void LargeVolume<VoxelType>::Sampler::moveNegativeZ(void)
{
//Note the *post* decreament here
if((this->mZPosInVolume--) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< LargeVolume<VoxelType> >::moveNegativeZ();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
mCurrentVoxel -= this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength;
@ -243,91 +282,91 @@ namespace PolyVox
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx1ny1nz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
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_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx1ny0pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx1ny1pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
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_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx0py1nz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx0py0pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) )
{
return *(mCurrentVoxel - 1);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx0py1pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx1py1nz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
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_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx1py0pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1nx1py1pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
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_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
//////////////////////////////////////////////////////////////////////////
@ -335,87 +374,91 @@ namespace PolyVox
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px1ny1nz(void) const
{
if( BORDER_LOW(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px1ny0pz(void) const
{
if( BORDER_LOW(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px1ny1pz(void) const
{
if( BORDER_LOW(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px0py1nz(void) const
{
if( BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px0py0pz(void) const
{
if((this->isCurrentPositionValid()))
{
return *mCurrentVoxel;
}
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px0py1pz(void) const
{
if( BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px1py1nz(void) const
{
if( BORDER_HIGH(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px1py0pz(void) const
{
if( BORDER_HIGH(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel0px1py1pz(void) const
{
if( BORDER_HIGH(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
//////////////////////////////////////////////////////////////////////////
@ -423,93 +466,97 @@ namespace PolyVox
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px1ny1nz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
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_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px1ny0pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px1ny1pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
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_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px0py1nz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px0py0pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) )
{
return *(mCurrentVoxel + 1);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px0py1pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px1py1nz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
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_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px1py0pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType LargeVolume<VoxelType>::Sampler::peekVoxel1px1py1pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
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_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
}
#undef BORDER_LOW
#undef BORDER_HIGH
#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

View File

@ -28,6 +28,7 @@ freely, subject to the following restrictions:
#include "Impl/TypeDef.h"
#include "PolyVoxCore/Array.h"
#include "PolyVoxCore/BaseVolume.h" //For wrap modes... should move these?
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/DefaultMarchingCubesController.h"
@ -37,7 +38,7 @@ namespace PolyVox
class MarchingCubesSurfaceExtractor
{
public:
MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, Controller controller = Controller());
MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(0), Controller controller = Controller());
void execute();
@ -189,7 +190,7 @@ namespace PolyVox
SurfaceMesh<PositionMaterialNormal>* m_meshCurrent;
//Information about the region we are currently processing
const Region m_regSizeInVoxels;
Region m_regSizeInVoxels;
Region m_regSizeInCells;
/*Region m_regSizeInVoxelsCropped;
Region m_regSizeInVoxelsUncropped;
@ -201,7 +202,7 @@ namespace PolyVox
Controller m_controller;
//Our threshold value
const typename Controller::DensityType m_tThreshold;
typename Controller::DensityType m_tThreshold;
};
}

View File

@ -24,7 +24,7 @@ freely, subject to the following restrictions:
namespace PolyVox
{
template<typename VolumeType, typename Controller>
MarchingCubesSurfaceExtractor<VolumeType, Controller>::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, Controller controller)
MarchingCubesSurfaceExtractor<VolumeType, Controller>::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, Controller controller)
:m_volData(volData)
,m_sampVolume(volData)
,m_meshCurrent(result)
@ -35,6 +35,8 @@ namespace PolyVox
//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 Controller>

View File

@ -42,6 +42,10 @@ namespace PolyVox
{
public:
MaterialDensityPair() : m_uMaterial(0), m_uDensity(0) {}
// FIXME - This is a bit odd... we need to allow the MaterialDensityPair to be initialised with a single integer
// because PolyVox often initialises voxels by calling VoxelType(0). Is there a better way we should handle this?
MaterialDensityPair(Type tValue) : m_uMaterial(tValue), m_uDensity(tValue) {}
MaterialDensityPair(Type uMaterial, Type uDensity) : m_uMaterial(uMaterial), m_uDensity(uDensity) {}
bool operator==(const MaterialDensityPair& rhs) const
@ -137,6 +141,11 @@ namespace PolyVox
return m_tThreshold;
}
void setThreshold(DensityType tThreshold)
{
m_tThreshold = tThreshold;
}
private:
DensityType m_tThreshold;
};

View File

@ -1,187 +0,0 @@
/*******************************************************************************
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_MeshDecimator_H__
#define __PolyVox_MeshDecimator_H__
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/Vector.h"
#include "PolyVoxCore/VertexTypes.h"
#include <bitset>
#include <vector>
namespace PolyVox
{
/// The MeshDecimator reduces the number of triangles in a mesh.
////////////////////////////////////////////////////////////////////////////////
/// Meshes generated by the PolyVox surface extractors typically have a very high
/// number of triangles in them. This can pose difficulties both for the rendering
/// storage of such meshes. The MeshDecimator provides a way of reducing the triangle
/// count with minimal visual effect.
///
/// The MeshDecimator is based on the principle of edge collapse, and currently works
/// with meshes generated by the MarchingCubesSurfaceExtractor or CubicSurfaceExtractor. It does
/// not work with meshes generated by the CubicSurfaceExtractorWithNormals, although
/// this may be addressed in the future. The algorithm iterates over each pair of
/// connected vertices in the mesh and attemps to determine if they can be collapsed
/// into a single vertex.
///
/// The main criteria used in deciding whether two vertices can collapse is whether
/// they have the same normal. In the case of the cubic surfaces the normals must be
/// exactly the same, whereas in the case of the Marching Cubes surfaces a threshold
/// is used to determine whether two normals are 'close enough'. Additional constraints
/// apply to vertices which lie on the edges of regions or on the boundary between two
/// regions - these vertices are much less likely to be collapsed.
///
/// Given a mesh called 'mesh', you can create a decimated version as follows:
/// \code
/// SurfaceMesh<PositionMaterial> decimatedMesh;
/// MeshDecimator<PositionMaterial> decimator(&mesh, &decimatedMesh);
/// decimator.execute();
/// \endcode
///
/// The above applies for a cubic mesh, for a Marching Cubes mesh you need to parametise
/// the MeshDecimator and resulting SurfaceMesh on the 'PositionMaterialNormal' type
/// instead of the 'PositionMaterial' type.
///
/// \deprecated
template <typename VertexType>
class MeshDecimator
{
//Used to keep track of when a vertex is
//on one or more faces of the region
enum RegionFaceFlags
{
RFF_ON_REGION_FACE_NEG_X,
RFF_ON_REGION_FACE_POS_X ,
RFF_ON_REGION_FACE_NEG_Y ,
RFF_ON_REGION_FACE_POS_Y ,
RFF_ON_REGION_FACE_NEG_Z ,
RFF_ON_REGION_FACE_POS_Z,
RFF_NO_OF_REGION_FACE_FLAGS
};
//Data about the initial mesh - this
//will be fill in once at the start
struct InitialVertexMetadata
{
Vector3DFloat normal;
bool isOnMaterialEdge;
std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> isOnRegionFace;
};
//Representing a triangle for decimation purposes.
struct Triangle
{
uint32_t v0;
uint32_t v1;
uint32_t v2;
Vector3DFloat normal;
};
struct IntVertex
{
int32_t x;
int32_t y;
int32_t z;
uint32_t index;
IntVertex(int32_t xVal, int32_t yVal, int32_t zVal, uint32_t indexVal)
:x(xVal)
,y(yVal)
,z(zVal)
,index(indexVal)
{
}
bool operator==(const IntVertex& rhs) const
{
return (x == rhs.x) && (y == rhs.y) && (z == rhs.z);
}
bool operator<(const IntVertex& rhs) const
{
if (z < rhs.z)
return true;
if (rhs.z < z)
return false;
if (y < rhs.y)
return true;
if (rhs.y < y)
return false;
if (x < rhs.x)
return true;
if (rhs.x < x)
return false;
return false;
}
};
public:
///Constructor
POLYVOX_DEPRECATED MeshDecimator(const SurfaceMesh<VertexType>* pInputMesh, SurfaceMesh<VertexType>* pOutputMesh, float fEdgeCollapseThreshold = 0.95f);
///Performs the decimation.
POLYVOX_DEPRECATED void execute();
private:
void fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecInitialVertexMetadata);
void buildConnectivityData(void);
bool attemptEdgeCollapse(uint32_t uSrc, uint32_t uDst);
const SurfaceMesh<VertexType>* m_pInputMesh;
SurfaceMesh<VertexType>* m_pOutputMesh;
uint32_t performDecimationPass(float m_fMinDotProductForCollapse);
bool isSubset(std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> a, std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> b);
bool canCollapseEdge(uint32_t uSrc, uint32_t uDst);
bool canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst);
bool canCollapseRegionEdge(uint32_t uSrc, uint32_t uDst);
bool canCollapseMaterialEdge(uint32_t uSrc, uint32_t uDst);
bool collapseChangesFaceNormals(uint32_t uSrc, uint32_t uDst, float fThreshold);
//Data structures used during decimation
std::vector<bool> vertexLocked;
std::vector<uint32_t> vertexMapper;
std::vector<Triangle> m_vecTriangles;
std::vector< std::vector<uint32_t> > trianglesUsingVertex; //Should probably use vector of vectors, and resise in advance.
std::vector<InitialVertexMetadata> m_vecInitialVertexMetadata;
float m_fMinDotProductForCollapse;
};
}
#include "PolyVoxCore/MeshDecimator.inl"
#endif //__PolyVox_MeshDecimator_H__

View File

@ -1,347 +0,0 @@
/*******************************************************************************
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
{
////////////////////////////////////////////////////////////////////////////////
/// Builds a MeshDecimator.
/// \param pInputMesh A pointer to the mesh to be decimated.
/// \param[out] pOutputMesh A pointer to where the result should be stored. Any existing
/// contents will be deleted.
/// \param fEdgeCollapseThreshold This is only use in the case of a Marching Cubes
/// surface and controls how close two normals must be to collapse. The dot product
/// between the normals is computed and compared to this threshold. A threshold of
/// 1.0 means nothing will collapse, a threshold of 0.0 means everything will collapse.
////////////////////////////////////////////////////////////////////////////////
template <typename VertexType>
MeshDecimator<VertexType>::MeshDecimator(const SurfaceMesh<VertexType>* pInputMesh, SurfaceMesh<VertexType>* pOutputMesh, float fEdgeCollapseThreshold)
:m_pInputMesh(pInputMesh)
,m_pOutputMesh(pOutputMesh)
,m_fMinDotProductForCollapse(fEdgeCollapseThreshold)
{
*m_pOutputMesh = *m_pInputMesh;
}
template <typename VertexType>
void MeshDecimator<VertexType>::execute()
{
//Sanity check.
if((m_pOutputMesh->m_vecVertices.empty()) || (m_pOutputMesh->m_vecTriangleIndices.empty()))
{
return;
}
buildConnectivityData();
fillInitialVertexMetadata(m_vecInitialVertexMetadata);
uint32_t noOfEdgesCollapsed;
do
{
noOfEdgesCollapsed = performDecimationPass(m_fMinDotProductForCollapse);
m_pOutputMesh->removeDegenerateTris();
if(noOfEdgesCollapsed > 0)
{
//Build the connectivity data for the next pass. If this is slow, then look
//at adjusting it (based on vertex mapper?) rather than bulding from scratch.
buildConnectivityData();
}
}while(noOfEdgesCollapsed > 0);
m_pOutputMesh->removeUnusedVertices();
//Decimation will have invalidated LOD levels.
m_pOutputMesh->m_vecLodRecords.clear();
LodRecord lodRecord;
lodRecord.beginIndex = 0;
lodRecord.endIndex = m_pOutputMesh->getNoOfIndices();
m_pOutputMesh->m_vecLodRecords.push_back(lodRecord);
}
template <typename VertexType>
void MeshDecimator<VertexType>::buildConnectivityData(void)
{
//Build a list of all the triangles, complete with face normals.
m_vecTriangles.clear();
m_vecTriangles.resize(m_pOutputMesh->m_vecTriangleIndices.size() / 3);
for(uint32_t triCt = 0; triCt < m_vecTriangles.size(); triCt++)
{
m_vecTriangles[triCt].v0 = m_pOutputMesh->m_vecTriangleIndices[triCt * 3 + 0];
m_vecTriangles[triCt].v1 = m_pOutputMesh->m_vecTriangleIndices[triCt * 3 + 1];
m_vecTriangles[triCt].v2 = m_pOutputMesh->m_vecTriangleIndices[triCt * 3 + 2];
Vector3DFloat v0Pos = m_pOutputMesh->m_vecVertices[m_vecTriangles[triCt].v0].position;
Vector3DFloat v1Pos = m_pOutputMesh->m_vecVertices[m_vecTriangles[triCt].v1].position;
Vector3DFloat v2Pos = m_pOutputMesh->m_vecVertices[m_vecTriangles[triCt].v2].position;
Vector3DFloat v0v1 = v1Pos - v0Pos;
Vector3DFloat v0v2 = v2Pos - v0Pos;
Vector3DFloat normal = v0v1.cross(v0v2);
normal.normalise();
m_vecTriangles[triCt].normal = normal;
}
//For each vertex, determine which triangles are using it.
trianglesUsingVertex.clear();
trianglesUsingVertex.resize(m_pOutputMesh->m_vecVertices.size());
for(uint32_t ct = 0; ct < trianglesUsingVertex.size(); ct++)
{
trianglesUsingVertex[ct].reserve(6);
}
for(uint32_t ct = 0; ct < m_vecTriangles.size(); ct++)
{
trianglesUsingVertex[m_vecTriangles[ct].v0].push_back(ct);
trianglesUsingVertex[m_vecTriangles[ct].v1].push_back(ct);
trianglesUsingVertex[m_vecTriangles[ct].v2].push_back(ct);
}
}
template <typename VertexType>
uint32_t MeshDecimator<VertexType>::performDecimationPass(float /*m_fMinDotProductForCollapse*/)
{
// Count how many edges we have collapsed
uint32_t noOfEdgesCollapsed = 0;
// The vertex mapper track whick vertices collapse onto which.
vertexMapper.clear();
vertexMapper.resize(m_pOutputMesh->m_vecVertices.size());
// Once a vertex is involved in a collapse (either because it
// moves onto a different vertex, or because a different vertex
// moves onto it) it is forbidden to take part in another collapse
// this pass. We enforce this by setting the vertex locked flag.
vertexLocked.clear();
vertexLocked.resize(m_pOutputMesh->m_vecVertices.size());
// Initialise the vectors
for(uint32_t ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++)
{
// Initiall all vertices points to themselves
vertexMapper[ct] = ct;
// All vertices are initially unlocked
vertexLocked[ct] = false;
}
//For each triangle...
for(uint32_t ctIter = 0; ctIter < m_vecTriangles.size(); ctIter++)
{
if(attemptEdgeCollapse(m_vecTriangles[ctIter].v0, m_vecTriangles[ctIter].v1))
{
++noOfEdgesCollapsed;
}
if(attemptEdgeCollapse(m_vecTriangles[ctIter].v1, m_vecTriangles[ctIter].v2))
{
++noOfEdgesCollapsed;
}
if(attemptEdgeCollapse(m_vecTriangles[ctIter].v2, m_vecTriangles[ctIter].v0))
{
++noOfEdgesCollapsed;
}
}
if(noOfEdgesCollapsed > 0)
{
//Fix up the indices
for(uint32_t triCt = 0; triCt < m_pOutputMesh->m_vecTriangleIndices.size(); triCt++)
{
uint32_t before = m_pOutputMesh->m_vecTriangleIndices[triCt];
uint32_t after = vertexMapper[m_pOutputMesh->m_vecTriangleIndices[triCt]];
if(before != after)
{
m_pOutputMesh->m_vecTriangleIndices[triCt] = vertexMapper[m_pOutputMesh->m_vecTriangleIndices[triCt]];
}
}
}
return noOfEdgesCollapsed;
}
template <typename VertexType>
bool MeshDecimator<VertexType>::attemptEdgeCollapse(uint32_t uSrc, uint32_t uDst)
{
//A vertex will be locked if it has already been involved in a collapse this pass.
if(vertexLocked[uSrc] || vertexLocked[uDst])
{
return false;
}
if(canCollapseEdge(uSrc, uDst))
{
//Move v0 onto v1
vertexMapper[uSrc] = uDst; //vertexMapper[v1];
vertexLocked[uSrc] = true;
vertexLocked[uDst] = true;
//Increment the counter
return true;
}
return false;
}
template <typename VertexType>
bool MeshDecimator<VertexType>::canCollapseEdge(uint32_t uSrc, uint32_t uDst)
{
bool bCanCollapse = true;
if(m_vecInitialVertexMetadata[uSrc].isOnMaterialEdge)
{
bCanCollapse &= canCollapseMaterialEdge(uSrc, uDst);
}
if(m_vecInitialVertexMetadata[uSrc].isOnRegionFace.any())
{
bCanCollapse &= canCollapseRegionEdge(uSrc, uDst);
}
if(bCanCollapse) //Only bother with this if the earlier tests passed.
{
bCanCollapse &= canCollapseNormalEdge(uSrc, uDst);
}
return bCanCollapse;
}
template <typename VertexType>
bool MeshDecimator<VertexType>::canCollapseRegionEdge(uint32_t uSrc, uint32_t uDst)
{
// We can collapse normal vertices onto edge vertices, and edge vertices
// onto corner vertices, but not vice-versa. Hence we check whether all
// the edge flags in the source vertex are also set in the destination vertex.
if(isSubset(m_vecInitialVertexMetadata[uSrc].isOnRegionFace, m_vecInitialVertexMetadata[uDst].isOnRegionFace) == false)
{
return false;
}
// In general adjacent regions surface meshes may collapse differently
// and this can cause cracks. We solve this by only allowing the collapse
// is the normals are exactly the same. We do not use the user provided
// tolerence here (but do allow for floating point error).
if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < 0.999f)
{
return false;
}
return true;
}
template <typename VertexType>
bool MeshDecimator<VertexType>::canCollapseMaterialEdge(uint32_t /*uSrc*/, uint32_t /*uDst*/)
{
return false;
}
//This function should really use some work. For a start we already have the
//faces normals for the input mesh yet we are computing them on the fly here.
template <typename VertexType>
bool MeshDecimator<VertexType>::collapseChangesFaceNormals(uint32_t uSrc, uint32_t uDst, float fThreshold)
{
bool faceFlipped = false;
std::vector<uint32_t>& triangles = trianglesUsingVertex[uSrc];
for(std::vector<uint32_t>::iterator triIter = triangles.begin(); triIter != triangles.end(); triIter++)
{
uint32_t tri = *triIter;
const uint32_t& v0Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3];
const uint32_t& v1Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3 + 1];
const uint32_t& v2Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3 + 2];
//Check if degenerate
if((v0Old == v1Old) || (v1Old == v2Old) || (v2Old == v0Old))
{
continue;
}
uint32_t v0New = v0Old;
uint32_t v1New = v1Old;
uint32_t v2New = v2Old;
if(v0New == uSrc)
v0New = uDst;
if(v1New == uSrc)
v1New = uDst;
if(v2New == uSrc)
v2New = uDst;
//Check if degenerate
if((v0New == v1New) || (v1New == v2New) || (v2New == v0New))
{
continue;
}
const Vector3DFloat& v0OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v0Old]].getPosition(); //Note: we need the vertex mapper here. These neighbouring vertices may have been moved.
const Vector3DFloat& v1OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1Old]].getPosition();
const Vector3DFloat& v2OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v2Old]].getPosition();
const Vector3DFloat& v0NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v0New]].getPosition();
const Vector3DFloat& v1NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1New]].getPosition();
const Vector3DFloat& v2NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v2New]].getPosition();
Vector3DFloat OldNormal = (v1OldPos - v0OldPos).cross(v2OldPos - v1OldPos);
Vector3DFloat NewNormal = (v1NewPos - v0NewPos).cross(v2NewPos - v1NewPos);
OldNormal.normalise();
NewNormal.normalise();
float dotProduct = OldNormal.dot(NewNormal);
//NOTE: I don't think we should be using the threshold here, we're just checking for a complete face flip
if(dotProduct < fThreshold)
{
//cout << " Face flipped!!" << endl;
faceFlipped = true;
/*vertexLocked[v0] = true;
vertexLocked[v1] = true;*/
break;
}
}
return faceFlipped;
}
// Returns true if every bit which is set in 'a' is also set in 'b'. The reverse does not need to be true.
template <typename VertexType>
bool MeshDecimator<VertexType>::isSubset(std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> a, std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> b)
{
bool result = true;
for(int ct = 0; ct < RFF_NO_OF_REGION_FACE_FLAGS; ct++)
{
if(a.test(ct))
{
if(b.test(ct) == false)
{
result = false;
break;
}
}
}
return result;
}
}

View File

@ -127,6 +127,11 @@ namespace PolyVox
////////////////////////////////////////////////////////////////////////////////
class Region;
////////////////////////////////////////////////////////////////////////////////
// SimpleVolume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> class SimpleVolume;
////////////////////////////////////////////////////////////////////////////////
// MarchingCubesSurfaceExtractor
////////////////////////////////////////////////////////////////////////////////

View File

@ -104,14 +104,9 @@ namespace PolyVox
inline VoxelType peekVoxel1px1py1pz(void) const;
private:
//Other current position information
VoxelType* mCurrentVoxel;
//Whether the current position is inside the volume
//FIXME - Replace these with flags
bool m_bIsCurrentPositionValidInX;
bool m_bIsCurrentPositionValidInY;
bool m_bIsCurrentPositionValidInZ;
};
#endif
@ -122,15 +117,19 @@ namespace PolyVox
/// Destructor
~RawVolume();
/// Gets the value used for voxels which are outside the volume
VoxelType getBorderValue(void) 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) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxel(const Vector3DInt32& v3dPos) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType(0)) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType(0)) 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
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
/// Sets the voxel at the position given by a 3D vector
@ -151,9 +150,6 @@ namespace PolyVox
//The block data
VoxelType* m_pData;
//The border value
VoxelType m_tBorderValue;
};
}

View File

@ -31,7 +31,7 @@ namespace PolyVox
RawVolume<VoxelType>::RawVolume(const Region& regValid)
:BaseVolume<VoxelType>(regValid)
{
setBorderValue(VoxelType());
this->setBorderValue(VoxelType());
//Create a volume of the right size.
initialise(regValid);
@ -74,14 +74,37 @@ namespace PolyVox
}
////////////////////////////////////////////////////////////////////////////////
/// 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
/// \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>::getBorderValue(void) const
VoxelType RawVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{
return m_tBorderValue;
assert(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()
];
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos) const
{
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
}
////////////////////////////////////////////////////////////////////////////////
@ -124,12 +147,59 @@ namespace PolyVox
}
////////////////////////////////////////////////////////////////////////////////
/// \param tBorder The value to use for voxels outside the volume.
/// \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>
void RawVolume<VoxelType>::setBorderValue(const VoxelType& tBorder)
VoxelType RawVolume<VoxelType>::getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const
{
m_tBorderValue = tBorder;
switch(eWrapMode)
{
case WrapModes::Clamp:
{
//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());
//Get the voxel value
return getVoxel(uXPos, uYPos, uZPos);
//No need to break as we've returned
}
case WrapModes::Border:
{
if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
{
return getVoxel(uXPos, uYPos, uZPos);
}
else
{
return tBorder;
}
//No need to break as we've returned
}
default:
{
//Should never happen
assert(false);
return VoxelType(0);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const
{
return getVoxelWithWrapping(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -21,12 +21,12 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#define BORDER_LOWX(val) (val > this->mVolume->getEnclosingRegion().getLowerCorner().getX())
#define BORDER_HIGHX(val) (val < this->mVolume->getEnclosingRegion().getUpperCorner().getX())
#define BORDER_LOWY(val) (val > this->mVolume->getEnclosingRegion().getLowerCorner().getY())
#define BORDER_HIGHY(val) (val < this->mVolume->getEnclosingRegion().getUpperCorner().getY())
#define BORDER_LOWZ(val) (val > this->mVolume->getEnclosingRegion().getLowerCorner().getZ())
#define BORDER_HIGHZ(val) (val < this->mVolume->getEnclosingRegion().getUpperCorner().getZ())
#define CAN_GO_NEG_X(val) (val > this->mVolume->getEnclosingRegion().getLowerCorner().getX())
#define CAN_GO_POS_X(val) (val < this->mVolume->getEnclosingRegion().getUpperCorner().getX())
#define CAN_GO_NEG_Y(val) (val > this->mVolume->getEnclosingRegion().getLowerCorner().getY())
#define CAN_GO_POS_Y(val) (val < this->mVolume->getEnclosingRegion().getUpperCorner().getY())
#define CAN_GO_NEG_Z(val) (val > this->mVolume->getEnclosingRegion().getLowerCorner().getZ())
#define CAN_GO_POS_Z(val) (val < this->mVolume->getEnclosingRegion().getUpperCorner().getZ())
namespace PolyVox
{
@ -34,9 +34,6 @@ namespace PolyVox
RawVolume<VoxelType>::Sampler::Sampler(RawVolume<VoxelType>* volume)
:BaseVolume<VoxelType>::template Sampler< RawVolume<VoxelType> >(volume)
,mCurrentVoxel(0)
,m_bIsCurrentPositionValidInX(false)
,m_bIsCurrentPositionValidInY(false)
,m_bIsCurrentPositionValidInZ(false)
{
}
@ -48,7 +45,14 @@ namespace PolyVox
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::getVoxel(void) const
{
return (m_bIsCurrentPositionValidInX && m_bIsCurrentPositionValidInY && m_bIsCurrentPositionValidInZ) ? *mCurrentVoxel : this->mVolume->getBorderValue();
if(this->isCurrentPositionValid())
{
return *mCurrentVoxel;
}
else
{
return getVoxelAt(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType>
@ -60,10 +64,12 @@ namespace PolyVox
template <typename VoxelType>
void RawVolume<VoxelType>::Sampler::setPosition(int32_t xPos, int32_t yPos, int32_t zPos)
{
this->mXPosInVolume = xPos;
this->mYPosInVolume = yPos;
this->mZPosInVolume = 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();
@ -74,17 +80,18 @@ namespace PolyVox
iLocalZPos * this->mVolume->getWidth() * this->mVolume->getHeight();
mCurrentVoxel = this->mVolume->m_pData + uVoxelIndex;
m_bIsCurrentPositionValidInX = this->mVolume->getEnclosingRegion().containsPointInX(xPos);
m_bIsCurrentPositionValidInY = this->mVolume->getEnclosingRegion().containsPointInY(yPos);
m_bIsCurrentPositionValidInZ = this->mVolume->getEnclosingRegion().containsPointInZ(zPos);
}
else
{
mCurrentVoxel = 0;
}
}
template <typename VoxelType>
bool RawVolume<VoxelType>::Sampler::setVoxel(VoxelType tValue)
{
//return m_bIsCurrentPositionValid ? *mCurrentVoxel : this->mVolume->getBorderValue();
if(m_bIsCurrentPositionValidInX && m_bIsCurrentPositionValidInY && m_bIsCurrentPositionValidInZ)
if(this->m_bIsCurrentPositionValidInX && this->m_bIsCurrentPositionValidInY && this->m_bIsCurrentPositionValidInZ)
{
*mCurrentVoxel = tValue;
return true;
@ -98,139 +105,211 @@ namespace PolyVox
template <typename VoxelType>
void RawVolume<VoxelType>::Sampler::movePositiveX(void)
{
this->mXPosInVolume++;
// 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;
m_bIsCurrentPositionValidInX = this->mVolume->getEnclosingRegion().containsPointInX(this->mXPosInVolume);
}
else
{
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType>
void RawVolume<VoxelType>::Sampler::movePositiveY(void)
{
this->mYPosInVolume++;
// 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();
m_bIsCurrentPositionValidInY = this->mVolume->getEnclosingRegion().containsPointInY(this->mYPosInVolume);
}
else
{
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType>
void RawVolume<VoxelType>::Sampler::movePositiveZ(void)
{
this->mZPosInVolume++;
// 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();
m_bIsCurrentPositionValidInZ = this->mVolume->getEnclosingRegion().containsPointInZ(this->mZPosInVolume);
}
else
{
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType>
void RawVolume<VoxelType>::Sampler::moveNegativeX(void)
{
this->mXPosInVolume--;
// 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;
m_bIsCurrentPositionValidInX = this->mVolume->getEnclosingRegion().containsPointInX(this->mXPosInVolume);
}
else
{
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType>
void RawVolume<VoxelType>::Sampler::moveNegativeY(void)
{
this->mYPosInVolume--;
// 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();
m_bIsCurrentPositionValidInY = this->mVolume->getEnclosingRegion().containsPointInY(this->mYPosInVolume);
}
else
{
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType>
void RawVolume<VoxelType>::Sampler::moveNegativeZ(void)
{
this->mZPosInVolume--;
// 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();
m_bIsCurrentPositionValidInZ = this->mVolume->getEnclosingRegion().containsPointInZ(this->mZPosInVolume);
}
else
{
setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx1ny1nz(void) const
{
if( BORDER_LOWX(this->mXPosInVolume) && BORDER_LOWY(this->mYPosInVolume) && BORDER_LOWZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWX(this->mXPosInVolume) && BORDER_LOWY(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - 1 - this->mVolume->getWidth());
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWX(this->mXPosInVolume) && BORDER_LOWY(this->mYPosInVolume) && BORDER_HIGHZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWX(this->mXPosInVolume) && BORDER_LOWZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWX(this->mXPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) )
{
return *(mCurrentVoxel - 1);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1nx0py1pz(void) const
{
if( BORDER_LOWX(this->mXPosInVolume) && BORDER_HIGHZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWX(this->mXPosInVolume) && BORDER_HIGHY(this->mYPosInVolume) && BORDER_LOWZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWX(this->mXPosInVolume) && BORDER_HIGHY(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - 1 + this->mVolume->getWidth());
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWX(this->mXPosInVolume) && BORDER_HIGHY(this->mYPosInVolume) && BORDER_HIGHZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
//////////////////////////////////////////////////////////////////////////
@ -238,87 +317,91 @@ namespace PolyVox
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1ny1nz(void) const
{
if( BORDER_LOWX(this->mYPosInVolume) && BORDER_LOWZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWY(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->getWidth());
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1ny1pz(void) const
{
if( BORDER_LOWY(this->mYPosInVolume) && BORDER_HIGHZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_LOWZ(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->getWidth() * this->mVolume->getHeight());
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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->getVoxelWithWrapping(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px0py1pz(void) const
{
if( BORDER_HIGHZ(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->getWidth() * this->mVolume->getHeight());
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1py1nz(void) const
{
if( BORDER_HIGHY(this->mYPosInVolume) && BORDER_LOWZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_HIGHY(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->getWidth());
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel0px1py1pz(void) const
{
if( BORDER_HIGHY(this->mYPosInVolume) && BORDER_HIGHZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
//////////////////////////////////////////////////////////////////////////
@ -326,97 +409,97 @@ namespace PolyVox
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px1ny1nz(void) const
{
if( BORDER_HIGHX(this->mXPosInVolume) && BORDER_LOWY(this->mYPosInVolume) && BORDER_LOWZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_HIGHX(this->mXPosInVolume) && BORDER_LOWY(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + 1 - this->mVolume->getWidth());
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(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( BORDER_HIGHX(this->mXPosInVolume) && BORDER_LOWY(this->mYPosInVolume) && BORDER_HIGHZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_HIGHX(this->mXPosInVolume) && BORDER_LOWZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_HIGHX(this->mXPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) )
{
return *(mCurrentVoxel + 1);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType RawVolume<VoxelType>::Sampler::peekVoxel1px0py1pz(void) const
{
if( BORDER_HIGHX(this->mXPosInVolume) && BORDER_HIGHZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_HIGHX(this->mXPosInVolume) && BORDER_HIGHY(this->mYPosInVolume) && BORDER_LOWZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(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( BORDER_HIGHX(this->mXPosInVolume) && BORDER_HIGHY(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + 1 + this->mVolume->getWidth());
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(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( BORDER_HIGHX(this->mXPosInVolume) && BORDER_HIGHY(this->mYPosInVolume) && BORDER_HIGHZ(this->mZPosInVolume) )
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->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
}
#undef BORDER_LOWX
#undef BORDER_HIGHX
#undef BORDER_LOWY
#undef BORDER_HIGHY
#undef BORDER_LOWZ
#undef BORDER_HIGHZ
#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

View File

@ -30,20 +30,24 @@ freely, subject to the following restrictions:
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>. The class also provides functions for modifying the regions in a variety of ways.
\Note The dimensions of a region can be measured either in voxels or in cells. See the manual for more information
about these definitions.
/** 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
@ -53,74 +57,355 @@ namespace PolyVox
{
public:
/// A Region with the lower corner set as low as possible and the upper corner set as high as possible.
static const Region MaxRegion;
/// A Region with the lower corner set as high as possible and the upper corner set as low as possible.
static const 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.
/// Equality Operator.
bool operator==(const Region& rhs) const;
///Inequality Operator.
/// Inequality Operator.
bool operator!=(const Region& rhs) const;
const Vector3DInt32& getLowerCorner(void) const;
const Vector3DInt32& getUpperCorner(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 width of the region measured in voxels
/// 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
/// Gets the height of the region measured in voxels.
int32_t getHeightInVoxels(void) const;
/// Gets the depth of the region measured in voxels
/// Gets the depth of the region measured in voxels.
int32_t getDepthInVoxels(void) const;
/// Gets the dimensions of the region measured in voxels
/// Gets the dimensions of the region measured in voxels.
Vector3DInt32 getDimensionsInVoxels(void) const;
/// Gets the width of the region measured in cells
/// Gets the width of the region measured in cells.
int32_t getWidthInCells(void) const;
/// Gets the height of the region measured in cells
/// Gets the height of the region measured in cells.
int32_t getHeightInCells(void) const;
/// Gets the depth of the region measured in cells
/// Gets the depth of the region measured in cells.
int32_t getDepthInCells(void) const;
/// Gets the dimensions of the region measured in cells
/// 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;
//FIXME - Don't like these. Make containsPoint take flags indicating which axes to check?
/// 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;
/// 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);
/// Deprecated and misleading
POLYVOX_DEPRECATED int32_t depth(void) const;
/// Deprecated and misleading
POLYVOX_DEPRECATED int32_t height(void) const;
void shift(const Vector3DInt32& amount);
void shiftLowerCorner(const Vector3DInt32& amount);
void shiftUpperCorner(const Vector3DInt32& amount);
//FIXME - Add dilate and erode functions?
/// Deprecated and misleading
POLYVOX_DEPRECATED Vector3DInt32 dimensions(void);
/// Deprecated and misleading
POLYVOX_DEPRECATED int32_t width(void) const;
/// 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:
Vector3DInt32 m_v3dLowerCorner;
Vector3DInt32 m_v3dUpperCorner;
//FIXME - This variable is unused, but without it the OpenGL example crashes in release mode
//when the volume size is 128^3 and the level of detail is 2. Very strange, but consistant.
//Presubablly some kind of alignment issue? It started after this class was changed to use
//int16's rather than int32's. To be investigated.
uint8_t dummy;
int32_t m_iLowerX;
int32_t m_iLowerY;
int32_t m_iLowerZ;
int32_t m_iUpperX;
int32_t m_iUpperY;
int32_t m_iUpperZ;
};
// 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 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::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();
}
}
#endif

View File

@ -1,46 +0,0 @@
/*******************************************************************************
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_SimpleInterface_H__
#define __PolyVox_SimpleInterface_H__
#include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h"
#include "PolyVoxCore/MaterialDensityPair.h"
#include "PolyVoxCore/SimpleVolume.h"
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
namespace PolyVox
{
//The PolyVox simple interface only exposes one voxel type and one volume type. But if you like you can
//adjust these typedefs and rebuild the library in order to modify which one volume and voxel is exposed.
typedef SimpleVolume<MaterialDensityPair88> Volume;
typedef SurfaceMesh<PositionMaterialNormal> Mesh;
/// \deprecated
POLYVOX_DEPRECATED void extractCubicMesh(Volume& volume, const Region& region, Mesh& resultMesh);
/// \deprecated
POLYVOX_DEPRECATED void extractSmoothMesh(Volume& volume, const Region& region, Mesh& resultMesh);
}
#endif //__PolyVox_SimpleInterface_H__

View File

@ -87,9 +87,8 @@ namespace PolyVox
Sampler(SimpleVolume<VoxelType>* volume);
~Sampler();
Sampler& operator=(const Sampler& rhs);
VoxelType getSubSampledVoxel(uint8_t uLevel) const;
/// \deprecated
POLYVOX_DEPRECATED VoxelType getSubSampledVoxel(uint8_t uLevel) const;
/// Get the value of the current voxel
inline VoxelType getVoxel(void) const;
@ -157,15 +156,19 @@ namespace PolyVox
/// Destructor
~SimpleVolume();
/// Gets the value used for voxels which are outside the volume
VoxelType getBorderValue(void) 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) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxel(const Vector3DInt32& v3dPos) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType(0)) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType(0)) 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
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
/// Sets the voxel at the position given by a 3D vector
@ -189,12 +192,6 @@ namespace PolyVox
//The block data
Block* m_pBlocks;
//We don't store an actual Block for the border, just the uncompressed data. This is partly because the border
//block does not have a position (so can't be passed to getUncompressedBlock()) and partly because there's a
//good chance we'll often hit it anyway. It's a chunk of homogenous data (rather than a single value) so that
//the VolumeIterator can do it's usual pointer arithmetic without needing to know it's gone outside the volume.
VoxelType* m_pUncompressedBorderData;
//The size of the volume in vlocks
Region m_regValidRegionInBlocks;

View File

@ -56,7 +56,6 @@ namespace PolyVox
SimpleVolume<VoxelType>::~SimpleVolume()
{
delete[] m_pBlocks;
delete[] m_pUncompressedBorderData;
}
////////////////////////////////////////////////////////////////////////////////
@ -73,14 +72,37 @@ namespace PolyVox
}
////////////////////////////////////////////////////////////////////////////////
/// 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
/// \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 SimpleVolume<VoxelType>::getBorderValue(void) const
VoxelType SimpleVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{
return *m_pUncompressedBorderData;
assert(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)));
const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
const int32_t blockY = uYPos >> m_uBlockSideLengthPower;
const int32_t blockZ = uZPos >> m_uBlockSideLengthPower;
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (blockX << m_uBlockSideLengthPower));
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower));
typename SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset);
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos) const
{
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
}
////////////////////////////////////////////////////////////////////////////////
@ -108,7 +130,7 @@ namespace PolyVox
}
else
{
return getBorderValue();
return this->getBorderValue();
}
}
@ -123,14 +145,59 @@ namespace PolyVox
}
////////////////////////////////////////////////////////////////////////////////
/// \param tBorder The value to use for voxels outside the volume.
/// \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>
void SimpleVolume<VoxelType>::setBorderValue(const VoxelType& tBorder)
VoxelType SimpleVolume<VoxelType>::getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const
{
/*Block<VoxelType>* pUncompressedBorderBlock = getUncompressedBlock(&m_pBorderBlock);
return pUncompressedBorderBlock->fill(tBorder);*/
std::fill(m_pUncompressedBorderData, m_pUncompressedBorderData + m_uNoOfVoxelsPerBlock, tBorder);
switch(eWrapMode)
{
case WrapModes::Clamp:
{
//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());
//Get the voxel value
return getVoxel(uXPos, uYPos, uZPos);
//No need to break as we've returned
}
case WrapModes::Border:
{
if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
{
return getVoxel(uXPos, uYPos, uZPos);
}
else
{
return tBorder;
}
//No need to break as we've returned
}
default:
{
//Should never happen
assert(false);
return VoxelType(0);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const
{
return getVoxelWithWrapping(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
}
////////////////////////////////////////////////////////////////////////////////
@ -197,18 +264,19 @@ namespace PolyVox
throw std::invalid_argument("Block side length must be a power of two.");
}
m_uBlockSideLength = uBlockSideLength;
m_uNoOfVoxelsPerBlock = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength;
m_pUncompressedBorderData = 0;
this->m_regValidRegion = regValidRegion;
m_regValidRegionInBlocks.setLowerCorner(this->m_regValidRegion.getLowerCorner() / static_cast<int32_t>(uBlockSideLength));
m_regValidRegionInBlocks.setUpperCorner(this->m_regValidRegion.getUpperCorner() / static_cast<int32_t>(uBlockSideLength));
//Compute the block side length
m_uBlockSideLength = uBlockSideLength;
m_uBlockSideLengthPower = logBase2(m_uBlockSideLength);
m_uNoOfVoxelsPerBlock = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength;
m_regValidRegionInBlocks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setLowerY(this->m_regValidRegion.getLowerY() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setLowerZ(this->m_regValidRegion.getLowerZ() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setUpperX(this->m_regValidRegion.getUpperX() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uBlockSideLengthPower);
m_regValidRegionInBlocks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uBlockSideLengthPower);
//Compute the size of the volume in blocks (and note +1 at the end)
m_uWidthInBlocks = m_regValidRegionInBlocks.getUpperCorner().getX() - m_regValidRegionInBlocks.getLowerCorner().getX() + 1;
@ -223,10 +291,6 @@ namespace PolyVox
m_pBlocks[i].initialise(m_uBlockSideLength);
}
//Create the border block
m_pUncompressedBorderData = new VoxelType[m_uNoOfVoxelsPerBlock];
std::fill(m_pUncompressedBorderData, m_pUncompressedBorderData + m_uNoOfVoxelsPerBlock, VoxelType());
//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());
@ -242,6 +306,10 @@ namespace PolyVox
uBlockY -= m_regValidRegionInBlocks.getLowerCorner().getY();
uBlockZ -= m_regValidRegionInBlocks.getLowerCorner().getZ();
assert(uBlockX >= 0);
assert(uBlockY >= 0);
assert(uBlockZ >= 0);
//Compute the block index
uint32_t uBlockIndex =
uBlockX +
@ -264,8 +332,8 @@ namespace PolyVox
uint32_t uSizeOfBlockInBytes = m_uNoOfVoxelsPerBlock * sizeof(VoxelType);
//Memory used by the blocks ( + 1 is for border)
uSizeInBytes += uSizeOfBlockInBytes * (m_uNoOfBlocksInVolume + 1);
//Memory used by the blocks
uSizeInBytes += uSizeOfBlockInBytes * (m_uNoOfBlocksInVolume);
return uSizeInBytes;
}

View File

@ -21,10 +21,12 @@ freely, subject to the following restrictions:
distribution.
*******************************************************************************/
#define BORDER_LOW(x) ((( x >> this->mVolume->m_uBlockSideLengthPower) << this->mVolume->m_uBlockSideLengthPower) != x)
#define BORDER_HIGH(x) ((( (x+1) >> this->mVolume->m_uBlockSideLengthPower) << this->mVolume->m_uBlockSideLengthPower) != (x+1))
//#define BORDER_LOW(x) (( x % this->mVolume->m_uBlockSideLength) != 0)
//#define BORDER_HIGH(x) (( x % this->mVolume->m_uBlockSideLength) != this->mVolume->m_uBlockSideLength - 1)
#define CAN_GO_NEG_X(val) ((val > this->mVolume->getEnclosingRegion().getLowerCorner().getX()) && (val % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_POS_X(val) ((val < this->mVolume->getEnclosingRegion().getUpperCorner().getX()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_NEG_Y(val) ((val > this->mVolume->getEnclosingRegion().getLowerCorner().getY()) && (val % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_POS_Y(val) ((val < this->mVolume->getEnclosingRegion().getUpperCorner().getY()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_NEG_Z(val) ((val > this->mVolume->getEnclosingRegion().getLowerCorner().getZ()) && (val % this->mVolume->m_uBlockSideLength != 0))
#define CAN_GO_POS_Z(val) ((val < this->mVolume->getEnclosingRegion().getUpperCorner().getZ()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0))
namespace PolyVox
{
@ -42,21 +44,6 @@ namespace PolyVox
{
}
template <typename VoxelType>
typename SimpleVolume<VoxelType>::Sampler& SimpleVolume<VoxelType>::Sampler::operator=(const typename SimpleVolume<VoxelType>::Sampler& rhs)
{
if(this == &rhs)
{
return *this;
}
this->mVolume = rhs.mVolume;
this->mXPosInVolume = rhs.mXPosInVolume;
this->mYPosInVolume = rhs.mYPosInVolume;
this->mZPosInVolume = rhs.mZPosInVolume;
mCurrentVoxel = rhs.mCurrentVoxel;
return *this;
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::getSubSampledVoxel(uint8_t uLevel) const
{
@ -100,9 +87,16 @@ namespace PolyVox
*/
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::getVoxel(void) const
{
if(this->isCurrentPositionValid())
{
return *mCurrentVoxel;
}
else
{
return getVoxelAt(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
/**
* \param v3dNewPos The position to set to
@ -121,10 +115,12 @@ namespace PolyVox
template <typename VoxelType>
void SimpleVolume<VoxelType>::Sampler::setPosition(int32_t xPos, int32_t yPos, int32_t zPos)
{
this->mXPosInVolume = xPos;
this->mYPosInVolume = yPos;
this->mZPosInVolume = zPos;
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::setPosition(xPos, yPos, zPos);
// Then we update the voxel pointer
if(this->isCurrentPositionValid())
{
const int32_t uXBlock = this->mXPosInVolume >> this->mVolume->m_uBlockSideLengthPower;
const int32_t uYBlock = this->mYPosInVolume >> this->mVolume->m_uBlockSideLengthPower;
const int32_t uZBlock = this->mZPosInVolume >> this->mVolume->m_uBlockSideLengthPower;
@ -137,15 +133,13 @@ namespace PolyVox
uYPosInBlock * this->mVolume->m_uBlockSideLength +
uZPosInBlock * this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength;
if(this->mVolume->m_regValidRegionInBlocks.containsPoint(Vector3DInt32(uXBlock, uYBlock, uZBlock)))
{
Block* pUncompressedCurrentBlock = this->mVolume->getUncompressedBlock(uXBlock, uYBlock, uZBlock);
mCurrentVoxel = pUncompressedCurrentBlock->m_tUncompressedData + uVoxelIndexInBlock;
}
else
{
mCurrentVoxel = this->mVolume->m_pUncompressedBorderData + uVoxelIndexInBlock;
mCurrentVoxel = 0;
}
}
@ -161,10 +155,7 @@ namespace PolyVox
template <typename VoxelType>
bool SimpleVolume<VoxelType>::Sampler::setVoxel(VoxelType tValue)
{
VoxelType* pBorderDataEndPlusOne = this->mVolume->m_pUncompressedBorderData + this->mVolume->m_uNoOfVoxelsPerBlock;
//Make sure we're not trying to write to the border data
if((mCurrentVoxel < this->mVolume->m_pUncompressedBorderData) || (mCurrentVoxel >= pBorderDataEndPlusOne))
if(this->m_bIsCurrentPositionValidInX && this->m_bIsCurrentPositionValidInY && this->m_bIsCurrentPositionValidInZ)
{
*mCurrentVoxel = tValue;
return true;
@ -178,8 +169,14 @@ namespace PolyVox
template <typename VoxelType>
void SimpleVolume<VoxelType>::Sampler::movePositiveX(void)
{
//Note the *pre* increament here
if((++this->mXPosInVolume) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::movePositiveX();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
++mCurrentVoxel;
@ -194,8 +191,14 @@ namespace PolyVox
template <typename VoxelType>
void SimpleVolume<VoxelType>::Sampler::movePositiveY(void)
{
//Note the *pre* increament here
if((++this->mYPosInVolume) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::movePositiveY();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
mCurrentVoxel += this->mVolume->m_uBlockSideLength;
@ -210,8 +213,14 @@ namespace PolyVox
template <typename VoxelType>
void SimpleVolume<VoxelType>::Sampler::movePositiveZ(void)
{
//Note the *pre* increament here
if((++this->mZPosInVolume) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::movePositiveZ();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
mCurrentVoxel += this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength;
@ -226,8 +235,14 @@ namespace PolyVox
template <typename VoxelType>
void SimpleVolume<VoxelType>::Sampler::moveNegativeX(void)
{
//Note the *post* decreament here
if((this->mXPosInVolume--) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::moveNegativeX();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
--mCurrentVoxel;
@ -242,8 +257,14 @@ namespace PolyVox
template <typename VoxelType>
void SimpleVolume<VoxelType>::Sampler::moveNegativeY(void)
{
//Note the *post* decreament here
if((this->mYPosInVolume--) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::moveNegativeY();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
mCurrentVoxel -= this->mVolume->m_uBlockSideLength;
@ -258,8 +279,14 @@ namespace PolyVox
template <typename VoxelType>
void SimpleVolume<VoxelType>::Sampler::moveNegativeZ(void)
{
//Note the *post* decreament here
if((this->mZPosInVolume--) % this->mVolume->m_uBlockSideLength != 0)
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::moveNegativeZ();
// Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0))
{
//No need to compute new block.
mCurrentVoxel -= this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength;
@ -274,91 +301,91 @@ namespace PolyVox
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1ny1nz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
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_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1ny0pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1ny1pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
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_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx0py1nz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx0py0pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) )
{
return *(mCurrentVoxel - 1);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx0py1pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1py1nz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
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_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1py0pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1py1pz(void) const
{
if( BORDER_LOW(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
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_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
//////////////////////////////////////////////////////////////////////////
@ -366,87 +393,91 @@ namespace PolyVox
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1ny1nz(void) const
{
if( BORDER_LOW(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1ny0pz(void) const
{
if( BORDER_LOW(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1ny1pz(void) const
{
if( BORDER_LOW(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px0py1nz(void) const
{
if( BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px0py0pz(void) const
{
if((this->isCurrentPositionValid()))
{
return *mCurrentVoxel;
}
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px0py1pz(void) const
{
if( BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1py1nz(void) const
{
if( BORDER_HIGH(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1py0pz(void) const
{
if( BORDER_HIGH(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1py1pz(void) const
{
if( BORDER_HIGH(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
//////////////////////////////////////////////////////////////////////////
@ -454,93 +485,97 @@ namespace PolyVox
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1ny1nz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
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_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1ny0pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1ny1pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_LOW(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
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_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px0py1nz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px0py0pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) )
{
return *(mCurrentVoxel + 1);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px0py1pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) )
{
return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1py1nz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) && BORDER_LOW(this->mZPosInVolume) )
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_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1py0pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) )
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) )
{
return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType>
VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1py1pz(void) const
{
if( BORDER_HIGH(this->mXPosInVolume) && BORDER_HIGH(this->mYPosInVolume) && BORDER_HIGH(this->mZPosInVolume) )
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_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength);
}
return this->mVolume->getVoxelAt(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1);
return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder);
}
}
#undef BORDER_LOW
#undef BORDER_HIGH
#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

View File

@ -36,192 +36,193 @@ freely, subject to the following restrictions:
namespace PolyVox
{
/**
Represents a vector in space.
This Vector class is templated on both size and data type. It is designed to be
generic but so far had only been tested with vectors of size 2 and 3. Also note
that some of the operations do not make sense with integer types, for example it
does not make conceptual sense to try and normalise an integer Vector.
The elements of the Vector are accessed via the overloaded () operator which takes
an index indicating the element to fetch. They are set using the set() function which
takes an index indicating the element to set and a new value for that element. For
convienience, the functions getX(), setX(), getY(), setY(), getZ(), setZ(), getw() and setW()
do the same thing for the first 4 elements of the Vector.
A variety of overloaded operators are also provided for comparison and arithmetic
operations. For most of these arithmetic operators only the unary versions are
documented below - however often binary versions are also generated by std::operators.
Lastly, note that for convienience a set of typedefs are included for 2 and 3 dimensional
vectors with type float, double, int32_t, and uint32_t. They are used as follows:
\code
Vector2DInt4 test(1,2); //Declares a 2 dimensional Vector of type int4.
\endcode
* 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
/// Constructor
Vector(void);
///Constructor.
/// Constructor.
Vector(StorageType tFillValue);
///Constructor.
/// Constructor.
Vector(StorageType x, StorageType y);
///Constructor.
/// Constructor.
Vector(StorageType x, StorageType y, StorageType z);
///Constructor.
/// Constructor.
Vector(StorageType x, StorageType y, StorageType z, StorageType w);
///Copy Constructor.
/// Copy Constructor.
Vector(const Vector<Size,StorageType,OperationType>& vector);
///Copy Constructor which performs casting.
/// Copy Constructor which performs casting.
template <typename CastType> explicit Vector(const Vector<Size,CastType>& vector);
///Destructor.
/// Destructor.
~Vector(void);
///Assignment Operator.
/// Assignment Operator.
Vector<Size,StorageType,OperationType>& operator=(const Vector<Size,StorageType,OperationType>& rhs);
///Equality Operator.
/// Equality Operator.
bool operator==(const Vector<Size,StorageType,OperationType>& rhs) const;
///Inequality Operator.
/// Inequality Operator.
bool operator!=(const Vector<Size,StorageType,OperationType>& rhs) const;
///Comparison Operator.
bool operator<(const Vector<Size,StorageType,OperationType>& rhs) const;
///Addition and Assignment Operator.
/// 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.
/// Subtraction and Assignment Operator.
Vector<Size,StorageType,OperationType>& operator-=(const Vector<Size,StorageType,OperationType> &rhs);
///Multiplication and Assignment Operator.
/// Multiplication and Assignment Operator.
Vector<Size,StorageType,OperationType>& operator*=(const Vector<Size,StorageType,OperationType> &rhs);
///Division and Assignment Operator.
/// Division and Assignment Operator.
Vector<Size,StorageType,OperationType>& operator/=(const Vector<Size,StorageType,OperationType> &rhs);
///Multiplication and Assignment Operator.
/// Multiplication and Assignment Operator.
Vector<Size,StorageType,OperationType>& operator*=(const StorageType& rhs);
///Division and Assignment Operator.
/// Division and Assignment Operator.
Vector<Size,StorageType,OperationType>& operator/=(const StorageType& rhs);
///Element Access.
/// Element Access.
StorageType getElement(uint32_t index) const;
///Get the x component of the vector.
/// Get the x component of the vector.
StorageType getX(void) const;
///Get the y component of the vector.
/// Get the y component of the vector.
StorageType getY(void) const;
///Get the z component of the vector.
/// Get the z component of the vector.
StorageType getZ(void) const;
///Get the w component of the vector.
/// Get the w component of the vector.
StorageType getW(void) const;
///Element Access.
/// Element Access.
void setElement(uint32_t index, StorageType tValue);
///Element Access.
/// Element Access.
void setElements(StorageType x, StorageType y);
///Element Access.
/// Element Access.
void setElements(StorageType x, StorageType y, StorageType z);
///Element Access.
/// Element Access.
void setElements(StorageType x, StorageType y, StorageType z, StorageType w);
///Set the x component of the vector.
/// Set the x component of the vector.
void setX(StorageType tX);
///Set the y component of the vector.
/// Set the y component of the vector.
void setY(StorageType tY);
///Set the z component of the vector.
/// Set the z component of the vector.
void setZ(StorageType tZ);
///Set the w component of the vector.
/// Set the w component of the vector.
void setW(StorageType tW);
///Get the length of the vector.
double length(void) const;
///Get the squared length of the vector.
double lengthSquared(void) const;
///Find the angle between this vector and that which is passed as a parameter.
double angleTo(const Vector<Size,StorageType,OperationType>& vector) const;
///Find the cross product between this vector and the vector passed as a parameter.
/// 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.
StorageType dot(const Vector<Size,StorageType,OperationType>& rhs) const;
///Normalise the vector.
/// 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
// Values for the vector
StorageType m_tElements[Size];
};
//Non-member overloaded operators.
///Addition operator.
// 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.
/// 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.
/// 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.
/// 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.
/// 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.
/// 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.
/// 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.
/// A 2D Vector of floats.
typedef Vector<2,float,float> Vector2DFloat;
///A 2D Vector of doubles.
/// A 2D Vector of doubles.
typedef Vector<2,double,double> Vector2DDouble;
///A 2D Vector of signed 8-bit values.
/// A 2D Vector of signed 8-bit values.
typedef Vector<2,int8_t,int32_t> Vector2DInt8;
///A 2D Vector of unsigned 8-bit values.
/// A 2D Vector of unsigned 8-bit values.
typedef Vector<2,uint8_t,int32_t> Vector2DUint8;
///A 2D Vector of signed 16-bit values.
/// A 2D Vector of signed 16-bit values.
typedef Vector<2,int16_t,int32_t> Vector2DInt16;
///A 2D Vector of unsigned 16-bit values.
/// A 2D Vector of unsigned 16-bit values.
typedef Vector<2,uint16_t,int32_t> Vector2DUint16;
///A 2D Vector of signed 32-bit values.
/// A 2D Vector of signed 32-bit values.
typedef Vector<2,int32_t,int32_t> Vector2DInt32;
///A 2D Vector of unsigned 32-bit values.
/// A 2D Vector of unsigned 32-bit values.
typedef Vector<2,uint32_t,int32_t> Vector2DUint32;
///A 3D Vector of floats.
/// A 3D Vector of floats.
typedef Vector<3,float,float> Vector3DFloat;
///A 3D Vector of doubles.
/// A 3D Vector of doubles.
typedef Vector<3,double,double> Vector3DDouble;
///A 3D Vector of signed 8-bit values.
/// A 3D Vector of signed 8-bit values.
typedef Vector<3,int8_t,int32_t> Vector3DInt8;
///A 3D Vector of unsigned 8-bit values.
/// A 3D Vector of unsigned 8-bit values.
typedef Vector<3,uint8_t,int32_t> Vector3DUint8;
///A 3D Vector of signed 16-bit values.
/// A 3D Vector of signed 16-bit values.
typedef Vector<3,int16_t,int32_t> Vector3DInt16;
///A 3D Vector of unsigned 16-bit values.
/// A 3D Vector of unsigned 16-bit values.
typedef Vector<3,uint16_t,int32_t> Vector3DUint16;
///A 3D Vector of signed 32-bit values.
/// A 3D Vector of signed 32-bit values.
typedef Vector<3,int32_t,int32_t> Vector3DInt32;
///A 3D Vector of unsigned 32-bit values.
/// A 3D Vector of unsigned 32-bit values.
typedef Vector<3,uint32_t,int32_t> Vector3DUint32;
///A 4D Vector of floats.
/// A 4D Vector of floats.
typedef Vector<4,float,float> Vector4DFloat;
///A 4D Vector of doubles.
/// A 4D Vector of doubles.
typedef Vector<4,double,double> Vector4DDouble;
///A 4D Vector of signed 8-bit values.
/// A 4D Vector of signed 8-bit values.
typedef Vector<4,int8_t,int32_t> Vector4DInt8;
///A 4D Vector of unsigned 8-bit values.
/// A 4D Vector of unsigned 8-bit values.
typedef Vector<4,uint8_t,int32_t> Vector4DUint8;
///A 4D Vector of signed 16-bit values.
/// A 4D Vector of signed 16-bit values.
typedef Vector<4,int16_t,int32_t> Vector4DInt16;
///A 4D Vector of unsigned 16-bit values.
/// A 4D Vector of unsigned 16-bit values.
typedef Vector<4,uint16_t,int32_t> Vector4DUint16;
///A 4D Vector of signed 32-bit values.
/// A 4D Vector of signed 32-bit values.
typedef Vector<4,int32_t,int32_t> Vector4DInt32;
///A 4D Vector of unsigned 32-bit values.
/// A 4D Vector of unsigned 32-bit values.
typedef Vector<4,uint32_t,int32_t> Vector4DUint32;

View File

@ -25,7 +25,7 @@ namespace PolyVox
{
//-------------------------- Constructors, etc ---------------------------------
/**
Creates a Vector object but does not initialise it.
* Creates a Vector object but does not initialise it.
*/
template <uint32_t Size, typename StorageType, typename OperationType>
Vector<Size, StorageType, OperationType>::Vector(void)
@ -33,8 +33,8 @@ namespace PolyVox
}
/**
Creates a Vector object and initialises it with given values.
\param x x component to set.
* 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)
@ -46,9 +46,9 @@ namespace PolyVox
}
/**
Creates a Vector object and initialises it with given values.
\param x x component to set.
\param y y component to set.
* 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)
@ -62,10 +62,10 @@ namespace PolyVox
}
/**
Creates a Vector3D object and initialises it with given values.
\param x x component to set.
\param y y component to set.
\param z z component to set.
* 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)
@ -81,11 +81,11 @@ namespace PolyVox
}
/**
Creates a Vector3D object and initialises it with given values.
\param x x component to set.
\param y y component to set.
\param z z component to set.
\param w w component to set.
* 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)
@ -101,8 +101,8 @@ namespace PolyVox
}
/**
Copy constructor builds object based on object passed as parameter.
\param vector A reference to the Vector to be copied.
* 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)
@ -111,13 +111,13 @@ namespace PolyVox
}
/**
This copy constructor allows casting between vectors with different data types.
It is now possible to use code such as:
Vector3DDouble v3dDouble(1.0,2.0,3.0);
Vector3DFloat v3dFloat = static_cast<Vector3DFloat>(v3dDouble); //Casting
\param vector A reference to the Vector to be copied.
* 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>
@ -130,7 +130,7 @@ namespace PolyVox
}
/**
Destroys the Vector.
* Destroys the Vector.
*/
template <uint32_t Size, typename StorageType, typename OperationType>
Vector<Size, StorageType, OperationType>::~Vector(void)
@ -146,9 +146,9 @@ namespace PolyVox
}
/**
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.
* 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)
@ -162,10 +162,10 @@ namespace PolyVox
}
/**
Checks whether two Vectors are equal.
\param rhs The Vector to compare to.
\return true if the Vectors match.
\see operator!=
* 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
@ -183,10 +183,10 @@ namespace PolyVox
}
/**
Checks whether two Vectors are not equal.
\param rhs The Vector to compare to.
\return true if the Vectors do not match.
\see operator==
* 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
@ -195,11 +195,13 @@ namespace PolyVox
}
/**
Checks whether this vector is less than the parameter. The metric is
meaningless but it allows Vectors to me used as key in sdt::map, etc.
\param rhs The Vector to compare to.
\return true if this is less than the parameter
\see operator!=
* 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
@ -215,9 +217,9 @@ namespace PolyVox
}
/**
Addition operator adds corresponding elements of the two Vectors.
\param rhs Vector to add
\return The resulting Vector.
* 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)
@ -230,9 +232,9 @@ namespace PolyVox
}
/**
Subtraction operator subtracts corresponding elements of one Vector from the other.
\param rhs Vector to subtract
\return The resulting Vector.
* 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)
@ -245,9 +247,9 @@ namespace PolyVox
}
/**
Multiplication operator multiplies corresponding elements of the two Vectors.
\param rhs Vector to multiply by
\return The resulting Vector.
* 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)
@ -260,9 +262,9 @@ namespace PolyVox
}
/**
Division operator divides corresponding elements of one Vector by the other.
\param rhs Vector to divide by
\return The resulting Vector.
* 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)
@ -275,9 +277,9 @@ namespace PolyVox
}
/**
Multiplication operator multiplies each element of the Vector by a number.
\param rhs the number the Vector is multiplied by.
\return The resulting Vector.
* 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)
@ -290,9 +292,9 @@ namespace PolyVox
}
/**
Division operator divides each element of the Vector by a number.
\param rhs the number the Vector is divided by.
\return The resulting Vector.
* 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)
@ -305,10 +307,10 @@ namespace PolyVox
}
/**
Addition operator adds corresponding elements of the two Vectors.
\param lhs Vector to add to.
\param rhs Vector to add.
\return The resulting Vector.
* 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)
@ -319,10 +321,10 @@ namespace PolyVox
}
/**
Subtraction operator subtracts corresponding elements of one Vector from the other.
\param lhs Vector to subtract from.
\param rhs Vector to subtract.
\return The resulting Vector.
* 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)
@ -333,10 +335,10 @@ namespace PolyVox
}
/**
Multiplication operator mulitplies corresponding elements of the two Vectors.
\param lhs Vector to multiply.
\param rhs Vector to multiply by.
\return The resulting Vector.
* 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)
@ -347,10 +349,10 @@ namespace PolyVox
}
/**
Division operator divides corresponding elements of one Vector by the other.
\param lhs Vector to divide.
\param rhs Vector to divide by.
\return The resulting Vector.
* 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)
@ -361,10 +363,10 @@ namespace PolyVox
}
/**
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.
* 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)
@ -375,10 +377,10 @@ namespace PolyVox
}
/**
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.
* 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)
@ -389,10 +391,10 @@ namespace PolyVox
}
/**
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.
* 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)
@ -411,9 +413,9 @@ namespace PolyVox
}
/**
Returns the element at the given position.
\param index The index of the element to return.
\return The element.
* 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
@ -423,7 +425,7 @@ namespace PolyVox
}
/**
\return A const reference to the X component of a 1, 2, 3, or 4 dimensional Vector.
* \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
@ -432,7 +434,7 @@ namespace PolyVox
}
/**
\return A const reference to the Y component of a 2, 3, or 4 dimensional Vector.
* \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
@ -441,7 +443,7 @@ namespace PolyVox
}
/**
\return A const reference to the Z component of a 3 or 4 dimensional Vector.
* \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
@ -454,7 +456,7 @@ namespace PolyVox
}
/**
\return A const reference to the W component of a 4 dimensional Vector.
* \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
@ -467,8 +469,8 @@ namespace PolyVox
}
/**
\param index The index of the element to set.
\param tValue The new value for the element.
* \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)
@ -478,9 +480,9 @@ namespace PolyVox
}
/**
Sets several elements of a vector at once.
\param x x component to set.
\param y y component to set.
* 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)
@ -491,10 +493,10 @@ namespace PolyVox
}
/**
Sets several elements of a vector at once.
\param x x component to set.
\param y y component to set.
\param z z component to set.
* 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)
@ -508,11 +510,11 @@ namespace PolyVox
}
/**
Sets several elements of a vector at once.
\param x x component to set.
\param y y component to set.
\param z z component to set.
\param w w component to set.
* 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)
@ -527,7 +529,7 @@ namespace PolyVox
}
/**
\param tX The new value for the X component of a 1, 2, 3, or 4 dimensional Vector.
* \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)
@ -536,7 +538,7 @@ namespace PolyVox
}
/**
\param tY The new value for the Y component of a 2, 3, or 4 dimensional Vector.
* \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)
@ -545,7 +547,7 @@ namespace PolyVox
}
/**
\param tZ The new value for the Z component of a 3 or 4 dimensional Vector.
* \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)
@ -557,7 +559,7 @@ namespace PolyVox
}
/**
\param tW The new value for the W component of a 4 dimensional Vector.
* \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)
@ -569,55 +571,55 @@ namespace PolyVox
}
/**
\note This function does not make much sense on integer Vectors.
\return Length of the Vector.
* \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 double Vector<Size, StorageType, OperationType>::length(void) const
inline float Vector<Size, StorageType, OperationType>::length(void) const
{
return sqrt(lengthSquared());
return sqrt(static_cast<float>(lengthSquared()));
}
/**
\return Squared length of the Vector.
* \return The squared length of the Vector.
*/
template <uint32_t Size, typename StorageType, typename OperationType>
inline double Vector<Size, StorageType, OperationType>::lengthSquared(void) const
inline OperationType Vector<Size, StorageType, OperationType>::lengthSquared(void) const
{
double result = 0.0f;
OperationType tLengthSquared = static_cast<OperationType>(0);
for(uint32_t ct = 0; ct < Size; ++ct)
{
result += m_tElements[ct] * m_tElements[ct];
tLengthSquared += static_cast<OperationType>(m_tElements[ct]) * static_cast<OperationType>(m_tElements[ct]);
}
return result;
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 does not make much sense on integer Vectors.
\param vector The Vector to find the angle to.
\return The angle between them in radians.
* 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 double Vector<Size, StorageType, OperationType>::angleTo(const Vector<Size, StorageType, OperationType>& vector) const
inline float Vector<Size, StorageType, OperationType>::angleTo(const Vector<Size, StorageType, OperationType>& vector) const
{
return acos(dot(vector) / (vector.length() * this->length()));
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()
* 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
@ -629,40 +631,39 @@ namespace PolyVox
}
/**
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()
* 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 StorageType Vector<Size, StorageType, OperationType>::dot(const Vector<Size, StorageType, OperationType>& rhs) const
inline OperationType Vector<Size, StorageType, OperationType>::dot(const Vector<Size, StorageType, OperationType>& rhs) const
{
StorageType dotProduct = static_cast<StorageType>(0);
OperationType dotProduct = static_cast<OperationType>(0);
for(uint32_t ct = 0; ct < Size; ++ct)
{
dotProduct += m_tElements[ct] * rhs.m_tElements[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.
\note This function does not make much sense on integer Vectors.
* 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)
{
StorageType tLength = static_cast<StorageType>(this->length());
//FIXME - throw div by zero exception?
if(tLength < 0.0001f)
{
return;
}
float fLength = this->length();
for(uint32_t ct = 0; ct < Size; ++ct)
{
m_tElements[ct] /= tLength;
// Standard float rules apply for divide-by-zero
m_tElements[ct] /= fLength;
assert(m_tElements[ct] == m_tElements[ct]); //Will assert if NAN
}
}
}//namespace PolyVox

View File

@ -1,181 +0,0 @@
/*******************************************************************************
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/MeshDecimator.h"
#include "PolyVoxCore/SurfaceMesh.h"
using namespace std;
namespace PolyVox
{
template<>
POLYVOX_API void MeshDecimator<PositionMaterial>::fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecVertexMetadata)
{
vecVertexMetadata.clear();
vecVertexMetadata.resize(m_pOutputMesh->m_vecVertices.size());
//Initialise the metadata
for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
{
vecVertexMetadata[ct].normal.setElements(0,0,0);
vecVertexMetadata[ct].isOnMaterialEdge = false;
vecVertexMetadata[ct].isOnRegionFace.reset();
}
//Identify duplicate vertices, as they lie on the material edge. To do this we convert into integers and sort
//(first on z, then y, then x). They should be mostly in order as this is the order they come out of the
//CubicSurfaceExtractor in. Duplicates are now neighbours in the resulting list so just scan through for pairs.
std::vector<IntVertex> intVertices;
intVertices.reserve(m_pOutputMesh->m_vecVertices.size());
for(uint32_t ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++)
{
const Vector3DFloat& floatPos = m_pOutputMesh->m_vecVertices[ct].position;
IntVertex intVertex(static_cast<uint32_t>(floatPos.getX()), static_cast<uint32_t>(floatPos.getY()), static_cast<uint32_t>(floatPos.getZ()), ct);
intVertices.push_back(intVertex);
}
//Do the sorting so that duplicate become neighbours
sort(intVertices.begin(), intVertices.end());
//Find neighbours which are duplicates.
for(uint32_t ct = 0; ct < intVertices.size() - 1; ct++)
{
const IntVertex& v0 = intVertices[ct+0];
const IntVertex& v1 = intVertices[ct+1];
if((v0.x == v1.x) && (v0.y == v1.y) && (v0.z == v1.z))
{
vecVertexMetadata[v0.index].isOnMaterialEdge = true;
vecVertexMetadata[v1.index].isOnMaterialEdge = true;
}
}
//Compute an approcimation to the normal, used when deciding if an edge can collapse.
for(uint32_t ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++)
{
Vector3DFloat sumOfNormals(0.0f,0.0f,0.0f);
for(vector<uint32_t>::iterator iter = trianglesUsingVertex[ct].begin(); iter != trianglesUsingVertex[ct].end(); iter++)
{
sumOfNormals += m_vecTriangles[*iter].normal;
}
vecVertexMetadata[ct].normal = sumOfNormals;
vecVertexMetadata[ct].normal.normalise();
}
//Identify those vertices on the edge of a region. Care will need to be taken when moving them.
for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
{
Region regTransformed = m_pOutputMesh->m_Region;
regTransformed.shift(regTransformed.getLowerCorner() * static_cast<int32_t>(-1));
//Plus and minus X
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() < regTransformed.getLowerCorner().getX() + 0.001f);
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() > regTransformed.getUpperCorner().getX() - 0.001f);
//Plus and minus Y
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() < regTransformed.getLowerCorner().getY() + 0.001f);
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() > regTransformed.getUpperCorner().getY() - 0.001f);
//Plus and minus Z
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() < regTransformed.getLowerCorner().getZ() + 0.001f);
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() > regTransformed.getUpperCorner().getZ() - 0.001f);
}
}
template<>
POLYVOX_API void MeshDecimator<PositionMaterialNormal>::fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecVertexMetadata)
{
vecVertexMetadata.clear();
vecVertexMetadata.resize(m_pOutputMesh->m_vecVertices.size());
//Initialise the metadata
for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
{
vecVertexMetadata[ct].isOnRegionFace.reset();
vecVertexMetadata[ct].isOnMaterialEdge = false;
vecVertexMetadata[ct].normal = m_pOutputMesh->m_vecVertices[ct].normal;
}
//Identify those vertices on the edge of a region. Care will need to be taken when moving them.
for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
{
Region regTransformed = m_pOutputMesh->m_Region;
regTransformed.shift(regTransformed.getLowerCorner() * static_cast<int32_t>(-1));
//Plus and minus X
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() < regTransformed.getLowerCorner().getX() + 0.001f);
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() > regTransformed.getUpperCorner().getX() - 0.001f);
//Plus and minus Y
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() < regTransformed.getLowerCorner().getY() + 0.001f);
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() > regTransformed.getUpperCorner().getY() - 0.001f);
//Plus and minus Z
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() < regTransformed.getLowerCorner().getZ() + 0.001f);
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() > regTransformed.getUpperCorner().getZ() - 0.001f);
}
//If all three vertices have the same material then we are not on a material edge. If any vertex has a different
//material then all three vertices are on a material edge. E.g. If one vertex has material 'a' and the other two
//have material 'b', then the two 'b's are still on an edge (with 'a') even though they are the same as eachother.
for(uint32_t ct = 0; ct < m_vecTriangles.size(); ct++)
{
uint32_t v0 = m_vecTriangles[ct].v0;
uint32_t v1 = m_vecTriangles[ct].v1;
uint32_t v2 = m_vecTriangles[ct].v2;
bool allMatch =
(m_pOutputMesh->m_vecVertices[v0].material - m_pOutputMesh->m_vecVertices[v1].material < 0.001f) &&
(m_pOutputMesh->m_vecVertices[v1].material - m_pOutputMesh->m_vecVertices[v2].material < 0.001f);
if(!allMatch)
{
vecVertexMetadata[v0].isOnMaterialEdge = true;
vecVertexMetadata[v1].isOnMaterialEdge = true;
vecVertexMetadata[v2].isOnMaterialEdge = true;
}
}
}
template<>
POLYVOX_API bool MeshDecimator<PositionMaterialNormal>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
{
if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < m_fMinDotProductForCollapse)
{
return false;
}
//With the marching cubes surface we honour the user specified threshold
return !collapseChangesFaceNormals(uSrc, uDst, m_fMinDotProductForCollapse);
}
template<>
POLYVOX_API bool MeshDecimator<PositionMaterial>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
{
//We don't actually use the normal here, because we want to allow face
//vertices to collapse onto edge vertices. Simply checking whether anything
//has flipped has proved to be the most robust approach, though rather slow.
//It's not sufficient to just check the normals, there can be holes in the middle
//of the mesh for example.
//User specified threshold is not used for cubic surface, any
//movement is too much (but allow for floating point error).
return !collapseChangesFaceNormals(uSrc, uDst, 0.999f);
}
}

View File

@ -23,236 +23,449 @@ freely, subject to the following restrictions:
#include "PolyVoxCore/Region.h"
#include <cassert>
#include <limits>
namespace PolyVox
{
/**
*/
const Region Region::MaxRegion
(
Vector3DInt32((std::numeric_limits<int32_t>::min)(), (std::numeric_limits<int32_t>::min)(), (std::numeric_limits<int32_t>::min)()),
Vector3DInt32((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.
*/
const Region Region::InvertedRegion
(
Vector3DInt32((std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)(), (std::numeric_limits<int32_t>::max)()),
Vector3DInt32((std::numeric_limits<int32_t>::min)(), (std::numeric_limits<int32_t>::min)(), (std::numeric_limits<int32_t>::min)())
);
Region::Region()
:m_v3dLowerCorner(0,0,0)
,m_v3dUpperCorner(0,0,0)
/**
* \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.
*/
void Region::accumulate(int32_t iX, int32_t iY, int32_t iZ)
{
}
Region::Region(const Vector3DInt32& v3dLowerCorner, const Vector3DInt32& v3dUpperCorner)
:m_v3dLowerCorner(v3dLowerCorner)
,m_v3dUpperCorner(v3dUpperCorner)
{
//Check the region is valid.
assert(m_v3dUpperCorner.getX() >= m_v3dLowerCorner.getX());
assert(m_v3dUpperCorner.getY() >= m_v3dLowerCorner.getY());
assert(m_v3dUpperCorner.getZ() >= m_v3dLowerCorner.getZ());
}
Region::Region(int32_t iLowerX, int32_t iLowerY, int32_t iLowerZ, int32_t iUpperX, int32_t iUpperY, int32_t iUpperZ)
:m_v3dLowerCorner(iLowerX, iLowerY, iLowerZ)
,m_v3dUpperCorner(iUpperX, iUpperY, iUpperZ)
{
//Check the region is valid.
assert(m_v3dUpperCorner.getX() >= m_v3dLowerCorner.getX());
assert(m_v3dUpperCorner.getY() >= m_v3dLowerCorner.getY());
assert(m_v3dUpperCorner.getZ() >= m_v3dLowerCorner.getZ());
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));
}
/**
Checks whether two Regions are equal.
\param rhs The Region to compare to.
\return true if the Regions match.
\see operator!=
* \param v3dPos The position to accumulate.
*/
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()
*/
void Region::accumulate(const Region& reg)
{
assert(reg.isValid()); //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.
*/
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.
*/
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.
*/
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!=
*/
bool Region::operator==(const Region& rhs) const
{
return ((m_v3dLowerCorner == rhs.m_v3dLowerCorner) && (m_v3dUpperCorner == rhs.m_v3dUpperCorner));
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));
}
/**
Checks whether two Regions are not equal.
\param rhs The Region to compare to.
\return true if the Regions do not match.
\see operator==
*/
////////////////////////////////////////////////////////////////////////////////
/// 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==
////////////////////////////////////////////////////////////////////////////////
bool Region::operator!=(const Region& rhs) const
{
return !(*this == rhs);
}
const Vector3DInt32& Region::getLowerCorner(void) const
/**
* 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.
*/
bool Region::containsPoint(float fX, float fY, float fZ, float boundary) const
{
return m_v3dLowerCorner;
}
const Vector3DInt32& Region::getUpperCorner(void) const
{
return m_v3dUpperCorner;
}
int32_t Region::getWidthInVoxels(void) const
{
return getWidthInCells() + 1;
}
int32_t Region::getHeightInVoxels(void) const
{
return getHeightInCells() + 1;
}
int32_t Region::getDepthInVoxels(void) const
{
return getDepthInCells() + 1;
}
Vector3DInt32 Region::getDimensionsInVoxels(void) const
{
return getDimensionsInCells() + Vector3DInt32(1, 1, 1);
}
int32_t Region::getWidthInCells(void) const
{
return m_v3dUpperCorner.getX() - m_v3dLowerCorner.getX();
}
int32_t Region::getHeightInCells(void) const
{
return m_v3dUpperCorner.getY() - m_v3dLowerCorner.getY();
}
Vector3DInt32 Region::getDimensionsInCells(void) const
{
return m_v3dUpperCorner - m_v3dLowerCorner;
}
int32_t Region::getDepthInCells(void) const
{
return m_v3dUpperCorner.getZ() - m_v3dLowerCorner.getZ();
}
void Region::setLowerCorner(const Vector3DInt32& v3dLowerCorner)
{
m_v3dLowerCorner = v3dLowerCorner;
}
void Region::setUpperCorner(const Vector3DInt32& v3dUpperCorner)
{
m_v3dUpperCorner = v3dUpperCorner;
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.
*/
bool Region::containsPoint(const Vector3DFloat& pos, float boundary) const
{
return (pos.getX() <= m_v3dUpperCorner.getX() - boundary)
&& (pos.getY() <= m_v3dUpperCorner.getY() - boundary)
&& (pos.getZ() <= m_v3dUpperCorner.getZ() - boundary)
&& (pos.getX() >= m_v3dLowerCorner.getX() + boundary)
&& (pos.getY() >= m_v3dLowerCorner.getY() + boundary)
&& (pos.getZ() >= m_v3dLowerCorner.getZ() + boundary);
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.
*/
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.
*/
bool Region::containsPoint(const Vector3DInt32& pos, uint8_t boundary) const
{
return (pos.getX() <= m_v3dUpperCorner.getX() - boundary)
&& (pos.getY() <= m_v3dUpperCorner.getY() - boundary)
&& (pos.getZ() <= m_v3dUpperCorner.getZ() - boundary)
&& (pos.getX() >= m_v3dLowerCorner.getX() + boundary)
&& (pos.getY() >= m_v3dLowerCorner.getY() + boundary)
&& (pos.getZ() >= m_v3dLowerCorner.getZ() + boundary);
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.
*/
bool Region::containsPointInX(float pos, float boundary) const
{
return (pos <= m_v3dUpperCorner.getX() - boundary)
&& (pos >= m_v3dLowerCorner.getX() + boundary);
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.
*/
bool Region::containsPointInX(int32_t pos, uint8_t boundary) const
{
return (pos <= m_v3dUpperCorner.getX() - boundary)
&& (pos >= m_v3dLowerCorner.getX() + boundary);
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.
*/
bool Region::containsPointInY(float pos, float boundary) const
{
return (pos <= m_v3dUpperCorner.getY() - boundary)
&& (pos >= m_v3dLowerCorner.getY() + boundary);
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.
*/
bool Region::containsPointInY(int32_t pos, uint8_t boundary) const
{
return (pos <= m_v3dUpperCorner.getY() - boundary)
&& (pos >= m_v3dLowerCorner.getY() + boundary);
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.
*/
bool Region::containsPointInZ(float pos, float boundary) const
{
return (pos <= m_v3dUpperCorner.getZ() - boundary)
&& (pos >= m_v3dLowerCorner.getZ() + boundary);
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.
*/
bool Region::containsPointInZ(int32_t pos, uint8_t boundary) const
{
return (pos <= m_v3dUpperCorner.getZ() - boundary)
&& (pos >= m_v3dLowerCorner.getZ() + boundary);
return (pos <= m_iUpperZ - boundary)
&& (pos >= 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.
*/
void Region::cropTo(const Region& other)
{
m_v3dLowerCorner.setX((std::max)(m_v3dLowerCorner.getX(), other.m_v3dLowerCorner.getX()));
m_v3dLowerCorner.setY((std::max)(m_v3dLowerCorner.getY(), other.m_v3dLowerCorner.getY()));
m_v3dLowerCorner.setZ((std::max)(m_v3dLowerCorner.getZ(), other.m_v3dLowerCorner.getZ()));
m_v3dUpperCorner.setX((std::min)(m_v3dUpperCorner.getX(), other.m_v3dUpperCorner.getX()));
m_v3dUpperCorner.setY((std::min)(m_v3dUpperCorner.getY(), other.m_v3dUpperCorner.getY()));
m_v3dUpperCorner.setZ((std::min)(m_v3dUpperCorner.getZ(), other.m_v3dUpperCorner.getZ()));
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));
}
/// \deprecated Use getDepthInVoxels() or getDepthInCells() instead
int32_t Region::depth(void) const
/**
* 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.
*/
void Region::grow(int32_t iAmount)
{
//This function is deprecated and wrong.
assert(false);
return m_v3dUpperCorner.getZ() - m_v3dLowerCorner.getZ();
m_iLowerX -= iAmount;
m_iLowerY -= iAmount;
m_iLowerZ -= iAmount;
m_iUpperX += iAmount;
m_iUpperY += iAmount;
m_iUpperZ += iAmount;
}
/// \deprecated Use getHeightInVoxels() or getHeightInCells() instead
int32_t Region::height(void) const
/**
* 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'.
*/
void Region::grow(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ)
{
//This function is deprecated and wrong.
assert(false);
return m_v3dUpperCorner.getY() - m_v3dLowerCorner.getY();
m_iLowerX -= iAmountX;
m_iLowerY -= iAmountY;
m_iLowerZ -= iAmountZ;
m_iUpperX += iAmountX;
m_iUpperY += iAmountY;
m_iUpperZ += iAmountZ;
}
void Region::shift(const Vector3DInt32& amount)
/**
* 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).
*/
void Region::grow(const Vector3DInt32& v3dAmount)
{
m_v3dLowerCorner += amount;
m_v3dUpperCorner += amount;
grow(v3dAmount.getX(), v3dAmount.getY(), v3dAmount.getZ());
}
void Region::shiftLowerCorner(const Vector3DInt32& amount)
/**
*/
bool Region::isValid(void) const
{
m_v3dLowerCorner += amount;
return (m_iUpperX >= m_iLowerX) && (m_iUpperY >= m_iLowerY) && (m_iUpperZ >= m_iLowerZ);
}
void Region::shiftUpperCorner(const Vector3DInt32& amount)
/**
* \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'.
*/
void Region::shift(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ)
{
m_v3dUpperCorner += amount;
shiftLowerCorner(iAmountX, iAmountY, iAmountZ);
shiftUpperCorner(iAmountX, iAmountY, iAmountZ);
}
/// \deprecated Use getDimensionsInVoxels() or getDimensionsInCells() instead
Vector3DInt32 Region::dimensions(void)
/**
* \param v3dAmount The amount to move the Region by.
*/
void Region::shift(const Vector3DInt32& v3dAmount)
{
//This function is deprecated and wrong.
assert(false);
return m_v3dUpperCorner - m_v3dLowerCorner;
shiftLowerCorner(v3dAmount);
shiftUpperCorner(v3dAmount);
}
/// \deprecated Use getWidthInVoxels() or getWidthInCells() instead
int32_t Region::width(void) const
/**
* \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'.
*/
void Region::shiftLowerCorner(int32_t iAmountX, int32_t iAmountY, int32_t iAmountZ)
{
//This function is deprecated and wrong.
assert(false);
return m_v3dUpperCorner.getX() - m_v3dLowerCorner.getX();
m_iLowerX += iAmountX;
m_iLowerY += iAmountY;
m_iLowerZ += iAmountZ;
}
/**
* \param v3dAmount The amount to move the lower corner by.
*/
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'.
*/
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.
*/
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.
*/
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'.
*/
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).
*/
void Region::shrink(const Vector3DInt32& v3dAmount)
{
shrink(v3dAmount.getX(), v3dAmount.getY(), v3dAmount.getZ());
}
}

View File

@ -1,43 +0,0 @@
/*******************************************************************************
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/SimpleInterface.h"
//DOESN'T BELONG HERE - JUST FOR TESTING!!
#include "PolyVoxCore/Density.h"
#include "PolyVoxCore/MaterialDensityPair.h"
namespace PolyVox
{
void extractCubicMesh(Volume& volume, const Region& region, Mesh& resultMesh)
{
CubicSurfaceExtractorWithNormals< SimpleVolume<MaterialDensityPair88> > surfaceExtractor(&volume, region, &resultMesh);
surfaceExtractor.execute();
}
void extractSmoothMesh(Volume& volume, const Region& region, Mesh& resultMesh)
{
MarchingCubesSurfaceExtractor< SimpleVolume<MaterialDensityPair88> > surfaceExtractor(&volume, region, &resultMesh);
surfaceExtractor.execute();
}
}

View File

@ -31,10 +31,7 @@ SET(UTIL_SRC_FILES
#Projects headers files
SET(UTIL_INC_FILES
include/PolyVoxUtil/Serialization.h
include/PolyVoxUtil/Serialization.inl
include/PolyVoxUtil/VolumeChangeTracker.h
include/PolyVoxUtil/VolumeChangeTracker.inl
#Nothing here at the moment...
)
ADD_DEFINITIONS(-DPOLYVOX_SHARED_EXPORTS) #Export symbols in the .dll

View File

@ -0,0 +1 @@
I don't think Git allows empty directories, so this is just a placeholder until we decide what to do with PolyVoxUtil.

View File

@ -1,77 +0,0 @@
/*******************************************************************************
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_Serialization_H__
#define __PolyVox_Serialization_H__
#include "PolyVoxCore/Impl/Utility.h"
#include "PolyVoxCore/Region.h"
#include <iostream>
#include <memory>
namespace PolyVox
{
/// \deprecated
class POLYVOX_DEPRECATED VolumeSerializationProgressListener
{
public:
virtual void onProgressUpdated(float fProgress) = 0;
};
////////////////////////////////////////////////////////////////////////////////
// THESE FUNCTIONS ARE DEPRECATED.
////////////////////////////////////////////////////////////////////////////////
/// \deprecated
template< typename VolumeType >
POLYVOX_DEPRECATED polyvox_shared_ptr< VolumeType > loadVolumeRaw(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0);
/// \deprecated
template< typename VolumeType >
POLYVOX_DEPRECATED void saveVolumeRaw(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
/// \deprecated
template< typename VolumeType >
POLYVOX_DEPRECATED polyvox_shared_ptr< VolumeType > loadVolumeRle(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0);
/// \deprecated
template< typename VolumeType >
POLYVOX_DEPRECATED void saveVolumeRle(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
/// \deprecated
template< typename VolumeType >
POLYVOX_DEPRECATED bool loadVolume(std::istream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
/// \deprecated
template< typename VolumeType >
POLYVOX_DEPRECATED bool saveVolume(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
/// \deprecated
template< typename VolumeType >
POLYVOX_DEPRECATED bool loadVersion0(std::istream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
/// \deprecated
template< typename VolumeType >
POLYVOX_DEPRECATED bool saveVersion0(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
}
#include "PolyVoxUtil/Serialization.inl"
#endif

View File

@ -1,433 +0,0 @@
/*******************************************************************************
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
{
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
template< typename VolumeType >
polyvox_shared_ptr< VolumeType > loadVolumeRaw(std::istream& stream, VolumeSerializationProgressListener* progressListener)
{
assert(false); //THIS FUNCTION IS DEPRECATED. REMOVE THIS ASSERT TO CONTINUE, BUT SWITCH TO 'loadVolume()' ASAP.
//Read volume dimensions
uint8_t volumeWidthPower = 0;
uint8_t volumeHeightPower = 0;
uint8_t volumeDepthPower = 0;
stream.read(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.read(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.read(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
uint16_t volumeWidth = 0x0001 << volumeWidthPower;
uint16_t volumeHeight = 0x0001 << volumeHeightPower;
uint16_t volumeDepth = 0x0001 << volumeDepthPower;
//FIXME - need to support non cubic volumes
polyvox_shared_ptr< VolumeType > volume(new LargeVolume<VolumeType::VoxelType>(volumeWidth, volumeHeight, volumeDepth));
//Read data
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
VolumeType::VoxelType value;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
volume->setVoxelAt(x,y,z,value);
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
return volume;
}
template< typename VolumeType >
void saveVolumeRaw(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
{
assert(false); //THIS FUNCTION IS DEPRECATED. REMOVE THIS ASSERT TO CONTINUE, BUT SWITCH TO 'saveVolume()' ASAP.
//Write volume dimensions
uint16_t volumeWidth = volume.getWidth();
uint16_t volumeHeight = volume.getHeight();
uint16_t volumeDepth = volume.getDepth();
uint8_t volumeWidthPower = logBase2(volumeWidth);
uint8_t volumeHeightPower = logBase2(volumeHeight);
uint8_t volumeDepthPower = logBase2(volumeDepth);
stream.write(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.write(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.write(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
//Write data
VolumeType::Sampler volIter(&volume);
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
volIter.setPosition(x,y,z);
VolumeType::VoxelType value = volIter.getVoxel();
stream.write(reinterpret_cast<char*>(&value), sizeof(value));
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
}
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
template< typename VolumeType >
polyvox_shared_ptr< VolumeType > loadVolumeRle(std::istream& stream, VolumeSerializationProgressListener* progressListener)
{
assert(false); //THIS FUNCTION IS DEPRECATED. REMOVE THIS ASSERT TO CONTINUE, BUT SWITCH TO 'loadVolume()' ASAP.
//Read volume dimensions
uint8_t volumeWidthPower = 0;
uint8_t volumeHeightPower = 0;
uint8_t volumeDepthPower = 0;
stream.read(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.read(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.read(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
uint16_t volumeWidth = 0x0001 << volumeWidthPower;
uint16_t volumeHeight = 0x0001 << volumeHeightPower;
uint16_t volumeDepth = 0x0001 << volumeDepthPower;
//FIXME - need to support non cubic volumes
polyvox_shared_ptr< VolumeType > volume(new LargeVolume<VolumeType::VoxelType>(volumeWidth, volumeHeight, volumeDepth));
//Read data
bool firstTime = true;
uint32_t runLength = 0;
VolumeType::VoxelType value;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
if(runLength != 0)
{
volume->setVoxelAt(x,y,z,value);
runLength--;
}
else
{
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
volume->setVoxelAt(x,y,z,value);
runLength--;
}
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
return volume;
}
template< typename VolumeType >
void saveVolumeRle(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
{
assert(false); //THIS FUNCTION IS DEPRECATED. REMOVE THIS ASSERT TO CONTINUE, BUT SWITCH TO 'saveVolume()' ASAP.
//Write volume dimensions
uint16_t volumeWidth = volume.getWidth();
uint16_t volumeHeight = volume.getHeight();
uint16_t volumeDepth = volume.getDepth();
uint8_t volumeWidthPower = logBase2(volumeWidth);
uint8_t volumeHeightPower = logBase2(volumeHeight);
uint8_t volumeDepthPower = logBase2(volumeDepth);
stream.write(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.write(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.write(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
//Write data
VolumeType::Sampler volIter(&volume);
VolumeType::VoxelType current;
uint32_t runLength = 0;
bool firstTime = true;
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
volIter.setPosition(x,y,z);
VolumeType::VoxelType value = volIter.getVoxel();
if(firstTime)
{
current = value;
runLength = 1;
firstTime = false;
}
else
{
if(value == current)
{
runLength++;
}
else
{
stream.write(reinterpret_cast<char*>(&current), sizeof(current));
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
current = value;
runLength = 1;
}
}
}
}
}
stream.write(reinterpret_cast<char*>(&current), sizeof(current));
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// New version of load/save code with versioning
////////////////////////////////////////////////////////////////////////////////////////////////////
template< typename VolumeType >
bool loadVolume(std::istream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
{
char pIdentifier[8];
stream.read(pIdentifier, 7);
pIdentifier[7] = '\0'; //Set the null terminator
if(strcmp(pIdentifier, "PolyVox") != 0)
{
return false;
}
uint16_t uVersion;
stream.read(reinterpret_cast<char*>(&uVersion), sizeof(uVersion));
switch(uVersion)
{
case 0:
return loadVersion0(stream, volume, progressListener);
//Return means no need to break...
default:
return false;
}
}
template< typename VolumeType >
bool saveVolume(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
{
char pIdentifier[] = "PolyVox";
stream.write(pIdentifier, 7);
uint16_t uVersion = 0;
stream.write(reinterpret_cast<const char*>(&uVersion), sizeof(uVersion));
return saveVersion0(stream, volume, progressListener);
}
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
template< typename VolumeType >
bool loadVersion0(std::istream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
{
//Read volume dimensions
uint16_t volumeWidth = 0;
uint16_t volumeHeight = 0;
uint16_t volumeDepth = 0;
stream.read(reinterpret_cast<char*>(&volumeWidth), sizeof(volumeWidth));
stream.read(reinterpret_cast<char*>(&volumeHeight), sizeof(volumeHeight));
stream.read(reinterpret_cast<char*>(&volumeDepth), sizeof(volumeDepth));
//Resize the volume
//HACK - Forces block size to 32. This functions needs reworking anyway due to large volume support.
volume.resize(Region(Vector3DInt32(0,0,0), Vector3DInt32(volumeWidth-1, volumeHeight-1, volumeDepth-1)), 32);
//Read data
bool firstTime = true;
uint32_t runLength = 0;
VolumeType::VoxelType value;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
if(runLength != 0)
{
volume.setVoxelAt(x,y,z,value);
runLength--;
}
else
{
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
volume.setVoxelAt(x,y,z,value);
runLength--;
}
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
return true;
}
template< typename VolumeType >
bool saveVersion0(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
{
//Write volume dimensions
uint16_t volumeWidth = volume.getWidth();
uint16_t volumeHeight = volume.getHeight();
uint16_t volumeDepth = volume.getDepth();
stream.write(reinterpret_cast<char*>(&volumeWidth), sizeof(volumeWidth));
stream.write(reinterpret_cast<char*>(&volumeHeight), sizeof(volumeHeight));
stream.write(reinterpret_cast<char*>(&volumeDepth), sizeof(volumeDepth));
//Write data
VolumeType::Sampler volIter(&volume);
VolumeType::VoxelType current;
uint32_t runLength = 0;
bool firstTime = true;
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
volIter.setPosition(x,y,z);
VolumeType::VoxelType value = volIter.getVoxel();
if(firstTime)
{
current = value;
runLength = 1;
firstTime = false;
}
else
{
if(value == current)
{
runLength++;
}
else
{
stream.write(reinterpret_cast<char*>(&current), sizeof(current));
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
current = value;
runLength = 1;
}
}
}
}
}
stream.write(reinterpret_cast<char*>(&current), sizeof(current));
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
return true;
}
}

View File

@ -1,83 +0,0 @@
/*******************************************************************************
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_VolumeChangeTracker_H__
#define __PolyVox_VolumeChangeTracker_H__
#include "Impl/Utility.h"
#include "PolyVoxCore/Region.h"
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/Vector.h"
namespace PolyVox
{
/// Voxel scene manager
/// \deprecated
template <typename VoxelType>
class POLYVOX_DEPRECATED VolumeChangeTracker
{
public:
//Constructors, etc
VolumeChangeTracker(LargeVolume<VoxelType>* volumeDataToSet, uint16_t regionSideLength);
~VolumeChangeTracker();
//Getters
int32_t getCurrentTime(void) const;
int32_t getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ);
LargeVolume<VoxelType>* getWrappedVolume(void) const;
//Setters
void setAllRegionsModified(void);
void setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value);
void setVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value);
//Others
void lockRegion(const Region& regToLock);
void unlockRegion(void);
//void markRegionChanged(uint16_t firstX, uint16_t firstY, uint16_t firstZ, uint16_t lastX, uint16_t lastY, uint16_t lastZ);
public:
void incrementCurrentTime(void);
bool m_bIsLocked;
Region m_regLastLocked;
LargeVolume<VoxelType>* volumeData;
uint16_t m_uRegionSideLength;
uint8_t m_uRegionSideLengthPower;
uint16_t m_uVolumeWidthInRegions;
uint16_t m_uVolumeHeightInRegions;
uint16_t m_uVolumeDepthInRegions;
//It's not what the block class was designed for, but it
//provides a handy way of storing a 3D grid of values.
LargeVolume<int32_t>* volRegionLastModified;
static uint32_t m_uCurrentTime;
};
}
#include "PolyVoxUtil/VolumeChangeTracker.inl"
#endif

View File

@ -1,212 +0,0 @@
/*******************************************************************************
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 VoxelType>
uint32_t VolumeChangeTracker<VoxelType>::m_uCurrentTime = 0;
//////////////////////////////////////////////////////////////////////////
// VolumeChangeTracker
//////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VolumeChangeTracker<VoxelType>::VolumeChangeTracker(LargeVolume<VoxelType>* volumeDataToSet, uint16_t regionSideLength)
:m_bIsLocked(false)
,volumeData(0)
,m_uRegionSideLength(regionSideLength)
{
volumeData = volumeDataToSet;
m_uVolumeWidthInRegions = volumeData->getWidth() / m_uRegionSideLength;
m_uVolumeHeightInRegions = volumeData->getHeight() / m_uRegionSideLength;
m_uVolumeDepthInRegions = volumeData->getDepth() / m_uRegionSideLength;
m_uRegionSideLengthPower = PolyVox::logBase2(m_uRegionSideLength);
volRegionLastModified = new LargeVolume<int32_t>(m_uVolumeWidthInRegions, m_uVolumeHeightInRegions, m_uVolumeDepthInRegions, 0);
}
template <typename VoxelType>
VolumeChangeTracker<VoxelType>::~VolumeChangeTracker()
{
}
template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::setAllRegionsModified(void)
{
incrementCurrentTime();
for(uint16_t blockZ = 0; blockZ < m_uVolumeDepthInRegions; ++blockZ)
{
for(uint16_t blockY = 0; blockY < m_uVolumeHeightInRegions; ++blockY)
{
for(uint16_t blockX = 0; blockX < m_uVolumeWidthInRegions; ++blockX)
{
volRegionLastModified->setVoxelAt(blockX, blockY, blockZ, m_uCurrentTime);
}
}
}
}
template <typename VoxelType>
int32_t VolumeChangeTracker<VoxelType>::getCurrentTime(void) const
{
return m_uCurrentTime;
}
template <typename VoxelType>
int32_t VolumeChangeTracker<VoxelType>::getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ)
{
return volRegionLastModified->getVoxelAt(uX, uY, uZ);
}
template <typename VoxelType>
LargeVolume<VoxelType>* VolumeChangeTracker<VoxelType>::getWrappedVolume(void) const
{
return volumeData;
}
template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::setVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value)
{
//Note: We increase the time stamp both at the start and the end
//to avoid ambiguity about whether the timestamp comparison should
//be '<' vs '<=' or '>' vs '>=' in the users code.
incrementCurrentTime();
volumeData->setVoxelAt(x,y,z,value);
//If we are not on a boundary, just mark one region.
if((x % m_uRegionSideLength != 0) &&
(x % m_uRegionSideLength != m_uRegionSideLength-1) &&
(y % m_uRegionSideLength != 0) &&
(y % m_uRegionSideLength != m_uRegionSideLength-1) &&
(z % m_uRegionSideLength != 0) &&
(z % m_uRegionSideLength != m_uRegionSideLength-1))
{
volRegionLastModified->setVoxelAt(x >> m_uRegionSideLengthPower, y >> m_uRegionSideLengthPower, z >> m_uRegionSideLengthPower, m_uCurrentTime);
}
else //Mark surrounding regions as well
{
const uint16_t regionX = x >> m_uRegionSideLengthPower;
const uint16_t regionY = y >> m_uRegionSideLengthPower;
const uint16_t regionZ = z >> m_uRegionSideLengthPower;
const uint16_t minRegionX = (std::max)(uint16_t(0),uint16_t(regionX-1));
const uint16_t minRegionY = (std::max)(uint16_t(0),uint16_t(regionY-1));
const uint16_t minRegionZ = (std::max)(uint16_t(0),uint16_t(regionZ-1));
const uint16_t maxRegionX = (std::min)(uint16_t(m_uVolumeWidthInRegions-1),uint16_t(regionX+1));
const uint16_t maxRegionY = (std::min)(uint16_t(m_uVolumeHeightInRegions-1),uint16_t(regionY+1));
const uint16_t maxRegionZ = (std::min)(uint16_t(m_uVolumeDepthInRegions-1),uint16_t(regionZ+1));
for(uint16_t zCt = minRegionZ; zCt <= maxRegionZ; zCt++)
{
for(uint16_t yCt = minRegionY; yCt <= maxRegionY; yCt++)
{
for(uint16_t xCt = minRegionX; xCt <= maxRegionX; xCt++)
{
volRegionLastModified->setVoxelAt(xCt,yCt,zCt,m_uCurrentTime);
}
}
}
}
//Increment time stamp. See earlier note.
incrementCurrentTime();
}
template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value)
{
assert(m_bIsLocked);
//FIXME - rather than creating a iterator each time we should have one stored
/*Sampler<VoxelType> iterVol(*volumeData);
iterVol.setPosition(x,y,z);
iterVol.setVoxel(value);*/
volumeData->setVoxelAt(x,y,z,value);
}
template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::lockRegion(const Region& regToLock)
{
if(m_bIsLocked)
{
throw std::logic_error("A region is already locked. Please unlock it before locking another.");
}
m_regLastLocked = regToLock;
m_bIsLocked = true;
}
template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::unlockRegion(void)
{
if(!m_bIsLocked)
{
throw std::logic_error("No region is locked. You must lock a region before you can unlock it.");
}
//Note: We increase the time stamp both at the start and the end
//to avoid ambiguity about whether the timestamp comparison should
//be '<' vs '<=' or '>' vs '>=' in the users code.
incrementCurrentTime();
const uint16_t firstRegionX = m_regLastLocked.getLowerCorner().getX() >> m_uRegionSideLengthPower;
const uint16_t firstRegionY = m_regLastLocked.getLowerCorner().getY() >> m_uRegionSideLengthPower;
const uint16_t firstRegionZ = m_regLastLocked.getLowerCorner().getZ() >> m_uRegionSideLengthPower;
const uint16_t lastRegionX = m_regLastLocked.getUpperCorner().getX() >> m_uRegionSideLengthPower;
const uint16_t lastRegionY = m_regLastLocked.getUpperCorner().getY() >> m_uRegionSideLengthPower;
const uint16_t lastRegionZ = m_regLastLocked.getUpperCorner().getZ() >> m_uRegionSideLengthPower;
for(uint16_t zCt = firstRegionZ; zCt <= lastRegionZ; zCt++)
{
for(uint16_t yCt = firstRegionY; yCt <= lastRegionY; yCt++)
{
for(uint16_t xCt = firstRegionX; xCt <= lastRegionX; xCt++)
{
volRegionLastModified->setVoxelAt(xCt,yCt,zCt,m_uCurrentTime);
}
}
}
m_bIsLocked = false;
//Increment time stamp. See earlier note.
incrementCurrentTime();
}
template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::incrementCurrentTime(void)
{
//Increment the current time.
uint32_t time = m_uCurrentTime++;
//Watch out for wraparound. Hopefully this will never happen
//as we have a pretty big counter, but it's best to be sure...
assert(time < m_uCurrentTime);
if(time >= m_uCurrentTime)
{
throw std::overflow_error("The VolumeChangeTracker time has overflowed.");
}
}
}

View File

@ -0,0 +1,8 @@
%module SimpleVolume
%{
#include "BaseVolume.h"
%}
%include "BaseVolume.h"
VOLUMETYPES(BaseVolume)

View File

@ -1,13 +1,8 @@
%module CubicSurfaceExtractor
%{
#include "SimpleVolume.h"
#include "Array.h"
#include "CubicSurfaceExtractor.h"
%}
%include "SimpleVolume.h"
%include "Array.h"
%include "CubicSurfaceExtractor.h"
%template(CubicSurfaceExtractorMaterial8) PolyVox::CubicSurfaceExtractor<PolyVox::Material8>;
%template(CubicSurfaceExtractorDensity8) PolyVox::CubicSurfaceExtractor<PolyVox::Density8>;
EXTRACTORS(CubicSurfaceExtractor)

View File

@ -1,9 +0,0 @@
%module Density
%{
#include "Density.h"
%}
%include "MarchingCubesSurfaceExtractor.h"
%include "Density.h"
%template(Density8) PolyVox::Density<uint8_t>;

View File

@ -0,0 +1,8 @@
%module LargeVolume
%{
#include "LargeVolume.h"
%}
%include "LargeVolume.h"
VOLUMETYPES(LargeVolume)

View File

@ -1,11 +1,8 @@
%module MarchingCubesSurfaceExtractor
%{
#include "SimpleVolume.h"
#include "Material.h"
#include "MarchingCubesSurfaceExtractor.h"
%}
%include "SimpleVolume.h"
%include "MarchingCubesSurfaceExtractor.h"
%template(SurfaceExtractorSimpleVolumeDensity8) PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<PolyVox::Density8> >;
EXTRACTORS(MarchingCubesSurfaceExtractor)

View File

@ -1,10 +0,0 @@
%module Material
%{
#include "Material.h"
%}
%include "DefaultIsQuadNeeded.h"
%include "Material.h"
%template(Material8) PolyVox::Material<uint8_t>;
%template(Material16) PolyVox::Material<uint16_t>;

View File

@ -1,9 +0,0 @@
%module MaterialDensityPair
%{
#include "MaterialDensityPair.h"
%}
%include "MaterialDensityPair.h"
%template(MaterialDensityPair44) PolyVox::MaterialDensityPair<uint8_t, 4, 4>;
%template(MaterialDensityPair88) PolyVox::MaterialDensityPair<uint16_t, 8, 8>;

View File

@ -25,28 +25,56 @@ const char* __str__() {
}
%enddef
//Centralise this to avoid repeating ourselves
//This macro will be called in the volume interface files to define the various volume types.
%define VOLUMETYPES(class)
%template(class ## int8) PolyVox::class<int8_t>;
%template(class ## int16) PolyVox::class<int16_t>;
%template(class ## int32) PolyVox::class<int32_t>;
%template(class ## uint8) PolyVox::class<uint8_t>;
%template(class ## uint16) PolyVox::class<uint16_t>;
%template(class ## uint32) PolyVox::class<uint32_t>;
%template(class ## float) PolyVox::class<float>;
%enddef
//Template based on voxel type
%define EXTRACTOR(class, volumetype)
%template(class ## volumetype ## int8) PolyVox::class<PolyVox::volumetype<int8_t> >;
%template(class ## volumetype ## int16) PolyVox::class<PolyVox::volumetype<int16_t> >;
%template(class ## volumetype ## int32) PolyVox::class<PolyVox::volumetype<int32_t> >;
%template(class ## volumetype ## uint8) PolyVox::class<PolyVox::volumetype<uint8_t> >;
%template(class ## volumetype ## uint16) PolyVox::class<PolyVox::volumetype<uint16_t> >;
%template(class ## volumetype ## uint32) PolyVox::class<PolyVox::volumetype<uint32_t> >;
%template(class ## volumetype ## float) PolyVox::class<PolyVox::volumetype<float> >;
%enddef
//Template based on volume type
%define EXTRACTORS(shortname)
EXTRACTOR(shortname, SimpleVolume)
EXTRACTOR(shortname, RawVolume)
EXTRACTOR(shortname, LargeVolume)
%enddef
%feature("autodoc", "1");
#ifdef SWIGPYTHON
//This will rename "operator=" to "assign" since Python doesn't have assignment
%rename(assign) *::operator=;
#endif
%include "stdint.i"
%include "std_vector.i"
%include "Vector.i"
%include "DefaultMarchingCubesController.i"
%include "Density.i"
%include "Material.i"
%include "MaterialDensityPair.i"
%include "Region.i"
%include "BaseVolume.i"
%include "SimpleVolume.i"
//%include "TypeDef.i"
%include "RawVolume.i"
%include "LargeVolume.i"
//%include "SubArray.i"
//%include "Array.i"
%include "VertexTypes.i"
%include "SurfaceMesh.i"
//%include "SimpleVolumeSampler.i"
%include "MarchingCubesSurfaceExtractor.i"
//%include "CubicSurfaceExtractor.i"
//%include "CubicSurfaceExtractorWithNormals.i"
//%include "MeshDecimator.i"
%include "Raycast.i"

View File

@ -0,0 +1,8 @@
%module RawVolume
%{
#include "RawVolume.h"
%}
%include "RawVolume.h"
VOLUMETYPES(RawVolume)

View File

@ -0,0 +1,53 @@
%module Raycast
%{
#include "Raycast.h"
template<typename VolumeType>
class PyCallback
{
private:
PyObject *func;
PyCallback& operator=(const PyCallback&); // Not allowed
public:
PyCallback(const PyCallback& o) : func(o.func)
{
Py_XINCREF(func);
}
PyCallback(PyObject *func) : func(func)
{
Py_XINCREF(this->func);
assert(PyCallable_Check(this->func));
}
~PyCallback()
{
Py_XDECREF(func);
}
bool operator()(const typename VolumeType::Sampler& sampler)
{
if (!func || Py_None == func || !PyCallable_Check(func))
{
return false; //Make this raise a Python exception
}
PyObject *args = Py_BuildValue("(l)", sampler.getVoxel()); //TODO pass the sampler object itself in
PyObject *result = PyObject_Call(func,args,0);
Py_DECREF(args);
Py_XDECREF(result);
return (PyInt_AsLong(result) == 0) ? false : true;
}
};
template<typename VolumeType, typename Callback>
PolyVox::RaycastResult raycastWithEndpointsPython(VolumeType* volData, const PolyVox::Vector3DFloat& v3dStart, const PolyVox::Vector3DFloat& v3dEnd, PyObject *callback)
{
PyCallback<VolumeType> newCallback(callback);
return PolyVox::raycastWithEndpoints(volData, v3dStart, v3dEnd, newCallback);
}
%}
%include "Raycast.h"
template<typename VolumeType, typename Callback>
PolyVox::RaycastResult raycastWithEndpointsPython(VolumeType* volData, const PolyVox::Vector3DFloat& v3dStart, const PolyVox::Vector3DFloat& v3dEnd, PyObject *callback);
%template(raycastWithEndpointsSimpleVolumeuint8) raycastWithEndpointsPython<PolyVox::SimpleVolume<uint8_t>, PyCallback<PolyVox::SimpleVolume<uint8_t> > >;

View File

@ -1,26 +1,8 @@
%module SimpleVolume
%{
#include "Material.h"
#include "Density.h"
#include "SimpleVolume.h"
%}
%import "BaseVolume.h"
%include "Material.h"
%include "Density.h"
%include "SimpleVolume.h"
%template(BaseVolumeDensity8) PolyVox::BaseVolume<PolyVox::Density8>;
%template(SimpleVolumeDensity8) PolyVox::SimpleVolume<PolyVox::Density8>;
%template(BaseVolumeMaterial8) PolyVox::BaseVolume<PolyVox::Material8>;
%template(SimpleVolumeMaterial8) PolyVox::SimpleVolume<PolyVox::Material8>;
%template(BaseVolumeMaterial16) PolyVox::BaseVolume<PolyVox::Material16>;
%template(SimpleVolumeMaterial16) PolyVox::SimpleVolume<PolyVox::Material16>;
%template(BaseVolumeMaterialDensityPair44) PolyVox::BaseVolume<PolyVox::MaterialDensityPair44>;
%template(SimpleVolumeMaterialDensityPair44) PolyVox::SimpleVolume<PolyVox::MaterialDensityPair44>;
%template(BaseVolumeMaterialDensityPair88) PolyVox::BaseVolume<PolyVox::MaterialDensityPair88>;
%template(SimpleVolumeMaterialDensityPair88) PolyVox::SimpleVolume<PolyVox::MaterialDensityPair88>;
VOLUMETYPES(SimpleVolume)

View File

@ -51,6 +51,7 @@ REMOVE_DEFINITIONS(-DQT_GUI_LIB) #Make sure the tests don't link to the QtGui
# Python tests
IF(BUILD_BINDINGS)
ADD_TEST(PythonSurfaceExtractorTest python ${CMAKE_CURRENT_SOURCE_DIR}/TestSurfaceExtractor.py)
ADD_TEST(PythonRaycastTest python ${CMAKE_CURRENT_SOURCE_DIR}/TestRaycast.py)
ENDIF()
# AmbientOcclusionGenerator tests
@ -72,10 +73,6 @@ ADD_TEST(CubicSurfaceExtractorExecuteTest ${LATEST_TEST} testExecute)
CREATE_TEST(TestLowPassFilter.h TestLowPassFilter.cpp TestLowPassFilter)
ADD_TEST(LowPassFilterExecuteTest ${LATEST_TEST} testExecute)
# LargeVolume tests
CREATE_TEST(testvolume.h testvolume.cpp testvolume)
ADD_TEST(VolumeSizeTest ${LATEST_TEST} testSize)
# Material tests
CREATE_TEST(testmaterial.h testmaterial.cpp testmaterial)
ADD_TEST(MaterialTestCompile ${LATEST_TEST} testCompile)
@ -97,6 +94,17 @@ ADD_TEST(VectorLengthTest ${LATEST_TEST} testLength)
ADD_TEST(VectorDotProductTest ${LATEST_TEST} testDotProduct)
ADD_TEST(VectorEqualityTest ${LATEST_TEST} testEquality)
# Volume tests
CREATE_TEST(testvolume.h testvolume.cpp testvolume)
ADD_TEST(RawVolumeDirectAccessTest ${LATEST_TEST} testRawVolumeDirectAccess)
ADD_TEST(SimpleVolumeDirectAccessTest ${LATEST_TEST} testSimpleVolumeDirectAccess)
ADD_TEST(LargeVolumeDirectAccessTest ${LATEST_TEST} testLargeVolumeDirectAccess)
ADD_TEST(RawVolumeSamplersTest ${LATEST_TEST} testRawVolumeSamplers)
ADD_TEST(SimpleVolumeSamplersTest ${LATEST_TEST} testSimpleVolumeSamplers)
ADD_TEST(LargeVolumeSamplersTest ${LATEST_TEST} testLargeVolumeSamplers)
# Volume subclass tests
CREATE_TEST(TestVolumeSubclass.h TestVolumeSubclass.cpp TestVolumeSubclass)
ADD_TEST(VolumeSubclassExtractSurfaceTest ${LATEST_TEST} testExtractSurface)

View File

@ -42,18 +42,30 @@ class RaycastTestFunctor
{
public:
RaycastTestFunctor()
:m_uTotalVoxelsTouched(0)
:m_uVoxelsTouched(0)
,m_bRayLeftVolume(false)
{
}
bool operator()(const SimpleVolume<int8_t>::Sampler& sampler)
{
m_uTotalVoxelsTouched++;
m_uVoxelsTouched++;
// For this particular test we know that we are always starting a ray inside the volume,
// so if it ever leaves the volume we know it can't go back in and so we can terminate early.
// This optimisation is worthwhile because samplers get slow once outside the volume.
if(!sampler.isCurrentPositionValid())
{
m_bRayLeftVolume = true;
return false;
}
// We are in the volume, so decide whether to continue based on the voxel value.
return sampler.getVoxel() <= 0;
}
uint32_t m_uTotalVoxelsTouched;
uint32_t m_uVoxelsTouched;
bool m_bRayLeftVolume;
};
void TestRaycast::testExecute()
@ -83,21 +95,23 @@ void TestRaycast::testExecute()
//Cast rays from the centre. Roughly 2/3 should escape.
Vector3DFloat start (uVolumeSideLength / 2, uVolumeSideLength / 2, uVolumeSideLength / 2);
// For demonstration purposes we are using the same function object for all raycasts.
// Therefore, the state it maintains (total voxels touched) is accumulated over all raycsts.
RaycastTestFunctor raycastTestFunctor;
// We could have counted the total number of hits in the same way as the total number of voxels
// touched, but for demonstration and testing purposes we are making use of the raycast return value
// and counting them seperatly in this variable.
int hits = 0;
uint32_t uTotalVoxelsTouched = 0;
// Cast a large number of random rays
for(int ct = 0; ct < 1000000; ct++)
{
RaycastTestFunctor raycastTestFunctor;
RaycastResult result = raycastWithDirection(&volData, start, randomUnitVectors[ct % 1024] * 1000.0f, raycastTestFunctor);
if(result == RaycastResults::Interupted)
uTotalVoxelsTouched += raycastTestFunctor.m_uVoxelsTouched;
// If the raycast completed then we know it did not hit anything.If it was interupted then it
// probably hit something, unless we noted that the reason it was interupted was that it left the volume.
if((result == RaycastResults::Interupted) && (raycastTestFunctor.m_bRayLeftVolume == false))
{
hits++;
}
@ -107,7 +121,7 @@ void TestRaycast::testExecute()
QCOMPARE(hits, 687494);
// Check the total number of voxels touched
QCOMPARE(raycastTestFunctor.m_uTotalVoxelsTouched, static_cast<uint32_t>(486219343));
QCOMPARE(uTotalVoxelsTouched, static_cast<uint32_t>(29783248));
}
QTEST_MAIN(TestRaycast)

28
tests/TestRaycast.py Normal file
View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
import sys
sys.path.append("../library/bindings/")
import unittest
import PolyVoxCore
def test_functor(sampler):
return sampler <= 0
class TestSurfaceExtractor(unittest.TestCase):
def setUp(self):
#Create a small volume
r = PolyVoxCore.Region(PolyVoxCore.Vector3DInt32(0,0,0), PolyVoxCore.Vector3DInt32(31,31,31))
self.vol = PolyVoxCore.SimpleVolumeuint8(r)
#Set one single voxel to have a reasonably high density
self.vol.setVoxelAt(PolyVoxCore.Vector3DInt32(5, 5, 5), 200)
def test_hit_voxel(self):
self.assertEqual(PolyVoxCore.raycastWithEndpointsSimpleVolumeuint8(self.vol, PolyVoxCore.Vector3DFloat(0,0,0), PolyVoxCore.Vector3DFloat(31,31,31), test_functor), 1)
def test_miss_voxel(self):
self.assertEqual(PolyVoxCore.raycastWithEndpointsSimpleVolumeuint8(self.vol, PolyVoxCore.Vector3DFloat(0,0,0), PolyVoxCore.Vector3DFloat(0,31,31), test_functor), 0)
if __name__ == '__main__':
unittest.main()

View File

@ -120,8 +120,9 @@ void testForType(SurfaceMesh<PositionMaterialNormal>& result)
}
}
DefaultMarchingCubesController<VoxelType> controller(50);
MarchingCubesSurfaceExtractor< SimpleVolume<VoxelType> > extractor(&volData, volData.getEnclosingRegion(), &result, controller);
DefaultMarchingCubesController<VoxelType> controller;
controller.setThreshold(50);
MarchingCubesSurfaceExtractor< SimpleVolume<VoxelType> > extractor(&volData, volData.getEnclosingRegion(), &result, WrapModes::Border, 0, controller);
extractor.execute();
}
@ -145,7 +146,7 @@ void testCustomController(SurfaceMesh<PositionMaterialNormal>& result)
}
CustomMarchingCubesController controller;
MarchingCubesSurfaceExtractor< SimpleVolume<float>, CustomMarchingCubesController > extractor(&volData, volData.getEnclosingRegion(), &result, controller);
MarchingCubesSurfaceExtractor< SimpleVolume<float>, CustomMarchingCubesController > extractor(&volData, volData.getEnclosingRegion(), &result, WrapModes::Border, 0, controller);
extractor.execute();
}

View File

@ -11,11 +11,11 @@ class TestSurfaceExtractor(unittest.TestCase):
#Create a small volume
r = PolyVoxCore.Region(PolyVoxCore.Vector3DInt32(0,0,0), PolyVoxCore.Vector3DInt32(31,31,31))
vol = PolyVoxCore.SimpleVolumeDensity8(r)
vol = PolyVoxCore.SimpleVolumeuint8(r)
#Set one single voxel to have a reasonably high density
vol.setVoxelAt(PolyVoxCore.Vector3DInt32(5, 5, 5), PolyVoxCore.Density8(200))
vol.setVoxelAt(PolyVoxCore.Vector3DInt32(5, 5, 5), 200)
self.mesh = PolyVoxCore.SurfaceMeshPositionMaterialNormal()
extractor = PolyVoxCore.SurfaceExtractorSimpleVolumeDensity8(vol, r, self.mesh)
extractor = PolyVoxCore.MarchingCubesSurfaceExtractorSimpleVolumeuint8(vol, r, self.mesh)
extractor.execute()
def test_num_vertices(self):

View File

@ -32,7 +32,7 @@ using namespace PolyVox;
void TestVector::testLength()
{
Vector3DInt8 vec(3, 4, 5);
QCOMPARE(vec.lengthSquared(), double(3*3+4*4+5*5));
QCOMPARE(vec.lengthSquared(), int32_t(3*3+4*4+5*5)); // QCOMPARE is strict on types. For an int8 vector, the OperationType is int32_t.
}
void TestVector::testDotProduct()
@ -40,7 +40,7 @@ void TestVector::testDotProduct()
Vector3DInt8 vecxy(3, 4, 0);
Vector3DInt8 vecz(0, 0, 1);
QCOMPARE(vecxy.dot(vecz), int8_t(0)); //QCOMPARE is very strict on the types matching
QCOMPARE(vecxy.dot(vecz), int32_t(0)); // QCOMPARE is strict on types. For an int8 vector, the OperationType is int32_t .
}
void TestVector::testEquality()

View File

@ -24,30 +24,330 @@ freely, subject to the following restrictions:
#include "testvolume.h"
#include "PolyVoxCore/LargeVolume.h"
#include "PolyVoxCore/RawVolume.h"
#include "PolyVoxCore/SimpleVolume.h"
#include <QtGlobal>
#include <QtTest>
using namespace PolyVox;
void TestVolume::testSize()
// This is used to compute a value from a list of integers. We use it to
// make sure we get the expected result from a series of volume accesses.
inline int32_t cantorTupleFunction(int32_t previousResult, int32_t value)
{
const int32_t g_uVolumeSideLength = 128;
LargeVolume<uint8_t> volData(Region(Vector3DInt32(0,0,0), Vector3DInt32(g_uVolumeSideLength-1, g_uVolumeSideLength-1, g_uVolumeSideLength-1)));
return (( previousResult + value ) * ( previousResult + value + 1 ) + value ) / 2;
}
for (int32_t z = 0; z < g_uVolumeSideLength; z++)
template <typename VolumeType>
VolumeType* createAndFillVolume(void)
{
//Create the volume
VolumeType* volume = new VolumeType(Region(-57, -31, 12, 64, 96, 131)); // Deliberatly awkward size
//Fill the volume with some data
for(int z = volume->getEnclosingRegion().getLowerZ(); z <= volume->getEnclosingRegion().getUpperZ(); z++)
{
for (int32_t y = 0; y < g_uVolumeSideLength; y++)
for(int y = volume->getEnclosingRegion().getLowerY(); y <= volume->getEnclosingRegion().getUpperY(); y++)
{
for (int32_t x = 0; x < g_uVolumeSideLength; x++)
for(int x = volume->getEnclosingRegion().getLowerX(); x <= volume->getEnclosingRegion().getUpperX(); x++)
{
volData.setVoxelAt(x,y,z,255);
volume->setVoxelAt(x, y, z, x + y + z);
}
}
}
QCOMPARE(volData.getWidth(), g_uVolumeSideLength);
QCOMPARE(volData.getHeight(), g_uVolumeSideLength);
QCOMPARE(volData.getDepth(), g_uVolumeSideLength);
return volume;
}
template <typename VolumeType>
int32_t testDirectAccessWithWrapping(const VolumeType* volume)
{
int32_t result = 0;
for(int z = volume->getEnclosingRegion().getLowerZ() - 2; z <= volume->getEnclosingRegion().getUpperZ() + 4; z++)
{
for(int y = volume->getEnclosingRegion().getLowerY() - 3; y <= volume->getEnclosingRegion().getUpperY() + 5; y++)
{
for(int x = volume->getEnclosingRegion().getLowerX() - 1; x <= volume->getEnclosingRegion().getUpperX() + 2; x++)
{
//Three level loop now processes 27 voxel neighbourhood
for(int innerZ = -1; innerZ <=1; innerZ++)
{
for(int innerY = -1; innerY <=1; innerY++)
{
for(int innerX = -1; innerX <=1; innerX++)
{
result = cantorTupleFunction(result, volume->getVoxelWithWrapping(x + innerX, y + innerY, z + innerZ, WrapModes::Border, 3));
}
}
}
//End of inner loops
}
}
}
return result;
}
template <typename VolumeType>
int32_t testSamplersWithWrapping(VolumeType* volume)
{
int32_t result = 0;
typename VolumeType::Sampler sampler(volume);
sampler.setWrapMode(WrapModes::Border, 3);
for(int z = volume->getEnclosingRegion().getLowerZ() - 2; z <= volume->getEnclosingRegion().getUpperZ() + 4; z++)
{
for(int y = volume->getEnclosingRegion().getLowerY() - 3; y <= volume->getEnclosingRegion().getUpperY() + 5; y++)
{
for(int x = volume->getEnclosingRegion().getLowerX() - 1; x <= volume->getEnclosingRegion().getUpperX() + 2; x++)
{
sampler.setPosition(x, y, z);
result = cantorTupleFunction(result, sampler.peekVoxel1nx1ny1nz());
result = cantorTupleFunction(result, sampler.peekVoxel0px1ny1nz());
result = cantorTupleFunction(result, sampler.peekVoxel1px1ny1nz());
result = cantorTupleFunction(result, sampler.peekVoxel1nx0py1nz());
result = cantorTupleFunction(result, sampler.peekVoxel0px0py1nz());
result = cantorTupleFunction(result, sampler.peekVoxel1px0py1nz());
result = cantorTupleFunction(result, sampler.peekVoxel1nx1py1nz());
result = cantorTupleFunction(result, sampler.peekVoxel0px1py1nz());
result = cantorTupleFunction(result, sampler.peekVoxel1px1py1nz());
result = cantorTupleFunction(result, sampler.peekVoxel1nx1ny0pz());
result = cantorTupleFunction(result, sampler.peekVoxel0px1ny0pz());
result = cantorTupleFunction(result, sampler.peekVoxel1px1ny0pz());
result = cantorTupleFunction(result, sampler.peekVoxel1nx0py0pz());
result = cantorTupleFunction(result, sampler.peekVoxel0px0py0pz());
result = cantorTupleFunction(result, sampler.peekVoxel1px0py0pz());
result = cantorTupleFunction(result, sampler.peekVoxel1nx1py0pz());
result = cantorTupleFunction(result, sampler.peekVoxel0px1py0pz());
result = cantorTupleFunction(result, sampler.peekVoxel1px1py0pz());
result = cantorTupleFunction(result, sampler.peekVoxel1nx1ny1pz());
result = cantorTupleFunction(result, sampler.peekVoxel0px1ny1pz());
result = cantorTupleFunction(result, sampler.peekVoxel1px1ny1pz());
result = cantorTupleFunction(result, sampler.peekVoxel1nx0py1pz());
result = cantorTupleFunction(result, sampler.peekVoxel0px0py1pz());
result = cantorTupleFunction(result, sampler.peekVoxel1px0py1pz());
result = cantorTupleFunction(result, sampler.peekVoxel1nx1py1pz());
result = cantorTupleFunction(result, sampler.peekVoxel0px1py1pz());
result = cantorTupleFunction(result, sampler.peekVoxel1px1py1pz());
}
}
}
return result;
}
template <typename VolumeType>
int32_t complexVolumeTest(void)
{
VolumeType* testVolume = createAndFillVolume<VolumeType>();
int32_t result = 0;
//Test the getVoxel function
for(int z = testVolume->getEnclosingRegion().getLowerZ(); z <= testVolume->getEnclosingRegion().getUpperZ(); z++)
{
for(int y = testVolume->getEnclosingRegion().getLowerY(); y <= testVolume->getEnclosingRegion().getUpperY(); y++)
{
for(int x = testVolume->getEnclosingRegion().getLowerX(); x <= testVolume->getEnclosingRegion().getUpperX(); x++)
{
result = cantorTupleFunction(result, testVolume->getVoxel(x, y, z));
}
}
}
//Test border wrap mode
for(int z = testVolume->getEnclosingRegion().getLowerZ(); z <= testVolume->getEnclosingRegion().getUpperZ(); z++)
{
//Extending outside in y
for(int y = testVolume->getEnclosingRegion().getLowerY() - 3; y <= testVolume->getEnclosingRegion().getUpperY() + 5; y++)
{
for(int x = testVolume->getEnclosingRegion().getLowerX(); x <= testVolume->getEnclosingRegion().getUpperX(); x++)
{
result = cantorTupleFunction(result, testVolume->getVoxelWithWrapping(x, y, z, WrapModes::Border, 3));
}
}
}
//Test clamp wrap mode
for(int z = testVolume->getEnclosingRegion().getLowerZ(); z <= testVolume->getEnclosingRegion().getUpperZ(); z++)
{
for(int y = testVolume->getEnclosingRegion().getLowerY(); y <= testVolume->getEnclosingRegion().getUpperY(); y++)
{
//Extending outside in x
for(int x = testVolume->getEnclosingRegion().getLowerX() - 2; x <= testVolume->getEnclosingRegion().getUpperX() + 4; x++)
{
result = cantorTupleFunction(result, testVolume->getVoxelWithWrapping(x, y, z, WrapModes::Clamp));
}
}
}
//Test the sampler setPosition
typename VolumeType::Sampler sampler(testVolume);
sampler.setWrapMode(WrapModes::Border, 1);
for(int z = testVolume->getEnclosingRegion().getLowerZ() - 2; z <= testVolume->getEnclosingRegion().getUpperZ() + 1; z++)
{
for(int y = testVolume->getEnclosingRegion().getLowerY() - 1; y <= testVolume->getEnclosingRegion().getUpperY() + 3; y++)
{
for(int x = testVolume->getEnclosingRegion().getLowerX() - 4; x <= testVolume->getEnclosingRegion().getUpperX() + 2; x++)
{
sampler.setPosition(x,y,z);
result = cantorTupleFunction(result, sampler.getVoxel());
}
}
}
//Test the sampler move functions
typename VolumeType::Sampler xSampler(testVolume);
typename VolumeType::Sampler ySampler(testVolume);
typename VolumeType::Sampler zSampler(testVolume);
xSampler.setWrapMode(WrapModes::Border, 1);
ySampler.setWrapMode(WrapModes::Clamp, 1);
zSampler.setWrapMode(WrapModes::Border, -3);
zSampler.setPosition(testVolume->getEnclosingRegion().getLowerX() - 4, testVolume->getEnclosingRegion().getLowerY() - 1, testVolume->getEnclosingRegion().getLowerZ() - 2);
for(int z = testVolume->getEnclosingRegion().getLowerZ() - 2; z <= testVolume->getEnclosingRegion().getUpperZ() + 1; z++)
{
ySampler = zSampler;
for(int y = testVolume->getEnclosingRegion().getLowerY() - 1; y <= testVolume->getEnclosingRegion().getUpperY() + 3; y++)
{
xSampler = ySampler;
for(int x = testVolume->getEnclosingRegion().getLowerX() - 4; x <= testVolume->getEnclosingRegion().getUpperX() + 2; x++)
{
result = cantorTupleFunction(result, xSampler.getVoxel());
xSampler.movePositiveX();
}
ySampler.movePositiveY();
}
zSampler.movePositiveZ();
}
xSampler.setWrapMode(WrapModes::Clamp);
ySampler.setWrapMode(WrapModes::Border, 1);
zSampler.setWrapMode(WrapModes::Clamp, -1);
zSampler.setPosition(testVolume->getEnclosingRegion().getUpperX() + 2, testVolume->getEnclosingRegion().getUpperY() + 3, testVolume->getEnclosingRegion().getUpperZ() + 1);
for(int z = 0; z < testVolume->getEnclosingRegion().getDepthInVoxels() + 8; z++)
{
ySampler = zSampler;
for(int y = 0; y < testVolume->getEnclosingRegion().getHeightInVoxels() + 3; y++)
{
xSampler = ySampler;
for(int x = 0; x < testVolume->getEnclosingRegion().getWidthInVoxels() + 5; x++)
{
result = cantorTupleFunction(result, xSampler.getVoxel());
xSampler.moveNegativeX();
}
ySampler.moveNegativeY();
}
zSampler.moveNegativeZ();
}
delete testVolume;
return result;
}
TestVolume::TestVolume()
{
Region region(-57, -31, 12, 64, 96, 131); // Deliberatly awkward size
//Create the volumes
m_pRawVolume = new RawVolume<int32_t>(region);
m_pSimpleVolume = new SimpleVolume<int32_t>(region);
m_pLargeVolume = new LargeVolume<int32_t>(region);
//Fill the volume with some data
for(int z = region.getLowerZ(); z <= region.getUpperZ(); z++)
{
for(int y = region.getLowerY(); y <= region.getUpperY(); y++)
{
for(int x = region.getLowerX(); x <= region.getUpperX(); x++)
{
int32_t value = x + y + z;
m_pRawVolume->setVoxelAt(x, y, z, value);
m_pSimpleVolume->setVoxelAt(x, y, z, value);
m_pLargeVolume->setVoxelAt(x, y, z, value);
}
}
}
}
TestVolume::~TestVolume()
{
delete m_pRawVolume;
delete m_pSimpleVolume;
delete m_pLargeVolume;
}
void TestVolume::testRawVolumeDirectAccess()
{
int32_t result = 0;
QBENCHMARK
{
result = testDirectAccessWithWrapping(m_pRawVolume);
}
QCOMPARE(result, static_cast<int32_t>(-928601007));
}
void TestVolume::testRawVolumeSamplers()
{
int32_t result = 0;
QBENCHMARK
{
result = testSamplersWithWrapping(m_pRawVolume);
}
QCOMPARE(result, static_cast<int32_t>(-928601007));
}
void TestVolume::testSimpleVolumeDirectAccess()
{
int32_t result = 0;
QBENCHMARK
{
result = testDirectAccessWithWrapping(m_pSimpleVolume);
}
QCOMPARE(result, static_cast<int32_t>(-928601007));
}
void TestVolume::testSimpleVolumeSamplers()
{
int32_t result = 0;
QBENCHMARK
{
result = testSamplersWithWrapping(m_pSimpleVolume);
}
QCOMPARE(result, static_cast<int32_t>(-928601007));
}
void TestVolume::testLargeVolumeDirectAccess()
{
int32_t result = 0;
QBENCHMARK
{
result = testDirectAccessWithWrapping(m_pLargeVolume);
}
QCOMPARE(result, static_cast<int32_t>(-928601007));
}
void TestVolume::testLargeVolumeSamplers()
{
int32_t result = 0;
QBENCHMARK
{
result = testSamplersWithWrapping(m_pLargeVolume);
}
QCOMPARE(result, static_cast<int32_t>(-928601007));
}
QTEST_MAIN(TestVolume)

View File

@ -24,14 +24,32 @@ freely, subject to the following restrictions:
#ifndef __PolyVox_TestVolume_H__
#define __PolyVox_TestVolume_H__
#include "PolyVoxCore/PolyVoxForwardDeclarations.h"
#include <QObject>
class TestVolume: public QObject
{
Q_OBJECT
private slots:
void testSize();
public:
TestVolume();
~TestVolume();
private slots:
void testRawVolumeDirectAccess();
void testRawVolumeSamplers();
void testSimpleVolumeDirectAccess();
void testSimpleVolumeSamplers();
void testLargeVolumeDirectAccess();
void testLargeVolumeSamplers();
private:
PolyVox::RawVolume<int32_t>* m_pRawVolume;
PolyVox::SimpleVolume<int32_t>* m_pSimpleVolume;
PolyVox::LargeVolume<int32_t>* m_pLargeVolume;
};
#endif