PolyVox  0.3.0-dev
Open source voxel management library
SimpleVolume.inl
Go to the documentation of this file.
1 /*******************************************************************************
2 Copyright (c) 2005-2009 David Williams
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11 
12  1. The origin of this software must not be misrepresented; you must not
13  claim that you wrote the original software. If you use this software
14  in a product, an acknowledgment in the product documentation would be
15  appreciated but is not required.
16 
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19 
20  3. This notice may not be removed or altered from any source
21  distribution.
22 *******************************************************************************/
23 
25 
26 namespace PolyVox
27 {
33  template <typename VoxelType>
34  SimpleVolume<VoxelType>::SimpleVolume(const Region& regValid, uint16_t uBlockSideLength)
35  :BaseVolume<VoxelType>(regValid)
36  {
37  //Create a volume of the right size.
38  initialise(regValid,uBlockSideLength);
39  }
40 
48  template <typename VoxelType>
50  {
51  POLYVOX_ASSERT(false, "Copy constructor not implemented."); // See function comment above.
52  }
53 
57  template <typename VoxelType>
59  {
60  delete[] m_pBlocks;
61  }
62 
70  template <typename VoxelType>
72  {
73  POLYVOX_ASSERT(false, "Assignment operator not implemented."); // See function comment above.
74  }
75 
82  template <typename VoxelType>
84  {
85  POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
86 
87  const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
88  const int32_t blockY = uYPos >> m_uBlockSideLengthPower;
89  const int32_t blockZ = uZPos >> m_uBlockSideLengthPower;
90 
91  const uint16_t xOffset = static_cast<uint16_t>(uXPos - (blockX << m_uBlockSideLengthPower));
92  const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower));
93  const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower));
94 
95  typename SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
96 
97  return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset);
98  }
99 
104  template <typename VoxelType>
106  {
107  return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
108  }
109 
116  template <typename VoxelType>
118  {
119  if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)))
120  {
121  const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
122  const int32_t blockY = uYPos >> m_uBlockSideLengthPower;
123  const int32_t blockZ = uZPos >> m_uBlockSideLengthPower;
124 
125  const uint16_t xOffset = static_cast<uint16_t>(uXPos - (blockX << m_uBlockSideLengthPower));
126  const uint16_t yOffset = static_cast<uint16_t>(uYPos - (blockY << m_uBlockSideLengthPower));
127  const uint16_t zOffset = static_cast<uint16_t>(uZPos - (blockZ << m_uBlockSideLengthPower));
128 
129  typename SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
130 
131  return pUncompressedBlock->getVoxelAt(xOffset,yOffset,zOffset);
132  }
133  else
134  {
135  return this->getBorderValue();
136  }
137  }
138 
143  template <typename VoxelType>
145  {
146  return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
147  }
148 
155  template <typename VoxelType>
157  {
158  switch(eWrapMode)
159  {
160  case WrapModes::Clamp:
161  {
162  //Perform clamping
163  uXPos = (std::max)(uXPos, this->m_regValidRegion.getLowerX());
164  uYPos = (std::max)(uYPos, this->m_regValidRegion.getLowerY());
165  uZPos = (std::max)(uZPos, this->m_regValidRegion.getLowerZ());
166  uXPos = (std::min)(uXPos, this->m_regValidRegion.getUpperX());
167  uYPos = (std::min)(uYPos, this->m_regValidRegion.getUpperY());
168  uZPos = (std::min)(uZPos, this->m_regValidRegion.getUpperZ());
169 
170  //Get the voxel value
171  return getVoxel(uXPos, uYPos, uZPos);
172  //No need to break as we've returned
173  }
174  case WrapModes::Border:
175  {
176  if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
177  {
178  return getVoxel(uXPos, uYPos, uZPos);
179  }
180  else
181  {
182  return tBorder;
183  }
184  //No need to break as we've returned
185  }
186  default:
187  {
188  //Should never happen
189  POLYVOX_ASSERT(false, "Invalid case.");
190  return VoxelType();
191  }
192  }
193  }
194 
199  template <typename VoxelType>
201  {
202  return getVoxelWithWrapping(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
203  }
204 
212  template <typename VoxelType>
214  {
215  POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
216 
217  const int32_t blockX = uXPos >> m_uBlockSideLengthPower;
218  const int32_t blockY = uYPos >> m_uBlockSideLengthPower;
219  const int32_t blockZ = uZPos >> m_uBlockSideLengthPower;
220 
221  const uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower);
222  const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower);
223  const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower);
224 
225  typename SimpleVolume<VoxelType>::Block* pUncompressedBlock = getUncompressedBlock(blockX, blockY, blockZ);
226 
227  pUncompressedBlock->setVoxelAt(xOffset,yOffset,zOffset, tValue);
228 
229  //Return true to indicate that we modified a voxel.
230  return true;
231  }
232 
238  template <typename VoxelType>
240  {
241  return setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
242  }
243 
247  template <typename VoxelType>
248  void SimpleVolume<VoxelType>::initialise(const Region& regValidRegion, uint16_t uBlockSideLength)
249  {
250  //Debug mode validation
251  POLYVOX_ASSERT(uBlockSideLength >= 8, "Block side length should be at least 8");
252  POLYVOX_ASSERT(uBlockSideLength <= 256, "Block side length should not be more than 256");
253  POLYVOX_ASSERT(isPowerOf2(uBlockSideLength), "Block side length must be a power of two.");
254 
255  //Release mode validation
256  if(uBlockSideLength < 8)
257  {
258  POLYVOX_THROW(std::invalid_argument, "Block side length should be at least 8");
259  }
260  if(uBlockSideLength > 256)
261  {
262  POLYVOX_THROW(std::invalid_argument, "Block side length should not be more than 256");
263  }
264  if(!isPowerOf2(uBlockSideLength))
265  {
266  POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two.");
267  }
268 
269  this->m_regValidRegion = regValidRegion;
270 
271  //Compute the block side length
272  m_uBlockSideLength = uBlockSideLength;
273  m_uBlockSideLengthPower = logBase2(m_uBlockSideLength);
274  m_uNoOfVoxelsPerBlock = m_uBlockSideLength * m_uBlockSideLength * m_uBlockSideLength;
275 
276  m_regValidRegionInBlocks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uBlockSideLengthPower);
277  m_regValidRegionInBlocks.setLowerY(this->m_regValidRegion.getLowerY() >> m_uBlockSideLengthPower);
278  m_regValidRegionInBlocks.setLowerZ(this->m_regValidRegion.getLowerZ() >> m_uBlockSideLengthPower);
279  m_regValidRegionInBlocks.setUpperX(this->m_regValidRegion.getUpperX() >> m_uBlockSideLengthPower);
280  m_regValidRegionInBlocks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uBlockSideLengthPower);
281  m_regValidRegionInBlocks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uBlockSideLengthPower);
282 
283  //Compute the size of the volume in blocks (and note +1 at the end)
284  m_uWidthInBlocks = m_regValidRegionInBlocks.getUpperX() - m_regValidRegionInBlocks.getLowerX() + 1;
285  m_uHeightInBlocks = m_regValidRegionInBlocks.getUpperY() - m_regValidRegionInBlocks.getLowerY() + 1;
286  m_uDepthInBlocks = m_regValidRegionInBlocks.getUpperZ() - m_regValidRegionInBlocks.getLowerZ() + 1;
287  m_uNoOfBlocksInVolume = m_uWidthInBlocks * m_uHeightInBlocks * m_uDepthInBlocks;
288 
289  //Allocate the data
290  m_pBlocks = new Block[m_uNoOfBlocksInVolume];
291  for(uint32_t i = 0; i < m_uNoOfBlocksInVolume; ++i)
292  {
293  m_pBlocks[i].initialise(m_uBlockSideLength);
294  }
295 
296  //Other properties we might find useful later
297  this->m_uLongestSideLength = (std::max)((std::max)(this->getWidth(),this->getHeight()),this->getDepth());
298  this->m_uShortestSideLength = (std::min)((std::min)(this->getWidth(),this->getHeight()),this->getDepth());
299  this->m_fDiagonalLength = sqrtf(static_cast<float>(this->getWidth() * this->getWidth() + this->getHeight() * this->getHeight() + this->getDepth() * this->getDepth()));
300  }
301 
302  template <typename VoxelType>
304  {
305  //The lower left corner of the volume could be
306  //anywhere, but array indices need to start at zero.
307  uBlockX -= m_regValidRegionInBlocks.getLowerX();
308  uBlockY -= m_regValidRegionInBlocks.getLowerY();
309  uBlockZ -= m_regValidRegionInBlocks.getLowerZ();
310 
311  POLYVOX_ASSERT(uBlockX >= 0, "Block coordinate must not be negative.");
312  POLYVOX_ASSERT(uBlockY >= 0, "Block coordinate must not be negative.");
313  POLYVOX_ASSERT(uBlockZ >= 0, "Block coordinate must not be negative.");
314 
315  //Compute the block index
316  uint32_t uBlockIndex =
317  uBlockX +
318  uBlockY * m_uWidthInBlocks +
319  uBlockZ * m_uWidthInBlocks * m_uHeightInBlocks;
320 
321  //Return the block
322  return &(m_pBlocks[uBlockIndex]);
323  }
324 
330  template <typename VoxelType>
332  {
333  uint32_t uSizeInBytes = sizeof(SimpleVolume);
334 
335  uint32_t uSizeOfBlockInBytes = m_uNoOfVoxelsPerBlock * sizeof(VoxelType);
336 
337  //Memory used by the blocks
338  uSizeInBytes += uSizeOfBlockInBytes * (m_uNoOfBlocksInVolume);
339 
340  return uSizeInBytes;
341  }
342 
343 }
344