Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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
59int REveScene::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset)
60{
61 j["Mandatory"] = fMandatory;
62
63 return REveElement::WriteCoreJson(j, rnr_offset);
64}
65//------------------------------------------------------------------------------
66
67void REveScene::AddSubscriber(std::unique_ptr<REveClient> &&sub)
68{
69 assert(sub.get() != nullptr && fAcceptingChanges == kFALSE);
70
71 fSubscribers.emplace_back(std::move(sub));
72
73 // XXX Here should send out the package to the new subscriber,
74 // In principle can expect a new one in short time?
75 // Keep streamed data until next begin change, maybe.
76}
77
79{
80 auto pred = [&](std::unique_ptr<REveClient> &client) {
81 return client->fId == id;
82 };
83
84 fSubscribers.erase(std::remove_if(fSubscribers.begin(), fSubscribers.end(), pred), fSubscribers.end());
85}
86
87// Add Button in client gui with this command
88void REveScene::AddCommand(const std::string &name, const std::string &icon, const REveElement *element, const std::string &action)
89{
90 static const REveException eh("REveScene::AddCommand ");
91 if (element->GetElementId() && element->IsA())
92 {
93 fCommands.emplace_back(name, icon, element, action);
94 }
95 else
96 {
97 throw eh + "Element id and dictionary has to be defined";
98 }
99}
100
102{
103 if (fAcceptingChanges) return;
104
105 if (HasSubscribers()) {
107 /*
108 for (auto &&client : fSubscribers) {
109 REX::gEve->SceneSubscriberProcessingChanges(client->fId);
110 }
111 */
112 }
113}
114
116{
117 assert(fAcceptingChanges);
118
119 fChangedElements.push_back(element);
120}
121
123{
124 fRemovedElements.push_back(id);
125}
126
128{
129 if ( ! fAcceptingChanges) return;
130
132}
133
135{
136 fOutputJson.clear();
137 fOutputBinary.clear();
138
139 fElsWithBinaryData.clear();
141
142 nlohmann::json jarr = nlohmann::json::array();
143
144 nlohmann::json jhdr = {};
145 jhdr["content"] = "REveScene::StreamElements";
146 jhdr["fSceneId"] = fElementId;
147
148 if (fCommands.size() > 0) {
149 jhdr["commands"] = nlohmann::json::array();
150 for (auto &&cmd : fCommands) {
151 nlohmann::json jcmd = {};
152 jcmd["name"] = cmd.fName;
153 jcmd["icon"] = cmd.fIcon;
154 jcmd["elementid"] = cmd.fElementId;
155 jcmd["elementclass"] = cmd.fElementClass;
156 jcmd["func"] = cmd.fAction; // SL: may be not needed on client side, can use name
157 jhdr["commands"].push_back(jcmd);
158 }
159 }
160
161 jarr.push_back(jhdr);
162
163 StreamJsonRecurse(this, jarr);
164 // for (auto &c : fChildren)
165 // {
166 // StreamJsonRecurse(c, jarr);
167 // }
168
170 Int_t off = 0;
171
172 for (auto &&e : fElsWithBinaryData)
173 {
174 auto rd_size = e->fRenderData->Write(&fOutputBinary[off], fOutputBinary.size() - off);
175 off += rd_size;
176 }
177 assert(off == fTotalBinarySize);
178
179 jarr.front()["fTotalBinarySize"] = fTotalBinarySize;
180
181 fOutputJson = jarr.dump();
182}
183
184void REveScene::StreamJsonRecurse(REveElement *el, nlohmann::json &jarr)
185{
186 nlohmann::json jobj = {};
187 Int_t rd_size = el->WriteCoreJson(jobj, fTotalBinarySize);
188 jarr.push_back(jobj);
189
190 // If this is another scene, do not stream additional details.
191 // It should be requested / subscribed to independently.
192
193 if (el->fScene == el && el != this)
194 {
195 return;
196 }
197
198 if (rd_size > 0)
199 {
200 assert (rd_size % 4 == 0);
201
202 fTotalBinarySize += rd_size;
203 fElsWithBinaryData.push_back(el);
204 }
205
206 for (auto &&c : el->fChildren)
207 {
208 // Stream only objects element el is a mother of.
209 //
210 // XXXX This is spooky side effect of multi-parenting.
211 //
212 // In particular screwed up for selection.
213 // Selection now streams element ids and implied selected ids
214 // and secondary-ids as part of core json.
215 //
216 // I wonder how this screws up REveProjectionManager (should
217 // we hold a map of already streamed ids?).
218 //
219 // Do uncles and aunts and figure out a clean way for backrefs.
220
221 if (c->GetMother() == el)
222 {
223 StreamJsonRecurse(c, jarr);
224 }
225 }
226}
227
228////////////////////////////////////////////////////////////////////////////////
229//
230/// Prepare data for sending element changes
231//
232////////////////////////////////////////////////////////////////////////////////
233
235{
236 fElsWithBinaryData.clear();
238
239 nlohmann::json jarr = nlohmann::json::array();
240
241 nlohmann::json jhdr = {};
242 jhdr["content"] = "ElementsRepresentaionChanges";
243 jhdr["fSceneId"] = fElementId;
244
245 jhdr["removedElements"] = nlohmann::json::array();
246 for (auto &re : fRemovedElements)
247 jhdr["removedElements"].push_back(re);
248
249 jhdr["numRepresentationChanged"] = fChangedElements.size();
250
251 // jarr.push_back(jhdr);
252
253 for (auto &el: fChangedElements)
254 {
255 UChar_t bits = el->GetChangeBits();
256
257 nlohmann::json jobj = {};
258 jobj["fElementId"] = el->GetElementId();
259 jobj["changeBit"] = bits;
260
261 if (bits & kCBElementAdded || bits & kCBObjProps)
262 {
263 if (gDebug > 0 && bits & kCBElementAdded)
264 {
265 Info("REveScene::StreamRepresentationChanges", "new element change %s %d\n",
266 el->GetCName(), bits);
267 }
268
269 Int_t rd_size = el->WriteCoreJson(jobj, fTotalBinarySize);
270 if (rd_size) {
271 assert (rd_size % 4 == 0);
272 fTotalBinarySize += rd_size;
273 fElsWithBinaryData.push_back(el);
274 }
275 }
276 else
277 {
278 if (bits & kCBVisibility)
279 {
280 jobj["fRnrSelf"] = el->GetRnrSelf();
281 jobj["fRnrChildren"] = el->GetRnrChildren();
282 }
283
284 if (bits & kCBColorSelection)
285 {
286 el->WriteCoreJson(jobj, -1);
287 }
288
289 if (bits & kCBTransBBox)
290 {
291 }
292 }
293
294 jarr.push_back(jobj);
295
296 el->ClearStamps();
297 }
298
299 fChangedElements.clear();
300 fRemovedElements.clear();
301
302 // render data for total change
304 Int_t off = 0;
305
306 for (auto &e : fElsWithBinaryData) {
307 auto rd_size = e->fRenderData->Write(&fOutputBinary[off], fOutputBinary.size() - off);
308
309 off += rd_size;
310 }
311 assert(off == fTotalBinarySize);
312
313 jhdr["fTotalBinarySize"] = fTotalBinarySize;
314
315 nlohmann::json msg = { {"header", jhdr}, {"arr", jarr}};
316 fOutputJson = msg.dump();
317
318 if (gDebug > 0)
319 Info("REveScene::StreamRepresentationChanges", "class: %s changes %s ...", GetCName(), msg.dump(1).c_str() );
320}
321
323{
324 for (auto && client : fSubscribers) {
325 if (fOutputJson.size()) {
326 if (gDebug > 0)
327 printf(" sending json, len = %d --> to conn_id = %d\n", (int) fOutputJson.size(), client->fId);
328 client->fWebWindow->Send(client->fId, fOutputJson);
329 }
330 if (fTotalBinarySize) {
331 if (gDebug > 0)
332 printf(" sending binary, len = %d --> to conn_id = %d\n", fTotalBinarySize, client->fId);
333 client->fWebWindow->SendBinary(client->fId, &fOutputBinary[0], fTotalBinarySize);
334 }
336 }
337 fOutputJson.clear();
338 fOutputBinary.clear();
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)
511 else
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}
#define c(i)
Definition RSha256.hxx:101
#define e(i)
Definition RSha256.hxx:103
unsigned char UChar_t
Definition RtypesCore.h:38
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:218
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void on
char name[80]
Definition TGX11.cxx:110
Int_t gDebug
Definition TROOT.cxx:597
virtual void DestroyOrWarn()
Destroy this element. Prints a warning if deny-destroy is in force.
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
virtual void DestroyElements()
Destroy all children of this element.
ElementId_t GetElementId() const
virtual void RemoveElement(REveElement *el)
Remove el from the list of children.
REveException Exception-type thrown by Eve classes.
Definition REveTypes.hxx:41
REveSceneList * GetScenes() const
void SceneSubscriberWaitingResponse(unsigned cinnId)
REveViewerList * GetViewers() const
REveSceneList(const REveSceneList &)=delete
void DestroyScenes()
Destroy all scenes and their contents.
void AcceptChanges(bool)
Set accept changes flag on all scenes.
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:88
void AddSubscriber(std::unique_ptr< REveClient > &&sub)
Definition REveScene.cxx:67
virtual ~REveScene()
Destructor.
Definition REveScene.cxx:50
std::vector< char > fOutputBinary
!
Definition REveScene.hxx:78
void SceneElementRemoved(ElementId_t id)
void StreamRepresentationChanges()
Prepare data for sending element changes.
void StreamJsonRecurse(REveElement *el, nlohmann::json &jobj)
std::vector< SceneCommand > fCommands
!
Definition REveScene.hxx:81
Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset) override
Write core json.
Definition REveScene.cxx:59
std::vector< ElementId_t > fRemovedElements
!
Definition REveScene.hxx:72
void SceneElementChanged(REveElement *element)
void RemoveSubscriber(unsigned int)
Definition REveScene.cxx:78
void SceneDestructing(REveScene *scene)
Callback done from a REveScene destructor allowing proper removal of the scene from affected viewers.
const Int_t n
Definition legend1.C:16
R__EXTERN REveManager * gEve