Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGLScene.cxx
Go to the documentation of this file.
1// @(#)root/gl:$Id$
2// Author: Matevz Tadel, Feb 2007
3// Author: Richard Maunder 25/05/2005
4// Parts taken from original TGLRender by Timur Pocheptsov
5
6/*************************************************************************
7 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#include "TGLScene.h"
15#include "TGLRnrCtx.h"
16#include "TGLObject.h"
17#include "TGLSelectRecord.h"
18#include "TGLLogicalShape.h"
19#include "TGLPhysicalShape.h"
20#include "TGLCamera.h"
21#include "TGLContext.h"
22#include "TGLIncludes.h"
23
24#include <TColor.h>
25#include <TROOT.h>
26#include <TClass.h>
27
28#include <algorithm>
29
30//==============================================================================
31// TGLScene::TSceneInfo
32//==============================================================================
33
34//______________________________________________________________________
35//
36// Extend TGLSceneInfo for needs of TGLScene:
37//
38// 1. DrawElement vectors for opaque/transparent shapes which cache
39// physicals that pass the clip tests (frustum and additional
40// clip-object);
41//
42// 2. Statistics / debug information
43//
44
45////////////////////////////////////////////////////////////////////////////////
46/// Constructor.
47
49 TGLSceneInfo (view, scene),
50 fMinorStamp (0),
51 fOpaqueCnt (0),
52 fTranspCnt (0),
53 fAsPixelCnt (0)
54{
55}
56
57////////////////////////////////////////////////////////////////////////////////
58/// Destructor.
59
61{
62}
63
64////////////////////////////////////////////////////////////////////////////////
65/// Clear given vec and if it grew too large compared to the size of
66/// shape-of-interest also resize it.
67
69 Int_t maxSize)
70{
71 if (vec.capacity() > (size_t) maxSize) {
73 foo.reserve((size_t) maxSize);
74 vec.swap(foo);
75 } else {
76 vec.clear();
77 }
78}
79
80////////////////////////////////////////////////////////////////////////////////
81/// Clear given vec and if it grew too large compared to the size of
82/// shape-of-interest also resize it.
83
85 Int_t maxSize)
86{
87 if (vec.capacity() > (size_t) maxSize) {
89 foo.reserve((size_t) maxSize);
90 vec.swap(foo);
91 } else {
92 vec.clear();
93 }
94}
95
96////////////////////////////////////////////////////////////////////////////////
97/// Clear DrawElementVector fVisibleElement and optionally resize it
98/// so that it doesn't take more space then required by all the
99/// elements in the scene's draw-list.
100
102{
103 Int_t maxSize = (Int_t) fShapesOfInterest.size();
104
105 ClearDrawElementVec(fVisibleElements, maxSize);
106}
107
108////////////////////////////////////////////////////////////////////////////////
109/// Clear DrawElementPtrVectors and optionally resize them so that
110/// they don't take more space then required by all the elements in
111/// the scene's draw-list.
112
114{
115 Int_t maxSize = (Int_t) fShapesOfInterest.size();
116
117 ClearDrawElementPtrVec(fOpaqueElements, maxSize);
118 ClearDrawElementPtrVec(fTranspElements, maxSize);
119 ClearDrawElementPtrVec(fSelOpaqueElements, maxSize);
120 ClearDrawElementPtrVec(fSelTranspElements, maxSize);
121
122 fMinorStamp = 0;
123}
124
125////////////////////////////////////////////////////////////////////////////////
126/// Quantize LODs for given render-context.
127
129{
130 for (DrawElementVec_i i = fVisibleElements.begin(); i != fVisibleElements.end(); ++i)
131 i->fPhysical->QuantizeShapeLOD(i->fPixelLOD, ctx.CombiLOD(), i->fFinalLOD);
132}
133
134////////////////////////////////////////////////////////////////////////////////
135/// Prepare for drawing - fill DrawElementPtrVectors from the
136/// contents of fVisibleElements if there was some change.
137
139{
140 if (fMinorStamp < fScene->GetMinorStamp())
141 {
142 fOpaqueElements.clear();
143 fTranspElements.clear();
144 fSelOpaqueElements.clear();
145 fSelTranspElements.clear();
146
147 for (DrawElementVec_i i = fVisibleElements.begin(); i != fVisibleElements.end(); ++i)
148 {
149 if (i->fPhysical->IsSelected())
150 {
151 if (i->fPhysical->IsTransparent())
152 fSelTranspElements.push_back(&*i);
153 else
154 fSelOpaqueElements.push_back(&*i);
155 } else {
156 if (i->fPhysical->IsTransparent())
157 fTranspElements.push_back(&*i);
158 else
159 fOpaqueElements.push_back(&*i);
160 }
161 }
162 fMinorStamp = fScene->GetMinorStamp();
163 }
164}
165
166////////////////////////////////////////////////////////////////////////////////
167/// Clean-up after drawing, nothing to be done here.
168
170{
171}
172
173////////////////////////////////////////////////////////////////////////////////
174/// Reset draw statistics.
175
177{
178 fOpaqueCnt = 0;
179 fTranspCnt = 0;
180 fAsPixelCnt = 0;
181 fByShapeCnt.clear();
182}
183
184////////////////////////////////////////////////////////////////////////////////
185/// Update draw stats, for newly drawn 'shape'
186
188 Short_t lod)
189{
190 // Update opaque/transparent draw count
191 if (shape.IsTransparent()) {
192 ++fTranspCnt;
193 } else {
194 ++fOpaqueCnt;
195 }
196
197 if (lod == TGLRnrCtx::kLODPixel) {
198 ++fAsPixelCnt;
199 }
200
201 // By type only done at higher debug level.
202 if (gDebug>3) {
203 // Update the stats
204 TClass* logIsA = shape.GetLogical()->IsA();
205 std::map<TClass*, UInt_t>::iterator it = fByShapeCnt.find(logIsA);
206 if (it == fByShapeCnt.end()) {
207 //do not need to check insert(.....).second, because it was stats.end() before
208 it = fByShapeCnt.insert(std::make_pair(logIsA, 0u)).first;
209 }
210
211 it->second++;
212 }
213}
214
215////////////////////////////////////////////////////////////////////////////////
216/// Output draw stats to Info stream.
217
219{
220 if (gDebug>2)
221 {
222 TString out;
223 // Draw/container counts
224 out += Form("Drew scene (%s / %i LOD) - %i (Op %i Trans %i) %i pixel\n",
225 TGLRnrCtx::StyleName(LastStyle()), LastLOD(),
226 fOpaqueCnt + fTranspCnt, fOpaqueCnt, fTranspCnt, fAsPixelCnt);
227 out += Form("\tInner phys nums: physicals=%d, of_interest=%lu, visible=%lu, op=%lu, trans=%lu",
228 ((TGLScene*)fScene)->GetMaxPhysicalID(),
229 (ULong_t)fShapesOfInterest.size(), (ULong_t)fVisibleElements.size(),
230 (ULong_t)fOpaqueElements.size(), (ULong_t)fTranspElements.size());
231
232 // By shape type counts
233 if (gDebug>3)
234 {
235 out += "\n\tStatistics by shape:\n";
236 std::map<TClass*, UInt_t>::const_iterator it = fByShapeCnt.begin();
237 while (it != fByShapeCnt.end()) {
238 out += Form("\t%-20s %u\n", it->first->GetName(), it->second);
239 ++it;
240 }
241 }
242 Info("TGLScene::DumpDrawStats()", "%s",out.Data());
243 }
244}
245
246
247/** \class TGLScene
248\ingroup opengl
249TGLScene provides management and rendering of ROOT's default 3D
250/object representation as logical and physical shapes.
251
252A GL scene is the container for all the viewable objects (shapes)
253loaded into the viewer. It consists of two main stl::maps containing
254the TGLLogicalShape and TGLPhysicalShape collections, and interface
255functions enabling viewers to manage objects in these. The physical
256shapes defined the placement of copies of the logical shapes - see
257TGLLogicalShape/TGLPhysicalShape for more information on relationship
258
259The scene can be drawn by owning viewer, passing camera, draw style
260& quality (LOD), clipping etc - see Draw(). The scene can also be
261drawn for selection in similar fashion - see Select(). The scene
262keeps track of a single selected physical - which can be modified by
263viewers.
264
265The scene maintains a lazy calculated bounding box for the total
266scene extents, axis aligned round TGLPhysicalShape shapes.
267
268Currently a scene is owned exclusively by one viewer - however it is
269intended that it could easily be shared by multiple viewers - for
270efficiency and synchronisation reasons. Hence viewer variant objects
271camera, clips etc being owned by viewer and passed at draw/select
272*/
273
275
276////////////////////////////////////////////////////////////////////////////////
277
279 TGLSceneBase(),
280 fGLCtxIdentity(nullptr),
284{
285 if (fSceneID == 1)
287}
288
289////////////////////////////////////////////////////////////////////////////////
290/// Destroy scene objects
291
293{
298 if (fGLCtxIdentity)
301}
302
303/**************************************************************************/
304// GLCtxIdentity
305/**************************************************************************/
306
307////////////////////////////////////////////////////////////////////////////////
308/// Release all GL resources for current context identity.
309/// Requires iteration over all logical shapes.
310
312{
313 if (fGLCtxIdentity == nullptr) return;
314
315 if (fGLCtxIdentity->IsValid())
316 {
317 // Purge logical's DLs
319 while (lit != fLogicalShapes.end()) {
320 lit->second->DLCachePurge();
321 ++lit;
322 }
323 }
324 else
325 {
326 // Drop logical's DLs
328 while (lit != fLogicalShapes.end()) {
329 lit->second->DLCacheDrop();
330 ++lit;
331 }
332 }
334 fGLCtxIdentity = nullptr;
335}
336
337/**************************************************************************/
338// SceneInfo management
339/**************************************************************************/
340
341
342////////////////////////////////////////////////////////////////////////////////
343/// Create a scene-info instance appropriate for this scene class.
344/// Here we instantiate the inner class TSceneInfo that includes
345/// camera/clipping specific draw-list containers.
346
348{
349 return new TSceneInfo(view, this);
350}
351
352////////////////////////////////////////////////////////////////////////////////
353/// Compare 'shape1' and 'shape2' bounding box volumes - return kTRUE if
354/// 'shape1' bigger than 'shape2'.
355
357 const TGLPhysicalShape* shape2)
358{
359 return (shape1->BoundingBox().Volume() > shape2->BoundingBox().Volume());
360}
361
362////////////////////////////////////////////////////////////////////////////////
363/// Compare 'shape1' and 'shape2' bounding box volumes - return kTRUE if
364/// 'shape1' bigger than 'shape2'.
365
367 const TGLPhysicalShape* shape2)
368{
369 return (shape1->BoundingBox().Diagonal() > shape2->BoundingBox().Diagonal());
370}
371
372////////////////////////////////////////////////////////////////////////////////
373/// Major change in scene, need to rebuild all-element draw-vector and
374/// sort it.
375///
376/// Sort the TGLPhysical draw list by shape bounding box diagonal, from
377/// large to small. This makes dropout of shapes with time limited
378/// Draw() calls must less noticeable. As this does not use projected
379/// size it only needs to be done after a scene content change - not
380/// every time scene drawn (potential camera/projection change).
381
383{
384 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
385 if (sinfo == nullptr || sinfo->GetScene() != this) {
386 Error("TGLScene::RebuildSceneInfo", "Scene mismatch.");
387 return;
388 }
389
391
392 if (sinfo->fShapesOfInterest.capacity() > fPhysicalShapes.size()) {
393 ShapeVec_t foo;
394 foo.reserve(fPhysicalShapes.size());
395 sinfo->fShapesOfInterest.swap(foo);
396 } else {
397 sinfo->fShapesOfInterest.clear();
398 }
399
401 while (pit != fPhysicalShapes.end())
402 {
403 TGLPhysicalShape * pshp = pit->second;
404 const TGLLogicalShape * lshp = pshp->GetLogical();
405 if (rnrCtx.GetCamera()->OfInterest(pshp->BoundingBox(),
407 {
408 sinfo->fShapesOfInterest.push_back(pshp);
409 }
410 ++pit;
411 }
412
413 std::sort(sinfo->fShapesOfInterest.begin(), sinfo->fShapesOfInterest.end(),
415
416 sinfo->ClearAfterRebuild();
417}
418
419////////////////////////////////////////////////////////////////////////////////
420/// Fill scene-info with information needed for rendering, take into
421/// account the render-context (viewer state, camera, clipping).
422/// Here we have to iterate over all the physical shapes and select
423/// the visible ones. While at it, opaque and transparent shapes are
424/// divided into two groups.
425
427{
428 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
429 if (sinfo == nullptr || sinfo->GetScene() != this) {
430 Error("TGLScene::UpdateSceneInfo", "Scene mismatch.");
431 return;
432 }
433
434 // Clean-up/reset, update of transformation matrices and clipping
435 // planes done in base-class.
437
438 if (!sinfo->IsVisible())
439 return;
440
441 sinfo->fVisibleElements.clear();
442
443 // Check individual physicals, build DrawElementList.
444
445 Int_t checkCount = 0;
446 Bool_t timerp = rnrCtx.IsStopwatchRunning();
447 sinfo->ResetUpdateTimeouted();
448
449 for (ShapeVec_i phys=sinfo->fShapesOfInterest.begin();
450 phys!=sinfo->fShapesOfInterest.end();
451 ++phys, ++checkCount)
452 {
453 const TGLPhysicalShape * drawShape = *phys;
454
455 // TODO: Do small skipping first? Probably cheaper than frustum check
456 // Profile relative costs? The frustum check could be done implicitly
457 // from the LOD as we project all 8 vertices of the BB onto viewport
458
459 // Work out if we need to draw this shape - assume we do first
460 Bool_t drawNeeded = kTRUE;
461
462 // Draw test against passed clipping planes.
463 // Do before camera clipping on assumption clip planes remove
464 // more objects.
465 if (sinfo->ClipMode() == TGLSceneInfo::kClipOutside)
466 {
467 // Draw not needed if outside any of the planes.
468 std::vector<TGLPlane>::iterator pi = sinfo->ClipPlanes().begin();
469 while (pi != sinfo->ClipPlanes().end())
470 {
471 if (drawShape->BoundingBox().Overlap(*pi) == Rgl::kOutside)
472 {
473 drawNeeded = kFALSE;
474 break;
475 }
476 ++pi;
477 }
478 }
479 else if (sinfo->ClipMode() == TGLSceneInfo::kClipInside)
480 {
481 // Draw not needed if inside all the planes.
482 std::vector<TGLPlane>::iterator pi = sinfo->ClipPlanes().begin();
483 size_t cnt = 0;
484 while (pi != sinfo->ClipPlanes().end())
485 {
486 Rgl::EOverlap ovlp = drawShape->BoundingBox().Overlap(*pi);
487 if (ovlp == Rgl::kOutside)
488 break;
489 else if (ovlp == Rgl::kInside)
490 ++cnt;
491 ++pi;
492 }
493 if (cnt == sinfo->ClipPlanes().size())
494 drawNeeded = kFALSE;
495 }
496
497 // Test against camera frustum planes (here mode is Outside
498 // implicitly).
499 if (drawNeeded)
500 {
501 std::vector<TGLPlane>::iterator pi = sinfo->FrustumPlanes().begin();
502 while (pi != sinfo->FrustumPlanes().end())
503 {
504 if (drawShape->BoundingBox().Overlap(*pi) == Rgl::kOutside)
505 {
506 drawNeeded = kFALSE;
507 break;
508 }
509 ++pi;
510 }
511 }
512
513 // Draw? Then calculate lod and store ...
514 if (drawNeeded)
515 {
516 DrawElement_t de(drawShape);
517 drawShape->CalculateShapeLOD(rnrCtx, de.fPixelSize, de.fPixelLOD);
518 sinfo->fVisibleElements.push_back(de);
519 }
520
521 // Terminate the traversal if over scene rendering limit.
522 // Only test every 5000 objects as this is somewhat costly.
523 if (timerp && (checkCount % 5000) == 0 && rnrCtx.HasStopwatchTimedOut())
524 {
525 sinfo->UpdateTimeouted();
526 if (rnrCtx.ViewerLOD() == TGLRnrCtx::kLODHigh)
527 Warning("TGLScene::UpdateSceneInfo",
528 "Timeout reached, not all elements processed.");
529 break;
530 }
531 }
532
533 sinfo->ClearAfterUpdate();
534
535 // !!! MT Transparents should be sorted by their eye z-coordinate.
536 // Need combined matrices in scene-info to do this.
537 // Even more ... should z-sort contributions from ALL scenes!
538}
539
540////////////////////////////////////////////////////////////////////////////////
541/// Setup LOD-dependant values in scene-info.
542/// We have to perform LOD quantization for all draw-elements.
543
545{
546 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
547 if (sinfo == nullptr || sinfo->GetScene() != this) {
548 Error("TGLScene::LodifySceneInfo", "Scene mismatch.");
549 return;
550 }
551
553
554 sinfo->Lodify(rnrCtx);
555}
556
557
558/**************************************************************************/
559// Rendering
560/**************************************************************************/
561
562////////////////////////////////////////////////////////////////////////////////
563/// Initialize rendering.
564/// Pass to base-class where most work is done.
565/// Check if GL-ctx is shared with the previous one; if not
566/// wipe display-lists of all logicals.
567
569{
570 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
571 if (sinfo == nullptr || sinfo->GetScene() != this) {
572 TGLSceneInfo* si = rnrCtx.GetSceneInfo();
573 Error("TGLScene::PreDraw", "%s", Form("SceneInfo mismatch (0x%zx, '%s').",
574 (size_t)si, si ? si->IsA()->GetName() : "<>"));
575 return;
576 }
577
578 // Setup ctx, check if Update/Lodify needed.
579 TGLSceneBase::PreDraw(rnrCtx);
580
581 TGLContextIdentity* cid = rnrCtx.GetGLCtxIdentity();
582 if (cid != fGLCtxIdentity)
583 {
585 fGLCtxIdentity = cid;
587 }
588 else
589 {
592 {
593 // Clear logical's DLs
595 while (lit != fLogicalShapes.end()) {
596 lit->second->DLCacheClear();
597 ++lit;
598 }
599 }
600 }
603
604 sinfo->PreDraw();
605
606 // Reset-scene-info counters.
607 sinfo->ResetDrawStats();
608}
609
610////////////////////////////////////////////////////////////////////////////////
611/// Render opaque elements.
612
614{
615 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
616 if (!sinfo->fOpaqueElements.empty())
617 RenderAllPasses(rnrCtx, sinfo->fOpaqueElements, kTRUE);
618}
619
620////////////////////////////////////////////////////////////////////////////////
621/// Render transparent elements.
622
624{
625 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
626 if (!sinfo->fTranspElements.empty())
627 RenderAllPasses(rnrCtx, sinfo->fTranspElements, kTRUE);
628}
629
630////////////////////////////////////////////////////////////////////////////////
631/// Render selected opaque elements.
632
634{
635 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
636 if ( ! sinfo->fSelOpaqueElements.empty())
638}
639
640////////////////////////////////////////////////////////////////////////////////
641/// Render selected transparent elements.
642
644{
645 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
646 if (!sinfo->fSelTranspElements.empty())
648}
649
650////////////////////////////////////////////////////////////////////////////////
651/// Render selected opaque elements for highlight.
652
654{
655 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
656 if ( ! sinfo->fSelOpaqueElements.empty())
657 RenderHighlight(rnrCtx, sinfo->fSelOpaqueElements);
658}
659
660////////////////////////////////////////////////////////////////////////////////
661/// Render selected transparent elements for highlight.
662
664{
665 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
666 if (!sinfo->fSelTranspElements.empty())
667 RenderHighlight(rnrCtx, sinfo->fSelTranspElements);
668}
669
670////////////////////////////////////////////////////////////////////////////////
671
673 DrawElementPtrVec_t& elVec)
674{
675 DrawElementPtrVec_t svec(1);
676
677 glEnable(GL_STENCIL_TEST);
678 for (DrawElementPtrVec_i i = elVec.begin(); i != elVec.end(); ++i)
679 {
680 svec[0] = *i;
681
682 glStencilFunc(GL_ALWAYS, 0x1, 0x1);
683 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
684 glClear(GL_STENCIL_BUFFER_BIT);
685
686 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
687
688 RenderAllPasses(rnrCtx, svec, kFALSE);
689
690 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
691
692 glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
693 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
694
696 RenderAllPasses(rnrCtx, svec, kFALSE);
698 }
699 glDisable(GL_STENCIL_TEST);
700}
701
702////////////////////////////////////////////////////////////////////////////////
703/// Called after the rendering is finished.
704/// In debug mode draw statistics is dumped.
705/// Parent's PostDraw is called for GL cleanup.
706
708{
709 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
710
711 if (gDebug)
712 sinfo->DumpDrawStats();
713
714 sinfo->PostDraw();
715
717}
718
719////////////////////////////////////////////////////////////////////////////////
720/// Do full rendering of scene.
721///
722/// First draw the opaques, then the transparents. For each we do
723/// the number of passes required by draw mode and clipping setup.
724
726 DrawElementPtrVec_t& elVec,
727 Bool_t check_timeout)
728{
729 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
730 assert(sinfo != nullptr);
731
732 Short_t sceneStyle = rnrCtx.SceneStyle();
733
734 // Setup GL for current draw style - fill, wireframe, outline
735 Int_t reqPasses = 1; // default
736
737 Short_t rnrPass[2];
738 rnrPass[0] = rnrPass[1] = TGLRnrCtx::kPassUndef;
739
740 switch (sceneStyle)
741 {
742 case TGLRnrCtx::kFill:
744 {
745 glEnable(GL_LIGHTING);
746 if (sinfo->ShouldClip())
747 {
748 // Clip object - two sided lighting, two side polygons, don't cull (BACK) faces
749 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
750 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
751 glDisable(GL_CULL_FACE);
752 }
753 // No clip - default single side lighting,
754 // front polygons, cull (BACK) faces ok
755 if (sceneStyle == TGLRnrCtx::kOutline && ! (rnrCtx.Selection() || rnrCtx.Highlight()))
756 {
757 reqPasses = 2; // Outline needs two full draws
758 rnrPass[0] = TGLRnrCtx::kPassOutlineFill;
759 rnrPass[1] = TGLRnrCtx::kPassOutlineLine;
760 }
761 else
762 {
763 rnrPass[0] = TGLRnrCtx::kPassFill;
764 }
765 break;
766 }
768 {
769 rnrPass[0] = TGLRnrCtx::kPassWireFrame;
770 glDisable(GL_LIGHTING);
771 glDisable(GL_CULL_FACE);
772 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
773 break;
774 }
775 default:
776 {
777 assert(kFALSE);
778 }
779 }
780
781 for (Int_t i = 0; i < reqPasses; ++i)
782 {
783 // For outline two full draws (fill + wireframe) required.
784 // Do it this way to avoid costly GL state swaps on per drawable basis
785
786 Short_t pass = rnrPass[i];
787 rnrCtx.SetDrawPass(pass);
788
789 if (pass == TGLRnrCtx::kPassOutlineFill)
790 {
791 // First pass - filled polygons
792 glEnable(GL_POLYGON_OFFSET_FILL);
793 glPolygonOffset(0.5f, 0.5f);
794 }
795 else if (pass == TGLRnrCtx::kPassOutlineLine)
796 {
797 // Second pass - outline (wireframe)
799 glDisable(GL_POLYGON_OFFSET_FILL);
800 glDisable(GL_LIGHTING);
801
802 // We are only showing back faces with clipping as a
803 // better solution than completely invisible faces.
804 // *Could* cull back faces and only outline on front like this:
805 // glEnable(GL_CULL_FACE);
806 // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
807 // However this means clipped back edges not shown - so do inside and out....
808 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
809 }
810 else if (pass == TGLRnrCtx::kPassWireFrame)
811 {
813 }
814
815 // If no clip object no plane sets to extract/pass
816 if ( ! sinfo->ShouldClip())
817 {
818 RenderElements(rnrCtx, elVec, check_timeout);
819 }
820 else
821 {
822 // Get the clip plane set from the clipping object
823 TGLPlaneSet_t & planeSet = sinfo->ClipPlanes();
824
825 if (gDebug > 3)
826 {
827 Info("TGLScene::RenderAllPasses()",
828 "%ld active clip planes", (Long_t)planeSet.size());
829 }
830 // Limit to smaller of plane set size or GL implementation plane support
831 Int_t maxGLPlanes;
832 glGetIntegerv(GL_MAX_CLIP_PLANES, &maxGLPlanes);
833 UInt_t maxPlanes = maxGLPlanes;
834 UInt_t planeInd;
835 if (planeSet.size() < maxPlanes) {
836 maxPlanes = planeSet.size();
837 }
838
839 if (sinfo->ClipMode() == TGLSceneInfo::kClipOutside)
840 {
841 // Clip away scene outside of the clip object.
842 // Load all clip planes (up to max) at once.
843 for (UInt_t ii=0; ii<maxPlanes; ii++) {
844 glClipPlane(GL_CLIP_PLANE0+ii, planeSet[ii].CArr());
845 glEnable(GL_CLIP_PLANE0+ii);
846 }
847
848 // Draw scene once with full time slot, physicals have been
849 // clipped during UpdateSceneInfo, so no need to repeat that.
850 RenderElements(rnrCtx, elVec, check_timeout);
851 }
852 else
853 {
854 // Clip away scene inside of the clip object.
855 // This requires number-of-clip-planes passes and can not
856 // be entirely pre-computed (non-relevant planes are removed).
857 std::vector<TGLPlane> activePlanes;
858 for (planeInd=0; planeInd<maxPlanes; planeInd++)
859 {
860 activePlanes.push_back(planeSet[planeInd]);
861 TGLPlane& p = activePlanes.back();
862 p.Negate();
863 glClipPlane(GL_CLIP_PLANE0+planeInd, p.CArr());
864 glEnable(GL_CLIP_PLANE0+planeInd);
865
866 // Draw scene with active planes, allocating fraction of time
867 // for total planes.
868 RenderElements(rnrCtx, elVec, check_timeout, &activePlanes);
869
870 p.Negate();
871 glClipPlane(GL_CLIP_PLANE0+planeInd, p.CArr());
872 }
873 }
874 // Ensure all clip planes turned off again
875 for (planeInd=0; planeInd<maxPlanes; planeInd++) {
876 glDisable(GL_CLIP_PLANE0+planeInd);
877 }
878 }
879 } // end for reqPasses
880
881 // Reset gl modes to defaults
882 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
883 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
884 glEnable(GL_CULL_FACE);
885 glEnable(GL_LIGHTING);
886}
887
888////////////////////////////////////////////////////////////////////////////////
889/// Render DrawElements in elementVec with given timeout.
890/// If clipPlanes is non-zero, test each element against its
891/// clipping planes.
892
894 DrawElementPtrVec_t& elVec,
895 Bool_t check_timeout,
896 const TGLPlaneSet_t* clipPlanes)
897{
898 TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
899 assert(sinfo != nullptr);
900
901 Int_t drawCount = 0;
902
903 for (DrawElementPtrVec_i i = elVec.begin(); i != elVec.end(); ++i)
904 {
905 const TGLPhysicalShape * drawShape = (*i)->fPhysical;
906
907 Bool_t drawNeeded = kTRUE;
908
909 // If clipping planes are passed as argument, we test against them.
910 if (clipPlanes && IsOutside(drawShape->BoundingBox(), *clipPlanes))
911 drawNeeded = kFALSE;
912
913 // Draw?
914 if (drawNeeded)
915 {
916 rnrCtx.SetShapeLOD((*i)->fFinalLOD);
917 rnrCtx.SetShapePixSize((*i)->fPixelSize);
918 glPushName(drawShape->ID());
919 drawShape->Draw(rnrCtx);
920 glPopName();
921 ++drawCount;
922 sinfo->UpdateDrawStats(*drawShape, rnrCtx.ShapeLOD());
923 }
924
925 // Terminate the draw if over opaque fraction timeout.
926 // Only test every 2000 objects as this is somewhat costly.
927 if (check_timeout && (drawCount % 2000) == 0 &&
928 rnrCtx.HasStopwatchTimedOut())
929 {
930 if (rnrCtx.ViewerLOD() == TGLRnrCtx::kLODHigh)
931 Warning("TGLScene::RenderElements",
932 "Timeout reached, not all elements rendered.");
933 break;
934 }
935 }
936}
937
938
939/**************************************************************************/
940// Selection
941/**************************************************************************/
942
943////////////////////////////////////////////////////////////////////////////////
944/// Process selection record rec.
945/// 'curIdx' is the item position where the scene should start
946/// its processing.
947/// Return TRUE if an object has been identified or FALSE otherwise.
948/// The scene-info member of the record is already set by the caller.
949
951{
952 if (curIdx >= rec.GetN())
953 return kFALSE;
954
955 TGLPhysicalShape* pshp = FindPhysical(rec.GetItem(curIdx));
956 if (pshp)
957 {
958 rec.SetTransparent(pshp->IsTransparent());
959 rec.SetPhysShape(pshp);
960 rec.SetLogShape(const_cast<TGLLogicalShape*>(pshp->GetLogical()));
961 rec.SetObject(pshp->GetLogical()->GetExternal());
962 rec.SetSpecific(nullptr);
963 return kTRUE;
964 }
965 return kFALSE;
966}
967
968
969/**************************************************************************/
970// Bounding-box
971/**************************************************************************/
972
973////////////////////////////////////////////////////////////////////////////////
974/// Encapsulates all physical shapes bounding box with axes aligned box.
975/// Validity checked in the base-class.
976
978{
979 Double_t xMin, xMax, yMin, yMax, zMin, zMax;
980 xMin = xMax = yMin = yMax = zMin = zMax = 0.0;
981 PhysicalShapeMapCIt_t physicalShapeIt = fPhysicalShapes.begin();
982 const TGLPhysicalShape * physicalShape;
983 while (physicalShapeIt != fPhysicalShapes.end())
984 {
985 physicalShape = physicalShapeIt->second;
986 if (!physicalShape)
987 {
988 assert(kFALSE);
989 continue;
990 }
991 const TGLBoundingBox& box = physicalShape->BoundingBox();
992 if (physicalShapeIt == fPhysicalShapes.begin()) {
993 xMin = box.XMin(); xMax = box.XMax();
994 yMin = box.YMin(); yMax = box.YMax();
995 zMin = box.ZMin(); zMax = box.ZMax();
996 } else {
997 if (box.XMin() < xMin) { xMin = box.XMin(); }
998 if (box.XMax() > xMax) { xMax = box.XMax(); }
999 if (box.YMin() < yMin) { yMin = box.YMin(); }
1000 if (box.YMax() > yMax) { yMax = box.YMax(); }
1001 if (box.ZMin() < zMin) { zMin = box.ZMin(); }
1002 if (box.ZMax() > zMax) { zMax = box.ZMax(); }
1003 }
1004 ++physicalShapeIt;
1005 }
1006 fBoundingBox.SetAligned(TGLVertex3(xMin,yMin,zMin), TGLVertex3(xMax,yMax,zMax));
1008}
1009
1010/**************************************************************************/
1011// Logical shapes
1012/**************************************************************************/
1013
1014////////////////////////////////////////////////////////////////////////////////
1015/// Adopt dynamically created logical 'shape' - add to internal map
1016/// and take responsibility for deleting.
1017
1019{
1020 if (fLock != kModifyLock) {
1021 Error("TGLScene::AdoptLogical", "expected ModifyLock");
1022 return;
1023 }
1024
1025 shape.fScene = this;
1026 fLogicalShapes.insert(LogicalShapeMapValueType_t(shape.ID(), &shape));
1027}
1028
1029////////////////////////////////////////////////////////////////////////////////
1030/// Destroy logical shape defined by unique 'ID'.
1031/// Returns kTRUE if found/destroyed - kFALSE otherwise.
1032///
1033/// If mustFind is true, an error is reported if the logical is not
1034/// found.
1035
1037{
1038 if (fLock != kModifyLock) {
1039 Error("TGLScene::DestroyLogical", "expected ModifyLock");
1040 return kFALSE;
1041 }
1042
1043 LogicalShapeMapIt_t lit = fLogicalShapes.find(logid);
1044
1045 if (lit == fLogicalShapes.end()) {
1046 if (mustFind)
1047 Error("TGLScene::DestroyLogical", "logical not found in map.");
1048 return kFALSE;
1049 }
1050
1051 TGLLogicalShape * logical = lit->second;
1052 UInt_t phid;
1053 while ((phid = logical->UnrefFirstPhysical()) != 0)
1054 {
1055 PhysicalShapeMapIt_t pit = fPhysicalShapes.find(phid);
1056 if (pit != fPhysicalShapes.end())
1058 else
1059 Warning("TGLScene::DestroyLogical", "an attached physical not found in map.");
1060 }
1061 assert(logical->Ref() == 0);
1062 fLogicalShapes.erase(lit);
1063 delete logical;
1065 IncTimeStamp();
1066 return kTRUE;
1067}
1068
1069////////////////////////////////////////////////////////////////////////////////
1070/// Destroy all logical shapes in scene.
1071/// Return number of destroyed logicals.
1072
1074{
1075 if (fLock != kModifyLock) {
1076 Error("TGLScene::DestroyLogicals", "expected ModifyLock");
1077 return 0;
1078 }
1079
1080 Int_t count = 0;
1081 LogicalShapeMapIt_t logicalShapeIt = fLogicalShapes.begin();
1082 const TGLLogicalShape * logicalShape;
1083 while (logicalShapeIt != fLogicalShapes.end()) {
1084 logicalShape = logicalShapeIt->second;
1085 if (logicalShape) {
1086 if (logicalShape->Ref() == 0) {
1087 fLogicalShapes.erase(logicalShapeIt++);
1088 delete logicalShape;
1089 ++count;
1090 continue;
1091 } else {
1092 assert(kFALSE);
1093 }
1094 } else {
1095 assert(kFALSE);
1096 }
1097 ++logicalShapeIt;
1098 }
1099
1100 return count;
1101}
1102
1103////////////////////////////////////////////////////////////////////////////////
1104/// Find and return logical shape identified by unique logid.
1105/// Returns 0 if not found.
1106
1108{
1109 LogicalShapeMapCIt_t lit = fLogicalShapes.find(logid);
1110 if (lit != fLogicalShapes.end()) {
1111 return lit->second;
1112 } else {
1113 if (fInSmartRefresh)
1114 return FindLogicalSmartRefresh(logid);
1115 else
1116 return nullptr;
1117 }
1118}
1119
1120
1121/**************************************************************************/
1122// Physical shapes
1123/**************************************************************************/
1124
1125////////////////////////////////////////////////////////////////////////////////
1126/// Adopt dynamically created physical 'shape' - add to internal map and take
1127/// responsibility for deleting
1128
1130{
1131 if (fLock != kModifyLock) {
1132 Error("TGLScene::AdoptPhysical", "expected ModifyLock");
1133 return;
1134 }
1135 // TODO: Very inefficient check - disable
1136 assert(fPhysicalShapes.find(shape.ID()) == fPhysicalShapes.end());
1137
1138 fPhysicalShapes.insert(PhysicalShapeMapValueType_t(shape.ID(), &shape));
1139
1141 IncTimeStamp();
1142}
1143
1144////////////////////////////////////////////////////////////////////////////////
1145/// Virtual function to destroy a physical. Sub-classes might have
1146/// special checks to perform.
1147/// Caller should also invalidate the draw-list.
1148
1150{
1151 delete pit->second;
1152 fPhysicalShapes.erase(pit);
1153}
1154
1155////////////////////////////////////////////////////////////////////////////////
1156/// Destroy physical shape defined by unique 'ID'.
1157/// Returns kTRUE if found/destroyed - kFALSE otherwise.
1158
1160{
1161 if (fLock != kModifyLock) {
1162 Error("TGLScene::DestroyPhysical", "expected ModifyLock.");
1163 return kFALSE;
1164 }
1165
1166 PhysicalShapeMapIt_t pit = fPhysicalShapes.find(phid);
1167
1168 if (pit == fPhysicalShapes.end()) {
1169 Error("TGLScene::DestroyPhysical::UpdatePhysical", "physical not found.");
1170 return kFALSE;
1171 }
1172
1174
1176
1177 return kTRUE;
1178}
1179
1180////////////////////////////////////////////////////////////////////////////////
1181/// Destroy physical shapes.
1182
1184{
1185 if (fLock != kModifyLock) {
1186 Error("TGLScene::DestroyPhysicals", "expected ModifyLock");
1187 return 0;
1188 }
1189
1190 // Loop over logicals -- it is much more efficient that way.
1191
1192 UInt_t count = 0;
1193
1194 LogicalShapeMapIt_t lit = fLogicalShapes.begin();
1195 while (lit != fLogicalShapes.end())
1196 {
1197 TGLLogicalShape *lshp = lit->second;
1198 if (lshp && lshp->Ref() != 0)
1199 {
1200 count += lshp->Ref();
1201 lshp->DestroyPhysicals();
1202 }
1203 ++lit;
1204 }
1205
1206 assert (count == fPhysicalShapes.size());
1207 fPhysicalShapes.clear();
1208
1209 if (count > 0) {
1211 IncTimeStamp();
1212 }
1213
1214 return count;
1215}
1216
1217////////////////////////////////////////////////////////////////////////////////
1218/// Find and return physical shape identified by unique 'ID'.
1219/// Returns 0 if not found.
1220
1222{
1223 PhysicalShapeMapCIt_t pit = fPhysicalShapes.find(phid);
1224 return (pit != fPhysicalShapes.end()) ? pit->second : 0;
1225}
1226
1227////////////////////////////////////////////////////////////////////////////////
1228/// Returns the maximum used physical id.
1229/// Returns 0 if empty.
1230
1232{
1233 if (fPhysicalShapes.empty()) return 0;
1234 return (--fPhysicalShapes.end())->first;
1235}
1236
1237
1238/**************************************************************************/
1239// Update methods
1240/**************************************************************************/
1241
1242////////////////////////////////////////////////////////////////////////////////
1243/// Put scene in update mode, return true if lock acquired.
1244
1246{
1248 return ok;
1249}
1250
1251////////////////////////////////////////////////////////////////////////////////
1252/// Exit scene update mode.
1253///
1254/// If sceneChanged is true (default), the scene timestamp is
1255/// increased and basic draw-lists etc will be rebuild on next draw
1256/// request. If you only changed colors or some other visual
1257/// parameters that do not affect object bounding-box or
1258/// transformation matrix, you can set it to false.
1259///
1260/// If updateViewers is true (default), the viewers using this scene
1261/// will be tagged as changed. If sceneChanged is true the
1262/// updateViewers should be true as well, unless you take care of
1263/// the viewers elsewhere or in some other way.
1264
1265void TGLScene::EndUpdate(Bool_t minorChange, Bool_t sceneChanged, Bool_t updateViewers)
1266{
1267 if (minorChange)
1268 IncMinorStamp();
1269
1270 if (sceneChanged)
1271 IncTimeStamp();
1272
1274
1275 if (updateViewers)
1277}
1278
1279////////////////////////////////////////////////////////////////////////////////
1280/// Drop display-lists for the logical (assume TGLObject/direct rendering).
1281/// Re-calculate the bounding box (also for all physicals).
1282
1284{
1285 if (fLock != kModifyLock) {
1286 Error("TGLScene::UpdateLogical", "expected ModifyLock");
1287 return;
1288 }
1289
1290 TGLLogicalShape* log = FindLogical(logid);
1291
1292 if (log == nullptr) {
1293 Error("TGLScene::UpdateLogical", "logical not found");
1294 return;
1295 }
1296
1297 log->DLCacheClear();
1298 log->UpdateBoundingBox();
1299}
1300
1301////////////////////////////////////////////////////////////////////////////////
1302/// Reposition/recolor physical shape.
1303
1305{
1306 if (fLock != kModifyLock) {
1307 Error("TGLScene::UpdatePhysical", "expected ModifyLock");
1308 return;
1309 }
1310
1311 TGLPhysicalShape* phys = FindPhysical(phid);
1312
1313 if (phys == nullptr) {
1314 Error("TGLScene::UpdatePhysical", "physical not found");
1315 return;
1316 }
1317
1318 if (trans) phys->SetTransform(trans);
1319 if (col) phys->SetDiffuseColor(col);
1320}
1321
1322////////////////////////////////////////////////////////////////////////////////
1323/// Reposition/recolor physical shape.
1324
1326{
1327 if (fLock != kModifyLock) {
1328 Error("TGLScene::UpdatePhysical", "expected ModifyLock");
1329 return;
1330 }
1331
1332 TGLPhysicalShape* phys = FindPhysical(phid);
1333
1334 if (phys == nullptr) {
1335 Error("TGLScene::UpdatePhysical", "physical not found");
1336 return;
1337 }
1338
1339 if (trans)
1340 phys->SetTransform(trans);
1341 if (cidx >= 0) {
1342 Float_t rgba[4];
1343 RGBAFromColorIdx(rgba, cidx, transp);
1344 phys->SetDiffuseColor(rgba);
1345 }
1346}
1347
1348////////////////////////////////////////////////////////////////////////////////
1349/// Reposition/recolor physical for given logical (assume TGLObject and
1350/// a single physical).
1351
1353{
1354 if (fLock != kModifyLock) {
1355 Error("TGLScene::UpdatePhysioLogical", "expected ModifyLock");
1356 return;
1357 }
1358
1359 TGLLogicalShape* log = FindLogical(logid);
1360
1361 if (log == nullptr) {
1362 Error("TGLScene::UpdatePhysioLogical", "logical not found");
1363 return;
1364 }
1365
1366 if (log->Ref() != 1) {
1367 Warning("TGLScene::UpdatePhysioLogical", "expecting a single physical (%d).", log->Ref());
1368 }
1369
1370 TGLPhysicalShape* phys = log->fFirstPhysical;
1371 if (trans) phys->SetTransform(trans);
1372 if (col) phys->SetDiffuseColor(col);
1373}
1374
1375////////////////////////////////////////////////////////////////////////////////
1376/// Reposition/recolor physical for given logical (assume TGLObject and
1377/// a single physical).
1378
1380{
1381 if (fLock != kModifyLock) {
1382 Error("TGLScene::UpdatePhysioLogical", "expected ModifyLock");
1383 return;
1384 }
1385
1386 TGLLogicalShape* log = FindLogical(logid);
1387
1388 if (log == nullptr) {
1389 Error("TGLScene::UpdatePhysioLogical", "logical not found");
1390 return;
1391 }
1392
1393 if (log->Ref() != 1) {
1394 Warning("TGLScene::UpdatePhysioLogical", "expecting a single physical (%d).", log->Ref());
1395 }
1396
1397 TGLPhysicalShape* phys = log->fFirstPhysical;
1398 if (trans)
1399 phys->SetTransform(trans);
1400 if (cidx >= 0) {
1401 Float_t rgba[4];
1402 RGBAFromColorIdx(rgba, cidx, transp);
1403 phys->SetDiffuseColor(rgba);
1404 }
1405}
1406
1407
1408/**************************************************************************/
1409// Smart refresh
1410/**************************************************************************/
1411
1412////////////////////////////////////////////////////////////////////////////////
1413/// Moves logicals that support smart-refresh to intermediate cache.
1414/// Destroys the others and returns the number of destroyed ones.
1415
1417{
1419 // Remove all logicals that don't survive a refresh.
1420 UInt_t count = 0;
1422 while (i != fSmartRefreshCache.end()) {
1423 if (i->second->KeepDuringSmartRefresh() == kFALSE) {
1424 LogicalShapeMapIt_t j = i++;
1425 delete j->second;
1426 fSmartRefreshCache.erase(j);
1427 ++count;
1428 } else {
1429 ++i;
1430 }
1431 }
1433 return count;
1434}
1435
1436////////////////////////////////////////////////////////////////////////////////
1437/// Wipes logicals in refresh-cache.
1438
1440{
1442
1444 while (i != fSmartRefreshCache.end()) {
1445 delete i->second;
1446 ++i;
1447 }
1448 fSmartRefreshCache.clear();
1449}
1450
1451////////////////////////////////////////////////////////////////////////////////
1452/// Find and return logical shape identified by unique 'ID' in refresh-cache.
1453/// Returns 0 if not found.
1454
1456{
1458 if (it != fSmartRefreshCache.end())
1459 {
1460 TGLLogicalShape* l_shape = it->second;
1461 fSmartRefreshCache.erase(it);
1462 if (l_shape->IsA() != TGLObject::GetGLRenderer(ID->IsA()))
1463 {
1464 Warning("TGLScene::FindLogicalSmartRefresh", "Wrong renderer-type found in cache.");
1465 delete l_shape;
1466 return nullptr;
1467 }
1468 // printf("TGLScene::SmartRefresh found cached: %p '%s' [%s] for %p\n",
1469 // l_shape, l_shape->GetExternal()->GetName(),
1470 // l_shape->GetExternal()->IsA()->GetName(), (void*) ID);
1472 lsm->insert(LogicalShapeMapValueType_t(l_shape->ID(), l_shape));
1473 l_shape->DLCacheClear();
1474 l_shape->UpdateBoundingBox();
1475 return l_shape;
1476 } else {
1477 return nullptr;
1478 }
1479}
1480
1481
1482/**************************************************************************/
1483// Helpers
1484/**************************************************************************/
1485
1486////////////////////////////////////////////////////////////////////////////////
1487/// Return memory cost of scene.
1488/// Warning: NOT CORRECT at present - doesn't correctly calculate size.
1489/// of logical shapes with dynamic internal contents.
1490
1492{
1493 UInt_t size = sizeof(*this);
1494
1495 printf("Size: Scene Only %u\n", size);
1496
1497 LogicalShapeMapCIt_t logicalShapeIt = fLogicalShapes.begin();
1498 const TGLLogicalShape * logicalShape;
1499 while (logicalShapeIt != fLogicalShapes.end()) {
1500 logicalShape = logicalShapeIt->second;
1501 size += sizeof(*logicalShape);
1502 ++logicalShapeIt;
1503 }
1504
1505 printf("Size: Scene + Logical Shapes %u\n", size);
1506
1507 PhysicalShapeMapCIt_t physicalShapeIt = fPhysicalShapes.begin();
1508 const TGLPhysicalShape * physicalShape;
1509 while (physicalShapeIt != fPhysicalShapes.end()) {
1510 physicalShape = physicalShapeIt->second;
1511 size += sizeof(*physicalShape);
1512 ++physicalShapeIt;
1513 }
1514
1515 printf("Size: Scene + Logical Shapes + Physical Shapes %u\n", size);
1516
1517 return size;
1518}
1519
1520////////////////////////////////////////////////////////////////////////////////
1521/// Print sizes of logical and physical-shape maps.
1522
1524{
1525 printf("Scene: %u Logicals / %u Physicals\n",
1526 (UInt_t) fLogicalShapes.size(), (UInt_t) fPhysicalShapes.size());
1527}
1528
1529////////////////////////////////////////////////////////////////////////////////
1530/// Fill rgba color from ROOT color-index ci and transparency (0->100).
1531
1533{
1534 TColor* c = gROOT->GetColor(ci);
1535 if(c) c->GetRGB(rgba[0], rgba[1], rgba[2]);
1536 else rgba[0] = rgba[1] = rgba[2] = 0.5;
1537 rgba[3] = 1.0f - transp/100.0f;
1538}
1539
1540////////////////////////////////////////////////////////////////////////////////
1541/// Check if box is outside of all planes.
1542
1544 const TGLPlaneSet_t & planes)
1545{
1546 for (TGLPlaneSet_ci p=planes.begin(); p!=planes.end(); ++p)
1547 if (box.Overlap(*p) == Rgl::kOutside)
1548 return kTRUE;
1549 return kFALSE;
1550}
#define GL_TRUE
Definition GL_glu.h:262
#define GL_FALSE
Definition GL_glu.h:261
#define c(i)
Definition RSha256.hxx:101
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Definition RtypesCore.h:45
short Color_t
Definition RtypesCore.h:92
unsigned char UChar_t
Definition RtypesCore.h:38
char Char_t
Definition RtypesCore.h:37
unsigned long ULong_t
Definition RtypesCore.h:55
long Long_t
Definition RtypesCore.h:54
float Float_t
Definition RtypesCore.h:57
short Short_t
Definition RtypesCore.h:39
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
#define ClassImp(name)
Definition Rtypes.h:377
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:218
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:229
std::vector< TGLPlane > TGLPlaneSet_t
Definition TGLUtil.h:571
std::vector< TGLPlane >::const_iterator TGLPlaneSet_ci
Definition TGLUtil.h:573
winID h TVirtualViewer3D TVirtualGLPainter p
Int_t gDebug
Definition TROOT.cxx:595
#define gROOT
Definition TROOT.h:406
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
The color creation and management class.
Definition TColor.h:21
static Int_t GetColor(const char *hexcolor)
Static method returning color number for color specified by hex color string of form: "#rrggbb",...
Definition TColor.cxx:1839
Concrete class describing an orientated (free) or axis aligned box of 8 vertices.
Double_t Volume() const
Double_t Diagonal() const
void SetAligned(const TGLVertex3 &lowVertex, const TGLVertex3 &highVertex)
Set ALIGNED box from two low/high vertices.
Rgl::EOverlap Overlap(const TGLPlane &plane) const
Find overlap (Inside, Outside, Partial) of plane c.f. bounding box.
Bool_t OfInterest(const TGLBoundingBox &box, Bool_t ignoreSize) const
Calculate if the an object defined by world frame bounding box is 'of interest' to the camera.
Identifier of a shared GL-context.
Definition TGLContext.h:81
Bool_t IsValid() const
Definition TGLContext.h:99
Bool_t TakeLock(ELock lock) const
Lock the object in mode 'lock'.
Bool_t ReleaseLock(ELock lock) const
Release current lock, make sure it the same as the 'lock' argument.
Abstract logical shape - a GL 'drawable' - base for all shapes - faceset sphere etc.
UInt_t UnrefFirstPhysical()
Unreferenced first physical in the list, returning its id and making it fit for destruction somewhere...
TObject * GetExternal() const
void DestroyPhysicals()
Destroy all physicals attached to this logical.
static void SetEnvDefaults()
TObject * ID() const
virtual void UpdateBoundingBox()
UInt_t Ref() const
TGLScene * fScene
Shape's bounding box.
virtual TClass * IsA() const
virtual void DLCacheClear()
Clear all entries for all LODs for this drawable from the display list cache but keeping the reserved...
virtual Bool_t IgnoreSizeForOfInterest() const
Return true if size of this shape should be ignored when determining if the object should be drawn.
static TClass * GetGLRenderer(TClass *isa)
Return direct-rendering GL class for class isa.
Concrete physical shape - a GL drawable.
UInt_t ID() const
void SetTransform(const TGLMatrix &transform)
const TGLBoundingBox & BoundingBox() const
const TGLLogicalShape * GetLogical() const
virtual void CalculateShapeLOD(TGLRnrCtx &rnrCtx, Float_t &pixSize, Short_t &shapeLOD) const
Calculate shape-lod, suitable for use under projection defined by 'rnrCtx', taking account of which l...
void SetDiffuseColor(const Float_t rgba[4])
Set color from ROOT color index and transparency [0,100].
Bool_t IsTransparent() const
virtual void Draw(TGLRnrCtx &rnrCtx) const
Draw physical shape, using LOD flags, potential from display list cache.
3D plane class - of format Ax + By + Cz + D = 0
Definition TGLUtil.h:525
The TGLRnrCtx class aggregates data for a given redering context as needed by various parts of the RO...
Definition TGLRnrCtx.h:41
void SetShapeLOD(Short_t LOD)
Definition TGLRnrCtx.h:178
Short_t SceneStyle() const
Definition TGLRnrCtx.h:184
Float_t SceneOLLineW() const
Definition TGLRnrCtx.h:193
void SetShapePixSize(Float_t ps)
Definition TGLRnrCtx.h:180
void SetHighlightOutline(Bool_t ho)
Definition TGLRnrCtx.h:221
Bool_t IsStopwatchRunning() const
Definition TGLRnrCtx.h:214
Short_t ViewerLOD() const
Definition TGLRnrCtx.h:171
Bool_t HasStopwatchTimedOut()
Check if the stopwatch went beyond the render time limit.
void SetDrawPass(Short_t dpass)
Definition TGLRnrCtx.h:205
Bool_t Highlight() const
Definition TGLRnrCtx.h:218
Float_t SceneWFLineW() const
Definition TGLRnrCtx.h:189
TGLCamera * GetCamera()
Definition TGLRnrCtx.h:156
static const char * StyleName(Short_t style)
Return string describing the style.
TGLSceneInfo * GetSceneInfo()
Definition TGLRnrCtx.h:158
@ kPassOutlineFill
Definition TGLRnrCtx.h:56
@ kPassWireFrame
Definition TGLRnrCtx.h:58
@ kPassOutlineLine
Definition TGLRnrCtx.h:57
Bool_t Selection() const
Definition TGLRnrCtx.h:222
Short_t ShapeLOD() const
Definition TGLRnrCtx.h:177
TGLContextIdentity * GetGLCtxIdentity() const
Definition TGLRnrCtx.h:254
Short_t CombiLOD() const
Definition TGLRnrCtx.h:175
Scene base-class – provides basic interface expected by the TGLViewer or its sub-classes:
virtual void PostDraw(TGLRnrCtx &rnrCtx)
Finalize drawing.
UInt_t fMinorStamp
TGLBoundingBox fBoundingBox
virtual void LodifySceneInfo(TGLRnrCtx &ctx)
Setup LOD-dependant values in scene-info.
Bool_t fBoundingBoxValid
void IncTimeStamp()
UInt_t fSceneID
UInt_t GetMinorStamp() const
void InvalidateBoundingBox()
virtual void PreDraw(TGLRnrCtx &rnrCtx)
Perform basic pre-render initialization:
virtual void RebuildSceneInfo(TGLRnrCtx &ctx)
Fill scene-info with very basic information that is practically view independent.
virtual void UpdateSceneInfo(TGLRnrCtx &ctx)
Fill scene-info with information needed for rendering, take into account the render-context (viewer s...
void TagViewersChanged()
Tag all viewers as changed.
void IncMinorStamp()
Base class for extended scene context.
void UpdateTimeouted()
Bool_t ShouldClip() const
virtual TClass * IsA() const
Char_t ClipMode() const
Bool_t IsVisible() const
std::vector< TGLPlane > & ClipPlanes()
std::vector< TGLPlane > & FrustumPlanes()
void ResetUpdateTimeouted()
TGLSceneBase * GetScene() const
DrawElementPtrVec_t fSelTranspElements
Definition TGLScene.h:96
void PostDraw()
Clean-up after drawing, nothing to be done here.
Definition TGLScene.cxx:169
DrawElementPtrVec_t fTranspElements
Definition TGLScene.h:94
void ClearAfterRebuild()
Clear DrawElementVector fVisibleElement and optionally resize it so that it doesn't take more space t...
Definition TGLScene.cxx:101
void ResetDrawStats()
Reset draw statistics.
Definition TGLScene.cxx:176
void DumpDrawStats()
Output draw stats to Info stream.
Definition TGLScene.cxx:218
~TSceneInfo() override
Destructor.
Definition TGLScene.cxx:60
TSceneInfo(TGLViewerBase *view=nullptr, TGLScene *scene=nullptr)
Constructor.
Definition TGLScene.cxx:48
DrawElementVec_t fVisibleElements
Definition TGLScene.h:90
void PreDraw()
Prepare for drawing - fill DrawElementPtrVectors from the contents of fVisibleElements if there was s...
Definition TGLScene.cxx:138
DrawElementPtrVec_t fOpaqueElements
Definition TGLScene.h:93
ShapeVec_t fShapesOfInterest
Definition TGLScene.h:88
void ClearDrawElementVec(DrawElementVec_t &vec, Int_t maxSize)
Clear given vec and if it grew too large compared to the size of shape-of-interest also resize it.
Definition TGLScene.cxx:68
void UpdateDrawStats(const TGLPhysicalShape &shape, Short_t lod)
Update draw stats, for newly drawn 'shape'.
Definition TGLScene.cxx:187
DrawElementPtrVec_t fSelOpaqueElements
Definition TGLScene.h:95
void ClearAfterUpdate()
Clear DrawElementPtrVectors and optionally resize them so that they don't take more space then requir...
Definition TGLScene.cxx:113
void Lodify(TGLRnrCtx &ctx)
Quantize LODs for given render-context.
Definition TGLScene.cxx:128
void ClearDrawElementPtrVec(DrawElementPtrVec_t &vec, Int_t maxSize)
Clear given vec and if it grew too large compared to the size of shape-of-interest also resize it.
Definition TGLScene.cxx:84
TGLScene provides management and rendering of ROOT's default 3D /object representation as logical and...
Definition TGLScene.h:29
Float_t fLastLineWidthScale
Definition TGLScene.h:140
void UpdateSceneInfo(TGLRnrCtx &rnrCtx) override
Fill scene-info with information needed for rendering, take into account the render-context (viewer s...
Definition TGLScene.cxx:426
std::vector< DrawElement_t > DrawElementVec_t
Definition TGLScene.h:65
virtual TGLPhysicalShape * FindPhysical(UInt_t phid) const
Find and return physical shape identified by unique 'ID'.
PhysicalShapeMap_t::const_iterator PhysicalShapeMapCIt_t
Definition TGLScene.h:50
void RenderOpaque(TGLRnrCtx &rnrCtx) override
Render opaque elements.
Definition TGLScene.cxx:613
void CalcBoundingBox() const override
Encapsulates all physical shapes bounding box with axes aligned box.
Definition TGLScene.cxx:977
virtual void DestroyPhysicalInternal(PhysicalShapeMapIt_t pit)
Virtual function to destroy a physical.
void PostDraw(TGLRnrCtx &rnrCtx) override
Called after the rendering is finished.
Definition TGLScene.cxx:707
virtual Bool_t BeginUpdate()
Put scene in update mode, return true if lock acquired.
virtual void AdoptPhysical(TGLPhysicalShape &shape)
Adopt dynamically created physical 'shape' - add to internal map and take responsibility for deleting...
void ReleaseGLCtxIdentity()
Release all GL resources for current context identity.
Definition TGLScene.cxx:311
LogicalShapeMap_t::const_iterator LogicalShapeMapCIt_t
Definition TGLScene.h:44
void RebuildSceneInfo(TGLRnrCtx &rnrCtx) override
Major change in scene, need to rebuild all-element draw-vector and sort it.
Definition TGLScene.cxx:382
virtual void EndUpdate(Bool_t minorChange=kTRUE, Bool_t sceneChanged=kTRUE, Bool_t updateViewers=kTRUE)
Exit scene update mode.
Float_t fLastPointSizeScale
Definition TGLScene.h:139
static Bool_t ComparePhysicalVolumes(const TGLPhysicalShape *shape1, const TGLPhysicalShape *shape2)
Compare 'shape1' and 'shape2' bounding box volumes - return kTRUE if 'shape1' bigger than 'shape2'.
Definition TGLScene.cxx:356
LogicalShapeMap_t fLogicalShapes
Definition TGLScene.h:125
virtual Int_t DestroyPhysicals()
Destroy physical shapes.
virtual void RenderAllPasses(TGLRnrCtx &rnrCtx, DrawElementPtrVec_t &elVec, Bool_t check_timeout)
Do full rendering of scene.
Definition TGLScene.cxx:725
virtual void AdoptLogical(TGLLogicalShape &shape)
Adopt dynamically created logical 'shape' - add to internal map and take responsibility for deleting.
void LodifySceneInfo(TGLRnrCtx &rnrCtx) override
Setup LOD-dependant values in scene-info.
Definition TGLScene.cxx:544
virtual void RenderElements(TGLRnrCtx &rnrCtx, DrawElementPtrVec_t &elVec, Bool_t check_timeout, const TGLPlaneSet_t *clipPlanes=nullptr)
Render DrawElements in elementVec with given timeout.
Definition TGLScene.cxx:893
Bool_t ResolveSelectRecord(TGLSelectRecord &rec, Int_t curIdx) override
Process selection record rec.
Definition TGLScene.cxx:950
static Bool_t IsOutside(const TGLBoundingBox &box, const TGLPlaneSet_t &planes)
Check if box is outside of all planes.
void RenderSelTranspForHighlight(TGLRnrCtx &rnrCtx) override
Render selected transparent elements for highlight.
Definition TGLScene.cxx:663
void EndSmartRefresh()
Wipes logicals in refresh-cache.
virtual Bool_t DestroyLogical(TObject *logid, Bool_t mustFind=kTRUE)
Destroy logical shape defined by unique 'ID'.
std::vector< const TGLPhysicalShape * > ShapeVec_t
Definition TGLScene.h:72
Bool_t fInSmartRefresh
Definition TGLScene.h:135
UInt_t SizeOfScene() const
Return memory cost of scene.
PhysicalShapeMap_t::iterator PhysicalShapeMapIt_t
Definition TGLScene.h:49
LogicalShapeMap_t fSmartRefreshCache
Definition TGLScene.h:136
virtual void RenderHighlight(TGLRnrCtx &rnrCtx, DrawElementPtrVec_t &elVec)
Definition TGLScene.cxx:672
PhysicalShapeMap_t fPhysicalShapes
Definition TGLScene.h:126
std::vector< DrawElement_t >::iterator DrawElementVec_i
Definition TGLScene.h:66
TSceneInfo * CreateSceneInfo(TGLViewerBase *view) override
Create a scene-info instance appropriate for this scene class.
Definition TGLScene.cxx:347
LogicalShapeMap_t::iterator LogicalShapeMapIt_t
Definition TGLScene.h:43
PhysicalShapeMap_t::value_type PhysicalShapeMapValueType_t
Definition TGLScene.h:48
LogicalShapeMap_t::value_type LogicalShapeMapValueType_t
Definition TGLScene.h:42
std::vector< DrawElement_t * > DrawElementPtrVec_t
Definition TGLScene.h:68
std::map< TObject *, TGLLogicalShape * > LogicalShapeMap_t
Definition TGLScene.h:41
ShapeVec_t::iterator ShapeVec_i
Definition TGLScene.h:73
void RenderSelOpaqueForHighlight(TGLRnrCtx &rnrCtx) override
Render selected opaque elements for highlight.
Definition TGLScene.cxx:653
virtual void UpdatePhysioLogical(TObject *logid, Double_t *trans, UChar_t *col)
Reposition/recolor physical for given logical (assume TGLObject and a single physical).
virtual Bool_t DestroyPhysical(UInt_t phid)
Destroy physical shape defined by unique 'ID'.
static void RGBAFromColorIdx(Float_t rgba[4], Color_t ci, Char_t transp=0)
Fill rgba color from ROOT color-index ci and transparency (0->100).
void RenderTransp(TGLRnrCtx &rnrCtx) override
Render transparent elements.
Definition TGLScene.cxx:623
virtual Int_t DestroyLogicals()
Destroy all logical shapes in scene.
TGLLogicalShape * FindLogicalSmartRefresh(TObject *ID) const
Find and return logical shape identified by unique 'ID' in refresh-cache.
~TGLScene() override
Destroy scene objects.
Definition TGLScene.cxx:292
std::vector< DrawElement_t * >::iterator DrawElementPtrVec_i
Definition TGLScene.h:69
void RenderSelTransp(TGLRnrCtx &rnrCtx) override
Render selected transparent elements.
Definition TGLScene.cxx:643
virtual void UpdateLogical(TObject *logid)
Drop display-lists for the logical (assume TGLObject/direct rendering).
TGLContextIdentity * fGLCtxIdentity
Definition TGLScene.h:131
void PreDraw(TGLRnrCtx &rnrCtx) override
Initialize rendering.
Definition TGLScene.cxx:568
void DumpMapSizes() const
Print sizes of logical and physical-shape maps.
virtual void UpdatePhysical(UInt_t phid, Double_t *trans, UChar_t *col)
Reposition/recolor physical shape.
virtual UInt_t GetMaxPhysicalID()
Returns the maximum used physical id.
TGLLogicalShape * FindLogical(TObject *logid) const override
Find and return logical shape identified by unique logid.
UInt_t BeginSmartRefresh()
Moves logicals that support smart-refresh to intermediate cache.
static Bool_t ComparePhysicalDiagonals(const TGLPhysicalShape *shape1, const TGLPhysicalShape *shape2)
Compare 'shape1' and 'shape2' bounding box volumes - return kTRUE if 'shape1' bigger than 'shape2'.
Definition TGLScene.cxx:366
void RenderSelOpaque(TGLRnrCtx &rnrCtx) override
Render selected opaque elements.
Definition TGLScene.cxx:633
Standard selection record including information about containing scene and details ob out selected ob...
static Float_t GetPointSizeScale()
Get global point-size scale.
Definition TGLUtil.cxx:1883
static Float_t GetLineWidthScale()
Returns global line-width scale.
Definition TGLUtil.cxx:1899
static Float_t LineWidth()
Get the line-width, taking the global scaling into account.
Definition TGLUtil.cxx:1943
3 component (x/y/z) vertex class.
Definition TGLUtil.h:84
Base class for GL viewers.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
Mother of all ROOT objects.
Definition TObject.h:41
virtual TClass * IsA() const
Definition TObject.h:245
Basic string class.
Definition TString.h:139
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition fillpatterns.C:1
EOverlap
Definition TGLUtil.h:35
@ kInside
Definition TGLUtil.h:36
@ kOutside
Definition TGLUtil.h:38