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 "json.hpp"
21
22#include <cassert>
23
24
25using namespace ROOT::Experimental;
26namespace REX = ROOT::Experimental;
27
28/** \class REveScene
29\ingroup REve
30Eve representation of TGLScene.
31The GLScene is owned by this class - it is created on construction
32time and deleted at destruction.
33
34Normally all objects are positioned directly in global scene-space.
35By setting the fHierarchical flag, positions of children get
36calculated by multiplying the transformation matrices of all parents.
37*/
38
39////////////////////////////////////////////////////////////////////////////////
40/// Constructor.
41
42REveScene::REveScene(const std::string& n, const std::string& t) :
43 REveElement(n, t)
44{
45 fScene = this;
46}
47
48////////////////////////////////////////////////////////////////////////////////
49/// Destructor.
50
52{
54
57}
58
59//------------------------------------------------------------------------------
60
61void 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
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
84{
85 if (fAcceptingChanges) return;
86
88}
89
91{
92 assert(fAcceptingChanges);
93
94 fChangedElements.push_back(element);
95}
96
98{
99 fRemovedElements.push_back(id);
100}
101
103{
104 if ( ! fAcceptingChanges) return;
105
107}
108
110{
111 if (IsChanged())
112 {
115 }
116}
117
119{
120 fOutputJson.clear();
121 fOutputBinary.clear();
122
123 fElsWithBinaryData.clear();
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
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
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
219{
220 fOutputJson.clear();
221 fOutputBinary.clear();
222
223 fElsWithBinaryData.clear();
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
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
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
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
337void 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
374void 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
387void 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
416void 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
431void 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
444void 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
455List of Scenes providing common operations on REveScene collections.
456*/
457
458////////////////////////////////////////////////////////////////////////////////
459/// Constructor.
460
461REveSceneList::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
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
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
500void 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
515void 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
526void 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
546{
547 if (gDebug > 0)
548 ::Info("REveSceneList::ProcessSceneChanges","processing");
549
550 for (auto &el : fChildren)
551 {
552 ((REveScene*) el)->ProcessChanges();
553 }
554}
#define c(i)
Definition: RSha256.hxx:101
#define e(i)
Definition: RSha256.hxx:103
unsigned char UChar_t
Definition: RtypesCore.h:36
const Bool_t kFALSE
Definition: RtypesCore.h:90
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
const Bool_t kTRUE
Definition: RtypesCore.h:89
void Info(const char *location, const char *msgfmt,...)
R__EXTERN TEveManager * gEve
Definition: TEveManager.h:243
XFontStruct * id
Definition: TGX11.cxx:108
virtual Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset)
Write core json.
const char * GetCName() const
REveSceneList(const REveSceneList &)=delete
void DestroyScenes()
Destroy all scenes and their contents.
Definition: REveScene.cxx:471
void AcceptChanges(bool)
Set accept changes flag on all scenes.
Definition: REveScene.cxx:485
std::vector< std::unique_ptr< REveClient > > fSubscribers
!
Definition: REveScene.hxx:74
void AddSubscriber(std::unique_ptr< REveClient > &&sub)
Definition: REveScene.cxx:61
virtual ~REveScene()
Destructor.
Definition: REveScene.cxx:51
std::vector< char > fOutputBinary
!
Definition: REveScene.hxx:78
void SceneElementRemoved(ElementId_t id)
Definition: REveScene.cxx:97
void StreamRepresentationChanges()
Prepare data for sending element changes.
Definition: REveScene.cxx:218
void StreamJsonRecurse(REveElement *el, nlohmann::json &jobj)
Definition: REveScene.cxx:168
std::vector< SceneCommand > fCommands
!
Definition: REveScene.hxx:81
std::vector< ElementId_t > fRemovedElements
!
Definition: REveScene.hxx:72
void SceneElementChanged(REveElement *element)
Definition: REveScene.cxx:90
void RemoveSubscriber(unsigned int)
Definition: REveScene.cxx:72
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:489
const Int_t n
Definition: legend1.C:16
static constexpr double s
basic_json<> json
default JSON class
Definition: REveElement.hxx:88