voxelTerrain
 All Classes Functions Variables Typedefs Enumerations Pages
renderer.hpp
1 #ifndef BLUB_PROCEDURAL_VOXEL_SIMPLE_RENDERER_HPP
2 #define BLUB_PROCEDURAL_VOXEL_SIMPLE_RENDERER_HPP
3 
4 #include "blub/core/globals.hpp"
5 #include "blub/core/hashMap.hpp"
6 #include "blub/log/global.hpp"
7 #include "blub/math/octree/container.hpp"
8 #include "blub/math/vector3.hpp"
9 #include "blub/procedural/voxel/simple/base.hpp"
10 #include "blub/procedural/voxel/simple/surface.hpp"
11 #include "blub/procedural/voxel/tile/renderer.hpp"
12 #include "blub/procedural/voxel/tile/surface.hpp"
13 #include "blub/sync/predecl.hpp"
14 #include "blub/sync/sender.hpp"
15 
16 #include <functional>
17 
18 
19 namespace blub
20 {
21 namespace procedural
22 {
23 namespace voxel
24 {
25 namespace simple
26 {
27 
28 
35 // TODO reimplement class, with better threading and better octree/sync.
36 template <class configType>
37 class renderer : public base<typename configType::t_renderer::t_tile>
38 {
39 public:
40  typedef configType t_config;
41  typedef typename t_config::t_renderer::t_tile t_tile;
42  typedef sharedPointer<t_tile> t_tilePtr;
43  typedef base<t_tile> t_base;
44  typedef typename t_base::t_tileId t_tileId;
45 
46  typedef sharedPointer<sync::identifier> t_cameraPtr;
47  typedef sync::sender<t_tileId, t_cameraPtr> t_sync;
48 
49  typedef hashMap<vector3int32, t_tilePtr> t_tileMap;
50 
51  typedef typename t_config::t_surface::t_tile t_tileSurface;
52  typedef sharedPointer<t_tileSurface> t_tileDataPtr;
53 
54  typedef std::function<bool (vector3, axisAlignedBox)> t_octreeSearchCallback;
55 
56  typedef typename t_config::t_surface::t_simple t_rendererSurface;
57 
58 
68  t_rendererSurface *tiles,
69  const int32 &lod,
70  const real &lodCutDistNear,
71  const real &lodCutDistFar)
72  : t_base(worker)
73  , m_lod(lod)
74  , m_lodCutDistNear(lodCutDistNear)
75  , m_lodCutDistFar(lodCutDistFar)
76  , m_voxelSize(math::pow(2., m_lod))
77  , m_voxels(tiles)
78  {
79  const int32 voxelsPerTile(t_config::voxelsPerTile);
80  m_sync = new t_sync(worker, vector3int32(voxelsPerTile));
81  m_sync->setCallbackInSyncRangeReceiver(boost::bind(&renderer::isInSyncRangeReceiver, this, _1, _2, _3));
82  m_sync->setCallbackInSyncRangeSync(boost::bind(&renderer::isInSyncRangeSync, this, _1, _2, _3));
83  m_sync->signalAdd()->connect(boost::bind(&renderer::addSyncReceiver, this, _1, _2));
84  m_sync->signalRemove()->connect(boost::bind(&renderer::removeSyncReceiver, this, _1, _2));
85 
86  m_voxels->signalEditDone()->connect(boost::bind(&renderer::editDone, this));
87  }
92  {
93  delete m_sync;
94  }
95 
101  // adding more than one camera is untested - but should work.
102  void addCamera(t_cameraPtr toAdd, const blub::vector3& position)
103  {
104  m_sync->addReceiver(toAdd, position / m_voxelSize);
105  }
111  void updateCamera(t_cameraPtr toUpdate, const blub::vector3& position)
112  {
113  m_sync->getMaster().dispatch(boost::bind(&renderer::updateCameraMaster, this, toUpdate, position));
114  }
119  void removeCamera(t_cameraPtr toRemove)
120  {
121  m_sync->removeReceiver(toRemove);
122  }
123 
124  // lock class for read before work
129  const t_tileMap &getTileMap() const
130  {
131  return m_tileData;
132  }
133 
134 protected:
138  void editDone()
139  {
140  m_voxels->lockForRead();
141  t_base::m_worker.post(boost::bind(&renderer::editDoneMaster, this));
142  }
143 
149  {
150  auto& change(m_voxels->getTilesThatGotEdited());
151  for (auto hasChanged : change)
152  {
153  const t_tileId id(hasChanged.first);
154  const t_tileDataPtr work(hasChanged.second);
155 
156  if (work.isNull())
157  {
159  }
160  else
161  {
162  tileGotSetMaster(id, work);
163  }
164  }
165 
166  m_voxels->unlockRead();
167  }
168 
174  void tileGotSetMaster(const t_tileId& id, const t_tileDataPtr toSet)
175  {
176  BASSERT(toSet->getIndices().size() > 0);
177 
178  typename t_tileMap::const_iterator it = m_tileData.find(id);
179  const bool found(it != m_tileData.cend());
180 
181  const int32 voxelsPerTile(t_config::voxelsPerTile);
182  axisAlignedBox aabb(vector3(id*voxelsPerTile),
183  vector3(id*voxelsPerTile+vector3int32(voxelsPerTile)));
184  aabb*=m_voxelSize;
185  t_tilePtr workTile;
186  if (found)
187  {
188  workTile = it->second;
189  }
190  else
191  {
192  workTile = t_base::createTile();
193  }
194 
195  workTile->setTileData(toSet, aabb);
196 
197  if (!found)
198  {
199  m_tileData.insert(id, workTile);
200 
201  const vector3int32 size(voxelsPerTile);
202  vector3int32 pos(id*size + size/2);
203  m_sync->addSyncMaster(id, vector3(pos));
204  }
205  }
206 
211  void tileGotRemovedMaster(const t_tileId& id)
212  {
213  typename t_tileMap::const_iterator it = m_tileData.find(id);
214  BASSERT(it != m_tileData.cend());
215 
216  m_sync->removeSyncMaster(id);
217 
218  m_tileData.erase(it);
219  }
220 
224  bool isInSyncRangeReceiver(const typename t_sync::t_receiver receiver,
225  const vector3 &posOfReceiverLeafCenter,
226  const typename t_sync::t_syncTree::t_nodePtr& octreeNode)
227  {
228  (void)receiver;
229  return isInRange(posOfReceiverLeafCenter, axisAlignedBox(octreeNode->getBoundingBox())) == 0;
230  }
234  bool isInSyncRangeSync(const typename t_sync::t_sync sync,
235  const vector3 &posOfSyncLeafCenter,
236  const typename t_sync::t_receiverTree::t_nodePtr& octreeNode)
237  {
238  (void)sync;
239  return isInRange(posOfSyncLeafCenter, axisAlignedBox(octreeNode->getBoundingBox())) == 0;
240  }
241 
247  void addSyncReceiver(const typename t_sync::t_receiver receiver,
248  const typename t_sync::t_sync sync)
249  {
250  (void)receiver;
251  typename t_tileMap::const_iterator it(m_tileData.find(sync));
252  BASSERT(it != m_tileData.cend());
253 
254  it->second->setVisible(true);
255 
256  updateLod(sync, it->second);
257  }
263  void removeSyncReceiver(const typename t_sync::t_receiver receiver,
264  const typename t_sync::t_sync sync)
265  {
266  (void)receiver;
267  typename t_tileMap::const_iterator it(m_tileData.find(sync));
268  BASSERT(it != m_tileData.cend());
269 
270  it->second->setVisible(false);
271 
272  updateLod(sync, it->second);
273  }
274 
281  void updateLod(const t_tileId &id, t_tilePtr toUpdate)
282  {
283  if (m_lod == 0)
284  {
285  return;
286  }
287  /*if (toUpdate->getVisible() && isInRange(m_cameraPositionInTreeLeaf, axisAlignedBox(neighbourOctreeNode)) == 2)
288  {
289  return; // got invis because too far away --> no lod on this tile
290  // leads to bug when syncRadien are chosen too small.
291  }*/
292 
293  const int32 sizeLeaf(t_config::voxelsPerTile);
294  const vector3int32 posAbs(id*sizeLeaf);
295  const axisAlignedBoxInt32 octreeNode(posAbs, posAbs+vector3int32(sizeLeaf));
296  const vector3int32 toIterate[] = {vector3int32(-1, 0, 0),
297  vector3int32(1, 0, 0),
298  vector3int32(0, -1, 0),
299  vector3int32(0, 1, 0),
300  vector3int32(0, 0, -1),
301  vector3int32(0, 0, 1)
302  };
303  const int32 toSetOnNeighbour[] = {1, 0, 3, 2, 5, 4};
304  const int32 tileWork(isInRange(m_cameraPositionInTreeLeaf, axisAlignedBox(octreeNode)));
305  if ((tileWork == 0) != toUpdate->getVisible())
306  {
307  BLUB_PROCEDURAL_LOG_WARNING() << "(tileWork == 0) != toUpdate->getVisible() id:" << id; // may occur, when server deletes tile message, arrives before up-to-date camera position.
308  }
309  for (int32 lod = 0; lod < 6; ++lod)
310  {
311  const vector3int32 neighbourId(id+toIterate[lod]);
312  const vector3int32 neighbourPosAbs(neighbourId*sizeLeaf);
313  const axisAlignedBoxInt32 neighbourOctreeNode(neighbourPosAbs, neighbourPosAbs+vector3int32(sizeLeaf));
314  const int32 doLod(isInRange(m_cameraPositionInTreeLeaf, axisAlignedBox(neighbourOctreeNode)));
315  if (toUpdate->getVisible())
316  {
317  toUpdate->setVisibleLod(lod, doLod == 1);
318  }
319  else
320  {
321  toUpdate->setVisibleLod(lod, false);
322  }
323  typename t_tileMap::const_iterator it(m_tileData.find(neighbourId));
324  if (it == m_tileData.cend())
325  {
326  continue;
327  }
328  if (toUpdate->getVisible())
329  {
330  it->second->setVisibleLod(toSetOnNeighbour[lod], false);
331  }
332  else
333  {
334  it->second->setVisibleLod(toSetOnNeighbour[lod], tileWork == 1);
335  }
336  }
337  }
338 
345  int32 isInRange(const vector3& posLeafCenter, const axisAlignedBox& octreeNode)
346  {
347  const vector3 sizeLeaf(t_config::voxelsPerTile);
348  const vector3 sizeLeafDoubled(sizeLeaf*2);
349  const vector3 octreeNodeTwiceMinimum((octreeNode.getMinimum()/sizeLeafDoubled).getFloor()*sizeLeafDoubled);
350  const axisAlignedBox octreeNodeTwice(octreeNodeTwiceMinimum, octreeNodeTwiceMinimum + octreeNode.getSize()*2.);
351 
352  const vector3 posLeafCenterScaled((posLeafCenter / sizeLeafDoubled).getFloor());
353 
354  if (m_lod != 0)
355  {
356  if (octreeNode.getSize() == sizeLeaf)
357  {
358  const real radius(m_lodCutDistNear / 2.);
359  blub::sphere coll2(posLeafCenter, radius);
360  if (coll2.intersects(octreeNode))
361  {
362  return 1;
363  }
364  }
365  }
366 
367  const real radius(m_lodCutDistFar);
368  blub::sphere coll(posLeafCenterScaled * sizeLeafDoubled + sizeLeaf, radius);
369  if(coll.intersects(octreeNodeTwice))
370  {
371  return 0;
372  }
373  else
374  {
375  return 2;
376  }
377  }
378 
382  void updateCameraMaster(t_cameraPtr toUpdate, const blub::vector3& position)
383  {
384  const vector3 camPosScaled(position / m_voxelSize);
385  const real tileContainerSize(t_config::voxelsPerTile);
386  m_cameraPositionInTreeLeaf = (camPosScaled/tileContainerSize).getFloor()*tileContainerSize + vector3(tileContainerSize*0.5);
387  m_sync->updateReceiverMaster(toUpdate, camPosScaled);
388  }
389 
390 private:
391  const int32 m_lod;
392  const real m_lodCutDistNear;
393  const real m_lodCutDistFar;
394  vector3 m_cameraPositionInTreeLeaf;
395  real m_voxelSize;
396  t_rendererSurface* m_voxels;
397 
398  t_tileMap m_tileData; // TODO remove me. insert the tile into the tree, instead of the id --> faster and cleaner.
399  t_sync *m_sync;
400 
401 };
402 
403 
404 }
405 }
406 }
407 }
408 
409 
410 #endif // BLUB_PROCEDURAL_VOXEL_SIMPLE_RENDERER_HPP
void tileGotSetMaster(const t_tileId &id, const t_tileDataPtr toSet)
tileGotSetMaster sets the surface tiles to the octree.
Definition: renderer.hpp:174
Definition: customVertexInformation.cpp:193
Definition: math.hpp:15
vector3int32 t_tileId
Definition: base.hpp:44
vector3 getSize(void) const
Gets the size of the box.
Definition: axisAlignedBox.cpp:57
bool isInSyncRangeReceiver(const typename t_sync::t_receiver receiver, const vector3 &posOfReceiverLeafCenter, const typename t_sync::t_syncTree::t_nodePtr &octreeNode)
Definition: renderer.hpp:224
bool intersects(const sphere &s) const
Definition: sphere.cpp:9
void removeCamera(t_cameraPtr toRemove)
removeCamera removes a camera.
Definition: renderer.hpp:119
virtual t_tilePtr createTile() const
createTile creates a new Tile. Uses callback set by setCreateTileCallback()
Definition: base.hpp:249
void addCamera(t_cameraPtr toAdd, const blub::vector3 &position)
addCamera adds an camera.
Definition: renderer.hpp:102
void editDoneMaster()
editDoneMaster gets called when simple::surface changed.
Definition: renderer.hpp:148
void updateCameraMaster(t_cameraPtr toUpdate, const blub::vector3 &position)
Definition: renderer.hpp:382
Definition: axisAlignedBoxInt32.hpp:12
void tileGotRemovedMaster(const t_tileId &id)
tileGotRemovedMaster removes tile from octree.
Definition: renderer.hpp:211
renderer(blub::async::dispatcher &worker, t_rendererSurface *tiles, const int32 &lod, const real &lodCutDistNear, const real &lodCutDistFar)
renderer constructor.
Definition: renderer.hpp:67
Definition: dispatcher.hpp:29
bool isInSyncRangeSync(const typename t_sync::t_sync sync, const vector3 &posOfSyncLeafCenter, const typename t_sync::t_receiverTree::t_nodePtr &octreeNode)
Definition: renderer.hpp:234
void updateCamera(t_cameraPtr toUpdate, const blub::vector3 &position)
updateCamera updates the position of a camera you have to add before by using addCamera() ...
Definition: renderer.hpp:111
Definition: vector3.hpp:26
~renderer()
~renderer destructor.
Definition: renderer.hpp:91
void updateLod(const t_tileId &id, t_tilePtr toUpdate)
updateLod checks if a neighbour of the tile has a different lod. If so it enables the by the transvox...
Definition: renderer.hpp:281
Definition: axisAlignedBox.hpp:20
const t_tileMap & getTileMap() const
getTileMap Returns all surface-tiles holded by this class. Read-lock class before.
Definition: renderer.hpp:129
void addSyncReceiver(const typename t_sync::t_receiver receiver, const typename t_sync::t_sync sync)
addSyncReceiver gets called by octree if a tile should be visible.
Definition: renderer.hpp:247
const vector3 & getMinimum(void) const
Definition: axisAlignedBox.hpp:126
void removeSyncReceiver(const typename t_sync::t_receiver receiver, const typename t_sync::t_sync sync)
removeSyncReceiver gets called by octree if a tile shouldn't be visible.
Definition: renderer.hpp:263
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
Definition: deadlineTimer.hpp:10
void editDone()
editDone gets called when simple::surface changed. Read-locks surface.
Definition: renderer.hpp:138
int32 isInRange(const vector3 &posLeafCenter, const axisAlignedBox &octreeNode)
isInRange checks the distance of a tile to the camera.
Definition: renderer.hpp:345
Definition: sphere.hpp:10