voxelTerrain
 All Classes Functions Variables Typedefs Enumerations Pages
sender.hpp
1 #ifndef NETWORK_SYNC_VOXEL_ACCESSOR_MULTIPLETILES_SENDER_HPP
2 #define NETWORK_SYNC_VOXEL_ACCESSOR_MULTIPLETILES_SENDER_HPP
3 
4 #include "blub/async/dispatcher.hpp"
5 #include "blub/core/byteArray.hpp"
6 #include "blub/core/hashList.hpp"
7 #include "blub/core/hashMap.hpp"
8 #include "blub/core/signal.hpp"
9 #include "blub/log/global.hpp"
10 #include "blub/math/axisAlignedBox.hpp"
11 #include "blub/math/octree/search.hpp"
12 #include "blub/procedural/predecl.hpp"
13 #include "blub/procedural/voxel/simple/accessor.hpp"
14 #include "blub/procedural/voxel/tile/accessor.hpp"
15 #include "blub/sync/log/global.hpp"
16 #include "blub/sync/sender.hpp"
17 #include "blub/sync/voxel/accessor/multipleTiles/base.hpp"
18 
19 #include <boost/iostreams/copy.hpp>
20 #include <boost/iostreams/filter/bzip2.hpp>
21 #include <boost/iostreams/filtering_stream.hpp>
22 #include <boost/iostreams/stream.hpp>
23 #include <boost/function/function2.hpp>
24 #include <boost/signals2/connection.hpp>
25 
26 
27 namespace blub
28 {
29 namespace sync
30 {
31 namespace voxel
32 {
33 namespace accessor
34 {
35 namespace multipleTiles
36 {
37 
38 
39 template <class voxelType, class identifierType>
40 class sender : protected ::blub::sync::sender<vector3int32, sharedPointer<identifierType> >
41 {
42 public:
43  typedef identifierType t_identifier;
44  typedef vector3int32 t_tileId;
48 
50 
53 
57 
59 
60  typedef boost::function<bool (vector3, axisAlignedBox)> t_octreeSearchCallback;
61 
63 
64 
65  sender(async::dispatcher &worker, const real &voxelSize, const t_octreeSearchCallback& octreeSearch, t_multipleTilesAccessor* tiles)
66  : t_base(worker, vector3int32(t_tileContainer::voxelLength))
67  , m_worker(worker)
68  , m_voxels(tiles)
69  , m_searchFunction(octreeSearch)
70  , m_voxelSize(voxelSize)
71  , m_numtilesInWork(0)
72  {
73  BASSERT(tiles != nullptr);
74 
75  m_connTileVoxelEditDone = m_voxels->signalEditDone()->connect(boost::bind(&sender::tileEditDone, this));
76  }
77  virtual ~sender()
78  {
79  ;
80  }
81 
82  // to "send sync"
83  void tileEditDone()
84  {
85  BASSERT(m_voxels != nullptr);
86 
87  m_voxels->lockForRead();
88 
89  t_base::m_master.post(boost::bind(&sender::tileEditDoneMaster, this));
90  }
91 
92  // add/update/remove sync-reveiver
93  void addSyncReceiver(t_receiverIdentifierPtr receiver, const vector3& pos)
94  {
95  BASSERT(!receiver.isNull());
96 
97  t_base::m_master.post(boost::bind(&sender::addSyncReceiverMaster, this, receiver, pos));
98  }
99  void updateSyncReceiver(t_receiverIdentifierPtr receiver, const vector3& pos)
100  {
101  BASSERT(!receiver.isNull());
102 
103  t_base::m_master.post(boost::bind(&sender::updateSyncReceiverMaster, this, receiver, pos));
104  }
105  void removeSyncReceiver(t_receiverIdentifierPtr receiver)
106  {
107  BASSERT(!receiver.isNull());
108 
109  t_base::m_master.post(boost::bind(&sender::removeSyncReceiverMaster, this, receiver));
110  }
111 
112  // to "send sync" signals
114  t_sigSendTileData* signalSendTileData()
115  {
116  return &m_sigSendTileData;
117  }
118 
119 protected:
120  void tileEditDoneMaster()
121  {
122  const t_tileAccessorChangeList& changeList(m_voxels->getTilesThatGotEdited());
123 
124  BASSERT(m_numtilesInWork == 0);
125  m_numtilesInWork = changeList.size();
126 
127  for (auto change : changeList)
128  {
129  t_tileId id(change.first);
130  t_tileAccessorPtr workTile(change.second);
131 
132  if (workTile.isNull()) // when empty/full
133  {
134  compressTileAfterMaster(id, workTile, nullptr);
135  continue;
136  }
137  t_tileDataMap::const_iterator it = m_tileData.find(id);
138  if (it == m_tileData.cend())
139  {
140  BASSERT(!workTile->isEmpty());
141  BASSERT(!workTile->isFull());
142  m_worker.post(boost::bind(&sender::compressTileWorker, this, id, workTile, nullptr));
143  continue;
144  }
145  m_worker.post(boost::bind(&sender::compressTileWorker, this, id, workTile, it->second));
146  }
147  }
148 
149  void addSyncReceiverMaster(t_receiverIdentifierPtr receiver, const vector3& pos)
150  {
151  t_base::addReceiverMaster(receiver, pos / m_voxelSize);
152 
153  unlockAllReceiver();
154  }
155  void updateSyncReceiverMaster(t_receiverIdentifierPtr receiver, const vector3& pos)
156  {
157  if (t_base::m_receiverPosMap.find(receiver) == t_base::m_receiverPosMap.cend())
158  {
159  BLUB_SYNC_LOG_WARNING() << "m_receiverPosMap.find(receiver) == m_receiverPosMap.cend()";
160  return;
161  }
162  //blub::BOUT("sender::updateSyncReceiverMaster m_voxelSize:" + blub::string::number(m_voxelSize)
163  // + " pos:" + blub::string::number(pos));
164  t_base::updateReceiverMaster(receiver, pos / m_voxelSize);
165 
166  unlockAllReceiver();
167  }
168  void removeSyncReceiverMaster(t_receiverIdentifierPtr receiver)
169  {
170  t_base::removeReceiverMaster(receiver);
171 
172  unlockAllReceiver();
173  }
174 
175  void sendSetTileMaster(t_receiverIdentifierPtr receiver, const t_tileId &id, t_tileDataPtr data)
176  {
177  std::stringstream result;
178  {
180 
181  sendType typeToSend = sendType::setTile;
182  if (data.isNull())
183  {
184  typeToSend = sendType::removeTile;
185  }
186  format << typeToSend;
187  format << id;
188  if (!data.isNull())
189  {
190  format << *data.get();
191  }
192  } // flush happens here
193  t_tileDataPtr send(new byteArray(result.str().c_str(), result.str().size()));
194 
195  m_sigSendTileData(receiver, send);
196  }
197  void sendLockUnlockForEditMaster(sender::t_receiverIdentifierPtr receiver, const bool& lock)
198  {
199  std::stringstream result;
200  {
202 
203  sendType typeToSend = sendType::unlockForEdit;
204  if (lock)
205  {
206  typeToSend = sendType::lockForEdit;
207  }
208  format << typeToSend;
209  } // flush happens here
210  t_tileDataPtr send(new byteArray(result.str().c_str(), result.str().size()));
211 
212  m_sigSendTileData(receiver, send);
213  }
214  void sendLockForEditMaster(sender::t_receiverIdentifierPtr receiver)
215  {
216  sendLockUnlockForEditMaster(receiver, true);
217  }
218  void sendUnlockForEditMaster(sender::t_receiverIdentifierPtr receiver)
219  {
220  sendLockUnlockForEditMaster(receiver, false);
221  }
222 
223  void compressTileWorker(const t_tileId& id, const t_tileAccessorPtr &tile, t_tileDataPtr toSave)
224  {
225  BASSERT(!tile.isNull());
226 
227  std::stringstream toCompress;
228  {
230 
231  format << *tile.get();
232  } // flush happens here
233 
234  std::ostringstream dataContainerCompressed;
235  {
236  boost::iostreams::filtering_ostream filterOut;
237  filterOut.push(boost::iostreams::bzip2_compressor());
238  filterOut.push(dataContainerCompressed);
239 
240  boost::iostreams::copy(toCompress, filterOut);
241  }
242 
243  const int32 sizeCompressed = dataContainerCompressed.str().size();
244 
245  if (toSave.isNull())
246  {
247  toSave = new byteArray(dataContainerCompressed.str().data(), sizeCompressed);
248  }
249  else
250  {
251  toSave->resize(sizeCompressed);
252  memcpy(toSave->data(), dataContainerCompressed.str().data(), sizeCompressed);
253  }
254 
255  t_base::m_master.post(boost::bind(&sender::compressTileAfterMaster, this, id, tile, toSave));
256  }
257  void compressTileAfterMaster(const t_tileId& id, const t_tileAccessorPtr &tile, t_tileDataPtr toSave)
258  {
259  t_tileDataMap::const_iterator it = m_tileData.find(id);
260  const bool found(it != m_tileData.cend());
261 
262  if (found && tile.isNull()) // remove tile
263  {
264  m_tileData.erase(it);
265  t_base::removeSyncMaster(id);
266  }
267  else
268  if (found && !tile.isNull()) // change - no save in m_tileData needed, pointer still valid
269  {
270  typename t_base::t_syncToReceiversMap::const_iterator itTile = t_base::m_syncReceivers.find(id);
271  BASSERT(itTile != t_base::m_syncReceivers.cend());
272  const typename t_base::t_receiverList& receivers(itTile->second);
273  for (typename t_base::t_receiverList::const_iterator itRec = receivers.cbegin(); itRec != receivers.cend(); ++itRec)
274  {
275  lockReceiver(*itRec);
276  sendSetTileMaster(*itRec, id, toSave);
277  }
278  }
279  else
280  if (!found && !tile.isNull()) // add
281  {
282  m_tileData.insert(id, toSave);
283 
284  const vector3int32 pos(id*t_base::m_syncTree.getMinNodeSize() + t_base::m_syncTree.getMinNodeSize()/2);
285  t_base::addSyncMaster(id, vector3(pos));
286  }
287  else
288  {
289  BLUB_SYNC_LOG_ERROR() << "compressTileAfterMaster: invalid case";
290  }
291 
292  --m_numtilesInWork;
293  BASSERT(m_numtilesInWork >= 0);
294  if (m_numtilesInWork == 0)
295  {
296  m_voxels->unlockRead();
297 
298  unlockAllReceiver();
299  }
300  }
301 
302 
303  void lockReceiver(const typename t_base::t_receiver toLock)
304  {
305  if (m_lockedReceiverList.find(toLock) == m_lockedReceiverList.cend())
306  {
307  m_lockedReceiverList.insert(toLock);
308  sendLockForEditMaster(toLock);
309  }
310  }
311  void unlockAllReceiver()
312  {
313  // blub::BOUT("sender::unlockAllReceiver() m_lockedReceiverList.size():" + blub::string::number(m_lockedReceiverList.size()));
314  for (auto rec : m_lockedReceiverList)
315  {
316  sendUnlockForEditMaster(rec);
317  }
318  m_lockedReceiverList.clear();
319  }
320 
321  virtual bool isInSyncRangeReceiver(const typename t_base::t_receiver receiver, const vector3 &posOfReceiverLeafCenter, const typename t_base::t_syncTree::t_nodePtr& octreeNode)
322  {
323  (void)receiver;
324  return m_searchFunction(posOfReceiverLeafCenter, axisAlignedBox(octreeNode->getBoundingBox()));
325  }
326  virtual bool isInSyncRangeSync(const typename t_base::t_sync sync, const vector3 &posOfSyncLeafCenter, const typename t_base::t_receiverTree::t_nodePtr& octreeNode)
327  {
328  (void)sync;
329  return m_searchFunction(posOfSyncLeafCenter, axisAlignedBox(octreeNode->getBoundingBox()));
330  }
331  void addSyncReceiver(const typename t_base::t_receiver receiver, const typename t_base::t_sync sync) override
332  {
333  lockReceiver(receiver);
334 
335  t_tileDataMap::const_iterator it(m_tileData.find(sync));
336  BASSERT(it != m_tileData.cend());
337  sendSetTileMaster(receiver, sync, it->second);
338  }
339  void removeSyncReceiver(const typename t_base::t_receiver receiver, const typename t_base::t_sync sync) override
340  {
341  lockReceiver(receiver);
342 
343  sendSetTileMaster(receiver, sync, nullptr);
344  }
345 
346 
347 
348  blub::async::dispatcher &m_worker;
349 
350  t_multipleTilesAccessor* m_voxels;
351  t_octreeSearchCallback m_searchFunction;
352  real m_voxelSize;
353 
354  t_tileDataMap m_tileData;
355 
356  int32 m_numtilesInWork;
357  t_lockedReceiverList m_lockedReceiverList;
358 
359  t_sigSendTileData m_sigSendTileData;
360 
361  boost::signals2::scoped_connection m_connTileVoxelEditDone;
362 
363 };
364 
365 
366 }
367 }
368 }
369 }
370 }
371 
372 
373 #endif // NETWORK_SYNC_VOXEL_ACCESSOR_MULTIPLETILES_SENDER_HPP
The base class gets derived by every class in the namespace simple::*. It represends one level of det...
Definition: predecl.hpp:30
Definition: predecl.hpp:8
The container class contains an array of voxel. The amount of voxel per tile is voxelLength^3. The class counts how many voxel are max and how many are min. if all voxel are min or max the class simple::container::base doesnt save them. Additionally it saves an axisAlignedBox which describes the bounds of the voxel that changed.
Definition: predecl.hpp:19
const t_tilesGotChangedMap & getTilesThatGotEdited() const
getTilesThatGotEdited returns a list of tiles which changed since the last call lockForEdit() / lockF...
Definition: base.hpp:198
Definition: portable_binary_oarchive.hpp:63
Definition: sharedPointer.hpp:12
void unlockRead()
unlockRead unlocks the class after reading.
Definition: base.hpp:192
Definition: dispatcher.hpp:29
The accessor class caches all voxel needed by tile::surface for an extremly optimized and fast calcul...
Definition: predecl.hpp:21
Definition: vector3.hpp:26
void lockForRead()
lockForRead locks the class for reading.
Definition: base.hpp:186
Definition: axisAlignedBox.hpp:20
t_sigEditDone * signalEditDone()
signalEditDone gets called after unlockForEdit() got called.
Definition: base.hpp:261
Definition: byteArray.hpp:17
Definition: deadlineTimer.hpp:10
Definition: customVertexInformation.cpp:177