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