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