From f86ec57e142bbd46822850d534538e03d7352a21 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 16 Jun 2013 18:25:20 +0200 Subject: [PATCH 01/26] Adding skeletons of new paging classes. --- .../include/PolyVoxCore/FilePager.h | 63 +++++++++++++++++++ .../PolyVoxCore/include/PolyVoxCore/Pager.h | 48 ++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 library/PolyVoxCore/include/PolyVoxCore/FilePager.h create mode 100644 library/PolyVoxCore/include/PolyVoxCore/Pager.h diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h new file mode 100644 index 00000000..49ac5637 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -0,0 +1,63 @@ +/******************************************************************************* +Copyright (c) 2005-2009 David Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#ifndef __PolyVox_FilePager_H__ +#define __PolyVox_FilePager_H__ + +#include "PolyVoxCore/Impl/TypeDef.h" + +#include "PolyVoxCore/Pager.h" + +#include +#include + +namespace PolyVox +{ + /** + * Provides an interface for performing paging of data. + */ + class FilePager : public Pager + { + public: + /// Constructor + FilePager(const std::string& strFolderName) + :Pager() + { + } + + /// Destructor + virtual ~FilePager() {}; + + virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) + { + } + + virtual void dataOverflowHandler(const ConstVolumeProxy& volumeProxy, const Region& region) + { + } + + protected: + std::string m_strFolderName; +} + +#endif //__PolyVox_FilePager_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/Pager.h b/library/PolyVoxCore/include/PolyVoxCore/Pager.h new file mode 100644 index 00000000..1281fdba --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/Pager.h @@ -0,0 +1,48 @@ +/******************************************************************************* +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_Pager_H__ +#define __PolyVox_Pager_H__ + +#include "PolyVoxCore/Impl/TypeDef.h" + +#include "PolyVoxCore/ConstVolumeProxy.h" + +namespace PolyVox +{ + /** + * Provides an interface for performing paging of data. + */ + class Pager + { + public: + /// Constructor + Pager() {}; + /// Destructor + virtual ~Pager() {}; + + virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region); + virtual void dataOverflowHandler(const ConstVolumeProxy& volumeProxy, const Region& region); +} + +#endif //__PolyVox_Pager_H__ From 414a012230d59846e143db1ddc9dc3a4cfe07bc3 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 16 Jun 2013 19:12:37 +0200 Subject: [PATCH 02/26] Creating a Perlin noise generator as a 'pager'. --- examples/Paging/main.cpp | 70 ++++++++++++++++++- .../include/PolyVoxCore/FilePager.h | 2 + .../include/PolyVoxCore/LargeVolume.h | 1 + .../include/PolyVoxCore/LargeVolume.inl | 2 + .../PolyVoxCore/include/PolyVoxCore/Pager.h | 2 + 5 files changed, 75 insertions(+), 2 deletions(-) diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 20a272c6..ab40f514 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -27,6 +27,8 @@ freely, subject to the following restrictions: #include "PolyVoxCore/MaterialDensityPair.h" #include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h" #include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" +#include "PolyVoxCore/Pager.h" +#include "PolyVoxCore/RLECompressor.h" #include "PolyVoxCore/SurfaceMesh.h" #include "PolyVoxCore/LargeVolume.h" @@ -197,6 +199,68 @@ void createSphereInVolume(LargeVolume& volData, Vector3DF } } +/** + * Generates data using Perlin noise. + */ +class PerlinNoisePager : public PolyVox::Pager +{ +public: + /// Constructor + PerlinNoisePager() + :Pager() + { + } + + /// Destructor + virtual ~PerlinNoisePager() {}; + + virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) + { + Perlin perlin(2,2,1,234); + + for(int x = region.getLowerX(); x <= region.getUpperX(); x++) + { + for(int y = region.getLowerY(); y <= region.getUpperY(); y++) + { + float perlinVal = perlin.Get(x / static_cast(255-1), y / static_cast(255-1)); + perlinVal += 1.0f; + perlinVal *= 0.5f; + perlinVal *= 255; + for(int z = region.getLowerZ(); z <= region.getUpperZ(); z++) + { + MaterialDensityPair44 voxel; + if(z < perlinVal) + { + const int xpos = 50; + const int zpos = 100; + if((x-xpos)*(x-xpos) + (z-zpos)*(z-zpos) < 200) { + // tunnel + voxel.setMaterial(0); + voxel.setDensity(MaterialDensityPair44::getMinDensity()); + } else { + // solid + voxel.setMaterial(245); + voxel.setDensity(MaterialDensityPair44::getMaxDensity()); + } + } + else + { + voxel.setMaterial(0); + voxel.setDensity(MaterialDensityPair44::getMinDensity()); + } + + volumeProxy.setVoxelAt(x, y, z, voxel); + } + } + } + } + + virtual void dataOverflowHandler(const ConstVolumeProxy& /*volumeProxy*/, const Region& region) + { + std::cout << "warning unloading region: " << region.getLowerCorner() << " -> " << region.getUpperCorner() << std::endl; + } +}; + void load(const ConstVolumeProxy& volume, const PolyVox::Region& reg) { Perlin perlin(2,2,1,234); @@ -250,10 +314,12 @@ int main(int argc, char *argv[]) OpenGLWidget openGLWidget(0); openGLWidget.show(); + RLECompressor* compressor = new RLECompressor(); + //If these lines don't compile, please try commenting them out and using the two lines after //(you will need Boost for this). If you have to do this then please let us know in the forums as //we rely on community feedback to keep the Boost version running. - LargeVolume volData(&load, &unload, 256); + LargeVolume volData(compressor, &load, &unload, 64); //LargeVolume volData(polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2), // polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2), 256); volData.setMaxNumberOfBlocksInMemory(4096); @@ -269,7 +335,7 @@ int main(int argc, char *argv[]) std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; //volData.setBlockCacheSize(64); - PolyVox::Region reg(Vector3DInt32(-255,0,0), Vector3DInt32(255,255,255)); + PolyVox::Region reg(Vector3DInt32(-63,0,0), Vector3DInt32(63,63,255)); std::cout << "Prefetching region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl; volData.prefetch(reg); std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h index 49ac5637..ad259ace 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -36,6 +36,7 @@ namespace PolyVox /** * Provides an interface for performing paging of data. */ + template class FilePager : public Pager { public: @@ -58,6 +59,7 @@ namespace PolyVox protected: std::string m_strFolderName; + }; } #endif //__PolyVox_FilePager_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index a7b7d72f..ae504a20 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -248,6 +248,7 @@ namespace PolyVox /// Constructor for creating a very large paging volume. LargeVolume ( + Compressor* pCompressor, polyvox_function&, const Region&)> dataRequiredHandler, polyvox_function&, const Region&)> dataOverflowHandler, uint16_t uBlockSideLength = 32 diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index e9967114..4ea2b2af 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -37,11 +37,13 @@ namespace PolyVox template LargeVolume::LargeVolume ( + Compressor* pCompressor, polyvox_function&, const Region&)> dataRequiredHandler, polyvox_function&, const Region&)> dataOverflowHandler, uint16_t uBlockSideLength ) :BaseVolume(Region::MaxRegion) + ,m_pCompressor(pCompressor) { m_funcDataRequiredHandler = dataRequiredHandler; m_funcDataOverflowHandler = dataOverflowHandler; diff --git a/library/PolyVoxCore/include/PolyVoxCore/Pager.h b/library/PolyVoxCore/include/PolyVoxCore/Pager.h index 1281fdba..706640aa 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Pager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Pager.h @@ -33,6 +33,7 @@ namespace PolyVox /** * Provides an interface for performing paging of data. */ + template class Pager { public: @@ -43,6 +44,7 @@ namespace PolyVox virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region); virtual void dataOverflowHandler(const ConstVolumeProxy& volumeProxy, const Region& region); + }; } #endif //__PolyVox_Pager_H__ From a14de4a72e554586804c9858aafbcd74b6a5c6dc Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 16 Jun 2013 19:48:14 +0200 Subject: [PATCH 03/26] Replaced std::functions with Pager class for paging. --- examples/OpenGL/main.cpp | 4 ++- examples/Paging/main.cpp | 5 ++-- .../include/PolyVoxCore/LargeVolume.h | 17 +++++------- .../include/PolyVoxCore/LargeVolume.inl | 27 +++++++------------ .../PolyVoxCore/include/PolyVoxCore/Pager.h | 11 ++++++-- tests/testvolume.cpp | 2 +- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index 5ed191f5..ccae9941 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -25,6 +25,7 @@ freely, subject to the following restrictions: #include "PolyVoxCore/LargeVolume.h" #include "PolyVoxCore/LowPassFilter.h" #include "PolyVoxCore/RawVolume.h" +#include "PolyVoxCore/RLECompressor.h" #include "PolyVoxCore/SurfaceMesh.h" #include "PolyVoxCore/Impl/Utility.h" @@ -48,7 +49,8 @@ using namespace std; int main(int argc, char *argv[]) { - LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(g_uVolumeSideLength-1, g_uVolumeSideLength-1, g_uVolumeSideLength-1))); + RLECompressor* compressor = new RLECompressor(); + LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(g_uVolumeSideLength-1, g_uVolumeSideLength-1, g_uVolumeSideLength-1)), compressor, 0); //Make our volume contain a sphere in the center. int32_t minPos = 0; diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index ab40f514..8e6cba7f 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -314,12 +314,13 @@ int main(int argc, char *argv[]) OpenGLWidget openGLWidget(0); openGLWidget.show(); - RLECompressor* compressor = new RLECompressor(); + RLECompressor* compressor = new RLECompressor(); + PerlinNoisePager* pager = new PerlinNoisePager(); //If these lines don't compile, please try commenting them out and using the two lines after //(you will need Boost for this). If you have to do this then please let us know in the forums as //we rely on community feedback to keep the Boost version running. - LargeVolume volData(compressor, &load, &unload, 64); + LargeVolume volData(compressor, pager, 64); //LargeVolume volData(polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2), // polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2), 256); volData.setMaxNumberOfBlocksInMemory(4096); diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index ae504a20..6de905b3 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -27,6 +27,7 @@ freely, subject to the following restrictions: #include "PolyVoxCore/BaseVolume.h" #include "Impl/Block.h" #include "PolyVoxCore/Compressor.h" +#include "PolyVoxCore/Pager.h" #include "PolyVoxCore/Region.h" #include "PolyVoxCore/Vector.h" @@ -249,18 +250,15 @@ namespace PolyVox LargeVolume ( Compressor* pCompressor, - polyvox_function&, const Region&)> dataRequiredHandler, - polyvox_function&, const Region&)> dataOverflowHandler, + Pager* pPager, uint16_t uBlockSideLength = 32 ); /// Constructor for creating a fixed size volume. LargeVolume ( const Region& regValid, - Compressor* pCompressor = 0, - polyvox_function&, const Region&)> dataRequiredHandler = 0, - polyvox_function&, const Region&)> dataOverflowHandler = 0, - bool bPagingEnabled = false, + Compressor* pCompressor, + Pager* pPager, uint16_t uBlockSideLength = 32 ); /// Destructor @@ -346,12 +344,12 @@ namespace PolyVox /// gets called when a new region is allocated and needs to be filled /// NOTE: accessing ANY voxels outside this region during the process of this function /// is absolutely unsafe - polyvox_function&, const Region&)> m_funcDataRequiredHandler; + //polyvox_function&, const Region&)> m_funcDataRequiredHandler; /// gets called when a Region needs to be stored by the user, because LargeVolume will erase it right after /// this function returns /// NOTE: accessing ANY voxels outside this region during the process of this function /// is absolutely unsafe - polyvox_function&, const Region&)> m_funcDataOverflowHandler; + //polyvox_function&, const Region&)> m_funcDataOverflowHandler; Block* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; void eraseBlock(typename std::map::iterator itBlock) const; @@ -381,8 +379,7 @@ namespace PolyVox //The compressor used by the Blocks to compress their data if required. Compressor* m_pCompressor; - - bool m_bPagingEnabled; + Pager* m_pPager; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 4ea2b2af..7201836a 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -38,16 +38,13 @@ namespace PolyVox LargeVolume::LargeVolume ( Compressor* pCompressor, - polyvox_function&, const Region&)> dataRequiredHandler, - polyvox_function&, const Region&)> dataOverflowHandler, + Pager* pPager, uint16_t uBlockSideLength ) :BaseVolume(Region::MaxRegion) ,m_pCompressor(pCompressor) { - m_funcDataRequiredHandler = dataRequiredHandler; - m_funcDataOverflowHandler = dataOverflowHandler; - m_bPagingEnabled = true; + m_pPager = pPager; //Create a volume of the right size. initialise(Region::MaxRegion,uBlockSideLength); } @@ -66,17 +63,13 @@ namespace PolyVox ( const Region& regValid, Compressor* pCompressor, - polyvox_function&, const Region&)> dataRequiredHandler, - polyvox_function&, const Region&)> dataOverflowHandler, - bool bPagingEnabled, + Pager* pPager, uint16_t uBlockSideLength ) :BaseVolume(regValid) ,m_pCompressor(pCompressor) { - m_funcDataRequiredHandler = dataRequiredHandler; - m_funcDataOverflowHandler = dataOverflowHandler; - m_bPagingEnabled = bPagingEnabled; + m_pPager = pPager; //Create a volume of the right size. initialise(regValid,uBlockSideLength); @@ -540,7 +533,7 @@ namespace PolyVox template void LargeVolume::eraseBlock(typename std::map::iterator itBlock) const { - if(m_funcDataOverflowHandler) + //if(m_funcDataOverflowHandler) { Vector3DInt32 v3dPos = itBlock->first; Vector3DInt32 v3dLower(v3dPos.getX() << m_uBlockSideLengthPower, v3dPos.getY() << m_uBlockSideLengthPower, v3dPos.getZ() << m_uBlockSideLengthPower); @@ -549,7 +542,7 @@ namespace PolyVox Region reg(v3dLower, v3dUpper); ConstVolumeProxy ConstVolumeProxy(*this, reg); - m_funcDataOverflowHandler(ConstVolumeProxy, reg); + m_pPager->dataOverflowHandler(ConstVolumeProxy, reg); } if(m_pCompressor) { @@ -617,7 +610,7 @@ namespace PolyVox //The block is not in the map, so we will have to create a new block and add it. //Before we do so, we might want to dump some existing data to make space. We //Only do this if paging is enabled. - if(m_bPagingEnabled) + if(m_pPager) { // check wether another block needs to be unloaded before this one can be loaded if(m_pBlocks.size() == m_uMaxNumberOfBlocksInMemory) @@ -648,9 +641,9 @@ namespace PolyVox //We have created the new block. If paging is enabled it should be used to //fill in the required data. Otherwise it is just left in the default state. - if(m_bPagingEnabled) + if(m_pPager) { - if(m_funcDataRequiredHandler) + //if(m_funcDataRequiredHandler) { // "load" will actually call setVoxel, which will in turn call this function again but the block will be found // so this if(itBlock == m_pBlocks.end()) never is entered @@ -659,7 +652,7 @@ namespace PolyVox Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); Region reg(v3dLower, v3dUpper); ConstVolumeProxy ConstVolumeProxy(*this, reg); - m_funcDataRequiredHandler(ConstVolumeProxy, reg); + m_pPager->dataRequiredHandler(ConstVolumeProxy, reg); } } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/Pager.h b/library/PolyVoxCore/include/PolyVoxCore/Pager.h index 706640aa..893898bb 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Pager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Pager.h @@ -42,8 +42,15 @@ namespace PolyVox /// Destructor virtual ~Pager() {}; - virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region); - virtual void dataOverflowHandler(const ConstVolumeProxy& volumeProxy, const Region& region); + virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) + { + POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); + } + + virtual void dataOverflowHandler(const ConstVolumeProxy& volumeProxy, const Region& region) + { + POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); + } }; } diff --git a/tests/testvolume.cpp b/tests/testvolume.cpp index dd000a88..4a4d638d 100644 --- a/tests/testvolume.cpp +++ b/tests/testvolume.cpp @@ -277,7 +277,7 @@ TestVolume::TestVolume() //Create the volumes m_pRawVolume = new RawVolume(region); m_pSimpleVolume = new SimpleVolume(region); - m_pLargeVolume = new LargeVolume(region, m_pCompressor); + m_pLargeVolume = new LargeVolume(region, m_pCompressor, 0, 32); // LargeVolume currently fails a test if compression is enabled. It // may be related to accessing the data through more than one sampler? From 20db75fb753b623b912fecc35e8d2b08418af814 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 22 Jun 2013 07:24:19 +0200 Subject: [PATCH 04/26] Added null pointer check. Added files to CMakeLists.txt --- library/PolyVoxCore/CMakeLists.txt | 2 ++ library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index 2c352a50..8366d527 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -57,6 +57,7 @@ SET(CORE_INC_FILES include/PolyVoxCore/DefaultIsQuadNeeded.h include/PolyVoxCore/DefaultMarchingCubesController.h include/PolyVoxCore/Density.h + include/PolyVoxCore/FilePager.h include/PolyVoxCore/GradientEstimators.h include/PolyVoxCore/GradientEstimators.inl include/PolyVoxCore/Interpolation.h @@ -72,6 +73,7 @@ SET(CORE_INC_FILES include/PolyVoxCore/Material.h include/PolyVoxCore/MaterialDensityPair.h include/PolyVoxCore/MinizCompressor.h + include/PolyVoxCore/Pager.h include/PolyVoxCore/PolyVoxForwardDeclarations.h include/PolyVoxCore/Picking.h include/PolyVoxCore/Picking.inl diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 7201836a..6322135b 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -533,7 +533,7 @@ namespace PolyVox template void LargeVolume::eraseBlock(typename std::map::iterator itBlock) const { - //if(m_funcDataOverflowHandler) + if(m_pPager) { Vector3DInt32 v3dPos = itBlock->first; Vector3DInt32 v3dLower(v3dPos.getX() << m_uBlockSideLengthPower, v3dPos.getY() << m_uBlockSideLengthPower, v3dPos.getZ() << m_uBlockSideLengthPower); From 5664e2f68186ad84034b1004f565c56598ca1ccd Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 22 Jun 2013 07:30:06 +0200 Subject: [PATCH 05/26] Restored Paging Example back to previous values. --- examples/Paging/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 8e6cba7f..81dc7534 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -320,7 +320,7 @@ int main(int argc, char *argv[]) //If these lines don't compile, please try commenting them out and using the two lines after //(you will need Boost for this). If you have to do this then please let us know in the forums as //we rely on community feedback to keep the Boost version running. - LargeVolume volData(compressor, pager, 64); + LargeVolume volData(compressor, pager, 256); //LargeVolume volData(polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2), // polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2), 256); volData.setMaxNumberOfBlocksInMemory(4096); @@ -336,7 +336,7 @@ int main(int argc, char *argv[]) std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; //volData.setBlockCacheSize(64); - PolyVox::Region reg(Vector3DInt32(-63,0,0), Vector3DInt32(63,63,255)); + PolyVox::Region reg(Vector3DInt32(-255,0,0), Vector3DInt32(255,255,255)); std::cout << "Prefetching region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl; volData.prefetch(reg); std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; From 288b448b9f9a5a80052f3bf43e534e51c74adf63 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 22 Jun 2013 10:16:16 +0200 Subject: [PATCH 06/26] Brought across Region operator<< from Cubiquity branch. --- library/PolyVoxCore/include/PolyVoxCore/Region.h | 4 ++++ library/PolyVoxCore/source/Region.cpp | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Region.h b/library/PolyVoxCore/include/PolyVoxCore/Region.h index 655b3bce..4fe45a7e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Region.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Region.h @@ -202,6 +202,10 @@ namespace PolyVox int32_t m_iUpperZ; }; + // Non-member overloaded operators. + /// Stream insertion operator. + std::ostream& operator<<(std::ostream& os, const Region& region); + // Functions to be inlined to to be in the header rather than the .cpp. // 'inline' keyword is used for the definition rather than the declaration. // See also http://www.parashift.com/c++-faq-lite/inline-functions.html diff --git a/library/PolyVoxCore/source/Region.cpp b/library/PolyVoxCore/source/Region.cpp index 444a1770..2f61f63a 100644 --- a/library/PolyVoxCore/source/Region.cpp +++ b/library/PolyVoxCore/source/Region.cpp @@ -487,4 +487,17 @@ namespace PolyVox { shrink(v3dAmount.getX(), v3dAmount.getY(), v3dAmount.getZ()); } -} + + /** + * Enables the Region to be used intuitively with output streams such as cout. + * \param os The output stream to write to. + * \param region The Region to write to the stream. + * \return A reference to the output stream to allow chaining. + */ + std::ostream& operator<<(std::ostream& os, const Region& region) + { + os << "(" << region.getLowerX() << "," << region.getLowerY() << "," << region.getLowerZ() << + ") to (" << region.getUpperX() << "," << region.getUpperY() << "," << region.getUpperZ() << ")"; + return os; + } +} \ No newline at end of file From d9ebe96c5abdf3a8c1daa75aba63f407ba06045d Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 22 Jun 2013 10:16:33 +0200 Subject: [PATCH 07/26] Work on FilePager. --- .../include/PolyVoxCore/FilePager.h | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h index ad259ace..8ba7a081 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -29,6 +29,7 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Pager.h" #include +#include #include namespace PolyVox @@ -37,18 +38,85 @@ namespace PolyVox * Provides an interface for performing paging of data. */ template - class FilePager : public Pager + class FilePager : public Pager { public: /// Constructor FilePager(const std::string& strFolderName) :Pager() + ,m_strFolderName(strFolderName) { } /// Destructor virtual ~FilePager() {}; + virtual void pageIn(const Region& region, Block* pBlockData) + { + POLYVOX_ASSERT(pBlockData, "Attempting to page in NULL block"); + POLYVOX_ASSERT(pBlockData->m_bIsCompressed, "Attempting to page in uncompressed block"); + + std::stringstream ss; + ss << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_" + << region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ(); + + std::string filename = m_strFolderName + ss.str(); + + // FIXME - This should be replaced by C++ style IO, but currently this causes problems with + // the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919 + + FILE* pFile = fopen(filename.c_str(), "rb"); + if(pFile) + { + logTrace() << "Paging in data for " << region; + + fread(pBlockData->m_pCompressedData, sizeof(uint8_t), pBlockData->m_uCompressedDataLength, pFile); + + if(ferror(pFile)) + { + POLYVOX_THROW(std::runtime_error, "Error reading in block data, even though a file exists."); + } + + fclose(pFile); + } + else + { + logTrace() << "No data found for " << region << " during paging in."; + } + } + + virtual void pageOut(const Region& region, Block* pBlockData) + { + POLYVOX_ASSERT(pBlockData, "Attempting to page out NULL block"); + POLYVOX_ASSERT(pBlockData->m_bIsCompressed, "Attempting to page out uncompressed block"); + + logTrace() << "Paging out data for " << region; + + std::stringstream ss; + ss << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_" + << region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ(); + + std::string filename = m_strFolderName + ss.str(); + + // FIXME - This should be replaced by C++ style IO, but currently this causes problems with + // the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919 + + FILE* pFile = fopen(filename.c_str(), "wb"); + if(!pFile) + { + POLYVOX_THROW(std::runtime_error, "Unable to open file to write out block data."); + } + + fwrite(pBlockData->m_pCompressedData, sizeof(uint8_t), pBlockData->m_uCompressedDataLength, pFile); + + if(ferror(pFile)) + { + POLYVOX_THROW(std::runtime_error, "Error writing out block data."); + } + + fclose(pFile); + } + virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) { } From 564314088263887504b3db376ae4b20bb7a0d750 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 22 Jun 2013 11:19:30 +0200 Subject: [PATCH 08/26] Work on paging to file. --- library/PolyVoxCore/include/PolyVoxCore/FilePager.h | 7 +++++++ library/PolyVoxCore/include/PolyVoxCore/Pager.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h index 8ba7a081..5e28782d 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -70,6 +70,13 @@ namespace PolyVox { logTrace() << "Paging in data for " << region; + fseek(pFile, 0L, SEEK_END); + pBlockData->m_uCompressedDataLength = ftell(pFile); + fseek(pFile, 0L, SEEK_SET); + + delete[] pBlockData->m_pCompressedData; + pBlockData->m_pCompressedData = new uint8_t[pBlockData->m_uCompressedDataLength]; + fread(pBlockData->m_pCompressedData, sizeof(uint8_t), pBlockData->m_uCompressedDataLength, pFile); if(ferror(pFile)) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Pager.h b/library/PolyVoxCore/include/PolyVoxCore/Pager.h index 893898bb..13f4ad19 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Pager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Pager.h @@ -24,6 +24,7 @@ freely, subject to the following restrictions: #ifndef __PolyVox_Pager_H__ #define __PolyVox_Pager_H__ +#include "PolyVoxCore/Impl/Block.h" #include "PolyVoxCore/Impl/TypeDef.h" #include "PolyVoxCore/ConstVolumeProxy.h" @@ -42,6 +43,9 @@ namespace PolyVox /// Destructor virtual ~Pager() {}; + virtual void pageIn(const Region& region, Block* pBlockData) = 0; + virtual void pageOut(const Region& region, Block* pBlockData) = 0; + virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) { POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); From 785ac611b959bba697a72cf84a7baac61c8a44f4 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 22 Jun 2013 11:20:05 +0200 Subject: [PATCH 09/26] Work on file paging. --- examples/Paging/main.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 81dc7534..4622764c 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -214,6 +214,18 @@ public: /// Destructor virtual ~PerlinNoisePager() {}; + virtual void pageIn(const Region& region, Block* pBlockData) + { + POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); + + + } + + virtual void pageOut(const Region& region, Block* pBlockData) + { + std::cout << "warning unloading region: " << region.getLowerCorner() << " -> " << region.getUpperCorner() << std::endl; + } + virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) { Perlin perlin(2,2,1,234); From e80fa3de7dd5636ad5774d6893d4e47fd7f53c6c Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 22 Jun 2013 12:16:52 +0200 Subject: [PATCH 10/26] Added functions for accessing compressed data in block. --- .../include/PolyVoxCore/Impl/Block.h | 3 ++ .../include/PolyVoxCore/Impl/Block.inl | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h index 1f7b71d5..93a9c0f0 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h @@ -51,10 +51,13 @@ namespace PolyVox public: Block(uint16_t uSideLength = 0); + const uint8_t* getCompressedData(void) const; + const uint32_t getCompressedDataLength(void) const; uint16_t getSideLength(void) const; VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; VoxelType getVoxel(const Vector3DUint16& v3dPos) const; + void setCompressedData(const uint8_t* const data, uint32_t dataLength); void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index 61c9baac..64fbe33b 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -51,6 +51,24 @@ namespace PolyVox } } + template + const uint8_t* Block::getCompressedData(void) const + { + POLYVOX_ASSERT(m_bIsCompressed, "You cannot call getCompressedData() when the block is not compressed"); + POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); + + return m_pCompressedData; + } + + template + const uint32_t Block::getCompressedDataLength(void) const + { + POLYVOX_ASSERT(m_bIsCompressed, "You cannot call getCompressedData() when the block is not compressed"); + POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); + + return m_uCompressedDataLength; + } + template uint16_t Block::getSideLength(void) const { @@ -64,6 +82,7 @@ namespace PolyVox POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block"); + POLYVOX_ASSERT(!m_bIsCompressed, "You cannot call getVoxel() when a block is compressed"); POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels."); return m_tUncompressedData @@ -80,6 +99,20 @@ namespace PolyVox return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); } + template + void Block::setCompressedData(const uint8_t* const data, uint32_t dataLength) + { + POLYVOX_ASSERT(m_bIsCompressed, "You cannot call setCompressedData() when the block is not compressed"); + POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); + POLYVOX_ASSERT(m_pCompressedData != data, "Attempting to copy data onto itself"); + + delete[] m_pCompressedData; + + m_uCompressedDataLength = dataLength; + m_pCompressedData = new uint8_t[dataLength]; + memcpy(m_pCompressedData, data, dataLength); + } + template void Block::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue) { @@ -87,6 +120,7 @@ namespace PolyVox POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block"); + POLYVOX_ASSERT(!m_bIsCompressed, "You cannot call setVoxelAt() when a block is compressed"); POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels."); m_tUncompressedData From 59505d47e9509dd8a8c25dede649294aa9782d26 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 23 Jun 2013 23:17:40 +0200 Subject: [PATCH 11/26] Tidying up Block and FilePager. --- examples/Basic/main.cpp | 24 +++++++++++++++---- .../include/PolyVoxCore/FilePager.h | 18 +++++++------- .../include/PolyVoxCore/Impl/Block.h | 4 +++- .../include/PolyVoxCore/Impl/Block.inl | 8 ++++++- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index e7359f52..40bf0058 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -26,14 +26,17 @@ freely, subject to the following restrictions: #include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h" #include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" #include "PolyVoxCore/SurfaceMesh.h" -#include "PolyVoxCore/SimpleVolume.h" +//#include "PolyVoxCore/SimpleVolume.h" +#include "PolyVoxCore/LargeVolume.h" +#include "PolyVoxCore/RLECompressor.h" +#include "PolyVoxCore/FilePager.h" #include //Use the PolyVox namespace using namespace PolyVox; -void createSphereInVolume(SimpleVolume& volData, float fRadius) +void createSphereInVolume(LargeVolume& volData, float fRadius) { //This vector hold the position of the center of the volume Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); @@ -68,21 +71,32 @@ void createSphereInVolume(SimpleVolume& volData, float fRadius) int main(int argc, char *argv[]) { + setTraceStream(&(std::cout)); + setDebugStream(&(std::cout)); + setInfoStream(&(std::cout)); + //Create and show the Qt OpenGL window QApplication app(argc, argv); OpenGLWidget openGLWidget(0); openGLWidget.show(); //Create an empty volume and then place a sphere in it - SimpleVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63))); + RLECompressor* pCompressor = new RLECompressor(); + FilePager* pFilePager = new FilePager("D:/temp/voldata/"); + + LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63)), pCompressor, pFilePager, 32); + //volData.setMaxNumberOfUncompressedBlocks(6); + //volData.setMaxNumberOfBlocksInMemory(7); + + createSphereInVolume(volData, 30); //A mesh object to hold the result of surface extraction SurfaceMesh mesh; //Create a surface extractor. Comment out one of the following two lines to decide which type gets created. - CubicSurfaceExtractorWithNormals< SimpleVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); - //MarchingCubesSurfaceExtractor< SimpleVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); + CubicSurfaceExtractorWithNormals< LargeVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); + //MarchingCubesSurfaceExtractor< LargeVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); //Execute the surface extractor. surfaceExtractor.execute(); diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h index 5e28782d..97b9f2cc 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -54,7 +54,7 @@ namespace PolyVox virtual void pageIn(const Region& region, Block* pBlockData) { POLYVOX_ASSERT(pBlockData, "Attempting to page in NULL block"); - POLYVOX_ASSERT(pBlockData->m_bIsCompressed, "Attempting to page in uncompressed block"); + POLYVOX_ASSERT(pBlockData->isCompressed(), "Attempting to page in uncompressed block"); std::stringstream ss; ss << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_" @@ -71,13 +71,13 @@ namespace PolyVox logTrace() << "Paging in data for " << region; fseek(pFile, 0L, SEEK_END); - pBlockData->m_uCompressedDataLength = ftell(pFile); + size_t fileSizeInBytes = ftell(pFile); fseek(pFile, 0L, SEEK_SET); - - delete[] pBlockData->m_pCompressedData; - pBlockData->m_pCompressedData = new uint8_t[pBlockData->m_uCompressedDataLength]; - - fread(pBlockData->m_pCompressedData, sizeof(uint8_t), pBlockData->m_uCompressedDataLength, pFile); + + uint8_t* buffer = new uint8_t[fileSizeInBytes]; + fread(buffer, sizeof(uint8_t), fileSizeInBytes, pFile); + pBlockData->setCompressedData(buffer, fileSizeInBytes); + delete[] buffer; if(ferror(pFile)) { @@ -95,7 +95,7 @@ namespace PolyVox virtual void pageOut(const Region& region, Block* pBlockData) { POLYVOX_ASSERT(pBlockData, "Attempting to page out NULL block"); - POLYVOX_ASSERT(pBlockData->m_bIsCompressed, "Attempting to page out uncompressed block"); + POLYVOX_ASSERT(pBlockData->isCompressed(), "Attempting to page out uncompressed block"); logTrace() << "Paging out data for " << region; @@ -114,7 +114,7 @@ namespace PolyVox POLYVOX_THROW(std::runtime_error, "Unable to open file to write out block data."); } - fwrite(pBlockData->m_pCompressedData, sizeof(uint8_t), pBlockData->m_uCompressedDataLength, pFile); + fwrite(pBlockData->getCompressedData(), sizeof(uint8_t), pBlockData->getCompressedDataLength(), pFile); if(ferror(pFile)) { diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h index 93a9c0f0..8c3b68bd 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h @@ -51,12 +51,14 @@ namespace PolyVox public: Block(uint16_t uSideLength = 0); - const uint8_t* getCompressedData(void) const; + const uint8_t* const getCompressedData(void) const; const uint32_t getCompressedDataLength(void) const; uint16_t getSideLength(void) const; VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; VoxelType getVoxel(const Vector3DUint16& v3dPos) const; + bool isCompressed(void); + void setCompressedData(const uint8_t* const data, uint32_t dataLength); void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index 64fbe33b..c2f38883 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -52,7 +52,7 @@ namespace PolyVox } template - const uint8_t* Block::getCompressedData(void) const + const uint8_t* const Block::getCompressedData(void) const { POLYVOX_ASSERT(m_bIsCompressed, "You cannot call getCompressedData() when the block is not compressed"); POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); @@ -99,6 +99,12 @@ namespace PolyVox return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); } + template + bool Block::isCompressed(void) + { + return m_bIsCompressed; + } + template void Block::setCompressedData(const uint8_t* const data, uint32_t dataLength) { From c346d19d77da28c322ce667dec43560d4549a4f5 Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Tue, 25 Jun 2013 16:20:58 +0200 Subject: [PATCH 12/26] Doing some tidying in the Block class. --- .../include/PolyVoxCore/Impl/Block.h | 11 ----- .../include/PolyVoxCore/Impl/Block.inl | 41 ++++++++----------- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h index 8c3b68bd..8bc6c5fd 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h @@ -37,17 +37,6 @@ namespace PolyVox template class Block { - template - struct RunlengthEntry - { - LengthType length; - VoxelType value; - - //We can parametise the length on anything up to uint32_t. - //This lets us experiment with the optimal size in the future. - static uint32_t maxRunlength(void) {return (std::numeric_limits::max)();} - }; - public: Block(uint16_t uSideLength = 0); diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index c2f38883..edba9045 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -45,10 +45,25 @@ namespace PolyVox ,m_bIsCompressed(false) ,m_bIsUncompressedDataModified(true) { - if(uSideLength != 0) + if(uSideLength == 0) { - initialise(uSideLength); + POLYVOX_THROW(std::invalid_argument, "Block side cannot be zero."); } + + if(!isPowerOf2(uSideLength)) + { + POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two."); + } + + //Compute the side length + m_uSideLength = uSideLength; + m_uSideLengthPower = logBase2(uSideLength); + + //Create the block data + const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; + m_tUncompressedData = new VoxelType[uNoOfVoxels]; + std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, VoxelType()); + m_bIsUncompressedDataModified = true; } template @@ -145,28 +160,6 @@ namespace PolyVox setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); } - template - void Block::initialise(uint16_t uSideLength) - { - //Release mode validation - if(!isPowerOf2(uSideLength)) - { - POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two."); - } - - //Compute the side length - m_uSideLength = uSideLength; - m_uSideLengthPower = logBase2(uSideLength); - - //Create the block data - m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; - - //Clear it (should we bother?) - const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; - std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, VoxelType()); - m_bIsUncompressedDataModified = true; - } - template uint32_t Block::calculateSizeInBytes(void) { From baed7ddccc172b3989cf5d746b8179b7984f8284 Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Tue, 25 Jun 2013 16:45:53 +0200 Subject: [PATCH 13/26] Tidying up and refactoring of block class. --- .../include/PolyVoxCore/Impl/Block.h | 7 ++-- .../include/PolyVoxCore/Impl/Block.inl | 36 +++++++++---------- .../include/PolyVoxCore/LargeVolume.h | 4 +-- .../include/PolyVoxCore/LargeVolume.inl | 12 +++---- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h index 8bc6c5fd..2d4cfeee 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h @@ -38,7 +38,7 @@ namespace PolyVox class Block { public: - Block(uint16_t uSideLength = 0); + Block(uint16_t uSideLength, Compressor* pCompressor); const uint8_t* const getCompressedData(void) const; const uint32_t getCompressedDataLength(void) const; @@ -56,9 +56,10 @@ namespace PolyVox uint32_t calculateSizeInBytes(void); public: - void compress(Compressor* pCompressor); - void uncompress(Compressor* pCompressor); + void compress(); + void uncompress(); + Compressor* m_pCompressor; uint8_t* m_pCompressedData; uint32_t m_uCompressedDataLength; VoxelType* m_tUncompressedData; diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index edba9045..8a75beab 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -36,8 +36,9 @@ freely, subject to the following restrictions: namespace PolyVox { template - Block::Block(uint16_t uSideLength) - :m_pCompressedData(0) + Block::Block(uint16_t uSideLength, Compressor* pCompressor) + :m_pCompressor(pCompressor) + ,m_pCompressedData(0) ,m_uCompressedDataLength(0) ,m_tUncompressedData(0) ,m_uSideLength(0) @@ -47,7 +48,7 @@ namespace PolyVox { if(uSideLength == 0) { - POLYVOX_THROW(std::invalid_argument, "Block side cannot be zero."); + POLYVOX_THROW(std::invalid_argument, "Block side length cannot be zero."); } if(!isPowerOf2(uSideLength)) @@ -55,6 +56,11 @@ namespace PolyVox POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two."); } + if(pCompressor == 0) + { + POLYVOX_THROW(std::invalid_argument, "Block must be provided with a valid compressor."); + } + //Compute the side length m_uSideLength = uSideLength; m_uSideLengthPower = logBase2(uSideLength); @@ -169,18 +175,13 @@ namespace PolyVox } template - void Block::compress(Compressor* pCompressor) + void Block::compress() { if(m_bIsCompressed) { POLYVOX_THROW(invalid_operation, "Attempted to compress block which is already flagged as compressed."); } - if(!pCompressor) - { - POLYVOX_THROW(std::invalid_argument, "A valid compressor must be provided"); - } - POLYVOX_ASSERT(m_tUncompressedData != 0, "No uncompressed data is present."); //If the uncompressed data hasn't actually been @@ -202,7 +203,7 @@ namespace PolyVox try { - uCompressedLength = pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); + uCompressedLength = m_pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); // Create new compressed data and copy across m_pCompressedData = new uint8_t[uCompressedLength]; @@ -214,7 +215,9 @@ namespace PolyVox // It is possible for the compression to fail. A common cause for this would be if the destination // buffer is not big enough. So now we try again using a buffer that is definitely big enough. // Note that ideally we will choose our earlier buffer size so that this almost never happens. - uint32_t uMaxCompressedSize = pCompressor->getMaxCompressedSize(uSrcLength); + logWarning() << "The compressor failed to compress the block, proabaly due to the buffer being too small."; + logWarning() << "The compression will be tried again with a larger buffer"; + uint32_t uMaxCompressedSize = m_pCompressor->getMaxCompressedSize(uSrcLength); uint8_t* buffer = new uint8_t[ uMaxCompressedSize ]; pDstData = reinterpret_cast( buffer ); @@ -222,7 +225,7 @@ namespace PolyVox try { - uCompressedLength = pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); + uCompressedLength = m_pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength); // Create new compressed data and copy across m_pCompressedData = new uint8_t[uCompressedLength]; @@ -248,18 +251,13 @@ namespace PolyVox } template - void Block::uncompress(Compressor* pCompressor) + void Block::uncompress() { if(!m_bIsCompressed) { POLYVOX_THROW(invalid_operation, "Attempted to uncompress block which is not flagged as compressed."); } - if(!pCompressor) - { - POLYVOX_THROW(std::invalid_argument, "A valid compressor must be provided"); - } - POLYVOX_ASSERT(m_tUncompressedData == 0, "Uncompressed data already exists."); m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; @@ -271,7 +269,7 @@ namespace PolyVox //MinizCompressor compressor; //RLECompressor compressor; - uint32_t uUncompressedLength = pCompressor->decompress(pSrcData, uSrcLength, pDstData, uDstLength); + uint32_t uUncompressedLength = m_pCompressor->decompress(pSrcData, uSrcLength, pDstData, uDstLength); POLYVOX_ASSERT(uUncompressedLength == m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType), "Destination length has changed."); diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index 6de905b3..8e46cb79 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -234,8 +234,8 @@ namespace PolyVox struct LoadedBlock { public: - LoadedBlock(uint16_t uSideLength = 0) - :block(uSideLength) + LoadedBlock(uint16_t uSideLength, Compressor* pCompressor) + :block(uSideLength, pCompressor) ,timestamp(0) { } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 6322135b..9fc1d7c1 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -471,7 +471,7 @@ namespace PolyVox { for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) { - m_vecUncompressedBlockCache[ct]->block.compress(m_pCompressor); + m_vecUncompressedBlockCache[ct]->block.compress(); } m_vecUncompressedBlockCache.clear(); } @@ -552,7 +552,7 @@ namespace PolyVox if(m_vecUncompressedBlockCache[ct] == &(itBlock->second)) { // TODO: compression is unneccessary? or will not compressing this cause a memleak? - itBlock->second.block.compress(m_pCompressor); + itBlock->second.block.compress(); // put last object in cache here m_vecUncompressedBlockCache[ct] = m_vecUncompressedBlockCache.back(); // decrease cache size by one since last element is now in here twice @@ -630,12 +630,12 @@ namespace PolyVox } // create the new block - LoadedBlock newBlock(m_uBlockSideLength); + LoadedBlock newBlock(m_uBlockSideLength, m_pCompressor); // Blocks start out compressed - should we change this? // Or maybe we should just 'seed' them with compressed data, // rather than creating an empty block and then compressing? - newBlock.block.compress(m_pCompressor); + newBlock.block.compress(); itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; @@ -688,7 +688,7 @@ namespace PolyVox } //Compress the least recently used block. - m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.compress(m_pCompressor); + m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.compress(); //We don't actually remove any elements from this vector, we //simply change the pointer to point at the new uncompressed bloack. @@ -699,7 +699,7 @@ namespace PolyVox m_vecUncompressedBlockCache.push_back(&loadedBlock); } - loadedBlock.block.uncompress(m_pCompressor); + loadedBlock.block.uncompress(); m_pLastAccessedBlock = &(loadedBlock.block); POLYVOX_ASSERT(m_pLastAccessedBlock->m_tUncompressedData, "Block has no uncompressed data"); From 6b92a5ab51f112f25437139cea52a20915006e47 Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Tue, 25 Jun 2013 17:04:10 +0200 Subject: [PATCH 14/26] More tidying/refaxctoring of Block class. --- .../include/PolyVoxCore/FilePager.h | 2 -- .../include/PolyVoxCore/Impl/Block.h | 3 +-- .../include/PolyVoxCore/Impl/Block.inl | 24 +++++++------------ .../include/PolyVoxCore/LargeVolume.inl | 2 +- 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h index 97b9f2cc..07dc94e1 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -54,7 +54,6 @@ namespace PolyVox virtual void pageIn(const Region& region, Block* pBlockData) { POLYVOX_ASSERT(pBlockData, "Attempting to page in NULL block"); - POLYVOX_ASSERT(pBlockData->isCompressed(), "Attempting to page in uncompressed block"); std::stringstream ss; ss << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_" @@ -95,7 +94,6 @@ namespace PolyVox virtual void pageOut(const Region& region, Block* pBlockData) { POLYVOX_ASSERT(pBlockData, "Attempting to page out NULL block"); - POLYVOX_ASSERT(pBlockData->isCompressed(), "Attempting to page out uncompressed block"); logTrace() << "Paging out data for " << region; diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h index 2d4cfeee..cc6253b6 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h @@ -46,7 +46,7 @@ namespace PolyVox VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; VoxelType getVoxel(const Vector3DUint16& v3dPos) const; - bool isCompressed(void); + bool hasUncompressedData(void) const; void setCompressedData(const uint8_t* const data, uint32_t dataLength); void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); @@ -65,7 +65,6 @@ namespace PolyVox VoxelType* m_tUncompressedData; uint16_t m_uSideLength; uint8_t m_uSideLengthPower; - bool m_bIsCompressed; bool m_bIsUncompressedDataModified; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index 8a75beab..39bddb3a 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -43,7 +43,6 @@ namespace PolyVox ,m_tUncompressedData(0) ,m_uSideLength(0) ,m_uSideLengthPower(0) - ,m_bIsCompressed(false) ,m_bIsUncompressedDataModified(true) { if(uSideLength == 0) @@ -75,18 +74,14 @@ namespace PolyVox template const uint8_t* const Block::getCompressedData(void) const { - POLYVOX_ASSERT(m_bIsCompressed, "You cannot call getCompressedData() when the block is not compressed"); POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); - return m_pCompressedData; } template const uint32_t Block::getCompressedDataLength(void) const { - POLYVOX_ASSERT(m_bIsCompressed, "You cannot call getCompressedData() when the block is not compressed"); POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); - return m_uCompressedDataLength; } @@ -103,7 +98,7 @@ namespace PolyVox POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block"); - POLYVOX_ASSERT(!m_bIsCompressed, "You cannot call getVoxel() when a block is compressed"); + POLYVOX_ASSERT(hasUncompressedData(), "The block must have uncompressed data to call getVoxel()"); POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels."); return m_tUncompressedData @@ -121,15 +116,14 @@ namespace PolyVox } template - bool Block::isCompressed(void) + bool Block::hasUncompressedData(void) const { - return m_bIsCompressed; + return m_tUncompressedData != 0; } template void Block::setCompressedData(const uint8_t* const data, uint32_t dataLength) { - POLYVOX_ASSERT(m_bIsCompressed, "You cannot call setCompressedData() when the block is not compressed"); POLYVOX_ASSERT(m_pCompressedData, "Compressed data is NULL"); POLYVOX_ASSERT(m_pCompressedData != data, "Attempting to copy data onto itself"); @@ -147,7 +141,7 @@ namespace PolyVox POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block"); POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block"); - POLYVOX_ASSERT(!m_bIsCompressed, "You cannot call setVoxelAt() when a block is compressed"); + POLYVOX_ASSERT(hasUncompressedData(), "The block must have uncompressed data to call setVoxelAt()"); POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels."); m_tUncompressedData @@ -177,9 +171,9 @@ namespace PolyVox template void Block::compress() { - if(m_bIsCompressed) + if(!hasUncompressedData()) { - POLYVOX_THROW(invalid_operation, "Attempted to compress block which is already flagged as compressed."); + POLYVOX_THROW(invalid_operation, "No uncompressed data to compress."); } POLYVOX_ASSERT(m_tUncompressedData != 0, "No uncompressed data is present."); @@ -247,15 +241,14 @@ namespace PolyVox //Flag the uncompressed data as no longer being used. delete[] m_tUncompressedData; m_tUncompressedData = 0; - m_bIsCompressed = true; } template void Block::uncompress() { - if(!m_bIsCompressed) + if(hasUncompressedData()) { - POLYVOX_THROW(invalid_operation, "Attempted to uncompress block which is not flagged as compressed."); + POLYVOX_THROW(invalid_operation, "Uncompressed data already exists."); } POLYVOX_ASSERT(m_tUncompressedData == 0, "Uncompressed data already exists."); @@ -275,7 +268,6 @@ namespace PolyVox //m_tUncompressedData = reinterpret_cast(uncompressedResult.ptr); - m_bIsCompressed = false; m_bIsUncompressedDataModified = false; } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 9fc1d7c1..47746f4d 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -663,7 +663,7 @@ namespace PolyVox m_v3dLastAccessedBlockPos = v3dBlockPos; m_pLastAccessedBlock = &(loadedBlock.block); - if(loadedBlock.block.m_bIsCompressed == false) + if(loadedBlock.block.hasUncompressedData()) { POLYVOX_ASSERT(m_pLastAccessedBlock->m_tUncompressedData, "Block has no uncompressed data"); return m_pLastAccessedBlock; From a2210fc3f01d1ac484a0b5ea27fd25c777da23af Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 25 Jun 2013 20:57:50 +0200 Subject: [PATCH 15/26] Renamed compress and uncompress functions. --- .../include/PolyVoxCore/Impl/Block.h | 7 +++---- .../include/PolyVoxCore/Impl/Block.inl | 20 +++++++++---------- .../include/PolyVoxCore/LargeVolume.inl | 10 +++++----- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h index cc6253b6..ed9ca146 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h @@ -52,13 +52,12 @@ namespace PolyVox void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); - void initialise(uint16_t uSideLength); + void createUncompressedData(void); + void destroyUncompressedData(void); + uint32_t calculateSizeInBytes(void); public: - void compress(); - void uncompress(); - Compressor* m_pCompressor; uint8_t* m_pCompressedData; uint32_t m_uCompressedDataLength; diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index 39bddb3a..cf103eaa 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -161,15 +161,7 @@ namespace PolyVox } template - uint32_t Block::calculateSizeInBytes(void) - { - //FIXME - This function is incomplete. - uint32_t uSizeInBytes = sizeof(Block); - return uSizeInBytes; - } - - template - void Block::compress() + void Block::destroyUncompressedData() { if(!hasUncompressedData()) { @@ -244,7 +236,7 @@ namespace PolyVox } template - void Block::uncompress() + void Block::createUncompressedData() { if(hasUncompressedData()) { @@ -270,4 +262,12 @@ namespace PolyVox m_bIsUncompressedDataModified = false; } + + template + uint32_t Block::calculateSizeInBytes(void) + { + //FIXME - This function is incomplete. + uint32_t uSizeInBytes = sizeof(Block); + return uSizeInBytes; + } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 47746f4d..b49ce49f 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -471,7 +471,7 @@ namespace PolyVox { for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) { - m_vecUncompressedBlockCache[ct]->block.compress(); + m_vecUncompressedBlockCache[ct]->block.destroyUncompressedData(); } m_vecUncompressedBlockCache.clear(); } @@ -552,7 +552,7 @@ namespace PolyVox if(m_vecUncompressedBlockCache[ct] == &(itBlock->second)) { // TODO: compression is unneccessary? or will not compressing this cause a memleak? - itBlock->second.block.compress(); + itBlock->second.block.destroyUncompressedData(); // put last object in cache here m_vecUncompressedBlockCache[ct] = m_vecUncompressedBlockCache.back(); // decrease cache size by one since last element is now in here twice @@ -635,7 +635,7 @@ namespace PolyVox // Blocks start out compressed - should we change this? // Or maybe we should just 'seed' them with compressed data, // rather than creating an empty block and then compressing? - newBlock.block.compress(); + newBlock.block.destroyUncompressedData(); itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; @@ -688,7 +688,7 @@ namespace PolyVox } //Compress the least recently used block. - m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.compress(); + m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.destroyUncompressedData(); //We don't actually remove any elements from this vector, we //simply change the pointer to point at the new uncompressed bloack. @@ -699,7 +699,7 @@ namespace PolyVox m_vecUncompressedBlockCache.push_back(&loadedBlock); } - loadedBlock.block.uncompress(); + loadedBlock.block.createUncompressedData(); m_pLastAccessedBlock = &(loadedBlock.block); POLYVOX_ASSERT(m_pLastAccessedBlock->m_tUncompressedData, "Block has no uncompressed data"); From 900e4e0ecda1be0955cfdd9e0e7eb3ff37ec022c Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 25 Jun 2013 21:18:06 +0200 Subject: [PATCH 16/26] Refactoring some LargeVolume code... --- .../include/PolyVoxCore/LargeVolume.h | 2 +- .../include/PolyVoxCore/LargeVolume.inl | 51 +++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index 8e46cb79..c0643a75 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -363,7 +363,7 @@ namespace PolyVox //than in the Block class. This is so that in the future each VolumeIterator might to maintain its own cache //of blocks. However, this could mean the same block data is uncompressed and modified in more than one //location in memory... could be messy with threading. - mutable std::vector< LoadedBlock* > m_vecUncompressedBlockCache; + mutable std::vector< LoadedBlock* > m_vecBlocksWithUncompressedData; mutable uint32_t m_uTimestamper; mutable Vector3DInt32 m_v3dLastAccessedBlockPos; mutable Block* m_pLastAccessedBlock; diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index b49ce49f..66b711f7 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -469,11 +469,11 @@ namespace PolyVox template void LargeVolume::clearBlockCache(void) { - for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) + for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++) { - m_vecUncompressedBlockCache[ct]->block.destroyUncompressedData(); + m_vecBlocksWithUncompressedData[ct]->block.destroyUncompressedData(); } - m_vecUncompressedBlockCache.clear(); + m_vecBlocksWithUncompressedData.clear(); } //////////////////////////////////////////////////////////////////////////////// @@ -544,23 +544,22 @@ namespace PolyVox m_pPager->dataOverflowHandler(ConstVolumeProxy, reg); } - if(m_pCompressor) + + for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++) { - for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) + // find the block in the uncompressed cache + if(m_vecBlocksWithUncompressedData[ct] == &(itBlock->second)) { - // find the block in the uncompressed cache - if(m_vecUncompressedBlockCache[ct] == &(itBlock->second)) - { - // TODO: compression is unneccessary? or will not compressing this cause a memleak? - itBlock->second.block.destroyUncompressedData(); - // put last object in cache here - m_vecUncompressedBlockCache[ct] = m_vecUncompressedBlockCache.back(); - // decrease cache size by one since last element is now in here twice - m_vecUncompressedBlockCache.resize(m_vecUncompressedBlockCache.size()-1); - break; - } + // TODO: compression is unneccessary? or will not compressing this cause a memleak? + itBlock->second.block.destroyUncompressedData(); + // put last object in cache here + m_vecBlocksWithUncompressedData[ct] = m_vecBlocksWithUncompressedData.back(); + // decrease cache size by one since last element is now in here twice + m_vecBlocksWithUncompressedData.resize(m_vecBlocksWithUncompressedData.size()-1); + break; } } + m_pBlocks.erase(itBlock); } @@ -635,7 +634,7 @@ namespace PolyVox // Blocks start out compressed - should we change this? // Or maybe we should just 'seed' them with compressed data, // rather than creating an empty block and then compressing? - newBlock.block.destroyUncompressedData(); + //newBlock.block.destroyUncompressedData(); itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; @@ -670,7 +669,7 @@ namespace PolyVox } //If we are allowed to compress then check whether we need to - if((m_pCompressor) && (m_vecUncompressedBlockCache.size() == m_uMaxNumberOfUncompressedBlocks)) + if(m_vecBlocksWithUncompressedData.size() == m_uMaxNumberOfUncompressedBlocks) { int32_t leastRecentlyUsedBlockIndex = -1; uint32_t uLeastRecentTimestamp = (std::numeric_limits::max)(); @@ -678,25 +677,25 @@ namespace PolyVox //Currently we find the oldest block by iterating over the whole array. Of course we could store the blocks sorted by //timestamp (set, priority_queue, etc) but then we'll need to move them around as the timestamp changes. Can come back //to this if it proves to be a bottleneck (compraed to the cost of actually doing the compression/decompression). - for(uint32_t ct = 0; ct < m_vecUncompressedBlockCache.size(); ct++) + for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++) { - if(m_vecUncompressedBlockCache[ct]->timestamp < uLeastRecentTimestamp) + if(m_vecBlocksWithUncompressedData[ct]->timestamp < uLeastRecentTimestamp) { - uLeastRecentTimestamp = m_vecUncompressedBlockCache[ct]->timestamp; + uLeastRecentTimestamp = m_vecBlocksWithUncompressedData[ct]->timestamp; leastRecentlyUsedBlockIndex = ct; } } //Compress the least recently used block. - m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex]->block.destroyUncompressedData(); + m_vecBlocksWithUncompressedData[leastRecentlyUsedBlockIndex]->block.destroyUncompressedData(); //We don't actually remove any elements from this vector, we //simply change the pointer to point at the new uncompressed bloack. - m_vecUncompressedBlockCache[leastRecentlyUsedBlockIndex] = &loadedBlock; + m_vecBlocksWithUncompressedData[leastRecentlyUsedBlockIndex] = &loadedBlock; } else { - m_vecUncompressedBlockCache.push_back(&loadedBlock); + m_vecBlocksWithUncompressedData.push_back(&loadedBlock); } loadedBlock.block.createUncompressedData(); @@ -734,8 +733,8 @@ namespace PolyVox } //Memory used by the block cache. - uSizeInBytes += m_vecUncompressedBlockCache.capacity() * sizeof(LoadedBlock); - uSizeInBytes += m_vecUncompressedBlockCache.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); + uSizeInBytes += m_vecBlocksWithUncompressedData.capacity() * sizeof(LoadedBlock); + uSizeInBytes += m_vecBlocksWithUncompressedData.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); return uSizeInBytes; } From 0cf3de4e7644df99a3e2bb6020fa9ec43985d0c7 Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 25 Jun 2013 22:54:40 +0200 Subject: [PATCH 17/26] Removed LoadedBlock and put timestamp into regular Block. --- .../include/PolyVoxCore/Impl/Block.h | 2 + .../include/PolyVoxCore/LargeVolume.h | 18 ++----- .../include/PolyVoxCore/LargeVolume.inl | 49 +++++++++---------- 3 files changed, 27 insertions(+), 42 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h index ed9ca146..8a9932c0 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h @@ -65,6 +65,8 @@ namespace PolyVox uint16_t m_uSideLength; uint8_t m_uSideLengthPower; bool m_bIsUncompressedDataModified; + + uint32_t timestamp; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index c0643a75..daded00b 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -231,18 +231,6 @@ namespace PolyVox // Make the ConstVolumeProxy a friend friend class ConstVolumeProxy; - struct LoadedBlock - { - public: - LoadedBlock(uint16_t uSideLength, Compressor* pCompressor) - :block(uSideLength, pCompressor) - ,timestamp(0) - { - } - - Block block; - uint32_t timestamp; - }; #endif public: @@ -352,18 +340,18 @@ namespace PolyVox //polyvox_function&, const Region&)> m_funcDataOverflowHandler; Block* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; - void eraseBlock(typename std::map::iterator itBlock) const; + void eraseBlock(typename std::map, 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 m_pBlocks; + mutable std::map, 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 //of blocks. However, this could mean the same block data is uncompressed and modified in more than one //location in memory... could be messy with threading. - mutable std::vector< LoadedBlock* > m_vecBlocksWithUncompressedData; + mutable std::vector< Block* > m_vecBlocksWithUncompressedData; mutable uint32_t m_uTimestamper; mutable Vector3DInt32 m_v3dLastAccessedBlockPos; mutable Block* m_pLastAccessedBlock; diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 66b711f7..8f9e6085 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -381,7 +381,7 @@ namespace PolyVox for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++) { Vector3DInt32 pos(x,y,z); - typename std::map::iterator itBlock = m_pBlocks.find(pos); + typename std::map, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(pos); if(itBlock != m_pBlocks.end()) { @@ -412,7 +412,7 @@ namespace PolyVox template void LargeVolume::flushAll() { - typename std::map::iterator i; + typename std::map, BlockPositionCompare>::iterator i; //Replaced the for loop here as the call to //eraseBlock was invalidating the iterator. while(m_pBlocks.size() > 0) @@ -446,7 +446,7 @@ namespace PolyVox for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++) { Vector3DInt32 pos(x,y,z); - typename std::map::iterator itBlock = m_pBlocks.find(pos); + typename std::map, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(pos); if(itBlock == m_pBlocks.end()) { // not loaded, not unloading @@ -471,7 +471,7 @@ namespace PolyVox { for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++) { - m_vecBlocksWithUncompressedData[ct]->block.destroyUncompressedData(); + m_vecBlocksWithUncompressedData[ct]->destroyUncompressedData(); } m_vecBlocksWithUncompressedData.clear(); } @@ -531,7 +531,7 @@ namespace PolyVox } template - void LargeVolume::eraseBlock(typename std::map::iterator itBlock) const + void LargeVolume::eraseBlock(typename std::map, BlockPositionCompare>::iterator itBlock) const { if(m_pPager) { @@ -551,7 +551,7 @@ namespace PolyVox if(m_vecBlocksWithUncompressedData[ct] == &(itBlock->second)) { // TODO: compression is unneccessary? or will not compressing this cause a memleak? - itBlock->second.block.destroyUncompressedData(); + itBlock->second.destroyUncompressedData(); // put last object in cache here m_vecBlocksWithUncompressedData[ct] = m_vecBlocksWithUncompressedData.back(); // decrease cache size by one since last element is now in here twice @@ -602,7 +602,7 @@ namespace PolyVox return m_pLastAccessedBlock; } - typename std::map::iterator itBlock = m_pBlocks.find(v3dBlockPos); + typename std::map, BlockPositionCompare>::iterator itBlock = m_pBlocks.find(v3dBlockPos); // check whether the block is already loaded if(itBlock == m_pBlocks.end()) { @@ -615,8 +615,8 @@ namespace PolyVox if(m_pBlocks.size() == m_uMaxNumberOfBlocksInMemory) { // find the least recently used block - typename std::map::iterator i; - typename std::map::iterator itUnloadBlock = m_pBlocks.begin(); + typename std::map, BlockPositionCompare>::iterator i; + typename std::map, BlockPositionCompare>::iterator itUnloadBlock = m_pBlocks.begin(); for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++) { if(i->second.timestamp < itUnloadBlock->second.timestamp) @@ -629,12 +629,7 @@ namespace PolyVox } // create the new block - LoadedBlock newBlock(m_uBlockSideLength, m_pCompressor); - - // Blocks start out compressed - should we change this? - // Or maybe we should just 'seed' them with compressed data, - // rather than creating an empty block and then compressing? - //newBlock.block.destroyUncompressedData(); + Block newBlock(m_uBlockSideLength, m_pCompressor); itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; @@ -657,12 +652,12 @@ namespace PolyVox } //Get the block and mark that we accessed it - LoadedBlock& loadedBlock = itBlock->second; - loadedBlock.timestamp = ++m_uTimestamper; + Block& block = itBlock->second; + block.timestamp = ++m_uTimestamper; m_v3dLastAccessedBlockPos = v3dBlockPos; - m_pLastAccessedBlock = &(loadedBlock.block); + m_pLastAccessedBlock = █ - if(loadedBlock.block.hasUncompressedData()) + if(block.hasUncompressedData()) { POLYVOX_ASSERT(m_pLastAccessedBlock->m_tUncompressedData, "Block has no uncompressed data"); return m_pLastAccessedBlock; @@ -687,20 +682,20 @@ namespace PolyVox } //Compress the least recently used block. - m_vecBlocksWithUncompressedData[leastRecentlyUsedBlockIndex]->block.destroyUncompressedData(); + m_vecBlocksWithUncompressedData[leastRecentlyUsedBlockIndex]->destroyUncompressedData(); //We don't actually remove any elements from this vector, we //simply change the pointer to point at the new uncompressed bloack. - m_vecBlocksWithUncompressedData[leastRecentlyUsedBlockIndex] = &loadedBlock; + m_vecBlocksWithUncompressedData[leastRecentlyUsedBlockIndex] = █ } else { - m_vecBlocksWithUncompressedData.push_back(&loadedBlock); + m_vecBlocksWithUncompressedData.push_back(&block); } - loadedBlock.block.createUncompressedData(); + block.createUncompressedData(); - m_pLastAccessedBlock = &(loadedBlock.block); + m_pLastAccessedBlock = &(block); POLYVOX_ASSERT(m_pLastAccessedBlock->m_tUncompressedData, "Block has no uncompressed data"); return m_pLastAccessedBlock; } @@ -725,15 +720,15 @@ namespace PolyVox uint32_t uSizeInBytes = sizeof(LargeVolume); //Memory used by the blocks - typename std::map::iterator i; + typename std::map, BlockPositionCompare>::iterator i; for(i = m_pBlocks.begin(); i != m_pBlocks.end(); i++) { //Inaccurate - account for rest of loaded block. - uSizeInBytes += i->second.block.calculateSizeInBytes(); + uSizeInBytes += i->second.calculateSizeInBytes(); } //Memory used by the block cache. - uSizeInBytes += m_vecBlocksWithUncompressedData.capacity() * sizeof(LoadedBlock); + uSizeInBytes += m_vecBlocksWithUncompressedData.capacity() * sizeof(Block); uSizeInBytes += m_vecBlocksWithUncompressedData.size() * m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength * sizeof(VoxelType); return uSizeInBytes; From 8ab6d73f0af7f1dbd13060d83980fffa92b750c5 Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 25 Jun 2013 23:34:58 +0200 Subject: [PATCH 18/26] Work on LargeVolume refactoring - getting FilePager working. --- examples/Basic/main.cpp | 4 ++-- .../PolyVoxCore/include/PolyVoxCore/FilePager.h | 2 ++ .../include/PolyVoxCore/Impl/Block.inl | 5 ++++- .../include/PolyVoxCore/LargeVolume.inl | 16 +++++++++++----- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index 40bf0058..444e71fb 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -85,8 +85,8 @@ int main(int argc, char *argv[]) FilePager* pFilePager = new FilePager("D:/temp/voldata/"); LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63)), pCompressor, pFilePager, 32); - //volData.setMaxNumberOfUncompressedBlocks(6); - //volData.setMaxNumberOfBlocksInMemory(7); + volData.setMaxNumberOfUncompressedBlocks(6); + volData.setMaxNumberOfBlocksInMemory(7); createSphereInVolume(volData, 30); diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h index 07dc94e1..5d8d97ed 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -54,6 +54,7 @@ namespace PolyVox virtual void pageIn(const Region& region, Block* pBlockData) { POLYVOX_ASSERT(pBlockData, "Attempting to page in NULL block"); + POLYVOX_ASSERT(pBlockData->hasUncompressedData() == false, "Block should not have uncompressed data"); std::stringstream ss; ss << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_" @@ -94,6 +95,7 @@ namespace PolyVox virtual void pageOut(const Region& region, Block* pBlockData) { POLYVOX_ASSERT(pBlockData, "Attempting to page out NULL block"); + POLYVOX_ASSERT(pBlockData->hasUncompressedData() == false, "Block should not have uncompressed data"); logTrace() << "Paging out data for " << region; diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index cf103eaa..3076d2bb 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -64,11 +64,14 @@ namespace PolyVox m_uSideLength = uSideLength; m_uSideLengthPower = logBase2(uSideLength); - //Create the block data + //Temporarily create the block data. This is just so we can compress it an discard it. + // FIXME - this is a temporary solution. const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; m_tUncompressedData = new VoxelType[uNoOfVoxels]; std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, VoxelType()); m_bIsUncompressedDataModified = true; + + destroyUncompressedData(); } template diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 8f9e6085..dccaa4cd 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -540,9 +540,11 @@ namespace PolyVox Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); Region reg(v3dLower, v3dUpper); - ConstVolumeProxy ConstVolumeProxy(*this, reg); + /*ConstVolumeProxy ConstVolumeProxy(*this, reg); - m_pPager->dataOverflowHandler(ConstVolumeProxy, reg); + m_pPager->dataOverflowHandler(ConstVolumeProxy, reg);*/ + + m_pPager->pageOut(reg, &(itBlock->second)); } for(uint32_t ct = 0; ct < m_vecBlocksWithUncompressedData.size(); ct++) @@ -631,7 +633,9 @@ namespace PolyVox // create the new block Block newBlock(m_uBlockSideLength, m_pCompressor); - itBlock = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)).first; + auto retVal = m_pBlocks.insert(std::make_pair(v3dBlockPos, newBlock)); + itBlock = retVal.first; + POLYVOX_ASSERT(retVal.second == true, "Element was not supposed to exist!"); //We have created the new block. If paging is enabled it should be used to //fill in the required data. Otherwise it is just left in the default state. @@ -645,8 +649,10 @@ namespace PolyVox Vector3DInt32 v3dLower(v3dBlockPos.getX() << m_uBlockSideLengthPower, v3dBlockPos.getY() << m_uBlockSideLengthPower, v3dBlockPos.getZ() << m_uBlockSideLengthPower); Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); Region reg(v3dLower, v3dUpper); - ConstVolumeProxy ConstVolumeProxy(*this, reg); - m_pPager->dataRequiredHandler(ConstVolumeProxy, reg); + /*ConstVolumeProxy ConstVolumeProxy(*this, reg); + m_pPager->dataRequiredHandler(ConstVolumeProxy, reg);*/ + + m_pPager->pageIn(reg, &(itBlock->second)); } } } From 44d525f5912f2eb232d0b9355f0f058f73c1508b Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Wed, 26 Jun 2013 17:02:06 +0200 Subject: [PATCH 19/26] Tidying up and refactoring LargeVolume. --- examples/Basic/main.cpp | 6 +-- examples/Paging/main.cpp | 2 +- .../include/PolyVoxCore/LargeVolume.h | 35 +++++++------ .../include/PolyVoxCore/LargeVolume.inl | 51 ++++++++++++------- 4 files changed, 55 insertions(+), 39 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index 444e71fb..407d4e8e 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -82,11 +82,11 @@ int main(int argc, char *argv[]) //Create an empty volume and then place a sphere in it RLECompressor* pCompressor = new RLECompressor(); - FilePager* pFilePager = new FilePager("D:/temp/voldata/"); + FilePager* pFilePager = new FilePager("C:/temp/voldata/"); LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63)), pCompressor, pFilePager, 32); - volData.setMaxNumberOfUncompressedBlocks(6); - volData.setMaxNumberOfBlocksInMemory(7); + volData.setMaxNumberOfUncompressedBlocks(2); + volData.setMaxNumberOfBlocksInMemory(4); createSphereInVolume(volData, 30); diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 4622764c..03601f9b 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -332,7 +332,7 @@ int main(int argc, char *argv[]) //If these lines don't compile, please try commenting them out and using the two lines after //(you will need Boost for this). If you have to do this then please let us know in the forums as //we rely on community feedback to keep the Boost version running. - LargeVolume volData(compressor, pager, 256); + LargeVolume volData(Region::MaxRegion, compressor, pager, 256); //LargeVolume volData(polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2), // polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2), 256); volData.setMaxNumberOfBlocksInMemory(4096); diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index daded00b..581f1adf 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -233,20 +233,19 @@ namespace PolyVox #endif - public: - /// Constructor for creating a very large paging volume. + public: + /// Constructor for creating a fixed size volume. LargeVolume ( - Compressor* pCompressor, - Pager* pPager, - uint16_t uBlockSideLength = 32 + const Region& regValid, + uint16_t uBlockSideLength = 32 ); /// Constructor for creating a fixed size volume. LargeVolume ( const Region& regValid, - Compressor* pCompressor, - Pager* pPager, + Compressor* pCompressor, + Pager* pPager , uint16_t uBlockSideLength = 32 ); /// Destructor @@ -319,7 +318,7 @@ namespace PolyVox return false; } }; - void initialise(const Region& regValidRegion, uint16_t uBlockSideLength); + void initialise(); // A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057 template @@ -344,13 +343,13 @@ namespace PolyVox /// 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 + // The block data mutable std::map, 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 - //of blocks. However, this could mean the same block data is uncompressed and modified in more than one - //location in memory... could be messy with threading. + // 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 + // of blocks. However, this could mean the same block data is uncompressed and modified in more than one + // location in memory... could be messy with threading. mutable std::vector< Block* > m_vecBlocksWithUncompressedData; mutable uint32_t m_uTimestamper; mutable Vector3DInt32 m_v3dLastAccessedBlockPos; @@ -358,16 +357,20 @@ namespace PolyVox uint32_t m_uMaxNumberOfUncompressedBlocks; uint32_t m_uMaxNumberOfBlocksInMemory; - //The size of the volume + // The size of the volume Region m_regValidRegionInBlocks; - //The size of the blocks + // The size of the blocks uint16_t m_uBlockSideLength; uint8_t m_uBlockSideLengthPower; - //The compressor used by the Blocks to compress their data if required. + // The compressor used by the Blocks to compress their data if required. Compressor* m_pCompressor; Pager* m_pPager; + + // Whether we created the compressor or whether it was provided + // by the user. This controls whether we delete it on destruction. + bool m_bIsOurCompressor; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index dccaa4cd..640ddc3e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -23,6 +23,8 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Impl/ErrorHandling.h" +#include "PolyVoxCore/MinizCompressor.h" + //Included here rather than in the .h because it refers to LargeVolume (avoids forward declaration) #include "PolyVoxCore/ConstVolumeProxy.h" @@ -37,16 +39,19 @@ namespace PolyVox template LargeVolume::LargeVolume ( - Compressor* pCompressor, - Pager* pPager, - uint16_t uBlockSideLength + const Region& regValid, + uint16_t uBlockSideLength ) - :BaseVolume(Region::MaxRegion) - ,m_pCompressor(pCompressor) + :BaseVolume(regValid) { - m_pPager = pPager; - //Create a volume of the right size. - initialise(Region::MaxRegion,uBlockSideLength); + m_uBlockSideLength = uBlockSideLength; + + m_pCompressor = new MinizCompressor(); + m_bIsOurCompressor = true; + + m_pPager = 0; + + initialise(); } //////////////////////////////////////////////////////////////////////////////// @@ -67,12 +72,16 @@ namespace PolyVox uint16_t uBlockSideLength ) :BaseVolume(regValid) - ,m_pCompressor(pCompressor) { + + m_uBlockSideLength = uBlockSideLength; + + m_pCompressor = pCompressor; + m_bIsOurCompressor = false; + m_pPager = pPager; - //Create a volume of the right size. - initialise(regValid,uBlockSideLength); + initialise(); } //////////////////////////////////////////////////////////////////////////////// @@ -95,6 +104,12 @@ namespace PolyVox LargeVolume::~LargeVolume() { flushAll(); + + // Only delete the compressor if it was created by us (in the constructor), not by the user. + if(m_bIsOurCompressor) + { + delete m_pCompressor; + } } //////////////////////////////////////////////////////////////////////////////// @@ -480,33 +495,31 @@ namespace PolyVox /// This function should probably be made internal... //////////////////////////////////////////////////////////////////////////////// template - void LargeVolume::initialise(const Region& regValidRegion, uint16_t uBlockSideLength) + void LargeVolume::initialise() { //Validate parameters - if(uBlockSideLength == 0) + if(m_uBlockSideLength == 0) { POLYVOX_THROW(std::invalid_argument, "Block side length cannot be zero."); } - if(!isPowerOf2(uBlockSideLength)) + + if(!isPowerOf2(m_uBlockSideLength)) { POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two."); } + if(!m_pCompressor) { - POLYVOX_THROW(std::invalid_argument, "You must provide a compressor for the LargeVolume to use."); + POLYVOX_THROW(std::invalid_argument, "You must provide a valid compressor for the LargeVolume to use."); } m_uTimestamper = 0; m_uMaxNumberOfUncompressedBlocks = 16; - m_uBlockSideLength = uBlockSideLength; 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; - this->m_regValidRegion = regValidRegion; - //Compute the block side length - m_uBlockSideLength = uBlockSideLength; m_uBlockSideLengthPower = logBase2(m_uBlockSideLength); m_regValidRegionInBlocks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uBlockSideLengthPower); From 938eea7c8e2a28eb85575e8ebf99b61935873373 Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 26 Jun 2013 22:01:44 +0200 Subject: [PATCH 20/26] Work on tidying LargeVolume... --- examples/Basic/main.cpp | 2 +- library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index 407d4e8e..b3ba51b7 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) //Create an empty volume and then place a sphere in it RLECompressor* pCompressor = new RLECompressor(); - FilePager* pFilePager = new FilePager("C:/temp/voldata/"); + FilePager* pFilePager = new FilePager("D:/temp/voldata/"); LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63)), pCompressor, pFilePager, 32); volData.setMaxNumberOfUncompressedBlocks(2); diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 640ddc3e..4473e350 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -546,6 +546,11 @@ namespace PolyVox template void LargeVolume::eraseBlock(typename std::map, BlockPositionCompare>::iterator itBlock) const { + if(itBlock->second.hasUncompressedData()) + { + itBlock->second.destroyUncompressedData(); + } + if(m_pPager) { Vector3DInt32 v3dPos = itBlock->first; @@ -565,8 +570,6 @@ namespace PolyVox // find the block in the uncompressed cache if(m_vecBlocksWithUncompressedData[ct] == &(itBlock->second)) { - // TODO: compression is unneccessary? or will not compressing this cause a memleak? - itBlock->second.destroyUncompressedData(); // put last object in cache here m_vecBlocksWithUncompressedData[ct] = m_vecBlocksWithUncompressedData.back(); // decrease cache size by one since last element is now in here twice From acb43d54d996bab4b2faa09a57f3f8bc2f6ef635 Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 26 Jun 2013 22:08:49 +0200 Subject: [PATCH 21/26] Fixed paging example. --- examples/Paging/main.cpp | 80 ++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 03601f9b..9ddf456f 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -216,9 +216,47 @@ public: virtual void pageIn(const Region& region, Block* pBlockData) { - POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); + pBlockData->createUncompressedData(); - + Perlin perlin(2,2,1,234); + + for(int x = region.getLowerX(); x <= region.getUpperX(); x++) + { + for(int y = region.getLowerY(); y <= region.getUpperY(); y++) + { + float perlinVal = perlin.Get(x / static_cast(255-1), y / static_cast(255-1)); + perlinVal += 1.0f; + perlinVal *= 0.5f; + perlinVal *= 255; + for(int z = region.getLowerZ(); z <= region.getUpperZ(); z++) + { + MaterialDensityPair44 voxel; + if(z < perlinVal) + { + const int xpos = 50; + const int zpos = 100; + if((x-xpos)*(x-xpos) + (z-zpos)*(z-zpos) < 200) { + // tunnel + voxel.setMaterial(0); + voxel.setDensity(MaterialDensityPair44::getMinDensity()); + } else { + // solid + voxel.setMaterial(245); + voxel.setDensity(MaterialDensityPair44::getMaxDensity()); + } + } + else + { + voxel.setMaterial(0); + voxel.setDensity(MaterialDensityPair44::getMinDensity()); + } + + pBlockData->setVoxelAt(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), voxel); + } + } + } + + pBlockData->destroyUncompressedData(); } virtual void pageOut(const Region& region, Block* pBlockData) @@ -228,43 +266,7 @@ public: virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) { - Perlin perlin(2,2,1,234); - - for(int x = region.getLowerX(); x <= region.getUpperX(); x++) - { - for(int y = region.getLowerY(); y <= region.getUpperY(); y++) - { - float perlinVal = perlin.Get(x / static_cast(255-1), y / static_cast(255-1)); - perlinVal += 1.0f; - perlinVal *= 0.5f; - perlinVal *= 255; - for(int z = region.getLowerZ(); z <= region.getUpperZ(); z++) - { - MaterialDensityPair44 voxel; - if(z < perlinVal) - { - const int xpos = 50; - const int zpos = 100; - if((x-xpos)*(x-xpos) + (z-zpos)*(z-zpos) < 200) { - // tunnel - voxel.setMaterial(0); - voxel.setDensity(MaterialDensityPair44::getMinDensity()); - } else { - // solid - voxel.setMaterial(245); - voxel.setDensity(MaterialDensityPair44::getMaxDensity()); - } - } - else - { - voxel.setMaterial(0); - voxel.setDensity(MaterialDensityPair44::getMinDensity()); - } - - volumeProxy.setVoxelAt(x, y, z, voxel); - } - } - } + POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); } virtual void dataOverflowHandler(const ConstVolumeProxy& /*volumeProxy*/, const Region& region) From 1064ea1c4777fcf10abcea778684ea8ba2a3352c Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 26 Jun 2013 22:14:01 +0200 Subject: [PATCH 22/26] Stripped out unused code. --- examples/Paging/main.cpp | 65 --------------- library/PolyVoxCore/CMakeLists.txt | 1 - .../include/PolyVoxCore/ConstVolumeProxy.h | 83 ------------------- .../include/PolyVoxCore/FilePager.h | 8 -- .../include/PolyVoxCore/LargeVolume.h | 17 ---- .../include/PolyVoxCore/LargeVolume.inl | 32 ------- .../PolyVoxCore/include/PolyVoxCore/Pager.h | 12 --- 7 files changed, 218 deletions(-) delete mode 100644 library/PolyVoxCore/include/PolyVoxCore/ConstVolumeProxy.h diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index 9ddf456f..f10c2331 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -263,64 +263,8 @@ public: { std::cout << "warning unloading region: " << region.getLowerCorner() << " -> " << region.getUpperCorner() << std::endl; } - - virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) - { - POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); - } - - virtual void dataOverflowHandler(const ConstVolumeProxy& /*volumeProxy*/, const Region& region) - { - std::cout << "warning unloading region: " << region.getLowerCorner() << " -> " << region.getUpperCorner() << std::endl; - } }; -void load(const ConstVolumeProxy& volume, const PolyVox::Region& reg) -{ - Perlin perlin(2,2,1,234); - - for(int x = reg.getLowerX(); x <= reg.getUpperX(); x++) - { - for(int y = reg.getLowerY(); y <= reg.getUpperY(); y++) - { - float perlinVal = perlin.Get(x / static_cast(255-1), y / static_cast(255-1)); - perlinVal += 1.0f; - perlinVal *= 0.5f; - perlinVal *= 255; - for(int z = reg.getLowerZ(); z <= reg.getUpperZ(); z++) - { - MaterialDensityPair44 voxel; - if(z < perlinVal) - { - const int xpos = 50; - const int zpos = 100; - if((x-xpos)*(x-xpos) + (z-zpos)*(z-zpos) < 200) { - // tunnel - voxel.setMaterial(0); - voxel.setDensity(MaterialDensityPair44::getMinDensity()); - } else { - // solid - voxel.setMaterial(245); - voxel.setDensity(MaterialDensityPair44::getMaxDensity()); - } - } - else - { - voxel.setMaterial(0); - voxel.setDensity(MaterialDensityPair44::getMinDensity()); - } - - volume.setVoxelAt(x, y, z, voxel); - } - } - } -} - -void unload(const ConstVolumeProxy& /*vol*/, const PolyVox::Region& reg) -{ - std::cout << "warning unloading region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl; -} - int main(int argc, char *argv[]) { //Create and show the Qt OpenGL window @@ -330,19 +274,10 @@ int main(int argc, char *argv[]) RLECompressor* compressor = new RLECompressor(); PerlinNoisePager* pager = new PerlinNoisePager(); - - //If these lines don't compile, please try commenting them out and using the two lines after - //(you will need Boost for this). If you have to do this then please let us know in the forums as - //we rely on community feedback to keep the Boost version running. LargeVolume volData(Region::MaxRegion, compressor, pager, 256); - //LargeVolume volData(polyvox_bind(&load, polyvox_placeholder_1, polyvox_placeholder_2), - // polyvox_bind(&unload, polyvox_placeholder_1, polyvox_placeholder_2), 256); volData.setMaxNumberOfBlocksInMemory(4096); volData.setMaxNumberOfUncompressedBlocks(64); - //volData.dataRequiredHandler = &load; - //volData.dataOverflowHandler = &unload; - //volData.setMaxNumberOfUncompressedBlocks(4096); //createSphereInVolume(volData, 30); //createPerlinTerrain(volData); diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index 8366d527..a8ce8a0c 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -49,7 +49,6 @@ SET(CORE_INC_FILES include/PolyVoxCore/BaseVolume.inl include/PolyVoxCore/BaseVolumeSampler.inl include/PolyVoxCore/Compressor.h - include/PolyVoxCore/ConstVolumeProxy.h include/PolyVoxCore/CubicSurfaceExtractor.h include/PolyVoxCore/CubicSurfaceExtractor.inl include/PolyVoxCore/CubicSurfaceExtractorWithNormals.h diff --git a/library/PolyVoxCore/include/PolyVoxCore/ConstVolumeProxy.h b/library/PolyVoxCore/include/PolyVoxCore/ConstVolumeProxy.h deleted file mode 100644 index 751377ec..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/ConstVolumeProxy.h +++ /dev/null @@ -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_ConstVolumeProxy_H__ -#define __PolyVox_ConstVolumeProxy_H__ - -#include "PolyVoxCore/Region.h" -#include "PolyVoxCore/Vector.h" - -namespace PolyVox -{ - template - class ConstVolumeProxy - { - //LargeVolume is a friend so it can call the constructor. - friend class LargeVolume; - public: - VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const - { - // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. - POLYVOX_ASSERT(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); - return m_pVolume.getVoxel(uXPos, uYPos, uZPos); - } - - VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const - { - // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. - POLYVOX_ASSERT(m_regValid.containsPoint(v3dPos), "Position is outside valid region"); - return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); - } - - void setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const - { - // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. - POLYVOX_ASSERT(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); - m_pVolume.setVoxelAtConst(uXPos, uYPos, uZPos, tValue); - } - - void setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue) const - { - // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. - POLYVOX_ASSERT(m_regValid.containsPoint(v3dPos), "Position is outside valid region"); - setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); - } - private: - //Private constructor, so client code can't abuse this class. - ConstVolumeProxy(const LargeVolume& pVolume, const Region& regValid) - :m_pVolume(pVolume) - ,m_regValid(regValid) - { - } - - //Private assignment operator, so client code can't abuse this class. - ConstVolumeProxy& operator=(const ConstVolumeProxy& rhs) - { - } - - const LargeVolume& m_pVolume; - const Region& m_regValid; - }; -} - -#endif //__PolyVox_ConstVolumeProxy_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h index 5d8d97ed..e5ab35b3 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/FilePager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/FilePager.h @@ -124,14 +124,6 @@ namespace PolyVox fclose(pFile); } - virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) - { - } - - virtual void dataOverflowHandler(const ConstVolumeProxy& volumeProxy, const Region& region) - { - } - protected: std::string m_strFolderName; }; diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index 581f1adf..103d7ca8 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -42,8 +42,6 @@ freely, subject to the following restrictions: namespace PolyVox { - template class ConstVolumeProxy; - /// The LargeVolume class provides a memory efficient method of storing voxel data while also allowing fast access and modification. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// A LargeVolume is essentially a 3D array in which each element (or voxel) is identified by a three dimensional (x,y,z) coordinate. @@ -228,9 +226,6 @@ namespace PolyVox VoxelType* mCurrentVoxel; }; - // Make the ConstVolumeProxy a friend - friend class ConstVolumeProxy; - #endif public: @@ -327,21 +322,9 @@ namespace PolyVox VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; - - /// gets called when a new region is allocated and needs to be filled - /// NOTE: accessing ANY voxels outside this region during the process of this function - /// is absolutely unsafe - //polyvox_function&, const Region&)> m_funcDataRequiredHandler; - /// gets called when a Region needs to be stored by the user, because LargeVolume will erase it right after - /// this function returns - /// NOTE: accessing ANY voxels outside this region during the process of this function - /// is absolutely unsafe - //polyvox_function&, const Region&)> m_funcDataOverflowHandler; Block* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; void eraseBlock(typename std::map, 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, BlockPositionCompare> m_pBlocks; diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index 4473e350..ef8dbb40 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -25,9 +25,6 @@ freely, subject to the following restrictions: #include "PolyVoxCore/MinizCompressor.h" -//Included here rather than in the .h because it refers to LargeVolume (avoids forward declaration) -#include "PolyVoxCore/ConstVolumeProxy.h" - namespace PolyVox { //////////////////////////////////////////////////////////////////////////////// @@ -558,9 +555,6 @@ namespace PolyVox Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); Region reg(v3dLower, v3dUpper); - /*ConstVolumeProxy ConstVolumeProxy(*this, reg); - - m_pPager->dataOverflowHandler(ConstVolumeProxy, reg);*/ m_pPager->pageOut(reg, &(itBlock->second)); } @@ -581,30 +575,6 @@ namespace PolyVox m_pBlocks.erase(itBlock); } - template - bool LargeVolume::setVoxelAtConst(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const - { - //We don't have any range checks in this function because it - //is a private function only called by the ConstVolumeProxy. The - //ConstVolumeProxy takes care of ensuring the range is appropriate. - - 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 = uXPos - (blockX << m_uBlockSideLengthPower); - const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); - const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); - - Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); - - pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue); - - //Return true to indicate that we modified a voxel. - return true; - } - - template Block* LargeVolume::getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const { @@ -665,8 +635,6 @@ namespace PolyVox Vector3DInt32 v3dLower(v3dBlockPos.getX() << m_uBlockSideLengthPower, v3dBlockPos.getY() << m_uBlockSideLengthPower, v3dBlockPos.getZ() << m_uBlockSideLengthPower); Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uBlockSideLength-1, m_uBlockSideLength-1, m_uBlockSideLength-1); Region reg(v3dLower, v3dUpper); - /*ConstVolumeProxy ConstVolumeProxy(*this, reg); - m_pPager->dataRequiredHandler(ConstVolumeProxy, reg);*/ m_pPager->pageIn(reg, &(itBlock->second)); } diff --git a/library/PolyVoxCore/include/PolyVoxCore/Pager.h b/library/PolyVoxCore/include/PolyVoxCore/Pager.h index 13f4ad19..4cb95adc 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Pager.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Pager.h @@ -27,8 +27,6 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Impl/Block.h" #include "PolyVoxCore/Impl/TypeDef.h" -#include "PolyVoxCore/ConstVolumeProxy.h" - namespace PolyVox { /** @@ -45,16 +43,6 @@ namespace PolyVox virtual void pageIn(const Region& region, Block* pBlockData) = 0; virtual void pageOut(const Region& region, Block* pBlockData) = 0; - - virtual void dataRequiredHandler(const ConstVolumeProxy& volumeProxy, const Region& region) - { - POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); - } - - virtual void dataOverflowHandler(const ConstVolumeProxy& volumeProxy, const Region& region) - { - POLYVOX_ASSERT(false, "NOT IMPLEMENTED"); - } }; } From 56cf423bfd15a7d798300a6583bf8bbddbf3258f Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 26 Jun 2013 22:39:15 +0200 Subject: [PATCH 23/26] Added POLYVOX_THROW_IF macro to simplify error handling. --- .../PolyVoxCore/include/PolyVoxCore/Array.inl | 30 ++------ .../include/PolyVoxCore/Impl/ErrorHandling.h | 77 ++++++++++++++----- 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Array.inl b/library/PolyVoxCore/include/PolyVoxCore/Array.inl index 1821817d..53f428ac 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Array.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Array.inl @@ -73,10 +73,7 @@ namespace PolyVox template SubArray Array::operator[](uint32_t uIndex) { - if(uIndex >= m_pDimensions[0]) - { - POLYVOX_THROW(std::out_of_range, "Array index out of range"); - } + POLYVOX_THROW_IF(uIndex >= m_pDimensions[0], std::out_of_range, "Array index out of range"); return SubArray(&m_pElements[uIndex*m_pOffsets[0]], @@ -95,10 +92,7 @@ namespace PolyVox template const SubArray Array::operator[](uint32_t uIndex) const { - if(uIndex >= m_pDimensions[0]) - { - POLYVOX_THROW(std::out_of_range, "Array index out of range"); - } + POLYVOX_THROW_IF(uIndex >= m_pDimensions[0], std::out_of_range, "Array index out of range"); return SubArray(&m_pElements[uIndex*m_pOffsets[0]], @@ -147,10 +141,7 @@ namespace PolyVox m_uNoOfElements = 1; for (uint32_t i = 0; i uint32_t Array::getDimension(uint32_t uDimension) { - if(uDimension >= noOfDims) - { - POLYVOX_THROW(std::out_of_range, "Array dimension out of range"); - } + POLYVOX_THROW_IF(uDimension >= noOfDims, std::out_of_range, "Array dimension out of range"); return m_pDimensions[uDimension]; } @@ -266,10 +254,7 @@ namespace PolyVox template ElementType& Array<1, ElementType>::operator[] (uint32_t uIndex) { - if(uIndex >= m_pDimensions[0]) - { - POLYVOX_THROW(std::out_of_range, "Array index out of range"); - } + POLYVOX_THROW_IF(uIndex >= m_pDimensions[0], std::out_of_range, "Array index out of range"); return m_pElements[uIndex]; } @@ -277,10 +262,7 @@ namespace PolyVox template const ElementType& Array<1, ElementType>::operator[] (uint32_t uIndex) const { - if(uIndex >= m_pDimensions[0]) - { - POLYVOX_THROW(std::out_of_range, "Array index out of range"); - } + POLYVOX_THROW_IF(uIndex >= m_pDimensions[0], std::out_of_range, "Array index out of range"); return m_pElements[uIndex]; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h index 5080f7db..afc452c0 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h @@ -255,15 +255,36 @@ namespace PolyVox * ... */ #ifdef POLYVOX_THROW_ENABLED - #define POLYVOX_THROW(type, message) \ - PolyVox::logError() << (message); \ - throw type((message)) - // Some fast functions (getVoxel(), etc) use exceptions for error handling but don't want the overhead of logging. - // This overhead is present even if no exception is thrown, probably because the presence of the logging code prevents - // some inlining. Therefore we provide this macro which doesn't log for such specialised circumstances. - #define POLYVOX_THROW_DONT_LOG(type, message) \ - throw type((message)) + #define POLYVOX_THROW_IF(condition, type, message) \ + /* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \ + but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \ + (http://stackoverflow.com/a/1946485) is to disable these warnings. */ \ + POLYVOX_MSC_WARNING_PUSH \ + POLYVOX_DISABLE_MSC_WARNING(4127) \ + do \ + { \ + if ((condition)) \ + { \ + PolyVox::logError() << (message); \ + throw type((message)); \ + } \ + } while(0) \ + POLYVOX_MSC_WARNING_POP + + #define POLYVOX_THROW(type, message) \ + /* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \ + but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \ + (http://stackoverflow.com/a/1946485) is to disable these warnings. */ \ + POLYVOX_MSC_WARNING_PUSH \ + POLYVOX_DISABLE_MSC_WARNING(4127) \ + do \ + { \ + PolyVox::logError() << (message); \ + throw type((message)); \ + } while(0) \ + POLYVOX_MSC_WARNING_POP + #else namespace PolyVox { @@ -273,17 +294,37 @@ namespace PolyVox void setThrowHandler(ThrowHandler newHandler); } - #define POLYVOX_THROW(type, message) \ - PolyVox::logError() << (message); \ - type except = (type)((message)); \ - getThrowHandler()((except), __FILE__, __LINE__) + #define POLYVOX_THROW_IF(condition, type, message) \ + /* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \ + but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \ + (http://stackoverflow.com/a/1946485) is to disable these warnings. */ \ + POLYVOX_MSC_WARNING_PUSH \ + POLYVOX_DISABLE_MSC_WARNING(4127) \ + do \ + { \ + if ((condition)) \ + { \ + PolyVox::logError() << (message); \ + type except = (type)((message)); \ + getThrowHandler()((except), __FILE__, __LINE__); \ + } \ + } while(0) \ + POLYVOX_MSC_WARNING_POP + + #define POLYVOX_THROW(type, message) \ + /* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \ + but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \ + (http://stackoverflow.com/a/1946485) is to disable these warnings. */ \ + POLYVOX_MSC_WARNING_PUSH \ + POLYVOX_DISABLE_MSC_WARNING(4127) \ + do \ + { \ + PolyVox::logError() << (message); \ + type except = (type)((message)); \ + getThrowHandler()((except), __FILE__, __LINE__); \ + } while(0) \ + POLYVOX_MSC_WARNING_POP - // Some fast functions (getVoxel(), etc) use exceptions for error handling but don't want the overhead of logging. - // This overhead is present even if no exception is thrown, probably because the presence of the logging code prevents - // some inlining. Therefore we provide this macro which doesn't log for such specialised circumstances. - #define POLYVOX_THROW_DONT_LOG(type, message) \ - type except = (type)((message)); \ - getThrowHandler()((except), __FILE__, __LINE__) #endif namespace PolyVox From 72b3cd5154e52b489d30d4246c4ea885839325f4 Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 26 Jun 2013 23:39:21 +0200 Subject: [PATCH 24/26] Tidying up and comments. --- examples/Paging/main.cpp | 128 +----------------- .../include/PolyVoxCore/LargeVolume.inl | 3 +- 2 files changed, 4 insertions(+), 127 deletions(-) diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index f10c2331..55e08b75 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -37,129 +37,6 @@ freely, subject to the following restrictions: //Use the PolyVox namespace using namespace PolyVox; -void createPerlinVolumeSlow(LargeVolume& volData) -{ - Perlin perlin(2,8,1,234); - - for(int z = 1; z < 256-1; z++) - { - std::cout << z << std::endl; - for(int y = 1; y < 256-1; y++) - { - for(int x = 1; x < 256-1; x++) - { - float perlinVal = perlin.Get3D(x /static_cast(256-1), (y) / static_cast(256-1), z / static_cast(256-1)); - - perlinVal += 1.0f; - perlinVal *= 0.5f; - perlinVal *= MaterialDensityPair44::getMaxDensity(); - - MaterialDensityPair44 voxel; - - voxel.setMaterial(245); - voxel.setDensity(perlinVal); - - /*if(perlinVal < 0.0f) - { - voxel.setMaterial(245); - voxel.setDensity(MaterialDensityPair44::getMaxDensity()); - } - else - { - voxel.setMaterial(0); - voxel.setDensity(MaterialDensityPair44::getMinDensity()); - }*/ - - volData.setVoxelAt(x, y, z, voxel); - } - } - } -} - -/*void createPerlinVolumeFast(LargeVolume& volData) -{ - Perlin perlin(2,8,1,234); - - for(int blockZ = 0; blockZ < volData.m_uDepthInBlocks; blockZ++) - { - std::cout << blockZ << std::endl; - for(int blockY = 0; blockY < volData.m_uHeightInBlocks; blockY++) - { - for(int blockX = 0; blockX < volData.m_uWidthInBlocks; blockX++) - { - for(int offsetz = 0; offsetz < volData.m_uBlockSideLength; offsetz++) - { - for(int offsety = 0; offsety < volData.m_uBlockSideLength; offsety++) - { - for(int offsetx = 0; offsetx < volData.m_uBlockSideLength; offsetx++) - { - int x = blockX * volData.m_uBlockSideLength + offsetx; - int y = blockY * volData.m_uBlockSideLength + offsety; - int z = blockZ * volData.m_uBlockSideLength + offsetz; - - if((x == 0) || (x == volData.getWidth()-1)) continue; - if((y == 0) || (y == volData.getHeight()-1)) continue; - if((z == 0) || (z == volData.getDepth()-1)) continue; - - float perlinVal = perlin.Get3D(x /static_cast(volData.getWidth()-1), (y) / static_cast(volData.getHeight()-1), z / static_cast(volData.getDepth()-1)); - - MaterialDensityPair44 voxel; - if(perlinVal < 0.0f) - { - voxel.setMaterial(245); - voxel.setDensity(MaterialDensityPair44::getMaxDensity()); - } - else - { - voxel.setMaterial(0); - voxel.setDensity(MaterialDensityPair44::getMinDensity()); - } - - volData.setVoxelAt(x, y, z, voxel); - } - } - } - } - } - } -}*/ - -void createPerlinTerrain(LargeVolume& volData) -{ - Perlin perlin(2,2,1,234); - - for(int x = 1; x < 255-1; x++) - { - if(x%(255/100) == 0) { - std::cout << "." << std::flush; - } - for(int y = 1; y < 255-1; y++) - { - float perlinVal = perlin.Get(x / static_cast(255-1), y / static_cast(255-1)); - perlinVal += 1.0f; - perlinVal *= 0.5f; - perlinVal *= 255; - for(int z = 1; z < 255-1; z++) - { - MaterialDensityPair44 voxel; - if(z < perlinVal) - { - voxel.setMaterial(245); - voxel.setDensity(MaterialDensityPair44::getMaxDensity()); - } - else - { - voxel.setMaterial(0); - voxel.setDensity(MaterialDensityPair44::getMinDensity()); - } - - volData.setVoxelAt(x, y, z, voxel); - } - } - } - std::cout << std::endl; -} - void createSphereInVolume(LargeVolume& volData, Vector3DFloat v3dVolCenter, float fRadius) { //This vector hold the position of the center of the volume @@ -251,12 +128,13 @@ public: voxel.setDensity(MaterialDensityPair44::getMinDensity()); } + // Voxel position within a block always start from zero. So if a block represents region (4, 8, 12) to (11, 19, 15) + // then the valid block voxels are from (0, 0, 0) to (7, 11, 3). Hence we subtract the lower corner position of the + // region from the volume space position in order to get the block space position. pBlockData->setVoxelAt(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), voxel); } } } - - pBlockData->destroyUncompressedData(); } virtual void pageOut(const Region& region, Block* pBlockData) diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index ef8dbb40..ab6f4b46 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -586,7 +586,7 @@ namespace PolyVox //This check should also provide a significant speed boost as usually it is true. if((v3dBlockPos == m_v3dLastAccessedBlockPos) && (m_pLastAccessedBlock != 0)) { - POLYVOX_ASSERT(m_pLastAccessedBlock->m_tUncompressedData, "Block has no uncompressed data"); + POLYVOX_ASSERT(m_pLastAccessedBlock->hasUncompressedData(), "Last accessed block has no uncompressed data."); return m_pLastAccessedBlock; } @@ -649,7 +649,6 @@ namespace PolyVox if(block.hasUncompressedData()) { - POLYVOX_ASSERT(m_pLastAccessedBlock->m_tUncompressedData, "Block has no uncompressed data"); return m_pLastAccessedBlock; } From 97a501e3dabb8217aea290bf6144f5616eea42ea Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Thu, 27 Jun 2013 16:41:24 +0200 Subject: [PATCH 25/26] Updated changelog. --- CHANGELOG.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c8df1d8d..d50bb57e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -10,9 +10,13 @@ The getVoxelAt() and setVoxelAt() functions have been deprecated and replaced by LargeVolume ----------- +Behaviour and interface of the LargeVolume has changed significantly and code which uses it will certainly need to be updated. Plese see the LargeVolume API docs for full details of how it now works. + It is now possible to provide custom compressors for the data which is stored in a LargeVolume. Two compressor implementation are provided with PolyVox - RLECompressor which is suitable for cubic-style terrain, and MinizCompressor which uses the 'miniz' zlib implementation for smooth terrain or general purpose use. Users can provide their own implementation of the compressor interface if they wish. -Note that the setCompressionEnabled() functionality has been removed and a compressor must always be provided when constructing the volume. The ability to disable compression was of questionable benefit and was complicating the logic in the code. In practice it is still possible to mostly disable compression by setting the maximum number of uncompressed blocks to a high value by calling setMaxNumberOfUncompressedBlocks(). +Note that the setCompressionEnabled() functionality has been removed and a compressor must always be provided when constructing the volume. The ability to disable compression was of questionable benefit and was complicating the logic in the code. + +The LargeVolume also supports custom paging code which can be supplied by providing a subclass of Pager and implementing the relevant methods. This replaces the dataRequiredHandler() and dataOverflowHandler() functions. These changes regarding compression and paging have also affected the LargeVolume constructors(s). Please see the API docs to see how they look now. From f3ec94dd75415f1e212fb03c63a768c7fd9de999 Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Thu, 27 Jun 2013 16:43:49 +0200 Subject: [PATCH 26/26] Reverted changes made for testing. --- examples/Basic/main.cpp | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index b3ba51b7..64097731 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -26,17 +26,14 @@ freely, subject to the following restrictions: #include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h" #include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" #include "PolyVoxCore/SurfaceMesh.h" -//#include "PolyVoxCore/SimpleVolume.h" -#include "PolyVoxCore/LargeVolume.h" -#include "PolyVoxCore/RLECompressor.h" -#include "PolyVoxCore/FilePager.h" +#include "PolyVoxCore/SimpleVolume.h" #include //Use the PolyVox namespace using namespace PolyVox; -void createSphereInVolume(LargeVolume& volData, float fRadius) +void createSphereInVolume(SimpleVolume& volData, float fRadius) { //This vector hold the position of the center of the volume Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); @@ -71,32 +68,21 @@ void createSphereInVolume(LargeVolume& volData, float fRadius) int main(int argc, char *argv[]) { - setTraceStream(&(std::cout)); - setDebugStream(&(std::cout)); - setInfoStream(&(std::cout)); - //Create and show the Qt OpenGL window QApplication app(argc, argv); OpenGLWidget openGLWidget(0); openGLWidget.show(); //Create an empty volume and then place a sphere in it - RLECompressor* pCompressor = new RLECompressor(); - FilePager* pFilePager = new FilePager("D:/temp/voldata/"); - - LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63)), pCompressor, pFilePager, 32); - volData.setMaxNumberOfUncompressedBlocks(2); - volData.setMaxNumberOfBlocksInMemory(4); - - + SimpleVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63))); createSphereInVolume(volData, 30); //A mesh object to hold the result of surface extraction SurfaceMesh mesh; //Create a surface extractor. Comment out one of the following two lines to decide which type gets created. - CubicSurfaceExtractorWithNormals< LargeVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); - //MarchingCubesSurfaceExtractor< LargeVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); + CubicSurfaceExtractorWithNormals< SimpleVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); + //MarchingCubesSurfaceExtractor< SimpleVolume > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); //Execute the surface extractor. surfaceExtractor.execute(); @@ -106,4 +92,4 @@ int main(int argc, char *argv[]) //Run the message pump. return app.exec(); -} +} \ No newline at end of file