Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLViewerBase.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 "TGLViewerBase.h"
13 
14 #include "TGLSceneBase.h"
15 #include "TGLSceneInfo.h"
16 
17 #include "TGLRnrCtx.h"
18 #include "TGLCamera.h"
19 #include "TGLClip.h"
20 #include "TGLOverlay.h"
21 #include "TGLSelectBuffer.h"
22 #include "TGLSelectRecord.h"
23 #include "TGLAnnotation.h"
24 #include "TGLUtil.h"
25 
26 #include "TGLContext.h"
27 #include "TGLIncludes.h"
28 
29 #include "TEnv.h"
30 
31 #include <algorithm>
32 #include <stdexcept>
33 
34 /** \class TGLViewerBase
35 \ingroup opengl
36 Base class for GL viewers. Provides a basic scene management and a
37 small set of control variables (camera, LOD, style, clip) that are
38 used by the scene classes. Renering wrappers are available but
39 minimal.
40 
41 There is no concept of GL-context here ... we just draw
42 into whatever is set from outside.
43 
44 Development notes:
45 
46 Each viewer automatically creates a TGLRnrCtx and passes it down
47 all render functions.
48 */
49 
50 ClassImp(TGLViewerBase);
51 
52 ////////////////////////////////////////////////////////////////////////////////
53 
54 TGLViewerBase::TGLViewerBase() :
55  fRnrCtx (0),
56  fCamera (0),
57  fClip (0),
58  fLOD (TGLRnrCtx::kLODHigh),
59  fStyle (TGLRnrCtx::kFill),
60  fWFLineW (1),
61  fOLLineW (1),
62 
63  fResetSceneInfosOnRender (kFALSE),
64  fChanged (kFALSE)
65 {
66  // Constructor.
67 
68  fRnrCtx = new TGLRnrCtx(this);
69 
70  fWFLineW = gEnv->GetValue("OpenGL.WireframeLineScalingFactor", 1.0);
71  fOLLineW = gEnv->GetValue("OpenGL.OutlineLineScalingFactor", 1.0);
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 /// Destructor.
76 
77 TGLViewerBase::~TGLViewerBase()
78 {
79  for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
80  {
81  (*i)->GetScene()->RemoveViewer(this);
82  delete *i;
83  }
84 
85  DeleteOverlayElements(TGLOverlayElement::kAll);
86 
87  delete fRnrCtx;
88 }
89 
90 ////////////////////////////////////////////////////////////////////////////////
91 /// Name to print in locking output.
92 
93 const char* TGLViewerBase::LockIdStr() const
94 {
95  return "TGLViewerBase";
96 }
97 
98 /**************************************************************************/
99 // Scene & scene-info management
100 /**************************************************************************/
101 
102 ////////////////////////////////////////////////////////////////////////////////
103 /// Find scene-info corresponding to scene.
104 
105 TGLViewerBase::SceneInfoList_i
106 TGLViewerBase::FindScene(TGLSceneBase* scene)
107 {
108  SceneInfoList_i i = fScenes.begin();
109  while (i != fScenes.end() && (*i)->GetScene() != scene) ++i;
110  return i;
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////
114 /// Add new scene, appropriate scene-info is created.
115 
116 TGLSceneInfo* TGLViewerBase::AddScene(TGLSceneBase* scene)
117 {
118  SceneInfoList_i i = FindScene(scene);
119  if (i == fScenes.end()) {
120  TGLSceneInfo* sinfo = scene->CreateSceneInfo(this);
121  fScenes.push_back(sinfo);
122  scene->AddViewer(this);
123  Changed();
124  return sinfo;
125  } else {
126  Warning("TGLViewerBase::AddScene", "scene '%s' already in the list.",
127  scene->GetName());
128  return 0;
129  }
130 }
131 
132 ////////////////////////////////////////////////////////////////////////////////
133 /// Remove scene from the viewer, its scene-info is deleted.
134 
135 void TGLViewerBase::RemoveScene(TGLSceneBase* scene)
136 {
137  SceneInfoList_i i = FindScene(scene);
138  if (i != fScenes.end()) {
139  delete *i;
140  fScenes.erase(i);
141  scene->RemoveViewer(this);
142  Changed();
143  } else {
144  Warning("TGLViewerBase::RemoveScene", "scene '%s' not found.",
145  scene->GetName());
146  }
147 }
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 /// Remove all scenes from the viewer, their scene-infos are deleted.
151 
152 void TGLViewerBase::RemoveAllScenes()
153 {
154  for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
155  {
156  TGLSceneInfo * sinfo = *i;
157  sinfo->GetScene()->RemoveViewer(this);
158  delete sinfo;
159  }
160  fScenes.clear();
161  Changed();
162 }
163 
164 ////////////////////////////////////////////////////////////////////////////////
165 /// Remove scene, its scene-info is deleted.
166 /// Called from scene that is being destroyed while still holding
167 /// viewer references.
168 
169 void TGLViewerBase::SceneDestructing(TGLSceneBase* scene)
170 {
171  SceneInfoList_i i = FindScene(scene);
172  if (i != fScenes.end()) {
173  delete *i;
174  fScenes.erase(i);
175  Changed();
176  } else {
177  Warning("TGLViewerBase::SceneDestructing", "scene not found.");
178  }
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 /// Find scene-info corresponding to scene.
183 
184 TGLSceneInfo* TGLViewerBase::GetSceneInfo(TGLSceneBase* scene)
185 {
186  SceneInfoList_i i = FindScene(scene);
187  if (i != fScenes.end())
188  return *i;
189  else
190  return 0;
191 }
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 /// Find logical-shape representing object id in the list of scenes.
195 /// Return 0 if not found.
196 
197 TGLLogicalShape* TGLViewerBase::FindLogicalInScenes(TObject* id)
198 {
199  for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
200  {
201  TGLLogicalShape *lshp = (*i)->GetScene()->FindLogical(id);
202  if (lshp)
203  return lshp;
204  }
205  return 0;
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// Add overlay element.
210 
211 void TGLViewerBase::AddOverlayElement(TGLOverlayElement* el)
212 {
213  fOverlay.push_back(el);
214  Changed();
215 }
216 
217 ////////////////////////////////////////////////////////////////////////////////
218 /// Remove overlay element.
219 
220 void TGLViewerBase::RemoveOverlayElement(TGLOverlayElement* el)
221 {
222  OverlayElmVec_i it = std::find(fOverlay.begin(), fOverlay.end(), el);
223  if (it != fOverlay.end())
224  fOverlay.erase(it);
225  Changed();
226 }
227 
228 ////////////////////////////////////////////////////////////////////////////////
229 /// Delete overlay elements that are annotations.
230 
231 void TGLViewerBase::DeleteOverlayAnnotations()
232 {
233  DeleteOverlayElements(TGLOverlayElement::kAnnotation);
234 }
235 
236 ////////////////////////////////////////////////////////////////////////////////
237 /// Delete overlay elements.
238 
239 void TGLViewerBase::DeleteOverlayElements(TGLOverlayElement::ERole role)
240 {
241  OverlayElmVec_t ovl;
242  fOverlay.swap(ovl);
243 
244  for (OverlayElmVec_i i = ovl.begin(); i != ovl.end(); ++i)
245  {
246  if (role == TGLOverlayElement::kAll || (*i)->GetRole() == role)
247  delete *i;
248  else
249  fOverlay.push_back(*i);
250  }
251 
252  Changed();
253 }
254 
255 /**************************************************************************/
256 // SceneInfo update / check
257 /**************************************************************************/
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 /// Force rebuild of view-dependent scene-info structures.
261 ///
262 /// This should be called before calling render (draw/select) if
263 /// something that affects camera interest has been changed.
264 
265 void TGLViewerBase::ResetSceneInfos()
266 {
267  SceneInfoList_i i = fScenes.begin();
268  while (i != fScenes.end())
269  {
270  (*i)->ResetSceneStamp();
271  ++i;
272  }
273 }
274 
275 ////////////////////////////////////////////////////////////////////////////////
276 /// Merge bounding-boxes of all active registered scenes.
277 
278 void TGLViewerBase::MergeSceneBBoxes(TGLBoundingBox& bbox)
279 {
280  bbox.SetEmpty();
281  for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
282  {
283  TGLSceneInfo * sinfo = *i;
284  if (sinfo->GetActive())
285  {
286  sinfo->SetupTransformsAndBBox(); // !!! transform not done yet, no camera
287  bbox.MergeAligned(sinfo->GetTransformedBBox());
288  }
289  }
290 }
291 
292 /**************************************************************************/
293 // Rendering / selection virtuals
294 /**************************************************************************/
295 
296 ////////////////////////////////////////////////////////////////////////////////
297 /// Setup clip-object. Protected virtual method.
298 
299 void TGLViewerBase::SetupClipObject()
300 {
301  if (fClip)
302  {
303  fClip->Setup(fOverallBoundingBox);
304  }
305 }
306 
307 ////////////////////////////////////////////////////////////////////////////////
308 /// Initialize render-context, setup camera, GL, render-area.
309 /// Check and lock scenes, determine their visibility.
310 
311 void TGLViewerBase::PreRender()
312 {
313  TGLContextIdentity* cid = TGLContextIdentity::GetCurrent();
314  if (cid == 0)
315  {
316  // Assume derived class set it up for us.
317  // This happens due to complex implementation
318  // of gl-in-pad using gGLManager.
319  // In principle we should throw an exception:
320  // throw std::runtime_error("Can not resolve GL context.");
321  }
322  else
323  {
324  if (cid != fRnrCtx->GetGLCtxIdentity())
325  {
326  if (fRnrCtx->GetGLCtxIdentity() != 0)
327  Warning("TGLViewerBase::PreRender", "Switching to another GL context; maybe you should use context-sharing.");
328  fRnrCtx->SetGLCtxIdentity(cid);
329  }
330  }
331 
332  fRnrCtx->SetCamera (fCamera);
333  fRnrCtx->SetViewerLOD (fLOD);
334  fRnrCtx->SetViewerStyle (fStyle);
335  fRnrCtx->SetViewerWFLineW (fWFLineW);
336  fRnrCtx->SetViewerOLLineW (fOLLineW);
337  fRnrCtx->SetViewerClip (fClip);
338 
339  if (fResetSceneInfosOnRender)
340  {
341  ResetSceneInfos();
342  fResetSceneInfosOnRender = kFALSE;
343  }
344 
345  fOverallBoundingBox.SetEmpty();
346  SceneInfoList_t locked_scenes;
347  for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
348  {
349  TGLSceneInfo *sinfo = *i;
350  TGLSceneBase *scene = sinfo->GetScene();
351  if (sinfo->GetActive())
352  {
353  if ( ! fRnrCtx->Selection() || scene->GetSelectable())
354  {
355  if ( ! sinfo->GetScene()->TakeLock(kDrawLock))
356  {
357  Warning("TGLViewerBase::PreRender", "locking of scene '%s' failed, skipping.",
358  sinfo->GetScene()->GetName());
359  continue;
360  }
361  locked_scenes.push_back(sinfo);
362  }
363  sinfo->SetupTransformsAndBBox(); // !!! transform not done yet
364  fOverallBoundingBox.MergeAligned(sinfo->GetTransformedBBox());
365  }
366  }
367 
368  fCamera->Apply(fOverallBoundingBox, fRnrCtx->GetPickRectangle());
369  SetupClipObject();
370 
371  // Make precursory selection of visible scenes.
372  // Only scene bounding-box .vs. camera frustum check performed.
373  fVisScenes.clear();
374  for (SceneInfoList_i i=locked_scenes.begin(); i!=locked_scenes.end(); ++i)
375  {
376  TGLSceneInfo * sinfo = *i;
377  const TGLBoundingBox & bbox = sinfo->GetTransformedBBox();
378  Bool_t visp = (!bbox.IsEmpty() && fCamera->FrustumOverlap(bbox) != Rgl::kOutside);
379  sinfo->ViewCheck(visp);
380  if (visp) {
381  fRnrCtx->SetSceneInfo(sinfo);
382  sinfo->GetScene()->PreDraw(*fRnrCtx);
383  if (sinfo->IsVisible()) {
384  fVisScenes.push_back(sinfo);
385  } else {
386  sinfo->GetScene()->PostDraw(*fRnrCtx);
387  sinfo->GetScene()->ReleaseLock(kDrawLock);
388  }
389  fRnrCtx->SetSceneInfo(0);
390  } else {
391  sinfo->GetScene()->ReleaseLock(kDrawLock);
392  }
393  }
394 }
395 
396 ////////////////////////////////////////////////////////////////////////////////
397 /// Call sub-rendering function render_foo on all currently visible
398 /// scenes.
399 
400 void TGLViewerBase::SubRenderScenes(SubRender_foo render_foo)
401 {
402  Int_t nScenes = fVisScenes.size();
403 
404  for (Int_t i = 0; i < nScenes; ++i)
405  {
406  TGLSceneInfo* sinfo = fVisScenes[i];
407  TGLSceneBase* scene = sinfo->GetScene();
408  fRnrCtx->SetSceneInfo(sinfo);
409  glPushName(i);
410  scene->PreRender(*fRnrCtx);
411  (scene->*render_foo)(*fRnrCtx);
412  scene->PostRender(*fRnrCtx);
413  glPopName();
414  fRnrCtx->SetSceneInfo(0);
415  }
416 }
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 /// Render all scenes. This is done in two main passes:
420 /// - render opaque objects from all scenes
421 /// - render transparent objects from all scenes
422 
423 void TGLViewerBase::Render()
424 {
425  RenderOpaque();
426  RenderTransparent();
427 }
428 
429 ////////////////////////////////////////////////////////////////////////////////
430 /// Render non-selected objects from all scenes.
431 
432 void TGLViewerBase::RenderNonSelected()
433 {
434  SubRenderScenes(&TGLSceneBase::RenderOpaque);
435 
436  TGLCapabilityEnabler blend(GL_BLEND, kTRUE);
437  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
438  glDepthMask(GL_FALSE);
439 
440  SubRenderScenes(&TGLSceneBase::RenderTransp);
441 
442  glDepthMask(GL_TRUE);
443 
444  TGLUtil::CheckError("TGLViewerBase::RenderNonSelected - pre exit check");
445 }
446 
447 ////////////////////////////////////////////////////////////////////////////////
448 /// Render selected objects from all scenes.
449 
450 void TGLViewerBase::RenderSelected()
451 {
452  SubRenderScenes(&TGLSceneBase::RenderSelOpaque);
453 
454  TGLCapabilityEnabler blend(GL_BLEND, kTRUE);
455  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
456  glDepthMask(GL_FALSE);
457 
458  SubRenderScenes(&TGLSceneBase::RenderSelTransp);
459 
460  glDepthMask(GL_TRUE);
461 
462  TGLUtil::CheckError("TGLViewerBase::RenderSelected - pre exit check");
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////
466 /// Render selected objects from all scenes for highlight.
467 
468 void TGLViewerBase::RenderSelectedForHighlight()
469 {
470  fRnrCtx->SetHighlight(kTRUE);
471 
472  SubRenderScenes(&TGLSceneBase::RenderSelOpaqueForHighlight);
473 
474  TGLCapabilityEnabler blend(GL_BLEND, kTRUE);
475  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
476  glDepthMask(GL_FALSE);
477 
478  SubRenderScenes(&TGLSceneBase::RenderSelTranspForHighlight);
479 
480  glDepthMask(GL_TRUE);
481 
482  fRnrCtx->SetHighlight(kFALSE);
483 }
484 
485 ////////////////////////////////////////////////////////////////////////////////
486 /// Render opaque objects from all scenes.
487 
488 void TGLViewerBase::RenderOpaque(Bool_t rnr_non_selected, Bool_t rnr_selected)
489 {
490  if (rnr_non_selected)
491  {
492  SubRenderScenes(&TGLSceneBase::RenderOpaque);
493  }
494  if (rnr_selected)
495  {
496  SubRenderScenes(&TGLSceneBase::RenderSelOpaque);
497  }
498 
499  TGLUtil::CheckError("TGLViewerBase::RenderOpaque - pre exit check");
500 }
501 
502 ////////////////////////////////////////////////////////////////////////////////
503 /// Render transparent objects from all scenes.
504 
505 void TGLViewerBase::RenderTransparent(Bool_t rnr_non_selected, Bool_t rnr_selected)
506 {
507  TGLCapabilityEnabler blend(GL_BLEND, kTRUE);
508  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
509  glDepthMask(GL_FALSE);
510 
511  if (rnr_non_selected)
512  {
513  SubRenderScenes(&TGLSceneBase::RenderTransp);
514  }
515  if (rnr_selected)
516  {
517  SubRenderScenes(&TGLSceneBase::RenderSelTransp);
518  }
519 
520  glDepthMask(GL_TRUE);
521 
522  TGLUtil::CheckError("TGLViewerBase::RenderTransparent - pre exit check");
523 }
524 
525 ////////////////////////////////////////////////////////////////////////////////
526 /// Render overlay objects.
527 
528 void TGLViewerBase::RenderOverlay(Int_t state, Bool_t selection)
529 {
530  Int_t nOvl = fOverlay.size();
531  for (Int_t i = 0; i < nOvl; ++i)
532  {
533  TGLOverlayElement* el = fOverlay[i];
534  if (el->GetState() & state)
535  {
536  if (selection) glPushName(i);
537  el->Render(*fRnrCtx);
538  if (selection) glPopName();
539  }
540  }
541 }
542 
543 ////////////////////////////////////////////////////////////////////////////////
544 /// Function called after rendering is finished.
545 /// Here we just unlock the scenes.
546 
547 void TGLViewerBase::PostRender()
548 {
549  for (SceneInfoVec_i i = fVisScenes.begin(); i != fVisScenes.end(); ++i)
550  {
551  TGLSceneInfo* sinfo = *i;
552  fRnrCtx->SetSceneInfo(sinfo);
553  sinfo->GetScene()->PostDraw(*fRnrCtx);
554  fRnrCtx->SetSceneInfo(0);
555  sinfo->GetScene()->ReleaseLock(kDrawLock);
556  }
557  fChanged = kFALSE;
558 }
559 
560 ////////////////////////////////////////////////////////////////////////////////
561 /// Perform minimal initialization for overlay selection.
562 /// Here we assume that scene has already been drawn and that
563 /// camera and overall bounding box are ok.
564 /// Scenes are not locked.
565 
566 void TGLViewerBase::PreRenderOverlaySelection()
567 {
568  fCamera->Apply(fOverallBoundingBox, fRnrCtx->GetPickRectangle());
569 }
570 
571 ////////////////////////////////////////////////////////////////////////////////
572 /// Perform cleanup after overlay selection.
573 
574 void TGLViewerBase::PostRenderOverlaySelection()
575 {
576 }
577 
578 /**************************************************************************/
579 // High-level functions: drawing and picking.
580 /**************************************************************************/
581 
582 
583 //______________________________________________________________________
584 //void TGLViewerBase::Select(Int_t selX, Int_t selY, Int_t selRadius)
585 //{
586  // Perform render-pass in selection mode.
587  // Process the selection results.
588  // For now only in derived classes.
589 //}
590 
591 ////////////////////////////////////////////////////////////////////////////////
592 /// Process selection record on buffer-position 'recIdx' and
593 /// fill the data into 'rec'.
594 ///
595 /// Returns TRUE if scene was demangled and an object identified.
596 /// When FALSE is returned it is still possible that scene has been
597 /// identified. Check for this if interested in scene-selection.
598 ///
599 /// The select-buffer is taken form fRnrCtx.
600 
601 Bool_t TGLViewerBase::ResolveSelectRecord(TGLSelectRecord& rec, Int_t recIdx)
602 {
603  TGLSelectBuffer* sb = fRnrCtx->GetSelectBuffer();
604  if (recIdx >= sb->GetNRecords())
605  return kFALSE;
606 
607  if (sb->SelectRecord(rec, recIdx) < 1)
608  return kFALSE;
609 
610  UInt_t sceneIdx = rec.GetItem(0);
611  if (sceneIdx >= fVisScenes.size())
612  return kFALSE;
613 
614  TGLSceneInfo* sinfo = fVisScenes[sceneIdx];
615  rec.SetSceneInfo(sinfo);
616  return sinfo->GetScene()->ResolveSelectRecord(rec, 1);
617 }
618 
619 ////////////////////////////////////////////////////////////////////////////////
620 /// Find next select record that can be resolved, starting from
621 /// position 'recIdx'.
622 /// 'recIdx' is passed as reference and points to found record in the buffer.
623 
624 Bool_t TGLViewerBase::FindClosestRecord(TGLSelectRecord& rec, Int_t& recIdx)
625 {
626  TGLSelectBuffer* sb = fRnrCtx->GetSelectBuffer();
627 
628  while (recIdx < sb->GetNRecords())
629  {
630  if (ResolveSelectRecord(rec, recIdx))
631  return kTRUE;
632  ++recIdx;
633  }
634  return kFALSE;
635 }
636 
637 ////////////////////////////////////////////////////////////////////////////////
638 /// Find next select record that can be resolved and whose result is
639 /// not transparent, starting from position 'recIdx'.
640 /// 'recIdx' is passed as reference and points to found record in the buffer.
641 
642 Bool_t TGLViewerBase::FindClosestOpaqueRecord(TGLSelectRecord& rec, Int_t& recIdx)
643 {
644  TGLSelectBuffer* sb = fRnrCtx->GetSelectBuffer();
645 
646  while (recIdx < sb->GetNRecords())
647  {
648  if (ResolveSelectRecord(rec, recIdx) && ! rec.GetTransparent())
649  return kTRUE;
650  ++recIdx;
651  }
652  return kFALSE;
653 }
654 
655 ////////////////////////////////////////////////////////////////////////////////
656 /// Find next overlay-select record that can be resolved, starting from
657 /// position 'recIdx'.
658 /// 'recIdx' is passed as reference and points to found record in the buffer.
659 
660 Bool_t TGLViewerBase::FindClosestOverlayRecord(TGLOvlSelectRecord& rec,
661  Int_t & recIdx)
662 {
663  TGLSelectBuffer* sb = fRnrCtx->GetSelectBuffer();
664 
665  while (recIdx < sb->GetNRecords())
666  {
667  sb->SelectRecord(rec, recIdx);
668  if (rec.GetItem(0) < fOverlay.size())
669  {
670  rec.SetOvlElement(fOverlay[rec.GetItem(0)]);
671  rec.NextPos();
672  return kTRUE;
673  }
674  ++recIdx;
675  }
676  return kFALSE;
677 }