PolyVox and Thermite3D now support the use of a density component as well as a material component for each voxel.

This commit is contained in:
David Williams 2010-06-25 21:41:13 +00:00
parent 29928b774d
commit 254fa3329e
24 changed files with 802 additions and 371 deletions

View File

@ -26,6 +26,7 @@ freely, subject to the following restrictions:
#include <QMouseEvent> #include <QMouseEvent>
#include "GradientEstimators.h" #include "GradientEstimators.h"
#include "MaterialDensityPair.h"
#include "SurfaceExtractor.h" #include "SurfaceExtractor.h"
#include "Mesh.h" #include "Mesh.h"
@ -48,7 +49,7 @@ OpenGLWidget::OpenGLWidget(QWidget *parent)
timer->start(0); timer->start(0);
} }
void OpenGLWidget::setVolume(PolyVox::Volume<uint8_t>* volData) void OpenGLWidget::setVolume(PolyVox::Volume<MaterialDensityPair44>* volData)
{ {
//First we free anything from the previous volume (if there was one). //First we free anything from the previous volume (if there was one).
m_mapOpenGLSurfaceMeshes.clear(); m_mapOpenGLSurfaceMeshes.clear();
@ -62,7 +63,7 @@ void OpenGLWidget::setVolume(PolyVox::Volume<uint8_t>* volData)
m_uVolumeHeightInRegions = volData->getHeight() / m_uRegionSideLength; m_uVolumeHeightInRegions = volData->getHeight() / m_uRegionSideLength;
m_uVolumeDepthInRegions = volData->getDepth() / m_uRegionSideLength; m_uVolumeDepthInRegions = volData->getDepth() / m_uRegionSideLength;
SurfaceExtractor surfaceExtractor(*volData); SurfaceExtractor<MaterialDensityPair44> surfaceExtractor(*volData);
//Our volume is broken down into cuboid regions, and we create one mesh for each region. //Our volume is broken down into cuboid regions, and we create one mesh for each region.
//This three-level for loop iterates over each region. //This three-level for loop iterates over each region.

View File

@ -45,7 +45,7 @@ class OpenGLWidget : public QGLWidget
public: public:
OpenGLWidget(QWidget *parent); OpenGLWidget(QWidget *parent);
void setVolume(PolyVox::Volume<uint8_t>* volData); void setVolume(PolyVox::Volume<PolyVox::MaterialDensityPair44>* volData);
void mouseMoveEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event);
@ -69,7 +69,7 @@ class OpenGLWidget : public QGLWidget
bool m_bUseOpenGLVertexBufferObjects; bool m_bUseOpenGLVertexBufferObjects;
//Creates a volume 128x128x128 //Creates a volume 128x128x128
PolyVox::Volume<uint8_t>* m_volData; PolyVox::Volume<PolyVox::MaterialDensityPair44>* m_volData;
//Rather than storing one big mesh, the volume is broken into regions and a mesh is stored for each region //Rather than storing one big mesh, the volume is broken into regions and a mesh is stored for each region
std::map<PolyVox::Vector3DUint8, OpenGLSurfaceMesh> m_mapOpenGLSurfaceMeshes; std::map<PolyVox::Vector3DUint8, OpenGLSurfaceMesh> m_mapOpenGLSurfaceMeshes;

View File

@ -23,9 +23,11 @@ freely, subject to the following restrictions:
#include "Shapes.h" #include "Shapes.h"
#include "MaterialDensityPair.h"
using namespace PolyVox; using namespace PolyVox;
void createSphereInVolume(Volume<uint8_t>& volData, float fRadius, uint8_t uValue) void createSphereInVolume(Volume<MaterialDensityPair44>& volData, float fRadius, uint8_t uValue)
{ {
//This vector hold the position of the center of the volume //This vector hold the position of the center of the volume
Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2);
@ -46,14 +48,14 @@ void createSphereInVolume(Volume<uint8_t>& volData, float fRadius, uint8_t uValu
//then we make it solid, otherwise we make it empty space. //then we make it solid, otherwise we make it empty space.
if(fDistToCenter <= fRadius) if(fDistToCenter <= fRadius)
{ {
volData.setVoxelAt(x,y,z, uValue); volData.setVoxelAt(x,y,z, MaterialDensityPair44(uValue, uValue > 0 ? MaterialDensityPair44::getMaxDensity() : MaterialDensityPair44::getMinDensity()));
} }
} }
} }
} }
} }
void createCubeInVolume(Volume<uint8_t>& volData, Vector3DUint16 lowerCorner, Vector3DUint16 upperCorner, uint8_t uValue) void createCubeInVolume(Volume<MaterialDensityPair44>& volData, Vector3DUint16 lowerCorner, Vector3DUint16 upperCorner, uint8_t uValue)
{ {
//This three-level for loop iterates over every voxel between the specified corners //This three-level for loop iterates over every voxel between the specified corners
for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++) for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++)
@ -62,7 +64,7 @@ void createCubeInVolume(Volume<uint8_t>& volData, Vector3DUint16 lowerCorner, Ve
{ {
for (int x = lowerCorner.getX() ; x <= upperCorner.getX(); x++) for (int x = lowerCorner.getX() ; x <= upperCorner.getX(); x++)
{ {
volData.setVoxelAt(x,y,z, uValue); volData.setVoxelAt(x,y,z, MaterialDensityPair44(uValue, uValue > 0 ? MaterialDensityPair44::getMaxDensity() : MaterialDensityPair44::getMinDensity()));
} }
} }
} }

View File

@ -24,9 +24,10 @@ freely, subject to the following restrictions:
#ifndef __OpenGLExample_Shapes_H__ #ifndef __OpenGLExample_Shapes_H__
#define __OpenGLExample_Shapes_H__ #define __OpenGLExample_Shapes_H__
#include "PolyVoxForwardDeclarations.h"
#include "Volume.h" #include "Volume.h"
void createSphereInVolume(PolyVox::Volume<uint8_t>& volData, float fRadius, uint8_t uValue); void createSphereInVolume(PolyVox::Volume<PolyVox::MaterialDensityPair44>& volData, float fRadius, uint8_t uValue);
void createCubeInVolume(PolyVox::Volume<uint8_t>& volData, PolyVox::Vector3DUint16 lowerCorner, PolyVox::Vector3DUint16 upperCorner, uint8_t uValue); void createCubeInVolume(PolyVox::Volume<PolyVox::MaterialDensityPair44>& volData, PolyVox::Vector3DUint16 lowerCorner, PolyVox::Vector3DUint16 upperCorner, uint8_t uValue);
#endif //__OpenGLExample_Shapes_H__ #endif //__OpenGLExample_Shapes_H__

View File

