Logo ROOT  
Reference Guide
TGLLogicalShape.cxx
Go to the documentation of this file.
1// @(#)root/gl:$Id$
2// Author: Richard Maunder 25/05/2005
3
4#include "TGLLogicalShape.h"
5#include "TGLPhysicalShape.h"
6#include "TGLRnrCtx.h"
7#include "TGLScene.h"
8#include "TGLCamera.h"
9#include "TGLSelectRecord.h"
10#include "TGLContext.h"
11#include "TGLIncludes.h"
12
13#include "TBuffer3D.h"
14#include "TClass.h"
15#include "TContextMenu.h"
16#include "TEnv.h"
17
18
19/** \class TGLLogicalShape
20\ingroup opengl
21Abstract logical shape - a GL 'drawable' - base for all shapes -
22faceset sphere etc. Logical shapes are a unique piece of geometry,
23described in it's local frame - e.g if we have three spheres in :
24
25 - Sphere A - Radius r1, center v1
26 - Sphere B - Radius r2, center v2
27 - Sphere C - Radius r1, center v3
28
29Spheres A and C can share a common logical sphere of radius r1 - and
30place them with two physicals with translations of v1 & v2. Sphere B
31requires a different logical (radius r2), placed with physical with
32translation v2.
33
34Physical shapes know about and can share logicals. Logicals do not
35about (aside from reference counting) physicals or share them.
36
37This sharing of logical shapes greatly reduces memory consumption and
38scene (re)build times in typical detector geometries which have many
39repeated objects placements.
40
41TGLLogicalShapes have reference counting, performed by the client
42physical shapes which are using it.
43
44Display list information is also stored here, possibly per LOD
45level. Most classes do not support LOD (only sphere and tube) and
46therefore reasonable defaults are encoded in the following virtual
47functions:
48~~~ {.cpp}
49 * ELODAxes SupportedLODAxes() { return kLODAxesNone; }
50 * Int_t DLCacheSize() { return 1; }
51 * UInt_t DLOffset(lod); // Transform lod into DL offset.
52 * Short_t QuantizeShapeLOD(); // Quantize lod.
53~~~
54Classes that have per-LOD display-lists than override these functions.
55'UShort_t fDLValid' is used as a bit-field determining validity of
56each quantized LOD-level; hopefully one will not have more than 16
57LOD levels per class.
58See also: TGLPhysicalShape::CalculateShapeLOD() where LOD is calculated.
59
60See base/src/TVirtualViewer3D for description of common external 3D
61viewer architecture and how external viewer clients use it.
62*/
63
65
67
70
71////////////////////////////////////////////////////////////////////////////////
72/// Constructor.
73
75 fRef (0),
76 fFirstPhysical (0),
77 fExternalObj (0),
78 fScene (0),
79 fDLBase (0),
80 fDLSize (1),
81 fDLValid (0),
82 fDLCache (kTRUE),
83 fRefStrong (kFALSE),
84 fOwnExtObj (kFALSE)
85{
86}
87
88////////////////////////////////////////////////////////////////////////////////
89/// Constructor with external object.
90
92 fRef (0),
93 fFirstPhysical (0),
94 fExternalObj (obj),
95 fScene (0),
96 fDLBase (0),
97 fDLSize (1),
98 fDLValid (0),
99 fDLCache (kTRUE),
100 fRefStrong (kFALSE),
101 fOwnExtObj (kFALSE)
102{
103}
104
105////////////////////////////////////////////////////////////////////////////////
106/// Constructor from TBuffer3D.
107
109 fRef (0),
110 fFirstPhysical (0),
111 fExternalObj (buffer.fID),
112 fScene (0),
113 fDLBase (0),
114 fDLSize (1),
115 fDLValid (0),
116 fDLCache (kTRUE),
117 fRefStrong (kFALSE),
118 fOwnExtObj (kFALSE)
119{
120 // Use the bounding box in buffer if valid
122 fBoundingBox.Set(buffer.fBBVertex);
123 } else if (buffer.SectionsValid(TBuffer3D::kRaw)) {
124 // otherwise use the raw points to generate one
125 fBoundingBox.SetAligned(buffer.NbPnts(), buffer.fPnts);
126 }
127
128 // If the logical is created without an external object reference,
129 // we create a generic here and delete it during the destruction.
130 if (fExternalObj == 0)
131 {
132 fExternalObj = new TNamed("Generic object", "Internal object created for bookkeeping.");
134 }
135}
136
137////////////////////////////////////////////////////////////////////////////////
138/// Destroy logical shape.
139
141{
142 // Physicals should have been cleared elsewhere as they are managed
143 // by the scene. But this could change.
144 if (fRef > 0) {
145 Warning("TGLLogicalShape::~TGLLogicalShape", "some physicals still lurking around.");
147 }
148 DLCachePurge();
149 if (fOwnExtObj)
150 {
151 delete fExternalObj;
152 }
153}
154
155
156/**************************************************************************/
157// Physical shape ref-counting, replica management
158/**************************************************************************/
159
160////////////////////////////////////////////////////////////////////////////////
161/// Add reference to given physical shape.
162
164{
166 fFirstPhysical = phys;
167 ++fRef;
168}
169
170////////////////////////////////////////////////////////////////////////////////
171/// Remove reference to given physical shape, potentially deleting
172/// *this* object when hitting zero ref-count (if fRefStrong is
173/// true).
174
176{
177 assert(phys != 0);
178
179 Bool_t found = kFALSE;
180 if (fFirstPhysical == phys) {
182 found = kTRUE;
183 } else {
184 TGLPhysicalShape *shp1 = fFirstPhysical, *shp2;
185 while ((shp2 = shp1->fNextPhysical) != 0) {
186 if (shp2 == phys) {
187 shp1->fNextPhysical = shp2->fNextPhysical;
188 found = kTRUE;
189 break;
190 }
191 shp1 = shp2;
192 }
193 }
194 if (found == kFALSE) {
195 Error("TGLLogicalShape::SubRef", "Attempt to un-ref an unregistered physical.");
196 return;
197 }
198
199 if (--fRef == 0 && fRefStrong)
200 delete this;
201}
202
203////////////////////////////////////////////////////////////////////////////////
204/// Destroy all physicals attached to this logical.
205
207{
208 TGLPhysicalShape *curr = fFirstPhysical, *next;
209 while (curr)
210 {
211 next = curr->fNextPhysical;
212 curr->fLogicalShape = 0;
213 --fRef;
214 delete curr;
215 curr = next;
216 }
217 assert (fRef == 0);
218 fFirstPhysical = 0;
219}
220
221////////////////////////////////////////////////////////////////////////////////
222/// Unreferenced first physical in the list, returning its id and
223/// making it fit for destruction somewhere else.
224/// Returns 0 if there are no replicas attached.
225
227{
228 if (fFirstPhysical == 0) return 0;
229
231 UInt_t phid = phys->ID();
233 phys->fLogicalShape = 0;
234 --fRef;
235 return phid;
236}
237
238
239/**************************************************************************/
240// Bounding-boxes
241/**************************************************************************/
242
243////////////////////////////////////////////////////////////////////////////////
244/// Update bounding-boxed of all dependent physicals.
245
247{
249 while (pshp)
250 {
251 pshp->UpdateBoundingBox();
252 pshp = pshp->fNextPhysical;
253 }
254}
255
256
257/**************************************************************************/
258// Display-list cache
259/**************************************************************************/
260
261////////////////////////////////////////////////////////////////////////////////
262/// Modify capture of draws into display list cache kTRUE - capture,
263/// kFALSE direct draw. Return kTRUE is state changed, kFALSE if not.
264
266{
267 if (cache == fDLCache)
268 return kFALSE;
269
270 if (fDLCache)
271 DLCachePurge();
272 fDLCache = cache;
273 return kTRUE;
274}
275
276////////////////////////////////////////////////////////////////////////////////
277/// Returns kTRUE if draws should be display list cached
278/// kFALSE otherwise.
279///
280/// Here we check that:
281/// a) fScene is set (Scene manages link to GL-context);
282/// b) secondary selection is not in progress as different
283/// render-path is usually taken in this case.
284///
285/// Otherwise we return internal bool.
286///
287/// Override this in sub-class if different behaviour is required.
288
290{
291 if (!fDLCache || !fScene ||
293 {
294 return kFALSE;
295 }
296 return kTRUE;
297}
298
299////////////////////////////////////////////////////////////////////////////////
300/// Clear all entries for all LODs for this drawable from the
301/// display list cache but keeping the reserved ids from GL context.
302
304{
305 fDLValid = 0;
306}
307
308////////////////////////////////////////////////////////////////////////////////
309/// Drop all entries for all LODs for this drawable from the display
310/// list cache, WITHOUT returning the reserved ids to GL context.
311///
312/// This is called by scene if it realized that the GL context was
313/// destroyed.
314
316{
317 fDLBase = 0;
318 fDLValid = 0;
319}
320
321////////////////////////////////////////////////////////////////////////////////
322/// Purge all entries for all LODs for this drawable from the
323/// display list cache, returning the reserved ids to GL context.
324///
325/// If you override this function:
326/// 1. call the base-class version from it;
327/// 2. call it from the destructor of the derived class!
328
330{
331 if (fDLBase != 0)
332 {
334 fDLBase = 0;
335 fDLValid = 0;
336 }
337}
338
339////////////////////////////////////////////////////////////////////////////////
340/// Purge given display-list range.
341/// Utility function.
342
344{
345 if (fScene)
346 {
348 }
349 else
350 {
351 Warning("TGLLogicalShape::PurgeDLRange", "Scene unknown, attempting direct deletion.");
352 glDeleteLists(base, size);
353 }
354}
355
356////////////////////////////////////////////////////////////////////////////////
357/// Logical shapes usually support only discreet LOD values,
358/// especially in view of display-list caching.
359/// This function should be overriden to perform the desired quantization.
360/// See TGLSphere.
361
363 Short_t /*combiLOD*/) const
364{
365 return shapeLOD;
366}
367
368////////////////////////////////////////////////////////////////////////////////
369/// Draw the GL drawable, using draw flags. If DL caching is enabled
370/// (see SetDLCache) then attempt to draw from the cache, if not found
371/// attempt to capture the draw - done by DirectDraw() - into a new cache entry.
372/// If not cached just call DirectDraw() for normal non DL cached drawing.
373
375{
376 // Debug tracing
377 if (gDebug > 4) {
378 Info("TGLLogicalShape::Draw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD());
379 }
380
381entry_point:
382 // If shape is not cached, or a capture to cache is already in
383 // progress perform a direct draw DL can be nested, but not created
384 // in nested fashion. As we only build DL on draw demands have to
385 // protected against this here.
386 // MT: I can't see how this could happen right now ... with
387 // rendering from a flat drawable-list.
388
389 if (!fgUseDLs || !ShouldDLCache(rnrCtx) || rnrCtx.IsDLCaptureOpen())
390 {
391 DirectDraw(rnrCtx);
392 return;
393 }
394
395 if (fDLBase == 0)
396 {
397 fDLBase = glGenLists(fDLSize);
398 if (fDLBase == 0)
399 {
400 Warning("TGLLogicalShape::Draw", "display-list registration failed.");
402 goto entry_point;
403 }
404 }
405
406 Short_t lod = rnrCtx.ShapeLOD();
407 UInt_t off = DLOffset(lod);
408 if ((1<<off) & fDLValid)
409 {
410 glCallList(fDLBase + off);
411 }
412 else
413 {
414 rnrCtx.OpenDLCapture();
415 glNewList(fDLBase + off, GL_COMPILE_AND_EXECUTE);
416 DirectDraw(rnrCtx);
417 glEndList();
418 rnrCtx.CloseDLCapture();
419 fDLValid |= (1<<off);
420 }
421}
422
423////////////////////////////////////////////////////////////////////////////////
424/// Draw the logical shape in highlight mode.
425/// If lvl argument is less than 0 (-1 by default), the index into color-set
426/// is taken from the physical shape itself.
427
429{
430 if (lvl < 0) lvl = pshp->GetSelected();
431
432 glColor4ubv(rnrCtx.ColorSet().Selection(lvl).CArr());
434 Draw(rnrCtx);
436}
437
438////////////////////////////////////////////////////////////////////////////////
439/// Virtual method called-back after a secondary selection hit
440/// is recorded (see TGLViewer::HandleButton(), Ctrl-Button1).
441/// The ptr argument holds the GL pick-record of the closest hit.
442///
443/// This base-class implementation simply prints out the result.
444
446{
447 printf("TGLLogicalShape::ProcessSelection %d names on the stack (z1=%g, z2=%g).\n",
448 rec.GetN(), rec.GetMinZ(), rec.GetMaxZ());
449 printf(" Names: ");
450 for (Int_t j=0; j<rec.GetN(); ++j) printf ("%u ", rec.GetItem(j));
451 printf("\n");
452}
453
454////////////////////////////////////////////////////////////////////////////////
455/// Invoke popup menu or our bound external TObject (if any), using passed
456/// 'menu' object, at location 'x' 'y'
457
459{
460 if (fExternalObj) {
461 menu.Popup(x, y, fExternalObj);
462 }
463}
464
465////////////////////////////////////////////////////////////////////////////////
466/// Return true if size of this shape should be ignored when determining if
467/// the object should be drawn. In this base-class we simply return state of
468/// static flag fgIgnoreSizeForCameraInterest.
469///
470/// Several sub-classes override this virtual function.
471
473{
475}
476
477////////////////////////////////////////////////////////////////////////////////
478/// Get state of static fgIgnoreSizeForCameraInterest flag.
479/// When this is true all objects, also very small, will be drawn by GL.
480
482{
484}
485
486////////////////////////////////////////////////////////////////////////////////
487/// Set state of static fgIgnoreSizeForCameraInterest flag.
488
490{
492}
493
494////////////////////////////////////////////////////////////////////////////////
495// Load GL shape settings from ROOT's TEnv into static data members.
496
498{
499 fgUseDLs = gEnv->GetValue("OpenGL.UseDisplayLists", 1);
500 fgUseDLsForVertArrs = gEnv->GetValue("OpenGL.UseDisplayListsForVertexArrays", 1);
501
503 {
504 printf("TGLLogicalShape::SetEnvDefaults() fgUseDLs=%d, fgUseDLsForVertArrs=%d\n",
506 }
507}
const Bool_t kFALSE
Definition: RtypesCore.h:90
long Long_t
Definition: RtypesCore.h:52
bool Bool_t
Definition: RtypesCore.h:61
short Short_t
Definition: RtypesCore.h:37
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
const Bool_t kTRUE
Definition: RtypesCore.h:89
#define ClassImp(name)
Definition: Rtypes.h:361
R__EXTERN TEnv * gEnv
Definition: TEnv.h:171
void Info(const char *location, const char *msgfmt,...)
void Error(const char *location, const char *msgfmt,...)
void Warning(const char *location, const char *msgfmt,...)
Generic 3D primitive description class.
Definition: TBuffer3D.h:18
UInt_t NbPnts() const
Definition: TBuffer3D.h:80
Bool_t SectionsValid(UInt_t mask) const
Definition: TBuffer3D.h:67
@ kBoundingBox
Definition: TBuffer3D.h:51
Double_t * fPnts
Definition: TBuffer3D.h:112
Double_t fBBVertex[8][3]
Definition: TBuffer3D.h:107
This class provides an interface to context sensitive popup menus.
Definition: TContextMenu.h:40
virtual void Popup(Int_t x, Int_t y, TObject *obj, TVirtualPad *c=nullptr, TVirtualPad *p=nullptr)
Popup context menu at given location in canvas c and pad p for selected object.
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition: TEnv.cxx:491
void Set(const TGLVertex3 vertex[8])
Set a bounding box from provided 8 vertices.
void SetAligned(const TGLVertex3 &lowVertex, const TGLVertex3 &highVertex)
Set ALIGNED box from two low/high vertices.
TGLColor & Selection(Int_t i)
Definition: TGLUtil.h:854
const UChar_t * CArr() const
Definition: TGLUtil.h:799
void RegisterDLNameRangeToWipe(UInt_t base, Int_t size)
Remember dl range for deletion in next MakeCurrent or dtor execution.
Definition: TGLContext.cxx:514
Abstract logical shape - a GL 'drawable' - base for all shapes - faceset sphere etc.
virtual void ProcessSelection(TGLRnrCtx &rnrCtx, TGLSelectRecord &rec)
Virtual method called-back after a secondary selection hit is recorded (see TGLViewer::HandleButton()...
virtual Bool_t SupportsSecondarySelect() const
TGLBoundingBox fBoundingBox
Also plays the role of ID.
virtual void Draw(TGLRnrCtx &rnrCtx) const
Draw the GL drawable, using draw flags.
virtual void DLCachePurge()
Purge all entries for all LODs for this drawable from the display list cache, returning the reserved ...
TObject * fExternalObj
first replica
virtual Bool_t ShouldDLCache(const TGLRnrCtx &rnrCtx) const
Returns kTRUE if draws should be display list cached kFALSE otherwise.
virtual void DirectDraw(TGLRnrCtx &rnrCtx) const =0
virtual void DrawHighlight(TGLRnrCtx &rnrCtx, const TGLPhysicalShape *pshp, Int_t lvl=-1) const
Draw the logical shape in highlight mode.
UInt_t UnrefFirstPhysical()
Unreferenced first physical in the list, returning its id and making it fit for destruction somewhere...
virtual ~TGLLogicalShape()
Destroy logical shape.
void SubRef(TGLPhysicalShape *phys) const
Remove reference to given physical shape, potentially deleting this object when hitting zero ref-coun...
virtual Short_t QuantizeShapeLOD(Short_t shapeLOD, Short_t combiLOD) const
Logical shapes usually support only discreet LOD values, especially in view of display-list caching.
TGLLogicalShape()
global flag for usage of display-lists in shapes that use vertex arrays
virtual UInt_t DLOffset(Short_t) const
Bool_t fOwnExtObj
Strong ref (delete on 0 ref); not in scene.
static void SetIgnoreSizeForCameraInterest(Bool_t isfci)
Set state of static fgIgnoreSizeForCameraInterest flag.
UShort_t fDLValid
display-list size for different LODs
virtual void DLCacheDrop()
Drop all entries for all LODs for this drawable from the display list cache, WITHOUT returning the re...
void UpdateBoundingBoxesOfPhysicals()
Update bounding-boxed of all dependent physicals.
static Bool_t fgIgnoreSizeForCameraInterest
void AddRef(TGLPhysicalShape *phys) const
Add reference to given physical shape.
void DestroyPhysicals()
Destroy all physicals attached to this logical.
static void SetEnvDefaults()
void InvokeContextMenu(TContextMenu &menu, UInt_t x, UInt_t y) const
Invoke popup menu or our bound external TObject (if any), using passed 'menu' object,...
TGLPhysicalShape * fFirstPhysical
physical instance ref counting
Bool_t SetDLCache(Bool_t cached)
Modify capture of draws into display list cache kTRUE - capture, kFALSE direct draw.
UInt_t fDLBase
scene where object is stored (can be zero!)
TGLScene * fScene
Shape's bounding box.
void PurgeDLRange(UInt_t base, Int_t size) const
External object is a fake.
static Bool_t GetIgnoreSizeForCameraInterest()
Get state of static fgIgnoreSizeForCameraInterest flag.
Int_t fDLSize
display-list id base
Bool_t fDLCache
display-list validity bit-field
virtual void DLCacheClear()
Clear all entries for all LODs for this drawable from the display list cache but keeping the reserved...
static Bool_t fgUseDLs
virtual Bool_t IgnoreSizeForOfInterest() const
Return true if size of this shape should be ignored when determining if the object should be drawn.
static Bool_t fgUseDLsForVertArrs
global flag for usage of display-lists
Bool_t fRefStrong
use display list caching
Concrete physical shape - a GL drawable.
TGLPhysicalShape * fNextPhysical
the associated logical shape
UInt_t ID() const
const TGLLogicalShape * fLogicalShape
UChar_t GetSelected() const
void UpdateBoundingBox()
cache
The TGLRnrCtx class aggregates data for a given redering context as needed by various parts of the RO...
Definition: TGLRnrCtx.h:41
Bool_t IsDLCaptureOpen() const
Definition: TGLRnrCtx.h:250
Bool_t SecSelection() const
Definition: TGLRnrCtx.h:224
void CloseDLCapture()
End display list capture.
Definition: TGLRnrCtx.cxx:347
TGLColorSet & ColorSet()
Return reference to current color-set (top of the stack).
Definition: TGLRnrCtx.cxx:278
void OpenDLCapture()
Start display-list capture.
Definition: TGLRnrCtx.cxx:338
Short_t ShapeLOD() const
Definition: TGLRnrCtx.h:177
TGLContextIdentity * GetGLCtxIdentity() const
Definition: TGLScene.h:230
Float_t GetMinZ() const
UInt_t GetItem(Int_t i) const
Int_t GetN() const
Float_t GetMaxZ() const
Standard selection record including information about containing scene and details ob out selected ob...
static UInt_t LockColor()
Prevent further color changes.
Definition: TGLUtil.cxx:1664
static UInt_t UnlockColor()
Allow color changes.
Definition: TGLUtil.cxx:1672
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
Mother of all ROOT objects.
Definition: TObject.h:37
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17