Removed features which were deprecated in release 0.2.
This commit is contained in:
parent
e7f4c69102
commit
7e38fc135e
@ -7,6 +7,10 @@ Removed functionality
|
||||
Functionality deprecated for the previous release has now been removed. This includes:
|
||||
|
||||
- Region::getWidth() and related functions. You should now use Region::getWidthInVoxels() or Region::getWidthInCells.
|
||||
- The MeshDecimator. We don't have a direct replacement for this so you should consider an alternative such as downsampling the volume or using an external mesh processing library.
|
||||
- The SimpleInterface. This was primarily for the bindings, and we are making other efforts to get those working.
|
||||
- Serialisation. You should implement ay required serialisation yourself.
|
||||
- This had a number of problems and was a little too high-level for PolyVox. You should implement change tracking yourself.
|
||||
|
||||
|
||||
The Region class has been tidied up and enhanced with new functionality. It now contains functions for growing and shrinking regions, as well as 'accumulate()' functions which ensure the Region contains a given point. The concept of an invalid region has also been introduced - this is one whose lower corner is greater than it's upper corner.
|
||||
|
@ -29,9 +29,7 @@ SET(CORE_SRC_FILES
|
||||
source/ArraySizes.cpp
|
||||
source/AStarPathfinder.cpp
|
||||
source/Log.cpp
|
||||
source/MeshDecimator.cpp
|
||||
source/Region.cpp
|
||||
source/SimpleInterface.cpp
|
||||
source/VertexTypes.cpp
|
||||
)
|
||||
|
||||
@ -70,8 +68,6 @@ SET(CORE_INC_FILES
|
||||
include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl
|
||||
include/PolyVoxCore/Material.h
|
||||
include/PolyVoxCore/MaterialDensityPair.h
|
||||
include/PolyVoxCore/MeshDecimator.h
|
||||
include/PolyVoxCore/MeshDecimator.inl
|
||||
include/PolyVoxCore/PolyVoxForwardDeclarations.h
|
||||
include/PolyVoxCore/RawVolume.h
|
||||
include/PolyVoxCore/RawVolume.inl
|
||||
@ -79,7 +75,6 @@ SET(CORE_INC_FILES
|
||||
include/PolyVoxCore/Raycast.h
|
||||
include/PolyVoxCore/Raycast.inl
|
||||
include/PolyVoxCore/Region.h
|
||||
include/PolyVoxCore/SimpleInterface.h
|
||||
include/PolyVoxCore/SimpleVolume.h
|
||||
include/PolyVoxCore/SimpleVolume.inl
|
||||
include/PolyVoxCore/SimpleVolumeBlock.inl
|
||||
|
@ -1,187 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_MeshDecimator_H__
|
||||
#define __PolyVox_MeshDecimator_H__
|
||||
|
||||
#include "PolyVoxCore/SurfaceMesh.h"
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
#include "PolyVoxCore/VertexTypes.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/// The MeshDecimator reduces the number of triangles in a mesh.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Meshes generated by the PolyVox surface extractors typically have a very high
|
||||
/// number of triangles in them. This can pose difficulties both for the rendering
|
||||
/// storage of such meshes. The MeshDecimator provides a way of reducing the triangle
|
||||
/// count with minimal visual effect.
|
||||
///
|
||||
/// The MeshDecimator is based on the principle of edge collapse, and currently works
|
||||
/// with meshes generated by the MarchingCubesSurfaceExtractor or CubicSurfaceExtractor. It does
|
||||
/// not work with meshes generated by the CubicSurfaceExtractorWithNormals, although
|
||||
/// this may be addressed in the future. The algorithm iterates over each pair of
|
||||
/// connected vertices in the mesh and attemps to determine if they can be collapsed
|
||||
/// into a single vertex.
|
||||
///
|
||||
/// The main criteria used in deciding whether two vertices can collapse is whether
|
||||
/// they have the same normal. In the case of the cubic surfaces the normals must be
|
||||
/// exactly the same, whereas in the case of the Marching Cubes surfaces a threshold
|
||||
/// is used to determine whether two normals are 'close enough'. Additional constraints
|
||||
/// apply to vertices which lie on the edges of regions or on the boundary between two
|
||||
/// regions - these vertices are much less likely to be collapsed.
|
||||
///
|
||||
/// Given a mesh called 'mesh', you can create a decimated version as follows:
|
||||
/// \code
|
||||
/// SurfaceMesh<PositionMaterial> decimatedMesh;
|
||||
/// MeshDecimator<PositionMaterial> decimator(&mesh, &decimatedMesh);
|
||||
/// decimator.execute();
|
||||
/// \endcode
|
||||
///
|
||||
/// The above applies for a cubic mesh, for a Marching Cubes mesh you need to parametise
|
||||
/// the MeshDecimator and resulting SurfaceMesh on the 'PositionMaterialNormal' type
|
||||
/// instead of the 'PositionMaterial' type.
|
||||
///
|
||||
/// \deprecated
|
||||
template <typename VertexType>
|
||||
class MeshDecimator
|
||||
{
|
||||
//Used to keep track of when a vertex is
|
||||
//on one or more faces of the region
|
||||
enum RegionFaceFlags
|
||||
{
|
||||
RFF_ON_REGION_FACE_NEG_X,
|
||||
RFF_ON_REGION_FACE_POS_X ,
|
||||
RFF_ON_REGION_FACE_NEG_Y ,
|
||||
RFF_ON_REGION_FACE_POS_Y ,
|
||||
RFF_ON_REGION_FACE_NEG_Z ,
|
||||
RFF_ON_REGION_FACE_POS_Z,
|
||||
RFF_NO_OF_REGION_FACE_FLAGS
|
||||
};
|
||||
|
||||
//Data about the initial mesh - this
|
||||
//will be fill in once at the start
|
||||
struct InitialVertexMetadata
|
||||
{
|
||||
Vector3DFloat normal;
|
||||
bool isOnMaterialEdge;
|
||||
std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> isOnRegionFace;
|
||||
};
|
||||
|
||||
//Representing a triangle for decimation purposes.
|
||||
struct Triangle
|
||||
{
|
||||
uint32_t v0;
|
||||
uint32_t v1;
|
||||
uint32_t v2;
|
||||
Vector3DFloat normal;
|
||||
};
|
||||
|
||||
struct IntVertex
|
||||
{
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t z;
|
||||
uint32_t index;
|
||||
|
||||
IntVertex(int32_t xVal, int32_t yVal, int32_t zVal, uint32_t indexVal)
|
||||
:x(xVal)
|
||||
,y(yVal)
|
||||
,z(zVal)
|
||||
,index(indexVal)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const IntVertex& rhs) const
|
||||
{
|
||||
return (x == rhs.x) && (y == rhs.y) && (z == rhs.z);
|
||||
}
|
||||
|
||||
bool operator<(const IntVertex& rhs) const
|
||||
{
|
||||
if (z < rhs.z)
|
||||
return true;
|
||||
if (rhs.z < z)
|
||||
return false;
|
||||
|
||||
if (y < rhs.y)
|
||||
return true;
|
||||
if (rhs.y < y)
|
||||
return false;
|
||||
|
||||
if (x < rhs.x)
|
||||
return true;
|
||||
if (rhs.x < x)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
///Constructor
|
||||
POLYVOX_DEPRECATED MeshDecimator(const SurfaceMesh<VertexType>* pInputMesh, SurfaceMesh<VertexType>* pOutputMesh, float fEdgeCollapseThreshold = 0.95f);
|
||||
|
||||
///Performs the decimation.
|
||||
POLYVOX_DEPRECATED void execute();
|
||||
|
||||
private:
|
||||
|
||||
void fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecInitialVertexMetadata);
|
||||
|
||||
void buildConnectivityData(void);
|
||||
|
||||
bool attemptEdgeCollapse(uint32_t uSrc, uint32_t uDst);
|
||||
|
||||
const SurfaceMesh<VertexType>* m_pInputMesh;
|
||||
SurfaceMesh<VertexType>* m_pOutputMesh;
|
||||
|
||||
uint32_t performDecimationPass(float m_fMinDotProductForCollapse);
|
||||
bool isSubset(std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> a, std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> b);
|
||||
|
||||
bool canCollapseEdge(uint32_t uSrc, uint32_t uDst);
|
||||
bool canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst);
|
||||
bool canCollapseRegionEdge(uint32_t uSrc, uint32_t uDst);
|
||||
bool canCollapseMaterialEdge(uint32_t uSrc, uint32_t uDst);
|
||||
bool collapseChangesFaceNormals(uint32_t uSrc, uint32_t uDst, float fThreshold);
|
||||
|
||||
//Data structures used during decimation
|
||||
|
||||
std::vector<bool> vertexLocked;
|
||||
std::vector<uint32_t> vertexMapper;
|
||||
|
||||
std::vector<Triangle> m_vecTriangles;
|
||||
std::vector< std::vector<uint32_t> > trianglesUsingVertex; //Should probably use vector of vectors, and resise in advance.
|
||||
|
||||
std::vector<InitialVertexMetadata> m_vecInitialVertexMetadata;
|
||||
|
||||
float m_fMinDotProductForCollapse;
|
||||
};
|
||||
}
|
||||
|
||||
#include "PolyVoxCore/MeshDecimator.inl"
|
||||
|
||||
#endif //__PolyVox_MeshDecimator_H__
|
@ -1,347 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Builds a MeshDecimator.
|
||||
/// \param pInputMesh A pointer to the mesh to be decimated.
|
||||
/// \param[out] pOutputMesh A pointer to where the result should be stored. Any existing
|
||||
/// contents will be deleted.
|
||||
/// \param fEdgeCollapseThreshold This is only use in the case of a Marching Cubes
|
||||
/// surface and controls how close two normals must be to collapse. The dot product
|
||||
/// between the normals is computed and compared to this threshold. A threshold of
|
||||
/// 1.0 means nothing will collapse, a threshold of 0.0 means everything will collapse.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename VertexType>
|
||||
MeshDecimator<VertexType>::MeshDecimator(const SurfaceMesh<VertexType>* pInputMesh, SurfaceMesh<VertexType>* pOutputMesh, float fEdgeCollapseThreshold)
|
||||
:m_pInputMesh(pInputMesh)
|
||||
,m_pOutputMesh(pOutputMesh)
|
||||
,m_fMinDotProductForCollapse(fEdgeCollapseThreshold)
|
||||
{
|
||||
*m_pOutputMesh = *m_pInputMesh;
|
||||
}
|
||||
|
||||
template <typename VertexType>
|
||||
void MeshDecimator<VertexType>::execute()
|
||||
{
|
||||
//Sanity check.
|
||||
if((m_pOutputMesh->m_vecVertices.empty()) || (m_pOutputMesh->m_vecTriangleIndices.empty()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buildConnectivityData();
|
||||
fillInitialVertexMetadata(m_vecInitialVertexMetadata);
|
||||
|
||||
uint32_t noOfEdgesCollapsed;
|
||||
do
|
||||
{
|
||||
noOfEdgesCollapsed = performDecimationPass(m_fMinDotProductForCollapse);
|
||||
m_pOutputMesh->removeDegenerateTris();
|
||||
if(noOfEdgesCollapsed > 0)
|
||||
{
|
||||
//Build the connectivity data for the next pass. If this is slow, then look
|
||||
//at adjusting it (based on vertex mapper?) rather than bulding from scratch.
|
||||
buildConnectivityData();
|
||||
}
|
||||
}while(noOfEdgesCollapsed > 0);
|
||||
|
||||
m_pOutputMesh->removeUnusedVertices();
|
||||
|
||||
//Decimation will have invalidated LOD levels.
|
||||
m_pOutputMesh->m_vecLodRecords.clear();
|
||||
LodRecord lodRecord;
|
||||
lodRecord.beginIndex = 0;
|
||||
lodRecord.endIndex = m_pOutputMesh->getNoOfIndices();
|
||||
m_pOutputMesh->m_vecLodRecords.push_back(lodRecord);
|
||||
}
|
||||
|
||||
template <typename VertexType>
|
||||
void MeshDecimator<VertexType>::buildConnectivityData(void)
|
||||
{
|
||||
//Build a list of all the triangles, complete with face normals.
|
||||
m_vecTriangles.clear();
|
||||
m_vecTriangles.resize(m_pOutputMesh->m_vecTriangleIndices.size() / 3);
|
||||
for(uint32_t triCt = 0; triCt < m_vecTriangles.size(); triCt++)
|
||||
{
|
||||
m_vecTriangles[triCt].v0 = m_pOutputMesh->m_vecTriangleIndices[triCt * 3 + 0];
|
||||
m_vecTriangles[triCt].v1 = m_pOutputMesh->m_vecTriangleIndices[triCt * 3 + 1];
|
||||
m_vecTriangles[triCt].v2 = m_pOutputMesh->m_vecTriangleIndices[triCt * 3 + 2];
|
||||
|
||||
Vector3DFloat v0Pos = m_pOutputMesh->m_vecVertices[m_vecTriangles[triCt].v0].position;
|
||||
Vector3DFloat v1Pos = m_pOutputMesh->m_vecVertices[m_vecTriangles[triCt].v1].position;
|
||||
Vector3DFloat v2Pos = m_pOutputMesh->m_vecVertices[m_vecTriangles[triCt].v2].position;
|
||||
|
||||
Vector3DFloat v0v1 = v1Pos - v0Pos;
|
||||
Vector3DFloat v0v2 = v2Pos - v0Pos;
|
||||
Vector3DFloat normal = v0v1.cross(v0v2);
|
||||
normal.normalise();
|
||||
|
||||
m_vecTriangles[triCt].normal = normal;
|
||||
}
|
||||
|
||||
//For each vertex, determine which triangles are using it.
|
||||
trianglesUsingVertex.clear();
|
||||
trianglesUsingVertex.resize(m_pOutputMesh->m_vecVertices.size());
|
||||
for(uint32_t ct = 0; ct < trianglesUsingVertex.size(); ct++)
|
||||
{
|
||||
trianglesUsingVertex[ct].reserve(6);
|
||||
}
|
||||
for(uint32_t ct = 0; ct < m_vecTriangles.size(); ct++)
|
||||
{
|
||||
trianglesUsingVertex[m_vecTriangles[ct].v0].push_back(ct);
|
||||
trianglesUsingVertex[m_vecTriangles[ct].v1].push_back(ct);
|
||||
trianglesUsingVertex[m_vecTriangles[ct].v2].push_back(ct);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VertexType>
|
||||
uint32_t MeshDecimator<VertexType>::performDecimationPass(float /*m_fMinDotProductForCollapse*/)
|
||||
{
|
||||
// Count how many edges we have collapsed
|
||||
uint32_t noOfEdgesCollapsed = 0;
|
||||
|
||||
// The vertex mapper track whick vertices collapse onto which.
|
||||
vertexMapper.clear();
|
||||
vertexMapper.resize(m_pOutputMesh->m_vecVertices.size());
|
||||
|
||||
// Once a vertex is involved in a collapse (either because it
|
||||
// moves onto a different vertex, or because a different vertex
|
||||
// moves onto it) it is forbidden to take part in another collapse
|
||||
// this pass. We enforce this by setting the vertex locked flag.
|
||||
vertexLocked.clear();
|
||||
vertexLocked.resize(m_pOutputMesh->m_vecVertices.size());
|
||||
|
||||
// Initialise the vectors
|
||||
for(uint32_t ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++)
|
||||
{
|
||||
// Initiall all vertices points to themselves
|
||||
vertexMapper[ct] = ct;
|
||||
// All vertices are initially unlocked
|
||||
vertexLocked[ct] = false;
|
||||
}
|
||||
|
||||
//For each triangle...
|
||||
for(uint32_t ctIter = 0; ctIter < m_vecTriangles.size(); ctIter++)
|
||||
{
|
||||
if(attemptEdgeCollapse(m_vecTriangles[ctIter].v0, m_vecTriangles[ctIter].v1))
|
||||
{
|
||||
++noOfEdgesCollapsed;
|
||||
}
|
||||
|
||||
if(attemptEdgeCollapse(m_vecTriangles[ctIter].v1, m_vecTriangles[ctIter].v2))
|
||||
{
|
||||
++noOfEdgesCollapsed;
|
||||
}
|
||||
|
||||
if(attemptEdgeCollapse(m_vecTriangles[ctIter].v2, m_vecTriangles[ctIter].v0))
|
||||
{
|
||||
++noOfEdgesCollapsed;
|
||||
}
|
||||
}
|
||||
|
||||
if(noOfEdgesCollapsed > 0)
|
||||
{
|
||||
//Fix up the indices
|
||||
for(uint32_t triCt = 0; triCt < m_pOutputMesh->m_vecTriangleIndices.size(); triCt++)
|
||||
{
|
||||
uint32_t before = m_pOutputMesh->m_vecTriangleIndices[triCt];
|
||||
uint32_t after = vertexMapper[m_pOutputMesh->m_vecTriangleIndices[triCt]];
|
||||
if(before != after)
|
||||
{
|
||||
m_pOutputMesh->m_vecTriangleIndices[triCt] = vertexMapper[m_pOutputMesh->m_vecTriangleIndices[triCt]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return noOfEdgesCollapsed;
|
||||
}
|
||||
|
||||
template <typename VertexType>
|
||||
bool MeshDecimator<VertexType>::attemptEdgeCollapse(uint32_t uSrc, uint32_t uDst)
|
||||
{
|
||||
//A vertex will be locked if it has already been involved in a collapse this pass.
|
||||
if(vertexLocked[uSrc] || vertexLocked[uDst])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(canCollapseEdge(uSrc, uDst))
|
||||
{
|
||||
//Move v0 onto v1
|
||||
vertexMapper[uSrc] = uDst; //vertexMapper[v1];
|
||||
vertexLocked[uSrc] = true;
|
||||
vertexLocked[uDst] = true;
|
||||
|
||||
//Increment the counter
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename VertexType>
|
||||
bool MeshDecimator<VertexType>::canCollapseEdge(uint32_t uSrc, uint32_t uDst)
|
||||
{
|
||||
bool bCanCollapse = true;
|
||||
|
||||
if(m_vecInitialVertexMetadata[uSrc].isOnMaterialEdge)
|
||||
{
|
||||
bCanCollapse &= canCollapseMaterialEdge(uSrc, uDst);
|
||||
}
|
||||
|
||||
if(m_vecInitialVertexMetadata[uSrc].isOnRegionFace.any())
|
||||
{
|
||||
bCanCollapse &= canCollapseRegionEdge(uSrc, uDst);
|
||||
}
|
||||
|
||||
if(bCanCollapse) //Only bother with this if the earlier tests passed.
|
||||
{
|
||||
bCanCollapse &= canCollapseNormalEdge(uSrc, uDst);
|
||||
}
|
||||
|
||||
return bCanCollapse;
|
||||
}
|
||||
|
||||
template <typename VertexType>
|
||||
bool MeshDecimator<VertexType>::canCollapseRegionEdge(uint32_t uSrc, uint32_t uDst)
|
||||
{
|
||||
// We can collapse normal vertices onto edge vertices, and edge vertices
|
||||
// onto corner vertices, but not vice-versa. Hence we check whether all
|
||||
// the edge flags in the source vertex are also set in the destination vertex.
|
||||
if(isSubset(m_vecInitialVertexMetadata[uSrc].isOnRegionFace, m_vecInitialVertexMetadata[uDst].isOnRegionFace) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// In general adjacent regions surface meshes may collapse differently
|
||||
// and this can cause cracks. We solve this by only allowing the collapse
|
||||
// is the normals are exactly the same. We do not use the user provided
|
||||
// tolerence here (but do allow for floating point error).
|
||||
if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < 0.999f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename VertexType>
|
||||
bool MeshDecimator<VertexType>::canCollapseMaterialEdge(uint32_t /*uSrc*/, uint32_t /*uDst*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//This function should really use some work. For a start we already have the
|
||||
//faces normals for the input mesh yet we are computing them on the fly here.
|
||||
template <typename VertexType>
|
||||
bool MeshDecimator<VertexType>::collapseChangesFaceNormals(uint32_t uSrc, uint32_t uDst, float fThreshold)
|
||||
{
|
||||
bool faceFlipped = false;
|
||||
std::vector<uint32_t>& triangles = trianglesUsingVertex[uSrc];
|
||||
|
||||
for(std::vector<uint32_t>::iterator triIter = triangles.begin(); triIter != triangles.end(); triIter++)
|
||||
{
|
||||
uint32_t tri = *triIter;
|
||||
|
||||
const uint32_t& v0Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3];
|
||||
const uint32_t& v1Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3 + 1];
|
||||
const uint32_t& v2Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3 + 2];
|
||||
|
||||
//Check if degenerate
|
||||
if((v0Old == v1Old) || (v1Old == v2Old) || (v2Old == v0Old))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t v0New = v0Old;
|
||||
uint32_t v1New = v1Old;
|
||||
uint32_t v2New = v2Old;
|
||||
|
||||
if(v0New == uSrc)
|
||||
v0New = uDst;
|
||||
if(v1New == uSrc)
|
||||
v1New = uDst;
|
||||
if(v2New == uSrc)
|
||||
v2New = uDst;
|
||||
|
||||
//Check if degenerate
|
||||
if((v0New == v1New) || (v1New == v2New) || (v2New == v0New))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const Vector3DFloat& v0OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v0Old]].getPosition(); //Note: we need the vertex mapper here. These neighbouring vertices may have been moved.
|
||||
const Vector3DFloat& v1OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1Old]].getPosition();
|
||||
const Vector3DFloat& v2OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v2Old]].getPosition();
|
||||
|
||||
const Vector3DFloat& v0NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v0New]].getPosition();
|
||||
const Vector3DFloat& v1NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1New]].getPosition();
|
||||
const Vector3DFloat& v2NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v2New]].getPosition();
|
||||
|
||||
Vector3DFloat OldNormal = (v1OldPos - v0OldPos).cross(v2OldPos - v1OldPos);
|
||||
Vector3DFloat NewNormal = (v1NewPos - v0NewPos).cross(v2NewPos - v1NewPos);
|
||||
|
||||
OldNormal.normalise();
|
||||
NewNormal.normalise();
|
||||
|
||||
float dotProduct = OldNormal.dot(NewNormal);
|
||||
//NOTE: I don't think we should be using the threshold here, we're just checking for a complete face flip
|
||||
if(dotProduct < fThreshold)
|
||||
{
|
||||
//cout << " Face flipped!!" << endl;
|
||||
|
||||
faceFlipped = true;
|
||||
|
||||
/*vertexLocked[v0] = true;
|
||||
vertexLocked[v1] = true;*/
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return faceFlipped;
|
||||
}
|
||||
|
||||
// Returns true if every bit which is set in 'a' is also set in 'b'. The reverse does not need to be true.
|
||||
template <typename VertexType>
|
||||
bool MeshDecimator<VertexType>::isSubset(std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> a, std::bitset<RFF_NO_OF_REGION_FACE_FLAGS> b)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for(int ct = 0; ct < RFF_NO_OF_REGION_FACE_FLAGS; ct++)
|
||||
{
|
||||
if(a.test(ct))
|
||||
{
|
||||
if(b.test(ct) == false)
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_SimpleInterface_H__
|
||||
#define __PolyVox_SimpleInterface_H__
|
||||
|
||||
#include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h"
|
||||
#include "PolyVoxCore/MaterialDensityPair.h"
|
||||
#include "PolyVoxCore/SimpleVolume.h"
|
||||
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
//The PolyVox simple interface only exposes one voxel type and one volume type. But if you like you can
|
||||
//adjust these typedefs and rebuild the library in order to modify which one volume and voxel is exposed.
|
||||
typedef SimpleVolume<MaterialDensityPair88> Volume;
|
||||
typedef SurfaceMesh<PositionMaterialNormal> Mesh;
|
||||
|
||||
/// \deprecated
|
||||
POLYVOX_DEPRECATED void extractCubicMesh(Volume& volume, const Region& region, Mesh& resultMesh);
|
||||
/// \deprecated
|
||||
POLYVOX_DEPRECATED void extractSmoothMesh(Volume& volume, const Region& region, Mesh& resultMesh);
|
||||
|
||||
}
|
||||
|
||||
#endif //__PolyVox_SimpleInterface_H__
|
@ -1,181 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/MeshDecimator.h"
|
||||
#include "PolyVoxCore/SurfaceMesh.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template<>
|
||||
POLYVOX_API void MeshDecimator<PositionMaterial>::fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecVertexMetadata)
|
||||
{
|
||||
vecVertexMetadata.clear();
|
||||
vecVertexMetadata.resize(m_pOutputMesh->m_vecVertices.size());
|
||||
//Initialise the metadata
|
||||
for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
|
||||
{
|
||||
vecVertexMetadata[ct].normal.setElements(0,0,0);
|
||||
vecVertexMetadata[ct].isOnMaterialEdge = false;
|
||||
vecVertexMetadata[ct].isOnRegionFace.reset();
|
||||
}
|
||||
|
||||
//Identify duplicate vertices, as they lie on the material edge. To do this we convert into integers and sort
|
||||
//(first on z, then y, then x). They should be mostly in order as this is the order they come out of the
|
||||
//CubicSurfaceExtractor in. Duplicates are now neighbours in the resulting list so just scan through for pairs.
|
||||
std::vector<IntVertex> intVertices;
|
||||
intVertices.reserve(m_pOutputMesh->m_vecVertices.size());
|
||||
for(uint32_t ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++)
|
||||
{
|
||||
const Vector3DFloat& floatPos = m_pOutputMesh->m_vecVertices[ct].position;
|
||||
IntVertex intVertex(static_cast<uint32_t>(floatPos.getX()), static_cast<uint32_t>(floatPos.getY()), static_cast<uint32_t>(floatPos.getZ()), ct);
|
||||
intVertices.push_back(intVertex);
|
||||
}
|
||||
|
||||
//Do the sorting so that duplicate become neighbours
|
||||
sort(intVertices.begin(), intVertices.end());
|
||||
|
||||
//Find neighbours which are duplicates.
|
||||
for(uint32_t ct = 0; ct < intVertices.size() - 1; ct++)
|
||||
{
|
||||
const IntVertex& v0 = intVertices[ct+0];
|
||||
const IntVertex& v1 = intVertices[ct+1];
|
||||
|
||||
if((v0.x == v1.x) && (v0.y == v1.y) && (v0.z == v1.z))
|
||||
{
|
||||
vecVertexMetadata[v0.index].isOnMaterialEdge = true;
|
||||
vecVertexMetadata[v1.index].isOnMaterialEdge = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Compute an approcimation to the normal, used when deciding if an edge can collapse.
|
||||
for(uint32_t ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++)
|
||||
{
|
||||
Vector3DFloat sumOfNormals(0.0f,0.0f,0.0f);
|
||||
for(vector<uint32_t>::iterator iter = trianglesUsingVertex[ct].begin(); iter != trianglesUsingVertex[ct].end(); iter++)
|
||||
{
|
||||
sumOfNormals += m_vecTriangles[*iter].normal;
|
||||
}
|
||||
|
||||
vecVertexMetadata[ct].normal = sumOfNormals;
|
||||
vecVertexMetadata[ct].normal.normalise();
|
||||
}
|
||||
|
||||
//Identify those vertices on the edge of a region. Care will need to be taken when moving them.
|
||||
for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
|
||||
{
|
||||
Region regTransformed = m_pOutputMesh->m_Region;
|
||||
regTransformed.shift(regTransformed.getLowerCorner() * static_cast<int32_t>(-1));
|
||||
|
||||
//Plus and minus X
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() < regTransformed.getLowerCorner().getX() + 0.001f);
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() > regTransformed.getUpperCorner().getX() - 0.001f);
|
||||
//Plus and minus Y
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() < regTransformed.getLowerCorner().getY() + 0.001f);
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() > regTransformed.getUpperCorner().getY() - 0.001f);
|
||||
//Plus and minus Z
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() < regTransformed.getLowerCorner().getZ() + 0.001f);
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() > regTransformed.getUpperCorner().getZ() - 0.001f);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
POLYVOX_API void MeshDecimator<PositionMaterialNormal>::fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecVertexMetadata)
|
||||
{
|
||||
vecVertexMetadata.clear();
|
||||
vecVertexMetadata.resize(m_pOutputMesh->m_vecVertices.size());
|
||||
|
||||
//Initialise the metadata
|
||||
for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
|
||||
{
|
||||
vecVertexMetadata[ct].isOnRegionFace.reset();
|
||||
vecVertexMetadata[ct].isOnMaterialEdge = false;
|
||||
vecVertexMetadata[ct].normal = m_pOutputMesh->m_vecVertices[ct].normal;
|
||||
}
|
||||
|
||||
//Identify those vertices on the edge of a region. Care will need to be taken when moving them.
|
||||
for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
|
||||
{
|
||||
Region regTransformed = m_pOutputMesh->m_Region;
|
||||
regTransformed.shift(regTransformed.getLowerCorner() * static_cast<int32_t>(-1));
|
||||
|
||||
//Plus and minus X
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() < regTransformed.getLowerCorner().getX() + 0.001f);
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() > regTransformed.getUpperCorner().getX() - 0.001f);
|
||||
//Plus and minus Y
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() < regTransformed.getLowerCorner().getY() + 0.001f);
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() > regTransformed.getUpperCorner().getY() - 0.001f);
|
||||
//Plus and minus Z
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() < regTransformed.getLowerCorner().getZ() + 0.001f);
|
||||
vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() > regTransformed.getUpperCorner().getZ() - 0.001f);
|
||||
}
|
||||
|
||||
//If all three vertices have the same material then we are not on a material edge. If any vertex has a different
|
||||
//material then all three vertices are on a material edge. E.g. If one vertex has material 'a' and the other two
|
||||
//have material 'b', then the two 'b's are still on an edge (with 'a') even though they are the same as eachother.
|
||||
for(uint32_t ct = 0; ct < m_vecTriangles.size(); ct++)
|
||||
{
|
||||
uint32_t v0 = m_vecTriangles[ct].v0;
|
||||
uint32_t v1 = m_vecTriangles[ct].v1;
|
||||
uint32_t v2 = m_vecTriangles[ct].v2;
|
||||
|
||||
bool allMatch =
|
||||
(m_pOutputMesh->m_vecVertices[v0].material - m_pOutputMesh->m_vecVertices[v1].material < 0.001f) &&
|
||||
(m_pOutputMesh->m_vecVertices[v1].material - m_pOutputMesh->m_vecVertices[v2].material < 0.001f);
|
||||
|
||||
if(!allMatch)
|
||||
{
|
||||
vecVertexMetadata[v0].isOnMaterialEdge = true;
|
||||
vecVertexMetadata[v1].isOnMaterialEdge = true;
|
||||
vecVertexMetadata[v2].isOnMaterialEdge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
POLYVOX_API bool MeshDecimator<PositionMaterialNormal>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
|
||||
{
|
||||
if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < m_fMinDotProductForCollapse)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//With the marching cubes surface we honour the user specified threshold
|
||||
return !collapseChangesFaceNormals(uSrc, uDst, m_fMinDotProductForCollapse);
|
||||
}
|
||||
|
||||
template<>
|
||||
POLYVOX_API bool MeshDecimator<PositionMaterial>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
|
||||
{
|
||||
//We don't actually use the normal here, because we want to allow face
|
||||
//vertices to collapse onto edge vertices. Simply checking whether anything
|
||||
//has flipped has proved to be the most robust approach, though rather slow.
|
||||
//It's not sufficient to just check the normals, there can be holes in the middle
|
||||
//of the mesh for example.
|
||||
|
||||
//User specified threshold is not used for cubic surface, any
|
||||
//movement is too much (but allow for floating point error).
|
||||
return !collapseChangesFaceNormals(uSrc, uDst, 0.999f);
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "PolyVoxCore/SimpleInterface.h"
|
||||
|
||||
//DOESN'T BELONG HERE - JUST FOR TESTING!!
|
||||
#include "PolyVoxCore/Density.h"
|
||||
#include "PolyVoxCore/MaterialDensityPair.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
void extractCubicMesh(Volume& volume, const Region& region, Mesh& resultMesh)
|
||||
{
|
||||
CubicSurfaceExtractorWithNormals< SimpleVolume<MaterialDensityPair88> > surfaceExtractor(&volume, region, &resultMesh);
|
||||
surfaceExtractor.execute();
|
||||
}
|
||||
|
||||
void extractSmoothMesh(Volume& volume, const Region& region, Mesh& resultMesh)
|
||||
{
|
||||
MarchingCubesSurfaceExtractor< SimpleVolume<MaterialDensityPair88> > surfaceExtractor(&volume, region, &resultMesh);
|
||||
surfaceExtractor.execute();
|
||||
}
|
||||
}
|
@ -31,10 +31,7 @@ SET(UTIL_SRC_FILES
|
||||
|
||||
#Projects headers files
|
||||
SET(UTIL_INC_FILES
|
||||
include/PolyVoxUtil/Serialization.h
|
||||
include/PolyVoxUtil/Serialization.inl
|
||||
include/PolyVoxUtil/VolumeChangeTracker.h
|
||||
include/PolyVoxUtil/VolumeChangeTracker.inl
|
||||
#Nothing here at the moment...
|
||||
)
|
||||
|
||||
ADD_DEFINITIONS(-DPOLYVOX_SHARED_EXPORTS) #Export symbols in the .dll
|
||||
|
1
library/PolyVoxUtil/include/PolyVoxUtil/Placeholder.txt
Normal file
1
library/PolyVoxUtil/include/PolyVoxUtil/Placeholder.txt
Normal file
@ -0,0 +1 @@
|
||||
I don't think Git allows empty directories, so this is just a placeholder until we decide what to do with PolyVoxUtil.
|
@ -1,77 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_Serialization_H__
|
||||
#define __PolyVox_Serialization_H__
|
||||
|
||||
#include "PolyVoxCore/Impl/Utility.h"
|
||||
|
||||
#include "PolyVoxCore/Region.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/// \deprecated
|
||||
class POLYVOX_DEPRECATED VolumeSerializationProgressListener
|
||||
{
|
||||
public:
|
||||
virtual void onProgressUpdated(float fProgress) = 0;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// THESE FUNCTIONS ARE DEPRECATED.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \deprecated
|
||||
template< typename VolumeType >
|
||||
POLYVOX_DEPRECATED polyvox_shared_ptr< VolumeType > loadVolumeRaw(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0);
|
||||
/// \deprecated
|
||||
template< typename VolumeType >
|
||||
POLYVOX_DEPRECATED void saveVolumeRaw(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
|
||||
|
||||
/// \deprecated
|
||||
template< typename VolumeType >
|
||||
POLYVOX_DEPRECATED polyvox_shared_ptr< VolumeType > loadVolumeRle(std::istream& stream, VolumeSerializationProgressListener* progressListener = 0);
|
||||
/// \deprecated
|
||||
template< typename VolumeType >
|
||||
POLYVOX_DEPRECATED void saveVolumeRle(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
|
||||
|
||||
/// \deprecated
|
||||
template< typename VolumeType >
|
||||
POLYVOX_DEPRECATED bool loadVolume(std::istream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
|
||||
/// \deprecated
|
||||
template< typename VolumeType >
|
||||
POLYVOX_DEPRECATED bool saveVolume(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
|
||||
|
||||
/// \deprecated
|
||||
template< typename VolumeType >
|
||||
POLYVOX_DEPRECATED bool loadVersion0(std::istream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
|
||||
/// \deprecated
|
||||
template< typename VolumeType >
|
||||
POLYVOX_DEPRECATED bool saveVersion0(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener = 0);
|
||||
}
|
||||
|
||||
#include "PolyVoxUtil/Serialization.inl"
|
||||
|
||||
#endif
|
@ -1,433 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
|
||||
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
|
||||
template< typename VolumeType >
|
||||
polyvox_shared_ptr< VolumeType > loadVolumeRaw(std::istream& stream, VolumeSerializationProgressListener* progressListener)
|
||||
{
|
||||
assert(false); //THIS FUNCTION IS DEPRECATED. REMOVE THIS ASSERT TO CONTINUE, BUT SWITCH TO 'loadVolume()' ASAP.
|
||||
|
||||
//Read volume dimensions
|
||||
uint8_t volumeWidthPower = 0;
|
||||
uint8_t volumeHeightPower = 0;
|
||||
uint8_t volumeDepthPower = 0;
|
||||
stream.read(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
|
||||
stream.read(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
|
||||
stream.read(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
|
||||
|
||||
uint16_t volumeWidth = 0x0001 << volumeWidthPower;
|
||||
uint16_t volumeHeight = 0x0001 << volumeHeightPower;
|
||||
uint16_t volumeDepth = 0x0001 << volumeDepthPower;
|
||||
|
||||
//FIXME - need to support non cubic volumes
|
||||
polyvox_shared_ptr< VolumeType > volume(new LargeVolume<VolumeType::VoxelType>(volumeWidth, volumeHeight, volumeDepth));
|
||||
|
||||
//Read data
|
||||
for(uint16_t z = 0; z < volumeDepth; ++z)
|
||||
{
|
||||
//Update progress once per slice.
|
||||
if(progressListener)
|
||||
{
|
||||
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
|
||||
progressListener->onProgressUpdated(fProgress);
|
||||
}
|
||||
|
||||
for(uint16_t y = 0; y < volumeHeight; ++y)
|
||||
{
|
||||
for(uint16_t x = 0; x < volumeWidth; ++x)
|
||||
{
|
||||
VolumeType::VoxelType value;
|
||||
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
|
||||
volume->setVoxelAt(x,y,z,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Finished
|
||||
if(progressListener)
|
||||
{
|
||||
progressListener->onProgressUpdated(1.0f);
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
template< typename VolumeType >
|
||||
void saveVolumeRaw(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
|
||||
{
|
||||
assert(false); //THIS FUNCTION IS DEPRECATED. REMOVE THIS ASSERT TO CONTINUE, BUT SWITCH TO 'saveVolume()' ASAP.
|
||||
|
||||
//Write volume dimensions
|
||||
uint16_t volumeWidth = volume.getWidth();
|
||||
uint16_t volumeHeight = volume.getHeight();
|
||||
uint16_t volumeDepth = volume.getDepth();
|
||||
|
||||
uint8_t volumeWidthPower = logBase2(volumeWidth);
|
||||
uint8_t volumeHeightPower = logBase2(volumeHeight);
|
||||
uint8_t volumeDepthPower = logBase2(volumeDepth);
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
|
||||
stream.write(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
|
||||
stream.write(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
|
||||
|
||||
//Write data
|
||||
VolumeType::Sampler volIter(&volume);
|
||||
for(uint16_t z = 0; z < volumeDepth; ++z)
|
||||
{
|
||||
//Update progress once per slice.
|
||||
if(progressListener)
|
||||
{
|
||||
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
|
||||
progressListener->onProgressUpdated(fProgress);
|
||||
}
|
||||
|
||||
for(uint16_t y = 0; y < volumeHeight; ++y)
|
||||
{
|
||||
for(uint16_t x = 0; x < volumeWidth; ++x)
|
||||
{
|
||||
volIter.setPosition(x,y,z);
|
||||
VolumeType::VoxelType value = volIter.getVoxel();
|
||||
stream.write(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Finished
|
||||
if(progressListener)
|
||||
{
|
||||
progressListener->onProgressUpdated(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
|
||||
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
|
||||
template< typename VolumeType >
|
||||
polyvox_shared_ptr< VolumeType > loadVolumeRle(std::istream& stream, VolumeSerializationProgressListener* progressListener)
|
||||
{
|
||||
assert(false); //THIS FUNCTION IS DEPRECATED. REMOVE THIS ASSERT TO CONTINUE, BUT SWITCH TO 'loadVolume()' ASAP.
|
||||
|
||||
//Read volume dimensions
|
||||
uint8_t volumeWidthPower = 0;
|
||||
uint8_t volumeHeightPower = 0;
|
||||
uint8_t volumeDepthPower = 0;
|
||||
stream.read(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
|
||||
stream.read(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
|
||||
stream.read(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
|
||||
|
||||
uint16_t volumeWidth = 0x0001 << volumeWidthPower;
|
||||
uint16_t volumeHeight = 0x0001 << volumeHeightPower;
|
||||
uint16_t volumeDepth = 0x0001 << volumeDepthPower;
|
||||
|
||||
//FIXME - need to support non cubic volumes
|
||||
polyvox_shared_ptr< VolumeType > volume(new LargeVolume<VolumeType::VoxelType>(volumeWidth, volumeHeight, volumeDepth));
|
||||
|
||||
//Read data
|
||||
bool firstTime = true;
|
||||
uint32_t runLength = 0;
|
||||
VolumeType::VoxelType value;
|
||||
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
|
||||
for(uint16_t z = 0; z < volumeDepth; ++z)
|
||||
{
|
||||
//Update progress once per slice.
|
||||
if(progressListener)
|
||||
{
|
||||
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
|
||||
progressListener->onProgressUpdated(fProgress);
|
||||
}
|
||||
|
||||
for(uint16_t y = 0; y < volumeHeight; ++y)
|
||||
{
|
||||
for(uint16_t x = 0; x < volumeWidth; ++x)
|
||||
{
|
||||
if(runLength != 0)
|
||||
{
|
||||
volume->setVoxelAt(x,y,z,value);
|
||||
runLength--;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
|
||||
|
||||
volume->setVoxelAt(x,y,z,value);
|
||||
runLength--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Finished
|
||||
if(progressListener)
|
||||
{
|
||||
progressListener->onProgressUpdated(1.0f);
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
template< typename VolumeType >
|
||||
void saveVolumeRle(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
|
||||
{
|
||||
assert(false); //THIS FUNCTION IS DEPRECATED. REMOVE THIS ASSERT TO CONTINUE, BUT SWITCH TO 'saveVolume()' ASAP.
|
||||
|
||||
//Write volume dimensions
|
||||
uint16_t volumeWidth = volume.getWidth();
|
||||
uint16_t volumeHeight = volume.getHeight();
|
||||
uint16_t volumeDepth = volume.getDepth();
|
||||
|
||||
uint8_t volumeWidthPower = logBase2(volumeWidth);
|
||||
uint8_t volumeHeightPower = logBase2(volumeHeight);
|
||||
uint8_t volumeDepthPower = logBase2(volumeDepth);
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&volumeWidthPower), sizeof(volumeWidthPower));
|
||||
stream.write(reinterpret_cast<char*>(&volumeHeightPower), sizeof(volumeHeightPower));
|
||||
stream.write(reinterpret_cast<char*>(&volumeDepthPower), sizeof(volumeDepthPower));
|
||||
|
||||
//Write data
|
||||
VolumeType::Sampler volIter(&volume);
|
||||
VolumeType::VoxelType current;
|
||||
uint32_t runLength = 0;
|
||||
bool firstTime = true;
|
||||
for(uint16_t z = 0; z < volumeDepth; ++z)
|
||||
{
|
||||
//Update progress once per slice.
|
||||
if(progressListener)
|
||||
{
|
||||
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
|
||||
progressListener->onProgressUpdated(fProgress);
|
||||
}
|
||||
|
||||
for(uint16_t y = 0; y < volumeHeight; ++y)
|
||||
{
|
||||
for(uint16_t x = 0; x < volumeWidth; ++x)
|
||||
{
|
||||
volIter.setPosition(x,y,z);
|
||||
VolumeType::VoxelType value = volIter.getVoxel();
|
||||
if(firstTime)
|
||||
{
|
||||
current = value;
|
||||
runLength = 1;
|
||||
firstTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(value == current)
|
||||
{
|
||||
runLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.write(reinterpret_cast<char*>(¤t), sizeof(current));
|
||||
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
|
||||
current = value;
|
||||
runLength = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.write(reinterpret_cast<char*>(¤t), sizeof(current));
|
||||
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
|
||||
|
||||
//Finished
|
||||
if(progressListener)
|
||||
{
|
||||
progressListener->onProgressUpdated(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// New version of load/save code with versioning
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template< typename VolumeType >
|
||||
bool loadVolume(std::istream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
|
||||
{
|
||||
char pIdentifier[8];
|
||||
stream.read(pIdentifier, 7);
|
||||
pIdentifier[7] = '\0'; //Set the null terminator
|
||||
if(strcmp(pIdentifier, "PolyVox") != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t uVersion;
|
||||
stream.read(reinterpret_cast<char*>(&uVersion), sizeof(uVersion));
|
||||
|
||||
switch(uVersion)
|
||||
{
|
||||
case 0:
|
||||
return loadVersion0(stream, volume, progressListener);
|
||||
//Return means no need to break...
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template< typename VolumeType >
|
||||
bool saveVolume(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
|
||||
{
|
||||
char pIdentifier[] = "PolyVox";
|
||||
stream.write(pIdentifier, 7);
|
||||
|
||||
uint16_t uVersion = 0;
|
||||
stream.write(reinterpret_cast<const char*>(&uVersion), sizeof(uVersion));
|
||||
|
||||
return saveVersion0(stream, volume, progressListener);
|
||||
}
|
||||
|
||||
//Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller.
|
||||
//FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow
|
||||
template< typename VolumeType >
|
||||
bool loadVersion0(std::istream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
|
||||
{
|
||||
//Read volume dimensions
|
||||
uint16_t volumeWidth = 0;
|
||||
uint16_t volumeHeight = 0;
|
||||
uint16_t volumeDepth = 0;
|
||||
stream.read(reinterpret_cast<char*>(&volumeWidth), sizeof(volumeWidth));
|
||||
stream.read(reinterpret_cast<char*>(&volumeHeight), sizeof(volumeHeight));
|
||||
stream.read(reinterpret_cast<char*>(&volumeDepth), sizeof(volumeDepth));
|
||||
|
||||
//Resize the volume
|
||||
//HACK - Forces block size to 32. This functions needs reworking anyway due to large volume support.
|
||||
volume.resize(Region(Vector3DInt32(0,0,0), Vector3DInt32(volumeWidth-1, volumeHeight-1, volumeDepth-1)), 32);
|
||||
|
||||
//Read data
|
||||
bool firstTime = true;
|
||||
uint32_t runLength = 0;
|
||||
VolumeType::VoxelType value;
|
||||
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
|
||||
for(uint16_t z = 0; z < volumeDepth; ++z)
|
||||
{
|
||||
//Update progress once per slice.
|
||||
if(progressListener)
|
||||
{
|
||||
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
|
||||
progressListener->onProgressUpdated(fProgress);
|
||||
}
|
||||
|
||||
for(uint16_t y = 0; y < volumeHeight; ++y)
|
||||
{
|
||||
for(uint16_t x = 0; x < volumeWidth; ++x)
|
||||
{
|
||||
if(runLength != 0)
|
||||
{
|
||||
volume.setVoxelAt(x,y,z,value);
|
||||
runLength--;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
stream.read(reinterpret_cast<char*>(&runLength), sizeof(runLength));
|
||||
|
||||
volume.setVoxelAt(x,y,z,value);
|
||||
runLength--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Finished
|
||||
if(progressListener)
|
||||
{
|
||||
progressListener->onProgressUpdated(1.0f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template< typename VolumeType >
|
||||
bool saveVersion0(std::ostream& stream, VolumeType& volume, VolumeSerializationProgressListener* progressListener)
|
||||
{
|
||||
//Write volume dimensions
|
||||
uint16_t volumeWidth = volume.getWidth();
|
||||
uint16_t volumeHeight = volume.getHeight();
|
||||
uint16_t volumeDepth = volume.getDepth();
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&volumeWidth), sizeof(volumeWidth));
|
||||
stream.write(reinterpret_cast<char*>(&volumeHeight), sizeof(volumeHeight));
|
||||
stream.write(reinterpret_cast<char*>(&volumeDepth), sizeof(volumeDepth));
|
||||
|
||||
//Write data
|
||||
VolumeType::Sampler volIter(&volume);
|
||||
VolumeType::VoxelType current;
|
||||
uint32_t runLength = 0;
|
||||
bool firstTime = true;
|
||||
for(uint16_t z = 0; z < volumeDepth; ++z)
|
||||
{
|
||||
//Update progress once per slice.
|
||||
if(progressListener)
|
||||
{
|
||||
float fProgress = static_cast<float>(z) / static_cast<float>(volumeDepth);
|
||||
progressListener->onProgressUpdated(fProgress);
|
||||
}
|
||||
|
||||
for(uint16_t y = 0; y < volumeHeight; ++y)
|
||||
{
|
||||
for(uint16_t x = 0; x < volumeWidth; ++x)
|
||||
{
|
||||
volIter.setPosition(x,y,z);
|
||||
VolumeType::VoxelType value = volIter.getVoxel();
|
||||
if(firstTime)
|
||||
{
|
||||
current = value;
|
||||
runLength = 1;
|
||||
firstTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(value == current)
|
||||
{
|
||||
runLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.write(reinterpret_cast<char*>(¤t), sizeof(current));
|
||||
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
|
||||
current = value;
|
||||
runLength = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.write(reinterpret_cast<char*>(¤t), sizeof(current));
|
||||
stream.write(reinterpret_cast<char*>(&runLength), sizeof(runLength));
|
||||
|
||||
//Finished
|
||||
if(progressListener)
|
||||
{
|
||||
progressListener->onProgressUpdated(1.0f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __PolyVox_VolumeChangeTracker_H__
|
||||
#define __PolyVox_VolumeChangeTracker_H__
|
||||
|
||||
#include "Impl/Utility.h"
|
||||
|
||||
#include "PolyVoxCore/Region.h"
|
||||
#include "PolyVoxCore/SurfaceMesh.h"
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
/// Voxel scene manager
|
||||
/// \deprecated
|
||||
template <typename VoxelType>
|
||||
class POLYVOX_DEPRECATED VolumeChangeTracker
|
||||
{
|
||||
public:
|
||||
//Constructors, etc
|
||||
VolumeChangeTracker(LargeVolume<VoxelType>* volumeDataToSet, uint16_t regionSideLength);
|
||||
~VolumeChangeTracker();
|
||||
|
||||
//Getters
|
||||
int32_t getCurrentTime(void) const;
|
||||
int32_t getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ);
|
||||
LargeVolume<VoxelType>* getWrappedVolume(void) const;
|
||||
|
||||
//Setters
|
||||
void setAllRegionsModified(void);
|
||||
void setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value);
|
||||
void setVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value);
|
||||
|
||||
//Others
|
||||
void lockRegion(const Region& regToLock);
|
||||
void unlockRegion(void);
|
||||
//void markRegionChanged(uint16_t firstX, uint16_t firstY, uint16_t firstZ, uint16_t lastX, uint16_t lastY, uint16_t lastZ);
|
||||
|
||||
public:
|
||||
void incrementCurrentTime(void);
|
||||
bool m_bIsLocked;
|
||||
Region m_regLastLocked;
|
||||
LargeVolume<VoxelType>* volumeData;
|
||||
|
||||
uint16_t m_uRegionSideLength;
|
||||
uint8_t m_uRegionSideLengthPower;
|
||||
uint16_t m_uVolumeWidthInRegions;
|
||||
uint16_t m_uVolumeHeightInRegions;
|
||||
uint16_t m_uVolumeDepthInRegions;
|
||||
|
||||
|
||||
//It's not what the block class was designed for, but it
|
||||
//provides a handy way of storing a 3D grid of values.
|
||||
LargeVolume<int32_t>* volRegionLastModified;
|
||||
|
||||
static uint32_t m_uCurrentTime;
|
||||
};
|
||||
}
|
||||
|
||||
#include "PolyVoxUtil/VolumeChangeTracker.inl"
|
||||
|
||||
#endif
|
@ -1,212 +0,0 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2005-2009 David Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
namespace PolyVox
|
||||
{
|
||||
template <typename VoxelType>
|
||||
uint32_t VolumeChangeTracker<VoxelType>::m_uCurrentTime = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// VolumeChangeTracker
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
template <typename VoxelType>
|
||||
VolumeChangeTracker<VoxelType>::VolumeChangeTracker(LargeVolume<VoxelType>* volumeDataToSet, uint16_t regionSideLength)
|
||||
:m_bIsLocked(false)
|
||||
,volumeData(0)
|
||||
,m_uRegionSideLength(regionSideLength)
|
||||
{
|
||||
volumeData = volumeDataToSet;
|
||||
m_uVolumeWidthInRegions = volumeData->getWidth() / m_uRegionSideLength;
|
||||
m_uVolumeHeightInRegions = volumeData->getHeight() / m_uRegionSideLength;
|
||||
m_uVolumeDepthInRegions = volumeData->getDepth() / m_uRegionSideLength;
|
||||
m_uRegionSideLengthPower = PolyVox::logBase2(m_uRegionSideLength);
|
||||
|
||||
volRegionLastModified = new LargeVolume<int32_t>(m_uVolumeWidthInRegions, m_uVolumeHeightInRegions, m_uVolumeDepthInRegions, 0);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
VolumeChangeTracker<VoxelType>::~VolumeChangeTracker()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void VolumeChangeTracker<VoxelType>::setAllRegionsModified(void)
|
||||
{
|
||||
incrementCurrentTime();
|
||||
for(uint16_t blockZ = 0; blockZ < m_uVolumeDepthInRegions; ++blockZ)
|
||||
{
|
||||
for(uint16_t blockY = 0; blockY < m_uVolumeHeightInRegions; ++blockY)
|
||||
{
|
||||
for(uint16_t blockX = 0; blockX < m_uVolumeWidthInRegions; ++blockX)
|
||||
{
|
||||
volRegionLastModified->setVoxelAt(blockX, blockY, blockZ, m_uCurrentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
int32_t VolumeChangeTracker<VoxelType>::getCurrentTime(void) const
|
||||
{
|
||||
return m_uCurrentTime;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
int32_t VolumeChangeTracker<VoxelType>::getLastModifiedTimeForRegion(uint16_t uX, uint16_t uY, uint16_t uZ)
|
||||
{
|
||||
return volRegionLastModified->getVoxelAt(uX, uY, uZ);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
LargeVolume<VoxelType>* VolumeChangeTracker<VoxelType>::getWrappedVolume(void) const
|
||||
{
|
||||
return volumeData;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void VolumeChangeTracker<VoxelType>::setVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value)
|
||||
{
|
||||
//Note: We increase the time stamp both at the start and the end
|
||||
//to avoid ambiguity about whether the timestamp comparison should
|
||||
//be '<' vs '<=' or '>' vs '>=' in the users code.
|
||||
incrementCurrentTime();
|
||||
|
||||
volumeData->setVoxelAt(x,y,z,value);
|
||||
|
||||
//If we are not on a boundary, just mark one region.
|
||||
if((x % m_uRegionSideLength != 0) &&
|
||||
(x % m_uRegionSideLength != m_uRegionSideLength-1) &&
|
||||
(y % m_uRegionSideLength != 0) &&
|
||||
(y % m_uRegionSideLength != m_uRegionSideLength-1) &&
|
||||
(z % m_uRegionSideLength != 0) &&
|
||||
(z % m_uRegionSideLength != m_uRegionSideLength-1))
|
||||
{
|
||||
volRegionLastModified->setVoxelAt(x >> m_uRegionSideLengthPower, y >> m_uRegionSideLengthPower, z >> m_uRegionSideLengthPower, m_uCurrentTime);
|
||||
}
|
||||
else //Mark surrounding regions as well
|
||||
{
|
||||
const uint16_t regionX = x >> m_uRegionSideLengthPower;
|
||||
const uint16_t regionY = y >> m_uRegionSideLengthPower;
|
||||
const uint16_t regionZ = z >> m_uRegionSideLengthPower;
|
||||
|
||||
const uint16_t minRegionX = (std::max)(uint16_t(0),uint16_t(regionX-1));
|
||||
const uint16_t minRegionY = (std::max)(uint16_t(0),uint16_t(regionY-1));
|
||||
const uint16_t minRegionZ = (std::max)(uint16_t(0),uint16_t(regionZ-1));
|
||||
|
||||
const uint16_t maxRegionX = (std::min)(uint16_t(m_uVolumeWidthInRegions-1),uint16_t(regionX+1));
|
||||
const uint16_t maxRegionY = (std::min)(uint16_t(m_uVolumeHeightInRegions-1),uint16_t(regionY+1));
|
||||
const uint16_t maxRegionZ = (std::min)(uint16_t(m_uVolumeDepthInRegions-1),uint16_t(regionZ+1));
|
||||
|
||||
for(uint16_t zCt = minRegionZ; zCt <= maxRegionZ; zCt++)
|
||||
{
|
||||
for(uint16_t yCt = minRegionY; yCt <= maxRegionY; yCt++)
|
||||
{
|
||||
for(uint16_t xCt = minRegionX; xCt <= maxRegionX; xCt++)
|
||||
{
|
||||
volRegionLastModified->setVoxelAt(xCt,yCt,zCt,m_uCurrentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Increment time stamp. See earlier note.
|
||||
incrementCurrentTime();
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void VolumeChangeTracker<VoxelType>::setLockedVoxelAt(uint16_t x, uint16_t y, uint16_t z, VoxelType value)
|
||||
{
|
||||
assert(m_bIsLocked);
|
||||
|
||||
//FIXME - rather than creating a iterator each time we should have one stored
|
||||
/*Sampler<VoxelType> iterVol(*volumeData);
|
||||
iterVol.setPosition(x,y,z);
|
||||
iterVol.setVoxel(value);*/
|
||||
volumeData->setVoxelAt(x,y,z,value);
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void VolumeChangeTracker<VoxelType>::lockRegion(const Region& regToLock)
|
||||
{
|
||||
if(m_bIsLocked)
|
||||
{
|
||||
throw std::logic_error("A region is already locked. Please unlock it before locking another.");
|
||||
}
|
||||
|
||||
m_regLastLocked = regToLock;
|
||||
m_bIsLocked = true;
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void VolumeChangeTracker<VoxelType>::unlockRegion(void)
|
||||
{
|
||||
if(!m_bIsLocked)
|
||||
{
|
||||
throw std::logic_error("No region is locked. You must lock a region before you can unlock it.");
|
||||
}
|
||||
|
||||
//Note: We increase the time stamp both at the start and the end
|
||||
//to avoid ambiguity about whether the timestamp comparison should
|
||||
//be '<' vs '<=' or '>' vs '>=' in the users code.
|
||||
incrementCurrentTime();
|
||||
|
||||
const uint16_t firstRegionX = m_regLastLocked.getLowerCorner().getX() >> m_uRegionSideLengthPower;
|
||||
const uint16_t firstRegionY = m_regLastLocked.getLowerCorner().getY() >> m_uRegionSideLengthPower;
|
||||
const uint16_t firstRegionZ = m_regLastLocked.getLowerCorner().getZ() >> m_uRegionSideLengthPower;
|
||||
|
||||
const uint16_t lastRegionX = m_regLastLocked.getUpperCorner().getX() >> m_uRegionSideLengthPower;
|
||||
const uint16_t lastRegionY = m_regLastLocked.getUpperCorner().getY() >> m_uRegionSideLengthPower;
|
||||
const uint16_t lastRegionZ = m_regLastLocked.getUpperCorner().getZ() >> m_uRegionSideLengthPower;
|
||||
|
||||
for(uint16_t zCt = firstRegionZ; zCt <= lastRegionZ; zCt++)
|
||||
{
|
||||
for(uint16_t yCt = firstRegionY; yCt <= lastRegionY; yCt++)
|
||||
{
|
||||
for(uint16_t xCt = firstRegionX; xCt <= lastRegionX; xCt++)
|
||||
{
|
||||
volRegionLastModified->setVoxelAt(xCt,yCt,zCt,m_uCurrentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_bIsLocked = false;
|
||||
|
||||
//Increment time stamp. See earlier note.
|
||||
incrementCurrentTime();
|
||||
}
|
||||
|
||||
template <typename VoxelType>
|
||||
void VolumeChangeTracker<VoxelType>::incrementCurrentTime(void)
|
||||
{
|
||||
//Increment the current time.
|
||||
uint32_t time = m_uCurrentTime++;
|
||||
|
||||
//Watch out for wraparound. Hopefully this will never happen
|
||||
//as we have a pretty big counter, but it's best to be sure...
|
||||
assert(time < m_uCurrentTime);
|
||||
if(time >= m_uCurrentTime)
|
||||
{
|
||||
throw std::overflow_error("The VolumeChangeTracker time has overflowed.");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user