@ -22,6 +22,7 @@ freely, subject to the following restrictions:
*******************************************************************************/ *******************************************************************************/
#include "Log.h" #include "Log.h"
#include "MaterialDensityPair.h"
#include "Volume.h" #include "Volume.h"
#include "SurfaceMesh.h" #include "SurfaceMesh.h"
#include "PolyVoxImpl/Utility.h" #include "PolyVoxImpl/Utility.h"
@ -70,7 +71,8 @@ void exampleLog(string message, int severity)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
logHandler = &exampleLog; logHandler = &exampleLog;
Volume<uint8_t> volData(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength); Volume<MaterialDensityPair44> volData(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength);
Volume<MaterialDensityPair44> volDataAveraged(g_uVolumeSideLength, g_uVolumeSideLength, g_uVolumeSideLength);
//Make our volume contain a sphere in the center. //Make our volume contain a sphere in the center.
uint16_t minPos = 0; uint16_t minPos = 0;
@ -106,14 +108,75 @@ int main(int argc, char *argv[])
createCubeInVolume(volData, Vector3DUint16(midPos+1, minPos, midPos+1), Vector3DUint16(maxPos, midPos-1, maxPos), 0); createCubeInVolume(volData, Vector3DUint16(midPos+1, minPos, midPos+1), Vector3DUint16(maxPos, midPos-1, maxPos), 0);
createCubeInVolume(volData, Vector3DUint16(minPos, midPos+1, midPos+1), Vector3DUint16(midPos-1, maxPos, maxPos), 0); createCubeInVolume(volData, Vector3DUint16(minPos, midPos+1, midPos+1), Vector3DUint16(midPos-1, maxPos, maxPos), 0);
createCubeInVolume(volData, Vector3DUint16(1, midPos-10, midPos-10), Vector3DUint16(maxPos-1, midPos+10, midPos+10), 255); createCubeInVolume(volData, Vector3DUint16(1, midPos-10, midPos-10), Vector3DUint16(maxPos-1, midPos+10, midPos+10), MaterialDensityPair44::getMaxDensity());
createCubeInVolume(volData, Vector3DUint16(midPos-10, 1, midPos-10), Vector3DUint16(midPos+10, maxPos-1, midPos+10), 255); createCubeInVolume(volData, Vector3DUint16(midPos-10, 1, midPos-10), Vector3DUint16(midPos+10, maxPos-1, midPos+10), MaterialDensityPair44::getMaxDensity());
createCubeInVolume(volData, Vector3DUint16(midPos-10, midPos-10 ,1), Vector3DUint16(midPos+10, midPos+10, maxPos-1), 255); createCubeInVolume(volData, Vector3DUint16(midPos-10, midPos-10 ,1), Vector3DUint16(midPos+10, midPos+10, maxPos-1), MaterialDensityPair44::getMaxDensity());
//createCubeInVolume(volData, Vector3DUint16(1, 1, 1), Vector3DUint16(maxPos-1, maxPos-1, midPos/4), 255); //createCubeInVolume(volData, Vector3DUint16(1, 1, 1), Vector3DUint16(maxPos-1, maxPos-1, midPos/4), 255);
for (int z = 1; z < volData.getWidth()-1; z++)
{
for (int y = 1; y < volData.getHeight()-1; y++)
{
for (int x = 1; x < volData.getDepth()-1; x++)
{
int uDensity = 0;
uDensity += volData.getVoxelAt(x-1,y-1,z-1).getDensity();
uDensity += volData.getVoxelAt(x-1,y-1,z-0).getDensity();
uDensity += volData.getVoxelAt(x-1,y-1,z+1).getDensity();
uDensity += volData.getVoxelAt(x-1,y-0,z-1).getDensity();
uDensity += volData.getVoxelAt(x-1,y-0,z-0).getDensity();
uDensity += volData.getVoxelAt(x-1,y-0,z+1).getDensity();
uDensity += volData.getVoxelAt(x-1,y+1,z-1).getDensity();
uDensity += volData.getVoxelAt(x-1,y+1,z-0).getDensity();
uDensity += volData.getVoxelAt(x-1,y+1,z+1).getDensity();
uDensity += volData.getVoxelAt(x-0,y-1,z-1).getDensity();
uDensity += volData.getVoxelAt(x-0,y-1,z-0).getDensity();
uDensity += volData.getVoxelAt(x-0,y-1,z+1).getDensity();
uDensity += volData.getVoxelAt(x-0,y-0,z-1).getDensity();
uDensity += volData.getVoxelAt(x-0,y-0,z-0).getDensity();
uDensity += volData.getVoxelAt(x-0,y-0,z+1).getDensity();
uDensity += volData.getVoxelAt(x-0,y+1,z-1).getDensity();
uDensity += volData.getVoxelAt(x-0,y+1,z-0).getDensity();
uDensity += volData.getVoxelAt(x-0,y+1,z+1).getDensity();
uDensity += volData.getVoxelAt(x+1,y-1,z-1).getDensity();
uDensity += volData.getVoxelAt(x+1,y-1,z-0).getDensity();
uDensity += volData.getVoxelAt(x+1,y-1,z+1).getDensity();
uDensity += volData.getVoxelAt(x+1,y-0,z-1).getDensity();
uDensity += volData.getVoxelAt(x+1,y-0,z-0).getDensity();
uDensity += volData.getVoxelAt(x+1,y-0,z+1).getDensity();
uDensity += volData.getVoxelAt(x+1,y+1,z-1).getDensity();
uDensity += volData.getVoxelAt(x+1,y+1,z-0).getDensity();
uDensity += volData.getVoxelAt(x+1,y+1,z+1).getDensity();
uDensity /= 27;
MaterialDensityPair44 val = volData.getVoxelAt(x,y,z);
val.setDensity(uDensity);
volDataAveraged.setVoxelAt(x,y,z,val);
}
}
}
/*std::vector<long int> counts(256);
fill(counts.begin(), counts.end(), 0);
for (int z = 0; z < volData.getWidth(); z++)
{
for (int y = 0; y < volData.getHeight(); y++)
{
for (int x = 0; x < volData.getDepth(); x++)
{
counts[volData.getVoxelAt(x,y,z).getMaterial()]++;
}
}
}*/
cout << "Tidying memory..."; cout << "Tidying memory...";
volData.tidyUpMemory(0); volData.tidyUpMemory(0);
volDataAveraged.tidyUpMemory(0);
cout << "done." << endl; cout << "done." << endl;
QApplication app(argc, argv); QApplication app(argc, argv);
@ -125,7 +188,7 @@ int main(int argc, char *argv[])
QTime time; QTime time;
time.start(); time.start();
openGLWidget.setVolume(&volData); openGLWidget.setVolume(&volDataAveraged);
cout << endl << "Time taken = " << time.elapsed() / 1000.0f << "s" << endl << endl; cout << endl << "Time taken = " << time.elapsed() / 1000.0f << "s" << endl << endl;
//return 0; //return 0;

View File

@ -4,6 +4,7 @@ PROJECT(PolyVoxCore)
#Projects source files #Projects source files
SET(CORE_SRC_FILES SET(CORE_SRC_FILES
source/ArraySizes.cpp
source/GradientEstimators.cpp source/GradientEstimators.cpp
source/SurfaceMesh.cpp source/SurfaceMesh.cpp
source/Log.cpp source/Log.cpp
@ -12,7 +13,6 @@ SET(CORE_SRC_FILES
source/MeshFace.cpp source/MeshFace.cpp
source/MeshVertex.cpp source/MeshVertex.cpp
source/Region.cpp source/Region.cpp
source/SurfaceExtractor.cpp
source/SurfaceVertex.cpp source/SurfaceVertex.cpp
source/VoxelFilters.cpp source/VoxelFilters.cpp
) )
@ -22,10 +22,10 @@ SET(CORE_INC_FILES
include/Array.h include/Array.h
include/Array.inl include/Array.inl
include/ArraySizes.h include/ArraySizes.h
include/ArraySizes.inl
include/GradientEstimators.inl include/GradientEstimators.inl
include/SurfaceMesh.h
include/Log.h include/Log.h
include/MaterialDensityPair.h
include/MaterialDensityPair.inl
include/Mesh.h include/Mesh.h
include/MeshEdge.h include/MeshEdge.h
include/MeshFace.h include/MeshFace.h
@ -33,6 +33,8 @@ SET(CORE_INC_FILES
include/PolyVoxForwardDeclarations.h include/PolyVoxForwardDeclarations.h
include/Region.h include/Region.h
include/SurfaceExtractor.h include/SurfaceExtractor.h
include/SurfaceExtractor.inl
include/SurfaceMesh.h
include/SurfaceVertex.h include/SurfaceVertex.h
include/Vector.h include/Vector.h
include/Vector.inl include/Vector.inl

View File

@ -77,6 +77,4 @@ namespace PolyVox
}; };
}//namespace PolyVox }//namespace PolyVox
#include "ArraySizes.inl"
#endif //__PolyVox_ArraySizes_H__ #endif //__PolyVox_ArraySizes_H__

