Normalized line endings
This commit is contained in:
@ -1,139 +1,139 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2011 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 "TestAStarPathfinder.h"
|
||||
|
||||
#include "PolyVoxCore/AStarPathfinder.h"
|
||||
#include "PolyVoxCore/Material.h"
|
||||
#include "PolyVoxCore/RawVolume.h"
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
template< typename VolumeType>
|
||||
bool testVoxelValidator(const VolumeType* volData, const Vector3DInt32& v3dPos)
|
||||
{
|
||||
//Voxels are considered valid candidates for the path if they are inside the volume...
|
||||
if(volData->getEnclosingRegion().containsPoint(v3dPos) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
typename VolumeType::VoxelType voxel = volData->getVoxel(v3dPos, WrapModes::Validate); // FIXME use templatised version of getVoxel(), but watch out for Linux compile issues.
|
||||
if(voxel != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestAStarPathfinder::testExecute()
|
||||
{
|
||||
const Vector3DInt32 expectedResult[] =
|
||||
{
|
||||
Vector3DInt32(0,0,0),
|
||||
Vector3DInt32(1,1,1),
|
||||
Vector3DInt32(2,1,2),
|
||||
Vector3DInt32(3,1,3),
|
||||
Vector3DInt32(3,1,4),
|
||||
Vector3DInt32(3,1,5),
|
||||
Vector3DInt32(3,1,6),
|
||||
Vector3DInt32(3,1,7),
|
||||
Vector3DInt32(4,2,8),
|
||||
Vector3DInt32(5,3,9),
|
||||
Vector3DInt32(5,3,10),
|
||||
Vector3DInt32(5,3,11),
|
||||
Vector3DInt32(6,4,12),
|
||||
Vector3DInt32(7,5,13),
|
||||
Vector3DInt32(8,6,13),
|
||||
Vector3DInt32(9,7,13),
|
||||
Vector3DInt32(9,8,13),
|
||||
Vector3DInt32(10,9,13),
|
||||
Vector3DInt32(11,10,14),
|
||||
Vector3DInt32(12,11,15),
|
||||
Vector3DInt32(13,12,15),
|
||||
Vector3DInt32(14,13,15),
|
||||
Vector3DInt32(14,14,15),
|
||||
Vector3DInt32(15,15,15)
|
||||
};
|
||||
|
||||
const int32_t uVolumeSideLength = 16;
|
||||
|
||||
//Create a volume
|
||||
RawVolume<uint8_t> volData(Region(Vector3DInt32(0,0,0), Vector3DInt32(uVolumeSideLength-1, uVolumeSideLength-1, uVolumeSideLength-1)));
|
||||
|
||||
//Clear the volume
|
||||
for(int z = 0; z < uVolumeSideLength; z++)
|
||||
{
|
||||
for(int y = 0; y < uVolumeSideLength; y++)
|
||||
{
|
||||
for(int x = 0; x < uVolumeSideLength; x++)
|
||||
{
|
||||
uint8_t solidVoxel(0);
|
||||
volData.setVoxelAt(x,y,z,solidVoxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Place a solid cube in the middle of it
|
||||
for(int z = 4; z < 12; z++)
|
||||
{
|
||||
for(int y = 4; y < 12; y++)
|
||||
{
|
||||
for(int x = 4; x < 12; x++)
|
||||
{
|
||||
uint8_t solidVoxel(1);
|
||||
volData.setVoxelAt(x,y,z,solidVoxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//List to store the resulting path
|
||||
std::list<Vector3DInt32> result;
|
||||
|
||||
//Create an AStarPathfinder
|
||||
AStarPathfinderParams< RawVolume<uint8_t> > params(&volData, Vector3DInt32(0,0,0), Vector3DInt32(15,15,15), &result, 1.0f, 10000, TwentySixConnected, &testVoxelValidator<RawVolume<uint8_t> >);
|
||||
AStarPathfinder< RawVolume<uint8_t> > pathfinder(params);
|
||||
|
||||
//Execute the pathfinder.
|
||||
QBENCHMARK {
|
||||
pathfinder.execute();
|
||||
}
|
||||
|
||||
//Make sure the right number of steps were created.
|
||||
QCOMPARE(result.size(), static_cast<size_t>(24));
|
||||
|
||||
//Make sure that each step is correct.
|
||||
uint32_t uExpectedIndex = 0;
|
||||
for(std::list<Vector3DInt32>::iterator iterResult = result.begin(); iterResult != result.end(); iterResult++)
|
||||
{
|
||||
Vector3DInt32 res = *iterResult;
|
||||
Vector3DInt32 exp = expectedResult[uExpectedIndex];
|
||||
QCOMPARE(res, exp);
|
||||
uExpectedIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestAStarPathfinder)
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2011 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 "TestAStarPathfinder.h"
|
||||
|
||||
#include "PolyVoxCore/AStarPathfinder.h"
|
||||
#include "PolyVoxCore/Material.h"
|
||||
#include "PolyVoxCore/RawVolume.h"
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
template< typename VolumeType>
|
||||
bool testVoxelValidator(const VolumeType* volData, const Vector3DInt32& v3dPos)
|
||||
{
|
||||
//Voxels are considered valid candidates for the path if they are inside the volume...
|
||||
if(volData->getEnclosingRegion().containsPoint(v3dPos) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
typename VolumeType::VoxelType voxel = volData->getVoxel(v3dPos, WrapModes::Validate); // FIXME use templatised version of getVoxel(), but watch out for Linux compile issues.
|
||||
if(voxel != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestAStarPathfinder::testExecute()
|
||||
{
|
||||
const Vector3DInt32 expectedResult[] =
|
||||
{
|
||||
Vector3DInt32(0,0,0),
|
||||
Vector3DInt32(1,1,1),
|
||||
Vector3DInt32(2,1,2),
|
||||
Vector3DInt32(3,1,3),
|
||||
Vector3DInt32(3,1,4),
|
||||
Vector3DInt32(3,1,5),
|
||||
Vector3DInt32(3,1,6),
|
||||
Vector3DInt32(3,1,7),
|
||||
Vector3DInt32(4,2,8),
|
||||
Vector3DInt32(5,3,9),
|
||||
Vector3DInt32(5,3,10),
|
||||
Vector3DInt32(5,3,11),
|
||||
Vector3DInt32(6,4,12),
|
||||
Vector3DInt32(7,5,13),
|
||||
Vector3DInt32(8,6,13),
|
||||
Vector3DInt32(9,7,13),
|
||||
Vector3DInt32(9,8,13),
|
||||
Vector3DInt32(10,9,13),
|
||||
Vector3DInt32(11,10,14),
|
||||
Vector3DInt32(12,11,15),
|
||||
Vector3DInt32(13,12,15),
|
||||
Vector3DInt32(14,13,15),
|
||||
Vector3DInt32(14,14,15),
|
||||
Vector3DInt32(15,15,15)
|
||||
};
|
||||
|
||||
const int32_t uVolumeSideLength = 16;
|
||||
|
||||
//Create a volume
|
||||
RawVolume<uint8_t> volData(Region(Vector3DInt32(0,0,0), Vector3DInt32(uVolumeSideLength-1, uVolumeSideLength-1, uVolumeSideLength-1)));
|
||||
|
||||
//Clear the volume
|
||||
for(int z = 0; z < uVolumeSideLength; z++)
|
||||
{
|
||||
for(int y = 0; y < uVolumeSideLength; y++)
|
||||
{
|
||||
for(int x = 0; x < uVolumeSideLength; x++)
|
||||
{
|
||||
uint8_t solidVoxel(0);
|
||||
volData.setVoxelAt(x,y,z,solidVoxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Place a solid cube in the middle of it
|
||||
for(int z = 4; z < 12; z++)
|
||||
{
|
||||
for(int y = 4; y < 12; y++)
|
||||
{
|
||||
for(int x = 4; x < 12; x++)
|
||||
{
|
||||
uint8_t solidVoxel(1);
|
||||
volData.setVoxelAt(x,y,z,solidVoxel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//List to store the resulting path
|
||||
std::list<Vector3DInt32> result;
|
||||
|
||||
//Create an AStarPathfinder
|
||||
AStarPathfinderParams< RawVolume<uint8_t> > params(&volData, Vector3DInt32(0,0,0), Vector3DInt32(15,15,15), &result, 1.0f, 10000, TwentySixConnected, &testVoxelValidator<RawVolume<uint8_t> >);
|
||||
AStarPathfinder< RawVolume<uint8_t> > pathfinder(params);
|
||||
|
||||
//Execute the pathfinder.
|
||||
QBENCHMARK {
|
||||
pathfinder.execute();
|
||||
}
|
||||
|
||||
//Make sure the right number of steps were created.
|
||||
QCOMPARE(result.size(), static_cast<size_t>(24));
|
||||
|
||||
//Make sure that each step is correct.
|
||||
uint32_t uExpectedIndex = 0;
|
||||
for(std::list<Vector3DInt32>::iterator iterResult = result.begin(); iterResult != result.end(); iterResult++)
|
||||
{
|
||||
Vector3DInt32 res = *iterResult;
|
||||
Vector3DInt32 exp = expectedResult[uExpectedIndex];
|
||||
QCOMPARE(res, exp);
|
||||
uExpectedIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestAStarPathfinder)
|
||||
|
@ -1,127 +1,127 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2010 Matt Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "TestArray.h"
|
||||
|
||||
#include "PolyVoxCore/Array.h"
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
void TestArray::testCArraySpeed()
|
||||
{
|
||||
const int width = 64;
|
||||
const int height = 32;
|
||||
const int depth = 16;
|
||||
|
||||
int cArray[width][height][depth];
|
||||
|
||||
QBENCHMARK
|
||||
{
|
||||
int ct = 1;
|
||||
int expectedTotal = 0;
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
cArray[x][y][z] = ct;
|
||||
expectedTotal += cArray[x][y][z];
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestArray::testPolyVoxArraySpeed()
|
||||
{
|
||||
const int width = 64;
|
||||
const int height = 32;
|
||||
const int depth = 16;
|
||||
|
||||
Array<3, int> polyvoxArray(width, height, depth);
|
||||
|
||||
QBENCHMARK
|
||||
{
|
||||
int ct = 1;
|
||||
int expectedTotal = 0;
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
polyvoxArray(x, y, z) = ct;
|
||||
expectedTotal += polyvoxArray(x, y, z);
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestArray::testReadWrite()
|
||||
{
|
||||
int width = 5;
|
||||
int height = 10;
|
||||
int depth = 20;
|
||||
|
||||
Array<3, int> myArray(width, height, depth);
|
||||
|
||||
int ct = 1;
|
||||
int expectedTotal = 0;
|
||||
for(int z = 0; z < depth; z++)
|
||||
{
|
||||
for(int y = 0; y < height; y++)
|
||||
{
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
myArray(x, y, z) = ct;
|
||||
expectedTotal += myArray(x, y, z);
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ct = 1;
|
||||
int total = 0;
|
||||
for(int z = 0; z < depth; z++)
|
||||
{
|
||||
for(int y = 0; y < height; y++)
|
||||
{
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
QCOMPARE(myArray(x, y, z), ct);
|
||||
total += myArray(x, y, z);
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QCOMPARE(total, expectedTotal);
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestArray)
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2010 Matt Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "TestArray.h"
|
||||
|
||||
#include "PolyVoxCore/Array.h"
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
void TestArray::testCArraySpeed()
|
||||
{
|
||||
const int width = 64;
|
||||
const int height = 32;
|
||||
const int depth = 16;
|
||||
|
||||
int cArray[width][height][depth];
|
||||
|
||||
QBENCHMARK
|
||||
{
|
||||
int ct = 1;
|
||||
int expectedTotal = 0;
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
cArray[x][y][z] = ct;
|
||||
expectedTotal += cArray[x][y][z];
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestArray::testPolyVoxArraySpeed()
|
||||
{
|
||||
const int width = 64;
|
||||
const int height = 32;
|
||||
const int depth = 16;
|
||||
|
||||
Array<3, int> polyvoxArray(width, height, depth);
|
||||
|
||||
QBENCHMARK
|
||||
{
|
||||
int ct = 1;
|
||||
int expectedTotal = 0;
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
polyvoxArray(x, y, z) = ct;
|
||||
expectedTotal += polyvoxArray(x, y, z);
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestArray::testReadWrite()
|
||||
{
|
||||
int width = 5;
|
||||
int height = 10;
|
||||
int depth = 20;
|
||||
|
||||
Array<3, int> myArray(width, height, depth);
|
||||
|
||||
int ct = 1;
|
||||
int expectedTotal = 0;
|
||||
for(int z = 0; z < depth; z++)
|
||||
{
|
||||
for(int y = 0; y < height; y++)
|
||||
{
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
myArray(x, y, z) = ct;
|
||||
expectedTotal += myArray(x, y, z);
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ct = 1;
|
||||
int total = 0;
|
||||
for(int z = 0; z < depth; z++)
|
||||
{
|
||||
for(int y = 0; y < height; y++)
|
||||
{
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
QCOMPARE(myArray(x, y, z), ct);
|
||||
total += myArray(x, y, z);
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QCOMPARE(total, expectedTotal);
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestArray)
|
||||
|
@ -34,26 +34,26 @@ freely, subject to the following restrictions:
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
template<typename _VoxelType>
|
||||
class CustomIsQuadNeeded
|
||||
{
|
||||
template<typename _VoxelType>
|
||||
class CustomIsQuadNeeded
|
||||
{
|
||||
public:
|
||||
typedef _VoxelType VoxelType;
|
||||
|
||||
bool operator()(VoxelType back, VoxelType front, VoxelType& materialToUse)
|
||||
{
|
||||
// Not a useful test - it just does something different
|
||||
// to the DefaultIsQuadNeeded so we can check it compiles.
|
||||
if ((back > 1) && (front <= 1))
|
||||
{
|
||||
bool operator()(VoxelType back, VoxelType front, VoxelType& materialToUse)
|
||||
{
|
||||
// Not a useful test - it just does something different
|
||||
// to the DefaultIsQuadNeeded so we can check it compiles.
|
||||
if ((back > 1) && (front <= 1))
|
||||
{
|
||||
materialToUse = static_cast<VoxelType>(back);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Runs the surface extractor for a given type.
|
||||
|
@ -1,236 +1,236 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2010 Matt Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "TestSurfaceExtractor.h"
|
||||
|
||||
#include "PolyVoxCore/Density.h"
|
||||
#include "PolyVoxCore/FilePager.h"
|
||||
#include "PolyVoxCore/MaterialDensityPair.h"
|
||||
#include "PolyVoxCore/RawVolume.h"
|
||||
#include "PolyVoxCore/PagedVolume.h"
|
||||
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
// Test our ability to modify the behaviour of the MarchingCubesSurfaceExtractor. This simple example only modifies
|
||||
// the threshold (and actually this can be achieved by passing a parameter to the constructor of the
|
||||
// DefaultMarchingCubesController) but you could implement custom behaviour in the other members
|
||||
// if you wanted too. Actually, it's not clear if this ability is really useful because I can't think
|
||||
// what you'd modify apart from the threshold but the ability is at least available. Also, the
|
||||
// DefaultMarchingCubesController is templatised whereas this exmple shows that controllers don't
|
||||
// have to be.
|
||||
class CustomMarchingCubesController
|
||||
{
|
||||
public:
|
||||
typedef float DensityType;
|
||||
typedef float MaterialType;
|
||||
|
||||
float convertToDensity(float voxel)
|
||||
{
|
||||
return voxel;
|
||||
}
|
||||
|
||||
float convertToMaterial(float /*voxel*/)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float blendMaterials(float /*a*/, float /*b*/, float /*weight*/)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float getThreshold(void)
|
||||
{
|
||||
return 50.0f;
|
||||
}
|
||||
};
|
||||
|
||||
// These 'writeDensityValueToVoxel' functions provide a unified interface for writting densities to primative and class voxel types.
|
||||
// They are conceptually the inverse of the 'convertToDensity' function used by the MarchingCubesSurfaceExtractor. They probably shouldn't be part
|
||||
// of PolyVox, but they might be usful to other tests so we cold move them into a 'Tests.h' or something in the future.
|
||||
template<typename VoxelType>
|
||||
void writeDensityValueToVoxel(int valueToWrite, VoxelType& voxel)
|
||||
{
|
||||
voxel = valueToWrite;
|
||||
}
|
||||
|
||||
template<>
|
||||
void writeDensityValueToVoxel(int valueToWrite, MaterialDensityPair88& voxel)
|
||||
{
|
||||
voxel.setDensity(valueToWrite);
|
||||
}
|
||||
|
||||
template<typename VoxelType>
|
||||
void writeMaterialValueToVoxel(int /*valueToWrite*/, VoxelType& /*voxel*/)
|
||||
{
|
||||
//Most types don't have a material
|
||||
return;
|
||||
}
|
||||
|
||||
template<>
|
||||
void writeMaterialValueToVoxel(int valueToWrite, MaterialDensityPair88& voxel)
|
||||
{
|
||||
voxel.setMaterial(valueToWrite);
|
||||
}
|
||||
|
||||
template <typename VolumeType>
|
||||
VolumeType* createAndFillVolume(void)
|
||||
{
|
||||
const int32_t uVolumeSideLength = 64;
|
||||
|
||||
FilePager<typename VolumeType::VoxelType>* pager = new FilePager<typename VolumeType::VoxelType>(".");
|
||||
|
||||
//Create empty volume
|
||||
VolumeType* volData = new VolumeType(Region(Vector3DInt32(0, 0, 0), Vector3DInt32(uVolumeSideLength - 1, uVolumeSideLength - 1, uVolumeSideLength - 1)), pager);
|
||||
|
||||
// Fill
|
||||
for (int32_t z = 0; z < uVolumeSideLength; z++)
|
||||
{
|
||||
for (int32_t y = 0; y < uVolumeSideLength; y++)
|
||||
{
|
||||
for (int32_t x = 0; x < uVolumeSideLength; x++)
|
||||
{
|
||||
// Create a density field which changes throughout the volume. It's
|
||||
// zero in the lower corner and increasing as the coordinates increase.
|
||||
typename VolumeType::VoxelType voxelValue;
|
||||
writeDensityValueToVoxel<typename VolumeType::VoxelType>(x + y + z, voxelValue);
|
||||
writeMaterialValueToVoxel<typename VolumeType::VoxelType>(z > uVolumeSideLength / 2 ? 42 : 79, voxelValue);
|
||||
volData->setVoxelAt(x, y, z, voxelValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return volData;
|
||||
}
|
||||
|
||||
// From http://stackoverflow.com/a/5289624
|
||||
float randomFloat(float a, float b)
|
||||
{
|
||||
float random = ((float)rand()) / (float)RAND_MAX;
|
||||
float diff = b - a;
|
||||
float r = random * diff;
|
||||
return a + r;
|
||||
}
|
||||
|
||||
template <typename VolumeType>
|
||||
VolumeType* createAndFillVolumeWithNoise(int32_t iVolumeSideLength, float minValue, float maxValue)
|
||||
{
|
||||
FilePager<float>* pager = new FilePager<float>(".");
|
||||
|
||||
//Create empty volume
|
||||
VolumeType* volData = new VolumeType(Region(Vector3DInt32(0, 0, 0), Vector3DInt32(iVolumeSideLength - 1, iVolumeSideLength - 1, iVolumeSideLength - 1)), pager);
|
||||
|
||||
// Seed generator for consistency between runs.
|
||||
srand(12345);
|
||||
|
||||
// Fill
|
||||
for (int32_t z = 0; z < iVolumeSideLength; z++)
|
||||
{
|
||||
for (int32_t y = 0; y < iVolumeSideLength; y++)
|
||||
{
|
||||
for (int32_t x = 0; x < iVolumeSideLength; x++)
|
||||
{
|
||||
float voxelValue = randomFloat(minValue, maxValue);
|
||||
volData->setVoxelAt(x, y, z, voxelValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return volData;
|
||||
}
|
||||
|
||||
void TestSurfaceExtractor::testBehaviour()
|
||||
{
|
||||
// These tests apply the Marching Cubes surface extractor to volumes of various voxel types. In addition we sometimes make use of custom controllers
|
||||
// and user-provided meshes to make sure these various combinations work as expected.
|
||||
//
|
||||
// It is also noted that the number of indices and vertices is varying quite significantly based on the voxel type. This seems unexpected, but could
|
||||
// be explained if some overflow is occuring when writing data into the volume, causing volumes of different voxel types to have different distributions.
|
||||
// Of course, the use of a custom controller will also make a significant diference, but this probably does need investigating further in the future.
|
||||
|
||||
// This basic test just uses the default controller and automatically generates a mesh of the appropriate type.
|
||||
auto uintVol = createAndFillVolume< PagedVolume<uint8_t> >();
|
||||
auto uintMesh = extractMarchingCubesMesh(uintVol, uintVol->getEnclosingRegion());
|
||||
QCOMPARE(uintMesh.getNoOfVertices(), uint32_t(12096)); // Verifies size of mesh and that we have 32-bit indices
|
||||
QCOMPARE(uintMesh.getNoOfIndices(), uint32_t(35157)); // Verifies size of mesh
|
||||
QCOMPARE(uintMesh.getIndex(100), uint32_t(44)); // Verifies that we have 32-bit indices
|
||||
QCOMPARE(uintMesh.getVertex(100).data, uint8_t(1)); // Not really meaningful for a primative type
|
||||
|
||||
// This test makes use of a custom controller
|
||||
auto floatVol = createAndFillVolume< PagedVolume<float> >();
|
||||
CustomMarchingCubesController floatCustomController;
|
||||
auto floatMesh = extractMarchingCubesMesh(floatVol, floatVol->getEnclosingRegion(), floatCustomController);
|
||||
QCOMPARE(floatMesh.getNoOfVertices(), uint32_t(16113)); // Verifies size of mesh and that we have 32-bit indices
|
||||
QCOMPARE(floatMesh.getNoOfIndices(), uint32_t(22053)); // Verifies size of mesh
|
||||
QCOMPARE(floatMesh.getIndex(100), uint32_t(26)); // Verifies that we have 32-bit indices
|
||||
QCOMPARE(floatMesh.getVertex(100).data, float(1.0f)); // Not really meaningful for a primative type
|
||||
|
||||
// This test makes use of a user provided mesh. It uses the default controller, but we have to explicitly provide this because C++ won't let us
|
||||
// use a default for the second-to-last parameter but noot use a default for the last parameter.
|
||||
auto intVol = createAndFillVolume< PagedVolume<int8_t> >();
|
||||
Mesh< MarchingCubesVertex< int8_t >, uint16_t > intMesh;
|
||||
extractMarchingCubesMeshCustom(intVol, intVol->getEnclosingRegion(), &intMesh);
|
||||
QCOMPARE(intMesh.getNoOfVertices(), uint16_t(11718)); // Verifies size of mesh and that we have 16-bit indices
|
||||
QCOMPARE(intMesh.getNoOfIndices(), uint32_t(34041)); // Verifies size of mesh
|
||||
QCOMPARE(intMesh.getIndex(100), uint16_t(29)); // Verifies that we have 16-bit indices
|
||||
QCOMPARE(intMesh.getVertex(100).data, int8_t(1)); // Not really meaningful for a primative type
|
||||
|
||||
// This test makes use of a user-provided mesh and also a custom controller.
|
||||
auto doubleVol = createAndFillVolume< PagedVolume<double> >();
|
||||
CustomMarchingCubesController doubleCustomController;
|
||||
Mesh< MarchingCubesVertex< double >, uint16_t > doubleMesh;
|
||||
extractMarchingCubesMeshCustom(doubleVol, doubleVol->getEnclosingRegion(), &doubleMesh, doubleCustomController);
|
||||
QCOMPARE(doubleMesh.getNoOfVertices(), uint16_t(16113)); // Verifies size of mesh and that we have 32-bit indices
|
||||
QCOMPARE(doubleMesh.getNoOfIndices(), uint32_t(22053)); // Verifies size of mesh
|
||||
QCOMPARE(doubleMesh.getIndex(100), uint16_t(26)); // Verifies that we have 32-bit indices
|
||||
QCOMPARE(doubleMesh.getVertex(100).data, double(1.0f)); // Not really meaningful for a primative type
|
||||
|
||||
// This test ensures the extractor works on a non-primitive voxel type.
|
||||
auto materialVol = createAndFillVolume< PagedVolume<MaterialDensityPair88> >();
|
||||
auto materialMesh = extractMarchingCubesMesh(materialVol, materialVol->getEnclosingRegion());
|
||||
QCOMPARE(materialMesh.getNoOfVertices(), uint32_t(12096)); // Verifies size of mesh and that we have 32-bit indices
|
||||
QCOMPARE(materialMesh.getNoOfIndices(), uint32_t(35157)); // Verifies size of mesh
|
||||
QCOMPARE(materialMesh.getIndex(100), uint32_t(44)); // Verifies that we have 32-bit indices
|
||||
QCOMPARE(materialMesh.getVertex(100).data.getMaterial(), uint16_t(79)); // Verify the data attached to the vertex
|
||||
}
|
||||
|
||||
void TestSurfaceExtractor::testEmptyVolumePerformance()
|
||||
{
|
||||
auto emptyVol = createAndFillVolumeWithNoise< PagedVolume<float> >(128, -2.0f, -1.0f);
|
||||
Mesh< MarchingCubesVertex< float >, uint16_t > emptyMesh;
|
||||
QBENCHMARK{ extractMarchingCubesMeshCustom(emptyVol, Region(32, 32, 32, 63, 63, 63), &emptyMesh); }
|
||||
QCOMPARE(emptyMesh.getNoOfVertices(), uint16_t(0));
|
||||
}
|
||||
|
||||
void TestSurfaceExtractor::testNoiseVolumePerformance()
|
||||
{
|
||||
auto noiseVol = createAndFillVolumeWithNoise< PagedVolume<float> >(128, -1.0f, 1.0f);
|
||||
Mesh< MarchingCubesVertex< float >, uint16_t > noiseMesh;
|
||||
QBENCHMARK{ extractMarchingCubesMeshCustom(noiseVol, Region(32, 32, 32, 63, 63, 63), &noiseMesh); }
|
||||
QCOMPARE(noiseMesh.getNoOfVertices(), uint16_t(48967));
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestSurfaceExtractor)
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2010 Matt Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "TestSurfaceExtractor.h"
|
||||
|
||||
#include "PolyVoxCore/Density.h"
|
||||
#include "PolyVoxCore/FilePager.h"
|
||||
#include "PolyVoxCore/MaterialDensityPair.h"
|
||||
#include "PolyVoxCore/RawVolume.h"
|
||||
#include "PolyVoxCore/PagedVolume.h"
|
||||
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h"
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
// Test our ability to modify the behaviour of the MarchingCubesSurfaceExtractor. This simple example only modifies
|
||||
// the threshold (and actually this can be achieved by passing a parameter to the constructor of the
|
||||
// DefaultMarchingCubesController) but you could implement custom behaviour in the other members
|
||||
// if you wanted too. Actually, it's not clear if this ability is really useful because I can't think
|
||||
// what you'd modify apart from the threshold but the ability is at least available. Also, the
|
||||
// DefaultMarchingCubesController is templatised whereas this exmple shows that controllers don't
|
||||
// have to be.
|
||||
class CustomMarchingCubesController
|
||||
{
|
||||
public:
|
||||
typedef float DensityType;
|
||||
typedef float MaterialType;
|
||||
|
||||
float convertToDensity(float voxel)
|
||||
{
|
||||
return voxel;
|
||||
}
|
||||
|
||||
float convertToMaterial(float /*voxel*/)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float blendMaterials(float /*a*/, float /*b*/, float /*weight*/)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float getThreshold(void)
|
||||
{
|
||||
return 50.0f;
|
||||
}
|
||||
};
|
||||
|
||||
// These 'writeDensityValueToVoxel' functions provide a unified interface for writting densities to primative and class voxel types.
|
||||
// They are conceptually the inverse of the 'convertToDensity' function used by the MarchingCubesSurfaceExtractor. They probably shouldn't be part
|
||||
// of PolyVox, but they might be usful to other tests so we cold move them into a 'Tests.h' or something in the future.
|
||||
template<typename VoxelType>
|
||||
void writeDensityValueToVoxel(int valueToWrite, VoxelType& voxel)
|
||||
{
|
||||
voxel = valueToWrite;
|
||||
}
|
||||
|
||||
template<>
|
||||
void writeDensityValueToVoxel(int valueToWrite, MaterialDensityPair88& voxel)
|
||||
{
|
||||
voxel.setDensity(valueToWrite);
|
||||
}
|
||||
|
||||
template<typename VoxelType>
|
||||
void writeMaterialValueToVoxel(int /*valueToWrite*/, VoxelType& /*voxel*/)
|
||||
{
|
||||
//Most types don't have a material
|
||||
return;
|
||||
}
|
||||
|
||||
template<>
|
||||
void writeMaterialValueToVoxel(int valueToWrite, MaterialDensityPair88& voxel)
|
||||
{
|
||||
voxel.setMaterial(valueToWrite);
|
||||
}
|
||||
|
||||
template <typename VolumeType>
|
||||
VolumeType* createAndFillVolume(void)
|
||||
{
|
||||
const int32_t uVolumeSideLength = 64;
|
||||
|
||||
FilePager<typename VolumeType::VoxelType>* pager = new FilePager<typename VolumeType::VoxelType>(".");
|
||||
|
||||
//Create empty volume
|
||||
VolumeType* volData = new VolumeType(Region(Vector3DInt32(0, 0, 0), Vector3DInt32(uVolumeSideLength - 1, uVolumeSideLength - 1, uVolumeSideLength - 1)), pager);
|
||||
|
||||
// Fill
|
||||
for (int32_t z = 0; z < uVolumeSideLength; z++)
|
||||
{
|
||||
for (int32_t y = 0; y < uVolumeSideLength; y++)
|
||||
{
|
||||
for (int32_t x = 0; x < uVolumeSideLength; x++)
|
||||
{
|
||||
// Create a density field which changes throughout the volume. It's
|
||||
// zero in the lower corner and increasing as the coordinates increase.
|
||||
typename VolumeType::VoxelType voxelValue;
|
||||
writeDensityValueToVoxel<typename VolumeType::VoxelType>(x + y + z, voxelValue);
|
||||
writeMaterialValueToVoxel<typename VolumeType::VoxelType>(z > uVolumeSideLength / 2 ? 42 : 79, voxelValue);
|
||||
volData->setVoxelAt(x, y, z, voxelValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return volData;
|
||||
}
|
||||
|
||||
// From http://stackoverflow.com/a/5289624
|
||||
float randomFloat(float a, float b)
|
||||
{
|
||||
float random = ((float)rand()) / (float)RAND_MAX;
|
||||
float diff = b - a;
|
||||
float r = random * diff;
|
||||
return a + r;
|
||||
}
|
||||
|
||||
template <typename VolumeType>
|
||||
VolumeType* createAndFillVolumeWithNoise(int32_t iVolumeSideLength, float minValue, float maxValue)
|
||||
{
|
||||
FilePager<float>* pager = new FilePager<float>(".");
|
||||
|
||||
//Create empty volume
|
||||
VolumeType* volData = new VolumeType(Region(Vector3DInt32(0, 0, 0), Vector3DInt32(iVolumeSideLength - 1, iVolumeSideLength - 1, iVolumeSideLength - 1)), pager);
|
||||
|
||||
// Seed generator for consistency between runs.
|
||||
srand(12345);
|
||||
|
||||
// Fill
|
||||
for (int32_t z = 0; z < iVolumeSideLength; z++)
|
||||
{
|
||||
for (int32_t y = 0; y < iVolumeSideLength; y++)
|
||||
{
|
||||
for (int32_t x = 0; x < iVolumeSideLength; x++)
|
||||
{
|
||||
float voxelValue = randomFloat(minValue, maxValue);
|
||||
volData->setVoxelAt(x, y, z, voxelValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return volData;
|
||||
}
|
||||
|
||||
void TestSurfaceExtractor::testBehaviour()
|
||||
{
|
||||
// These tests apply the Marching Cubes surface extractor to volumes of various voxel types. In addition we sometimes make use of custom controllers
|
||||
// and user-provided meshes to make sure these various combinations work as expected.
|
||||
//
|
||||
// It is also noted that the number of indices and vertices is varying quite significantly based on the voxel type. This seems unexpected, but could
|
||||
// be explained if some overflow is occuring when writing data into the volume, causing volumes of different voxel types to have different distributions.
|
||||
// Of course, the use of a custom controller will also make a significant diference, but this probably does need investigating further in the future.
|
||||
|
||||
// This basic test just uses the default controller and automatically generates a mesh of the appropriate type.
|
||||
auto uintVol = createAndFillVolume< PagedVolume<uint8_t> >();
|
||||
auto uintMesh = extractMarchingCubesMesh(uintVol, uintVol->getEnclosingRegion());
|
||||
QCOMPARE(uintMesh.getNoOfVertices(), uint32_t(12096)); // Verifies size of mesh and that we have 32-bit indices
|
||||
QCOMPARE(uintMesh.getNoOfIndices(), uint32_t(35157)); // Verifies size of mesh
|
||||
QCOMPARE(uintMesh.getIndex(100), uint32_t(44)); // Verifies that we have 32-bit indices
|
||||
QCOMPARE(uintMesh.getVertex(100).data, uint8_t(1)); // Not really meaningful for a primative type
|
||||
|
||||
// This test makes use of a custom controller
|
||||
auto floatVol = createAndFillVolume< PagedVolume<float> >();
|
||||
CustomMarchingCubesController floatCustomController;
|
||||
auto floatMesh = extractMarchingCubesMesh(floatVol, floatVol->getEnclosingRegion(), floatCustomController);
|
||||
QCOMPARE(floatMesh.getNoOfVertices(), uint32_t(16113)); // Verifies size of mesh and that we have 32-bit indices
|
||||
QCOMPARE(floatMesh.getNoOfIndices(), uint32_t(22053)); // Verifies size of mesh
|
||||
QCOMPARE(floatMesh.getIndex(100), uint32_t(26)); // Verifies that we have 32-bit indices
|
||||
QCOMPARE(floatMesh.getVertex(100).data, float(1.0f)); // Not really meaningful for a primative type
|
||||
|
||||
// This test makes use of a user provided mesh. It uses the default controller, but we have to explicitly provide this because C++ won't let us
|
||||
// use a default for the second-to-last parameter but noot use a default for the last parameter.
|
||||
auto intVol = createAndFillVolume< PagedVolume<int8_t> >();
|
||||
Mesh< MarchingCubesVertex< int8_t >, uint16_t > intMesh;
|
||||
extractMarchingCubesMeshCustom(intVol, intVol->getEnclosingRegion(), &intMesh);
|
||||
QCOMPARE(intMesh.getNoOfVertices(), uint16_t(11718)); // Verifies size of mesh and that we have 16-bit indices
|
||||
QCOMPARE(intMesh.getNoOfIndices(), uint32_t(34041)); // Verifies size of mesh
|
||||
QCOMPARE(intMesh.getIndex(100), uint16_t(29)); // Verifies that we have 16-bit indices
|
||||
QCOMPARE(intMesh.getVertex(100).data, int8_t(1)); // Not really meaningful for a primative type
|
||||
|
||||
// This test makes use of a user-provided mesh and also a custom controller.
|
||||
auto doubleVol = createAndFillVolume< PagedVolume<double> >();
|
||||
CustomMarchingCubesController doubleCustomController;
|
||||
Mesh< MarchingCubesVertex< double >, uint16_t > doubleMesh;
|
||||
extractMarchingCubesMeshCustom(doubleVol, doubleVol->getEnclosingRegion(), &doubleMesh, doubleCustomController);
|
||||
QCOMPARE(doubleMesh.getNoOfVertices(), uint16_t(16113)); // Verifies size of mesh and that we have 32-bit indices
|
||||
QCOMPARE(doubleMesh.getNoOfIndices(), uint32_t(22053)); // Verifies size of mesh
|
||||
QCOMPARE(doubleMesh.getIndex(100), uint16_t(26)); // Verifies that we have 32-bit indices
|
||||
QCOMPARE(doubleMesh.getVertex(100).data, double(1.0f)); // Not really meaningful for a primative type
|
||||
|
||||
// This test ensures the extractor works on a non-primitive voxel type.
|
||||
auto materialVol = createAndFillVolume< PagedVolume<MaterialDensityPair88> >();
|
||||
auto materialMesh = extractMarchingCubesMesh(materialVol, materialVol->getEnclosingRegion());
|
||||
QCOMPARE(materialMesh.getNoOfVertices(), uint32_t(12096)); // Verifies size of mesh and that we have 32-bit indices
|
||||
QCOMPARE(materialMesh.getNoOfIndices(), uint32_t(35157)); // Verifies size of mesh
|
||||
QCOMPARE(materialMesh.getIndex(100), uint32_t(44)); // Verifies that we have 32-bit indices
|
||||
QCOMPARE(materialMesh.getVertex(100).data.getMaterial(), uint16_t(79)); // Verify the data attached to the vertex
|
||||
}
|
||||
|
||||
void TestSurfaceExtractor::testEmptyVolumePerformance()
|
||||
{
|
||||
auto emptyVol = createAndFillVolumeWithNoise< PagedVolume<float> >(128, -2.0f, -1.0f);
|
||||
Mesh< MarchingCubesVertex< float >, uint16_t > emptyMesh;
|
||||
QBENCHMARK{ extractMarchingCubesMeshCustom(emptyVol, Region(32, 32, 32, 63, 63, 63), &emptyMesh); }
|
||||
QCOMPARE(emptyMesh.getNoOfVertices(), uint16_t(0));
|
||||
}
|
||||
|
||||
void TestSurfaceExtractor::testNoiseVolumePerformance()
|
||||
{
|
||||
auto noiseVol = createAndFillVolumeWithNoise< PagedVolume<float> >(128, -1.0f, 1.0f);
|
||||
Mesh< MarchingCubesVertex< float >, uint16_t > noiseMesh;
|
||||
QBENCHMARK{ extractMarchingCubesMeshCustom(noiseVol, Region(32, 32, 32, 63, 63, 63), &noiseMesh); }
|
||||
QCOMPARE(noiseMesh.getNoOfVertices(), uint16_t(48967));
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestSurfaceExtractor)
|
||||
|
@ -1,194 +1,194 @@
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2010 Matt Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "TestVolumeSubclass.h"
|
||||
|
||||
#include "PolyVoxCore/Array.h"
|
||||
|
||||
#include "PolyVoxCore/BaseVolume.h"
|
||||
#include "PolyVoxCore/CubicSurfaceExtractor.h"
|
||||
#include "PolyVoxCore/Material.h"
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
template <typename VoxelType>
|
||||
class VolumeSubclass : public BaseVolume<VoxelType>
|
||||
{
|
||||
public:
|
||||
//There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared.
|
||||
//There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but
|
||||
//which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler
|
||||
//option. For now it seems best to 'fix' it with the preprocessor insstead, but maybe the workaround can be reinstated
|
||||
//in the future
|
||||
//typedef BaseVolume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences. See http://goo.gl/qu1wn
|
||||
//class Sampler : public VolumeOfVoxelType::template Sampler< VolumeSubclass<VoxelType> >
|
||||
#if defined(_MSC_VER)
|
||||
class Sampler : public BaseVolume<VoxelType>::Sampler< VolumeSubclass<VoxelType> > //This line works on VS2010
|
||||
#else
|
||||
class Sampler : public BaseVolume<VoxelType>::template Sampler< VolumeSubclass<VoxelType> > //This line works on GCC
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
Sampler(VolumeSubclass<VoxelType>* volume)
|
||||
:BaseVolume<VoxelType>::template Sampler< VolumeSubclass<VoxelType> >(volume)
|
||||
{
|
||||
this->mVolume = volume;
|
||||
}
|
||||
//~Sampler();
|
||||
};
|
||||
|
||||
/// Constructor for creating a fixed size volume.
|
||||
VolumeSubclass(const Region& regValid)
|
||||
:BaseVolume<VoxelType>(regValid)
|
||||
, mVolumeData(this->getWidth(), this->getHeight(), this->getDepth())
|
||||
{
|
||||
//mVolumeData.resize(ArraySizes(this->getWidth())(this->getHeight())(this->getDepth()));
|
||||
}
|
||||
/// Destructor
|
||||
~VolumeSubclass() {};
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const
|
||||
{
|
||||
// FIXME: This templatised version is implemented in terms of the not template version. This is strange
|
||||
// from a peformance point of view but it's just because we were encountering some compile issues on GCC.
|
||||
return getVoxel(uXPos, uYPos, uZPos, eWrapMode, tBorder);
|
||||
}
|
||||
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const
|
||||
{
|
||||
// Simply call through to the real implementation
|
||||
return getVoxel<eWrapMode>(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder);
|
||||
}
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const
|
||||
{
|
||||
switch(eWrapMode)
|
||||
{
|
||||
case WrapModes::Validate:
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false)
|
||||
{
|
||||
POLYVOX_THROW(std::out_of_range, "Position is outside valid region");
|
||||
}
|
||||
|
||||
return mVolumeData(uXPos, uYPos, uZPos);
|
||||
}
|
||||
case WrapModes::Clamp:
|
||||
{
|
||||
//Perform clamping
|
||||
uXPos = (std::max)(uXPos, this->m_regValidRegion.getLowerX());
|
||||
uYPos = (std::max)(uYPos, this->m_regValidRegion.getLowerY());
|
||||
uZPos = (std::max)(uZPos, this->m_regValidRegion.getLowerZ());
|
||||
uXPos = (std::min)(uXPos, this->m_regValidRegion.getUpperX());
|
||||
uYPos = (std::min)(uYPos, this->m_regValidRegion.getUpperY());
|
||||
uZPos = (std::min)(uZPos, this->m_regValidRegion.getUpperZ());
|
||||
return mVolumeData(uXPos, uYPos, uZPos);
|
||||
}
|
||||
case WrapModes::Border:
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
|
||||
{
|
||||
return mVolumeData(uXPos, uYPos, uZPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
return tBorder;
|
||||
}
|
||||
}
|
||||
case WrapModes::AssumeValid:
|
||||
{
|
||||
return mVolumeData(uXPos, uYPos, uZPos);
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Should never happen
|
||||
POLYVOX_ASSERT(false, "Invalid wrap mode");
|
||||
return VoxelType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const
|
||||
{
|
||||
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
|
||||
}
|
||||
|
||||
/// Sets the value used for voxels which are outside the volume
|
||||
void setBorderValue(const VoxelType& tBorder) { }
|
||||
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue)
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)))
|
||||
{
|
||||
mVolumeData(uXPos, uYPos, uZPos) = tValue;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// Sets the voxel at the position given by a 3D vector
|
||||
bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue) { return setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); }
|
||||
|
||||
/// Calculates approximatly how many bytes of memory the volume is currently using.
|
||||
uint32_t calculateSizeInBytes(void) { return 0; }
|
||||
|
||||
/// Deprecated - I don't think we should expose this function? Let us know if you disagree...
|
||||
//void resize(const Region& regValidRegion);
|
||||
|
||||
private:
|
||||
Array<3, VoxelType> mVolumeData;
|
||||
};
|
||||
|
||||
void TestVolumeSubclass::testExtractSurface()
|
||||
{
|
||||
VolumeSubclass<Material8> volumeSubclass(Region(0,0,0,16,16,16));
|
||||
|
||||
for(int32_t z = 0; z < volumeSubclass.getDepth() / 2; z++)
|
||||
{
|
||||
for(int32_t y = 0; y < volumeSubclass.getHeight(); y++)
|
||||
{
|
||||
for(int32_t x = 0; x < volumeSubclass.getWidth(); x++)
|
||||
{
|
||||
Material8 mat(1);
|
||||
volumeSubclass.setVoxelAt(Vector3DInt32(x,y,z),mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*******************************************************************************
|
||||
Copyright (c) 2010 Matt Williams
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "TestVolumeSubclass.h"
|
||||
|
||||
#include "PolyVoxCore/Array.h"
|
||||
|
||||
#include "PolyVoxCore/BaseVolume.h"
|
||||
#include "PolyVoxCore/CubicSurfaceExtractor.h"
|
||||
#include "PolyVoxCore/Material.h"
|
||||
#include "PolyVoxCore/Vector.h"
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
using namespace PolyVox;
|
||||
|
||||
template <typename VoxelType>
|
||||
class VolumeSubclass : public BaseVolume<VoxelType>
|
||||
{
|
||||
public:
|
||||
//There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared.
|
||||
//There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but
|
||||
//which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler
|
||||
//option. For now it seems best to 'fix' it with the preprocessor insstead, but maybe the workaround can be reinstated
|
||||
//in the future
|
||||
//typedef BaseVolume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences. See http://goo.gl/qu1wn
|
||||
//class Sampler : public VolumeOfVoxelType::template Sampler< VolumeSubclass<VoxelType> >
|
||||
#if defined(_MSC_VER)
|
||||
class Sampler : public BaseVolume<VoxelType>::Sampler< VolumeSubclass<VoxelType> > //This line works on VS2010
|
||||
#else
|
||||
class Sampler : public BaseVolume<VoxelType>::template Sampler< VolumeSubclass<VoxelType> > //This line works on GCC
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
Sampler(VolumeSubclass<VoxelType>* volume)
|
||||
:BaseVolume<VoxelType>::template Sampler< VolumeSubclass<VoxelType> >(volume)
|
||||
{
|
||||
this->mVolume = volume;
|
||||
}
|
||||
//~Sampler();
|
||||
};
|
||||
|
||||
/// Constructor for creating a fixed size volume.
|
||||
VolumeSubclass(const Region& regValid)
|
||||
:BaseVolume<VoxelType>(regValid)
|
||||
, mVolumeData(this->getWidth(), this->getHeight(), this->getDepth())
|
||||
{
|
||||
//mVolumeData.resize(ArraySizes(this->getWidth())(this->getHeight())(this->getDepth()));
|
||||
}
|
||||
/// Destructor
|
||||
~VolumeSubclass() {};
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const
|
||||
{
|
||||
// FIXME: This templatised version is implemented in terms of the not template version. This is strange
|
||||
// from a peformance point of view but it's just because we were encountering some compile issues on GCC.
|
||||
return getVoxel(uXPos, uYPos, uZPos, eWrapMode, tBorder);
|
||||
}
|
||||
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
template <WrapMode eWrapMode>
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const
|
||||
{
|
||||
// Simply call through to the real implementation
|
||||
return getVoxel<eWrapMode>(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder);
|
||||
}
|
||||
|
||||
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const
|
||||
{
|
||||
switch(eWrapMode)
|
||||
{
|
||||
case WrapModes::Validate:
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false)
|
||||
{
|
||||
POLYVOX_THROW(std::out_of_range, "Position is outside valid region");
|
||||
}
|
||||
|
||||
return mVolumeData(uXPos, uYPos, uZPos);
|
||||
}
|
||||
case WrapModes::Clamp:
|
||||
{
|
||||
//Perform clamping
|
||||
uXPos = (std::max)(uXPos, this->m_regValidRegion.getLowerX());
|
||||
uYPos = (std::max)(uYPos, this->m_regValidRegion.getLowerY());
|
||||
uZPos = (std::max)(uZPos, this->m_regValidRegion.getLowerZ());
|
||||
uXPos = (std::min)(uXPos, this->m_regValidRegion.getUpperX());
|
||||
uYPos = (std::min)(uYPos, this->m_regValidRegion.getUpperY());
|
||||
uZPos = (std::min)(uZPos, this->m_regValidRegion.getUpperZ());
|
||||
return mVolumeData(uXPos, uYPos, uZPos);
|
||||
}
|
||||
case WrapModes::Border:
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
|
||||
{
|
||||
return mVolumeData(uXPos, uYPos, uZPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
return tBorder;
|
||||
}
|
||||
}
|
||||
case WrapModes::AssumeValid:
|
||||
{
|
||||
return mVolumeData(uXPos, uYPos, uZPos);
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Should never happen
|
||||
POLYVOX_ASSERT(false, "Invalid wrap mode");
|
||||
return VoxelType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a voxel at the position given by a 3D vector
|
||||
VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const
|
||||
{
|
||||
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
|
||||
}
|
||||
|
||||
/// Sets the value used for voxels which are outside the volume
|
||||
void setBorderValue(const VoxelType& tBorder) { }
|
||||
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
|
||||
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue)
|
||||
{
|
||||
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)))
|
||||
{
|
||||
mVolumeData(uXPos, uYPos, uZPos) = tValue;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// Sets the voxel at the position given by a 3D vector
|
||||
bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue) { return setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); }
|
||||
|
||||
/// Calculates approximatly how many bytes of memory the volume is currently using.
|
||||
uint32_t calculateSizeInBytes(void) { return 0; }
|
||||
|
||||
/// Deprecated - I don't think we should expose this function? Let us know if you disagree...
|
||||
//void resize(const Region& regValidRegion);
|
||||
|
||||
private:
|
||||
Array<3, VoxelType> mVolumeData;
|
||||
};
|
||||
|
||||
void TestVolumeSubclass::testExtractSurface()
|
||||
{
|
||||
VolumeSubclass<Material8> volumeSubclass(Region(0,0,0,16,16,16));
|
||||
|
||||
for(int32_t z = 0; z < volumeSubclass.getDepth() / 2; z++)
|
||||
{
|
||||
for(int32_t y = 0; y < volumeSubclass.getHeight(); y++)
|
||||
{
|
||||
for(int32_t x = 0; x < volumeSubclass.getWidth(); x++)
|
||||
{
|
||||
Material8 mat(1);
|
||||
volumeSubclass.setVoxelAt(Vector3DInt32(x,y,z),mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto result = extractCubicMesh(&volumeSubclass, volumeSubclass.getEnclosingRegion());
|
||||
|
||||
QCOMPARE(result.getNoOfVertices(), static_cast<uint32_t>(8));
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestVolumeSubclass)
|
||||
|
||||
QCOMPARE(result.getNoOfVertices(), static_cast<uint32_t>(8));
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestVolumeSubclass)
|
||||
|
Reference in New Issue
Block a user