Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
REveScene.cxx
Go to the documentation of this file.
1 // @(#)root/eve7:$Id$
2 // Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007, 2018
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <ROOT/REveScene.hxx>
13 #include <ROOT/REveViewer.hxx>
14 #include <ROOT/REveManager.hxx>
15 #include <ROOT/REveTrans.hxx>
16 #include <ROOT/REveRenderData.hxx>
17 #include <ROOT/REveClient.hxx>
18 #include <ROOT/RWebWindow.hxx>
19 
20 #include "json.hpp"
21 
22 #include <cassert>
23 
24 
25 using namespace ROOT::Experimental;
26 namespace REX = ROOT::Experimental;
27 
28 /** \class REveScene
29 \ingroup REve
30 Eve representation of TGLScene.
31 The GLScene is owned by this class - it is created on construction
32 time and deleted at destruction.
33 
34 Normally all objects are positioned directly in global scene-space.
35 By setting the fHierarchical flag, positions of children get
36 calculated by multiplying the transformation matrices of all parents.
37 */
38 
39 ////////////////////////////////////////////////////////////////////////////////
40 /// Constructor.
41 
42 REveScene::REveScene(const std::string& n, const std::string& t) :
43  REveElement(n, t)
44 {
45  fScene = this;
46 }
47 
48 ////////////////////////////////////////////////////////////////////////////////
49 /// Destructor.
50 
51 REveScene::~REveScene()
52 {
53  fDestructing = kStandard;
54 
55  REX::gEve->GetViewers()->SceneDestructing(this);
56  REX::gEve->GetScenes()->RemoveElement(this);
57 }
58 
59 //------------------------------------------------------------------------------
60 
61 void REveScene::AddSubscriber(std::unique_ptr<REveClient> &&sub)
62 {
63  assert(sub.get() != nullptr && fAcceptingChanges == kFALSE);
64 
65  fSubscribers.emplace_back(std::move(sub));
66 
67  // XXX Here should send out the package to the new subscriber,
68  // In principle can expect a new one in short time?
69  // Keep streamed data until next begin change, maybe.
70 }
71 
72 void REveScene::RemoveSubscriber(unsigned id)
73 {
74  assert(fAcceptingChanges == kFALSE);
75 
76  auto pred = [&](std::unique_ptr<REveClient> &client) {
77  return client->fId == id;
78  };
79 
80  fSubscribers.erase(std::remove_if(fSubscribers.begin(), fSubscribers.end(), pred), fSubscribers.end());
81 }
82 
83 void REveScene::BeginAcceptingChanges()
84 {
85  if (fAcceptingChanges) return;
86 
87  if (HasSubscribers()) fAcceptingChanges = kTRUE;
88 }
89 
90 void REveScene::SceneElementChanged(REveElement* element)
91 {
92  assert(fAcceptingChanges);
93 
94  fChangedElements.push_back(element);
95 }
96 
97 void REveScene::SceneElementRemoved(ElementId_t id)
98 {
99  fRemovedElements.push_back(id);
100 }
101 
102 void REveScene::EndAcceptingChanges()
103 {
104  if ( ! fAcceptingChanges) return;
105 
106  fAcceptingChanges = kFALSE;
107 }
108 
109 void REveScene::ProcessChanges()
110 {
111  if (IsChanged())
112  {
113  StreamRepresentationChanges();
114  SendChangesToSubscribers();
115  }
116 }
117 
118 void REveScene::StreamElements()
119 {
120  fOutputJson.clear();
121  fOutputBinary.clear();
122 
123  fElsWithBinaryData.clear();
124  fTotalBinarySize = 0;
125 
126  nlohmann::json jarr = nlohmann::json::array();
127 
128  nlohmann::json jhdr = {};
129  jhdr["content"] = "REveScene::StreamElements";
130  jhdr["fSceneId"] = fElementId;
131 
132  if (fCommands.size() > 0) {
133  jhdr["commands"] = nlohmann::json::array();
134  for (auto &&cmd : fCommands) {
135  nlohmann::json jcmd = {};
136  jcmd["name"] = cmd.fName;
137  jcmd["icon"] = cmd.fIcon;
138  jcmd["elementid"] = cmd.fElementId;
139  jcmd["elementclass"] = cmd.fElementClass;
140  jcmd["func"] = cmd.fAction; // SL: may be not needed on client side, can use name
141  jhdr["commands"].push_back(jcmd);
142  }
143  }
144 
145  jarr.push_back(jhdr);
146 
147  StreamJsonRecurse(this, jarr);
148  // for (auto &c : fChildren)
149  // {
150  // StreamJsonRecurse(c, jarr);
151  // }
152 
153  fOutputBinary.resize(fTotalBinarySize);
154  Int_t off = 0;
155 
156  for (auto &&e : fElsWithBinaryData)
157  {
158  auto rd_size = e->fRenderData->Write(&fOutputBinary[off], fOutputBinary.size() - off);
159  off += rd_size;
160  }
161  assert(off == fTotalBinarySize);
162 
163  jarr.front()["fTotalBinarySize"] = fTotalBinarySize;
164 
165  fOutputJson = jarr.dump();
166 }
167 
168 void REveScene::StreamJsonRecurse(REveElement *el, nlohmann::json &jarr)
169 {
170  nlohmann::json jobj = {};
171  Int_t rd_size = el->WriteCoreJson(jobj, fTotalBinarySize);
172  jarr.push_back(jobj);
173 
174  // If this is another scene, do not stream additional details.
175  // It should be requested / subscribed to independently.
176 
177  if (el->fScene == el && el != this)
178  {
179  return;
180  }
181 
182  if (rd_size > 0)
183  {
184  assert (rd_size % 4 == 0);
185 
186  fTotalBinarySize += rd_size;
187  fElsWithBinaryData.push_back(el);
188  }
189 
190  for (auto &&c : el->fChildren)
191  {
192  // Stream only objects element el is a mother of.
193  //
194  // XXXX This is spooky side effect of multi-parenting.
195  //
196  // In particular screwed up for selection.
197  // Selection now streams element ids and implied selected ids
198  // and secondary-ids as part of core json.
199  //
200  // I wonder how this screws up REveProjectionManager (should
201  // we hold a map of already streamed ids?).
202  //
203  // Do uncles and aunts and figure out a clean way for backrefs.
204 
205  if (c->GetMother() == el)
206  {
207  StreamJsonRecurse(c, jarr);
208  }
209  }
210 }
211 
212 ////////////////////////////////////////////////////////////////////////////////
213 //
214 /// Prepare data for sending element changes
215 //
216 ////////////////////////////////////////////////////////////////////////////////
217 
218 void REveScene::StreamRepresentationChanges()
219 {
220  fOutputJson.clear();
221  fOutputBinary.clear();
222 
223  fElsWithBinaryData.clear();
224  fTotalBinarySize = 0;
225 
226  nlohmann::json jarr = nlohmann::json::array();
227 
228  nlohmann::json jhdr = {};
229  jhdr["content"] = "ElementsRepresentaionChanges";
230  jhdr["fSceneId"] = fElementId;
231 
232  jhdr["removedElements"] = nlohmann::json::array();
233  for (auto &re : fRemovedElements)
234  jhdr["removedElements"].push_back(re);
235 
236  jhdr["numRepresentationChanged"] = fChangedElements.size();
237 
238  // jarr.push_back(jhdr);
239 
240  for (auto &el: fChangedElements)
241  {
242  UChar_t bits = el->GetChangeBits();
243 
244  nlohmann::json jobj = {};
245  jobj["fElementId"] = el->GetElementId();
246  jobj["changeBit"] = bits;
247 
248  if (bits & kCBElementAdded || bits & kCBObjProps)
249  {
250  if (gDebug > 0 && bits & kCBElementAdded)
251  {
252  Info("REveScene::StreamRepresentationChanges", "new element change %s %d\n",
253  el->GetCName(), bits);
254  }
255 
256  Int_t rd_size = el->WriteCoreJson(jobj, fTotalBinarySize);
257  if (rd_size) {
258  assert (rd_size % 4 == 0);
259  fTotalBinarySize += rd_size;
260  fElsWithBinaryData.push_back(el);
261  }
262  }
263  else
264  {
265  if (bits & kCBVisibility)
266  {
267  jobj["fRnrSelf"] = el->GetRnrSelf();
268  jobj["fRnrChildren"] = el->GetRnrChildren();
269  }
270 
271  if (bits & kCBColorSelection)
272  {
273  el->WriteCoreJson(jobj, -1);
274  }
275 
276  if (bits & kCBTransBBox)
277  {
278  }
279  }
280 
281  jarr.push_back(jobj);
282 
283  el->ClearStamps();
284  }
285 
286  fChangedElements.clear();
287  fRemovedElements.clear();
288 
289  // render data for total change
290  fOutputBinary.resize(fTotalBinarySize);
291  Int_t off = 0;
292 
293  for (auto &e : fElsWithBinaryData) {
294  auto rd_size = e->fRenderData->Write(&fOutputBinary[off], fOutputBinary.size() - off);
295 
296  off += rd_size;
297  }
298  assert(off == fTotalBinarySize);
299 
300  jhdr["fTotalBinarySize"] = fTotalBinarySize;
301 
302  nlohmann::json msg = { {"header", jhdr}, {"arr", jarr}};
303  fOutputJson = msg.dump();
304 
305  if (gDebug > 0)
306  Info("REveScene::StreamRepresentationChanges", "class: %s changes %s ...", GetCName(), msg.dump(1).c_str() );
307 }
308 
309 void REveScene::SendChangesToSubscribers()
310 {
311  for (auto && client : fSubscribers) {
312  if (gDebug > 0)
313  printf(" sending json, len = %d --> to conn_id = %d\n", (int) fOutputJson.size(), client->fId);
314  client->fWebWindow->Send(client->fId, fOutputJson);
315  if (fTotalBinarySize) {
316  if (gDebug > 0)
317  printf(" sending binary, len = %d --> to conn_id = %d\n", fTotalBinarySize, client->fId);
318  client->fWebWindow->SendBinary(client->fId, &fOutputBinary[0], fTotalBinarySize);
319  }
320  }
321 }
322 
323 Bool_t REveScene::IsChanged() const
324 {
325  if (gDebug > 0)
326  ::Info("REveScene::IsChanged","%s (changed_or_added=%d, removed=%d)", GetCName(),
327  (int) fChangedElements.size(), (int) fRemovedElements.size());
328 
329  return ! (fChangedElements.empty() && fRemovedElements.empty());
330 }
331 
332 
333 /*
334 ////////////////////////////////////////////////////////////////////////////////
335 /// Repaint the scene.
336 
337 void REveScene::Repaint(Bool_t dropLogicals)
338 {
339  if (dropLogicals) fGLScene->SetSmartRefresh(kFALSE);
340  fGLScene->PadPaint(fPad);
341  if (dropLogicals) fGLScene->SetSmartRefresh(kTRUE);
342  fChanged = kFALSE;
343 
344  // Hack to propagate selection state to physical shapes.
345  //
346  // Should actually be published in PadPaint() following a direct
347  // AddObject() call, but would need some other stuff for that.
348  // Optionally, this could be exported via the TAtt3D and everything
349  // would be sweet.
350 
351  TGLScene::LogicalShapeMap_t& logs = fGLScene->RefLogicalShapes();
352  REveElement* elm;
353  for (TGLScene::LogicalShapeMapIt_t li = logs.begin(); li != logs.end(); ++li)
354  {
355  elm = dynamic_cast<REveElement*>(li->first);
356  if (elm && li->second->Ref() == 1)
357  {
358  TGLPhysicalShape* pshp = const_cast<TGLPhysicalShape*>(li->second->GetFirstPhysical());
359  pshp->Select(elm->GetSelectedLevel());
360  }
361  }
362 
363  // Fix positions for hierarchical scenes.
364  if (fHierarchical)
365  {
366  RetransHierarchically();
367  }
368 }
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 /// Entry point for hierarchical transformation update.
372 /// Calls the recursive variant on all children.
373 
374 void REveScene::RetransHierarchically()
375 {
376  fGLScene->BeginUpdate();
377 
378  RetransHierarchicallyRecurse(this, RefMainTrans());
379 
380  fGLScene->EndUpdate();
381 }
382 
383 ////////////////////////////////////////////////////////////////////////////////
384 /// Set transformation matrix for physical shape of element el in
385 /// the GL-scene and recursively descend into children (if enabled).
386 
387 void REveScene::RetransHierarchicallyRecurse(REveElement* el, const REveTrans& tp)
388 {
389  static const REveException eh("REveScene::RetransHierarchicallyRecurse ");
390 
391  REveTrans t(tp);
392  if (el->HasMainTrans())
393  t *= el->RefMainTrans();
394 
395  if (el->GetRnrSelf() && el != this)
396  {
397  fGLScene->UpdatePhysioLogical(el->GetRenderObject(eh), t.Array(), 0);
398  }
399 
400  if (el->GetRnrChildren())
401  {
402  for (auto &c: el->RefChildren())
403  {
404  if (c->GetRnrAnything())
405  RetransHierarchicallyRecurse(c, t);
406  }
407  }
408 }
409 */
410 
411 
412 /*
413 ////////////////////////////////////////////////////////////////////////////////
414 /// Paint the scene. Iterate over children and calls PadPaint().
415 
416 void REveScene::Paint(Option_t* option)
417 {
418  if (GetRnrState())
419  {
420  for (auto &c: fChildren)
421  {
422  // c->PadPaint(option);
423  }
424  }
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 /// Remove element from the scene.
429 /// It is not an error if the element is not found in the scene.
430 
431 void REveScene::DestroyElementRenderers(REveElement* element)
432 {
433  static const REveException eh("REveScene::DestroyElementRenderers ");
434 
435  fGLScene->BeginUpdate();
436  Bool_t changed = fGLScene->DestroyLogical(element->GetRenderObject(eh), kFALSE);
437  fGLScene->EndUpdate(changed, changed);
438 }
439 
440 ////////////////////////////////////////////////////////////////////////////////
441 /// Remove element represented by object rnrObj from the scene.
442 /// It is not an error if the element is not found in the scene.
443 
444 void REveScene::DestroyElementRenderers(TObject* rnrObj)
445 {
446  fGLScene->BeginUpdate();
447  Bool_t changed = fGLScene->DestroyLogical(rnrObj, kFALSE);
448  fGLScene->EndUpdate(changed, changed);
449 }
450 */
451 
452 
453 /** \class REveSceneList
454 \ingroup REve
455 List of Scenes providing common operations on REveScene collections.
456 */
457 
458 ////////////////////////////////////////////////////////////////////////////////
459 /// Constructor.
460 
461 REveSceneList::REveSceneList(const std::string& n, const std::string& t) :
462  REveElement(n, t)
463 {
464  SetChildClass(TClass::GetClass<REveScene>());
465 }
466 
467 ////////////////////////////////////////////////////////////////////////////////
468 /// Destroy all scenes and their contents.
469 /// The object with non-zero deny-destroy will still survive.
470 
471 void REveSceneList::DestroyScenes()
472 {
473  auto i = fChildren.begin();
474  while (i != fChildren.end())
475  {
476  REveScene* s = (REveScene*) *(i++);
477  s->DestroyElements();
478  s->DestroyOrWarn();
479  }
480 }
481 
482 ////////////////////////////////////////////////////////////////////////////////
483 /// Set accept changes flag on all scenes.
484 
485 void REveSceneList::AcceptChanges(bool on)
486 {
487  for (auto &c: fChildren)
488  {
489  REveScene *s = (REveScene *)c;
490  if (on)
491  s->BeginAcceptingChanges();
492  else
493  s->EndAcceptingChanges();
494  }
495 }
496 /*
497 ////////////////////////////////////////////////////////////////////////////////
498 /// Repaint scenes that are tagged as changed.
499 
500 void REveSceneList::RepaintChangedScenes(Bool_t dropLogicals)
501 {
502  for (auto &c: fChildren)
503  {
504  REveScene* s = (REveScene*) c;
505  if (s->IsChanged())
506  {
507  s->Repaint(dropLogicals);
508  }
509  }
510 }
511 
512 ////////////////////////////////////////////////////////////////////////////////
513 /// Repaint all scenes.
514 
515 void REveSceneList::RepaintAllScenes(Bool_t dropLogicals)
516 {
517  for (auto &c: fChildren)
518  {
519  ((REveScene *)c)->Repaint(dropLogicals);
520  }
521 }
522 
523 ////////////////////////////////////////////////////////////////////////////////
524 /// Loop over all scenes and remove all instances of element from them.
525 
526 void REveSceneList::DestroyElementRenderers(REveElement* element)
527 {
528  static const REveException eh("REveSceneList::DestroyElementRenderers ");
529 
530  TObject* obj = element->GetRenderObject(eh);
531  for (auto &c: fChildren)
532  {
533  ((REveScene *)c)->DestroyElementRenderers(obj);
534  }
535 }
536 
537 */
538 
539 ////////////////////////////////////////////////////////////////////////////////
540 //
541 // Send an update of element representations
542 //
543 ////////////////////////////////////////////////////////////////////////////////
544 
545 void REveSceneList::ProcessSceneChanges()
546 {
547  if (gDebug > 0)
548  ::Info("REveSceneList::ProcessSceneChanges","processing");
549 
550  for (auto &el : fChildren)
551  {
552  ((REveScene*) el)->ProcessChanges();
553  }
554 }