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