View File

@ -0,0 +1,69 @@
#pragma region License
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#pragma endregion
#ifndef __PolyVox_MaterialDensityPair_H__
#define __PolyVox_MaterialDensityPair_H__
#pragma region Headers
#include "PolyVoxForwardDeclarations.h"
#include "PolyVoxImpl/TypeDef.h"
#pragma endregion
namespace PolyVox
{
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
class MaterialDensityPair
{
public:
MaterialDensityPair();
MaterialDensityPair(Type uMaterial, Type uDensity);
//Why are both of these needed?!
bool operator==(const MaterialDensityPair& rhs) const throw();
bool operator!=(const MaterialDensityPair& rhs) const throw();
bool operator<(const MaterialDensityPair& rhs) const throw();
Type getDensity() const throw();
Type getMaterial() const throw();
void setDensity(Type uDensity);
void setMaterial(Type uMaterial);
static Type getMaxDensity() throw();
static Type getMinDensity() throw();
static Type getMidDensity() throw();
private:
Type m_uMaterial : NoOfMaterialBits;
Type m_uDensity : NoOfDensityBits;
};
typedef MaterialDensityPair<uint8_t, 4, 4> MaterialDensityPair44;
}
#include "MaterialDensityPair.inl"
#endif

View File

@ -0,0 +1,114 @@
#pragma region License
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#pragma endregion
#pragma region Headers
#pragma endregion
namespace PolyVox
{
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::MaterialDensityPair()
:m_uMaterial(0)
,m_uDensity(0)
{
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::MaterialDensityPair(Type uMaterial, Type uDensity)
:m_uMaterial(uMaterial)
,m_uDensity(uDensity)
{
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
bool MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::operator==(const MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& rhs) const throw()
{
return (m_uMaterial == rhs.m_uMaterial) && (m_uDensity == rhs.m_uDensity);
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
bool MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::operator!=(const MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& rhs) const throw()
{
return !(*this == rhs);
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
bool MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::operator<(const MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& rhs) const throw()
{
if (m_uMaterial < rhs.m_uMaterial)
return true;
if (rhs.m_uMaterial < m_uMaterial)
return false;
if (m_uDensity < rhs.m_uDensity)
return true;
if (rhs.m_uDensity < m_uDensity)
return false;
return false;
//return m_uMaterial < rhs.m_uMaterial;
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
Type MaterialDensityPair<Type,NoOfMaterialBits, NoOfDensityBits>::getDensity() const throw()
{
return m_uDensity;
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
Type MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::getMaterial() const throw()
{
return m_uMaterial;
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
void MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::setDensity(Type uDensity)
{
m_uDensity = uDensity;
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
void MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::setMaterial(Type uMaterial)
{
m_uMaterial = uMaterial;
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
Type MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::getMaxDensity() throw()
{
return (0x01 << NoOfDensityBits) - 1;
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
Type MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::getMinDensity() throw()
{
return 0;
}
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits>
Type MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>::getMidDensity() throw()
{
return 0x01 << (NoOfDensityBits - 1);
}
}

View File

@ -76,10 +76,13 @@ namespace PolyVox
class MeshVertex; class MeshVertex;
//--------------------------------- //---------------------------------
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits> class MaterialDensityPair;
typedef MaterialDensityPair<uint8_t, 4, 4> MaterialDensityPair44;
class SurfaceMesh; class SurfaceMesh;
class Region; class Region;
class SurfaceVertex; class SurfaceVertex;
class SurfaceExtractor; template <typename VoxelType> class SurfaceExtractor;
//---------- Vector ---------- //---------- Vector ----------
template <uint32_t Size, typename Type> class Vector; template <uint32_t Size, typename Type> class Vector;

View File

@ -23,6 +23,8 @@ distribution.
*******************************************************************************/ *******************************************************************************/
#pragma endregion #pragma endregion
#include <algorithm>
namespace PolyVox namespace PolyVox
{ {
template <uint32_t N> template <uint32_t N>

View File

@ -26,10 +26,12 @@ freely, subject to the following restrictions:
#ifndef __PolyVox_MarchingCubeTables_H__ #ifndef __PolyVox_MarchingCubeTables_H__
#define __PolyVox_MarchingCubeTables_H__ #define __PolyVox_MarchingCubeTables_H__
#include "TypeDef.h"
namespace PolyVox namespace PolyVox
{ {
extern int edgeTable[256]; extern POLYVOXCORE_API int edgeTable[256];
extern int triTable[256][16]; extern POLYVOXCORE_API int triTable[256][16];
} }
#endif #endif

View File

@ -35,10 +35,11 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
class POLYVOXCORE_API SurfaceExtractor template <typename VoxelType>
class SurfaceExtractor
{ {
public: public:
SurfaceExtractor(Volume<uint8_t>& volData); SurfaceExtractor(Volume<VoxelType>& volData);
std::shared_ptr<SurfaceMesh> extractSurfaceForRegion(Region region); std::shared_ptr<SurfaceMesh> extractSurfaceForRegion(Region region);
@ -57,6 +58,9 @@ namespace PolyVox
Array2DInt32& m_pCurrentVertexIndicesY, Array2DInt32& m_pCurrentVertexIndicesY,
Array2DInt32& m_pCurrentVertexIndicesZ); Array2DInt32& m_pCurrentVertexIndicesZ);
Vector3DFloat computeCentralDifferenceGradient(const VolumeSampler<VoxelType>& volIter);
Vector3DFloat computeSobelGradient(const VolumeSampler<VoxelType>& volIter);
//Use the cell bitmasks to generate all the indices needed for that slice //Use the cell bitmasks to generate all the indices needed for that slice
void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask,
const Array2DInt32& m_pPreviousVertexIndicesX, const Array2DInt32& m_pPreviousVertexIndicesX,
@ -73,8 +77,8 @@ namespace PolyVox
} }
//The volume data and a sampler to access it. //The volume data and a sampler to access it.
Volume<uint8_t> m_volData; Volume<VoxelType> m_volData;
VolumeSampler<uint8_t> m_sampVolume; VolumeSampler<VoxelType> m_sampVolume;
//Used to keep track of where generated vertices have been placed. //Used to keep track of where generated vertices have been placed.
/*int32_t* m_pPreviousVertexIndicesX; /*int32_t* m_pPreviousVertexIndicesX;
@ -125,4 +129,6 @@ namespace PolyVox
}; };
} }
#include "SurfaceExtractor.inl"
#endif #endif

View File

@ -21,9 +21,8 @@ freely, subject to the following restrictions:
distribution. distribution.
*******************************************************************************/ *******************************************************************************/
#include "SurfaceExtractor.h"
#include "Array.h" #include "Array.h"
#include "MaterialDensityPair.h"
#include "SurfaceMesh.h" #include "SurfaceMesh.h"
#include "PolyVoxImpl/MarchingCubesTables.h" #include "PolyVoxImpl/MarchingCubesTables.h"
#include "SurfaceVertex.h" #include "SurfaceVertex.h"
@ -32,13 +31,15 @@ using namespace std;
namespace PolyVox namespace PolyVox
{ {
SurfaceExtractor::SurfaceExtractor(Volume<uint8_t>& volData) template <typename VoxelType>
SurfaceExtractor<VoxelType>::SurfaceExtractor(Volume<VoxelType>& volData)
:m_volData(volData) :m_volData(volData)
,m_sampVolume(&volData) ,m_sampVolume(&volData)
{ {
} }
shared_ptr<SurfaceMesh> SurfaceExtractor::extractSurfaceForRegion(Region region) template <typename VoxelType>
shared_ptr<SurfaceMesh> SurfaceExtractor<VoxelType>::extractSurfaceForRegion(Region region)
{ {
m_regInputUncropped = region; m_regInputUncropped = region;
@ -153,8 +154,9 @@ namespace PolyVox
return shared_ptr<SurfaceMesh>(m_meshCurrent); return shared_ptr<SurfaceMesh>(m_meshCurrent);
} }
template<typename VoxelType>
template<bool isPrevZAvail> template<bool isPrevZAvail>
uint32_t SurfaceExtractor::computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) uint32_t SurfaceExtractor<VoxelType>::computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask)
{ {
m_uNoOfOccupiedCells = 0; m_uNoOfOccupiedCells = 0;
@ -218,19 +220,20 @@ namespace PolyVox
return m_uNoOfOccupiedCells; return m_uNoOfOccupiedCells;
} }
template<typename VoxelType>
template<bool isPrevXAvail, bool isPrevYAvail, bool isPrevZAvail> template<bool isPrevXAvail, bool isPrevYAvail, bool isPrevZAvail>
void SurfaceExtractor::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) void SurfaceExtractor<VoxelType>::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask)
{ {
uint8_t iCubeIndex = 0; uint8_t iCubeIndex = 0;
uint8_t v000 = 0; VoxelType v000;
uint8_t v100 = 0; VoxelType v100;
uint8_t v010 = 0; VoxelType v010;
uint8_t v110 = 0; VoxelType v110;
uint8_t v001 = 0; VoxelType v001;
uint8_t v101 = 0; VoxelType v101;
uint8_t v011 = 0; VoxelType v011;
uint8_t v111 = 0; VoxelType v111;
if(isPrevZAvail) if(isPrevZAvail)
{ {
@ -256,7 +259,7 @@ namespace PolyVox
iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ;
if (v111 == 0) iCubeIndex |= 128; if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128;
} }
else //previous X not available else //previous X not available
{ {
@ -274,8 +277,8 @@ namespace PolyVox
iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ; iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ;
if (v011 == 0) iCubeIndex |= 64; if (v011.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 64;
if (v111 == 0) iCubeIndex |= 128; if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128;
} }
} }
else //previous Y not available else //previous Y not available
@ -296,8 +299,8 @@ namespace PolyVox
iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ; iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ;
if (v101 == 0) iCubeIndex |= 32; if (v101.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 32;
if (v111 == 0) iCubeIndex |= 128; if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128;
} }
else //previous X not available else //previous X not available
{ {
@ -310,10 +313,10 @@ namespace PolyVox
uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace];
iCubeIndex = iPreviousCubeIndexZ >> 4; iCubeIndex = iPreviousCubeIndexZ >> 4;
if (v001 == 0) iCubeIndex |= 16; if (v001.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 16;
if (v101 == 0) iCubeIndex |= 32; if (v101.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 32;
if (v011 == 0) iCubeIndex |= 64; if (v011.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 64;
if (v111 == 0) iCubeIndex |= 128; if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128;
} }
} }
} }
@ -338,8 +341,8 @@ namespace PolyVox
iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY; iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY;
if (v110 == 0) iCubeIndex |= 8; if (v110.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 8;
if (v111 == 0) iCubeIndex |= 128; if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128;
} }
else //previous X not available else //previous X not available
{ {
@ -356,10 +359,10 @@ namespace PolyVox
iCubeIndex = iPreviousCubeIndexY; iCubeIndex = iPreviousCubeIndexY;
if (v010 == 0) iCubeIndex |= 4; if (v010.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 4;
if (v110 == 0) iCubeIndex |= 8; if (v110.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 8;
if (v011 == 0) iCubeIndex |= 64; if (v011.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 64;
if (v111 == 0) iCubeIndex |= 128; if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128;
} }
} }
else //previous Y not available else //previous Y not available
@ -379,10 +382,10 @@ namespace PolyVox
iCubeIndex = iPreviousCubeIndexX; iCubeIndex = iPreviousCubeIndexX;
if (v100 == 0) iCubeIndex |= 2; if (v100.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 2;
if (v110 == 0) iCubeIndex |= 8; if (v110.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 8;
if (v101 == 0) iCubeIndex |= 32; if (v101.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 32;
if (v111 == 0) iCubeIndex |= 128; if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128;
} }
else //previous X not available else //previous X not available
{ {
@ -396,14 +399,14 @@ namespace PolyVox
v011 = m_sampVolume.peekVoxel0px1py1pz(); v011 = m_sampVolume.peekVoxel0px1py1pz();
v111 = m_sampVolume.peekVoxel1px1py1pz(); v111 = m_sampVolume.peekVoxel1px1py1pz();
if (v000 == 0) iCubeIndex |= 1; if (v000.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 1;
if (v100 == 0) iCubeIndex |= 2; if (v100.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 2;
if (v010 == 0) iCubeIndex |= 4; if (v010.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 4;
if (v110 == 0) iCubeIndex |= 8; if (v110.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 8;
if (v001 == 0) iCubeIndex |= 16; if (v001.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 16;
if (v101 == 0) iCubeIndex |= 32; if (v101.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 32;
if (v011 == 0) iCubeIndex |= 64; if (v011.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 64;
if (v111 == 0) iCubeIndex |= 128; if (v111.getDensity() < VoxelType::getMidDensity()) iCubeIndex |= 128;
} }
} }
} }
@ -417,7 +420,8 @@ namespace PolyVox
} }
} }
void SurfaceExtractor::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, template <typename VoxelType>
void SurfaceExtractor<VoxelType>::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask,
Array2DInt32& m_pCurrentVertexIndicesX, Array2DInt32& m_pCurrentVertexIndicesX,
Array2DInt32& m_pCurrentVertexIndicesY, Array2DInt32& m_pCurrentVertexIndicesY,
Array2DInt32& m_pCurrentVertexIndicesZ) Array2DInt32& m_pCurrentVertexIndicesZ)
@ -457,16 +461,28 @@ namespace PolyVox
m_sampVolume.setPosition(uXVolSpace,uYVolSpace,uZVolSpace); m_sampVolume.setPosition(uXVolSpace,uYVolSpace,uZVolSpace);
const uint8_t v000 = m_sampVolume.getVoxel(); const VoxelType v000 = m_sampVolume.getVoxel();
const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume);
/* Find the vertices where the surface intersects the cube */ /* Find the vertices where the surface intersects the cube */
if (edgeTable[iCubeIndex] & 1) if (edgeTable[iCubeIndex] & 1)
{ {
m_sampVolume.movePositiveX(); m_sampVolume.movePositiveX();
const uint8_t v100 = m_sampVolume.getVoxel(); const VoxelType v100 = m_sampVolume.getVoxel();
const Vector3DFloat v3dPosition(static_cast<float>(uXVolSpace - m_regInputCropped.getLowerCorner().getX()) + 0.5f, static_cast<float>(uYVolSpace - m_regInputCropped.getLowerCorner().getY()), static_cast<float>(uZVolSpace - m_regInputCropped.getLowerCorner().getZ())); const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume);
const Vector3DFloat v3dNormal(v000 > v100 ? 1.0f : -1.0f,0.0,0.0);
const uint8_t uMaterial = v000 | v100; //Because one of these is 0, the or operation takes the max. //float fInterp = static_cast<float>(v100.getDensity() - VoxelType::getMinDensity()) / static_cast<float>(VoxelType::getMaxDensity() - VoxelType::getMinDensity());
float fInterp = static_cast<float>(VoxelType::getMidDensity() - v000.getDensity()) / static_cast<float>(v100.getDensity() - v000.getDensity());
//fInterp = 0.5f;
const Vector3DFloat v3dPosition(static_cast<float>(uXVolSpace - m_regInputCropped.getLowerCorner().getX()) + fInterp, static_cast<float>(uYVolSpace - m_regInputCropped.getLowerCorner().getY()), static_cast<float>(uZVolSpace - m_regInputCropped.getLowerCorner().getZ()));
//const Vector3DFloat v3dNormal(v000.getDensity() > v100.getDensity() ? 1.0f : -1.0f,0.0,0.0);
Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp));
v3dNormal.normalise();
const uint8_t uMaterial = v000.getMaterial() | v100.getMaterial(); //Because one of these is 0, the or operation takes the max.
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge); //surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge); surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge);
@ -481,10 +497,20 @@ namespace PolyVox
if (edgeTable[iCubeIndex] & 8) if (edgeTable[iCubeIndex] & 8)
{ {
m_sampVolume.movePositiveY(); m_sampVolume.movePositiveY();
const uint8_t v010 = m_sampVolume.getVoxel(); const VoxelType v010 = m_sampVolume.getVoxel();
const Vector3DFloat v3dPosition(static_cast<float>(uXVolSpace - m_regInputCropped.getLowerCorner().getX()), static_cast<float>(uYVolSpace - m_regInputCropped.getLowerCorner().getY()) + 0.5f, static_cast<float>(uZVolSpace - m_regInputCropped.getLowerCorner().getZ())); const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume);
const Vector3DFloat v3dNormal(0.0,v000 > v010 ? 1.0f : -1.0f,0.0);
const uint8_t uMaterial = v000 | v010; //Because one of these is 0, the or operation takes the max. float fInterp = static_cast<float>(VoxelType::getMidDensity() - v000.getDensity()) / static_cast<float>(v010.getDensity() - v000.getDensity());
//fInterp = 0.5f;
const Vector3DFloat v3dPosition(static_cast<float>(uXVolSpace - m_regInputCropped.getLowerCorner().getX()), static_cast<float>(uYVolSpace - m_regInputCropped.getLowerCorner().getY()) + fInterp, static_cast<float>(uZVolSpace - m_regInputCropped.getLowerCorner().getZ()));
//const Vector3DFloat v3dNormal(0.0,v000.getDensity() > v010.getDensity() ? 1.0f : -1.0f,0.0);
Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp));
v3dNormal.normalise();
const uint8_t uMaterial = v000.getMaterial() | v010.getMaterial(); //Because one of these is 0, the or operation takes the max.
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge); //surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge); surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge);
@ -499,10 +525,20 @@ namespace PolyVox
if (edgeTable[iCubeIndex] & 256) if (edgeTable[iCubeIndex] & 256)
{ {
m_sampVolume.movePositiveZ(); m_sampVolume.movePositiveZ();
const uint8_t v001 = m_sampVolume.getVoxel(); const VoxelType v001 = m_sampVolume.getVoxel();
const Vector3DFloat v3dPosition(static_cast<float>(uXVolSpace - m_regInputCropped.getLowerCorner().getX()), static_cast<float>(uYVolSpace - m_regInputCropped.getLowerCorner().getY()), static_cast<float>(uZVolSpace - m_regInputCropped.getLowerCorner().getZ()) + 0.5f); const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume);
const Vector3DFloat v3dNormal(0.0,0.0,v000 > v001 ? 1.0f : -1.0f);
const uint8_t uMaterial = v000 | v001; //Because one of these is 0, the or operation takes the max. float fInterp = static_cast<float>(VoxelType::getMidDensity() - v000.getDensity()) / static_cast<float>(v001.getDensity() - v000.getDensity());
//fInterp = 0.5f;
const Vector3DFloat v3dPosition(static_cast<float>(uXVolSpace - m_regInputCropped.getLowerCorner().getX()), static_cast<float>(uYVolSpace - m_regInputCropped.getLowerCorner().getY()), static_cast<float>(uZVolSpace - m_regInputCropped.getLowerCorner().getZ()) + fInterp);
//const Vector3DFloat v3dNormal(0.0,0.0,v000.getDensity() > v001.getDensity() ? 1.0f : -1.0f);
Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp));
v3dNormal.normalise();
const uint8_t uMaterial = v000.getMaterial() | v001.getMaterial(); //Because one of these is 0, the or operation takes the max.
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge); //surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge); surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge);
@ -518,7 +554,111 @@ namespace PolyVox
} }
} }
void SurfaceExtractor::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, template <typename VoxelType>
Vector3DFloat SurfaceExtractor<VoxelType>::computeCentralDifferenceGradient(const VolumeSampler<VoxelType>& volIter)
{
uint8_t voxel1nx = volIter.peekVoxel1nx0py0pz().getDensity();
uint8_t voxel1px = volIter.peekVoxel1px0py0pz().getDensity();
uint8_t voxel1ny = volIter.peekVoxel0px1ny0pz().getDensity();
uint8_t voxel1py = volIter.peekVoxel0px1py0pz().getDensity();
uint8_t voxel1nz = volIter.peekVoxel0px0py1nz().getDensity();
uint8_t voxel1pz = volIter.peekVoxel0px0py1pz().getDensity();
return Vector3DFloat
(
static_cast<float>(voxel1nx) - static_cast<float>(voxel1px),
static_cast<float>(voxel1ny) - static_cast<float>(voxel1py),
static_cast<float>(voxel1nz) - static_cast<float>(voxel1pz)
);
}
template <typename VoxelType>
Vector3DFloat SurfaceExtractor<VoxelType>::computeSobelGradient(const VolumeSampler<VoxelType>& volIter)
{
static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, {
{3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } };
const uint8_t pVoxel1nx1ny1nz = volIter.peekVoxel1nx1ny1nz().getDensity();
const uint8_t pVoxel1nx1ny0pz = volIter.peekVoxel1nx1ny0pz().getDensity();
const uint8_t pVoxel1nx1ny1pz = volIter.peekVoxel1nx1ny1pz().getDensity();
const uint8_t pVoxel1nx0py1nz = volIter.peekVoxel1nx0py1nz().getDensity();
const uint8_t pVoxel1nx0py0pz = volIter.peekVoxel1nx0py0pz().getDensity();
const uint8_t pVoxel1nx0py1pz = volIter.peekVoxel1nx0py1pz().getDensity();
const uint8_t pVoxel1nx1py1nz = volIter.peekVoxel1nx1py1nz().getDensity();
const uint8_t pVoxel1nx1py0pz = volIter.peekVoxel1nx1py0pz().getDensity();
const uint8_t pVoxel1nx1py1pz = volIter.peekVoxel1nx1py1pz().getDensity();
const uint8_t pVoxel0px1ny1nz = volIter.peekVoxel0px1ny1nz().getDensity();
const uint8_t pVoxel0px1ny0pz = volIter.peekVoxel0px1ny0pz().getDensity();
const uint8_t pVoxel0px1ny1pz = volIter.peekVoxel0px1ny1pz().getDensity();
const uint8_t pVoxel0px0py1nz = volIter.peekVoxel0px0py1nz().getDensity();
//const uint8_t pVoxel0px0py0pz = volIter.peekVoxel0px0py0pz().getDensity();
const uint8_t pVoxel0px0py1pz = volIter.peekVoxel0px0py1pz().getDensity();
const uint8_t pVoxel0px1py1nz = volIter.peekVoxel0px1py1nz().getDensity();
const uint8_t pVoxel0px1py0pz = volIter.peekVoxel0px1py0pz().getDensity();
const uint8_t pVoxel0px1py1pz = volIter.peekVoxel0px1py1pz().getDensity();
const uint8_t pVoxel1px1ny1nz = volIter.peekVoxel1px1ny1nz().getDensity();
const uint8_t pVoxel1px1ny0pz = volIter.peekVoxel1px1ny0pz().getDensity();
const uint8_t pVoxel1px1ny1pz = volIter.peekVoxel1px1ny1pz().getDensity();
const uint8_t pVoxel1px0py1nz = volIter.peekVoxel1px0py1nz().getDensity();
const uint8_t pVoxel1px0py0pz = volIter.peekVoxel1px0py0pz().getDensity();
const uint8_t pVoxel1px0py1pz = volIter.peekVoxel1px0py1pz().getDensity();
const uint8_t pVoxel1px1py1nz = volIter.peekVoxel1px1py1nz().getDensity();
const uint8_t pVoxel1px1py0pz = volIter.peekVoxel1px1py0pz().getDensity();
const uint8_t pVoxel1px1py1pz = volIter.peekVoxel1px1py1pz().getDensity();
const int xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz -
weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] *
pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz -
weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] *
pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz +
weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] *
pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz +
weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] *
pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz +
weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
pVoxel1px1py1pz);
const int yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz +
weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] *
pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz -
weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] *
pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz +
weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] *
pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz -
weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] *
pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz +
weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
pVoxel1px1py1pz);
const int zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz +
weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] *
pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz -
weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] *
pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz +
weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] *
pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz -
weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] *
pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz +
weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] *
pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz -
weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] *
pVoxel1px1py1pz);
//Note: The above actually give gradients going from low density to high density.
//For our normals we want the the other way around, so we switch the components as we return them.
return Vector3DFloat(static_cast<float>(-xGrad),static_cast<float>(-yGrad),static_cast<float>(-zGrad));
}
template <typename VoxelType>
void SurfaceExtractor<VoxelType>::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask,
const Array2DInt32& m_pPreviousVertexIndicesX, const Array2DInt32& m_pPreviousVertexIndicesX,
const Array2DInt32& m_pPreviousVertexIndicesY, const Array2DInt32& m_pPreviousVertexIndicesY,
const Array2DInt32& m_pPreviousVertexIndicesZ, const Array2DInt32& m_pPreviousVertexIndicesZ,

