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