PolyVox  0.2.1
Open source voxel management library
Block.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 #include "PolyVoxCore/Vector.h"
26 
27 #include <cassert>
28 #include <cstring> //For memcpy
29 #include <limits>
30 #include <stdexcept> //for std::invalid_argument
31 
32 namespace PolyVox
33 {
34  template <typename VoxelType>
35  Block<VoxelType>::Block(uint16_t uSideLength)
36  :m_tUncompressedData(0)
37  ,m_uSideLength(0)
38  ,m_uSideLengthPower(0)
39  ,m_bIsCompressed(true)
40  ,m_bIsUncompressedDataModified(true)
41  {
42  if(uSideLength != 0)
43  {
44  initialise(uSideLength);
45  }
46  }
47 
48  template <typename VoxelType>
49  uint16_t Block<VoxelType>::getSideLength(void) const
50  {
51  return m_uSideLength;
52  }
53 
54  template <typename VoxelType>
55  VoxelType Block<VoxelType>::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
56  {
57  assert(uXPos < m_uSideLength);
58  assert(uYPos < m_uSideLength);
59  assert(uZPos < m_uSideLength);
60 
61  assert(m_tUncompressedData);
62 
63  return m_tUncompressedData
64  [
65  uXPos +
66  uYPos * m_uSideLength +
67  uZPos * m_uSideLength * m_uSideLength
68  ];
69  }
70 
71  template <typename VoxelType>
72  VoxelType Block<VoxelType>::getVoxelAt(const Vector3DUint16& v3dPos) const
73  {
74  return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
75  }
76 
77  template <typename VoxelType>
78  void Block<VoxelType>::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue)
79  {
80  assert(uXPos < m_uSideLength);
81  assert(uYPos < m_uSideLength);
82  assert(uZPos < m_uSideLength);
83 
84  assert(m_tUncompressedData);
85 
86  m_tUncompressedData
87  [
88  uXPos +
89  uYPos * m_uSideLength +
90  uZPos * m_uSideLength * m_uSideLength
91  ] = tValue;
92 
93  m_bIsUncompressedDataModified = true;
94  }
95 
96  template <typename VoxelType>
97  void Block<VoxelType>::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue)
98  {
99  setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
100  }
101 
102  template <typename VoxelType>
103  void Block<VoxelType>::fill(VoxelType tValue)
104  {
105  if(!m_bIsCompressed)
106  {
107  //The memset *may* be faster than the std::fill(), but it doesn't compile nicely
108  //in 64-bit mode as casting the pointer to an int causes a loss of precision.
109  const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
110  std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, tValue);
111 
112  m_bIsUncompressedDataModified = true;
113  }
114  else
115  {
116  RunlengthEntry<uint16_t> rle;
117  rle.length = m_uSideLength*m_uSideLength*m_uSideLength;
118  rle.value = tValue;
119  m_vecCompressedData.clear();
120  m_vecCompressedData.push_back(rle);
121  }
122  }
123 
124  template <typename VoxelType>
125  void Block<VoxelType>::initialise(uint16_t uSideLength)
126  {
127  //Debug mode validation
128  assert(isPowerOf2(uSideLength));
129 
130  //Release mode validation
131  if(!isPowerOf2(uSideLength))
132  {
133  throw std::invalid_argument("Block side length must be a power of two.");
134  }
135 
136  //Compute the side length
137  m_uSideLength = uSideLength;
138  m_uSideLengthPower = logBase2(uSideLength);
139 
140  Block<VoxelType>::fill(VoxelType());
141  }
142 
143  template <typename VoxelType>
145  {
146  uint32_t uSizeInBytes = sizeof(Block<VoxelType>);
147  uSizeInBytes += m_vecCompressedData.capacity() * sizeof(RunlengthEntry<uint16_t>);
148  return uSizeInBytes;
149  }
150 
151  template <typename VoxelType>
153  {
154  assert(m_bIsCompressed == false);
155  assert(m_tUncompressedData != 0);
156 
157  //If the uncompressed data hasn't actually been
158  //modified then we don't need to redo the compression.
159  if(m_bIsUncompressedDataModified)
160  {
161  uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
162  m_vecCompressedData.clear();
163 
164  RunlengthEntry<uint16_t> entry;
165  entry.length = 1;
166  entry.value = m_tUncompressedData[0];
167 
168  for(uint32_t ct = 1; ct < uNoOfVoxels; ++ct)
169  {
170  VoxelType value = m_tUncompressedData[ct];
171  if((value == entry.value) && (entry.length < entry.maxRunlength()))
172  {
173  entry.length++;
174  }
175  else
176  {
177  m_vecCompressedData.push_back(entry);
178  entry.value = value;
179  entry.length = 1;
180  }
181  }
182 
183  m_vecCompressedData.push_back(entry);
184 
185  //Shrink the vectors to their contents (maybe slow?):
186  //http://stackoverflow.com/questions/1111078/reduce-the-capacity-of-an-stl-vector
187  //C++0x may have a shrink_to_fit() function?
188  std::vector< RunlengthEntry<uint16_t> >(m_vecCompressedData).swap(m_vecCompressedData);
189  }
190 
191  //Flag the uncompressed data as no longer being used.
192  delete[] m_tUncompressedData;
193  m_tUncompressedData = 0;
194  m_bIsCompressed = true;
195  }
196 
197  template <typename VoxelType>
199  {
200  assert(m_bIsCompressed == true);
201  assert(m_tUncompressedData == 0);
202  m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
203 
204  VoxelType* pUncompressedData = m_tUncompressedData;
205  for(uint32_t ct = 0; ct < m_vecCompressedData.size(); ++ct)
206  {
207  std::fill(pUncompressedData, pUncompressedData + m_vecCompressedData[ct].length, m_vecCompressedData[ct].value);
208  pUncompressedData += m_vecCompressedData[ct].length;
209  }
210 
211  m_bIsCompressed = false;
212  m_bIsUncompressedDataModified = false;
213  }
214 }