diff --git a/examples/OpenGL/OpenGLWidget.cpp b/examples/OpenGL/OpenGLWidget.cpp index 3a36fd3b..2d91eac3 100644 --- a/examples/OpenGL/OpenGLWidget.cpp +++ b/examples/OpenGL/OpenGLWidget.cpp @@ -26,6 +26,7 @@ freely, subject to the following restrictions: #include #include "GradientEstimators.h" +#include "MaterialDensityPair.h" #include "SurfaceExtractor.h" #include "Mesh.h" @@ -48,7 +49,7 @@ OpenGLWidget::OpenGLWidget(QWidget *parent) timer->start(0); } -void OpenGLWidget::setVolume(PolyVox::Volume* volData) +void OpenGLWidget::setVolume(PolyVox::Volume* volData) { //First we free anything from the previous volume (if there was one). m_mapOpenGLSurfaceMeshes.clear(); @@ -62,7 +63,7 @@ void OpenGLWidget::setVolume(PolyVox::Volume* volData) m_uVolumeHeightInRegions = volData->getHeight() / m_uRegionSideLength; m_uVolumeDepthInRegions = volData->getDepth() / m_uRegionSideLength; - SurfaceExtractor surfaceExtractor(*volData); + SurfaceExtractor surfaceExtractor(*volData); //Our volume is broken down into cuboid regions, and we create one mesh for each region. //This three-level for loop iterates over each region. diff --git a/examples/OpenGL/OpenGLWidget.h b/examples/OpenGL/OpenGLWidget.h index 962950f5..5c85898a 100644 --- a/examples/OpenGL/OpenGLWidget.h +++ b/examples/OpenGL/OpenGLWidget.h @@ -45,7 +45,7 @@ class OpenGLWidget : public QGLWidget public: OpenGLWidget(QWidget *parent); - void setVolume(PolyVox::Volume* volData); + void setVolume(PolyVox::Volume* volData); void mouseMoveEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); @@ -69,7 +69,7 @@ class OpenGLWidget : public QGLWidget bool m_bUseOpenGLVertexBufferObjects; //Creates a volume 128x128x128 - PolyVox::Volume* m_volData; + PolyVox::Volume* m_volData; //Rather than storing one big mesh, the volume is broken into regions and a mesh is stored for each region std::map m_mapOpenGLSurfaceMeshes; diff --git a/examples/OpenGL/Shapes.cpp b/examples/OpenGL/Shapes.cpp index 49afa754..c5e14356 100644 --- a/examples/OpenGL/Shapes.cpp +++ b/examples/OpenGL/Shapes.cpp @@ -23,9 +23,11 @@ freely, subject to the following restrictions: #include "Shapes.h" +#include "MaterialDensityPair.h" + using namespace PolyVox; -void createSphereInVolume(Volume& volData, float fRadius, uint8_t uValue) +void createSphereInVolume(Volume& volData, float fRadius, uint8_t uValue) { //This vector hold the position of the center of the volume Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); @@ -46,14 +48,14 @@ void createSphereInVolume(Volume& volData, float fRadius, uint8_t uValu //then we make it solid, otherwise we make it empty space. if(fDistToCenter <= fRadius) { - volData.setVoxelAt(x,y,z, uValue); + volData.setVoxelAt(x,y,z, MaterialDensityPair44(uValue, uValue > 0 ? MaterialDensityPair44::getMaxDensity() : MaterialDensityPair44::getMinDensity())); } } } } } -void createCubeInVolume(Volume& volData, Vector3DUint16 lowerCorner, Vector3DUint16 upperCorner, uint8_t uValue) +void createCubeInVolume(Volume& volData, Vector3DUint16 lowerCorner, Vector3DUint16 upperCorner, uint8_t uValue) { //This three-level for loop iterates over every voxel between the specified corners for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++) @@ -62,7 +64,7 @@ void createCubeInVolume(Volume& volData, Vector3DUint16 lowerCorner, Ve { for (int x = lowerCorner.getX() ; x <= upperCorner.getX(); x++) { - volData.setVoxelAt(x,y,z, uValue); + volData.setVoxelAt(x,y,z, MaterialDensityPair44(uValue, uValue > 0 ? MaterialDensityPair44::getMaxDensity() : MaterialDensityPair44::getMinDensity())); } } } diff --git a/examples/OpenGL/Shapes.h b/examples/OpenGL/Shapes.h index 3ca18f48..4f054de5 100644 --- a/examples/OpenGL/Shapes.h +++ b/examples/OpenGL/Shapes.h @@ -24,9 +24,10 @@ freely, subject to the following restrictions: #ifndef __OpenGLExample_Shapes_H__ #define __OpenGLExample_Shapes_H__ +#include "PolyVoxForwardDeclarations.h" #include "Volume.h" -void createSphereInVolume(PolyVox::Volume& volData, float fRadius, uint8_t uValue); -void createCubeInVolume(PolyVox::Volume& volData, PolyVox::Vector3DUint16 lowerCorner, PolyVox::Vector3DUint16 upperCorner, uint8_t uValue); +void createSphereInVolume(PolyVox::Volume& volData, float fRadius, uint8_t uValue); +void createCubeInVolume(PolyVox::Volume& volData, PolyVox::Vector3DUint16 lowerCorner, PolyVox::Vector3DUint16 upperCorner, uint8_t uValue); #endif //__OpenGLExample_Shapes_H__ \ No newline at end of file diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index ade5002d..4d79c8ae 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -22,6 +22,7 @@ freely, subject to the following restrictions: *******************************************************************************/ #include "Log.h" +#include "MaterialDensityPair.h" #include "Volume.h" #include "SurfaceMesh.h" #include "PolyVoxImpl/Utility.h" @@ -70,7 +71,8 @@ void exampleLog(string message, int severity) int main(int argc, char *argv[]) { logHandler = &exampleLog; - Volume volData(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength); + Volume volData(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength); + Volume volDataAveraged(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength); //Make our volume contain a sphere in the center. uint16_t minPos = 0; @@ -106,14 +108,75 @@ int main(int argc, char *argv[]) createCubeInVolume(volData, Vector3DUint16(midPos+1, minPos, midPos+1), Vector3DUint16(maxPos, midPos-1, maxPos), 0); createCubeInVolume(volData, Vector3DUint16(minPos, midPos+1, midPos+1), Vector3DUint16(midPos-1, maxPos, maxPos), 0); - createCubeInVolume(volData, Vector3DUint16(1, midPos-10, midPos-10), Vector3DUint16(maxPos-1, midPos+10, midPos+10), 255); - createCubeInVolume(volData, Vector3DUint16(midPos-10, 1, midPos-10), Vector3DUint16(midPos+10, maxPos-1, midPos+10), 255); - createCubeInVolume(volData, Vector3DUint16(midPos-10, midPos-10 ,1), Vector3DUint16(midPos+10, midPos+10, maxPos-1), 255); + createCubeInVolume(volData, Vector3DUint16(1, midPos-10, midPos-10), Vector3DUint16(maxPos-1, midPos+10, midPos+10), MaterialDensityPair44::getMaxDensity()); + createCubeInVolume(volData, Vector3DUint16(midPos-10, 1, midPos-10), Vector3DUint16(midPos+10, maxPos-1, midPos+10), MaterialDensityPair44::getMaxDensity()); + createCubeInVolume(volData, Vector3DUint16(midPos-10, midPos-10 ,1), Vector3DUint16(midPos+10, midPos+10, maxPos-1), MaterialDensityPair44::getMaxDensity()); //createCubeInVolume(volData, Vector3DUint16(1, 1, 1), Vector3DUint16(maxPos-1, maxPos-1, midPos/4), 255); + for (int z = 1; z < volData.getWidth()-1; z++) + { + for (int y = 1; y < volData.getHeight()-1; y++) + { + for (int x = 1; x < volData.getDepth()-1; x++) + { + int uDensity = 0; + uDensity += volData.getVoxelAt(x-1,y-1,z-1).getDensity(); + uDensity += volData.getVoxelAt(x-1,y-1,z-0).getDensity(); + uDensity += volData.getVoxelAt(x-1,y-1,z+1).getDensity(); + uDensity += volData.getVoxelAt(x-1,y-0,z-1).getDensity(); + uDensity += volData.getVoxelAt(x-1,y-0,z-0).getDensity(); + uDensity += volData.getVoxelAt(x-1,y-0,z+1).getDensity(); + uDensity += volData.getVoxelAt(x-1,y+1,z-1).getDensity(); + uDensity += volData.getVoxelAt(x-1,y+1,z-0).getDensity(); + uDensity += volData.getVoxelAt(x-1,y+1,z+1).getDensity(); + + uDensity += volData.getVoxelAt(x-0,y-1,z-1).getDensity(); + uDensity += volData.getVoxelAt(x-0,y-1,z-0).getDensity(); + uDensity += volData.getVoxelAt(x-0,y-1,z+1).getDensity(); + uDensity += volData.getVoxelAt(x-0,y-0,z-1).getDensity(); + uDensity += volData.getVoxelAt(x-0,y-0,z-0).getDensity(); + uDensity += volData.getVoxelAt(x-0,y-0,z+1).getDensity(); + uDensity += volData.getVoxelAt(x-0,y+1,z-1).getDensity(); + uDensity += volData.getVoxelAt(x-0,y+1,z-0).getDensity(); + uDensity += volData.getVoxelAt(x-0,y+1,z+1).getDensity(); + + uDensity += volData.getVoxelAt(x+1,y-1,z-1).getDensity(); + uDensity += volData.getVoxelAt(x+1,y-1,z-0).getDensity(); + uDensity += volData.getVoxelAt(x+1,y-1,z+1).getDensity(); + uDensity += volData.getVoxelAt(x+1,y-0,z-1).getDensity(); + uDensity += volData.getVoxelAt(x+1,y-0,z-0).getDensity(); + uDensity += volData.getVoxelAt(x+1,y-0,z+1).getDensity(); + uDensity += volData.getVoxelAt(x+1,y+1,z-1).getDensity(); + uDensity += volData.getVoxelAt(x+1,y+1,z-0).getDensity(); + uDensity += volData.getVoxelAt(x+1,y+1,z+1).getDensity(); + uDensity /= 27; + + MaterialDensityPair44 val = volData.getVoxelAt(x,y,z); + val.setDensity(uDensity); + + volDataAveraged.setVoxelAt(x,y,z,val); + } + } + } + + /*std::vector counts(256); + fill(counts.begin(), counts.end(), 0); + + for (int z = 0; z < volData.getWidth(); z++) + { + for (int y = 0; y < volData.getHeight(); y++) + { + for (int x = 0; x < volData.getDepth(); x++) + { + counts[volData.getVoxelAt(x,y,z).getMaterial()]++; + } + } + }*/ + cout << "Tidying memory..."; volData.tidyUpMemory(0); + volDataAveraged.tidyUpMemory(0); cout << "done." << endl; QApplication app(argc, argv); @@ -125,7 +188,7 @@ int main(int argc, char *argv[]) QTime time; time.start(); - openGLWidget.setVolume(&volData); + openGLWidget.setVolume(&volDataAveraged); cout << endl << "Time taken = " << time.elapsed() / 1000.0f << "s" << endl << endl; //return 0; diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index 4fb722b6..3d5ef2e8 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -4,6 +4,7 @@ PROJECT(PolyVoxCore) #Projects source files SET(CORE_SRC_FILES + source/ArraySizes.cpp source/GradientEstimators.cpp source/SurfaceMesh.cpp source/Log.cpp @@ -12,7 +13,6 @@ SET(CORE_SRC_FILES source/MeshFace.cpp source/MeshVertex.cpp source/Region.cpp - source/SurfaceExtractor.cpp source/SurfaceVertex.cpp source/VoxelFilters.cpp ) @@ -22,10 +22,10 @@ SET(CORE_INC_FILES include/Array.h include/Array.inl include/ArraySizes.h - include/ArraySizes.inl include/GradientEstimators.inl - include/SurfaceMesh.h include/Log.h + include/MaterialDensityPair.h + include/MaterialDensityPair.inl include/Mesh.h include/MeshEdge.h include/MeshFace.h @@ -33,6 +33,8 @@ SET(CORE_INC_FILES include/PolyVoxForwardDeclarations.h include/Region.h include/SurfaceExtractor.h + include/SurfaceExtractor.inl + include/SurfaceMesh.h include/SurfaceVertex.h include/Vector.h include/Vector.inl diff --git a/library/PolyVoxCore/include/ArraySizes.h b/library/PolyVoxCore/include/ArraySizes.h index a0621e7c..335fe7ae 100644 --- a/library/PolyVoxCore/include/ArraySizes.h +++ b/library/PolyVoxCore/include/ArraySizes.h @@ -77,6 +77,4 @@ namespace PolyVox }; }//namespace PolyVox -#include "ArraySizes.inl" - #endif //__PolyVox_ArraySizes_H__ \ No newline at end of file diff --git a/library/PolyVoxCore/include/MaterialDensityPair.h b/library/PolyVoxCore/include/MaterialDensityPair.h new file mode 100644 index 00000000..1c4f0c73 --- /dev/null +++ b/library/PolyVoxCore/include/MaterialDensityPair.h @@ -0,0 +1,69 @@ +#pragma region License +/******************************************************************************* +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. +*******************************************************************************/ +#pragma endregion + +#ifndef __PolyVox_MaterialDensityPair_H__ +#define __PolyVox_MaterialDensityPair_H__ + +#pragma region Headers +#include "PolyVoxForwardDeclarations.h" +#include "PolyVoxImpl/TypeDef.h" +#pragma endregion + +namespace PolyVox +{ + template + class MaterialDensityPair + { + public: + MaterialDensityPair(); + MaterialDensityPair(Type uMaterial, Type uDensity); + + //Why are both of these needed?! + bool operator==(const MaterialDensityPair& rhs) const throw(); + bool operator!=(const MaterialDensityPair& rhs) const throw(); + + bool operator<(const MaterialDensityPair& rhs) const throw(); + + Type getDensity() const throw(); + Type getMaterial() const throw(); + + void setDensity(Type uDensity); + void setMaterial(Type uMaterial); + + static Type getMaxDensity() throw(); + static Type getMinDensity() throw(); + static Type getMidDensity() throw(); + + private: + Type m_uMaterial : NoOfMaterialBits; + Type m_uDensity : NoOfDensityBits; + }; + + typedef MaterialDensityPair MaterialDensityPair44; +} + +#include "MaterialDensityPair.inl" + +#endif \ No newline at end of file diff --git a/library/PolyVoxCore/include/MaterialDensityPair.inl b/library/PolyVoxCore/include/MaterialDensityPair.inl new file mode 100644 index 00000000..a63d6959 --- /dev/null +++ b/library/PolyVoxCore/include/MaterialDensityPair.inl @@ -0,0 +1,114 @@ +#pragma region License +/******************************************************************************* +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. +*******************************************************************************/ +#pragma endregion + +#pragma region Headers +#pragma endregion + +namespace PolyVox +{ + template + MaterialDensityPair::MaterialDensityPair() + :m_uMaterial(0) + ,m_uDensity(0) + { + } + + template + MaterialDensityPair::MaterialDensityPair(Type uMaterial, Type uDensity) + :m_uMaterial(uMaterial) + ,m_uDensity(uDensity) + { + } + + template + bool MaterialDensityPair::operator==(const MaterialDensityPair& rhs) const throw() + { + return (m_uMaterial == rhs.m_uMaterial) && (m_uDensity == rhs.m_uDensity); + } + + template + bool MaterialDensityPair::operator!=(const MaterialDensityPair& rhs) const throw() + { + return !(*this == rhs); + } + + template + bool MaterialDensityPair::operator<(const MaterialDensityPair& rhs) const throw() + { + if (m_uMaterial < rhs.m_uMaterial) + return true; + if (rhs.m_uMaterial < m_uMaterial) + return false; + if (m_uDensity < rhs.m_uDensity) + return true; + if (rhs.m_uDensity < m_uDensity) + return false; + + return false; + //return m_uMaterial < rhs.m_uMaterial; + } + + template + Type MaterialDensityPair::getDensity() const throw() + { + return m_uDensity; + } + + template + Type MaterialDensityPair::getMaterial() const throw() + { + return m_uMaterial; + } + + template + void MaterialDensityPair::setDensity(Type uDensity) + { + m_uDensity = uDensity; + } + + template + void MaterialDensityPair::setMaterial(Type uMaterial) + { + m_uMaterial = uMaterial; + } + + template + Type MaterialDensityPair::getMaxDensity() throw() + { + return (0x01 << NoOfDensityBits) - 1; + } + + template + Type MaterialDensityPair::getMinDensity() throw() + { + return 0; + } + + template + Type MaterialDensityPair::getMidDensity() throw() + { + return 0x01 << (NoOfDensityBits - 1); + } +} diff --git a/library/PolyVoxCore/include/PolyVoxForwardDeclarations.h b/library/PolyVoxCore/include/PolyVoxForwardDeclarations.h index 77e8035b..c5c3835e 100644 --- a/library/PolyVoxCore/include/PolyVoxForwardDeclarations.h +++ b/library/PolyVoxCore/include/PolyVoxForwardDeclarations.h @@ -76,10 +76,13 @@ namespace PolyVox class MeshVertex; //--------------------------------- + template class MaterialDensityPair; + typedef MaterialDensityPair MaterialDensityPair44; + class SurfaceMesh; class Region; class SurfaceVertex; - class SurfaceExtractor; + template class SurfaceExtractor; //---------- Vector ---------- template class Vector; diff --git a/library/PolyVoxCore/include/PolyVoxImpl/ArraySizesImpl.inl b/library/PolyVoxCore/include/PolyVoxImpl/ArraySizesImpl.inl index 168d8ad3..613d3dc0 100644 --- a/library/PolyVoxCore/include/PolyVoxImpl/ArraySizesImpl.inl +++ b/library/PolyVoxCore/include/PolyVoxImpl/ArraySizesImpl.inl @@ -23,6 +23,8 @@ distribution. *******************************************************************************/ #pragma endregion +#include + namespace PolyVox { template diff --git a/library/PolyVoxCore/include/PolyVoxImpl/MarchingCubesTables.h b/library/PolyVoxCore/include/PolyVoxImpl/MarchingCubesTables.h index 4cadc035..946bc472 100644 --- a/library/PolyVoxCore/include/PolyVoxImpl/MarchingCubesTables.h +++ b/library/PolyVoxCore/include/PolyVoxImpl/MarchingCubesTables.h @@ -26,10 +26,12 @@ freely, subject to the following restrictions: #ifndef __PolyVox_MarchingCubeTables_H__ #define __PolyVox_MarchingCubeTables_H__ +#include "TypeDef.h" + namespace PolyVox { - extern int edgeTable[256]; - extern int triTable[256][16]; + extern POLYVOXCORE_API int edgeTable[256]; + extern POLYVOXCORE_API int triTable[256][16]; } #endif diff --git a/library/PolyVoxCore/include/SurfaceExtractor.h b/library/PolyVoxCore/include/SurfaceExtractor.h index f5da3089..f0650da7 100644 --- a/library/PolyVoxCore/include/SurfaceExtractor.h +++ b/library/PolyVoxCore/include/SurfaceExtractor.h @@ -35,10 +35,11 @@ freely, subject to the following restrictions: namespace PolyVox { - class POLYVOXCORE_API SurfaceExtractor + template + class SurfaceExtractor { public: - SurfaceExtractor(Volume& volData); + SurfaceExtractor(Volume& volData); std::shared_ptr extractSurfaceForRegion(Region region); @@ -57,6 +58,9 @@ namespace PolyVox Array2DInt32& m_pCurrentVertexIndicesY, Array2DInt32& m_pCurrentVertexIndicesZ); + Vector3DFloat computeCentralDifferenceGradient(const VolumeSampler& volIter); + Vector3DFloat computeSobelGradient(const VolumeSampler& volIter); + //Use the cell bitmasks to generate all the indices needed for that slice void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, const Array2DInt32& m_pPreviousVertexIndicesX, @@ -73,8 +77,8 @@ namespace PolyVox } //The volume data and a sampler to access it. - Volume m_volData; - VolumeSampler m_sampVolume; + Volume m_volData; + VolumeSampler m_sampVolume; //Used to keep track of where generated vertices have been placed. /*int32_t* m_pPreviousVertexIndicesX; @@ -125,4 +129,6 @@ namespace PolyVox }; } +#include "SurfaceExtractor.inl" + #endif diff --git a/library/PolyVoxCore/source/SurfaceExtractor.cpp b/library/PolyVoxCore/include/SurfaceExtractor.inl similarity index 65% rename from library/PolyVoxCore/source/SurfaceExtractor.cpp rename to library/PolyVoxCore/include/SurfaceExtractor.inl index 4eaff355..b8a3703e 100644 --- a/library/PolyVoxCore/source/SurfaceExtractor.cpp +++ b/library/PolyVoxCore/include/SurfaceExtractor.inl @@ -21,9 +21,8 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ -#include "SurfaceExtractor.h" - #include "Array.h" +#include "MaterialDensityPair.h" #include "SurfaceMesh.h" #include "PolyVoxImpl/MarchingCubesTables.h" #include "SurfaceVertex.h" @@ -32,13 +31,15 @@ using namespace std; namespace PolyVox { - SurfaceExtractor::SurfaceExtractor(Volume& volData) + template + SurfaceExtractor::SurfaceExtractor(Volume& volData) :m_volData(volData) ,m_sampVolume(&volData) { } - shared_ptr SurfaceExtractor::extractSurfaceForRegion(Region region) + template + shared_ptr SurfaceExtractor::extractSurfaceForRegion(Region region) { m_regInputUncropped = region; @@ -153,8 +154,9 @@ namespace PolyVox return shared_ptr(m_meshCurrent); } + template template - uint32_t SurfaceExtractor::computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) + uint32_t SurfaceExtractor::computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) { m_uNoOfOccupiedCells = 0; @@ -218,19 +220,20 @@ namespace PolyVox return m_uNoOfOccupiedCells; } + template template - void SurfaceExtractor::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) + void SurfaceExtractor::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) { uint8_t iCubeIndex = 0; - uint8_t v000 = 0; - uint8_t v100 = 0; - uint8_t v010 = 0; - uint8_t v110 = 0; - uint8_t v001 = 0; - uint8_t v101 = 0; - uint8_t v011 = 0; - uint8_t v111 = 0; + VoxelType v000; + VoxelType v100; + VoxelType v010; + VoxelType v110; + VoxelType v001; + VoxelType v101; + VoxelType v011; + VoxelType v111; if(isPrevZAvail) { @@ -256,7 +259,7 @@ namespace PolyVox iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; - if (v111 == 0) iCubeIndex |= 128; + if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128; } else //previous X not available { @@ -274,8 +277,8 @@ namespace PolyVox iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ; - if (v011 == 0) iCubeIndex |= 64; - if (v111 == 0) iCubeIndex |= 128; + if (v011.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 64; + if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128; } } else //previous Y not available @@ -296,8 +299,8 @@ namespace PolyVox iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ; - if (v101 == 0) iCubeIndex |= 32; - if (v111 == 0) iCubeIndex |= 128; + if (v101.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 32; + if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128; } else //previous X not available { @@ -310,10 +313,10 @@ namespace PolyVox uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; iCubeIndex = iPreviousCubeIndexZ >> 4; - if (v001 == 0) iCubeIndex |= 16; - if (v101 == 0) iCubeIndex |= 32; - if (v011 == 0) iCubeIndex |= 64; - if (v111 == 0) iCubeIndex |= 128; + if (v001.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 16; + if (v101.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 32; + if (v011.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 64; + if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128; } } } @@ -338,8 +341,8 @@ namespace PolyVox iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY; - if (v110 == 0) iCubeIndex |= 8; - if (v111 == 0) iCubeIndex |= 128; + if (v110.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 8; + if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128; } else //previous X not available { @@ -356,10 +359,10 @@ namespace PolyVox iCubeIndex = iPreviousCubeIndexY; - if (v010 == 0) iCubeIndex |= 4; - if (v110 == 0) iCubeIndex |= 8; - if (v011 == 0) iCubeIndex |= 64; - if (v111 == 0) iCubeIndex |= 128; + if (v010.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 4; + if (v110.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 8; + if (v011.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 64; + if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128; } } else //previous Y not available @@ -379,10 +382,10 @@ namespace PolyVox iCubeIndex = iPreviousCubeIndexX; - if (v100 == 0) iCubeIndex |= 2; - if (v110 == 0) iCubeIndex |= 8; - if (v101 == 0) iCubeIndex |= 32; - if (v111 == 0) iCubeIndex |= 128; + if (v100.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 2; + if (v110.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 8; + if (v101.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 32; + if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128; } else //previous X not available { @@ -396,14 +399,14 @@ namespace PolyVox v011 = m_sampVolume.peekVoxel0px1py1pz(); v111 = m_sampVolume.peekVoxel1px1py1pz(); - if (v000 == 0) iCubeIndex |= 1; - if (v100 == 0) iCubeIndex |= 2; - if (v010 == 0) iCubeIndex |= 4; - if (v110 == 0) iCubeIndex |= 8; - if (v001 == 0) iCubeIndex |= 16; - if (v101 == 0) iCubeIndex |= 32; - if (v011 == 0) iCubeIndex |= 64; - if (v111 == 0) iCubeIndex |= 128; + if (v000.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 1; + if (v100.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 2; + if (v010.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 4; + if (v110.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 8; + if (v001.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 16; + if (v101.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 32; + if (v011.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 64; + if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128; } } } @@ -417,7 +420,8 @@ namespace PolyVox } } - void SurfaceExtractor::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, + template + void SurfaceExtractor::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, Array2DInt32& m_pCurrentVertexIndicesX, Array2DInt32& m_pCurrentVertexIndicesY, Array2DInt32& m_pCurrentVertexIndicesZ) @@ -457,16 +461,28 @@ namespace PolyVox m_sampVolume.setPosition(uXVolSpace,uYVolSpace,uZVolSpace); - const uint8_t v000 = m_sampVolume.getVoxel(); + const VoxelType v000 = m_sampVolume.getVoxel(); + const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { m_sampVolume.movePositiveX(); - const uint8_t v100 = m_sampVolume.getVoxel(); - const Vector3DFloat v3dPosition(static_cast(uXVolSpace - m_regInputCropped.getLowerCorner().getX()) + 0.5f, static_cast(uYVolSpace - m_regInputCropped.getLowerCorner().getY()), static_cast(uZVolSpace - m_regInputCropped.getLowerCorner().getZ())); - const Vector3DFloat v3dNormal(v000 > v100 ? 1.0f : -1.0f,0.0,0.0); - const uint8_t uMaterial = v000 | v100; //Because one of these is 0, the or operation takes the max. + const VoxelType v100 = m_sampVolume.getVoxel(); + const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); + + //float fInterp = static_cast(v100.getDensity() - VoxelType::getMinDensity()) / static_cast(VoxelType::getMaxDensity() - VoxelType::getMinDensity()); + float fInterp = static_cast(VoxelType::getMidDensity() - v000.getDensity()) / static_cast(v100.getDensity() - v000.getDensity()); + //fInterp = 0.5f; + + const Vector3DFloat v3dPosition(static_cast(uXVolSpace - m_regInputCropped.getLowerCorner().getX()) + fInterp, static_cast(uYVolSpace - m_regInputCropped.getLowerCorner().getY()), static_cast(uZVolSpace - m_regInputCropped.getLowerCorner().getZ())); + //const Vector3DFloat v3dNormal(v000.getDensity() > v100.getDensity() ? 1.0f : -1.0f,0.0,0.0); + + Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp)); + v3dNormal.normalise(); + + const uint8_t uMaterial = v000.getMaterial() | v100.getMaterial(); //Because one of these is 0, the or operation takes the max. + SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); //surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge); surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge); @@ -481,10 +497,20 @@ namespace PolyVox if (edgeTable[iCubeIndex] & 8) { m_sampVolume.movePositiveY(); - const uint8_t v010 = m_sampVolume.getVoxel(); - const Vector3DFloat v3dPosition(static_cast(uXVolSpace - m_regInputCropped.getLowerCorner().getX()), static_cast(uYVolSpace - m_regInputCropped.getLowerCorner().getY()) + 0.5f, static_cast(uZVolSpace - m_regInputCropped.getLowerCorner().getZ())); - const Vector3DFloat v3dNormal(0.0,v000 > v010 ? 1.0f : -1.0f,0.0); - const uint8_t uMaterial = v000 | v010; //Because one of these is 0, the or operation takes the max. + const VoxelType v010 = m_sampVolume.getVoxel(); + const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); + + float fInterp = static_cast(VoxelType::getMidDensity() - v000.getDensity()) / static_cast(v010.getDensity() - v000.getDensity()); + //fInterp = 0.5f; + + const Vector3DFloat v3dPosition(static_cast(uXVolSpace - m_regInputCropped.getLowerCorner().getX()), static_cast(uYVolSpace - m_regInputCropped.getLowerCorner().getY()) + fInterp, static_cast(uZVolSpace - m_regInputCropped.getLowerCorner().getZ())); + //const Vector3DFloat v3dNormal(0.0,v000.getDensity() > v010.getDensity() ? 1.0f : -1.0f,0.0); + + Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp)); + v3dNormal.normalise(); + + const uint8_t uMaterial = v000.getMaterial() | v010.getMaterial(); //Because one of these is 0, the or operation takes the max. + SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); //surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge); surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge); @@ -499,10 +525,20 @@ namespace PolyVox if (edgeTable[iCubeIndex] & 256) { m_sampVolume.movePositiveZ(); - const uint8_t v001 = m_sampVolume.getVoxel(); - const Vector3DFloat v3dPosition(static_cast(uXVolSpace - m_regInputCropped.getLowerCorner().getX()), static_cast(uYVolSpace - m_regInputCropped.getLowerCorner().getY()), static_cast(uZVolSpace - m_regInputCropped.getLowerCorner().getZ()) + 0.5f); - const Vector3DFloat v3dNormal(0.0,0.0,v000 > v001 ? 1.0f : -1.0f); - const uint8_t uMaterial = v000 | v001; //Because one of these is 0, the or operation takes the max. + const VoxelType v001 = m_sampVolume.getVoxel(); + const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); + + float fInterp = static_cast(VoxelType::getMidDensity() - v000.getDensity()) / static_cast(v001.getDensity() - v000.getDensity()); + //fInterp = 0.5f; + + const Vector3DFloat v3dPosition(static_cast(uXVolSpace - m_regInputCropped.getLowerCorner().getX()), static_cast(uYVolSpace - m_regInputCropped.getLowerCorner().getY()), static_cast(uZVolSpace - m_regInputCropped.getLowerCorner().getZ()) + fInterp); + //const Vector3DFloat v3dNormal(0.0,0.0,v000.getDensity() > v001.getDensity() ? 1.0f : -1.0f); + + Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp)); + v3dNormal.normalise(); + + const uint8_t uMaterial = v000.getMaterial() | v001.getMaterial(); //Because one of these is 0, the or operation takes the max. + SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); //surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge); surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge); @@ -518,7 +554,111 @@ namespace PolyVox } } - void SurfaceExtractor::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, + template + Vector3DFloat SurfaceExtractor::computeCentralDifferenceGradient(const VolumeSampler& volIter) + { + uint8_t voxel1nx = volIter.peekVoxel1nx0py0pz().getDensity(); + uint8_t voxel1px = volIter.peekVoxel1px0py0pz().getDensity(); + + uint8_t voxel1ny = volIter.peekVoxel0px1ny0pz().getDensity(); + uint8_t voxel1py = volIter.peekVoxel0px1py0pz().getDensity(); + + uint8_t voxel1nz = volIter.peekVoxel0px0py1nz().getDensity(); + uint8_t voxel1pz = volIter.peekVoxel0px0py1pz().getDensity(); + + return Vector3DFloat + ( + static_cast(voxel1nx) - static_cast(voxel1px), + static_cast(voxel1ny) - static_cast(voxel1py), + static_cast(voxel1nz) - static_cast(voxel1pz) + ); + } + + template + Vector3DFloat SurfaceExtractor::computeSobelGradient(const VolumeSampler& volIter) + { + static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, { + {3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } }; + + const uint8_t pVoxel1nx1ny1nz = volIter.peekVoxel1nx1ny1nz().getDensity(); + const uint8_t pVoxel1nx1ny0pz = volIter.peekVoxel1nx1ny0pz().getDensity(); + const uint8_t pVoxel1nx1ny1pz = volIter.peekVoxel1nx1ny1pz().getDensity(); + const uint8_t pVoxel1nx0py1nz = volIter.peekVoxel1nx0py1nz().getDensity(); + const uint8_t pVoxel1nx0py0pz = volIter.peekVoxel1nx0py0pz().getDensity(); + const uint8_t pVoxel1nx0py1pz = volIter.peekVoxel1nx0py1pz().getDensity(); + const uint8_t pVoxel1nx1py1nz = volIter.peekVoxel1nx1py1nz().getDensity(); + const uint8_t pVoxel1nx1py0pz = volIter.peekVoxel1nx1py0pz().getDensity(); + const uint8_t pVoxel1nx1py1pz = volIter.peekVoxel1nx1py1pz().getDensity(); + + const uint8_t pVoxel0px1ny1nz = volIter.peekVoxel0px1ny1nz().getDensity(); + const uint8_t pVoxel0px1ny0pz = volIter.peekVoxel0px1ny0pz().getDensity(); + const uint8_t pVoxel0px1ny1pz = volIter.peekVoxel0px1ny1pz().getDensity(); + const uint8_t pVoxel0px0py1nz = volIter.peekVoxel0px0py1nz().getDensity(); + //const uint8_t pVoxel0px0py0pz = volIter.peekVoxel0px0py0pz().getDensity(); + const uint8_t pVoxel0px0py1pz = volIter.peekVoxel0px0py1pz().getDensity(); + const uint8_t pVoxel0px1py1nz = volIter.peekVoxel0px1py1nz().getDensity(); + const uint8_t pVoxel0px1py0pz = volIter.peekVoxel0px1py0pz().getDensity(); + const uint8_t pVoxel0px1py1pz = volIter.peekVoxel0px1py1pz().getDensity(); + + const uint8_t pVoxel1px1ny1nz = volIter.peekVoxel1px1ny1nz().getDensity(); + const uint8_t pVoxel1px1ny0pz = volIter.peekVoxel1px1ny0pz().getDensity(); + const uint8_t pVoxel1px1ny1pz = volIter.peekVoxel1px1ny1pz().getDensity(); + const uint8_t pVoxel1px0py1nz = volIter.peekVoxel1px0py1nz().getDensity(); + const uint8_t pVoxel1px0py0pz = volIter.peekVoxel1px0py0pz().getDensity(); + const uint8_t pVoxel1px0py1pz = volIter.peekVoxel1px0py1pz().getDensity(); + const uint8_t pVoxel1px1py1nz = volIter.peekVoxel1px1py1nz().getDensity(); + const uint8_t pVoxel1px1py0pz = volIter.peekVoxel1px1py0pz().getDensity(); + const uint8_t pVoxel1px1py1pz = volIter.peekVoxel1px1py1pz().getDensity(); + + const int xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - + weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * + pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz - + weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] * + pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz - + weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] * + pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz + + weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] * + pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz + + weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] * + pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz + + weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * + pVoxel1px1py1pz); + + const int yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - + weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * + pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz + + weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] * + pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz - + weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] * + pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz + + weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] * + pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz - + weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] * + pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz + + weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * + pVoxel1px1py1pz); + + const int zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz + + weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] * + pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz - + weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] * + pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz + + weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] * + pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz - + weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] * + pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz + + weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] * + pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz - + weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] * + pVoxel1px1py1pz); + + //Note: The above actually give gradients going from low density to high density. + //For our normals we want the the other way around, so we switch the components as we return them. + return Vector3DFloat(static_cast(-xGrad),static_cast(-yGrad),static_cast(-zGrad)); + } + + template + void SurfaceExtractor::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, const Array2DInt32& m_pPreviousVertexIndicesX, const Array2DInt32& m_pPreviousVertexIndicesY, const Array2DInt32& m_pPreviousVertexIndicesZ, diff --git a/library/PolyVoxCore/include/Volume.h b/library/PolyVoxCore/include/Volume.h index 73ae75a0..84bc55de 100644 --- a/library/PolyVoxCore/include/Volume.h +++ b/library/PolyVoxCore/include/Volume.h @@ -132,8 +132,8 @@ namespace PolyVox uint16_t getShortestSideLength(void) const; ///Gets the length of the diagonal in voxels float getDiagonalLength(void) const; - VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tDefault = 0) const; - VoxelType getVoxelAt(const Vector3DUint16& v3dPos, VoxelType tDefault = 0) const; + VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tDefault = VoxelType()) const; + VoxelType getVoxelAt(const Vector3DUint16& v3dPos, VoxelType tDefault = VoxelType()) const; bool setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); bool setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); diff --git a/library/PolyVoxCore/include/Volume.inl b/library/PolyVoxCore/include/Volume.inl index 879f255a..b0dbac50 100644 --- a/library/PolyVoxCore/include/Volume.inl +++ b/library/PolyVoxCore/include/Volume.inl @@ -124,7 +124,7 @@ namespace PolyVox m_vecBlockIsPotentiallyHomogenous.resize(m_uNoOfBlocksInVolume); for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) { - m_pBlocks[i] = getHomogenousBlock(0); + m_pBlocks[i] = getHomogenousBlock(VoxelType()); m_vecBlockIsPotentiallyHomogenous[i] = false; } diff --git a/library/PolyVoxCore/include/ArraySizes.inl b/library/PolyVoxCore/source/ArraySizes.cpp similarity index 95% rename from library/PolyVoxCore/include/ArraySizes.inl rename to library/PolyVoxCore/source/ArraySizes.cpp index f700dde6..7e902acf 100644 --- a/library/PolyVoxCore/include/ArraySizes.inl +++ b/library/PolyVoxCore/source/ArraySizes.cpp @@ -23,6 +23,8 @@ freely, subject to the following restrictions: *******************************************************************************/ #pragma endregion +#include "ArraySizes.h" + namespace PolyVox { /** diff --git a/library/PolyVoxUtil/CMakeLists.txt b/library/PolyVoxUtil/CMakeLists.txt index 7a8d8c15..605d70c4 100644 --- a/library/PolyVoxUtil/CMakeLists.txt +++ b/library/PolyVoxUtil/CMakeLists.txt @@ -4,15 +4,16 @@ PROJECT(PolyVoxUtil) #Projects source files SET(UTIL_SRC_FILES - source/Serialization.cpp - source/VolumeChangeTracker.cpp + source/Dummy.cpp ) #Projects headers files SET(UTIL_INC_FILES include/Export.h include/Serialization.h + include/Serialization.inl include/VolumeChangeTracker.h + include/VolumeChangeTracker.inl ) ADD_DEFINITIONS(-DPOLYVOXUTIL_EXPORT) #Export symbols in the .dll diff --git a/library/PolyVoxUtil/include/Serialization.h b/library/PolyVoxUtil/include/Serialization.h index b337a3bc..52d1ee22 100644 --- a/library/PolyVoxUtil/include/Serialization.h +++ b/library/PolyVoxUtil/include/Serialization.h @@ -41,11 +41,279 @@ namespace PolyVox virtual void onProgressUpdated(float fProgress) = 0; }; - POLYVOXUTIL_API std::shared_ptr< Volume > loadVolumeRaw(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0); - POLYVOXUTIL_API void saveVolumeRaw(std::ostream& stream, Volume& volume, VolumeSerializationProgressListener* progressListener = 0); + template + std::shared_ptr< Volume > loadVolumeRaw(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0); + template + void saveVolumeRaw(std::ostream& stream, Volume& volume, VolumeSerializationProgressListener* progressListener = 0); - POLYVOXUTIL_API std::shared_ptr< Volume > loadVolumeRle(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0); - POLYVOXUTIL_API void saveVolumeRle(std::ostream& stream, Volume& volume, VolumeSerializationProgressListener* progressListener = 0); + template + std::shared_ptr< Volume > loadVolumeRle(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0); + template + void saveVolumeRle(std::ostream& stream, Volume& volume, VolumeSerializationProgressListener* progressListener = 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 "Serialization.h" + +#include "Volume.h" +#include "VolumeSampler.h" +#include "PolyVoxImpl/Utility.h" + +using namespace std; + +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 + shared_ptr< Volume > loadVolumeRaw(istream& stream, VolumeSerializationProgressListener* progressListener) + { + //Read volume dimensions + uint8_t volumeWidthPower = 0; + uint8_t volumeHeightPower = 0; + uint8_t volumeDepthPower = 0; + stream.read(reinterpret_cast(&volumeWidthPower), sizeof(volumeWidthPower)); + stream.read(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); + stream.read(reinterpret_cast(&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 + shared_ptr< Volume > volume(new Volume(volumeWidth, volumeHeight, volumeDepth)); + + //Read data + for(uint16_t z = 0; z < volumeDepth; ++z) + { + //Update progress once per slice. + if(progressListener) + { + float fProgress = static_cast(z) / static_cast(volumeDepth); + progressListener->onProgressUpdated(fProgress); + } + + for(uint16_t y = 0; y < volumeHeight; ++y) + { + for(uint16_t x = 0; x < volumeWidth; ++x) + { + VoxelType value; + stream.read(reinterpret_cast(&value), sizeof(value)); + + volume->setVoxelAt(x,y,z,value); + } + } + } + + //Finished + if(progressListener) + { + progressListener->onProgressUpdated(1.0f); + } + + return volume; + } + + template + void saveVolumeRaw(std::ostream& stream, Volume& volume, VolumeSerializationProgressListener* progressListener) + { + //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(&volumeWidthPower), sizeof(volumeWidthPower)); + stream.write(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); + stream.write(reinterpret_cast(&volumeDepthPower), sizeof(volumeDepthPower)); + + //Write data + VolumeSampler volIter(&volume); + for(uint16_t z = 0; z < volumeDepth; ++z) + { + //Update progress once per slice. + if(progressListener) + { + float fProgress = static_cast(z) / static_cast(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); + VoxelType value = volIter.getVoxel(); + stream.write(reinterpret_cast(&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 + shared_ptr< Volume > loadVolumeRle(istream& stream, VolumeSerializationProgressListener* progressListener) + { + //Read volume dimensions + uint8_t volumeWidthPower = 0; + uint8_t volumeHeightPower = 0; + uint8_t volumeDepthPower = 0; + stream.read(reinterpret_cast(&volumeWidthPower), sizeof(volumeWidthPower)); + stream.read(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); + stream.read(reinterpret_cast(&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 + shared_ptr< Volume > volume(new Volume(volumeWidth, volumeHeight, volumeDepth)); + + //Read data + bool firstTime = true; + uint32_t runLength = 0; + VoxelType value; + stream.read(reinterpret_cast(&value), sizeof(value)); + stream.read(reinterpret_cast(&runLength), sizeof(runLength)); + for(uint16_t z = 0; z < volumeDepth; ++z) + { + //Update progress once per slice. + if(progressListener) + { + float fProgress = static_cast(z) / static_cast(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(&value), sizeof(value)); + stream.read(reinterpret_cast(&runLength), sizeof(runLength)); + + volume->setVoxelAt(x,y,z,value); + runLength--; + } + } + } + } + + //Finished + if(progressListener) + { + progressListener->onProgressUpdated(1.0f); + } + + return volume; + } + + template + void saveVolumeRle(std::ostream& stream, Volume& volume, VolumeSerializationProgressListener* progressListener) + { + //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(&volumeWidthPower), sizeof(volumeWidthPower)); + stream.write(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); + stream.write(reinterpret_cast(&volumeDepthPower), sizeof(volumeDepthPower)); + + //Write data + VolumeSampler volIter(&volume); + 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(z) / static_cast(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); + VoxelType value = volIter.getVoxel(); + if(firstTime) + { + current = value; + runLength = 1; + firstTime = false; + } + else + { + if(value == current) + { + runLength++; + } + else + { + stream.write(reinterpret_cast(¤t), sizeof(current)); + stream.write(reinterpret_cast(&runLength), sizeof(runLength)); + current = value; + runLength = 1; + } + } + } + } + } + stream.write(reinterpret_cast(¤t), sizeof(current)); + stream.write(reinterpret_cast(&runLength), sizeof(runLength)); + + //Finished + if(progressListener) + { + progressListener->onProgressUpdated(1.0f); + } + } } #endif diff --git a/library/PolyVoxUtil/include/Serialization.inl b/library/PolyVoxUtil/include/Serialization.inl new file mode 100644 index 00000000..e69de29b diff --git a/library/PolyVoxUtil/include/VolumeChangeTracker.h b/library/PolyVoxUtil/include/VolumeChangeTracker.h index 12065792..303ad367 100644 --- a/library/PolyVoxUtil/include/VolumeChangeTracker.h +++ b/library/PolyVoxUtil/include/VolumeChangeTracker.h @@ -35,22 +35,23 @@ freely, subject to the following restrictions: namespace PolyVox { /// Voxel scene manager - class POLYVOXUTIL_API VolumeChangeTracker + template + class VolumeChangeTracker { public: //Constructors, etc - VolumeChangeTracker(Volume* volumeDataToSet, uint16_t regionSideLength); + VolumeChangeTracker(Volume* volumeDataToSet, uint16_t regionSideLength); ~VolumeChangeTracker(); //Getters int32_t getCurrentTime(void) const; int32_t getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ); - Volume* getWrappedVolume(void) const; + Volume* getWrappedVolume(void) const; //Setters void setAllRegionsModified(void); - void setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value); - void setVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value); + 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); @@ -61,7 +62,7 @@ namespace PolyVox void incrementCurrentTime(void); bool m_bIsLocked; Region m_regLastLocked; - Volume* volumeData; + Volume* volumeData; uint16_t m_uRegionSideLength; uint8_t m_uRegionSideLengthPower; @@ -78,4 +79,6 @@ namespace PolyVox }; } +#include "VolumeChangeTracker.inl" + #endif diff --git a/library/PolyVoxUtil/source/VolumeChangeTracker.cpp b/library/PolyVoxUtil/include/VolumeChangeTracker.inl similarity index 80% rename from library/PolyVoxUtil/source/VolumeChangeTracker.cpp rename to library/PolyVoxUtil/include/VolumeChangeTracker.inl index 84e6ac97..69b031c7 100644 --- a/library/PolyVoxUtil/source/VolumeChangeTracker.cpp +++ b/library/PolyVoxUtil/include/VolumeChangeTracker.inl @@ -38,12 +38,14 @@ using namespace std; namespace PolyVox { - uint32_t VolumeChangeTracker::m_uCurrentTime = 0; + template + uint32_t VolumeChangeTracker::m_uCurrentTime = 0; ////////////////////////////////////////////////////////////////////////// // VolumeChangeTracker ////////////////////////////////////////////////////////////////////////// - VolumeChangeTracker::VolumeChangeTracker(Volume* volumeDataToSet, uint16_t regionSideLength) + template + VolumeChangeTracker::VolumeChangeTracker(Volume* volumeDataToSet, uint16_t regionSideLength) :m_bIsLocked(false) ,volumeData(0) ,m_uRegionSideLength(regionSideLength) @@ -57,11 +59,13 @@ namespace PolyVox volRegionLastModified = new Volume(m_uVolumeWidthInRegions, m_uVolumeHeightInRegions, m_uVolumeDepthInRegions, 0); } - VolumeChangeTracker::~VolumeChangeTracker() + template + VolumeChangeTracker::~VolumeChangeTracker() { } - void VolumeChangeTracker::setAllRegionsModified(void) + template + void VolumeChangeTracker::setAllRegionsModified(void) { incrementCurrentTime(); for(uint16_t blockZ = 0; blockZ < m_uVolumeDepthInRegions; ++blockZ) @@ -76,22 +80,26 @@ namespace PolyVox } } - int32_t VolumeChangeTracker::getCurrentTime(void) const + template + int32_t VolumeChangeTracker::getCurrentTime(void) const { return m_uCurrentTime; } - int32_t VolumeChangeTracker::getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ) + template + int32_t VolumeChangeTracker::getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ) { return volRegionLastModified->getVoxelAt(uX, uY, uZ); } - Volume* VolumeChangeTracker::getWrappedVolume(void) const + template + Volume* VolumeChangeTracker::getWrappedVolume(void) const { return volumeData; } - void VolumeChangeTracker::setVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value) + template + void VolumeChangeTracker::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 @@ -140,18 +148,20 @@ namespace PolyVox incrementCurrentTime(); } - void VolumeChangeTracker::setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value) + template + void VolumeChangeTracker::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 - /*VolumeSampler iterVol(*volumeData); + /*VolumeSampler iterVol(*volumeData); iterVol.setPosition(x,y,z); iterVol.setVoxel(value);*/ volumeData->setVoxelAt(x,y,z,value); } - void VolumeChangeTracker::lockRegion(const Region& regToLock) + template + void VolumeChangeTracker::lockRegion(const Region& regToLock) { if(m_bIsLocked) { @@ -162,7 +172,8 @@ namespace PolyVox m_bIsLocked = true; } - void VolumeChangeTracker::unlockRegion(void) + template + void VolumeChangeTracker::unlockRegion(void) { if(!m_bIsLocked) { @@ -199,7 +210,8 @@ namespace PolyVox incrementCurrentTime(); } - void VolumeChangeTracker::incrementCurrentTime(void) + template + void VolumeChangeTracker::incrementCurrentTime(void) { //Increment the current time. uint32_t time = m_uCurrentTime++; diff --git a/library/PolyVoxUtil/source/Serialization.cpp b/library/PolyVoxUtil/source/Serialization.cpp deleted file mode 100644 index 0ab93e15..00000000 --- a/library/PolyVoxUtil/source/Serialization.cpp +++ /dev/null @@ -1,259 +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 "Serialization.h" - -#include "Volume.h" -#include "VolumeSampler.h" -#include "PolyVoxImpl/Utility.h" - -using namespace std; - -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 - shared_ptr< Volume > loadVolumeRaw(istream& stream, VolumeSerializationProgressListener* progressListener) - { - //Read volume dimensions - uint8_t volumeWidthPower = 0; - uint8_t volumeHeightPower = 0; - uint8_t volumeDepthPower = 0; - stream.read(reinterpret_cast(&volumeWidthPower), sizeof(volumeWidthPower)); - stream.read(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); - stream.read(reinterpret_cast(&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 - shared_ptr< Volume > volume(new Volume(volumeWidth, volumeHeight, volumeDepth)); - - //Read data - for(uint16_t z = 0; z < volumeDepth; ++z) - { - //Update progress once per slice. - if(progressListener) - { - float fProgress = static_cast(z) / static_cast(volumeDepth); - progressListener->onProgressUpdated(fProgress); - } - - for(uint16_t y = 0; y < volumeHeight; ++y) - { - for(uint16_t x = 0; x < volumeWidth; ++x) - { - uint8_t value = 0; - stream.read(reinterpret_cast(&value), sizeof(value)); - - volume->setVoxelAt(x,y,z,value); - } - } - } - - //Finished - if(progressListener) - { - progressListener->onProgressUpdated(1.0f); - } - - return volume; - } - - void saveVolumeRaw(std::ostream& stream, Volume& volume, VolumeSerializationProgressListener* progressListener) - { - //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(&volumeWidthPower), sizeof(volumeWidthPower)); - stream.write(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); - stream.write(reinterpret_cast(&volumeDepthPower), sizeof(volumeDepthPower)); - - //Write data - VolumeSampler volIter(&volume); - for(uint16_t z = 0; z < volumeDepth; ++z) - { - //Update progress once per slice. - if(progressListener) - { - float fProgress = static_cast(z) / static_cast(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); - uint8_t value = volIter.getVoxel(); - stream.write(reinterpret_cast(&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 - shared_ptr< Volume > loadVolumeRle(istream& stream, VolumeSerializationProgressListener* progressListener) - { - //Read volume dimensions - uint8_t volumeWidthPower = 0; - uint8_t volumeHeightPower = 0; - uint8_t volumeDepthPower = 0; - stream.read(reinterpret_cast(&volumeWidthPower), sizeof(volumeWidthPower)); - stream.read(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); - stream.read(reinterpret_cast(&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 - shared_ptr< Volume > volume(new Volume(volumeWidth, volumeHeight, volumeDepth)); - - //Read data - bool firstTime = true; - uint32_t runLength = 0; - uint8_t value = 0; - stream.read(reinterpret_cast(&value), sizeof(value)); - stream.read(reinterpret_cast(&runLength), sizeof(runLength)); - for(uint16_t z = 0; z < volumeDepth; ++z) - { - //Update progress once per slice. - if(progressListener) - { - float fProgress = static_cast(z) / static_cast(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(&value), sizeof(value)); - stream.read(reinterpret_cast(&runLength), sizeof(runLength)); - - volume->setVoxelAt(x,y,z,value); - runLength--; - } - } - } - } - - //Finished - if(progressListener) - { - progressListener->onProgressUpdated(1.0f); - } - - return volume; - } - - void saveVolumeRle(std::ostream& stream, Volume& volume, VolumeSerializationProgressListener* progressListener) - { - //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(&volumeWidthPower), sizeof(volumeWidthPower)); - stream.write(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); - stream.write(reinterpret_cast(&volumeDepthPower), sizeof(volumeDepthPower)); - - //Write data - VolumeSampler volIter(&volume); - uint8_t current = 0; - 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(z) / static_cast(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); - uint8_t value = volIter.getVoxel(); - if(firstTime) - { - current = value; - runLength = 1; - firstTime = false; - } - else - { - if(value == current) - { - runLength++; - } - else - { - stream.write(reinterpret_cast(¤t), sizeof(current)); - stream.write(reinterpret_cast(&runLength), sizeof(runLength)); - current = value; - runLength = 1; - } - } - } - } - } - stream.write(reinterpret_cast(¤t), sizeof(current)); - stream.write(reinterpret_cast(&runLength), sizeof(runLength)); - - //Finished - if(progressListener) - { - progressListener->onProgressUpdated(1.0f); - } - } -} \ No newline at end of file diff --git a/tests/TestArray.cpp b/tests/TestArray.cpp index fae1bea6..1518ea39 100644 --- a/tests/TestArray.cpp +++ b/tests/TestArray.cpp @@ -35,7 +35,8 @@ void TestArray::testReadWrite() int height = 10; int depth = 20; - Array<3, int> myArray(ArraySizes(width)(height)(depth)); + uint32_t dimensions[3] = {width, height, depth}; // Array dimensions + Array<3, int> myArray(dimensions); int ct = 1; int expectedTotal = 0;