PolyVox  0.3.0-dev
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 
26 
27 #include "PolyVoxCore/Compressor.h"
28 #include "PolyVoxCore/Vector.h"
29 
31 
32 #include <cstring> //For memcpy
33 #include <limits>
34 #include <stdexcept> //for std::invalid_argument
35 
36 namespace PolyVox
37 {
38  template <typename VoxelType>
40  :m_pCompressedData(0)
41  ,m_uCompressedDataLength(0)
42  ,m_tUncompressedData(0)
43  ,m_uSideLength(0)
44  ,m_uSideLengthPower(0)
45  ,m_bIsCompressed(false)
46  ,m_bIsUncompressedDataModified(true)
47  {
48  if(uSideLength != 0)
49  {
50  initialise(uSideLength);
51  }
52  }
53 
54  template <typename VoxelType>
56  {
57  return m_uSideLength;
58  }
59 
60  template <typename VoxelType>
62  {
63  POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block");
64  POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block");
65  POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block");
66 
67  POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels.");
68 
69  return m_tUncompressedData
70  [
71  uXPos +
72  uYPos * m_uSideLength +
73  uZPos * m_uSideLength * m_uSideLength
74  ];
75  }
76 
77  template <typename VoxelType>
79  {
80  return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
81  }
82 
83  template <typename VoxelType>
85  {
86  POLYVOX_ASSERT(uXPos < m_uSideLength, "Supplied position is outside of the block");
87  POLYVOX_ASSERT(uYPos < m_uSideLength, "Supplied position is outside of the block");
88  POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the block");
89 
90  POLYVOX_ASSERT(m_tUncompressedData, "No uncompressed data - block must be decompressed before accessing voxels.");
91 
92  m_tUncompressedData
93  [
94  uXPos +
95  uYPos * m_uSideLength +
96  uZPos * m_uSideLength * m_uSideLength
97  ] = tValue;
98 
99  m_bIsUncompressedDataModified = true;
100  }
101 
102  template <typename VoxelType>
104  {
105  setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
106  }
107 
108  template <typename VoxelType>
110  {
111  //Debug mode validation
112  POLYVOX_ASSERT(isPowerOf2(uSideLength), "Block side length must be a power of two.");
113 
114  //Release mode validation
115  if(!isPowerOf2(uSideLength))
116  {
117  POLYVOX_THROW(std::invalid_argument, "Block side length must be a power of two.");
118  }
119 
120  //Compute the side length
121  m_uSideLength = uSideLength;
122  m_uSideLengthPower = logBase2(uSideLength);
123 
124  //Create the block data
125  m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
126 
127  //Clear it (should we bother?)
128  const uint32_t uNoOfVoxels = m_uSideLength * m_uSideLength * m_uSideLength;
129  std::fill(m_tUncompressedData, m_tUncompressedData + uNoOfVoxels, VoxelType());
130  m_bIsUncompressedDataModified = true;
131  }
132 
133  template <typename VoxelType>
135  {
136  //FIXME - This function is incomplete.
137  uint32_t uSizeInBytes = sizeof(Block<VoxelType>);
138  return uSizeInBytes;
139  }
140 
141  template <typename VoxelType>
143  {
144  POLYVOX_ASSERT(pCompressor, "Compressor is not valid");
145  POLYVOX_ASSERT(m_bIsCompressed == false, "Attempted to compress block which is already flagged as compressed.");
146  POLYVOX_ASSERT(m_tUncompressedData != 0, "No uncompressed data is present.");
147 
148  //If the uncompressed data hasn't actually been
149  //modified then we don't need to redo the compression.
150  if(m_bIsUncompressedDataModified)
151  {
152  // Delete the old compressed data as we'll create a new one
153  delete[] m_pCompressedData;
154  m_pCompressedData = 0;
155 
156  void* pSrcData = reinterpret_cast<void*>(m_tUncompressedData);
157  uint32_t uSrcLength = m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType);
158 
159  uint8_t tempBuffer[10000];
160  void* pDstData = reinterpret_cast<void*>( tempBuffer );
161  uint32_t uDstLength = 10000;
162 
163  uint32_t uCompressedLength = 0;
164 
165  try
166  {
167  uCompressedLength = pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength);
168 
169  // Create new compressed data and copy across
170  m_pCompressedData = new uint8_t[uCompressedLength];
171  memcpy(m_pCompressedData, pDstData, uCompressedLength);
172  m_uCompressedDataLength = uCompressedLength;
173  }
174  catch(std::exception&)
175  {
176  // It is possible for the compression to fail. A common cause for this would be if the destination
177  // buffer is not big enough. So now we try again using a buffer that is definitely big enough.
178  // Note that ideally we will choose our earlier buffer size so that this almost never happens.
179  uint32_t uMaxCompressedSize = pCompressor->getMaxCompressedSize(uSrcLength);
180  uint8_t* buffer = new uint8_t[ uMaxCompressedSize ];
181 
182  pDstData = reinterpret_cast<void*>( buffer );
183  uDstLength = uMaxCompressedSize;
184 
185  try
186  {
187  uCompressedLength = pCompressor->compress(pSrcData, uSrcLength, pDstData, uDstLength);
188 
189  // Create new compressed data and copy across
190  m_pCompressedData = new uint8_t[uCompressedLength];
191  memcpy(m_pCompressedData, pDstData, uCompressedLength);
192  m_uCompressedDataLength = uCompressedLength;
193  }
194  catch(std::exception&)
195  {
196  // At this point it didn't work even with a bigger buffer.
197  // Not much more we can do so just rethrow the exception.
198  delete[] buffer;
199  POLYVOX_THROW(std::runtime_error, "Failed to compress block data");
200  }
201 
202  delete[] buffer;
203  }
204  }
205 
206  //Flag the uncompressed data as no longer being used.
207  delete[] m_tUncompressedData;
208  m_tUncompressedData = 0;
209  m_bIsCompressed = true;
210  }
211 
212  template <typename VoxelType>
214  {
215  POLYVOX_ASSERT(pCompressor, "Compressor is not valid");
216  POLYVOX_ASSERT(m_bIsCompressed == true, "Attempted to uncompress block which is not flagged as compressed.");
217  POLYVOX_ASSERT(m_tUncompressedData == 0, "Uncompressed data already exists.");
218 
219  m_tUncompressedData = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
220 
221  void* pSrcData = reinterpret_cast<void*>(m_pCompressedData);
222  void* pDstData = reinterpret_cast<void*>(m_tUncompressedData);
223  uint32_t uSrcLength = m_uCompressedDataLength;
224  uint32_t uDstLength = m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType);
225 
226  //MinizCompressor compressor;
227  //RLECompressor<VoxelType, uint16_t> compressor;
228  uint32_t uUncompressedLength = pCompressor->decompress(pSrcData, uSrcLength, pDstData, uDstLength);
229 
230  POLYVOX_ASSERT(uUncompressedLength == m_uSideLength * m_uSideLength * m_uSideLength * sizeof(VoxelType), "Destination length has changed.");
231 
232  //m_tUncompressedData = reinterpret_cast<VoxelType*>(uncompressedResult.ptr);
233 
234  m_bIsCompressed = false;
235  m_bIsUncompressedDataModified = false;
236  }
237 }