Renamed LargeVolume to PagedVolume, deleted SimpleVolume, and set up typedefs pointing LargeVolume and SimpleVolume to PagedVolume for backwards compatibility.
This commit is contained in:
		| @@ -32,7 +32,7 @@ freely, subject to the following restrictions: | ||||
| namespace PolyVox | ||||
| { | ||||
| 	/// The BaseVolume class provides common functionality and an interface for other volume classes to implement. You should not try to create an instance of this | ||||
| 	/// class directly. Instead you should use RawVolume, SimpleVolume, or LargeVolume. | ||||
| 	/// class directly. Instead you should use RawVolume, SimpleVolume, or PagedVolume. | ||||
| 	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// More details to come... | ||||
| 	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|   | ||||
| @@ -26,7 +26,7 @@ namespace PolyVox | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// This is protected because you should never create a BaseVolume directly, you should instead use one of the derived classes. | ||||
| 	/// | ||||
| 	/// \sa RawVolume, SimpleVolume, LargeVolume | ||||
| 	/// \sa RawVolume, SimpleVolume, PagedVolume | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	BaseVolume<VoxelType>::BaseVolume(const Region& regValid) | ||||
|   | ||||
| @@ -1,333 +1,7 @@ | ||||
| /******************************************************************************* | ||||
| Copyright (c) 2005-2009 David Williams | ||||
|  | ||||
| This software is provided 'as-is', without any express or implied | ||||
| warranty. In no event will the authors be held liable for any damages | ||||
| arising from the use of this software. | ||||
|  | ||||
| Permission is granted to anyone to use this software for any purpose, | ||||
| including commercial applications, and to alter it and redistribute it | ||||
| freely, subject to the following restrictions: | ||||
|  | ||||
|     1. The origin of this software must not be misrepresented; you must not | ||||
|     claim that you wrote the original software. If you use this software | ||||
|     in a product, an acknowledgment in the product documentation would be | ||||
|     appreciated but is not required. | ||||
|  | ||||
|     2. Altered source versions must be plainly marked as such, and must not be | ||||
|     misrepresented as being the original software. | ||||
|  | ||||
|     3. This notice may not be removed or altered from any source | ||||
|     distribution. 	 | ||||
| *******************************************************************************/ | ||||
|  | ||||
| #ifndef __PolyVox_LargeVolume_H__ | ||||
| #define __PolyVox_LargeVolume_H__ | ||||
|  | ||||
| #include "PolyVoxCore/BaseVolume.h" | ||||
| #include "PolyVoxCore/Pager.h" | ||||
| #include "PolyVoxCore/Region.h" | ||||
| #include "PolyVoxCore/UncompressedBlock.h" | ||||
| #include "PolyVoxCore/Vector.h" | ||||
| #include "PagedVolume.h" | ||||
| #include "PolyVoxForwardDeclarations.h" | ||||
|  | ||||
| #include <limits> | ||||
| #include <cstdlib> //For abort() | ||||
| #include <cstring> //For memcpy | ||||
| #include <unordered_map> | ||||
| #include <list> | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <stdexcept> //For invalid_argument | ||||
| #include <vector> | ||||
|  | ||||
| namespace PolyVox | ||||
| { | ||||
| 	/// The LargeVolume class provides a memory efficient method of storing voxel data while also allowing fast access and modification. | ||||
| 	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// A LargeVolume is essentially a 3D array in which each element (or <i>voxel</i>) is identified by a three dimensional (x,y,z) coordinate. | ||||
| 	/// We use the LargeVolume class to store our data in an efficient way, and it is the input to many of the algorithms (such as the surface | ||||
| 	/// extractors) which form the heart of PolyVox. The LargeVolume class is templatised so that different types of data can be stored within each voxel. | ||||
| 	/// | ||||
| 	/// Basic usage | ||||
| 	/// ----------- | ||||
| 	/// | ||||
| 	/// The following code snippet shows how to construct a volume and demonstrates basic usage: | ||||
| 	/// | ||||
| 	/// \code | ||||
| 	/// LargeVolume<Material8> volume(Region(Vector3DInt32(0,0,0), Vector3DInt32(63,127,255))); | ||||
| 	/// volume.setVoxelAt(15, 90, 42, Material8(5)); | ||||
| 	/// std::cout << "Voxel at (15, 90, 42) has value: " << volume.getVoxelAt(15, 90, 42).getMaterial() << std::endl; | ||||
| 	/// std::cout << "Width = " << volume.getWidth() << ", Height = " << volume.getHeight() << ", Depth = " << volume.getDepth() << std::endl; | ||||
| 	/// \endcode | ||||
| 	/// | ||||
| 	/// In this particular example each voxel in the LargeVolume is of type 'Material8', as specified by the template parameter. This is one of several | ||||
| 	/// predefined voxel types, and it is also possible to define your own. The Material8 type simply holds an integer value where zero represents | ||||
| 	/// empty space and any other value represents a solid material. | ||||
| 	///  | ||||
| 	/// The LargeVolume constructor takes a Region as a parameter. This specifies the valid range of voxels which can be held in the volume, so in this | ||||
| 	/// particular case the valid voxel positions are (0,0,0) to (63, 127, 255). Attempts to access voxels outside this range will result is accessing the | ||||
| 	/// border value (see getBorderValue() and setBorderValue()). PolyVox also has support for near infinite volumes which will be discussed later. | ||||
| 	///  | ||||
| 	/// Access to individual voxels is provided via the setVoxelAt() and getVoxelAt() member functions. Advanced users may also be interested in | ||||
| 	/// the Sampler class for faster read-only access to a large number of voxels. | ||||
| 	///  | ||||
| 	/// Lastly the example prints out some properties of the LargeVolume. Note that the dimentsions getWidth(), getHeight(), and getDepth() are inclusive, such | ||||
| 	/// that the width is 64 when the range of valid x coordinates goes from 0 to 63. | ||||
| 	///  | ||||
| 	/// Data Representaion | ||||
| 	/// ------------------ | ||||
| 	/// 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 LargeVolume 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 LargeVolume 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. The data for each block is stored in a compressed form, which uses only a small amout of | ||||
| 	/// memory but it is hard to modify the data. Therefore, before any given voxel can be modified, its corresponding block must be uncompressed. | ||||
| 	/// | ||||
| 	/// The compression and decompression of block is a relatively slow process and so we aim to do this as rarely as possible. In order | ||||
| 	/// to achive this, the volume class stores a cache of recently used blocks and their associated uncompressed data. Each time a voxel | ||||
| 	/// is touched a timestamp is updated on the corresponding block. When the cache becomes full the block with the oldest timestamp is | ||||
| 	/// recompressed and moved out of the cache. | ||||
| 	/// | ||||
| 	/// Achieving high compression rates | ||||
| 	/// -------------------------------- | ||||
| 	/// The compression rates which can be achieved can vary significantly depending the nature of the data you are storing, but you can | ||||
| 	/// encourage high compression rates by making your data as homogenous as possible. If you are simply storing a material with each | ||||
| 	/// voxel then this will probably happen naturally. Games such as Minecraft which use this approach will typically involve large areas | ||||
| 	/// of the same material which will compress down well. | ||||
| 	/// | ||||
| 	/// However, if you are storing density values then you may want to take some care. The advantage of storing smoothly changing values | ||||
| 	/// is that you can get smooth surfaces extracted, but storing smoothly changing values inside or outside objects (rather than just | ||||
| 	/// on the boundary) does not benefit the surface and is very hard to compress effectively. You may wish to apply some thresholding to  | ||||
| 	/// your density values to reduce this problem (this threasholding should only be applied to voxels who don't contribute to the surface). | ||||
| 	/// | ||||
| 	/// Paging large volumes | ||||
| 	/// -------------------- | ||||
| 	/// The compression scheme described previously will typically allow you to load several billion voxels into a few hundred megabytes of memory,  | ||||
| 	/// though as explained the exact compression rate is highly dependant on your data. If you have more data than this then PolyVox provides a | ||||
| 	/// mechanism by which parts of the volume can be paged out of memory by calling user supplied callback functions. This mechanism allows a | ||||
| 	/// potentially unlimited amount of data to be loaded, provided the user is able to take responsibility for storing any data which PolyVox | ||||
| 	/// cannot fit in memory, and then returning it back to PolyVox on demand. For example, the user might choose to temporarily store this data | ||||
| 	/// on disk or stream it to a remote database. | ||||
| 	/// | ||||
| 	/// You can construct such a LargeVolume as follows: | ||||
| 	/// | ||||
| 	/// \code | ||||
| 	/// void myDataRequiredHandler(const ConstVolumeProxy<MaterialDensityPair44>& volume, const PolyVox::Region& reg) | ||||
| 	/// { | ||||
| 	///		//This function is being called because part of the data is missing from memory and needs to be supplied. The parameter | ||||
| 	///		//'volume' provides access to the volume data, and the parameter 'reg' indicates which region of the volume you need fill.	 | ||||
| 	/// } | ||||
| 	/// | ||||
| 	/// void myDataOverflowHandler(const ConstVolumeProxy<MaterialDensityPair44>& vol, const PolyVox::Region& reg) | ||||
| 	/// { | ||||
| 	///		//This function is being called because part of the data is about to be removed from memory. The parameter 'volume'  | ||||
| 	///		//provides access to the volume data, and the parameter 'reg' indicates which region of the volume you need to store. | ||||
| 	/// } | ||||
| 	/// | ||||
| 	///	LargeVolume<Density>volData(&myDataRequiredHandler, &myDataOverflowHandler); | ||||
| 	/// \endcode | ||||
| 	/// | ||||
| 	/// Essentially you are providing an extension to the LargeVolume class - a way for data to be stored once PolyVox has run out of memory for it. Note | ||||
| 	/// that you don't actually have to do anything with the data - you could simply decide that once it gets removed from memory it doesn't matter | ||||
| 	/// anymore. But you still need to be ready to then provide something to PolyVox (even if it's just default data) in the event that it is requested. | ||||
| 	/// | ||||
| 	/// Cache-aware traversal | ||||
| 	/// --------------------- | ||||
| 	/// You might be suprised at just how many cache misses can occur when you traverse the volume in a naive manner. Consider a 1024x1024x1024 volume | ||||
| 	/// with blocks of size 32x32x32. And imagine you iterate over this volume with a simple three-level for loop which iterates over x, the y, then z. | ||||
| 	/// If you start at position (0,0,0) then ny the time you reach position (1023,0,0) you have touched 1024 voxels along one edge of the volume and | ||||
| 	/// have pulled 32 blocks into the cache. By the time you reach (1023,1023,0) you have hit 1024x1024 voxels and pulled 32x32 blocks into the cache. | ||||
| 	/// You are now ready to touch voxel (0,0,1) which is right nect to where you started, but unless your cache is at least 32x32 blocks large then this | ||||
| 	/// initial block has already been cleared from the cache. | ||||
| 	/// | ||||
| 	/// Ensuring you have a large enough cache size can obviously help the above situation, but you might also consider iterating over the voxels in a | ||||
| 	/// different order. For example, if you replace your three-level loop with a six-level loop then you can first process all the voxels between (0,0,0) | ||||
| 	/// and (31,31,31), then process all the voxels between (32,0,0) and (63,0,0), and so forth. Using this approach you will have no cache misses even | ||||
| 	/// is your cache sise is only one. Of course the logic is more complex, but writing code in such a cache-aware manner may be beneficial in some situations. | ||||
| 	/// | ||||
| 	/// Threading | ||||
| 	/// --------- | ||||
| 	/// The LargeVolume class does not make any guarentees about thread safety. You should ensure that all accesses are performed from the same thread. | ||||
| 	/// This is true even if you are only reading data from the volume, as concurrently reading from different threads can invalidate the contents | ||||
| 	/// of the block cache (amoung other problems). | ||||
| 	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	class LargeVolume : public BaseVolume<VoxelType> | ||||
| 	{ | ||||
| 	public: | ||||
| 		//There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared. | ||||
| 		//There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but | ||||
| 		//which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler | ||||
| 		//option. For now it seems best to 'fix' it with the preprocessor insstead, but maybe the workaround can be reinstated | ||||
| 		//in the future | ||||
| 		//typedef Volume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences. | ||||
| 		//class Sampler : public VolumeOfVoxelType::template Sampler< LargeVolume<VoxelType> > | ||||
| 		#ifndef SWIG | ||||
| #if defined(_MSC_VER) | ||||
| 		class Sampler : public BaseVolume<VoxelType>::Sampler< LargeVolume<VoxelType> > //This line works on VS2010 | ||||
| #else | ||||
|                 class Sampler : public BaseVolume<VoxelType>::template Sampler< LargeVolume<VoxelType> > //This line works on GCC | ||||
| #endif | ||||
| 		{ | ||||
| 		public: | ||||
| 			Sampler(LargeVolume<VoxelType>* volume); | ||||
| 			~Sampler(); | ||||
|  | ||||
| 			/// \deprecated | ||||
| 			POLYVOX_DEPRECATED VoxelType getSubSampledVoxel(uint8_t uLevel) const; | ||||
| 			inline VoxelType getVoxel(void) const;			 | ||||
|  | ||||
| 			void setPosition(const Vector3DInt32& v3dNewPos); | ||||
| 			void setPosition(int32_t xPos, int32_t yPos, int32_t zPos); | ||||
| 			inline bool setVoxel(VoxelType tValue); | ||||
|  | ||||
| 			void movePositiveX(void); | ||||
| 			void movePositiveY(void); | ||||
| 			void movePositiveZ(void); | ||||
|  | ||||
| 			void moveNegativeX(void); | ||||
| 			void moveNegativeY(void); | ||||
| 			void moveNegativeZ(void); | ||||
|  | ||||
| 			inline VoxelType peekVoxel1nx1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py1pz(void) const; | ||||
|  | ||||
| 			inline VoxelType peekVoxel0px1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py1pz(void) const; | ||||
|  | ||||
| 			inline VoxelType peekVoxel1px1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py1pz(void) const; | ||||
|  | ||||
| 		private: | ||||
| 			//Other current position information | ||||
| 			VoxelType* mCurrentVoxel; | ||||
| 		}; | ||||
|  | ||||
| 		#endif | ||||
|  | ||||
| 	public: | ||||
| 		/// Constructor for creating a fixed size volume. | ||||
| 		LargeVolume | ||||
| 		( | ||||
| 			const Region& regValid,	 | ||||
| 			Pager<VoxelType>* pPager = nullptr,	 | ||||
| 			uint16_t uBlockSideLength = 32 | ||||
| 		); | ||||
| 		/// Destructor | ||||
| 		~LargeVolume(); | ||||
|  | ||||
| 		/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates | ||||
| 		template <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const; | ||||
| 		/// Gets a voxel at the position given by a 3D vector | ||||
| 		template <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const; | ||||
|  | ||||
| 		/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates | ||||
| 		VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; | ||||
| 		/// 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 <tt>x,y,z</tt> 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 number of blocks for which uncompressed data is stored | ||||
| 		void setMemoryUsageLimit(uint32_t uMemoryUsageInBytes); | ||||
| 		/// Sets the voxel at the position given by <tt>x,y,z</tt> 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 <tt>x,y,z</tt> 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); | ||||
| 		/// Tries to ensure that the voxels within the specified Region are loaded into memory. | ||||
| 		void prefetch(Region regPrefetch); | ||||
| 		/// Ensures that any voxels within the specified Region are removed from memory. | ||||
| 		void flush(Region regFlush); | ||||
| 		/// Removes all voxels from memory | ||||
| 		void flushAll(); | ||||
|  | ||||
| 		/// Calculates approximatly how many bytes of memory the volume is currently using. | ||||
| 		uint32_t calculateSizeInBytes(void); | ||||
|  | ||||
| 	protected: | ||||
| 		/// Copy constructor | ||||
| 		LargeVolume(const LargeVolume& rhs); | ||||
|  | ||||
| 		/// Assignment operator | ||||
| 		LargeVolume& operator=(const LargeVolume& rhs); | ||||
|  | ||||
| 	private: | ||||
|  | ||||
| 		typedef std::unordered_map<Vector3DInt32, std::shared_ptr< UncompressedBlock<VoxelType> > > SharedPtrBlockMap; | ||||
| 		typedef std::unordered_map<Vector3DInt32, std::weak_ptr< UncompressedBlock<VoxelType> > > WeakPtrBlockMap; | ||||
|  | ||||
| 		void initialise(); | ||||
|  | ||||
| 		// A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057 | ||||
| 		template <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType tBorder) const; | ||||
| 	 | ||||
| 		std::shared_ptr< UncompressedBlock<VoxelType> > getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; | ||||
|  | ||||
| 		void purgeNullPtrsFromAllBlocks(void) const; | ||||
|  | ||||
| 		// The block data | ||||
| 		mutable WeakPtrBlockMap m_pAllBlocks; | ||||
| 		mutable SharedPtrBlockMap m_pRecentlyUsedBlocks; | ||||
|  | ||||
| 		mutable uint32_t m_uTimestamper; | ||||
| 		mutable Vector3DInt32 m_v3dLastAccessedBlockPos; | ||||
| 		mutable std::shared_ptr< UncompressedBlock<VoxelType> > m_pLastAccessedBlock; | ||||
| 		uint32_t m_uBlockCountLimit; | ||||
|  | ||||
| 		// The size of the volume | ||||
| 		Region m_regValidRegionInBlocks; | ||||
|  | ||||
| 		// The size of the blocks | ||||
| 		uint16_t m_uBlockSideLength; | ||||
| 		uint8_t m_uBlockSideLengthPower; | ||||
|  | ||||
| 		Pager<VoxelType>* m_pPager; | ||||
|  | ||||
| 		// Enough to make sure a blocks and it's neighbours can be loaded, with a few to spare. | ||||
| 		static const uint32_t uMinPracticalNoOfBlocks = 32; | ||||
| 		// Should preent multi-gigabyte volumes with reasonable block sizes. | ||||
| 		static const uint32_t uMaxPracticalNoOfBlocks = 32768; | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| #include "PolyVoxCore/LargeVolume.inl" | ||||
| #include "PolyVoxCore/LargeVolumeSampler.inl" | ||||
|  | ||||
| #endif //__PolyVox_LargeVolume_H__ | ||||
| #endif //__PolyVox_LargeVolume_H__ | ||||
							
								
								
									
										333
									
								
								library/PolyVoxCore/include/PolyVoxCore/PagedVolume.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								library/PolyVoxCore/include/PolyVoxCore/PagedVolume.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,333 @@ | ||||
| /******************************************************************************* | ||||
| Copyright (c) 2005-2009 David Williams | ||||
|  | ||||
| This software is provided 'as-is', without any express or implied | ||||
| warranty. In no event will the authors be held liable for any damages | ||||
| arising from the use of this software. | ||||
|  | ||||
| Permission is granted to anyone to use this software for any purpose, | ||||
| including commercial applications, and to alter it and redistribute it | ||||
| freely, subject to the following restrictions: | ||||
|  | ||||
|     1. The origin of this software must not be misrepresented; you must not | ||||
|     claim that you wrote the original software. If you use this software | ||||
|     in a product, an acknowledgment in the product documentation would be | ||||
|     appreciated but is not required. | ||||
|  | ||||
|     2. Altered source versions must be plainly marked as such, and must not be | ||||
|     misrepresented as being the original software. | ||||
|  | ||||
|     3. This notice may not be removed or altered from any source | ||||
|     distribution. 	 | ||||
| *******************************************************************************/ | ||||
|  | ||||
| #ifndef __PolyVox_PagedVolume_H__ | ||||
| #define __PolyVox_PagedVolume_H__ | ||||
|  | ||||
| #include "PolyVoxCore/BaseVolume.h" | ||||
| #include "PolyVoxCore/Pager.h" | ||||
| #include "PolyVoxCore/Region.h" | ||||
| #include "PolyVoxCore/UncompressedBlock.h" | ||||
| #include "PolyVoxCore/Vector.h" | ||||
|  | ||||
| #include <limits> | ||||
| #include <cstdlib> //For abort() | ||||
| #include <cstring> //For memcpy | ||||
| #include <unordered_map> | ||||
| #include <list> | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <stdexcept> //For invalid_argument | ||||
| #include <vector> | ||||
|  | ||||
| namespace PolyVox | ||||
| { | ||||
| 	/// The PagedVolume class provides a memory efficient method of storing voxel data while also allowing fast access and modification. | ||||
| 	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// A PagedVolume is essentially a 3D array in which each element (or <i>voxel</i>) is identified by a three dimensional (x,y,z) coordinate. | ||||
| 	/// We use the PagedVolume class to store our data in an efficient way, and it is the input to many of the algorithms (such as the surface | ||||
| 	/// extractors) which form the heart of PolyVox. The PagedVolume class is templatised so that different types of data can be stored within each voxel. | ||||
| 	/// | ||||
| 	/// Basic usage | ||||
| 	/// ----------- | ||||
| 	/// | ||||
| 	/// The following code snippet shows how to construct a volume and demonstrates basic usage: | ||||
| 	/// | ||||
| 	/// \code | ||||
| 	/// PagedVolume<Material8> volume(Region(Vector3DInt32(0,0,0), Vector3DInt32(63,127,255))); | ||||
| 	/// volume.setVoxelAt(15, 90, 42, Material8(5)); | ||||
| 	/// std::cout << "Voxel at (15, 90, 42) has value: " << volume.getVoxelAt(15, 90, 42).getMaterial() << std::endl; | ||||
| 	/// std::cout << "Width = " << volume.getWidth() << ", Height = " << volume.getHeight() << ", Depth = " << volume.getDepth() << std::endl; | ||||
| 	/// \endcode | ||||
| 	/// | ||||
| 	/// In this particular example each voxel in the PagedVolume is of type 'Material8', as specified by the template parameter. This is one of several | ||||
| 	/// predefined voxel types, and it is also possible to define your own. The Material8 type simply holds an integer value where zero represents | ||||
| 	/// empty space and any other value represents a solid material. | ||||
| 	///  | ||||
| 	/// The PagedVolume constructor takes a Region as a parameter. This specifies the valid range of voxels which can be held in the volume, so in this | ||||
| 	/// particular case the valid voxel positions are (0,0,0) to (63, 127, 255). Attempts to access voxels outside this range will result is accessing the | ||||
| 	/// border value (see getBorderValue() and setBorderValue()). PolyVox also has support for near infinite volumes which will be discussed later. | ||||
| 	///  | ||||
| 	/// Access to individual voxels is provided via the setVoxelAt() and getVoxelAt() member functions. Advanced users may also be interested in | ||||
| 	/// the Sampler class for faster read-only access to a large number of voxels. | ||||
| 	///  | ||||
| 	/// Lastly the example prints out some properties of the PagedVolume. Note that the dimentsions getWidth(), getHeight(), and getDepth() are inclusive, such | ||||
| 	/// that the width is 64 when the range of valid x coordinates goes from 0 to 63. | ||||
| 	///  | ||||
| 	/// Data Representaion | ||||
| 	/// ------------------ | ||||
| 	/// 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 PagedVolume 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 PagedVolume 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. The data for each block is stored in a compressed form, which uses only a small amout of | ||||
| 	/// memory but it is hard to modify the data. Therefore, before any given voxel can be modified, its corresponding block must be uncompressed. | ||||
| 	/// | ||||
| 	/// The compression and decompression of block is a relatively slow process and so we aim to do this as rarely as possible. In order | ||||
| 	/// to achive this, the volume class stores a cache of recently used blocks and their associated uncompressed data. Each time a voxel | ||||
| 	/// is touched a timestamp is updated on the corresponding block. When the cache becomes full the block with the oldest timestamp is | ||||
| 	/// recompressed and moved out of the cache. | ||||
| 	/// | ||||
| 	/// Achieving high compression rates | ||||
| 	/// -------------------------------- | ||||
| 	/// The compression rates which can be achieved can vary significantly depending the nature of the data you are storing, but you can | ||||
| 	/// encourage high compression rates by making your data as homogenous as possible. If you are simply storing a material with each | ||||
| 	/// voxel then this will probably happen naturally. Games such as Minecraft which use this approach will typically involve large areas | ||||
| 	/// of the same material which will compress down well. | ||||
| 	/// | ||||
| 	/// However, if you are storing density values then you may want to take some care. The advantage of storing smoothly changing values | ||||
| 	/// is that you can get smooth surfaces extracted, but storing smoothly changing values inside or outside objects (rather than just | ||||
| 	/// on the boundary) does not benefit the surface and is very hard to compress effectively. You may wish to apply some thresholding to  | ||||
| 	/// your density values to reduce this problem (this threasholding should only be applied to voxels who don't contribute to the surface). | ||||
| 	/// | ||||
| 	/// Paging large volumes | ||||
| 	/// -------------------- | ||||
| 	/// The compression scheme described previously will typically allow you to load several billion voxels into a few hundred megabytes of memory,  | ||||
| 	/// though as explained the exact compression rate is highly dependant on your data. If you have more data than this then PolyVox provides a | ||||
| 	/// mechanism by which parts of the volume can be paged out of memory by calling user supplied callback functions. This mechanism allows a | ||||
| 	/// potentially unlimited amount of data to be loaded, provided the user is able to take responsibility for storing any data which PolyVox | ||||
| 	/// cannot fit in memory, and then returning it back to PolyVox on demand. For example, the user might choose to temporarily store this data | ||||
| 	/// on disk or stream it to a remote database. | ||||
| 	/// | ||||
| 	/// You can construct such a PagedVolume as follows: | ||||
| 	/// | ||||
| 	/// \code | ||||
| 	/// void myDataRequiredHandler(const ConstVolumeProxy<MaterialDensityPair44>& volume, const PolyVox::Region& reg) | ||||
| 	/// { | ||||
| 	///		//This function is being called because part of the data is missing from memory and needs to be supplied. The parameter | ||||
| 	///		//'volume' provides access to the volume data, and the parameter 'reg' indicates which region of the volume you need fill.	 | ||||
| 	/// } | ||||
| 	/// | ||||
| 	/// void myDataOverflowHandler(const ConstVolumeProxy<MaterialDensityPair44>& vol, const PolyVox::Region& reg) | ||||
| 	/// { | ||||
| 	///		//This function is being called because part of the data is about to be removed from memory. The parameter 'volume'  | ||||
| 	///		//provides access to the volume data, and the parameter 'reg' indicates which region of the volume you need to store. | ||||
| 	/// } | ||||
| 	/// | ||||
| 	///	PagedVolume<Density>volData(&myDataRequiredHandler, &myDataOverflowHandler); | ||||
| 	/// \endcode | ||||
| 	/// | ||||
| 	/// Essentially you are providing an extension to the PagedVolume class - a way for data to be stored once PolyVox has run out of memory for it. Note | ||||
| 	/// that you don't actually have to do anything with the data - you could simply decide that once it gets removed from memory it doesn't matter | ||||
| 	/// anymore. But you still need to be ready to then provide something to PolyVox (even if it's just default data) in the event that it is requested. | ||||
| 	/// | ||||
| 	/// Cache-aware traversal | ||||
| 	/// --------------------- | ||||
| 	/// You might be suprised at just how many cache misses can occur when you traverse the volume in a naive manner. Consider a 1024x1024x1024 volume | ||||
| 	/// with blocks of size 32x32x32. And imagine you iterate over this volume with a simple three-level for loop which iterates over x, the y, then z. | ||||
| 	/// If you start at position (0,0,0) then ny the time you reach position (1023,0,0) you have touched 1024 voxels along one edge of the volume and | ||||
| 	/// have pulled 32 blocks into the cache. By the time you reach (1023,1023,0) you have hit 1024x1024 voxels and pulled 32x32 blocks into the cache. | ||||
| 	/// You are now ready to touch voxel (0,0,1) which is right nect to where you started, but unless your cache is at least 32x32 blocks large then this | ||||
| 	/// initial block has already been cleared from the cache. | ||||
| 	/// | ||||
| 	/// Ensuring you have a large enough cache size can obviously help the above situation, but you might also consider iterating over the voxels in a | ||||
| 	/// different order. For example, if you replace your three-level loop with a six-level loop then you can first process all the voxels between (0,0,0) | ||||
| 	/// and (31,31,31), then process all the voxels between (32,0,0) and (63,0,0), and so forth. Using this approach you will have no cache misses even | ||||
| 	/// is your cache sise is only one. Of course the logic is more complex, but writing code in such a cache-aware manner may be beneficial in some situations. | ||||
| 	/// | ||||
| 	/// Threading | ||||
| 	/// --------- | ||||
| 	/// The PagedVolume class does not make any guarentees about thread safety. You should ensure that all accesses are performed from the same thread. | ||||
| 	/// This is true even if you are only reading data from the volume, as concurrently reading from different threads can invalidate the contents | ||||
| 	/// of the block cache (amoung other problems). | ||||
| 	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	class PagedVolume : public BaseVolume<VoxelType> | ||||
| 	{ | ||||
| 	public: | ||||
| 		//There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared. | ||||
| 		//There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but | ||||
| 		//which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler | ||||
| 		//option. For now it seems best to 'fix' it with the preprocessor insstead, but maybe the workaround can be reinstated | ||||
| 		//in the future | ||||
| 		//typedef Volume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences. | ||||
| 		//class Sampler : public VolumeOfVoxelType::template Sampler< PagedVolume<VoxelType> > | ||||
| 		#ifndef SWIG | ||||
| #if defined(_MSC_VER) | ||||
| 		class Sampler : public BaseVolume<VoxelType>::Sampler< PagedVolume<VoxelType> > //This line works on VS2010 | ||||
| #else | ||||
|                 class Sampler : public BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> > //This line works on GCC | ||||
| #endif | ||||
| 		{ | ||||
| 		public: | ||||
| 			Sampler(PagedVolume<VoxelType>* volume); | ||||
| 			~Sampler(); | ||||
|  | ||||
| 			/// \deprecated | ||||
| 			POLYVOX_DEPRECATED VoxelType getSubSampledVoxel(uint8_t uLevel) const; | ||||
| 			inline VoxelType getVoxel(void) const;			 | ||||
|  | ||||
| 			void setPosition(const Vector3DInt32& v3dNewPos); | ||||
| 			void setPosition(int32_t xPos, int32_t yPos, int32_t zPos); | ||||
| 			inline bool setVoxel(VoxelType tValue); | ||||
|  | ||||
| 			void movePositiveX(void); | ||||
| 			void movePositiveY(void); | ||||
| 			void movePositiveZ(void); | ||||
|  | ||||
| 			void moveNegativeX(void); | ||||
| 			void moveNegativeY(void); | ||||
| 			void moveNegativeZ(void); | ||||
|  | ||||
| 			inline VoxelType peekVoxel1nx1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py1pz(void) const; | ||||
|  | ||||
| 			inline VoxelType peekVoxel0px1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py1pz(void) const; | ||||
|  | ||||
| 			inline VoxelType peekVoxel1px1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py1pz(void) const; | ||||
|  | ||||
| 		private: | ||||
| 			//Other current position information | ||||
| 			VoxelType* mCurrentVoxel; | ||||
| 		}; | ||||
|  | ||||
| 		#endif | ||||
|  | ||||
| 	public: | ||||
| 		/// Constructor for creating a fixed size volume. | ||||
| 		PagedVolume | ||||
| 		( | ||||
| 			const Region& regValid,	 | ||||
| 			Pager<VoxelType>* pPager = nullptr,	 | ||||
| 			uint16_t uBlockSideLength = 32 | ||||
| 		); | ||||
| 		/// Destructor | ||||
| 		~PagedVolume(); | ||||
|  | ||||
| 		/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates | ||||
| 		template <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const; | ||||
| 		/// Gets a voxel at the position given by a 3D vector | ||||
| 		template <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const; | ||||
|  | ||||
| 		/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates | ||||
| 		VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; | ||||
| 		/// 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 <tt>x,y,z</tt> 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 number of blocks for which uncompressed data is stored | ||||
| 		void setMemoryUsageLimit(uint32_t uMemoryUsageInBytes); | ||||
| 		/// Sets the voxel at the position given by <tt>x,y,z</tt> 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 <tt>x,y,z</tt> 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); | ||||
| 		/// Tries to ensure that the voxels within the specified Region are loaded into memory. | ||||
| 		void prefetch(Region regPrefetch); | ||||
| 		/// Ensures that any voxels within the specified Region are removed from memory. | ||||
| 		void flush(Region regFlush); | ||||
| 		/// Removes all voxels from memory | ||||
| 		void flushAll(); | ||||
|  | ||||
| 		/// Calculates approximatly how many bytes of memory the volume is currently using. | ||||
| 		uint32_t calculateSizeInBytes(void); | ||||
|  | ||||
| 	protected: | ||||
| 		/// Copy constructor | ||||
| 		PagedVolume(const PagedVolume& rhs); | ||||
|  | ||||
| 		/// Assignment operator | ||||
| 		PagedVolume& operator=(const PagedVolume& rhs); | ||||
|  | ||||
| 	private: | ||||
|  | ||||
| 		typedef std::unordered_map<Vector3DInt32, std::shared_ptr< UncompressedBlock<VoxelType> > > SharedPtrBlockMap; | ||||
| 		typedef std::unordered_map<Vector3DInt32, std::weak_ptr< UncompressedBlock<VoxelType> > > WeakPtrBlockMap; | ||||
|  | ||||
| 		void initialise(); | ||||
|  | ||||
| 		// A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057 | ||||
| 		template <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType tBorder) const; | ||||
| 	 | ||||
| 		std::shared_ptr< UncompressedBlock<VoxelType> > getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; | ||||
|  | ||||
| 		void purgeNullPtrsFromAllBlocks(void) const; | ||||
|  | ||||
| 		// The block data | ||||
| 		mutable WeakPtrBlockMap m_pAllBlocks; | ||||
| 		mutable SharedPtrBlockMap m_pRecentlyUsedBlocks; | ||||
|  | ||||
| 		mutable uint32_t m_uTimestamper; | ||||
| 		mutable Vector3DInt32 m_v3dLastAccessedBlockPos; | ||||
| 		mutable std::shared_ptr< UncompressedBlock<VoxelType> > m_pLastAccessedBlock; | ||||
| 		uint32_t m_uBlockCountLimit; | ||||
|  | ||||
| 		// The size of the volume | ||||
| 		Region m_regValidRegionInBlocks; | ||||
|  | ||||
| 		// The size of the blocks | ||||
| 		uint16_t m_uBlockSideLength; | ||||
| 		uint8_t m_uBlockSideLengthPower; | ||||
|  | ||||
| 		Pager<VoxelType>* m_pPager; | ||||
|  | ||||
| 		// Enough to make sure a blocks and it's neighbours can be loaded, with a few to spare. | ||||
| 		static const uint32_t uMinPracticalNoOfBlocks = 32; | ||||
| 		// Should preent multi-gigabyte volumes with reasonable block sizes. | ||||
| 		static const uint32_t uMaxPracticalNoOfBlocks = 32768; | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| #include "PolyVoxCore/PagedVolume.inl" | ||||
| #include "PolyVoxCore/PagedVolumeSampler.inl" | ||||
|  | ||||
| #endif //__PolyVox_PagedVolume_H__ | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -103,11 +103,6 @@ namespace PolyVox | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> class FilePager; | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	// LargeVolume | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> class LargeVolume; | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	// MarchingCubesSurfaceExtractor | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -145,6 +140,15 @@ namespace PolyVox | ||||
| 	typedef uint32_t DefaultIndexType; | ||||
| 	template <typename VertexType, typename IndexType = DefaultIndexType> class Mesh; | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	// PagedVolume | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> class PagedVolume; | ||||
| 	template <typename VoxelType> | ||||
| 	using LargeVolume = PagedVolume<VoxelType>; | ||||
| 	template <typename VoxelType> | ||||
| 	using SimpleVolume = PagedVolume<VoxelType>; | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	// Pager | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -160,11 +164,6 @@ namespace PolyVox | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	class Region; | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	// SimpleVolume | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> class SimpleVolume; | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	// Vector | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
|   | ||||
| @@ -1,229 +1,7 @@ | ||||
| /******************************************************************************* | ||||
| Copyright (c) 2005-2009 David Williams | ||||
|  | ||||
| This software is provided 'as-is', without any express or implied | ||||
| warranty. In no event will the authors be held liable for any damages | ||||
| arising from the use of this software. | ||||
|  | ||||
| Permission is granted to anyone to use this software for any purpose, | ||||
| including commercial applications, and to alter it and redistribute it | ||||
| freely, subject to the following restrictions: | ||||
|  | ||||
|     1. The origin of this software must not be misrepresented; you must not | ||||
|     claim that you wrote the original software. If you use this software | ||||
|     in a product, an acknowledgment in the product documentation would be | ||||
|     appreciated but is not required. | ||||
|  | ||||
|     2. Altered source versions must be plainly marked as such, and must not be | ||||
|     misrepresented as being the original software. | ||||
|  | ||||
|     3. This notice may not be removed or altered from any source | ||||
|     distribution. 	 | ||||
| *******************************************************************************/ | ||||
|  | ||||
| #ifndef __PolyVox_SimpleVolume_H__ | ||||
| #define __PolyVox_SimpleVolume_H__ | ||||
|  | ||||
| #include "Impl/Utility.h" | ||||
| #include "PagedVolume.h" | ||||
| #include "PolyVoxForwardDeclarations.h" | ||||
|  | ||||
| #include "PolyVoxCore/BaseVolume.h" | ||||
| #include "PolyVoxCore/Region.h" | ||||
| #include "PolyVoxCore/Vector.h" | ||||
|  | ||||
| #include <cstdlib> //For abort() | ||||
| #include <cstring> //For memcpy | ||||
| #include <limits> | ||||
| #include <memory> | ||||
| #include <stdexcept> //For invalid_argument | ||||
|  | ||||
| namespace PolyVox | ||||
| { | ||||
| 	template <typename VoxelType> | ||||
| 	class SimpleVolume : public BaseVolume<VoxelType> | ||||
| 	{ | ||||
| 	public: | ||||
| 		#ifndef SWIG | ||||
| 		//Could be made private? | ||||
| 		class Block | ||||
| 		{ | ||||
| 		public: | ||||
| 			Block(uint16_t uSideLength = 0); | ||||
| 			~Block(); | ||||
|  | ||||
| 			uint16_t getSideLength(void) const; | ||||
| 			VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; | ||||
| 			VoxelType getVoxelAt(const Vector3DUint16& v3dPos) const; | ||||
|  | ||||
| 			void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); | ||||
| 			void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); | ||||
|  | ||||
| 			void fill(VoxelType tValue); | ||||
| 			void initialise(uint16_t uSideLength); | ||||
| 			uint32_t calculateSizeInBytes(void); | ||||
|  | ||||
| 		public: | ||||
| 			VoxelType* m_tUncompressedData; | ||||
| 			uint16_t m_uSideLength; | ||||
| 			uint8_t m_uSideLengthPower;	 | ||||
| 		}; | ||||
|  | ||||
| 		//There seems to be some descrepency between Visual Studio and GCC about how the following class should be declared. | ||||
| 		//There is a work around (see also See http://goo.gl/qu1wn) given below which appears to work on VS2010 and GCC, but | ||||
| 		//which seems to cause internal compiler errors on VS2008 when building with the /Gm 'Enable Minimal Rebuild' compiler | ||||
| 		//option. For now it seems best to 'fix' it with the preprocessor insstead, but maybe the workaround can be reinstated | ||||
| 		//in the future | ||||
| 		//typedef Volume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences. | ||||
| 		//class Sampler : public VolumeOfVoxelType::template Sampler< SimpleVolume<VoxelType> > | ||||
| #if defined(_MSC_VER) | ||||
| 		class Sampler : public BaseVolume<VoxelType>::Sampler< SimpleVolume<VoxelType> > //This line works on VS2010 | ||||
| #else | ||||
|                 class Sampler : public BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> > //This line works on GCC | ||||
| #endif | ||||
| 		{ | ||||
| 		public: | ||||
| 			/// Construct a new Sampler | ||||
| 			Sampler(SimpleVolume<VoxelType>* volume); | ||||
| 			~Sampler(); | ||||
|  | ||||
| 			/// \deprecated | ||||
| 			POLYVOX_DEPRECATED VoxelType getSubSampledVoxel(uint8_t uLevel) const; | ||||
| 			/// Get the value of the current voxel | ||||
| 			inline VoxelType getVoxel(void) const; | ||||
| 			 | ||||
| 			/// Set the current voxel position | ||||
| 			void setPosition(const Vector3DInt32& v3dNewPos); | ||||
| 			/// Set the current voxel position | ||||
| 			void setPosition(int32_t xPos, int32_t yPos, int32_t zPos); | ||||
| 			/// Set the value of the current voxel | ||||
| 			inline bool setVoxel(VoxelType tValue); | ||||
|  | ||||
| 			/// Increase the \a x position by \a 1 | ||||
| 			void movePositiveX(void); | ||||
| 			/// Increase the \a y position by \a 1 | ||||
| 			void movePositiveY(void); | ||||
| 			/// Increase the \a z position by \a 1 | ||||
| 			void movePositiveZ(void); | ||||
|  | ||||
| 			/// Decrease the \a x position by \a 1 | ||||
| 			void moveNegativeX(void); | ||||
| 			/// Decrease the \a y position by \a 1 | ||||
| 			void moveNegativeY(void); | ||||
| 			/// Decrease the \a z position by \a 1 | ||||
| 			void moveNegativeZ(void); | ||||
|  | ||||
| 			inline VoxelType peekVoxel1nx1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1nx1py1pz(void) const; | ||||
|  | ||||
| 			inline VoxelType peekVoxel0px1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel0px1py1pz(void) const; | ||||
|  | ||||
| 			inline VoxelType peekVoxel1px1ny1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1ny0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1ny1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px0py1pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py1nz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py0pz(void) const; | ||||
| 			inline VoxelType peekVoxel1px1py1pz(void) const; | ||||
|  | ||||
| 		private:			 | ||||
| 			//Other current position information | ||||
| 			VoxelType* mCurrentVoxel; | ||||
| 		}; | ||||
| 		#endif | ||||
|  | ||||
| 	public: | ||||
| 		/// Constructor for creating a fixed size volume. | ||||
| 		SimpleVolume(const Region& regValid, uint16_t uBlockSideLength = 32); | ||||
|  | ||||
| 		/// Destructor | ||||
| 		~SimpleVolume(); | ||||
|  | ||||
| 		/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates | ||||
| 		template <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const; | ||||
| 		/// Gets a voxel at the position given by a 3D vector | ||||
| 		template <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const; | ||||
|  | ||||
| 		/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates | ||||
| 		VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const; | ||||
| 		/// 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 <tt>x,y,z</tt> 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 <tt>x,y,z</tt> 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 <tt>x,y,z</tt> 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); | ||||
|  | ||||
| 		/// Calculates approximatly how many bytes of memory the volume is currently using. | ||||
| 		uint32_t calculateSizeInBytes(void); | ||||
|  | ||||
| 	protected: | ||||
| 		/// Copy constructor | ||||
| 		SimpleVolume(const SimpleVolume& rhs); | ||||
|  | ||||
| 		/// Assignment operator | ||||
| 		SimpleVolume& operator=(const SimpleVolume& rhs); | ||||
|  | ||||
| 	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 <WrapMode eWrapMode> | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const; | ||||
| 		VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType tBorder) const; | ||||
|  | ||||
| 		Block* getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const; | ||||
|  | ||||
| 		//The block data | ||||
| 		Block* m_pBlocks; | ||||
|  | ||||
| 		//The size of the volume in vlocks | ||||
| 		Region m_regValidRegionInBlocks; | ||||
|  | ||||
| 		//Volume size measured in blocks. | ||||
| 		uint32_t m_uNoOfBlocksInVolume; | ||||
| 		uint16_t m_uWidthInBlocks; | ||||
| 		uint16_t m_uHeightInBlocks; | ||||
| 		uint16_t m_uDepthInBlocks; | ||||
|  | ||||
| 		//The size of the blocks | ||||
| 		uint32_t m_uNoOfVoxelsPerBlock; | ||||
| 		uint16_t m_uBlockSideLength; | ||||
| 		uint8_t m_uBlockSideLengthPower; | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| #include "PolyVoxCore/SimpleVolumeBlock.inl" | ||||
| #include "PolyVoxCore/SimpleVolume.inl" | ||||
| #include "PolyVoxCore/SimpleVolumeSampler.inl" | ||||
|  | ||||
| #endif //__PolyVox_SimpleVolume_H__ | ||||
| #endif //__PolyVox_SimpleVolume_H__ | ||||
| @@ -1,441 +0,0 @@ | ||||
| /******************************************************************************* | ||||
| Copyright (c) 2005-2009 David Williams | ||||
|  | ||||
| This software is provided 'as-is', without any express or implied | ||||
| warranty. In no event will the authors be held liable for any damages | ||||
| arising from the use of this software. | ||||
|  | ||||
| Permission is granted to anyone to use this software for any purpose, | ||||
| including commercial applications, and to alter it and redistribute it | ||||
| freely, subject to the following restrictions: | ||||
|  | ||||
|     1. The origin of this software must not be misrepresented; you must not | ||||
|     claim that you wrote the original software. If you use this software | ||||
|     in a product, an acknowledgment in the product documentation would be | ||||
|     appreciated but is not required. | ||||
|  | ||||
|     2. Altered source versions must be plainly marked as such, and must not be | ||||
|     misrepresented as being the original software. | ||||
|  | ||||
|     3. This notice may not be removed or altered from any source | ||||
|     distribution. 	 | ||||
| *******************************************************************************/ | ||||
|  | ||||
| #include "PolyVoxCore/Impl/ErrorHandling.h" | ||||
|  | ||||
| namespace PolyVox | ||||
| { | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// This constructor creates a volume with a fixed size which is specified as a parameter. | ||||
| 	/// \param regValid Specifies the minimum and maximum valid voxel positions. | ||||
| 	/// \param uBlockSideLength The size of the block to use within the volume | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	SimpleVolume<VoxelType>::SimpleVolume(const Region& regValid, uint16_t uBlockSideLength) | ||||
| 		:BaseVolume<VoxelType>(regValid) | ||||
| 	{ | ||||
| 		//Create a volume of the right size. | ||||
| 		initialise(regValid,uBlockSideLength); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing | ||||
| 	/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to | ||||
| 	/// make a copy of a volume and in this case you should look at the Volumeresampler. | ||||
| 	/// | ||||
| 	/// \sa VolumeResampler | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	SimpleVolume<VoxelType>::SimpleVolume(const SimpleVolume<VoxelType>& /*rhs*/) | ||||
| 	{ | ||||
| 		POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons."); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// Destroys the volume | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	SimpleVolume<VoxelType>::~SimpleVolume() | ||||
| 	{ | ||||
| 		delete[] m_pBlocks; | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// This function should never be called. Copying volumes by value would be expensive, and we want to prevent users from doing | ||||
| 	/// it by accident (such as when passing them as paramenters to functions). That said, there are times when you really do want to | ||||
| 	/// make a copy of a volume and in this case you should look at the Volumeresampler. | ||||
| 	/// | ||||
| 	/// \sa VolumeResampler | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	SimpleVolume<VoxelType>& SimpleVolume<VoxelType>::operator=(const SimpleVolume<VoxelType>& /*rhs*/) | ||||
| 	{ | ||||
| 		POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons."); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// 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 <typename VoxelType> | ||||
| 	template <WrapMode eWrapMode> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const | ||||
| 	{ | ||||
| 		// Simply call through to the real implementation | ||||
| 		return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<eWrapMode>(), tBorder); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// 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 <typename VoxelType> | ||||
| 	template <WrapMode eWrapMode> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const | ||||
| 	{ | ||||
| 		// Simply call through to the real implementation | ||||
| 		return getVoxel<eWrapMode>(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 <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::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<WrapModes::Validate>(), tBorder); | ||||
| 		case WrapModes::Clamp: | ||||
| 			return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Clamp>(), tBorder); | ||||
| 		case WrapModes::Border: | ||||
| 			return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Border>(), tBorder); | ||||
| 		case WrapModes::AssumeValid: | ||||
| 			return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), 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 <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const | ||||
| 	{ | ||||
| 		return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, 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 | ||||
| 	/// \return The voxel value | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const | ||||
| 	{ | ||||
| 		if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos))) | ||||
| 		{ | ||||
| 			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<uint16_t>(uXPos - (blockX << m_uBlockSideLengthPower)); | ||||
| 			const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower)); | ||||
| 			const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower)); | ||||
|  | ||||
| 			typename SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); | ||||
|  | ||||
| 			return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return this->getBorderValue(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// \param v3dPos The 3D position of the voxel | ||||
| 	/// \return The voxel value | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxelAt(const Vector3DInt32& v3dPos) const | ||||
| 	{ | ||||
| 		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 | ||||
| 	/// \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 <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::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 = uXPos - (blockX << m_uBlockSideLengthPower); | ||||
| 		const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); | ||||
| 		const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); | ||||
|  | ||||
| 		typename SimpleVolume<VoxelType>::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 <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::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 | ||||
| 	/// \param uZPos the \c z position of the voxel | ||||
| 	/// \param tValue the value to which the voxel will be set | ||||
| 	/// \return whether the requested position is inside the volume | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	bool SimpleVolume<VoxelType>::setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue) | ||||
| 	{ | ||||
| 		// 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 = uXPos - (blockX << m_uBlockSideLengthPower); | ||||
| 		const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower); | ||||
| 		const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower); | ||||
|  | ||||
| 		typename SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); | ||||
|  | ||||
| 		pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue); | ||||
|  | ||||
| 		//Return true to indicate that we modified a voxel. | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// \param v3dPos the 3D position of the voxel | ||||
| 	/// \param tValue the value to which the voxel will be set | ||||
| 	/// \return whether the requested position is inside the volume | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	bool SimpleVolume<VoxelType>::setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue) | ||||
| 	{ | ||||
| 		return setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// This function should probably be made internal... | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::initialise(const Region& regValidRegion, uint16_t uBlockSideLength) | ||||
| 	{		 | ||||
| 		//Release mode validation | ||||
| 		if(uBlockSideLength < 8) | ||||
| 		{ | ||||
| 			POLYVOX_THROW(std::invalid_argument, "Block side length should be at least 8"); | ||||
| 		} | ||||
| 		if(uBlockSideLength > 256) | ||||
| 		{ | ||||
| 			POLYVOX_THROW(std::invalid_argument, "Block side length should not be more than 256"); | ||||
| 		} | ||||
| 		if(!isPowerOf2(uBlockSideLength)) | ||||
| 		{ | ||||
| 			POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two."); | ||||
| 		} | ||||
|  | ||||
| 		this->m_regValidRegion = regValidRegion; | ||||
|  | ||||
| 		//Compute the block side length | ||||
| 		m_uBlockSideLength = uBlockSideLength; | ||||
| 		m_uBlockSideLengthPower = logBase2(m_uBlockSideLength); | ||||
| 		m_uNoOfVoxelsPerBlock = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength; | ||||
|  | ||||
| 		m_regValidRegionInBlocks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uBlockSideLengthPower); | ||||
| 		m_regValidRegionInBlocks.setLowerY(this->m_regValidRegion.getLowerY() >> m_uBlockSideLengthPower); | ||||
| 		m_regValidRegionInBlocks.setLowerZ(this->m_regValidRegion.getLowerZ() >> m_uBlockSideLengthPower); | ||||
| 		m_regValidRegionInBlocks.setUpperX(this->m_regValidRegion.getUpperX() >> m_uBlockSideLengthPower); | ||||
| 		m_regValidRegionInBlocks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uBlockSideLengthPower); | ||||
| 		m_regValidRegionInBlocks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uBlockSideLengthPower); | ||||
|  | ||||
| 		//Compute the size of the volume in blocks (and note +1 at the end) | ||||
| 		m_uWidthInBlocks = m_regValidRegionInBlocks.getUpperX() - m_regValidRegionInBlocks.getLowerX() + 1; | ||||
| 		m_uHeightInBlocks = m_regValidRegionInBlocks.getUpperY() - m_regValidRegionInBlocks.getLowerY() + 1; | ||||
| 		m_uDepthInBlocks = m_regValidRegionInBlocks.getUpperZ() - m_regValidRegionInBlocks.getLowerZ() + 1; | ||||
| 		m_uNoOfBlocksInVolume = m_uWidthInBlocks * m_uHeightInBlocks * m_uDepthInBlocks; | ||||
|  | ||||
| 		//Allocate the data | ||||
| 		m_pBlocks = new Block[m_uNoOfBlocksInVolume]; | ||||
| 		for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i) | ||||
| 		{ | ||||
| 			m_pBlocks[i].initialise(m_uBlockSideLength); | ||||
| 		} | ||||
|  | ||||
| 		//Other properties we might find useful later | ||||
| 		this->m_uLongestSideLength = (std::max)((std::max)(this->getWidth(),this->getHeight()),this->getDepth()); | ||||
| 		this->m_uShortestSideLength = (std::min)((std::min)(this->getWidth(),this->getHeight()),this->getDepth()); | ||||
| 		this->m_fDiagonalLength = sqrtf(static_cast<float>(this->getWidth() * this->getWidth() + this->getHeight() * this->getHeight() + this->getDepth() * this->getDepth())); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	typename SimpleVolume<VoxelType>::Block* SimpleVolume<VoxelType>::getUncompressedBlock(int32_t uBlockX, int32_t uBlockY, int32_t uBlockZ) const | ||||
| 	{ | ||||
| 		//The lower left corner of the volume could be | ||||
| 		//anywhere, but array indices need to start at zero. | ||||
| 		uBlockX -= m_regValidRegionInBlocks.getLowerX(); | ||||
| 		uBlockY -= m_regValidRegionInBlocks.getLowerY(); | ||||
| 		uBlockZ -= m_regValidRegionInBlocks.getLowerZ(); | ||||
|  | ||||
| 		POLYVOX_ASSERT(uBlockX >= 0, "Block coordinate must not be negative."); | ||||
| 		POLYVOX_ASSERT(uBlockY >= 0, "Block coordinate must not be negative."); | ||||
| 		POLYVOX_ASSERT(uBlockZ >= 0, "Block coordinate must not be negative."); | ||||
|  | ||||
| 		//Compute the block index | ||||
| 		uint32_t uBlockIndex = | ||||
| 				uBlockX +  | ||||
| 				uBlockY * m_uWidthInBlocks +  | ||||
| 				uBlockZ * m_uWidthInBlocks * m_uHeightInBlocks; | ||||
|  | ||||
| 		//Return the block | ||||
| 		return &(m_pBlocks[uBlockIndex]); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	/// \todo This function needs reviewing for accuracy... | ||||
| 	/// | ||||
| 	/// \return The number of bytes used | ||||
| 	//////////////////////////////////////////////////////////////////////////////// | ||||
| 	template <typename VoxelType> | ||||
| 	uint32_t SimpleVolume<VoxelType>::calculateSizeInBytes(void) | ||||
| 	{ | ||||
| 		uint32_t uSizeInBytes = sizeof(SimpleVolume); | ||||
| 		 | ||||
| 		uint32_t uSizeOfBlockInBytes = m_uNoOfVoxelsPerBlock * sizeof(VoxelType); | ||||
|  | ||||
| 		//Memory used by the blocks | ||||
| 		uSizeInBytes += uSizeOfBlockInBytes * (m_uNoOfBlocksInVolume); | ||||
|  | ||||
| 		return uSizeInBytes; | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	template <WrapMode eWrapMode> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, 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 <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, 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<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position. | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, 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<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position. | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const | ||||
| 	{ | ||||
| 		if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos)) | ||||
| 		{ | ||||
| 			return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position. | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return tBorder; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, 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<uint16_t>(uXPos - (blockX << m_uBlockSideLengthPower)); | ||||
| 		const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower)); | ||||
| 		const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower)); | ||||
|  | ||||
| 		typename SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ); | ||||
|  | ||||
| 		return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -1,130 +0,0 @@ | ||||
| /******************************************************************************* | ||||
| Copyright (c) 2005-2009 David Williams | ||||
|  | ||||
| This software is provided 'as-is', without any express or implied | ||||
| warranty. In no event will the authors be held liable for any damages | ||||
| arising from the use of this software. | ||||
|  | ||||
| Permission is granted to anyone to use this software for any purpose, | ||||
| including commercial applications, and to alter it and redistribute it | ||||
| freely, subject to the following restrictions: | ||||
|  | ||||
|     1. The origin of this software must not be misrepresented; you must not | ||||
|     claim that you wrote the original software. If you use this software | ||||
|     in a product, an acknowledgment in the product documentation would be | ||||
|     appreciated but is not required. | ||||
|  | ||||
|     2. Altered source versions must be plainly marked as such, and must not be | ||||
|     misrepresented as being the original software. | ||||
|  | ||||
|     3. This notice may not be removed or altered from any source | ||||
|     distribution. 	 | ||||
| *******************************************************************************/ | ||||
|  | ||||
| #include "PolyVoxCore/Impl/ErrorHandling.h" | ||||
|  | ||||
| namespace PolyVox | ||||
| { | ||||
| 	template <typename VoxelType> | ||||
| 	SimpleVolume<VoxelType>::Block::Block(uint16_t uSideLength) | ||||
| 		:m_tUncompressedData(0) | ||||
| 		,m_uSideLength(0) | ||||
| 		,m_uSideLengthPower(0) | ||||
| 	{ | ||||
| 		if(uSideLength != 0) | ||||
| 		{ | ||||
| 			initialise(uSideLength); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	SimpleVolume<VoxelType>::Block::~Block() | ||||
| 	{ | ||||
| 		delete[] m_tUncompressedData; | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	uint16_t SimpleVolume<VoxelType>::Block::getSideLength(void) const | ||||
| 	{ | ||||
| 		return m_uSideLength; | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Block::getVoxelAt(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, "Position is outside of the block."); | ||||
| 		POLYVOX_ASSERT(uYPos < m_uSideLength, "Position is outside of the block."); | ||||
| 		POLYVOX_ASSERT(uZPos < m_uSideLength, "Position is outside of the block."); | ||||
| 		POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data available"); | ||||
|  | ||||
| 		return m_tUncompressedData | ||||
| 			[ | ||||
| 				uXPos +  | ||||
| 				uYPos * m_uSideLength +  | ||||
| 				uZPos * m_uSideLength * m_uSideLength | ||||
| 			]; | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Block::getVoxelAt(const Vector3DUint16& v3dPos) const | ||||
| 	{ | ||||
| 		return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Block::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue) | ||||
| 	{ | ||||
| 		// This is internal code not directly called by the user. For efficiency we assert rather than throwing. | ||||
| 		POLYVOX_ASSERT(uXPos < m_uSideLength, "Position is outside of the block."); | ||||
| 		POLYVOX_ASSERT(uYPos < m_uSideLength, "Position is outside of the block."); | ||||
| 		POLYVOX_ASSERT(uZPos < m_uSideLength, "Position is outside of the block."); | ||||
| 		POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data available"); | ||||
|  | ||||
| 		m_tUncompressedData | ||||
| 		[ | ||||
| 			uXPos +  | ||||
| 			uYPos * m_uSideLength +  | ||||
| 			uZPos * m_uSideLength * m_uSideLength | ||||
| 		] = tValue; | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Block::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue) | ||||
| 	{ | ||||
| 		setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Block::fill(VoxelType tValue) | ||||
| 	{ | ||||
| 		const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength; | ||||
| 		std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, tValue); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Block::initialise(uint16_t uSideLength) | ||||
| 	{ | ||||
| 		//Release mode validation | ||||
| 		if(!isPowerOf2(uSideLength)) | ||||
| 		{ | ||||
| 			POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two."); | ||||
| 		} | ||||
|  | ||||
| 		//Compute the side length		 | ||||
| 		m_uSideLength = uSideLength; | ||||
| 		m_uSideLengthPower = logBase2(uSideLength); | ||||
|  | ||||
| 		m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength]; | ||||
|  | ||||
| 		SimpleVolume<VoxelType>::Block::fill(VoxelType()); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	uint32_t SimpleVolume<VoxelType>::Block::calculateSizeInBytes(void) | ||||
| 	{ | ||||
| 		uint32_t uSizeInBytes = sizeof(Block); | ||||
| 		uSizeInBytes += sizeof(VoxelType) * m_uSideLength * m_uSideLength * m_uSideLength; | ||||
| 		return  uSizeInBytes; | ||||
| 	} | ||||
| } | ||||
| @@ -1,581 +0,0 @@ | ||||
| /******************************************************************************* | ||||
| Copyright (c) 2005-2009 David Williams | ||||
|  | ||||
| This software is provided 'as-is', without any express or implied | ||||
| warranty. In no event will the authors be held liable for any damages | ||||
| arising from the use of this software. | ||||
|  | ||||
| Permission is granted to anyone to use this software for any purpose, | ||||
| including commercial applications, and to alter it and redistribute it | ||||
| freely, subject to the following restrictions: | ||||
|  | ||||
|     1. The origin of this software must not be misrepresented; you must not | ||||
|     claim that you wrote the original software. If you use this software | ||||
|     in a product, an acknowledgment in the product documentation would be | ||||
|     appreciated but is not required. | ||||
|  | ||||
|     2. Altered source versions must be plainly marked as such, and must not be | ||||
|     misrepresented as being the original software. | ||||
|  | ||||
|     3. This notice may not be removed or altered from any source | ||||
|     distribution. 	 | ||||
| *******************************************************************************/ | ||||
|  | ||||
| #define CAN_GO_NEG_X(val) ((val > this->mVolume->getEnclosingRegion().getLowerX()) && (val % this->mVolume->m_uBlockSideLength != 0)) | ||||
| #define CAN_GO_POS_X(val) ((val < this->mVolume->getEnclosingRegion().getUpperX()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0)) | ||||
| #define CAN_GO_NEG_Y(val) ((val > this->mVolume->getEnclosingRegion().getLowerY()) && (val % this->mVolume->m_uBlockSideLength != 0)) | ||||
| #define CAN_GO_POS_Y(val) ((val < this->mVolume->getEnclosingRegion().getUpperY()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0)) | ||||
| #define CAN_GO_NEG_Z(val) ((val > this->mVolume->getEnclosingRegion().getLowerZ()) && (val % this->mVolume->m_uBlockSideLength != 0)) | ||||
| #define CAN_GO_POS_Z(val) ((val < this->mVolume->getEnclosingRegion().getUpperZ()) && ((val + 1) % this->mVolume->m_uBlockSideLength != 0)) | ||||
|  | ||||
| namespace PolyVox | ||||
| { | ||||
| 	/** | ||||
| 	 * \param volume The SimpleVolume you want to sample | ||||
| 	 */ | ||||
| 	template <typename VoxelType> | ||||
| 	SimpleVolume<VoxelType>::Sampler::Sampler(SimpleVolume<VoxelType>* volume) | ||||
| 		:BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >(volume) | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	SimpleVolume<VoxelType>::Sampler::~Sampler() | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::getSubSampledVoxel(uint8_t uLevel) const | ||||
| 	{		 | ||||
| 		if(uLevel == 0) | ||||
| 		{ | ||||
| 			return getVoxel(); | ||||
| 		} | ||||
| 		else if(uLevel == 1) | ||||
| 		{ | ||||
| 			VoxelType tValue = getVoxel(); | ||||
| 			tValue = (std::min)(tValue, peekVoxel1px0py0pz()); | ||||
| 			tValue = (std::min)(tValue, peekVoxel0px1py0pz()); | ||||
| 			tValue = (std::min)(tValue, peekVoxel1px1py0pz()); | ||||
| 			tValue = (std::min)(tValue, peekVoxel0px0py1pz()); | ||||
| 			tValue = (std::min)(tValue, peekVoxel1px0py1pz()); | ||||
| 			tValue = (std::min)(tValue, peekVoxel0px1py1pz()); | ||||
| 			tValue = (std::min)(tValue, peekVoxel1px1py1pz()); | ||||
| 			return tValue; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			const uint8_t uSize = 1 << uLevel; | ||||
|  | ||||
| 			VoxelType tValue = (std::numeric_limits<VoxelType>::max)(); | ||||
| 			for(uint8_t z = 0; z < uSize; ++z) | ||||
| 			{ | ||||
| 				for(uint8_t y = 0; y < uSize; ++y) | ||||
| 				{ | ||||
| 					for(uint8_t x = 0; x < uSize; ++x) | ||||
| 					{ | ||||
| 						tValue = (std::min)(tValue, this->mVolume->getVoxelAt(this->mXPosInVolume + x, this->mYPosInVolume + y, this->mZPosInVolume + z)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			return tValue; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * \return The current voxel | ||||
| 	 */ | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::getVoxel(void) const | ||||
| 	{ | ||||
| 		if(this->isCurrentPositionValid()) | ||||
| 		{ | ||||
| 			return *mCurrentVoxel; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return this->getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * \param v3dNewPos The position to set to | ||||
| 	 */ | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Sampler::setPosition(const Vector3DInt32& v3dNewPos) | ||||
| 	{ | ||||
| 		setPosition(v3dNewPos.getX(), v3dNewPos.getY(), v3dNewPos.getZ()); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * \param xPos The \a x position to set to | ||||
| 	 * \param yPos The \a y position to set to | ||||
| 	 * \param zPos The \a z position to set to | ||||
| 	 */ | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Sampler::setPosition(int32_t xPos, int32_t yPos, int32_t zPos) | ||||
| 	{ | ||||
| 		// Base version updates position and validity flags. | ||||
| 		BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::setPosition(xPos, yPos, zPos); | ||||
|  | ||||
| 		// Then we update the voxel pointer | ||||
| 		if(this->isCurrentPositionValid()) | ||||
| 		{ | ||||
| 			const int32_t uXBlock = this->mXPosInVolume >> this->mVolume->m_uBlockSideLengthPower; | ||||
| 			const int32_t uYBlock = this->mYPosInVolume >> this->mVolume->m_uBlockSideLengthPower; | ||||
| 			const int32_t uZBlock = this->mZPosInVolume >> this->mVolume->m_uBlockSideLengthPower; | ||||
|  | ||||
| 			const uint16_t uXPosInBlock = static_cast<uint16_t>(this->mXPosInVolume - (uXBlock << this->mVolume->m_uBlockSideLengthPower)); | ||||
| 			const uint16_t uYPosInBlock = static_cast<uint16_t>(this->mYPosInVolume - (uYBlock << this->mVolume->m_uBlockSideLengthPower)); | ||||
| 			const uint16_t uZPosInBlock = static_cast<uint16_t>(this->mZPosInVolume - (uZBlock << this->mVolume->m_uBlockSideLengthPower)); | ||||
|  | ||||
| 			const uint32_t uVoxelIndexInBlock = uXPosInBlock +  | ||||
| 					uYPosInBlock * this->mVolume->m_uBlockSideLength +  | ||||
| 					uZPosInBlock * this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength; | ||||
|  | ||||
| 			Block* pUncompressedCurrentBlock = this->mVolume->getUncompressedBlock(uXBlock, uYBlock, uZBlock); | ||||
|  | ||||
| 			mCurrentVoxel = pUncompressedCurrentBlock->m_tUncompressedData + uVoxelIndexInBlock; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			mCurrentVoxel = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * \details | ||||
| 	 *  | ||||
| 	 * This function checks that the current voxel position that you're trying | ||||
| 	 * to set is not outside the volume. If it is, this function returns | ||||
| 	 * \a false, otherwise it will return \a true. | ||||
| 	 *  | ||||
| 	 * \param tValue The value to set to voxel to | ||||
| 	 */ | ||||
| 	template <typename VoxelType> | ||||
| 	bool SimpleVolume<VoxelType>::Sampler::setVoxel(VoxelType tValue) | ||||
| 	{ | ||||
| 		if(this->m_bIsCurrentPositionValidInX && this->m_bIsCurrentPositionValidInY && this->m_bIsCurrentPositionValidInZ) | ||||
| 		{ | ||||
| 			*mCurrentVoxel = tValue; | ||||
| 			return true; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Sampler::movePositiveX(void) | ||||
| 	{ | ||||
| 		// We'll need this in a moment... | ||||
| 		bool bIsOldPositionValid = this->isCurrentPositionValid(); | ||||
|  | ||||
| 		// Base version updates position and validity flags. | ||||
| 		BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::movePositiveX(); | ||||
|  | ||||
| 		// Then we update the voxel pointer | ||||
| 		if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume) % this->mVolume->m_uBlockSideLength != 0)) | ||||
| 		{ | ||||
| 			//No need to compute new block. | ||||
| 			++mCurrentVoxel;			 | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			//We've hit the block boundary. Just calling setPosition() is the easiest way to resolve this. | ||||
| 			setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Sampler::movePositiveY(void) | ||||
| 	{ | ||||
| 		// We'll need this in a moment... | ||||
| 		bool bIsOldPositionValid = this->isCurrentPositionValid(); | ||||
|  | ||||
| 		// Base version updates position and validity flags. | ||||
| 		BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::movePositiveY(); | ||||
|  | ||||
| 		// Then we update the voxel pointer | ||||
| 		if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume) % this->mVolume->m_uBlockSideLength != 0)) | ||||
| 		{ | ||||
| 			//No need to compute new block. | ||||
| 			mCurrentVoxel += this->mVolume->m_uBlockSideLength; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			//We've hit the block boundary. Just calling setPosition() is the easiest way to resolve this. | ||||
| 			setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Sampler::movePositiveZ(void) | ||||
| 	{ | ||||
| 		// We'll need this in a moment... | ||||
| 		bool bIsOldPositionValid = this->isCurrentPositionValid(); | ||||
|  | ||||
| 		// Base version updates position and validity flags. | ||||
| 		BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::movePositiveZ(); | ||||
|  | ||||
| 		// Then we update the voxel pointer | ||||
| 		if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume) % this->mVolume->m_uBlockSideLength != 0)) | ||||
| 		{ | ||||
| 			//No need to compute new block. | ||||
| 			mCurrentVoxel += this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			//We've hit the block boundary. Just calling setPosition() is the easiest way to resolve this. | ||||
| 			setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Sampler::moveNegativeX(void) | ||||
| 	{ | ||||
| 		// We'll need this in a moment... | ||||
| 		bool bIsOldPositionValid = this->isCurrentPositionValid(); | ||||
|  | ||||
| 		// Base version updates position and validity flags. | ||||
| 		BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::moveNegativeX(); | ||||
|  | ||||
| 		// Then we update the voxel pointer | ||||
| 		if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0)) | ||||
| 		{ | ||||
| 			//No need to compute new block. | ||||
| 			--mCurrentVoxel;			 | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			//We've hit the block boundary. Just calling setPosition() is the easiest way to resolve this. | ||||
| 			setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Sampler::moveNegativeY(void) | ||||
| 	{ | ||||
| 		// We'll need this in a moment... | ||||
| 		bool bIsOldPositionValid = this->isCurrentPositionValid(); | ||||
|  | ||||
| 		// Base version updates position and validity flags. | ||||
| 		BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::moveNegativeY(); | ||||
|  | ||||
| 		// Then we update the voxel pointer | ||||
| 		if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0)) | ||||
| 		{ | ||||
| 			//No need to compute new block. | ||||
| 			mCurrentVoxel -= this->mVolume->m_uBlockSideLength; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			//We've hit the block boundary. Just calling setPosition() is the easiest way to resolve this. | ||||
| 			setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	void SimpleVolume<VoxelType>::Sampler::moveNegativeZ(void) | ||||
| 	{ | ||||
| 		// We'll need this in a moment... | ||||
| 		bool bIsOldPositionValid = this->isCurrentPositionValid(); | ||||
|  | ||||
| 		// Base version updates position and validity flags. | ||||
| 		BaseVolume<VoxelType>::template Sampler< SimpleVolume<VoxelType> >::moveNegativeZ(); | ||||
|  | ||||
| 		// Then we update the voxel pointer | ||||
| 		if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume + 1) % this->mVolume->m_uBlockSideLength != 0)) | ||||
| 		{ | ||||
| 			//No need to compute new block. | ||||
| 			mCurrentVoxel -= this->mVolume->m_uBlockSideLength * this->mVolume->m_uBlockSideLength; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			//We've hit the block boundary. Just calling setPosition() is the easiest way to resolve this. | ||||
| 			setPosition(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1ny1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1ny0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1ny1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx0py1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx0py0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx0py1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1py1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1py0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1nx1py1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - 1 + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1ny1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1ny0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1ny1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px0py1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px0py0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid())) | ||||
| 		{ | ||||
| 			return *mCurrentVoxel; | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px0py1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1py1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1py0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel0px1py1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1ny1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1ny0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1ny1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px0py1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1 - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px0py0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px0py1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1py1nz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength - this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1py0pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
|  | ||||
| 	template <typename VoxelType> | ||||
| 	VoxelType SimpleVolume<VoxelType>::Sampler::peekVoxel1px1py1pz(void) const | ||||
| 	{ | ||||
| 		if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) | ||||
| 		{ | ||||
| 			return *(mCurrentVoxel + 1 + this->mVolume->m_uBlockSideLength + this->mVolume->m_uBlockSideLength*this->mVolume->m_uBlockSideLength); | ||||
| 		} | ||||
| 		return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| #undef CAN_GO_NEG_X | ||||
| #undef CAN_GO_POS_X | ||||
| #undef CAN_GO_NEG_Y | ||||
| #undef CAN_GO_POS_Y | ||||
| #undef CAN_GO_NEG_Z | ||||
| #undef CAN_GO_POS_Z | ||||
| @@ -32,7 +32,7 @@ namespace PolyVox | ||||
| 	template <typename VoxelType> | ||||
|     class UncompressedBlock | ||||
|     { | ||||
| 		friend class LargeVolume<VoxelType>; | ||||
| 		friend class PagedVolume<VoxelType>; | ||||
|  | ||||
| 	public: | ||||
| 		UncompressedBlock(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager<VoxelType>* pPager = nullptr); | ||||
| @@ -54,7 +54,7 @@ namespace PolyVox | ||||
| 		/// Private assignment operator to prevent accisdental copying | ||||
| 		UncompressedBlock& operator=(const UncompressedBlock& /*rhs*/) {}; | ||||
|  | ||||
| 		// This is updated by the LargeVolume and used to discard the least recently used blocks. | ||||
| 		// This is updated by the PagedVolume and used to discard the least recently used blocks. | ||||
| 		uint32_t m_uBlockLastAccessed; | ||||
|  | ||||
| 		// This is so we can tell whether a uncompressed block has to be recompressed and whether | ||||
|   | ||||
		Reference in New Issue
	
	Block a user