diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index b4e60974..20a272c6 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -184,7 +184,7 @@ void createSphereInVolume(LargeVolume& volData, Vector3DF uint8_t uDensity = MaterialDensityPair44::getMaxDensity(); //Get the old voxel - MaterialDensityPair44 voxel = volData.getVoxelAt(x,y,z); + MaterialDensityPair44 voxel = volData.getVoxel(x,y,z); //Modify the density voxel.setDensity(uDensity); diff --git a/examples/SmoothLOD/main.cpp b/examples/SmoothLOD/main.cpp index fe2ccc3d..9b8f6f78 100644 --- a/examples/SmoothLOD/main.cpp +++ b/examples/SmoothLOD/main.cpp @@ -55,15 +55,8 @@ void createSphereInVolume(SimpleVolume& volData, float fRadius) if(fDistToCenter <= fRadius) { //Our new density value - //uint8_t uDensity = Density8::getmaxDensity()(); uint8_t uDensity = std::numeric_limits::max(); - //Get the old voxel - //uint8_t voxel = volData.getVoxelAt(x,y,z); - - //Modify the density - //voxel.setDensity(uDensity); - //Wrte the voxel value into the volume volData.setVoxelAt(x, y, z, uDensity); } diff --git a/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.h b/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.h index 04d70756..eeb3c50d 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.h @@ -36,16 +36,23 @@ namespace PolyVox //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// More details to come... //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + namespace WrapModes { enum WrapMode { - Clamp = 0, - Border = 1 + Validate = 0, + Clamp = 1, + Border = 2, + AssumeValid = 3 }; } typedef WrapModes::WrapMode WrapMode; + // Required for a trick to implement specialization of template member + // functions in template classes. See http://stackoverflow.com/a/4951057 + template struct WrapModeType{}; + template class BaseVolume { @@ -109,7 +116,7 @@ namespace PolyVox inline VoxelType peekVoxel1px1py1pz(void) const; protected: - VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; DerivedVolumeType* mVolume; @@ -146,22 +153,31 @@ namespace PolyVox int32_t getShortestSideLength(void) const; /// Gets the length of the diagonal in voxels float getDiagonalLength(void) const; + /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + template + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const; /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxel(const Vector3DInt32& v3dPos) const; + template + VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const; + /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; + VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; + /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType()) const; + POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType()) const; + POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; /// Sets the value used for voxels which are outside the volume void setBorderValue(const VoxelType& tBorder); /// Sets the voxel at the position given by x,y,z coordinates + void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); + /// Sets the voxel at the position given by a 3D vector + void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); + /// Sets the voxel at the position given by x,y,z coordinates bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue); /// Sets the voxel at the position given by a 3D vector bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue); diff --git a/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.inl index 2103726d..a78804ec 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/BaseVolume.inl @@ -154,26 +154,70 @@ namespace PolyVox } //////////////////////////////////////////////////////////////////////////////// + /// This version of the function requires the wrap mode to be specified as a + /// template parameter, which can provide better performance. /// \param uXPos The \c x position of the voxel /// \param uYPos The \c y position of the voxel /// \param uZPos The \c z position of the voxel + /// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. /// \return The voxel value //////////////////////////////////////////////////////////////////////////////// template - VoxelType BaseVolume::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const + template + VoxelType BaseVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const { - POLYVOX_THROW(not_implemented, "You should never call the base class version of this function."); + POLYVOX_ASSERT(false, "You should never call the base class version of this function."); return VoxelType(); } //////////////////////////////////////////////////////////////////////////////// - /// \param v3dPos The 3D position of the voxel + /// This version of the function requires the wrap mode to be specified as a + /// template parameter, which can provide better performance. + /// \param uXPos The \c x position of the voxel + /// \param uYPos The \c y position of the voxel + /// \param uZPos The \c z position of the voxel + /// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. /// \return The voxel value //////////////////////////////////////////////////////////////////////////////// template - VoxelType BaseVolume::getVoxel(const Vector3DInt32& /*v3dPos*/) const + template + VoxelType BaseVolume::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const { - POLYVOX_THROW(not_implemented, "You should never call the base class version of this function."); + POLYVOX_ASSERT(false, "You should never call the base class version of this function."); + return VoxelType(); + } + + //////////////////////////////////////////////////////////////////////////////// + /// This version of the function is provided so that the wrap mode does not need + /// to be specified as a template parameter, as it may be confusing to some users. + /// \param uXPos The \c x position of the voxel + /// \param uYPos The \c y position of the voxel + /// \param uZPos The \c z position of the voxel + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. + /// \return The voxel value + //////////////////////////////////////////////////////////////////////////////// + template + VoxelType BaseVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const + { + POLYVOX_ASSERT(false, "You should never call the base class version of this function."); + return VoxelType(); + } + + //////////////////////////////////////////////////////////////////////////////// + /// This version of the function is provided so that the wrap mode does not need + /// to be specified as a template parameter, as it may be confusing to some users. + /// \param v3dPos The 3D position of the voxel + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. + /// \return The voxel value + //////////////////////////////////////////////////////////////////////////////// + template + VoxelType BaseVolume::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const + { + POLYVOX_ASSERT(false, "You should never call the base class version of this function."); return VoxelType(); } @@ -201,30 +245,6 @@ namespace PolyVox return VoxelType(); } - //////////////////////////////////////////////////////////////////////////////// - /// \param uXPos The \c x position of the voxel - /// \param uYPos The \c y position of the voxel - /// \param uZPos The \c z position of the voxel - /// \return The voxel value - //////////////////////////////////////////////////////////////////////////////// - template - VoxelType BaseVolume::getVoxelWithWrapping(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const - { - POLYVOX_THROW(not_implemented, "You should never call the base class version of this function."); - return VoxelType(); - } - - //////////////////////////////////////////////////////////////////////////////// - /// \param v3dPos The 3D position of the voxel - /// \return The voxel value - //////////////////////////////////////////////////////////////////////////////// - template - VoxelType BaseVolume::getVoxelWithWrapping(const Vector3DInt32& /*v3dPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const - { - POLYVOX_THROW(not_implemented, "You should never call the base class version of this function."); - return VoxelType(); - } - //////////////////////////////////////////////////////////////////////////////// /// \param tBorder The value to use for voxels outside the volume. //////////////////////////////////////////////////////////////////////////////// @@ -234,6 +254,28 @@ namespace PolyVox m_tBorderValue = tBorder; } + //////////////////////////////////////////////////////////////////////////////// + /// \param uXPos the \c x position of the voxel + /// \param uYPos the \c y position of the voxel + /// \param uZPos the \c z position of the voxel + /// \param tValue the value to which the voxel will be set + //////////////////////////////////////////////////////////////////////////////// + template + void BaseVolume::setVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tValue*/, WrapMode /*eWrapMode*/) + { + POLYVOX_THROW(not_implemented, "You should never call the base class version of this function."); + } + + //////////////////////////////////////////////////////////////////////////////// + /// \param v3dPos the 3D position of the voxel + /// \param tValue the value to which the voxel will be set + //////////////////////////////////////////////////////////////////////////////// + template + void BaseVolume::setVoxel(const Vector3DInt32& /*v3dPos*/, VoxelType /*tValue*/, WrapMode /*eWrapMode*/) + { + POLYVOX_THROW(not_implemented, "You should never call the base class version of this function."); + } + //////////////////////////////////////////////////////////////////////////////// /// \param uXPos the \c x position of the voxel /// \param uYPos the \c y position of the voxel diff --git a/library/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl b/library/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl index 1e67a020..fedf56f6 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/BaseVolumeSampler.inl @@ -57,7 +57,7 @@ namespace PolyVox template VoxelType BaseVolume::Sampler::getVoxel(void) const { - return mVolume->getVoxelAt(mXPosInVolume, mYPosInVolume, mZPosInVolume); + return mVolume->getVoxel(mXPosInVolume, mYPosInVolume, mZPosInVolume, WrapModes::Validate); // FIXME - Use templatised version instead but watch for Linux compile errors. } template @@ -154,63 +154,63 @@ namespace PolyVox template VoxelType BaseVolume::Sampler::peekVoxel1nx1ny1nz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1nx1ny0pz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume ); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel1nx1ny1pz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume + 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1nx0py1nz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1nx0py0pz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume ); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel1nx0py1pz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume + 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1nx1py1nz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1nx1py0pz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume ); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel1nx1py1pz(void) const { - return getVoxelAt(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume + 1); } ////////////////////////////////////////////////////////////////////////// @@ -219,63 +219,63 @@ namespace PolyVox template VoxelType BaseVolume::Sampler::peekVoxel0px1ny1nz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel0px1ny0pz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume ); + return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel0px1ny1pz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume + 1); } template template VoxelType BaseVolume::Sampler::peekVoxel0px0py1nz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel0px0py0pz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume ); + return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel0px0py1pz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume , mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume + 1); } template template VoxelType BaseVolume::Sampler::peekVoxel0px1py1nz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel0px1py0pz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume ); + return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel0px1py1pz(void) const { - return getVoxelAt(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume + 1); } ////////////////////////////////////////////////////////////////////////// @@ -284,100 +284,83 @@ namespace PolyVox template VoxelType BaseVolume::Sampler::peekVoxel1px1ny1nz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1px1ny0pz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume ); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel1px1ny1pz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume + 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1px0py1nz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1px0py0pz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume ); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel1px0py1pz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume + 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1px1py1nz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume - 1); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume - 1); } template template VoxelType BaseVolume::Sampler::peekVoxel1px1py0pz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume ); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume ); } template template VoxelType BaseVolume::Sampler::peekVoxel1px1py1pz(void) const { - return getVoxelAt(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume + 1); + return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume + 1); } template template - VoxelType BaseVolume::Sampler::getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const + VoxelType BaseVolume::Sampler::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos) const { - if(mVolume->getEnclosingRegion().containsPoint(uXPos, uYPos, uZPos)) + switch(m_eWrapMode) { - return mVolume->getVoxelAt(uXPos, uYPos, uZPos); - } - else - { - switch(m_eWrapMode) - { - case WrapModes::Clamp: - { - const Vector3DInt32& lowerCorner = mVolume->m_regValidRegion.getLowerCorner(); - const Vector3DInt32& upperCorner = mVolume->m_regValidRegion.getUpperCorner(); - - int32_t iClampedX = clamp(uXPos, lowerCorner.getX(), upperCorner.getX()); - int32_t iClampedY = clamp(uYPos, lowerCorner.getY(), upperCorner.getY()); - int32_t iClampedZ = clamp(uZPos, lowerCorner.getZ(), upperCorner.getZ()); - - return mVolume->getVoxelAt(iClampedX, iClampedY, iClampedZ); - //No need to break as we've returned - } - case WrapModes::Border: - { - return m_tBorder; - //No need to break as we've returned - } - default: - { - //Should never happen - POLYVOX_THROW(std::invalid_argument, "Wrap mode parameter has an unrecognised value."); - } - } + case WrapModes::Validate: + return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Validate, m_tBorder); + case WrapModes::Clamp: + return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Clamp, m_tBorder); + case WrapModes::Border: + return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Border, m_tBorder); + case WrapModes::AssumeValid: + return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::AssumeValid, m_tBorder); + default: + // Should never happen + POLYVOX_ASSERT(false, "Invalid wrap mode"); + return VoxelType(); } } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/ConstVolumeProxy.h b/library/PolyVoxCore/include/PolyVoxCore/ConstVolumeProxy.h index 237a1c59..751377ec 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/ConstVolumeProxy.h +++ b/library/PolyVoxCore/include/PolyVoxCore/ConstVolumeProxy.h @@ -39,14 +39,14 @@ namespace PolyVox { // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. POLYVOX_ASSERT(m_regValid.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); - return m_pVolume.getVoxelAt(uXPos, uYPos, uZPos); + return m_pVolume.getVoxel(uXPos, uYPos, uZPos); } VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const { // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. POLYVOX_ASSERT(m_regValid.containsPoint(v3dPos), "Position is outside valid region"); - return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); } void setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) const diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractorWithNormals.inl b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractorWithNormals.inl index dca5f911..3956858c 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractorWithNormals.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractorWithNormals.inl @@ -53,7 +53,7 @@ namespace PolyVox uint32_t material = 0; - if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x+1,y,z,m_eWrapMode,m_tBorderValue), material)) + if(m_funcIsQuadNeededCallback(m_volData->getVoxel(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxel(x+1,y,z,m_eWrapMode,m_tBorderValue), material)) { uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), static_cast(material))); uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), static_cast(material))); @@ -63,7 +63,7 @@ namespace PolyVox m_meshCurrent->addTriangleCubic(v0,v2,v1); m_meshCurrent->addTriangleCubic(v1,v2,v3); } - if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x+1,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), material)) + if(m_funcIsQuadNeededCallback(m_volData->getVoxel(x+1,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxel(x,y,z,m_eWrapMode,m_tBorderValue), material)) { uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), static_cast(material))); uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), static_cast(material))); @@ -74,7 +74,7 @@ namespace PolyVox m_meshCurrent->addTriangleCubic(v1,v3,v2); } - if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y+1,z,m_eWrapMode,m_tBorderValue), material)) + if(m_funcIsQuadNeededCallback(m_volData->getVoxel(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxel(x,y+1,z,m_eWrapMode,m_tBorderValue), material)) { uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), static_cast(material))); uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), static_cast(material))); @@ -84,7 +84,7 @@ namespace PolyVox m_meshCurrent->addTriangleCubic(v0,v1,v2); m_meshCurrent->addTriangleCubic(v1,v3,v2); } - if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y+1,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), material)) + if(m_funcIsQuadNeededCallback(m_volData->getVoxel(x,y+1,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxel(x,y,z,m_eWrapMode,m_tBorderValue), material)) { uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), static_cast(material))); uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), static_cast(material))); @@ -95,7 +95,7 @@ namespace PolyVox m_meshCurrent->addTriangleCubic(v1,v2,v3); } - if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y,z+1,m_eWrapMode,m_tBorderValue), material)) + if(m_funcIsQuadNeededCallback(m_volData->getVoxel(x,y,z,m_eWrapMode,m_tBorderValue), m_volData->getVoxel(x,y,z+1,m_eWrapMode,m_tBorderValue), material)) { uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), static_cast(material))); uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), static_cast(material))); @@ -105,7 +105,7 @@ namespace PolyVox m_meshCurrent->addTriangleCubic(v0,v2,v1); m_meshCurrent->addTriangleCubic(v1,v2,v3); } - if(m_funcIsQuadNeededCallback(m_volData->getVoxelWithWrapping(x,y,z+1,m_eWrapMode,m_tBorderValue), m_volData->getVoxelWithWrapping(x,y,z,m_eWrapMode,m_tBorderValue), material)) + if(m_funcIsQuadNeededCallback(m_volData->getVoxel(x,y,z+1,m_eWrapMode,m_tBorderValue), m_volData->getVoxel(x,y,z,m_eWrapMode,m_tBorderValue), material)) { uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), static_cast(material))); uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), static_cast(material))); diff --git a/library/PolyVoxCore/include/PolyVoxCore/GradientEstimators.inl b/library/PolyVoxCore/include/PolyVoxCore/GradientEstimators.inl index cc401ad3..5add45bd 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/GradientEstimators.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/GradientEstimators.inl @@ -52,14 +52,14 @@ namespace PolyVox const int32_t z = volIter.getPosition().getZ(); //FIXME - bitwise way of doing this? - typename VolumeType::VoxelType voxel1nx = volIter.getVoxelAt(x-2, y ,z ) > 0 ? 1: 0; - typename VolumeType::VoxelType voxel1px = volIter.getVoxelAt(x-2, y ,z ) > 0 ? 1: 0; + typename VolumeType::VoxelType voxel1nx = volIter.getVoxel(x-2, y ,z ) > 0 ? 1: 0; + typename VolumeType::VoxelType voxel1px = volIter.getVoxel(x-2, y ,z ) > 0 ? 1: 0; - typename VolumeType::VoxelType voxel1ny = volIter.getVoxelAt(x , y-2,z ) > 0 ? 1: 0; - typename VolumeType::VoxelType voxel1py = volIter.getVoxelAt(x , y-2,z ) > 0 ? 1: 0; + typename VolumeType::VoxelType voxel1ny = volIter.getVoxel(x , y-2,z ) > 0 ? 1: 0; + typename VolumeType::VoxelType voxel1py = volIter.getVoxel(x , y-2,z ) > 0 ? 1: 0; - typename VolumeType::VoxelType voxel1nz = volIter.getVoxelAt(x , y ,z-2) > 0 ? 1: 0; - typename VolumeType::VoxelType voxel1pz = volIter.getVoxelAt(x , y ,z-2) > 0 ? 1: 0; + typename VolumeType::VoxelType voxel1nz = volIter.getVoxel(x , y ,z-2) > 0 ? 1: 0; + typename VolumeType::VoxelType voxel1pz = volIter.getVoxel(x , y ,z-2) > 0 ? 1: 0; return Vector3DFloat ( diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h index 67932672..1f7b71d5 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.h @@ -52,8 +52,8 @@ namespace PolyVox Block(uint16_t uSideLength = 0); uint16_t getSideLength(void) const; - VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; - VoxelType getVoxelAt(const Vector3DUint16& v3dPos) const; + VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; + VoxelType getVoxel(const Vector3DUint16& v3dPos) const; void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl index bb95f584..61c9baac 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Block.inl @@ -58,7 +58,7 @@ namespace PolyVox } template - VoxelType Block::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const + VoxelType Block::getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const { // This is internal code not directly called by the user. For efficiency we assert rather than throwing. POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block"); @@ -75,9 +75,9 @@ namespace PolyVox } template - VoxelType Block::getVoxelAt(const Vector3DUint16& v3dPos) const + VoxelType Block::getVoxel(const Vector3DUint16& v3dPos) const { - return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); } template diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h index 847ae008..5080f7db 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h @@ -258,6 +258,12 @@ namespace PolyVox #define POLYVOX_THROW(type, message) \ PolyVox::logError() << (message); \ throw type((message)) + + // Some fast functions (getVoxel(), etc) use exceptions for error handling but don't want the overhead of logging. + // This overhead is present even if no exception is thrown, probably because the presence of the logging code prevents + // some inlining. Therefore we provide this macro which doesn't log for such specialised circumstances. + #define POLYVOX_THROW_DONT_LOG(type, message) \ + throw type((message)) #else namespace PolyVox { @@ -271,6 +277,13 @@ namespace PolyVox PolyVox::logError() << (message); \ type except = (type)((message)); \ getThrowHandler()((except), __FILE__, __LINE__) + + // Some fast functions (getVoxel(), etc) use exceptions for error handling but don't want the overhead of logging. + // This overhead is present even if no exception is thrown, probably because the presence of the logging code prevents + // some inlining. Therefore we provide this macro which doesn't log for such specialised circumstances. + #define POLYVOX_THROW_DONT_LOG(type, message) \ + type except = (type)((message)); \ + getThrowHandler()((except), __FILE__, __LINE__) #endif namespace PolyVox diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h index 2be3f87d..a7b7d72f 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.h @@ -266,23 +266,31 @@ namespace PolyVox ~LargeVolume(); /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + template + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const; /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxel(const Vector3DInt32& v3dPos) const; + template + VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const; + /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; + VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; + /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType()) const; + POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType()) const; + POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; /// Sets the number of blocks for which uncompressed data is stored void setMaxNumberOfUncompressedBlocks(uint32_t uMaxNumberOfUncompressedBlocks); /// Sets the number of blocks which can be in memory before the paging system starts unloading them void setMaxNumberOfBlocksInMemory(uint32_t uMaxNumberOfBlocksInMemory); /// Sets the voxel at the position given by x,y,z coordinates + void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); + /// Sets the voxel at the position given by a 3D vector + void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); + /// Sets the voxel at the position given by x,y,z coordinates bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue); /// Sets the voxel at the position given by a 3D vector bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue); @@ -326,6 +334,14 @@ namespace PolyVox }; void initialise(const Region& regValidRegion, uint16_t uBlockSideLength); + // A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057 + template + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + /// gets called when a new region is allocated and needs to be filled /// NOTE: accessing ANY voxels outside this region during the process of this function /// is absolutely unsafe diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl index a00c744f..e9967114 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolume.inl @@ -116,38 +116,83 @@ namespace PolyVox } //////////////////////////////////////////////////////////////////////////////// + /// This version of the function requires the wrap mode to be specified as a + /// template parameter, which can provide better performance. /// \param uXPos The \c x position of the voxel /// \param uYPos The \c y position of the voxel /// \param uZPos The \c z position of the voxel + /// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. /// \return The voxel value //////////////////////////////////////////////////////////////////////////////// template - VoxelType LargeVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const + template + VoxelType LargeVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const { - // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. - POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); - - const int32_t blockX = uXPos >> m_uBlockSideLengthPower; - const int32_t blockY = uYPos >> m_uBlockSideLengthPower; - const int32_t blockZ = uZPos >> m_uBlockSideLengthPower; - - const uint16_t xOffset = static_cast(uXPos - (blockX << m_uBlockSideLengthPower)); - const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); - const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); - - Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); - - return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset); + // Simply call through to the real implementation + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); } //////////////////////////////////////////////////////////////////////////////// - /// \param v3dPos The 3D position of the voxel + /// This version of the function requires the wrap mode to be specified as a + /// template parameter, which can provide better performance. + /// \param uXPos The \c x position of the voxel + /// \param uYPos The \c y position of the voxel + /// \param uZPos The \c z position of the voxel + /// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. /// \return The voxel value //////////////////////////////////////////////////////////////////////////////// template - VoxelType LargeVolume::getVoxel(const Vector3DInt32& v3dPos) const + template + VoxelType LargeVolume::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const { - return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + // Simply call through to the real implementation + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder); + } + + //////////////////////////////////////////////////////////////////////////////// + /// This version of the function is provided so that the wrap mode does not need + /// to be specified as a template parameter, as it may be confusing to some users. + /// \param uXPos The \c x position of the voxel + /// \param uYPos The \c y position of the voxel + /// \param uZPos The \c z position of the voxel + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. + /// \return The voxel value + //////////////////////////////////////////////////////////////////////////////// + template + VoxelType LargeVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const + { + switch(eWrapMode) + { + case WrapModes::Validate: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::Clamp: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::Border: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::AssumeValid: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + default: + // Should never happen + POLYVOX_ASSERT(false, "Invalid wrap mode"); + return VoxelType(); + } + } + + //////////////////////////////////////////////////////////////////////////////// + /// This version of the function is provided so that the wrap mode does not need + /// to be specified as a template parameter, as it may be confusing to some users. + /// \param v3dPos The 3D position of the voxel + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. + /// \return The voxel value + //////////////////////////////////////////////////////////////////////////////// + template + VoxelType LargeVolume::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const + { + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder); } //////////////////////////////////////////////////////////////////////////////// @@ -171,7 +216,7 @@ namespace PolyVox Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); - return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset); + return pUncompressedBlock->getVoxel(xOffset,yOffset,zOffset); } else { @@ -189,61 +234,6 @@ namespace PolyVox return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); } - //////////////////////////////////////////////////////////////////////////////// - /// \param uXPos The \c x position of the voxel - /// \param uYPos The \c y position of the voxel - /// \param uZPos The \c z position of the voxel - /// \return The voxel value - //////////////////////////////////////////////////////////////////////////////// - template - VoxelType LargeVolume::getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const - { - switch(eWrapMode) - { - 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()); - - //Get the voxel value - return getVoxel(uXPos, uYPos, uZPos); - //No need to break as we've returned - } - case WrapModes::Border: - { - if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos)) - { - return getVoxel(uXPos, uYPos, uZPos); - } - else - { - return tBorder; - } - //No need to break as we've returned - } - default: - { - //Should never happen - POLYVOX_THROW(std::invalid_argument, "Wrap mode parameter has an unrecognised value."); - } - } - } - - //////////////////////////////////////////////////////////////////////////////// - /// \param v3dPos The 3D position of the voxel - /// \return The voxel value - //////////////////////////////////////////////////////////////////////////////// - template - VoxelType LargeVolume::getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const - { - return getVoxelWithWrapping(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder); - } - //////////////////////////////////////////////////////////////////////////////// /// Increasing the size of the block cache will increase memory but may improve performance. /// You may want to set this to a large value (e.g. 1024) when you are first loading your @@ -272,6 +262,56 @@ namespace PolyVox m_uMaxNumberOfBlocksInMemory = uMaxNumberOfBlocksInMemory; } + //////////////////////////////////////////////////////////////////////////////// + /// \param uXPos the \c x position of the voxel + /// \param uYPos the \c y position of the voxel + /// \param uZPos the \c z position of the voxel + /// \param tValue the value to which the voxel will be set + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data. + //////////////////////////////////////////////////////////////////////////////// + template + void LargeVolume::setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode) + { + if((eWrapMode != WrapModes::Validate) && (eWrapMode != WrapModes::AssumeValid)) + { + POLYVOX_THROW(std::invalid_argument, "Invalid wrap mode in call to setVoxel(). It must be 'None' or 'DontCheck'."); + } + + // This validation is skipped if the wrap mode is 'DontCheck' + if(eWrapMode == WrapModes::Validate) + { + if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false) + { + POLYVOX_THROW(std::out_of_range, "Position is outside valid region"); + } + } + + const int32_t blockX = uXPos >> m_uBlockSideLengthPower; + const int32_t blockY = uYPos >> m_uBlockSideLengthPower; + const int32_t blockZ = uZPos >> m_uBlockSideLengthPower; + + const uint16_t xOffset = static_cast(uXPos - (blockX << m_uBlockSideLengthPower)); + const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); + const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); + + Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); + + pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue); + } + + //////////////////////////////////////////////////////////////////////////////// + /// \param v3dPos the 3D position of the voxel + /// \param tValue the value to which the voxel will be set + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data. + //////////////////////////////////////////////////////////////////////////////// + template + void LargeVolume::setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode) + { + setVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue, eWrapMode); + } + //////////////////////////////////////////////////////////////////////////////// /// \param uXPos the \c x position of the voxel /// \param uYPos the \c y position of the voxel @@ -705,5 +745,66 @@ namespace PolyVox return uSizeInBytes; } + template + template + VoxelType LargeVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + // This function should never be called because one of the specialisations should always match. + POLYVOX_ASSERT(false, "This function is not implemented and should never be called!"); + } + + template + VoxelType LargeVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false) + { + POLYVOX_THROW(std::out_of_range, "Position is outside valid region"); + } + + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + + template + VoxelType LargeVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + //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 getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + + template + VoxelType LargeVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos)) + { + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + else + { + return tBorder; + } + } + + template + VoxelType LargeVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType /*tBorder*/) const + { + const int32_t blockX = uXPos >> m_uBlockSideLengthPower; + const int32_t blockY = uYPos >> m_uBlockSideLengthPower; + const int32_t blockZ = uZPos >> m_uBlockSideLengthPower; + + const uint16_t xOffset = static_cast(uXPos - (blockX << m_uBlockSideLengthPower)); + const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); + const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); + + Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); + + return pUncompressedBlock->getVoxel(xOffset,yOffset,zOffset); + } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LargeVolumeSampler.inl b/library/PolyVoxCore/include/PolyVoxCore/LargeVolumeSampler.inl index 9c05bc9d..33acc503 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LargeVolumeSampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LargeVolumeSampler.inl @@ -88,7 +88,7 @@ namespace PolyVox } else { - return getVoxelAt(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); + return getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); } } @@ -286,7 +286,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -296,7 +296,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -306,7 +306,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -316,7 +316,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -326,7 +326,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -336,7 +336,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -346,7 +346,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -356,7 +356,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -366,7 +366,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } ////////////////////////////////////////////////////////////////////////// @@ -378,7 +378,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -388,7 +388,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -398,7 +398,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -408,7 +408,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -418,7 +418,7 @@ namespace PolyVox { return *mCurrentVoxel; } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -428,7 +428,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -438,7 +438,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -448,7 +448,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -458,7 +458,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } ////////////////////////////////////////////////////////////////////////// @@ -470,7 +470,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -480,7 +480,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -490,7 +490,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -500,7 +500,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -510,7 +510,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -520,7 +520,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -530,7 +530,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -540,7 +540,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -550,7 +550,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/LowPassFilter.inl b/library/PolyVoxCore/include/PolyVoxCore/LowPassFilter.inl index 4d942519..22e476a9 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/LowPassFilter.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/LowPassFilter.inl @@ -192,8 +192,8 @@ namespace PolyVox { for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++) { - AccumulationType previousSum = static_cast(satVolume.getVoxelAt(x,y-1,z)); - AccumulationType currentSum = static_cast(satVolume.getVoxelAt(x,y,z)); + AccumulationType previousSum = static_cast(satVolume.getVoxel(x,y-1,z, WrapModes::Border)); + AccumulationType currentSum = static_cast(satVolume.getVoxel(x,y,z, WrapModes::Border)); satVolume.setVoxelAt(x,y,z,previousSum + currentSum); } @@ -206,8 +206,8 @@ namespace PolyVox { for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++) { - AccumulationType previousSum = static_cast(satVolume.getVoxelAt(x,y,z-1)); - AccumulationType currentSum = static_cast(satVolume.getVoxelAt(x,y,z)); + AccumulationType previousSum = static_cast(satVolume.getVoxel(x,y,z-1, WrapModes::Border)); + AccumulationType currentSum = static_cast(satVolume.getVoxel(x,y,z, WrapModes::Border)); satVolume.setVoxelAt(x,y,z,previousSum + currentSum); } @@ -234,14 +234,14 @@ namespace PolyVox int32_t satUpperY = iSrcY + border; int32_t satUpperZ = iSrcZ + border; - AccumulationType a = satVolume.getVoxelAt(satLowerX,satLowerY,satLowerZ); - AccumulationType b = satVolume.getVoxelAt(satUpperX,satLowerY,satLowerZ); - AccumulationType c = satVolume.getVoxelAt(satLowerX,satUpperY,satLowerZ); - AccumulationType d = satVolume.getVoxelAt(satUpperX,satUpperY,satLowerZ); - AccumulationType e = satVolume.getVoxelAt(satLowerX,satLowerY,satUpperZ); - AccumulationType f = satVolume.getVoxelAt(satUpperX,satLowerY,satUpperZ); - AccumulationType g = satVolume.getVoxelAt(satLowerX,satUpperY,satUpperZ); - AccumulationType h = satVolume.getVoxelAt(satUpperX,satUpperY,satUpperZ); + AccumulationType a = satVolume.getVoxel(satLowerX,satLowerY,satLowerZ, WrapModes::Border); + AccumulationType b = satVolume.getVoxel(satUpperX,satLowerY,satLowerZ, WrapModes::Border); + AccumulationType c = satVolume.getVoxel(satLowerX,satUpperY,satLowerZ, WrapModes::Border); + AccumulationType d = satVolume.getVoxel(satUpperX,satUpperY,satLowerZ, WrapModes::Border); + AccumulationType e = satVolume.getVoxel(satLowerX,satLowerY,satUpperZ, WrapModes::Border); + AccumulationType f = satVolume.getVoxel(satUpperX,satLowerY,satUpperZ, WrapModes::Border); + AccumulationType g = satVolume.getVoxel(satLowerX,satUpperY,satUpperZ, WrapModes::Border); + AccumulationType h = satVolume.getVoxel(satUpperX,satUpperY,satUpperZ, WrapModes::Border); AccumulationType sum = h+c-d-g-f-a+b+e; uint32_t sideLength = border * 2 + 1; diff --git a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h index e4549e1f..71f2be01 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h @@ -116,18 +116,26 @@ namespace PolyVox ~RawVolume(); /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + template + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const; /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxel(const Vector3DInt32& v3dPos) const; - /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; - /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; - /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType()) const; - /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType()) const; + template + VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const; + /// Gets a voxel at the position given by x,y,z coordinates + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; + /// Gets a voxel at the position given by a 3D vector + VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; + + /// Gets a voxel at the position given by x,y,z coordinates + POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + /// Gets a voxel at the position given by a 3D vector + POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; + + /// Sets the voxel at the position given by x,y,z coordinates + void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); + /// Sets the voxel at the position given by a 3D vector + void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); /// Sets the voxel at the position given by x,y,z coordinates bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue); /// Sets the voxel at the position given by a 3D vector @@ -146,6 +154,14 @@ namespace PolyVox private: void initialise(const Region& regValidRegion); + // A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057 + template + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + //The block data VoxelType* m_pData; }; diff --git a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl index dc6732e0..c76601b8 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl @@ -74,38 +74,83 @@ namespace PolyVox } //////////////////////////////////////////////////////////////////////////////// + /// This version of the function requires the wrap mode to be specified as a + /// template parameter, which can provide better performance. /// \param uXPos The \c x position of the voxel /// \param uYPos The \c y position of the voxel /// \param uZPos The \c z position of the voxel + /// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. /// \return The voxel value //////////////////////////////////////////////////////////////////////////////// template - VoxelType RawVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const + template + VoxelType RawVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const { - // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. - POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); - - const Vector3DInt32& v3dLowerCorner = this->m_regValidRegion.getLowerCorner(); - int32_t iLocalXPos = uXPos - v3dLowerCorner.getX(); - int32_t iLocalYPos = uYPos - v3dLowerCorner.getY(); - int32_t iLocalZPos = uZPos - v3dLowerCorner.getZ(); - - return m_pData - [ - iLocalXPos + - iLocalYPos * this->getWidth() + - iLocalZPos * this->getWidth() * this->getHeight() - ]; + // Simply call through to the real implementation + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); } //////////////////////////////////////////////////////////////////////////////// - /// \param v3dPos The 3D position of the voxel + /// This version of the function requires the wrap mode to be specified as a + /// template parameter, which can provide better performance. + /// \param uXPos The \c x position of the voxel + /// \param uYPos The \c y position of the voxel + /// \param uZPos The \c z position of the voxel + /// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. /// \return The voxel value //////////////////////////////////////////////////////////////////////////////// template - VoxelType RawVolume::getVoxel(const Vector3DInt32& v3dPos) const + template + VoxelType RawVolume::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const { - return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + // Simply call through to the real implementation + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder); + } + + //////////////////////////////////////////////////////////////////////////////// + /// This version of the function is provided so that the wrap mode does not need + /// to be specified as a template parameter, as it may be confusing to some users. + /// \param uXPos The \c x position of the voxel + /// \param uYPos The \c y position of the voxel + /// \param uZPos The \c z position of the voxel + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. + /// \return The voxel value + //////////////////////////////////////////////////////////////////////////////// + template + VoxelType RawVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const + { + switch(eWrapMode) + { + case WrapModes::Validate: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::Clamp: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::Border: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::AssumeValid: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + default: + // Should never happen + POLYVOX_ASSERT(false, "Invalid wrap mode"); + return VoxelType(); + } + } + + //////////////////////////////////////////////////////////////////////////////// + /// This version of the function is provided so that the wrap mode does not need + /// to be specified as a template parameter, as it may be confusing to some users. + /// \param v3dPos The 3D position of the voxel + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. + /// \return The voxel value + //////////////////////////////////////////////////////////////////////////////// + template + VoxelType RawVolume::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const + { + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder); } //////////////////////////////////////////////////////////////////////////////// @@ -148,58 +193,53 @@ namespace PolyVox } //////////////////////////////////////////////////////////////////////////////// - /// \param uXPos The \c x position of the voxel - /// \param uYPos The \c y position of the voxel - /// \param uZPos The \c z position of the voxel - /// \return The voxel value + /// \param uXPos the \c x position of the voxel + /// \param uYPos the \c y position of the voxel + /// \param uZPos the \c z position of the voxel + /// \param tValue the value to which the voxel will be set + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data. //////////////////////////////////////////////////////////////////////////////// template - VoxelType RawVolume::getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const + void RawVolume::setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode) { - switch(eWrapMode) + if((eWrapMode != WrapModes::Validate) && (eWrapMode != WrapModes::AssumeValid)) { - 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()); + POLYVOX_THROW(std::invalid_argument, "Invalid wrap mode in call to setVoxel(). It must be 'None' or 'DontCheck'."); + } - //Get the voxel value - return getVoxel(uXPos, uYPos, uZPos); - //No need to break as we've returned - } - case WrapModes::Border: + // This validation is skipped if the wrap mode is 'DontCheck' + if(eWrapMode == WrapModes::Validate) + { + if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false) { - if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos)) - { - return getVoxel(uXPos, uYPos, uZPos); - } - else - { - return tBorder; - } - //No need to break as we've returned - } - default: - { - //Should never happen - POLYVOX_THROW(std::invalid_argument, "Wrap mode parameter has an unrecognised value."); + POLYVOX_THROW(std::out_of_range, "Position is outside valid region"); } } + + const Vector3DInt32& v3dLowerCorner = this->m_regValidRegion.getLowerCorner(); + int32_t iLocalXPos = uXPos - v3dLowerCorner.getX(); + int32_t iLocalYPos = uYPos - v3dLowerCorner.getY(); + int32_t iLocalZPos = uZPos - v3dLowerCorner.getZ(); + + m_pData + [ + iLocalXPos + + iLocalYPos * this->getWidth() + + iLocalZPos * this->getWidth() * this->getHeight() + ] = tValue; } //////////////////////////////////////////////////////////////////////////////// - /// \param v3dPos The 3D position of the voxel - /// \return The voxel value + /// \param v3dPos the 3D position of the voxel + /// \param tValue the value to which the voxel will be set + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data. //////////////////////////////////////////////////////////////////////////////// template - VoxelType RawVolume::getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const + void RawVolume::setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode) { - return getVoxelWithWrapping(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder); + setVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue, eWrapMode); } //////////////////////////////////////////////////////////////////////////////// @@ -285,5 +325,66 @@ namespace PolyVox return this->getWidth() * this->getHeight() * this->getDepth() * sizeof(VoxelType); } + template + template + VoxelType RawVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + // This function should never be called because one of the specialisations should always match. + POLYVOX_ASSERT(false, "This function is not implemented and should never be called!"); + } + + template + VoxelType RawVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false) + { + POLYVOX_THROW(std::out_of_range, "Position is outside valid region"); + } + + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + + template + VoxelType RawVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + //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 getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + + template + VoxelType RawVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos)) + { + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + else + { + return tBorder; + } + } + + template + VoxelType RawVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType /*tBorder*/) const + { + const Vector3DInt32& v3dLowerCorner = this->m_regValidRegion.getLowerCorner(); + int32_t iLocalXPos = uXPos - v3dLowerCorner.getX(); + int32_t iLocalYPos = uYPos - v3dLowerCorner.getY(); + int32_t iLocalZPos = uZPos - v3dLowerCorner.getZ(); + + return m_pData + [ + iLocalXPos + + iLocalYPos * this->getWidth() + + iLocalZPos * this->getWidth() * this->getHeight() + ]; + } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/RawVolumeSampler.inl b/library/PolyVoxCore/include/PolyVoxCore/RawVolumeSampler.inl index 3124e4c8..6de3f3df 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RawVolumeSampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/RawVolumeSampler.inl @@ -51,7 +51,7 @@ namespace PolyVox } else { - return getVoxelAt(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); + return getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); } } @@ -229,7 +229,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -239,7 +239,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->getWidth()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -249,7 +249,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -259,7 +259,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -269,7 +269,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -279,7 +279,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -289,7 +289,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -299,7 +299,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->getWidth()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -309,7 +309,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } ////////////////////////////////////////////////////////////////////////// @@ -321,7 +321,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -331,7 +331,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->getWidth()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -341,7 +341,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -351,7 +351,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -361,7 +361,7 @@ namespace PolyVox { return *mCurrentVoxel; } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -371,7 +371,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -381,7 +381,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -391,7 +391,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->getWidth()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -401,7 +401,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } ////////////////////////////////////////////////////////////////////////// @@ -413,7 +413,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -423,7 +423,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->getWidth()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -433,7 +433,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -443,7 +443,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -453,7 +453,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -463,7 +463,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -473,7 +473,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->getWidth() - this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -483,7 +483,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->getWidth()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -493,7 +493,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->getWidth() + this->mVolume->getWidth() * this->mVolume->getHeight()); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/Region.h b/library/PolyVoxCore/include/PolyVoxCore/Region.h index 55c51ee4..655b3bce 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Region.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Region.h @@ -149,6 +149,9 @@ namespace PolyVox /// Tests whether the given position is contained in the 'z' range of this Region. bool containsPointInZ(int32_t pos, uint8_t boundary = 0) const; + /// Tests whether the given Region is contained in this Region. + bool containsRegion(const Region& reg, uint8_t boundary = 0) const; + /// Enlarges the Region so that it contains the specified position. void accumulate(int32_t iX, int32_t iY, int32_t iZ); /// Enlarges the Region so that it contains the specified position. diff --git a/library/PolyVoxCore/include/PolyVoxCore/SimpleVolume.h b/library/PolyVoxCore/include/PolyVoxCore/SimpleVolume.h index 8ce2083e..e8dda3e3 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/SimpleVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/SimpleVolume.h @@ -155,18 +155,26 @@ namespace PolyVox ~SimpleVolume(); /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + template + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const; /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxel(const Vector3DInt32& v3dPos) const; - /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; - /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; - /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType()) const; - /// Gets a voxel at the position given by a 3D vector - VoxelType getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Border, VoxelType tBorder = VoxelType()) const; + template + VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const; + /// Gets a voxel at the position given by x,y,z coordinates + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; + /// Gets a voxel at the position given by a 3D vector + VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; + + /// Gets a voxel at the position given by x,y,z coordinates + POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; + /// Gets a voxel at the position given by a 3D vector + POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const; + + /// Sets the voxel at the position given by x,y,z coordinates + void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); + /// Sets the voxel at the position given by a 3D vector + void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); /// Sets the voxel at the position given by x,y,z coordinates bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue); /// Sets the voxel at the position given by a 3D vector @@ -185,6 +193,14 @@ namespace PolyVox private: void initialise(const Region& regValidRegion, uint16_t uBlockSideLength); + // A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057 + template + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const; + Block* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; //The block data diff --git a/library/PolyVoxCore/include/PolyVoxCore/SimpleVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/SimpleVolume.inl index decbcfce..f32aacdd 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/SimpleVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/SimpleVolume.inl @@ -74,38 +74,83 @@ namespace PolyVox } //////////////////////////////////////////////////////////////////////////////// + /// This version of the function requires the wrap mode to be specified as a + /// template parameter, which can provide better performance. /// \param uXPos The \c x position of the voxel /// \param uYPos The \c y position of the voxel /// \param uZPos The \c z position of the voxel + /// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. /// \return The voxel value //////////////////////////////////////////////////////////////////////////////// template - VoxelType SimpleVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const + template + VoxelType SimpleVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const { - // PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual. - POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region"); - - const int32_t blockX = uXPos >> m_uBlockSideLengthPower; - const int32_t blockY = uYPos >> m_uBlockSideLengthPower; - const int32_t blockZ = uZPos >> m_uBlockSideLengthPower; - - const uint16_t xOffset = static_cast(uXPos - (blockX << m_uBlockSideLengthPower)); - const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); - const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); - - typename SimpleVolume::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); - - return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset); + // Simply call through to the real implementation + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); } //////////////////////////////////////////////////////////////////////////////// - /// \param v3dPos The 3D position of the voxel + /// This version of the function requires the wrap mode to be specified as a + /// template parameter, which can provide better performance. + /// \param uXPos The \c x position of the voxel + /// \param uYPos The \c y position of the voxel + /// \param uZPos The \c z position of the voxel + /// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. /// \return The voxel value //////////////////////////////////////////////////////////////////////////////// template - VoxelType SimpleVolume::getVoxel(const Vector3DInt32& v3dPos) const + template + VoxelType SimpleVolume::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const { - return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + // Simply call through to the real implementation + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder); + } + + //////////////////////////////////////////////////////////////////////////////// + /// This version of the function is provided so that the wrap mode does not need + /// to be specified as a template parameter, as it may be confusing to some users. + /// \param uXPos The \c x position of the voxel + /// \param uYPos The \c y position of the voxel + /// \param uZPos The \c z position of the voxel + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. + /// \return The voxel value + //////////////////////////////////////////////////////////////////////////////// + template + VoxelType SimpleVolume::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const + { + switch(eWrapMode) + { + case WrapModes::Validate: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::Clamp: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::Border: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + case WrapModes::AssumeValid: + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); + default: + // Should never happen + POLYVOX_ASSERT(false, "Invalid wrap mode"); + return VoxelType(); + } + } + + //////////////////////////////////////////////////////////////////////////////// + /// This version of the function is provided so that the wrap mode does not need + /// to be specified as a template parameter, as it may be confusing to some users. + /// \param v3dPos The 3D position of the voxel + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// \param tBorder The border value to use if the wrap mode is set to 'Border'. + /// \return The voxel value + //////////////////////////////////////////////////////////////////////////////// + template + VoxelType SimpleVolume::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const + { + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder); } //////////////////////////////////////////////////////////////////////////////// @@ -148,58 +193,53 @@ namespace PolyVox } //////////////////////////////////////////////////////////////////////////////// - /// \param uXPos The \c x position of the voxel - /// \param uYPos The \c y position of the voxel - /// \param uZPos The \c z position of the voxel - /// \return The voxel value + /// \param uXPos the \c x position of the voxel + /// \param uYPos the \c y position of the voxel + /// \param uZPos the \c z position of the voxel + /// \param tValue the value to which the voxel will be set + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data. //////////////////////////////////////////////////////////////////////////////// template - VoxelType SimpleVolume::getVoxelWithWrapping(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const + void SimpleVolume::setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode) { - switch(eWrapMode) + if((eWrapMode != WrapModes::Validate) && (eWrapMode != WrapModes::AssumeValid)) { - 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()); + POLYVOX_THROW(std::invalid_argument, "Invalid wrap mode in call to setVoxel(). It must be 'None' or 'DontCheck'."); + } - //Get the voxel value - return getVoxel(uXPos, uYPos, uZPos); - //No need to break as we've returned - } - case WrapModes::Border: + // This validation is skipped if the wrap mode is 'DontCheck' + if(eWrapMode == WrapModes::Validate) + { + if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false) { - if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos)) - { - return getVoxel(uXPos, uYPos, uZPos); - } - else - { - return tBorder; - } - //No need to break as we've returned - } - default: - { - //Should never happen - POLYVOX_THROW(std::invalid_argument, "Wrap mode parameter has an unrecognised value."); + POLYVOX_THROW(std::out_of_range, "Position is outside valid region"); } } + + const int32_t blockX = uXPos >> m_uBlockSideLengthPower; + const int32_t blockY = uYPos >> m_uBlockSideLengthPower; + const int32_t blockZ = uZPos >> m_uBlockSideLengthPower; + + const uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower); + const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); + const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); + + typename SimpleVolume::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); + + pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue); } //////////////////////////////////////////////////////////////////////////////// - /// \param v3dPos The 3D position of the voxel - /// \return The voxel value + /// \param v3dPos the 3D position of the voxel + /// \param tValue the value to which the voxel will be set + /// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume. + /// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data. //////////////////////////////////////////////////////////////////////////////// template - VoxelType SimpleVolume::getVoxelWithWrapping(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const + void SimpleVolume::setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode) { - return getVoxelWithWrapping(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder); + setVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue, eWrapMode); } //////////////////////////////////////////////////////////////////////////////// @@ -336,5 +376,66 @@ namespace PolyVox return uSizeInBytes; } + template + template + VoxelType SimpleVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + // This function should never be called because one of the specialisations should always match. + POLYVOX_ASSERT(false, "This function is not implemented and should never be called!"); + } + + template + VoxelType SimpleVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false) + { + POLYVOX_THROW(std::out_of_range, "Position is outside valid region"); + } + + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + + template + VoxelType SimpleVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + //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 getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + + template + VoxelType SimpleVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType tBorder) const + { + if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos)) + { + return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType(), tBorder); // No wrapping as we've just validated the position. + } + else + { + return tBorder; + } + } + + template + VoxelType SimpleVolume::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType, VoxelType /*tBorder*/) const + { + const int32_t blockX = uXPos >> m_uBlockSideLengthPower; + const int32_t blockY = uYPos >> m_uBlockSideLengthPower; + const int32_t blockZ = uZPos >> m_uBlockSideLengthPower; + + const uint16_t xOffset = static_cast(uXPos - (blockX << m_uBlockSideLengthPower)); + const uint16_t yOffset = static_cast(uYPos - (blockY << m_uBlockSideLengthPower)); + const uint16_t zOffset = static_cast(uZPos - (blockZ << m_uBlockSideLengthPower)); + + typename SimpleVolume::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); + + return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset); + } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/SimpleVolumeSampler.inl b/library/PolyVoxCore/include/PolyVoxCore/SimpleVolumeSampler.inl index 117651a4..a4892f26 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/SimpleVolumeSampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/SimpleVolumeSampler.inl @@ -94,7 +94,7 @@ namespace PolyVox } else { - return getVoxelAt(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); + return getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); } } @@ -305,7 +305,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -315,7 +315,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -325,7 +325,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -335,7 +335,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -345,7 +345,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -355,7 +355,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -365,7 +365,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -375,7 +375,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -385,7 +385,7 @@ namespace PolyVox { return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } ////////////////////////////////////////////////////////////////////////// @@ -397,7 +397,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -407,7 +407,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -417,7 +417,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -427,7 +427,7 @@ namespace PolyVox { return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -437,7 +437,7 @@ namespace PolyVox { return *mCurrentVoxel; } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -447,7 +447,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -457,7 +457,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -467,7 +467,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -477,7 +477,7 @@ namespace PolyVox { return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } ////////////////////////////////////////////////////////////////////////// @@ -489,7 +489,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -499,7 +499,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -509,7 +509,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -519,7 +519,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -529,7 +529,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -539,7 +539,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } template @@ -549,7 +549,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); } template @@ -559,7 +559,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); } template @@ -569,7 +569,7 @@ namespace PolyVox { return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); } - return this->mVolume->getVoxelWithWrapping(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); + return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl index 745a00bc..2c6c129d 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl @@ -72,7 +72,7 @@ namespace PolyVox { for(int32_t sx = m_regSrc.getLowerX(), dx = m_regDst.getLowerX(); dx <= m_regDst.getUpperX(); sx++,dx++) { - const typename SrcVolumeType::VoxelType& tSrcVoxel = m_pVolSrc->getVoxelAt(sx,sy,sz); + const typename SrcVolumeType::VoxelType& tSrcVoxel = m_pVolSrc->getVoxel(sx,sy,sz, WrapModes::AssumeValid); // FIXME use templatised version of getVoxel(), but watch out for Linux compile issues. const typename DstVolumeType::VoxelType& tDstVoxel = static_cast(tSrcVoxel); m_pVolDst->setVoxelAt(dx,dy,dz,tDstVoxel); } diff --git a/library/PolyVoxCore/source/Region.cpp b/library/PolyVoxCore/source/Region.cpp index 3db2edd6..444a1770 100644 --- a/library/PolyVoxCore/source/Region.cpp +++ b/library/PolyVoxCore/source/Region.cpp @@ -301,6 +301,23 @@ namespace PolyVox && (pos >= m_iLowerZ + boundary); } + /** + * The boundary value can be used to ensure a region is only considered to be inside + * another Region if it is that far in in all directions. Also, the test is inclusive such + * that a region is considered to be inside of itself. + * \param reg The region to test. + * \param boundary The desired boundary value. + */ + bool Region::containsRegion(const Region& reg, uint8_t boundary) const + { + return (reg.m_iUpperX <= m_iUpperX - boundary) + && (reg.m_iUpperY <= m_iUpperY - boundary) + && (reg.m_iUpperZ <= m_iUpperZ - boundary) + && (reg.m_iLowerX >= m_iLowerX + boundary) + && (reg.m_iLowerY >= m_iLowerY + boundary) + && (reg.m_iLowerZ >= m_iLowerZ + boundary); + } + /** * After calling this functions, the extents of this Region are given by the intersection * of this Region and the one it was cropped to. diff --git a/tests/TestAStarPathfinder.cpp b/tests/TestAStarPathfinder.cpp index 870b88e1..e36752f5 100644 --- a/tests/TestAStarPathfinder.cpp +++ b/tests/TestAStarPathfinder.cpp @@ -40,7 +40,7 @@ bool testVoxelValidator(const VolumeType* volData, const Vector3DInt32& v3dPos) return false; } - typename VolumeType::VoxelType voxel = volData->getVoxelAt(v3dPos); + 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; diff --git a/tests/TestLowPassFilter.cpp b/tests/TestLowPassFilter.cpp index 902c26d6..5af198b9 100644 --- a/tests/TestLowPassFilter.cpp +++ b/tests/TestLowPassFilter.cpp @@ -64,27 +64,27 @@ void TestLowPassFilter::testExecute() QBENCHMARK { lowPassfilter.execute(); } - QCOMPARE(resultVolume.getVoxelAt(0,0,0), Density8(4)); - QCOMPARE(resultVolume.getVoxelAt(1,1,1), Density8(21)); - QCOMPARE(resultVolume.getVoxelAt(2,2,2), Density8(10)); - QCOMPARE(resultVolume.getVoxelAt(3,3,3), Density8(21)); - QCOMPARE(resultVolume.getVoxelAt(4,4,4), Density8(10)); - QCOMPARE(resultVolume.getVoxelAt(5,5,5), Density8(21)); - QCOMPARE(resultVolume.getVoxelAt(6,6,6), Density8(10)); - QCOMPARE(resultVolume.getVoxelAt(7,7,7), Density8(4)); + QCOMPARE(resultVolume.getVoxel(0,0,0), Density8(4)); + QCOMPARE(resultVolume.getVoxel(1,1,1), Density8(21)); + QCOMPARE(resultVolume.getVoxel(2,2,2), Density8(10)); + QCOMPARE(resultVolume.getVoxel(3,3,3), Density8(21)); + QCOMPARE(resultVolume.getVoxel(4,4,4), Density8(10)); + QCOMPARE(resultVolume.getVoxel(5,5,5), Density8(21)); + QCOMPARE(resultVolume.getVoxel(6,6,6), Density8(10)); + QCOMPARE(resultVolume.getVoxel(7,7,7), Density8(4)); //Test the SAT implmentation QBENCHMARK { lowPassfilter.executeSAT(); } - QCOMPARE(resultVolume.getVoxelAt(0,0,0), Density8(4)); - QCOMPARE(resultVolume.getVoxelAt(1,1,1), Density8(21)); - QCOMPARE(resultVolume.getVoxelAt(2,2,2), Density8(10)); - QCOMPARE(resultVolume.getVoxelAt(3,3,3), Density8(21)); - QCOMPARE(resultVolume.getVoxelAt(4,4,4), Density8(10)); - QCOMPARE(resultVolume.getVoxelAt(5,5,5), Density8(21)); - QCOMPARE(resultVolume.getVoxelAt(6,6,6), Density8(10)); - QCOMPARE(resultVolume.getVoxelAt(7,7,7), Density8(4)); + QCOMPARE(resultVolume.getVoxel(0,0,0), Density8(4)); + QCOMPARE(resultVolume.getVoxel(1,1,1), Density8(21)); + QCOMPARE(resultVolume.getVoxel(2,2,2), Density8(10)); + QCOMPARE(resultVolume.getVoxel(3,3,3), Density8(21)); + QCOMPARE(resultVolume.getVoxel(4,4,4), Density8(10)); + QCOMPARE(resultVolume.getVoxel(5,5,5), Density8(21)); + QCOMPARE(resultVolume.getVoxel(6,6,6), Density8(10)); + QCOMPARE(resultVolume.getVoxel(7,7,7), Density8(4)); } QTEST_MAIN(TestLowPassFilter) diff --git a/tests/TestVolumeSubclass.cpp b/tests/TestVolumeSubclass.cpp index e70afb92..91a619b4 100644 --- a/tests/TestVolumeSubclass.cpp +++ b/tests/TestVolumeSubclass.cpp @@ -68,22 +68,77 @@ public: /// Destructor ~VolumeSubclass() {}; - /// Gets the value used for voxels which are outside the volume - VoxelType getBorderValue(void) const { return 0; } /// Gets a voxel at the position given by x,y,z coordinates - VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const + template + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const { - if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos))) + // 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 + VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const + { + // Simply call through to the real implementation + return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder); + } + + /// Gets a voxel at the position given by x,y,z coordinates + VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const + { + switch(eWrapMode) { - return mVolumeData[uXPos][uYPos][uZPos]; - } - else - { - return getBorderValue(); + 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 getVoxelAt(const Vector3DInt32& v3dPos) const { return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); } + 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) { } diff --git a/tests/testvolume.cpp b/tests/testvolume.cpp index 2bd15cbd..dd000a88 100644 --- a/tests/testvolume.cpp +++ b/tests/testvolume.cpp @@ -76,7 +76,7 @@ int32_t testDirectAccessWithWrappingForwards(const VolumeType* volume, int lowXO } else { - result = cantorTupleFunction(result, volume->getVoxelWithWrapping(x + innerX, y + innerY, z + innerZ, WrapModes::Border, 3)); + result = cantorTupleFunction(result, volume->getVoxel(x + innerX, y + innerY, z + innerZ, WrapModes::Border, 3)); } } } @@ -189,7 +189,7 @@ int32_t testDirectAccessWithWrappingBackwards(const VolumeType* volume, int lowX } else { - result = cantorTupleFunction(result, volume->getVoxelWithWrapping(x + innerX, y + innerY, z + innerZ, WrapModes::Border, 3)); + result = cantorTupleFunction(result, volume->getVoxel(x + innerX, y + innerY, z + innerZ, WrapModes::Border, 3)); } } }