TGLViewerBase.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLViewerBase.cxx 36675 2010-11-15 20:33:58Z matevz $
00002 // Author:  Matevz Tadel, Feb 2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TGLViewerBase.h"
00013 
00014 #include "TGLSceneBase.h"
00015 #include "TGLSceneInfo.h"
00016 
00017 #include "TGLRnrCtx.h"
00018 #include "TGLCamera.h"
00019 #include "TGLClip.h"
00020 #include "TGLOverlay.h"
00021 #include "TGLSelectBuffer.h"
00022 #include "TGLSelectRecord.h"
00023 #include "TGLAnnotation.h"
00024 #include "TGLUtil.h"
00025 
00026 #include "TGLContext.h"
00027 #include "TGLIncludes.h"
00028 
00029 #include <algorithm>
00030 #include <stdexcept>
00031 
00032 //______________________________________________________________________
00033 //
00034 // Base class for GL viewers. Provides a basic scene management and a
00035 // small set of control variables (camera, LOD, style, clip) that are
00036 // used by the scene classes. Renering wrappers are available but
00037 // minimal.
00038 //
00039 // There is no concept of GL-context here ... we just draw
00040 // into whatever is set from outside.
00041 //
00042 // Development notes:
00043 //
00044 // Each viewer automatically creates a TGLRnrCtx and passes it down
00045 // all render functions.
00046 
00047 ClassImp(TGLViewerBase);
00048 
00049 //______________________________________________________________________
00050 TGLViewerBase::TGLViewerBase() :
00051    fRnrCtx    (0),
00052    fCamera    (0),
00053    fClip      (0),
00054    fLOD       (TGLRnrCtx::kLODHigh),
00055    fStyle     (TGLRnrCtx::kFill),
00056    fWFLineW   (1),
00057    fOLLineW   (1),
00058 
00059    fResetSceneInfosOnRender (kFALSE),
00060    fChanged                 (kFALSE)
00061 {
00062    // Constructor.
00063 
00064    fRnrCtx = new TGLRnrCtx(this);
00065 }
00066 
00067 //______________________________________________________________________
00068 TGLViewerBase::~TGLViewerBase()
00069 {
00070    // Destructor.
00071 
00072    for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
00073    {
00074       (*i)->GetScene()->RemoveViewer(this);
00075       delete *i;
00076    }
00077 
00078    DeleteOverlayElements(TGLOverlayElement::kAll);
00079 
00080    delete fRnrCtx;
00081 }
00082 
00083 //______________________________________________________________________________
00084 const char* TGLViewerBase::LockIdStr() const
00085 {
00086    // Name to print in locking output.
00087 
00088    return "TGLViewerBase";
00089 }
00090 
00091 /**************************************************************************/
00092 // Scene & scene-info management
00093 /**************************************************************************/
00094 
00095 //______________________________________________________________________
00096 TGLViewerBase::SceneInfoList_i
00097 TGLViewerBase::FindScene(TGLSceneBase* scene)
00098 {
00099    // Find scene-info corresponding to scene.
00100 
00101    SceneInfoList_i i = fScenes.begin();
00102    while (i != fScenes.end() && (*i)->GetScene() != scene) ++i;
00103    return i;
00104 }
00105 
00106 //______________________________________________________________________
00107 TGLSceneInfo* TGLViewerBase::AddScene(TGLSceneBase* scene)
00108 {
00109    // Add new scene, appropriate scene-info is created.
00110 
00111    SceneInfoList_i i = FindScene(scene);
00112    if (i == fScenes.end()) {
00113       TGLSceneInfo* sinfo = scene->CreateSceneInfo(this);
00114       fScenes.push_back(sinfo);
00115       scene->AddViewer(this);
00116       Changed();
00117       return sinfo;
00118    } else {
00119       Warning("TGLViewerBase::AddScene", "scene '%s' already in the list.",
00120               scene->GetName());
00121       return 0;
00122    }
00123 }
00124 
00125 //______________________________________________________________________
00126 void TGLViewerBase::RemoveScene(TGLSceneBase* scene)
00127 {
00128    // Remove scene from the viewer, its scene-info is deleted.
00129 
00130    SceneInfoList_i i = FindScene(scene);
00131    if (i != fScenes.end()) {
00132       delete *i;
00133       fScenes.erase(i);
00134       scene->RemoveViewer(this);
00135       Changed();
00136    } else {
00137       Warning("TGLViewerBase::RemoveScene", "scene '%s' not found.",
00138               scene->GetName());
00139    }
00140 }
00141 
00142 //______________________________________________________________________
00143 void TGLViewerBase::RemoveAllScenes()
00144 {
00145    // Remove all scenes from the viewer, their scene-infos are deleted.
00146 
00147    for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
00148    {
00149       TGLSceneInfo * sinfo = *i;
00150       sinfo->GetScene()->RemoveViewer(this);
00151       delete sinfo;
00152    }
00153    fScenes.clear();
00154    Changed();
00155 }
00156 
00157 //______________________________________________________________________
00158 void TGLViewerBase::SceneDestructing(TGLSceneBase* scene)
00159 {
00160    // Remove scene, its scene-info is deleted.
00161    // Called from scene that is being destroyed while still holding
00162    // viewer references.
00163 
00164    SceneInfoList_i i = FindScene(scene);
00165    if (i != fScenes.end()) {
00166       delete *i;
00167       fScenes.erase(i);
00168       Changed();
00169    } else {
00170       Warning("TGLViewerBase::SceneDestructing", "scene not found.");
00171    }
00172 }
00173 
00174 //______________________________________________________________________
00175 TGLSceneInfo* TGLViewerBase::GetSceneInfo(TGLSceneBase* scene)
00176 {
00177    // Find scene-info corresponding to scene.
00178 
00179    SceneInfoList_i i = FindScene(scene);
00180    if (i != fScenes.end())
00181       return *i;
00182    else
00183       return 0;
00184 }
00185 
00186 //______________________________________________________________________________
00187 TGLLogicalShape* TGLViewerBase::FindLogicalInScenes(TObject* id)
00188 {
00189    // Find logical-shape representing object id in the list of scenes.
00190    // Return 0 if not found.
00191 
00192    for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
00193    {
00194       TGLLogicalShape *lshp = (*i)->GetScene()->FindLogical(id);
00195       if (lshp)
00196          return lshp;
00197    }
00198    return 0;
00199 }
00200 
00201 //______________________________________________________________________
00202 void TGLViewerBase::AddOverlayElement(TGLOverlayElement* el)
00203 {
00204    // Add overlay element.
00205 
00206    fOverlay.push_back(el);
00207    Changed();
00208 }
00209 
00210 //______________________________________________________________________
00211 void TGLViewerBase::RemoveOverlayElement(TGLOverlayElement* el)
00212 {
00213    // Remove overlay element.
00214 
00215    OverlayElmVec_i it = std::find(fOverlay.begin(), fOverlay.end(), el);
00216    if (it != fOverlay.end())
00217       fOverlay.erase(it);
00218    Changed();
00219 }
00220 
00221 //______________________________________________________________________
00222 void TGLViewerBase::DeleteOverlayAnnotations()
00223 {
00224    // Delete overlay elements that are annotations.
00225 
00226    DeleteOverlayElements(TGLOverlayElement::kAnnotation);
00227 }
00228 
00229 //______________________________________________________________________
00230 void TGLViewerBase::DeleteOverlayElements(TGLOverlayElement::ERole role)
00231 {
00232    // Delete overlay elements.
00233 
00234    OverlayElmVec_t ovl;
00235    fOverlay.swap(ovl);
00236 
00237    for (OverlayElmVec_i i = ovl.begin(); i != ovl.end(); ++i)
00238    {
00239       if (role == TGLOverlayElement::kAll || (*i)->GetRole() == role)
00240          delete *i;
00241       else
00242          fOverlay.push_back(*i);
00243    }
00244 
00245    Changed();
00246 }
00247 
00248 /**************************************************************************/
00249 // SceneInfo update / check
00250 /**************************************************************************/
00251 
00252 //______________________________________________________________________________
00253 void TGLViewerBase::ResetSceneInfos()
00254 {
00255    // Force rebuild of view-dependent scene-info structures.
00256    //
00257    // This should be called before calling render (draw/select) if
00258    // something that affects camera interest has been changed.
00259 
00260    SceneInfoList_i i = fScenes.begin();
00261    while (i != fScenes.end())
00262    {
00263       (*i)->ResetSceneStamp();
00264       ++i;
00265    }
00266 }
00267 
00268 //______________________________________________________________________________
00269 void TGLViewerBase::MergeSceneBBoxes(TGLBoundingBox& bbox)
00270 {
00271    // Merge bounding-boxes of all active registered scenes.
00272 
00273    bbox.SetEmpty();
00274    for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
00275    {
00276       TGLSceneInfo * sinfo = *i;
00277       if (sinfo->GetActive())
00278       {
00279          sinfo->SetupTransformsAndBBox(); // !!! transform not done yet, no camera
00280          bbox.MergeAligned(sinfo->GetTransformedBBox());
00281       }
00282    }
00283 }
00284 
00285 /**************************************************************************/
00286 // Rendering / selection virtuals
00287 /**************************************************************************/
00288 
00289 //______________________________________________________________________________
00290 void TGLViewerBase::SetupClipObject()
00291 {
00292    // Setup clip-object. Protected virtual method.
00293 
00294    if (fClip)
00295    {
00296       fClip->Setup(fOverallBoundingBox);
00297    }
00298 }
00299 
00300 //______________________________________________________________________
00301 void TGLViewerBase::PreRender()
00302 {
00303    // Initialize render-context, setup camera, GL, render-area.
00304    // Check and lock scenes, determine their visibility.
00305 
00306    TGLContextIdentity* cid = TGLContextIdentity::GetCurrent();
00307    if (cid == 0)
00308    {
00309       // Assume derived class set it up for us.
00310       // This happens due to complex implementation
00311       // of gl-in-pad using gGLManager.
00312       // In principle we should throw an exception:
00313       // throw std::runtime_error("Can not resolve GL context.");
00314    }
00315    else
00316    {
00317       if (cid != fRnrCtx->GetGLCtxIdentity())
00318       {
00319          if (fRnrCtx->GetGLCtxIdentity() != 0)
00320             Warning("TGLViewerBase::PreRender", "Switching to another GL context; maybe you should use context-sharing.");
00321          fRnrCtx->SetGLCtxIdentity(cid);
00322       }
00323    }
00324 
00325    fRnrCtx->SetCamera        (fCamera);
00326    fRnrCtx->SetViewerLOD     (fLOD);
00327    fRnrCtx->SetViewerStyle   (fStyle);
00328    fRnrCtx->SetViewerWFLineW (fWFLineW);
00329    fRnrCtx->SetViewerOLLineW (fOLLineW);
00330    fRnrCtx->SetViewerClip    (fClip);
00331 
00332    if (fResetSceneInfosOnRender)
00333    {
00334       ResetSceneInfos();
00335       fResetSceneInfosOnRender = kFALSE;
00336    }
00337 
00338    fOverallBoundingBox.SetEmpty();
00339    SceneInfoList_t locked_scenes;
00340    for (SceneInfoList_i i=fScenes.begin(); i!=fScenes.end(); ++i)
00341    {
00342       TGLSceneInfo *sinfo = *i;
00343       TGLSceneBase *scene = sinfo->GetScene();
00344       if (sinfo->GetActive())
00345       {
00346          if ( ! fRnrCtx->Selection() || scene->GetSelectable())
00347          {
00348             if ( ! sinfo->GetScene()->TakeLock(kDrawLock))
00349             {
00350                Warning("TGLViewerBase::PreRender", "locking of scene '%s' failed, skipping.",
00351                        sinfo->GetScene()->GetName());
00352                continue;
00353             }
00354             locked_scenes.push_back(sinfo);
00355          }
00356          sinfo->SetupTransformsAndBBox(); // !!! transform not done yet
00357          fOverallBoundingBox.MergeAligned(sinfo->GetTransformedBBox());
00358       }
00359    }
00360 
00361    fCamera->Apply(fOverallBoundingBox, fRnrCtx->GetPickRectangle());
00362    SetupClipObject();
00363 
00364    // Make precursory selection of visible scenes.
00365    // Only scene bounding-box .vs. camera frustum check performed.
00366    fVisScenes.clear();
00367    for (SceneInfoList_i i=locked_scenes.begin(); i!=locked_scenes.end(); ++i)
00368    {
00369       TGLSceneInfo         * sinfo = *i;
00370       const TGLBoundingBox & bbox  = sinfo->GetTransformedBBox();
00371       Bool_t visp = (!bbox.IsEmpty() && fCamera->FrustumOverlap(bbox) != kOutside);
00372       sinfo->ViewCheck(visp);
00373       if (visp) {
00374          fRnrCtx->SetSceneInfo(sinfo);
00375          sinfo->GetScene()->PreDraw(*fRnrCtx);
00376          if (sinfo->IsVisible()) {
00377             fVisScenes.push_back(sinfo);
00378          } else {
00379             sinfo->GetScene()->PostDraw(*fRnrCtx);
00380             sinfo->GetScene()->ReleaseLock(kDrawLock);
00381          }
00382          fRnrCtx->SetSceneInfo(0);
00383       } else {
00384          sinfo->GetScene()->ReleaseLock(kDrawLock);
00385       }
00386    }
00387 }
00388 
00389 //______________________________________________________________________________
00390 void TGLViewerBase::SubRenderScenes(SubRender_foo render_foo)
00391 {
00392    // Call sub-rendering function render_foo on all currently visible
00393    // scenes.
00394 
00395    Int_t nScenes = fVisScenes.size();
00396 
00397    for (Int_t i = 0; i < nScenes; ++i)
00398    {
00399       TGLSceneInfo* sinfo = fVisScenes[i];
00400       TGLSceneBase* scene = sinfo->GetScene();
00401       fRnrCtx->SetSceneInfo(sinfo);
00402       glPushName(i);
00403       scene->PreRender(*fRnrCtx);
00404       (scene->*render_foo)(*fRnrCtx);
00405       scene->PostRender(*fRnrCtx);
00406       glPopName();
00407       fRnrCtx->SetSceneInfo(0);
00408    }
00409 }
00410 
00411 //______________________________________________________________________
00412 void TGLViewerBase::Render()
00413 {
00414    // Render all scenes. This is done in four passes:
00415    // - render opaque objects from all scenes
00416    // - render transparent objects from all scenes
00417    // - clear depth buffer
00418    // - render opaque selected objects from all scenes (with highlight)
00419    // - render transparent selected objects from all scenes (with highlight)
00420 
00421    RenderNonSelected();
00422    glClear(GL_DEPTH_BUFFER_BIT);
00423    RenderSelected();
00424 }
00425 
00426 //______________________________________________________________________
00427 void TGLViewerBase::RenderNonSelected()
00428 {
00429    // Render non-selected objects from all scenes.
00430 
00431    SubRenderScenes(&TGLSceneBase::RenderOpaque);
00432 
00433    TGLCapabilityEnabler blend(GL_BLEND, kTRUE);
00434    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00435    glDepthMask(GL_FALSE);
00436 
00437    SubRenderScenes(&TGLSceneBase::RenderTransp);
00438 
00439    glDepthMask(GL_TRUE);
00440 
00441    TGLUtil::CheckError("TGLViewerBase::RenderNonSelected - pre exit check");
00442 }
00443 
00444 //______________________________________________________________________
00445 void TGLViewerBase::RenderSelected()
00446 {
00447    // Render selected objects from all scenes.
00448 
00449    SubRenderScenes(&TGLSceneBase::RenderSelOpaque);
00450 
00451    TGLCapabilityEnabler blend(GL_BLEND, kTRUE);
00452    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00453    glDepthMask(GL_FALSE);
00454 
00455    SubRenderScenes(&TGLSceneBase::RenderSelTransp);
00456 
00457    glDepthMask(GL_TRUE);
00458 
00459    TGLUtil::CheckError("TGLViewerBase::RenderSelected - pre exit check");
00460 }
00461 
00462 //______________________________________________________________________
00463 void TGLViewerBase::RenderOverlay(Int_t state, Bool_t selection)
00464 {
00465    // Render overlay objects.
00466 
00467    Int_t nOvl = fOverlay.size();
00468    for (Int_t i = 0; i < nOvl; ++i)
00469    {
00470       TGLOverlayElement* el = fOverlay[i];
00471       if (el->GetState() & state)
00472       {
00473          if (selection) glPushName(i);
00474          el->Render(*fRnrCtx);
00475          if (selection) glPopName();
00476       }
00477    }
00478 }
00479 
00480 //______________________________________________________________________
00481 void TGLViewerBase::PostRender()
00482 {
00483    // Function called after rendering is finished.
00484    // Here we just unlock the scenes.
00485 
00486    for (SceneInfoVec_i i = fVisScenes.begin(); i != fVisScenes.end(); ++i)
00487    {
00488       TGLSceneInfo* sinfo = *i;
00489       fRnrCtx->SetSceneInfo(sinfo);
00490       sinfo->GetScene()->PostDraw(*fRnrCtx);
00491       fRnrCtx->SetSceneInfo(0);
00492       sinfo->GetScene()->ReleaseLock(kDrawLock);
00493    }
00494    fChanged = kFALSE;
00495 }
00496 
00497 //______________________________________________________________________
00498 void TGLViewerBase::PreRenderOverlaySelection()
00499 {
00500    // Perform minimal initialization for overlay selection.
00501    // Here we assume that scene has already been drawn and that
00502    // camera and overall bounding box are ok.
00503    // Scenes are not locked.
00504 
00505    fCamera->Apply(fOverallBoundingBox, fRnrCtx->GetPickRectangle());
00506 }
00507 
00508 //______________________________________________________________________
00509 void TGLViewerBase::PostRenderOverlaySelection()
00510 {
00511    // Perform cleanup after overlay selection.
00512 
00513 }
00514 
00515 /**************************************************************************/
00516 // High-level functions: drawing and picking.
00517 /**************************************************************************/
00518 
00519 
00520 //______________________________________________________________________
00521 //void TGLViewerBase::Select(Int_t selX, Int_t selY, Int_t selRadius)
00522 //{
00523    // Perform render-pass in selection mode.
00524    // Process the selection results.
00525    // For now only in derived classes.
00526 //}
00527 
00528 //______________________________________________________________________
00529 Bool_t TGLViewerBase::ResolveSelectRecord(TGLSelectRecord& rec, Int_t recIdx)
00530 {
00531    // Process selection record on buffer-position 'recIdx' and
00532    // fill the data into 'rec'.
00533    //
00534    // Returns TRUE if scene was demangled and an object identified.
00535    // When FALSE is returned it is still possible that scene has been
00536    // identified. Check for this if interested in scene-selection.
00537    //
00538    // The select-buffer is taken form fRnrCtx.
00539 
00540    TGLSelectBuffer* sb = fRnrCtx->GetSelectBuffer();
00541    if (recIdx >= sb->GetNRecords())
00542        return kFALSE;
00543 
00544    sb->SelectRecord(rec, recIdx);
00545    UInt_t sceneIdx = rec.GetItem(0);
00546    if (sceneIdx >= fVisScenes.size())
00547        return kFALSE;
00548 
00549    TGLSceneInfo* sinfo = fVisScenes[sceneIdx];
00550    rec.SetSceneInfo(sinfo);
00551    return sinfo->GetScene()->ResolveSelectRecord(rec, 1);
00552 }
00553 
00554 //______________________________________________________________________
00555 Bool_t TGLViewerBase::FindClosestRecord(TGLSelectRecord& rec, Int_t& recIdx)
00556 {
00557    // Find next select record that can be resolved, starting from
00558    // position 'recIdx'.
00559    // 'recIdx' is passed as reference and points to found record in the buffer.
00560 
00561    TGLSelectBuffer* sb = fRnrCtx->GetSelectBuffer();
00562 
00563    while (recIdx < sb->GetNRecords())
00564    {
00565       if (ResolveSelectRecord(rec, recIdx))
00566          return kTRUE;
00567       ++recIdx;
00568    }
00569    return kFALSE;
00570 }
00571 
00572 //______________________________________________________________________
00573 Bool_t TGLViewerBase::FindClosestOpaqueRecord(TGLSelectRecord& rec, Int_t& recIdx)
00574 {
00575    // Find next select record that can be resolved and whose result is
00576    // not transparent, starting from position 'recIdx'.
00577    // 'recIdx' is passed as reference and points to found record in the buffer.
00578 
00579    TGLSelectBuffer* sb = fRnrCtx->GetSelectBuffer();
00580 
00581    while (recIdx < sb->GetNRecords())
00582    {
00583       if (ResolveSelectRecord(rec, recIdx) && ! rec.GetTransparent())
00584          return kTRUE;
00585       ++recIdx;
00586    }
00587    return kFALSE;
00588 }
00589 
00590 //______________________________________________________________________
00591 Bool_t TGLViewerBase::FindClosestOverlayRecord(TGLOvlSelectRecord& rec,
00592                                                Int_t             & recIdx)
00593 {
00594    // Find next overlay-select record that can be resolved, starting from
00595    // position 'recIdx'.
00596    // 'recIdx' is passed as reference and points to found record in the buffer.
00597 
00598    TGLSelectBuffer* sb = fRnrCtx->GetSelectBuffer();
00599 
00600    while (recIdx < sb->GetNRecords())
00601    {
00602       sb->SelectRecord(rec, recIdx);
00603       if (rec.GetItem(0) < fOverlay.size())
00604       {
00605          rec.SetOvlElement(fOverlay[rec.GetItem(0)]);
00606          rec.NextPos();
00607          return kTRUE;
00608       }
00609       ++recIdx;
00610    }
00611    return kFALSE;
00612 }

Generated on Tue Jul 5 14:18:09 2011 for ROOT_528-00b_version by  doxygen 1.5.1