249 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			249 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*******************************************************************************
 | |
| 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. 	
 | |
| *******************************************************************************/
 | |
| 
 | |
| 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*/)
 | |
| 	{
 | |
| 		assert(false); // See function comment above.
 | |
| 	}
 | |
| 
 | |
| 	////////////////////////////////////////////////////////////////////////////////
 | |
| 	/// 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*/)
 | |
| 	{
 | |
| 		assert(false); // See function comment above.
 | |
| 	}
 | |
| 
 | |
| 	////////////////////////////////////////////////////////////////////////////////
 | |
| 	/// \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 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
 | |
| 	/// \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)
 | |
| 	{
 | |
| 		assert(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 = 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)
 | |
| 	{
 | |
| 		//Debug mode validation
 | |
| 		assert(uBlockSideLength >= 8);
 | |
| 		assert(uBlockSideLength <= 256);
 | |
| 		assert(isPowerOf2(uBlockSideLength));
 | |
| 		
 | |
| 		//Release mode validation
 | |
| 		if(uBlockSideLength < 8)
 | |
| 		{
 | |
| 			throw std::invalid_argument("Block side length should be at least 8");
 | |
| 		}
 | |
| 		if(uBlockSideLength > 256)
 | |
| 		{
 | |
| 			throw std::invalid_argument("Block side length should not be more than 256");
 | |
| 		}
 | |
| 		if(!isPowerOf2(uBlockSideLength))
 | |
| 		{
 | |
| 			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.getUpperCorner().getX() - m_regValidRegionInBlocks.getLowerCorner().getX() + 1;
 | |
| 		m_uHeightInBlocks = m_regValidRegionInBlocks.getUpperCorner().getY() - m_regValidRegionInBlocks.getLowerCorner().getY() + 1;
 | |
| 		m_uDepthInBlocks = m_regValidRegionInBlocks.getUpperCorner().getZ() - m_regValidRegionInBlocks.getLowerCorner().getZ() + 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.getLowerCorner().getX();
 | |
| 		uBlockY -= m_regValidRegionInBlocks.getLowerCorner().getY();
 | |
| 		uBlockZ -= m_regValidRegionInBlocks.getLowerCorner().getZ();
 | |
| 
 | |
| 		//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;
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 |