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