Fix Ambient Occlusion Calculator to accept functors, functions and lambdas

By changing the 'pass by value' to be a 'pass by const reference' (and
adding some const qualifiers) the calculator can take any of the three
types.

Performance could be improved further using C++11 perfect forwarding to
pass the function on without changing a thing. I added a comment to remind
us of this.

Also added a test for passing a function and a (commented out) test for
passing a lambda.
This commit is contained in:
Matt Williams 2012-10-28 15:41:53 +00:00
parent d6640f64d0
commit bb87e9e628
3 changed files with 22 additions and 6 deletions

View File

@ -49,9 +49,8 @@ namespace PolyVox
class AmbientOcclusionCalculatorRaycastCallback class AmbientOcclusionCalculatorRaycastCallback
{ {
public: public:
AmbientOcclusionCalculatorRaycastCallback(IsVoxelTransparentCallback isVoxelTransparentCallback) AmbientOcclusionCalculatorRaycastCallback(IsVoxelTransparentCallback isVoxelTransparentCallback) : mIsVoxelTransparentCallback(isVoxelTransparentCallback)
{ {
mIsVoxelTransparentCallback = isVoxelTransparentCallback;
} }
bool operator()(const SimpleVolume<uint8_t>::Sampler& sampler) bool operator()(const SimpleVolume<uint8_t>::Sampler& sampler)
@ -65,13 +64,19 @@ namespace PolyVox
return direct; return direct;
} }
IsVoxelTransparentCallback mIsVoxelTransparentCallback; const IsVoxelTransparentCallback& mIsVoxelTransparentCallback;
}; };
// NOTE: The callback needs to be a functor not a function. I haven't been // NOTE: The callback needs to be a functor not a function. I haven't been
// able to work the required template magic to get functions working as well. // able to work the required template magic to get functions working as well.
//
// Matt: If you make the function take a "IsVoxelTransparentCallback&&" then
// it will forward it on. Works for functors, functions and lambdas.
// This will be 'perfect forwarding' using 'universal references'
// This will require C++11 rvalue references which is why I haven't made the
// change yet.
template<typename VolumeType, typename IsVoxelTransparentCallback> template<typename VolumeType, typename IsVoxelTransparentCallback>
void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback); void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, const IsVoxelTransparentCallback& isVoxelTransparentCallback);
} }
#include "PolyVoxCore/AmbientOcclusionCalculator.inl" #include "PolyVoxCore/AmbientOcclusionCalculator.inl"

View File

@ -24,7 +24,7 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
template<typename VolumeType, typename IsVoxelTransparentCallback> template<typename VolumeType, typename IsVoxelTransparentCallback>
void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback) void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, const IsVoxelTransparentCallback& isVoxelTransparentCallback)
{ {
typename VolumeType::Sampler m_sampVolume(volInput); typename VolumeType::Sampler m_sampVolume(volInput);

View File

@ -33,12 +33,17 @@ using namespace PolyVox;
class IsVoxelTransparent class IsVoxelTransparent
{ {
public: public:
bool operator()(uint8_t voxel) bool operator()(uint8_t voxel) const
{ {
return voxel == 0; return voxel == 0;
} }
}; };
bool isVoxelTransparentFunction(uint8_t voxel)
{
return voxel == 0;
}
void TestAmbientOcclusionGenerator::testExecute() void TestAmbientOcclusionGenerator::testExecute()
{ {
const int32_t g_uVolumeSideLength = 64; const int32_t g_uVolumeSideLength = 64;
@ -78,6 +83,12 @@ void TestAmbientOcclusionGenerator::testExecute()
QCOMPARE(static_cast<int>(ambientOcclusionResult[16][16][16]), 103); QCOMPARE(static_cast<int>(ambientOcclusionResult[16][16][16]), 103);
QCOMPARE(static_cast<int>(ambientOcclusionResult[16][24][16]), 123); QCOMPARE(static_cast<int>(ambientOcclusionResult[16][24][16]), 123);
QCOMPARE(static_cast<int>(ambientOcclusionResult[16][31][16]), 173); QCOMPARE(static_cast<int>(ambientOcclusionResult[16][31][16]), 173);
//Just run a quick test to make sure that it compiles when taking a function pointer
calculateAmbientOcclusion(&volData, &ambientOcclusionResult, volData.getEnclosingRegion(), 32.0f, 8, &isVoxelTransparentFunction);
//Also test it using a lambda
//calculateAmbientOcclusion(&volData, &ambientOcclusionResult, volData.getEnclosingRegion(), 32.0f, 8, [](uint8_t voxel){return voxel == 0;});
} }
QTEST_MAIN(TestAmbientOcclusionGenerator) QTEST_MAIN(TestAmbientOcclusionGenerator)