diff --git a/library/PolyVoxCore/include/Volume.h b/library/PolyVoxCore/include/Volume.h index b9e3a571..440ff945 100644 --- a/library/PolyVoxCore/include/Volume.h +++ b/library/PolyVoxCore/include/Volume.h @@ -37,72 +37,72 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. namespace PolyVox { ///The Volume class provides a memory efficient method of storing voxel data while also allowing fast access and modification. - /******************************************************************************* - A Volume is essentially a '3D image' in which each element (voxel) is identified - by a three dimensional (x,y,z) coordinate, rather than the two dimensional (x,y) - coordinate which is used to identify an element (pixel) in a normal image. Within - PolyVox, the Volume class is used to store and manipulate our data before we extract - our SurfacePatch's from it. - - Data Representaion - feel free to skip - If stored carelessly, volume data can take up a huge amount of memory. For example, a - volume of dimensions 1024x1024x1024 with 1 byte per voxel will require 1GB of memory - if stored in an uncompressed form. Natuarally our Volume class is much more efficient - than this and it is worth understanding (at least at a high level) the approach - which is used. - - Essentially, the Volume class stores its data as a collection of blocks. Each - of these block is much smaller than the whole volume, for example a typical size - might be 32x32x32 voxels (though is is configurable by the user). In this case, - a 256x512x1024 volume would contain 8x16x32 = 4096 blocks. However, it is unlikely that - all these blocks actually have to be stored because usually there are duplicates - in which case common data can be shared. - - Identifying duplicate blocks is in general a difficult task which involves looking at pairs - of blocks and comparing all the voxels. This is a time consuming task which is not amiable - to being performed when the volume is being modified in real time. However, there are two - specific scenarios which are easily spotted and which PolyVox uses to identify block - sharing opportunities. - - -# Homogeneous blocks (those which contain just a single voxel value) are easy to - spot and fairly common becuase volumes often contain large homogeous regions. Any time - you change the value of a voxel you have potentially made the block which contains - it homogeneous. PolyVox does not check the homogeneity immediatly as this would slow - down the process of modifying voxels, but you can use the tidyUpMemory() function - to check for and remove duplicate homogeneous regions whenever you have spare - processing time. - - -# Copying a volume naturally means that all the voxels in the second voluem are - the same as the first. Therefore volume copying is a relatively fast operation in - which all the blocks in the second volume simply reference the first volume. Future - modifications to either volume will, of course, cause the blocks to become unshared. - - Other advantages of breaking the volume down into blocks include enhancing data locality - (i.e. voxels which are spatially near to each other are also likely to be near in - memory) and the ability to load larger volumes as no large contiguous areas of - memory are needed. However, these advantages are more transparent to user code - so we will not dwell on them here. - - Usage - Volumes are constructed by passing the desired width height and depth to the - constructor. Note that for speed reasons only values which are a power of two - are permitted for these sidelengths. - - Access to specific voxels is provided by the getVoxelAt() and setVoxelAt fuctions. - Each of these has two forms so that voxels can be identified by integer triples - or by Vector3DUint16's. - - The tidyUpMemory() function should normally be called after you first populate - the volume with data, and then at periodic intervals as the volume is modified. - However, you don't actually have to call it at all. See the functions - documentation for further details. - - One further important point of note is that this class is templatised on the voxel - type. This allows you to store volumes of data types you might not normally expect, - for example theOpenGL example 'abuses' this class to store a 3D grid of pointers. - However, it is not guarentted that all functionality works correctly with non-integer - voxel types. - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// A Volume is essentially a '3D image' in which each element (voxel) is identified + /// by a three dimensional (x,y,z) coordinate, rather than the two dimensional (x,y) + /// coordinate which is used to identify an element (pixel) in a normal image. Within + /// PolyVox, the Volume class is used to store and manipulate our data before we extract + /// our SurfacePatch's from it. + /// + /// Data Representaion - feel free to skip + /// If stored carelessly, volume data can take up a huge amount of memory. For example, a + /// volume of dimensions 1024x1024x1024 with 1 byte per voxel will require 1GB of memory + /// if stored in an uncompressed form. Natuarally our Volume class is much more efficient + /// than this and it is worth understanding (at least at a high level) the approach + /// which is used. + /// + /// Essentially, the Volume class stores its data as a collection of blocks. Each + /// of these block is much smaller than the whole volume, for example a typical size + /// might be 32x32x32 voxels (though is is configurable by the user). In this case, + /// a 256x512x1024 volume would contain 8x16x32 = 4096 blocks. However, it is unlikely that + /// all these blocks actually have to be stored because usually there are duplicates + /// in which case common data can be shared. + /// + /// Identifying duplicate blocks is in general a difficult task which involves looking at pairs + /// of blocks and comparing all the voxels. This is a time consuming task which is not amiable + /// to being performed when the volume is being modified in real time. However, there are two + /// specific scenarios which are easily spotted and which PolyVox uses to identify block + /// sharing opportunities. + /// + /// -# Homogeneous blocks (those which contain just a single voxel value) are easy to + /// spot and fairly common becuase volumes often contain large homogeous regions. Any time + /// you change the value of a voxel you have potentially made the block which contains + /// it homogeneous. PolyVox does not check the homogeneity immediatly as this would slow + /// down the process of modifying voxels, but you can use the tidyUpMemory() function + /// to check for and remove duplicate homogeneous regions whenever you have spare + /// processing time. + /// + /// -# Copying a volume naturally means that all the voxels in the second voluem are + /// the same as the first. Therefore volume copying is a relatively fast operation in + /// which all the blocks in the second volume simply reference the first volume. Future + /// modifications to either volume will, of course, cause the blocks to become unshared. + /// + /// Other advantages of breaking the volume down into blocks include enhancing data locality + /// (i.e. voxels which are spatially near to each other are also likely to be near in + /// memory) and the ability to load larger volumes as no large contiguous areas of + /// memory are needed. However, these advantages are more transparent to user code + /// so we will not dwell on them here. + /// + /// Usage + /// Volumes are constructed by passing the desired width height and depth to the + /// constructor. Note that for speed reasons only values which are a power of two + /// are permitted for these sidelengths. + /// + /// Access to specific voxels is provided by the getVoxelAt() and setVoxelAt fuctions. + /// Each of these has two forms so that voxels can be identified by integer triples + /// or by Vector3DUint16's. + /// + /// The tidyUpMemory() function should normally be called after you first populate + /// the volume with data, and then at periodic intervals as the volume is modified. + /// However, you don't actually have to call it at all. See the functions + /// documentation for further details. + /// + /// One further important point of note is that this class is templatised on the voxel + /// type. This allows you to store volumes of data types you might not normally expect, + /// for example theOpenGL example 'abuses' this class to store a 3D grid of pointers. + /// However, it is not guarentted that all functionality works correctly with non-integer + /// voxel types. + //////////////////////////////////////////////////////////////////////////////// template class Volume { diff --git a/library/PolyVoxCore/include/Volume.inl b/library/PolyVoxCore/include/Volume.inl index aceb8155..64fa1f5f 100644 --- a/library/PolyVoxCore/include/Volume.inl +++ b/library/PolyVoxCore/include/Volume.inl @@ -35,20 +35,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. namespace PolyVox { #pragma region Constructors/Destructors - /******************************************************************************* - Builds a volume of the desired dimensions - \param uWidth The desired width in voxels. This must be a power of two. - \param uHeight The desired height in voxels. This must be a power of two. - \param uDepth The desired depth in voxels. This must be a power of two. - \param uBlockSideLength The size of the blocks which make up the volume. Small - blocks are more likely to be homogeneous (so more easily shared) and have better - cache behaviour. However, there is a memory overhead per block so if they are - not shared it could actually be less efficient (this will depend on the data). - The size of the volume may also be a factor when choosing block size. Specifying - '0' for the block side length will cause the blocks to be as large as possible, - which will basically be the length of the shortest side. Accept the default if - you are not sure what to choose here. - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// Builds a volume of the desired dimensions + /// \param uWidth The desired width in voxels. This must be a power of two. + /// \param uHeight The desired height in voxels. This must be a power of two. + /// \param uDepth The desired depth in voxels. This must be a power of two. + /// \param uBlockSideLength The size of the blocks which make up the volume. Small + /// blocks are more likely to be homogeneous (so more easily shared) and have better + /// cache behaviour. However, there is a memory overhead per block so if they are + /// not shared it could actually be less efficient (this will depend on the data). + /// The size of the volume may also be a factor when choosing block size. Specifying + /// '0' for the block side length will cause the blocks to be as large as possible, + /// which will basically be the length of the shortest side. Accept the default if + /// you are not sure what to choose here. + //////////////////////////////////////////////////////////////////////////////// template Volume::Volume(uint16_t uWidth, uint16_t uHeight, uint16_t uDepth, uint16_t uBlockSideLength) :m_pBlocks(0) @@ -130,9 +130,9 @@ namespace PolyVox m_fDiagonalLength = sqrtf(static_cast(m_uWidth * m_uWidth + m_uHeight * m_uHeight + m_uDepth * m_uDepth)); } - /******************************************************************************* - Destroys the volume and frees any blocks which are not in use by other volumes. - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// Destroys the volume and frees any blocks which are not in use by other volumes. + //////////////////////////////////////////////////////////////////////////////// template Volume::~Volume() { @@ -143,76 +143,76 @@ namespace PolyVox #pragma endregion #pragma region Getters - /******************************************************************************* - The result will always have a lower corner at (0,0,0) and an upper corner at one - less than the side length. For example, if a volume has dimensions 256x512x1024 - then the upper corner of the enclosing region will be at (255,511,1023). - \return A Region representing the extent of the volume. - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// The result will always have a lower corner at (0,0,0) and an upper corner at one + /// less than the side length. For example, if a volume has dimensions 256x512x1024 + /// then the upper corner of the enclosing region will be at (255,511,1023). + /// \return A Region representing the extent of the volume. + //////////////////////////////////////////////////////////////////////////////// template Region Volume::getEnclosingRegion(void) const { return Region(Vector3DInt32(0,0,0), Vector3DInt32(m_uWidth-1,m_uHeight-1,m_uDepth-1)); } - /******************************************************************************* - \return The width of the volume in voxels - \sa getHeight(), getDepth() - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// \return The width of the volume in voxels + /// \sa getHeight(), getDepth() + //////////////////////////////////////////////////////////////////////////////// template uint16_t Volume::getWidth(void) const { return m_uWidth; } - /******************************************************************************* - \return The height of the volume in voxels - \sa getWidth(), getDepth() - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// \return The height of the volume in voxels + /// \sa getWidth(), getDepth() + //////////////////////////////////////////////////////////////////////////////// template uint16_t Volume::getHeight(void) const { return m_uHeight; } - /******************************************************************************* - \return The depth of the volume in voxels - \sa getWidth(), getHeight() - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// \return The depth of the volume in voxels + /// \sa getWidth(), getHeight() + //////////////////////////////////////////////////////////////////////////////// template uint16_t Volume::getDepth(void) const { return m_uDepth; } - /******************************************************************************* - \return The length of the shortest side in voxels. For example, if a volume has - dimensions 256x512x1024 this function will return 256. - \sa getLongestSideLength(), getDiagonalLength() - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// \return The length of the shortest side in voxels. For example, if a volume has + /// dimensions 256x512x1024 this function will return 256. + /// \sa getLongestSideLength(), getDiagonalLength() + //////////////////////////////////////////////////////////////////////////////// template uint16_t Volume::getShortestSideLength(void) const { return m_uShortestSideLength; } - /******************************************************************************* - \return The length of the longest side in voxels. For example, if a volume has - dimensions 256x512x1024 this function will return 1024. - \sa getShortestSideLength(), getDiagonalLength() - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// \return The length of the longest side in voxels. For example, if a volume has + /// dimensions 256x512x1024 this function will return 1024. + /// \sa getShortestSideLength(), getDiagonalLength() + //////////////////////////////////////////////////////////////////////////////// template uint16_t Volume::getLongestSideLength(void) const { return m_uLongestSideLength; } - /******************************************************************************* - \return The length of the diagonal in voxels. For example, if a volume has - dimensions 256x512x1024 this function will return sqrt(256*256+512*512+1024*1024) - = 1173.139. This value is computed on volume creation so retrieving it is fast. - \sa getShortestSideLength(), getLongestSideLength() - *******************************************************************************/ + //////////////////////////////////////////////////////////////////////////////// + /// \return The length of the diagonal in voxels. For example, if a volume has + /// dimensions 256x512x1024 this function will return sqrt(256*256+512*512+1024*1024) + /// = 1173.139. This value is computed on volume creation so retrieving it is fast. + /// \sa getShortestSideLength(), getLongestSideLength() + //////////////////////////////////////////////////////////////////////////////// template float Volume::getDiagonalLength(void) const {