voxelTerrain
 All Classes Functions Variables Typedefs Enumerations Pages
accessor.hpp
1 #ifndef PROCEDURAL_VOXEL_ACCESSOR_ACCESSOR_HPP
2 #define PROCEDURAL_VOXEL_ACCESSOR_ACCESSOR_HPP
3 
4 #include "blub/async/mutexReadWrite.hpp"
5 #include "blub/core/globals.hpp"
6 #include "blub/core/hashList.hpp"
7 #include "blub/core/hashMap.hpp"
8 #include "blub/core/noncopyable.hpp"
9 #include "blub/core/signal.hpp"
10 #include "blub/math/axisAlignedBoxInt32.hpp"
11 #include "blub/math/vector3.hpp"
12 #include "blub/procedural/log/global.hpp"
13 #include "blub/procedural/voxel/simple/base.hpp"
14 #include "blub/procedural/voxel/simple/container/base.hpp"
15 #include "blub/procedural/voxel/simple/container/utils/tile.hpp"
16 #include "blub/procedural/voxel/tile/accessor.hpp"
17 #include "blub/procedural/voxel/tile/container.hpp"
18 
19 
20 namespace blub
21 {
22 namespace procedural
23 {
24 namespace voxel
25 {
26 namespace simple
27 {
28 
29 
35 template <class configType>
36 class accessor : public base<typename configType::t_accessor::t_tile>
37 {
38 public:
39  typedef configType t_config;
40  typedef typename t_config::t_accessor::t_tile t_tile;
41  typedef sharedPointer<t_tile> t_tilePtr;
42  typedef base<t_tile> t_base;
43  typedef typename t_config::t_data t_voxel;
44 
45  typedef typename t_base::t_tileId t_tileId;
46  typedef hashMap<vector3int32, t_tilePtr> t_tiles;
47 
48  typedef typename t_config::t_container::t_tile t_tileContainer;
49  typedef sharedPointer<t_tileContainer> t_tileContainerPtr;
50  typedef hashList<vector3int32> t_tileIdList;
51  typedef container::utils::tileState t_tileState;
52  typedef container::utils::tile<t_tileContainer> t_tileHolder;
53  typedef hashMap<t_tileId, t_tileHolder> t_tileHolderMap;
54 
55  typedef typename t_config::t_container::t_simple t_simpleContainerVoxel;
56 
57 
66  t_simpleContainerVoxel &voxels,
67  const int32& lod)
68  : t_base(worker)
69  , m_voxels(voxels)
70  , m_lod(lod)
71  , m_voxelSkip(math::pow(2, m_lod))
72  , m_numTilesInWork(0)
73  {
74  m_connTilesGotChanged = m_voxels.signalEditDone()->connect(boost::bind(&accessor::tilesGotChanged, this));
75 
76  t_base::setCreateTileCallback(boost::bind(&t_tile::create));
77  }
78 
83  {
84 #ifdef BLUB_LOG_VOXEL
85  blub::BOUT("accessor::~accessor()");
86 #endif
87  }
88 
93  t_simpleContainerVoxel &getVoxelContainer() const
94  {
95  return m_voxels;
96  }
97 
104  t_tilePtr getTile(const t_tileId& id) const
105  {
106  typename t_tiles::const_iterator it = m_tiles.find(id);
107  if (it == m_tiles.cend())
108  {
109  return nullptr;
110  }
111  return it->second;
112  }
113 
114 protected:
120  {
121  m_voxels.lockForRead();
122  t_base::m_master.post(boost::bind(&accessor::tilesGotChangedMaster, this));
123  }
124 
130  {
131  const auto& changedTiles(m_voxels.getTilesThatGotEdited());
132 #ifdef BLUB_LOG_VOXEL
133  BLUB_PROCEDURAL_LOG_OUT() << "accessor tilesGotChangedMaster changedTiles.size():" << changedTiles.size();
134 #endif
135  BASSERT(!changedTiles.empty());
136  /*if (changedTiles.empty())
137  {
138  m_voxels.unlockRead();
139  return;
140  }*/
141 
142  t_tileIdList affectedTiles;
143  for (auto change : changedTiles)
144  {
145  const t_tileId id(change.first);
146  const t_tileHolder workTile(change.second);
147 
148  if (m_lod == 0) // optimisation on lod_0 only
149  {
150  if (workTile.state == container::utils::tileState::empty)
151  {
152  if (m_tiles.find(id) == m_tiles.cend())
153  {
154  continue;
155  }
156  }
157  }
158 
159  calculateAffectedAccessorTilesByContainerTile(id, workTile, affectedTiles);
160  }
161 
162  if (affectedTiles.empty())
163  {
164 // blub::BWARNING("affectedTiles.empty()");
165  m_voxels.unlockRead();
166  return;
167  }
168 
170  BASSERT(m_numTilesInWork == 0);
171  m_numTilesInWork = affectedTiles.size();
172 
173  for (const t_tileId id : affectedTiles)
174  {
175  t_base::m_worker.post(boost::bind(&accessor::calculateAccessorTS, this, id, getTile(id)));
176  }
177  }
178 
184  void calculateAccessorTS(const t_tileId& id, t_tilePtr workTile)
185  {
186  if (workTile.isNull())
187  {
188  workTile = createTile();
189  // workTile->setEmpty();
190  }
191 
192  const vector3int32 voxelStart(id*t_tile::voxelLength*m_voxelSkip);
193  // axisAlignedBoxInt32 lastUsedTileBounds;
194  t_tileHolderMap lastUsedTiles;
195 
196  bool valuesChanged(false);
197  for (int32 indX = -1; indX < t_tile::voxelLength+2; ++indX)
198  {
199  for (int32 indY = -1; indY < t_tile::voxelLength+2; ++indY)
200  {
201  for (int32 indZ = -1; indZ < t_tile::voxelLength+2; ++indZ)
202  {
203  const vector3int32 pos(indX, indY, indZ);
204  const vector3int32 voxelPosAbs(voxelStart + pos*m_voxelSkip);
205 
206  valuesChanged |= workTile->setVoxel(pos, getVoxelData(voxelPosAbs, /*lastUsedTileBounds, */lastUsedTiles));
207  }
208  }
209  }
210 
211  if (workTile->getCalculateLod())
212  {
213  BASSERT(m_voxelSkip > 0);
214 
215  const int32 voxelLengthLod = t_tile::voxelLengthLod;
216  const vector3int32 toIterate[][2] = {
217  {vector3int32(0, 0, 0), vector3int32(1, voxelLengthLod, voxelLengthLod)},
218  {vector3int32(voxelLengthLod-2, 0, 0), vector3int32(voxelLengthLod-1, voxelLengthLod, voxelLengthLod)},
219  {vector3int32(0, 0, 0), vector3int32(voxelLengthLod, 1, voxelLengthLod)},
220  {vector3int32(0, voxelLengthLod-2, 0), vector3int32(voxelLengthLod, voxelLengthLod-1, voxelLengthLod)},
221  {vector3int32(0, 0, 0), vector3int32(voxelLengthLod, voxelLengthLod, 1)},
222  {vector3int32(0, 0, voxelLengthLod-2), vector3int32(voxelLengthLod, voxelLengthLod, voxelLengthLod-1)},
223  };
224  for (int32 lod = 0; lod < 6; ++lod)
225  {
226  const vector3int32& start(toIterate[lod][0]);
227  const vector3int32& end(toIterate[lod][1]);
228  for (int32 indX = start.x; indX < end.x; ++indX)
229  {
230  for (int32 indY = start.y; indY < end.y; ++indY)
231  {
232  for (int32 indZ = start.z; indZ < end.z; ++indZ)
233  {
234  const vector3int32 pos(indX, indY, indZ);
235  const vector3int32 voxelPosAbs(voxelStart + pos*(m_voxelSkip/2));
236 
237  const t_voxel result(getVoxelData(voxelPosAbs, /*lastUsedTileBounds, */lastUsedTiles));
238  #ifdef BLUB_DEBUG
239  if (indX % 2 == 0 &&
240  indY % 2 == 0 &&
241  indZ % 2 == 0)
242  {
243  BASSERT(workTile->getVoxel(pos / 2) == result);
244  }
245  #endif
246 
247  valuesChanged |= workTile->setVoxelLod(pos-start, result, lod);
248  }
249  }
250  }
251  }
252  }
253 
254  if (workTile->isEmpty() || workTile->isFull())
255  {
256  t_base::m_master.post(boost::bind(&accessor::afterCalculateAccessorMaster, this, id, nullptr, true));
257  return;
258  }
259 
260  t_base::m_master.post(boost::bind(&accessor::afterCalculateAccessorMaster, this, id, workTile, valuesChanged));
261  }
262 
269  void afterCalculateAccessorMaster(const t_tileId& id, t_tilePtr workTile, const bool &didValuesChanged)
270  {
271  BASSERT(t_base::getTilesThatGotEdited().find(id) == t_base::getTilesThatGotEdited().cend());
272 
273  typename t_tiles::const_iterator it = m_tiles.find(id);
274 
275  // no indices
276  if (workTile.isNull())
277  {
278  if (it != m_tiles.cend())
279  {
280  m_tiles.erase(it);
281  t_base::addToChangeList(id, nullptr);
282  }
283  }
284  else
285  {
286  BASSERT(!workTile.isNull());
287  if (it == m_tiles.cend())
288  {
289  m_tiles.insert(id, workTile);
290  }
291  if (didValuesChanged)
292  {
293  t_base::addToChangeList(id, workTile);
294  }
295  }
296 
297 
298  --m_numTilesInWork;
299  if (m_numTilesInWork == 0)
300  {
301  if (t_base::m_tilesThatGotEdited.size() == 0)
302  {
303  BLUB_LOG_WARNING() << "nothing changed";
304  }
305  m_voxels.unlockRead();
307  }
308  }
309 
310 
318  void calculateAffectedAccessorTilesByContainerTile(const t_tileId& conterainerId, const t_tileHolder &holder, t_tileIdList& resultingSurfaceTiles)
319  {
320  const vector3 forDiv(conterainerId);
321  const vector3int32 result((forDiv / (real)m_voxelSkip).getFloor());
322  resultingSurfaceTiles.insert(result);
323 
324  vector3int32 minimum(0);
325  if (holder.state == t_tileState::partitial)
326  {
327  BASSERT(holder.data->getEditedVoxelBoundingBox().isValid());
328  minimum = holder.data->getEditedVoxelBoundingBox().getMinimum();
329  }
330  if (minimum > vector3int32(0))
331  {
332  return;
333  }
334 
335  const vector3int32 resultMod(conterainerId%m_voxelSkip);
336  if (resultMod.x == 0 && minimum.x == 0)
337  {
338  resultingSurfaceTiles.insert(result - vector3int32(1, 0, 0));
339  }
340  if (resultMod.y == 0 && minimum.y == 0)
341  {
342  resultingSurfaceTiles.insert(result - vector3int32(0, 1, 0));
343  }
344  if (resultMod.z == 0 && minimum.z == 0)
345  {
346  resultingSurfaceTiles.insert(result - vector3int32(0, 0, 1));
347  }
348  if (resultMod.x == 0 && resultMod.y == 0 && minimum.x == 0 && minimum.y == 0)
349  {
350  resultingSurfaceTiles.insert(result - vector3int32(1, 1, 0));
351  }
352  if (resultMod.x == 0 && resultMod.z == 0 && minimum.x == 0 && minimum.z == 0)
353  {
354  resultingSurfaceTiles.insert(result - vector3int32(1, 0, 1));
355  }
356  if (resultMod.y == 0 && resultMod.z == 0 && minimum.y == 0 && minimum.z == 0)
357  {
358  resultingSurfaceTiles.insert(result - vector3int32(0, 1, 1));
359  }
360  if (resultMod.x == 0 && resultMod.y == 0 && resultMod.z == 0 && minimum == vector3int32(0))
361  {
362  resultingSurfaceTiles.insert(result - vector3int32(1, 1, 1));
363  }
364  }
365 
370  t_tilePtr createTile() const override
371  {
372  t_tilePtr result(t_base::createTile());
373  result->setCalculateLod(m_lod > 0);
374  return result;
375  }
376 
383  t_voxel getVoxelData(const vector3int32& voxelPosAbs, t_tileHolderMap& lastUsedTiles)
384  {
385  const vector3int32 &tilePos(m_voxels.calculateVoxelPosToTileId(voxelPosAbs));
386  const vector3int32 &tilePosAbs(tilePos*vector3int32(t_tile::voxelLength));
387 
388  typename t_tileHolderMap::const_iterator it = lastUsedTiles.find(tilePos);
389 
390  t_voxel result;
391  if (it != lastUsedTiles.cend())
392  {
393  const t_tileHolder &lastUsedTile(it->second);
394  switch(lastUsedTile.state)
395  {
396  case t_tileState::partitial:
397  result = lastUsedTile.data->getVoxel(voxelPosAbs-tilePosAbs);
398  break;
399  case t_tileState::empty:
400  result.setMin();
401  break;
402  case t_tileState::full:
403  result.setMax();
404  break;
405  default:
406  BASSERT(false);
407  }
408  return result;
409  }
410 
411  // get new tile
412  const t_tileHolder &lastUsedTile(m_voxels.getTileHolder(tilePos));
413  lastUsedTiles.insert(tilePos, lastUsedTile);
414 
415  // repeat step ahead
416  switch(lastUsedTile.state)
417  {
418  case t_tileState::partitial:
419  result = lastUsedTile.data->getVoxel(voxelPosAbs-tilePosAbs);
420  break;
421  case t_tileState::empty:
422  result.setMin();
423  break;
424  case t_tileState::full:
425  result.setMax();
426  break;
427  default:
428  BASSERT(false);
429  }
430  return result;
431  }
432 
433 protected:
434 
435  t_simpleContainerVoxel& m_voxels;
436  const int32 m_lod;
437  const int32 m_voxelSkip;
438  int32 m_numTilesInWork;
439 
440  t_tiles m_tiles;
441 
442  boost::signals2::scoped_connection m_connTilesGotChanged;
443 };
444 
445 
446 }
447 }
448 }
449 }
450 
451 
452 #endif // PROCEDURAL_VOXEL_ACCESSOR_ACCESSOR_HPP
virtual void lockForEditMaster()
lockForEditMaster locks for write, or waits until possible. Call by master dispatcher.
Definition: base.hpp:228
void tilesGotChangedMaster()
tilesGotChangedMaster must not get called paralell.
Definition: accessor.hpp:129
Definition: customVertexInformation.cpp:193
t_simpleContainerVoxel & getVoxelContainer() const
getVoxelContainer returns the voxel container, set in the constructor.
Definition: accessor.hpp:93
void setMax()
setMax sets all values to maximum. See class description.
Definition: data.hpp:113
void setMin()
setMin sets all values to minimum. See class description.
Definition: data.hpp:105
Definition: math.hpp:15
vector3int32 t_tileId
Definition: base.hpp:44
virtual t_tilePtr createTile() const
createTile creates a new Tile. Uses callback set by setCreateTileCallback()
Definition: base.hpp:249
void afterCalculateAccessorMaster(const t_tileId &id, t_tilePtr workTile, const bool &didValuesChanged)
afterCalculateAccessorMaster gets called after a worker-thread finished calculation of a part...
Definition: accessor.hpp:269
virtual void unlockForEditMaster()
unlockForEditMaster unlocks write. Call by master dispatcher.
Definition: base.hpp:236
const t_tilesGotChangedMap & getTilesThatGotEdited() const
getTilesThatGotEdited returns a list of tiles which changed since the last call lockForEdit() / lockF...
Definition: base.hpp:198
t_voxel getVoxelData(const vector3int32 &voxelPosAbs, t_tileHolderMap &lastUsedTiles)
getVoxelData returns a voxel from a cahned container-tile or looks up the tile and returns it...
Definition: accessor.hpp:383
void addToChangeList(const t_tileId &id, t_tilePtr toAdd)
addToChangeList adds a tile to the change-list.
Definition: base.hpp:210
Definition: dispatcher.hpp:29
t_tilePtr getTile(const t_tileId &id) const
getTile returns an accessor tile. Read-lock class before.
Definition: accessor.hpp:104
Definition: vector3.hpp:26
accessor(async::dispatcher &worker, t_simpleContainerVoxel &voxels, const int32 &lod)
accessor constructor
Definition: accessor.hpp:65
~accessor()
~accessor destructor
Definition: accessor.hpp:82
void calculateAccessorTS(const t_tileId &id, t_tilePtr workTile)
calculateAccessorTS accesses the container and pulls out all voxel needed for surface calculation (ma...
Definition: accessor.hpp:184
The data class is the default voxel. Contains an 8-bit interpolation value. Replace/derive it and set...
Definition: data.hpp:27
blub::async::dispatcher & m_worker
m_worker use it to dispatch heavy work. Don't write to class member with it. Do not use any locks...
Definition: base.hpp:148
void tilesGotChanged()
tilesGotChanged gets called after in the voxel container m_voxels, set in the constructor, the voxels changed. Which leads to a recalculation of the cache.
Definition: accessor.hpp:119
t_tilePtr createTile() const override
createTile creates an empty tile.
Definition: accessor.hpp:370
void calculateAffectedAccessorTilesByContainerTile(const t_tileId &conterainerId, const t_tileHolder &holder, t_tileIdList &resultingSurfaceTiles)
When a tile in container gets changed it affects (because of normal-correction and lod) 3^3 accessor-...
Definition: accessor.hpp:318
Definition: deadlineTimer.hpp:10
blub::async::strand m_master
m_master The master synchronises jobs for the worker-thread and writes to class member. The master calls all methods which end with *Master.
Definition: base.hpp:143
void setCreateTileCallback(const t_createTileCallback &callback)
setCreateTileCallback sets a callback for creating tiles. Use this method if you want to create custo...
Definition: base.hpp:204
Definition: customVertexInformation.cpp:177