Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLSceneBase.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Matevz Tadel, Feb 2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TGLSceneBase.h"
13 #include "TGLSceneInfo.h"
14 #include "TGLViewerBase.h"
15 #include "TGLRnrCtx.h"
16 #include "TGLCamera.h"
17 #include "TGLClip.h"
18 #include "TGLIncludes.h"
19 
20 #include <TMath.h>
21 
22 #include <string>
23 #include <algorithm>
24 
25 /** \class TGLSceneBase
26 \ingroup opengl
27 Scene base-class -- provides basic interface expected by the
28 TGLViewer or its sub-classes:
29  - unique scene id
30  - scene locking
31  - overall bounding box
32  - list of viewers displaying the scene (for update propagation)
33  - virtual interface for draw/select/render (?)
34 
35 The standard ROOT OpenGL scene is implemented in direct sub-class TGLScene.
36 
37 Note that while each scene can be shared among several viewers, ALL
38 of them are obliged to share the same display-list space (this can
39 be achieved on GL-context creation time; Matevz believes that by
40 default all GL contexts must use shared display-lists etc).
41 */
42 
43 ClassImp(TGLSceneBase);
44 
45 UInt_t TGLSceneBase::fgSceneIDSrc = 1;
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 TGLSceneBase::TGLSceneBase() :
50  TGLLockable(),
51 
52  fTimeStamp (1),
53  fMinorStamp (1),
54  fLOD (TGLRnrCtx::kLODHigh),
55  fStyle (TGLRnrCtx::kStyleUndef),
56  fWFLineW (0),
57  fOLLineW (0),
58  fClip (0),
59  fSelectable (kTRUE),
60  fBoundingBox (),
61  fBoundingBoxValid (kFALSE),
62  fDoFrustumCheck (kTRUE),
63  fDoClipCheck (kTRUE),
64  fAutoDestruct (kTRUE)
65 {
66  // Default constructor.
67 
68  fSceneID = fgSceneIDSrc++;
69  fName = Form("unnamed-%d", fSceneID);
70 }
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 /// Destructor.
74 
75 TGLSceneBase::~TGLSceneBase()
76 {
77  for (ViewerList_i i=fViewers.begin(); i!=fViewers.end(); ++i)
78  {
79  (*i)->SceneDestructing(this);
80  }
81 }
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// Add viewer to the list.
85 
86 void TGLSceneBase::AddViewer(TGLViewerBase* viewer)
87 {
88  ViewerList_i i = std::find(fViewers.begin(), fViewers.end(), viewer);
89  if (i == fViewers.end())
90  fViewers.push_back(viewer);
91  else
92  Warning("TGLSceneBase::AddViewer", "viewer already in the list.");
93 }
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 /// Remove viewer from the list.
97 /// If auto-destruct is on and the last viewer is removed the scene
98 /// destructs itself.
99 
100 void TGLSceneBase::RemoveViewer(TGLViewerBase* viewer)
101 {
102  ViewerList_i i = std::find(fViewers.begin(), fViewers.end(), viewer);
103  if (i != fViewers.end())
104  fViewers.erase(i);
105  else
106  Warning("TGLSceneBase::RemoveViewer", "viewer not found in the list.");
107 
108  if (fViewers.empty() && fAutoDestruct)
109  {
110  if (gDebug > 0)
111  Info("TGLSceneBase::RemoveViewer", "scene '%s' not used - autodestructing.", GetName());
112  delete this;
113  }
114 }
115 ////////////////////////////////////////////////////////////////////////////////
116 /// Tag all viewers as changed.
117 
118 void TGLSceneBase::TagViewersChanged()
119 {
120  for (ViewerList_i i=fViewers.begin(); i!=fViewers.end(); ++i)
121  {
122  (*i)->Changed();
123  }
124 }
125 
126 /**************************************************************************/
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Name printed on locking info messages.
130 
131 const char* TGLSceneBase::LockIdStr() const
132 {
133  return Form("TGLSceneBase %s", fName.Data());
134 }
135 
136 /**************************************************************************/
137 // SceneInfo management
138 /**************************************************************************/
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Create a scene-info instance appropriate for this scene class.
142 /// Here we instantiate the scene-info base-class TGLSceneInfo.
143 
144 TGLSceneInfo* TGLSceneBase::CreateSceneInfo(TGLViewerBase* view)
145 {
146  return new TGLSceneInfo(view, this);
147 }
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 /// Fill scene-info with very basic information that is practically
151 /// view independent. This is called when scene content is changed
152 /// or when camera-interest changes.
153 
154 void TGLSceneBase::RebuildSceneInfo(TGLRnrCtx& ctx)
155 {
156  TGLSceneInfo* sinfo = ctx.GetSceneInfo();
157 
158  sinfo->SetLastClip(0);
159  sinfo->SetLastCamera(0);
160 }
161 
162 ////////////////////////////////////////////////////////////////////////////////
163 /// Fill scene-info with information needed for rendering, take into
164 /// account the render-context (viewer state, camera, clipping).
165 /// Usually called from TGLViewer before rendering a scene if some
166 /// moderately significant part of render-context has changed.
167 ///
168 /// Here we update the basic state (clear last-LOD, mark the time,
169 /// set global <-> scene transformation matrices) and potentially
170 /// study and refine the clipping planes based on scene bounding box.
171 
172 void TGLSceneBase::UpdateSceneInfo(TGLRnrCtx& ctx)
173 {
174  if (gDebug > 3)
175  {
176  Info("TGLSceneBase::UpdateSceneInfo",
177  "'%s' timestamp=%u",
178  GetName(), fTimeStamp);
179  }
180 
181  TGLSceneInfo* sinfo = ctx.GetSceneInfo();
182 
183  // ------------------------------------------------------------
184  // Reset
185  // ------------------------------------------------------------
186 
187  sinfo->SetLastLOD (TGLRnrCtx::kLODUndef);
188  sinfo->SetLastStyle (TGLRnrCtx::kStyleUndef);
189  sinfo->SetSceneStamp(fTimeStamp);
190 
191  sinfo->InFrustum (kTRUE);
192  sinfo->InClip (kTRUE);
193  sinfo->ClipMode (TGLSceneInfo::kClipNone);
194 
195  // ------------------------------------------------------------
196  // Setup
197  // ------------------------------------------------------------
198 
199  // !!!
200  // setup scene transformation matrices
201  // so far the matrices in scene-base and scene-info are not enabled
202  // sinfo->fSceneToGlobal = scene-info-trans * scene-base-trans;
203  // sinfo->fGlobalToScene = inv of above;
204  // transform to clip and to eye coordinates also interesting
205  //
206  // All these are now done in TGLViewerBase::PreRender() via
207  // TGLSceneInfo::SetupTransformsAndBBox().
208 
209  sinfo->SetLastClip(0);
210  sinfo->FrustumPlanes().clear();
211  sinfo->ClipPlanes().clear();
212 
213  if (fDoFrustumCheck)
214  {
215  for (Int_t i=0; i<TGLCamera::kPlanesPerFrustum; ++i)
216  {
217  TGLPlane p = ctx.GetCamera()->FrustumPlane((TGLCamera::EFrustumPlane)i);
218  // !!! transform plane
219  switch (BoundingBox().Overlap(p))
220  {
221  case Rgl::kInside: // Whole scene passes ... no need to store it.
222  break;
223  case Rgl::kPartial:
224  sinfo->FrustumPlanes().push_back(p);
225  break;
226  case Rgl::kOutside:
227  sinfo->InFrustum(kFALSE);
228  break;
229  }
230  }
231  }
232 
233  if (fDoClipCheck && ctx.HasClip())
234  {
235  if (ctx.Clip()->GetMode() == TGLClip::kOutside)
236  sinfo->ClipMode(TGLSceneInfo::kClipOutside);
237  else
238  sinfo->ClipMode(TGLSceneInfo::kClipInside);
239 
240  std::vector<TGLPlane> planeSet;
241  ctx.Clip()->PlaneSet(planeSet);
242 
243  // Strip any planes outside the scene bounding box - no effect
244  std::vector<TGLPlane>::iterator it = planeSet.begin();
245  while (it != planeSet.end())
246  {
247  // !!! transform plane
248  switch (BoundingBox().Overlap(*it))
249  {
250  case Rgl::kInside: // Whole scene passes ... no need to store it.
251  break;
252  case Rgl::kPartial:
253  sinfo->ClipPlanes().push_back(*it);
254  break;
255  case Rgl::kOutside: // Depends on mode
256  if (sinfo->ClipMode() == TGLSceneInfo::kClipOutside)
257  {
258  // Scene is outside of whole clip object - nothing visible.
259  sinfo->InClip(kFALSE);
260  }
261  else
262  {
263  // Scene is completely inside of whole clip object -
264  // draw all scene without clipping.
265  sinfo->ClipMode(TGLSceneInfo::kClipNone);
266  }
267  // In either case further checks not needed.
268  sinfo->ClipPlanes().clear();
269  return;
270  }
271  ++it;
272  }
273  sinfo->SetLastClip(ctx.Clip());
274  sinfo->SetClipStamp(ctx.Clip()->TimeStamp());
275  }
276 
277  sinfo->SetLastCamera(ctx.GetCamera());
278  sinfo->SetCameraStamp(ctx.GetCamera()->TimeStamp());
279 }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 /// Setup LOD-dependant values in scene-info.
283 ///
284 /// Nothing to be done here but to store the last LOD.
285 
286 void TGLSceneBase::LodifySceneInfo(TGLRnrCtx& ctx)
287 {
288  if (gDebug > 3)
289  {
290  Info("TGLSceneBase::LodifySceneInfo",
291  "'%s' timestamp=%u lod=%d",
292  GetName(), fTimeStamp, ctx.CombiLOD());
293  }
294 
295  TGLSceneInfo & sInfo = * ctx.GetSceneInfo();
296  sInfo.SetLastLOD(ctx.CombiLOD());
297 }
298 
299 
300 /**************************************************************************/
301 // Rendering
302 /**************************************************************************/
303 
304 ////////////////////////////////////////////////////////////////////////////////
305 /// Perform basic pre-render initialization:
306 /// - calculate LOD, Style, Clipping,
307 /// - build draw lists.
308 ///
309 /// This is called in the beginning of the GL-viewer draw cycle.
310 
311 void TGLSceneBase::PreDraw(TGLRnrCtx & rnrCtx)
312 {
313  if ( ! IsDrawOrSelectLock()) {
314  Error("TGLSceneBase::FullRender", "expected Draw or Select Lock");
315  }
316 
317  TGLSceneInfo& sInfo = * rnrCtx.GetSceneInfo();
318 
319  // Bounding-box check done elsewhere (in viewer::pre-render)
320 
321  if (fTimeStamp > sInfo.SceneStamp())
322  {
323  RebuildSceneInfo(rnrCtx);
324  }
325 
326 
327  Bool_t needUpdate = sInfo.HasUpdateTimeouted();
328 
329  if (rnrCtx.GetCamera() != sInfo.LastCamera())
330  {
331  sInfo.ResetCameraStamp();
332  needUpdate = kTRUE;
333  }
334  else if (rnrCtx.GetCamera()->TimeStamp() > sInfo.CameraStamp())
335  {
336  needUpdate = kTRUE;
337  }
338 
339  TGLClip* clip = 0;
340  if (sInfo.Clip() != 0) clip = sInfo.Clip();
341  else if (fClip != 0) clip = fClip;
342  else clip = rnrCtx.ViewerClip();
343  if (clip != sInfo.LastClip())
344  {
345  sInfo.ResetClipStamp();
346  needUpdate = kTRUE;
347  }
348  else if (clip && clip->TimeStamp() > sInfo.ClipStamp())
349  {
350  needUpdate = kTRUE;
351  }
352  rnrCtx.SetClip(clip);
353 
354  if (needUpdate)
355  {
356  UpdateSceneInfo(rnrCtx);
357  }
358 
359 
360  // Setup LOD ... optionally lodify.
361  Short_t lod;
362  if (sInfo.LOD() != TGLRnrCtx::kLODUndef) lod = sInfo.LOD();
363  else if (fLOD != TGLRnrCtx::kLODUndef) lod = fLOD;
364  else lod = rnrCtx.ViewerLOD();
365  rnrCtx.SetSceneLOD(lod);
366  rnrCtx.SetCombiLOD(TMath::Min(rnrCtx.ViewerLOD(), rnrCtx.SceneLOD()));
367  if (needUpdate || rnrCtx.CombiLOD() != sInfo.LastLOD())
368  {
369  LodifySceneInfo(rnrCtx);
370  }
371 
372  // Setup style.
373  Short_t style;
374  if (sInfo.Style() != TGLRnrCtx::kStyleUndef) style = sInfo.Style();
375  else if (fStyle != TGLRnrCtx::kStyleUndef) style = fStyle;
376  else style = rnrCtx.ViewerStyle();
377  rnrCtx.SetSceneStyle(style);
378  sInfo.SetLastStyle(style);
379 
380  // Wireframe line width.
381  Float_t wf_linew;
382  if (sInfo.WFLineW() != 0) wf_linew = sInfo.WFLineW();
383  else if (fWFLineW != 0) wf_linew = fWFLineW;
384  else wf_linew = rnrCtx.ViewerWFLineW();
385  rnrCtx.SetSceneWFLineW(wf_linew);
386  sInfo.SetLastWFLineW(wf_linew);
387  // Outline line width.
388  Float_t ol_linew;
389  if (sInfo.OLLineW() != 0) ol_linew = sInfo.OLLineW();
390  else if (fOLLineW != 0) ol_linew = fOLLineW;
391  else ol_linew = rnrCtx.ViewerOLLineW();
392  rnrCtx.SetSceneOLLineW(ol_linew);
393  sInfo.SetLastOLLineW(ol_linew);
394 }
395 
396 ////////////////////////////////////////////////////////////////////////////////
397 /// Perform pre-render initialization - fill rnrCtx with
398 /// values stored during PreDraw().
399 ///
400 /// This is called each time before RenderXyzz().
401 
402 void TGLSceneBase::PreRender(TGLRnrCtx & rnrCtx)
403 {
404  TGLSceneInfo& sInfo = * rnrCtx.GetSceneInfo();
405 
406  rnrCtx.SetClip (sInfo.LastClip());
407  rnrCtx.SetCombiLOD (sInfo.LastLOD());
408  rnrCtx.SetSceneStyle (sInfo.LastStyle());
409  rnrCtx.SetSceneWFLineW (sInfo.LastWFLineW());
410  rnrCtx.SetSceneOLLineW (sInfo.LastOLLineW());
411 
412  // !!!
413  // eventually handle matrix stack.
414  // glPushMatrix();
415  // glMultMatrix(something-from-scene-info);
416  // Should also fix camera matrices
417 }
418 
419 ////////////////////////////////////////////////////////////////////////////////
420 /// This function does rendering of all stages, the shapes are
421 /// rendered in the following order: opaque, transparent,
422 /// selected-opaque, selected-transparent.
423 ///
424 /// GL-depth buffer is cleared after transparent shapes have been
425 /// rendered.
426 ///
427 /// This is never called from ROOT GL directly. Use it if you know
428 /// you are rendering a single scene.
429 
430 void TGLSceneBase::Render(TGLRnrCtx & rnrCtx)
431 {
432  RenderOpaque(rnrCtx);
433  RenderTransp(rnrCtx);
434  RenderSelOpaque(rnrCtx);
435  RenderSelTransp(rnrCtx);
436 }
437 
438 ////////////////////////////////////////////////////////////////////////////////
439 /// Render opaque elements.
440 
441 void TGLSceneBase::RenderOpaque(TGLRnrCtx & /*rnrCtx*/)
442 {
443 }
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 /// Render transparent elements.
447 
448 void TGLSceneBase::RenderTransp(TGLRnrCtx & /*rnrCtx*/)
449 {
450 }
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Render selected opaque elements.
454 
455 void TGLSceneBase::RenderSelOpaque(TGLRnrCtx & /*rnrCtx*/)
456 {
457 }
458 
459 ////////////////////////////////////////////////////////////////////////////////
460 /// Render selected transparent elements for highlight.
461 
462 void TGLSceneBase::RenderSelTransp(TGLRnrCtx & /*rnrCtx*/)
463 {
464 }
465 
466 ////////////////////////////////////////////////////////////////////////////////
467 /// Render selected opaque elements for highlight.
468 
469 void TGLSceneBase::RenderSelOpaqueForHighlight(TGLRnrCtx & /*rnrCtx*/)
470 {
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 /// Render selected transparent elements.
475 
476 void TGLSceneBase::RenderSelTranspForHighlight(TGLRnrCtx & /*rnrCtx*/)
477 {
478 }
479 
480 ////////////////////////////////////////////////////////////////////////////////
481 /// Perform post-render clean-up.
482 
483 void TGLSceneBase::PostRender(TGLRnrCtx & /*rnrCtx*/)
484 {
485  // !!!
486  // Cleanup matrix stack
487  // glPopMatrix();
488  // Should also fix camera matrices
489 }
490 
491 ////////////////////////////////////////////////////////////////////////////////
492 /// Finalize drawing.
493 ///
494 /// This is called at the end of the GL-viewer draw cycle.
495 
496 void TGLSceneBase::PostDraw(TGLRnrCtx & /*rnrCtx*/)
497 {
498 }
499 
500 /**************************************************************************/
501 // Selection
502 /**************************************************************************/
503 
504 ////////////////////////////////////////////////////////////////////////////////
505 /// Process selection record rec.
506 /// 'curIdx' is the item position where the scene should start
507 /// its processing.
508 /// Return TRUE if an object has been identified or FALSE otherwise.
509 /// The scene-info member of the record is already set by the caller.
510 ///
511 /// See implementation in sub-class TGLScene, here we just return FALSE.
512 
513 Bool_t TGLSceneBase::ResolveSelectRecord(TGLSelectRecord & /*rec*/,
514  Int_t /*curIdx*/)
515 {
516  return kFALSE;
517 }