View File

@ -132,8 +132,8 @@ namespace PolyVox
uint16_t getShortestSideLength(void) const; uint16_t getShortestSideLength(void) const;
///Gets the length of the diagonal in voxels ///Gets the length of the diagonal in voxels
float getDiagonalLength(void) const; float getDiagonalLength(void) const;
VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tDefault = 0) const; VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tDefault = VoxelType()) const;
VoxelType getVoxelAt(const Vector3DUint16& v3dPos, VoxelType tDefault = 0) const; VoxelType getVoxelAt(const Vector3DUint16& v3dPos, VoxelType tDefault = VoxelType()) const;
bool setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); bool setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue);
bool setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); bool setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue);

View File

@ -124,7 +124,7 @@ namespace PolyVox
m_vecBlockIsPotentiallyHomogenous.resize(m_uNoOfBlocksInVolume); m_vecBlockIsPotentiallyHomogenous.resize(m_uNoOfBlocksInVolume);
for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i)
{ {
m_pBlocks[i] = getHomogenousBlock(0); m_pBlocks[i] = getHomogenousBlock(VoxelType());
m_vecBlockIsPotentiallyHomogenous[i] = false; m_vecBlockIsPotentiallyHomogenous[i] = false;
} }

View File

@ -23,6 +23,8 @@ freely, subject to the following restrictions:
*******************************************************************************/ *******************************************************************************/
#pragma endregion #pragma endregion
#include "ArraySizes.h"
namespace PolyVox namespace PolyVox
{ {
/** /**

View File

@ -4,15 +4,16 @@ PROJECT(PolyVoxUtil)
#Projects source files #Projects source files
SET(UTIL_SRC_FILES SET(UTIL_SRC_FILES
source/Serialization.cpp source/Dummy.cpp
source/VolumeChangeTracker.cpp
) )
#Projects headers files #Projects headers files
SET(UTIL_INC_FILES SET(UTIL_INC_FILES
include/Export.h include/Export.h
include/Serialization.h include/Serialization.h
include/Serialization.inl
include/VolumeChangeTracker.h include/VolumeChangeTracker.h
include/VolumeChangeTracker.inl
) )
ADD_DEFINITIONS(-DPOLYVOXUTIL_EXPORT) #Export symbols in the .dll ADD_DEFINITIONS(-DPOLYVOXUTIL_EXPORT) #Export symbols in the .dll

View File

@ -41,11 +41,279 @@ namespace PolyVox
virtual void onProgressUpdated(float fProgress) = 0; virtual void onProgressUpdated(float fProgress) = 0;
}; };
POLYVOXUTIL_API std::shared_ptr< Volume<uint8_t> > loadVolumeRaw(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0); template <typename VoxelType>
POLYVOXUTIL_API void saveVolumeRaw(std::ostream& stream, Volume<uint8_t>& volume, VolumeSerializationProgressListener* progressListener = 0); std::shared_ptr< Volume<VoxelType> > loadVolumeRaw(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0);
template <typename VoxelType>
void saveVolumeRaw(std::ostream& stream, Volume<VoxelType>& volume, VolumeSerializationProgressListener* progressListener = 0);
POLYVOXUTIL_API std::shared_ptr< Volume<uint8_t> > loadVolumeRle(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0); template <typename VoxelType>
POLYVOXUTIL_API void saveVolumeRle(std::ostream& stream, Volume<uint8_t>& volume, VolumeSerializationProgressListener* progressListener = 0); std::shared_ptr< Volume<VoxelType> > loadVolumeRle(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0);
template <typename VoxelType>
void saveVolumeRle(std::ostream& stream, Volume<VoxelType>& volume, VolumeSerializationProgressListener* progressListener = 0);
}
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#include "Serialization.h"
#include "Volume.h"
#include "VolumeSampler.h"
#include "PolyVoxImpl/Utility.h"
using namespace std;
namespace PolyVox
{
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
template <typename VoxelType>
shared_ptr< Volume<VoxelType> > loadVolumeRaw(istream& stream, VolumeSerializationProgressListener* progressListener)
{
//Read volume dimensions
uint8_t volumeWidthPower = 0;
uint8_t volumeHeightPower = 0;
uint8_t volumeDepthPower = 0;
stream.read(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.read(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.read(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
uint16_t volumeWidth = 0x0001 << volumeWidthPower;
uint16_t volumeHeight = 0x0001 << volumeHeightPower;
uint16_t volumeDepth = 0x0001 << volumeDepthPower;
//FIXME - need to support non cubic volumes
shared_ptr< Volume<VoxelType> > volume(new Volume<VoxelType>(volumeWidth, volumeHeight, volumeDepth));
//Read data
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
VoxelType value;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
volume->setVoxelAt(x,y,z,value);
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
return volume;
}
template <typename VoxelType>
void saveVolumeRaw(std::ostream& stream, Volume<VoxelType>& volume, VolumeSerializationProgressListener* progressListener)
{
//Write volume dimensions
uint16_t volumeWidth = volume.getWidth();
uint16_t volumeHeight = volume.getHeight();
uint16_t volumeDepth = volume.getDepth();
uint8_t volumeWidthPower = logBase2(volumeWidth);
uint8_t volumeHeightPower = logBase2(volumeHeight);
uint8_t volumeDepthPower = logBase2(volumeDepth);
stream.write(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.write(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.write(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
//Write data
VolumeSampler<VoxelType> volIter(&volume);
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
volIter.setPosition(x,y,z);
VoxelType value = volIter.getVoxel();
stream.write(reinterpret_cast<char*>(&value), sizeof(value));
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
}
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
template <typename VoxelType>
shared_ptr< Volume<VoxelType> > loadVolumeRle(istream& stream, VolumeSerializationProgressListener* progressListener)
{
//Read volume dimensions
uint8_t volumeWidthPower = 0;
uint8_t volumeHeightPower = 0;
uint8_t volumeDepthPower = 0;
stream.read(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.read(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.read(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
uint16_t volumeWidth = 0x0001 << volumeWidthPower;
uint16_t volumeHeight = 0x0001 << volumeHeightPower;
uint16_t volumeDepth = 0x0001 << volumeDepthPower;
//FIXME - need to support non cubic volumes
shared_ptr< Volume<VoxelType> > volume(new Volume<VoxelType>(volumeWidth, volumeHeight, volumeDepth));
//Read data
bool firstTime = true;
uint32_t runLength = 0;
VoxelType value;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
if(runLength != 0)
{
volume->setVoxelAt(x,y,z,value);
runLength--;
}
else
{
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
volume->setVoxelAt(x,y,z,value);
runLength--;
}
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
return volume;
}
template <typename VoxelType>
void saveVolumeRle(std::ostream& stream, Volume<VoxelType>& volume, VolumeSerializationProgressListener* progressListener)
{
//Write volume dimensions
uint16_t volumeWidth = volume.getWidth();
uint16_t volumeHeight = volume.getHeight();
uint16_t volumeDepth = volume.getDepth();
uint8_t volumeWidthPower = logBase2(volumeWidth);
uint8_t volumeHeightPower = logBase2(volumeHeight);
uint8_t volumeDepthPower = logBase2(volumeDepth);
stream.write(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.write(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.write(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
//Write data
VolumeSampler<VoxelType> volIter(&volume);
VoxelType current;
uint32_t runLength = 0;
bool firstTime = true;
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
volIter.setPosition(x,y,z);
VoxelType value = volIter.getVoxel();
if(firstTime)
{
current = value;
runLength = 1;
firstTime = false;
}
else
{
if(value == current)
{
runLength++;
}
else
{
stream.write(reinterpret_cast<char*>(&current), sizeof(current));
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
current = value;
runLength = 1;
}
}
}
}
}
stream.write(reinterpret_cast<char*>(&current), sizeof(current));
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
}
} }
#endif #endif

View File

@ -35,22 +35,23 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
/// Voxel scene manager /// Voxel scene manager
class POLYVOXUTIL_API VolumeChangeTracker template <typename VoxelType>
class VolumeChangeTracker
{ {
public: public:
//Constructors, etc //Constructors, etc
VolumeChangeTracker(Volume<uint8_t>* volumeDataToSet, uint16_t regionSideLength); VolumeChangeTracker(Volume<VoxelType>* volumeDataToSet, uint16_t regionSideLength);
~VolumeChangeTracker(); ~VolumeChangeTracker();
//Getters //Getters
int32_t getCurrentTime(void) const; int32_t getCurrentTime(void) const;
int32_t getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ); int32_t getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ);
Volume<uint8_t>* getWrappedVolume(void) const; Volume<VoxelType>* getWrappedVolume(void) const;
//Setters //Setters
void setAllRegionsModified(void); void setAllRegionsModified(void);
void setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value); void setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value);
void setVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value); void setVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value);
//Others //Others
void lockRegion(const Region& regToLock); void lockRegion(const Region& regToLock);
@ -61,7 +62,7 @@ namespace PolyVox
void incrementCurrentTime(void); void incrementCurrentTime(void);
bool m_bIsLocked; bool m_bIsLocked;
Region m_regLastLocked; Region m_regLastLocked;
Volume<uint8_t>* volumeData; Volume<VoxelType>* volumeData;
uint16_t m_uRegionSideLength; uint16_t m_uRegionSideLength;
uint8_t m_uRegionSideLengthPower; uint8_t m_uRegionSideLengthPower;
@ -78,4 +79,6 @@ namespace PolyVox
}; };
} }
#include "VolumeChangeTracker.inl"
#endif #endif

View File

@ -38,12 +38,14 @@ using namespace std;
namespace PolyVox namespace PolyVox
{ {
uint32_t VolumeChangeTracker::m_uCurrentTime = 0; template <typename VoxelType>
uint32_t VolumeChangeTracker<VoxelType>::m_uCurrentTime = 0;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// VolumeChangeTracker // VolumeChangeTracker
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
VolumeChangeTracker::VolumeChangeTracker(Volume<uint8_t>* volumeDataToSet, uint16_t regionSideLength) template <typename VoxelType>
VolumeChangeTracker<VoxelType>::VolumeChangeTracker(Volume<VoxelType>* volumeDataToSet, uint16_t regionSideLength)
:m_bIsLocked(false) :m_bIsLocked(false)
,volumeData(0) ,volumeData(0)
,m_uRegionSideLength(regionSideLength) ,m_uRegionSideLength(regionSideLength)
@ -57,11 +59,13 @@ namespace PolyVox
volRegionLastModified = new Volume<int32_t>(m_uVolumeWidthInRegions, m_uVolumeHeightInRegions, m_uVolumeDepthInRegions, 0); volRegionLastModified = new Volume<int32_t>(m_uVolumeWidthInRegions, m_uVolumeHeightInRegions, m_uVolumeDepthInRegions, 0);
} }
VolumeChangeTracker::~VolumeChangeTracker() template <typename VoxelType>
VolumeChangeTracker<VoxelType>::~VolumeChangeTracker()
{ {
} }
void VolumeChangeTracker::setAllRegionsModified(void) template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::setAllRegionsModified(void)
{ {
incrementCurrentTime(); incrementCurrentTime();
for(uint16_t blockZ = 0; blockZ < m_uVolumeDepthInRegions; ++blockZ) for(uint16_t blockZ = 0; blockZ < m_uVolumeDepthInRegions; ++blockZ)
@ -76,22 +80,26 @@ namespace PolyVox
} }
} }
int32_t VolumeChangeTracker::getCurrentTime(void) const template <typename VoxelType>
int32_t VolumeChangeTracker<VoxelType>::getCurrentTime(void) const
{ {
return m_uCurrentTime; return m_uCurrentTime;
} }
int32_t VolumeChangeTracker::getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ) template <typename VoxelType>
int32_t VolumeChangeTracker<VoxelType>::getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ)
{ {
return volRegionLastModified->getVoxelAt(uX, uY, uZ); return volRegionLastModified->getVoxelAt(uX, uY, uZ);
} }
Volume<uint8_t>* VolumeChangeTracker::getWrappedVolume(void) const template <typename VoxelType>
Volume<VoxelType>* VolumeChangeTracker<VoxelType>::getWrappedVolume(void) const
{ {
return volumeData; return volumeData;
} }
void VolumeChangeTracker::setVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value) template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::setVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value)
{ {
//Note: We increase the time stamp both at the start and the end //Note: We increase the time stamp both at the start and the end
//to avoid ambiguity about whether the timestamp comparison should //to avoid ambiguity about whether the timestamp comparison should
@ -140,18 +148,20 @@ namespace PolyVox
incrementCurrentTime(); incrementCurrentTime();
} }
void VolumeChangeTracker::setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, uint8_t value) template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value)
{ {
assert(m_bIsLocked); assert(m_bIsLocked);
//FIXME - rather than creating a iterator each time we should have one stored //FIXME - rather than creating a iterator each time we should have one stored
/*VolumeSampler<uint8_t> iterVol(*volumeData); /*VolumeSampler<VoxelType> iterVol(*volumeData);
iterVol.setPosition(x,y,z); iterVol.setPosition(x,y,z);
iterVol.setVoxel(value);*/ iterVol.setVoxel(value);*/
volumeData->setVoxelAt(x,y,z,value); volumeData->setVoxelAt(x,y,z,value);
} }
void VolumeChangeTracker::lockRegion(const Region& regToLock) template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::lockRegion(const Region& regToLock)
{ {
if(m_bIsLocked) if(m_bIsLocked)
{ {
@ -162,7 +172,8 @@ namespace PolyVox
m_bIsLocked = true; m_bIsLocked = true;
} }
void VolumeChangeTracker::unlockRegion(void) template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::unlockRegion(void)
{ {
if(!m_bIsLocked) if(!m_bIsLocked)
{ {
@ -199,7 +210,8 @@ namespace PolyVox
incrementCurrentTime(); incrementCurrentTime();
} }
void VolumeChangeTracker::incrementCurrentTime(void) template <typename VoxelType>
void VolumeChangeTracker<VoxelType>::incrementCurrentTime(void)
{ {
//Increment the current time. //Increment the current time.
uint32_t time = m_uCurrentTime++; uint32_t time = m_uCurrentTime++;

View File

@ -1,259 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#include "Serialization.h"
#include "Volume.h"
#include "VolumeSampler.h"
#include "PolyVoxImpl/Utility.h"
using namespace std;
namespace PolyVox
{
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
shared_ptr< Volume<uint8_t> > loadVolumeRaw(istream& stream, VolumeSerializationProgressListener* progressListener)
{
//Read volume dimensions
uint8_t volumeWidthPower = 0;
uint8_t volumeHeightPower = 0;
uint8_t volumeDepthPower = 0;
stream.read(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.read(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.read(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
uint16_t volumeWidth = 0x0001 << volumeWidthPower;
uint16_t volumeHeight = 0x0001 << volumeHeightPower;
uint16_t volumeDepth = 0x0001 << volumeDepthPower;
//FIXME - need to support non cubic volumes
shared_ptr< Volume<uint8_t> > volume(new Volume<uint8_t>(volumeWidth, volumeHeight, volumeDepth));
//Read data
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
uint8_t value = 0;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
volume->setVoxelAt(x,y,z,value);
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
return volume;
}
void saveVolumeRaw(std::ostream& stream, Volume<uint8_t>& volume, VolumeSerializationProgressListener* progressListener)
{
//Write volume dimensions
uint16_t volumeWidth = volume.getWidth();
uint16_t volumeHeight = volume.getHeight();
uint16_t volumeDepth = volume.getDepth();
uint8_t volumeWidthPower = logBase2(volumeWidth);
uint8_t volumeHeightPower = logBase2(volumeHeight);
uint8_t volumeDepthPower = logBase2(volumeDepth);
stream.write(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.write(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.write(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
//Write data
VolumeSampler<uint8_t> volIter(&volume);
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
volIter.setPosition(x,y,z);
uint8_t value = volIter.getVoxel();
stream.write(reinterpret_cast<char*>(&value), sizeof(value));
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
}
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
shared_ptr< Volume<uint8_t> > loadVolumeRle(istream& stream, VolumeSerializationProgressListener* progressListener)
{
//Read volume dimensions
uint8_t volumeWidthPower = 0;
uint8_t volumeHeightPower = 0;
uint8_t volumeDepthPower = 0;
stream.read(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.read(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.read(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
uint16_t volumeWidth = 0x0001 << volumeWidthPower;
uint16_t volumeHeight = 0x0001 << volumeHeightPower;
uint16_t volumeDepth = 0x0001 << volumeDepthPower;
//FIXME - need to support non cubic volumes
shared_ptr< Volume<uint8_t> > volume(new Volume<uint8_t>(volumeWidth, volumeHeight, volumeDepth));
//Read data
bool firstTime = true;
uint32_t runLength = 0;
uint8_t value = 0;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
if(runLength != 0)
{
volume->setVoxelAt(x,y,z,value);
runLength--;
}
else
{
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
volume->setVoxelAt(x,y,z,value);
runLength--;
}
}
}
}
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
return volume;
}
void saveVolumeRle(std::ostream& stream, Volume<uint8_t>& volume, VolumeSerializationProgressListener* progressListener)
{
//Write volume dimensions
uint16_t volumeWidth = volume.getWidth();
uint16_t volumeHeight = volume.getHeight();
uint16_t volumeDepth = volume.getDepth();
uint8_t volumeWidthPower = logBase2(volumeWidth);
uint8_t volumeHeightPower = logBase2(volumeHeight);
uint8_t volumeDepthPower = logBase2(volumeDepth);
stream.write(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
stream.write(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
stream.write(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
//Write data
VolumeSampler<uint8_t> volIter(&volume);
uint8_t current = 0;
uint32_t runLength = 0;
bool firstTime = true;
for(uint16_t z = 0; z < volumeDepth; ++z)
{
//Update progress once per slice.
if(progressListener)
{
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
progressListener->onProgressUpdated(fProgress);
}
for(uint16_t y = 0; y < volumeHeight; ++y)
{
for(uint16_t x = 0; x < volumeWidth; ++x)
{
volIter.setPosition(x,y,z);
uint8_t value = volIter.getVoxel();
if(firstTime)
{
current = value;
runLength = 1;
firstTime = false;
}
else
{
if(value == current)
{
runLength++;
}
else
{
stream.write(reinterpret_cast<char*>(&current), sizeof(current));
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
current = value;
runLength = 1;
}
}
}
}
}
stream.write(reinterpret_cast<char*>(&current), sizeof(current));
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
//Finished
if(progressListener)
{
progressListener->onProgressUpdated(1.0f);
}
}
}

View File

@ -35,7 +35,8 @@ void TestArray::testReadWrite()
int height = 10; int height = 10;
int depth = 20; int depth = 20;
Array<3, int> myArray(ArraySizes(width)(height)(depth)); uint32_t dimensions[3] = {width, height, depth}; // Array dimensions
Array<3, int> myArray(dimensions);
int ct = 1; int ct = 1;
int expectedTotal = 0; int expectedTotal = 0;