TGLScene.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLScene.cxx 37397 2010-12-08 13:54:23Z matevz $
00002 // Author:  Matevz Tadel, Feb 2007
00003 // Author:  Richard Maunder  25/05/2005
00004 // Parts taken from original TGLRender by Timur Pocheptsov
00005 
00006 /*************************************************************************
00007  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
00008  * All rights reserved.                                                  *
00009  *                                                                       *
00010  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00011  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00012  *************************************************************************/
00013 
00014 #include "TGLScene.h"
00015 #include "TGLRnrCtx.h"
00016 #include "TGLObject.h"
00017 #include "TGLSelectRecord.h"
00018 #include "TGLLogicalShape.h"
00019 #include "TGLPhysicalShape.h"
00020 #include "TGLCamera.h"
00021 #include "TGLContext.h"
00022 #include "TGLIncludes.h"
00023 
00024 #include <TColor.h>
00025 #include <TROOT.h>
00026 #include <TClass.h>
00027 
00028 #include <algorithm>
00029 
00030 //==============================================================================
00031 // TGLScene::TSceneInfo
00032 //==============================================================================
00033 
00034 //______________________________________________________________________
00035 //
00036 // Extend TGLSceneInfo for needs of TGLScene:
00037 //
00038 // 1. DrawElement vectors for opaque/transparent shapes which cache
00039 // physicals that pass the clip tests (frustum and additional
00040 // clip-object);
00041 //
00042 // 2. Statistics / debug information
00043 //
00044 
00045 //______________________________________________________________________________
00046 TGLScene::TSceneInfo::TSceneInfo(TGLViewerBase* view, TGLScene* scene) :
00047    TGLSceneInfo (view, scene),
00048    fMinorStamp  (0),
00049    fOpaqueCnt   (0),
00050    fTranspCnt   (0),
00051    fAsPixelCnt  (0)
00052 {
00053    // Constructor.
00054 }
00055 
00056 //______________________________________________________________________________
00057 TGLScene::TSceneInfo::~TSceneInfo()
00058 {
00059    // Destructor.
00060 }
00061 
00062 //______________________________________________________________________________
00063 void TGLScene::TSceneInfo::ClearDrawElementVec(DrawElementVec_t& vec,
00064                                                Int_t maxSize)
00065 {
00066    // Clear given vec and if it grew too large compared to the size of
00067    // shape-of-interest also resize it.
00068 
00069    if (vec.capacity() > (size_t) maxSize) {
00070       DrawElementVec_t foo;
00071       foo.reserve((size_t) maxSize);
00072       vec.swap(foo);
00073    } else {
00074       vec.clear();
00075    }
00076 }
00077 
00078 //______________________________________________________________________________
00079 void TGLScene::TSceneInfo::ClearDrawElementPtrVec(DrawElementPtrVec_t& vec,
00080                                                   Int_t maxSize)
00081 {
00082    // Clear given vec and if it grew too large compared to the size of
00083    // shape-of-interest also resize it.
00084 
00085    if (vec.capacity() > (size_t) maxSize) {
00086       DrawElementPtrVec_t foo;
00087       foo.reserve((size_t) maxSize);
00088       vec.swap(foo);
00089    } else {
00090       vec.clear();
00091    }
00092 }
00093 
00094 //______________________________________________________________________________
00095 void TGLScene::TSceneInfo::ClearAfterRebuild()
00096 {
00097    // Clear DrawElementVector fVisibleElement and optionally resize it
00098    // so that it doesn't take more space then required by all the
00099    // elements in the scene's draw-list.
00100 
00101    Int_t maxSize = (Int_t) fShapesOfInterest.size();
00102 
00103    ClearDrawElementVec(fVisibleElements, maxSize);
00104 }
00105 
00106 //______________________________________________________________________________
00107 void TGLScene::TSceneInfo::ClearAfterUpdate()
00108 {
00109    // Clear DrawElementPtrVectors and optionally resize them so that
00110    // they don't take more space then required by all the elements in
00111    // the scene's draw-list.
00112 
00113    Int_t maxSize = (Int_t) fShapesOfInterest.size();
00114 
00115    ClearDrawElementPtrVec(fOpaqueElements, maxSize);
00116    ClearDrawElementPtrVec(fTranspElements, maxSize);
00117    ClearDrawElementPtrVec(fSelOpaqueElements, maxSize);
00118    ClearDrawElementPtrVec(fSelTranspElements, maxSize);
00119 
00120    fMinorStamp = 0;
00121 }
00122 
00123 //______________________________________________________________________________
00124 void TGLScene::TSceneInfo::Lodify(TGLRnrCtx& ctx)
00125 {
00126    // Quantize LODs for gice render-context.
00127 
00128    for (DrawElementVec_i i = fVisibleElements.begin(); i != fVisibleElements.end(); ++i)
00129       i->fPhysical->QuantizeShapeLOD(i->fPixelLOD, ctx.CombiLOD(), i->fFinalLOD);
00130 }
00131 
00132 //______________________________________________________________________________
00133 void TGLScene::TSceneInfo::PreDraw()
00134 {
00135    // Prepare for drawing - fill DrawElementPtrVectors from the
00136    // contents of fVisibleElements if there was some change.
00137 
00138    if (fMinorStamp < fScene->GetMinorStamp())
00139    {
00140       fOpaqueElements.clear();
00141       fTranspElements.clear();
00142       fSelOpaqueElements.clear();
00143       fSelTranspElements.clear();
00144 
00145       for (DrawElementVec_i i = fVisibleElements.begin(); i != fVisibleElements.end(); ++i)
00146       {
00147          if (i->fPhysical->IsSelected())
00148          {
00149             if (i->fPhysical->IsTransparent())
00150                fSelTranspElements.push_back(&*i);
00151             else
00152                fSelOpaqueElements.push_back(&*i);
00153          } else {
00154             if (i->fPhysical->IsTransparent())
00155                fTranspElements.push_back(&*i);
00156             else
00157                fOpaqueElements.push_back(&*i);
00158          }
00159       }
00160       fMinorStamp = fScene->GetMinorStamp();
00161    }
00162 }
00163 
00164 //______________________________________________________________________________
00165 void TGLScene::TSceneInfo::PostDraw()
00166 {
00167    // Clean-up after drawing, nothing to be done here.
00168 }
00169 
00170 //______________________________________________________________________________
00171 void TGLScene::TSceneInfo::ResetDrawStats()
00172 {
00173    // Reset draw statistics.
00174 
00175    fOpaqueCnt  = 0;
00176    fTranspCnt  = 0;
00177    fAsPixelCnt = 0;
00178    fByShapeCnt.clear();
00179 }
00180 
00181 //______________________________________________________________________________
00182 void TGLScene::TSceneInfo::UpdateDrawStats(const TGLPhysicalShape& shape,
00183                                            Short_t lod)
00184 {
00185    // Update draw stats, for newly drawn 'shape'
00186 
00187    // Update opaque/transparent draw count
00188    if (shape.IsTransparent()) {
00189       ++fTranspCnt;
00190    } else {
00191       ++fOpaqueCnt;
00192    }
00193 
00194    if (lod == TGLRnrCtx::kLODPixel) {
00195       ++fAsPixelCnt;
00196    }
00197 
00198    // By type only done at higher debug level.
00199    if (gDebug>3) {
00200       // Update the stats
00201       TClass* logIsA = shape.GetLogical()->IsA();
00202       std::map<TClass*, UInt_t>::iterator it = fByShapeCnt.find(logIsA);
00203       if (it == fByShapeCnt.end()) {
00204          //do not need to check insert(.....).second, because it was stats.end() before
00205          it = fByShapeCnt.insert(std::make_pair(logIsA, 0u)).first;
00206       }
00207 
00208       it->second++;
00209    }
00210 }
00211 
00212 //______________________________________________________________________________
00213 void TGLScene::TSceneInfo::DumpDrawStats()
00214 {
00215    // Output draw stats to Info stream.
00216 
00217    if (gDebug>2)
00218    {
00219       TString out;
00220       // Draw/container counts
00221       out += Form("Drew scene (%s / %i LOD) - %i (Op %i Trans %i) %i pixel\n",
00222                   TGLRnrCtx::StyleName(LastStyle()), LastLOD(),
00223                   fOpaqueCnt + fTranspCnt, fOpaqueCnt, fTranspCnt, fAsPixelCnt);
00224       out += Form("\tInner phys nums: physicals=%d, of_interest=%lu, visible=%lu, op=%lu, trans=%lu",
00225                   ((TGLScene*)fScene)->GetMaxPhysicalID(),
00226                   (ULong_t)fShapesOfInterest.size(), (ULong_t)fVisibleElements.size(),
00227                   (ULong_t)fOpaqueElements.size(), (ULong_t)fTranspElements.size());
00228 
00229       // By shape type counts
00230       if (gDebug>3)
00231       {
00232          out += "\n\tStatistics by shape:\n";
00233          std::map<TClass*, UInt_t>::const_iterator it = fByShapeCnt.begin();
00234          while (it != fByShapeCnt.end()) {
00235             out += Form("\t%-20s  %u\n", it->first->GetName(), it->second);
00236             it++;
00237          }
00238       }
00239       Info("TGLScene::DumpDrawStats()", "%s",out.Data());
00240    }
00241 }
00242 
00243 
00244 //==============================================================================
00245 // TGLScene
00246 //==============================================================================
00247 
00248 //______________________________________________________________________________
00249 //
00250 // TGLScene provides managememnt and rendering of ROOT's default 3D
00251 // object representation as logical and physical shapes.
00252 //
00253 // A GL scene is the container for all the viewable objects (shapes)
00254 // loaded into the viewer. It consists of two main stl::maps containing
00255 // the TGLLogicalShape and TGLPhysicalShape collections, and interface
00256 // functions enabling viewers to manage objects in these. The physical
00257 // shapes defined the placement of copies of the logical shapes - see
00258 // TGLLogicalShape/TGLPhysicalShape for more information on relationship
00259 //
00260 // The scene can be drawn by owning viewer, passing camera, draw style
00261 // & quality (LOD), clipping etc - see Draw(). The scene can also be
00262 // drawn for selection in similar fashion - see Select(). The scene
00263 // keeps track of a single selected physical - which can be modified by
00264 // viewers.
00265 //
00266 // The scene maintains a lazy calculated bounding box for the total
00267 // scene extents, axis aligned round TGLPhysicalShape shapes.
00268 //
00269 // Currently a scene is owned exclusively by one viewer - however it is
00270 // intended that it could easily be shared by multiple viewers - for
00271 // efficiency and syncronisation reasons. Hence viewer variant objects
00272 // camera, clips etc being owned by viewer and passed at draw/select
00273 
00274 ClassImp(TGLScene);
00275 
00276 //______________________________________________________________________________
00277 TGLScene::TGLScene() :
00278    TGLSceneBase(),
00279    fGLCtxIdentity(0),
00280    fInSmartRefresh(kFALSE),
00281    fLastPointSizeScale (0),
00282    fLastLineWidthScale (0)
00283 {}
00284 
00285 //______________________________________________________________________________
00286 TGLScene::~TGLScene()
00287 {
00288    // Destroy scene objects
00289    TakeLock(kModifyLock);
00290    ReleaseGLCtxIdentity();
00291    DestroyPhysicals();
00292    DestroyLogicals();
00293    if (fGLCtxIdentity)
00294       fGLCtxIdentity->ReleaseClient();
00295    ReleaseLock(kModifyLock);
00296 }
00297 
00298 /**************************************************************************/
00299 // GLCtxIdentity
00300 /**************************************************************************/
00301 
00302 //______________________________________________________________________________
00303 void TGLScene::ReleaseGLCtxIdentity()
00304 {
00305    // Release all GL resources for current context identity.
00306    // Requires iteration over all logical shapes.
00307 
00308    if (fGLCtxIdentity == 0) return;
00309 
00310    if (fGLCtxIdentity->IsValid())
00311    {
00312       // Purge logical's DLs
00313       LogicalShapeMapIt_t lit = fLogicalShapes.begin();
00314       while (lit != fLogicalShapes.end()) {
00315          lit->second->DLCachePurge();
00316          ++lit;
00317       }
00318    }
00319    else
00320    {
00321       // Drop logical's DLs
00322       LogicalShapeMapIt_t lit = fLogicalShapes.begin();
00323       while (lit != fLogicalShapes.end()) {
00324          lit->second->DLCacheDrop();
00325          ++lit;
00326       }
00327    }
00328    fGLCtxIdentity->ReleaseClient();
00329    fGLCtxIdentity = 0;
00330 }
00331 
00332 /**************************************************************************/
00333 // SceneInfo management
00334 /**************************************************************************/
00335 
00336 
00337 //______________________________________________________________________________
00338 TGLScene::TSceneInfo* TGLScene::CreateSceneInfo(TGLViewerBase* view)
00339 {
00340    // Create a scene-info instance appropriate for this scene class.
00341    // Here we instantiate the inner class TSceneInfo that includes
00342    // camera/clipping specific draw-list containers.
00343 
00344    return new TSceneInfo(view, this);
00345 }
00346 
00347 //______________________________________________________________________________
00348 inline Bool_t TGLScene::ComparePhysicalVolumes(const TGLPhysicalShape* shape1,
00349                                                const TGLPhysicalShape* shape2)
00350 {
00351    // Compare 'shape1' and 'shape2' bounding box volumes - return kTRUE if
00352    // 'shape1' bigger than 'shape2'.
00353 
00354    return (shape1->BoundingBox().Volume() > shape2->BoundingBox().Volume());
00355 }
00356 
00357 //______________________________________________________________________________
00358 inline Bool_t TGLScene::ComparePhysicalDiagonals(const TGLPhysicalShape* shape1,
00359                                                  const TGLPhysicalShape* shape2)
00360 {
00361    // Compare 'shape1' and 'shape2' bounding box volumes - return kTRUE if
00362    // 'shape1' bigger than 'shape2'.
00363 
00364    return (shape1->BoundingBox().Diagonal() > shape2->BoundingBox().Diagonal());
00365 }
00366 
00367 //______________________________________________________________________________
00368 void TGLScene::RebuildSceneInfo(TGLRnrCtx& rnrCtx)
00369 {
00370    // Major change in scene, need to rebuild all-element draw-vector and
00371    // sort it.
00372    //
00373    // Sort the TGLPhysical draw list by shape bounding box diagonal, from
00374    // large to small. This makes dropout of shapes with time limited
00375    // Draw() calls must less noticable. As this does not use projected
00376    // size it only needs to be done after a scene content change - not
00377    // everytime scene drawn (potential camera/projection change).
00378 
00379    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00380    if (sinfo == 0 || sinfo->GetScene() != this) {
00381       Error("TGLScene::RebuildSceneInfo", "Scene mismatch.");
00382       return;
00383    }
00384 
00385    TGLSceneBase::RebuildSceneInfo(rnrCtx);
00386 
00387    if (sinfo->fShapesOfInterest.capacity() > fPhysicalShapes.size()) {
00388       ShapeVec_t foo;
00389       foo.reserve(fPhysicalShapes.size());
00390       sinfo->fShapesOfInterest.swap(foo);
00391    } else {
00392       sinfo->fShapesOfInterest.clear();
00393    }
00394 
00395    PhysicalShapeMapIt_t pit = fPhysicalShapes.begin();
00396    while (pit != fPhysicalShapes.end())
00397    {
00398       TGLPhysicalShape      * pshp = pit->second;
00399       const TGLLogicalShape * lshp = pshp->GetLogical();
00400       if (rnrCtx.GetCamera()->OfInterest(pshp->BoundingBox(),
00401                                          lshp->IgnoreSizeForOfInterest()))
00402       {
00403          sinfo->fShapesOfInterest.push_back(pshp);
00404       }
00405       ++pit;
00406    }
00407 
00408    std::sort(sinfo->fShapesOfInterest.begin(), sinfo->fShapesOfInterest.end(),
00409              TGLScene::ComparePhysicalDiagonals);
00410 
00411    sinfo->ClearAfterRebuild();
00412 }
00413 
00414 //______________________________________________________________________________
00415 void TGLScene::UpdateSceneInfo(TGLRnrCtx& rnrCtx)
00416 {
00417    // Fill scene-info with information needed for rendering, take into
00418    // account the render-context (viewer state, camera, clipping).
00419    // Here we have to iterate over all the physical shapes and select
00420    // the visible ones. While at it, opaque and transparent shapes are
00421    // divided into two groups.
00422 
00423    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00424    if (sinfo == 0 || sinfo->GetScene() != this) {
00425       Error("TGLScene::UpdateSceneInfo", "Scene mismatch.");
00426       return;
00427    }
00428 
00429    // Clean-up/reset, update of transformation matrices and clipping
00430    // planes done in base-class.
00431    TGLSceneBase::UpdateSceneInfo(rnrCtx);
00432 
00433    if (!sinfo->IsVisible())
00434       return;
00435 
00436    sinfo->fVisibleElements.clear();
00437 
00438    // Check individual physicals, build DrawElementList.
00439 
00440    Int_t  checkCount = 0;
00441    Bool_t timerp     = rnrCtx.IsStopwatchRunning();
00442    sinfo->ResetUpdateTimeouted();
00443 
00444    for (ShapeVec_i phys=sinfo->fShapesOfInterest.begin();
00445         phys!=sinfo->fShapesOfInterest.end();
00446         ++phys, ++checkCount)
00447    {
00448       const TGLPhysicalShape * drawShape = *phys;
00449 
00450       // TODO: Do small skipping first? Probably cheaper than frustum check
00451       // Profile relative costs? The frustum check could be done implictly
00452       // from the LOD as we project all 8 verticies of the BB onto viewport
00453 
00454       // Work out if we need to draw this shape - assume we do first
00455       Bool_t drawNeeded = kTRUE;
00456 
00457       // Draw test against passed clipping planes.
00458       // Do before camera clipping on assumption clip planes remove
00459       // more objects.
00460       if (sinfo->ClipMode() == TGLSceneInfo::kClipOutside)
00461       {
00462          // Draw not needed if outside any of the planes.
00463          std::vector<TGLPlane>::iterator pi = sinfo->ClipPlanes().begin();
00464          while (pi != sinfo->ClipPlanes().end())
00465          {
00466             if (drawShape->BoundingBox().Overlap(*pi) == kOutside)
00467             {
00468                drawNeeded = kFALSE;
00469                break;
00470             }
00471             ++pi;
00472          }
00473       }
00474       else if (sinfo->ClipMode() == TGLSceneInfo::kClipInside)
00475       {
00476          // Draw not needed if inside all the planes.
00477          std::vector<TGLPlane>::iterator pi = sinfo->ClipPlanes().begin();
00478          size_t cnt = 0;
00479          while (pi != sinfo->ClipPlanes().end())
00480          {
00481             EOverlap ovlp = drawShape->BoundingBox().Overlap(*pi);
00482             if (ovlp == kOutside)
00483                break;
00484             else if (ovlp == kInside)
00485                ++cnt;
00486             ++pi;
00487          }
00488          if (cnt == sinfo->ClipPlanes().size())
00489             drawNeeded = kFALSE;
00490       }
00491 
00492       // Test against camera frustum planes (here mode is Outside
00493       // implicitly).
00494       if (drawNeeded)
00495       {
00496          std::vector<TGLPlane>::iterator pi = sinfo->FrustumPlanes().begin();
00497          while (pi != sinfo->FrustumPlanes().end())
00498          {
00499             if (drawShape->BoundingBox().Overlap(*pi) == kOutside)
00500             {
00501                drawNeeded = kFALSE;
00502                break;
00503             }
00504             ++pi;
00505          }
00506       }
00507 
00508       // Draw? Then calculate lod and store ...
00509       if (drawNeeded)
00510       {
00511          DrawElement_t de(drawShape);
00512          drawShape->CalculateShapeLOD(rnrCtx, de.fPixelSize, de.fPixelLOD);
00513          sinfo->fVisibleElements.push_back(de);
00514       }
00515 
00516       // Terminate the traversal if over scene rendering limit.
00517       // Only test every 5000 objects as this is somewhat costly.
00518       if (timerp && (checkCount % 5000) == 0 && rnrCtx.HasStopwatchTimedOut())
00519       {
00520          sinfo->UpdateTimeouted();
00521          if (rnrCtx.ViewerLOD() == TGLRnrCtx::kLODHigh)
00522             Warning("TGLScene::UpdateSceneInfo",
00523                     "Timeout reached, not all elements processed.");
00524          break;
00525       }
00526    }
00527 
00528    sinfo->ClearAfterUpdate();
00529 
00530    // !!! MT Transparents should be sorted by their eye z-coordinate.
00531    // Need combined matrices in scene-info to do this.
00532    // Even more ... should z-sort contributions from ALL scenes!
00533 }
00534 
00535 //______________________________________________________________________________
00536 void TGLScene::LodifySceneInfo(TGLRnrCtx& rnrCtx)
00537 {
00538    // Setup LOD-dependant values in scene-info.
00539    // We have to perform LOD quantization for all draw-elements.
00540 
00541    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00542    if (sinfo == 0 || sinfo->GetScene() != this) {
00543       Error("TGLScene::LodifySceneInfo", "Scene mismatch.");
00544       return;
00545    }
00546 
00547    TGLSceneBase::LodifySceneInfo(rnrCtx);
00548 
00549    sinfo->Lodify(rnrCtx);
00550 }
00551 
00552 
00553 /**************************************************************************/
00554 // Rendering
00555 /**************************************************************************/
00556 
00557 //______________________________________________________________________________
00558 void TGLScene::PreDraw(TGLRnrCtx& rnrCtx)
00559 {
00560    // Initialize rendering.
00561    // Pass to base-class where most work is done.
00562    // Check if GL-ctx is shared with the previous one; if not
00563    // wipe display-lists of all logicals.
00564 
00565    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00566    if (sinfo == 0 || sinfo->GetScene() != this) {
00567       TGLSceneInfo* si = rnrCtx.GetSceneInfo();
00568       Error("TGLScene::PreDraw", "%s", Form("SceneInfo mismatch (0x%lx, '%s').",
00569                                       (ULong_t)si, si ? si->IsA()->GetName() : "<>"));
00570       return;
00571    }
00572 
00573    // Setup ctx, check if Update/Lodify needed.
00574    TGLSceneBase::PreDraw(rnrCtx);
00575 
00576    TGLContextIdentity* cid = rnrCtx.GetGLCtxIdentity();
00577    if (cid != fGLCtxIdentity)
00578    {
00579       ReleaseGLCtxIdentity();
00580       fGLCtxIdentity = cid;
00581       fGLCtxIdentity->AddClientRef();
00582    }
00583    else
00584    {
00585       if (fLastPointSizeScale != TGLUtil::GetPointSizeScale() ||
00586           fLastLineWidthScale != TGLUtil::GetLineWidthScale())
00587       {
00588          // Clear logical's DLs
00589          LogicalShapeMapIt_t lit = fLogicalShapes.begin();
00590          while (lit != fLogicalShapes.end()) {
00591             lit->second->DLCacheClear();
00592             ++lit;
00593          }
00594       }
00595    }
00596    fLastPointSizeScale = TGLUtil::GetPointSizeScale();
00597    fLastLineWidthScale = TGLUtil::GetLineWidthScale();
00598 
00599    sinfo->PreDraw();
00600 
00601    // Reset-scene-info counters.
00602    sinfo->ResetDrawStats();
00603 }
00604 
00605 //______________________________________________________________________________
00606 void TGLScene::RenderOpaque(TGLRnrCtx& rnrCtx)
00607 {
00608    // Render opaque elements.
00609 
00610    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00611    if (!sinfo->fOpaqueElements.empty())
00612        RenderAllPasses(rnrCtx, sinfo->fOpaqueElements, kTRUE);
00613 }
00614 
00615 //______________________________________________________________________________
00616 void TGLScene::RenderTransp(TGLRnrCtx& rnrCtx)
00617 {
00618    // Render transparent elements.
00619 
00620    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00621    if (!sinfo->fTranspElements.empty())
00622        RenderAllPasses(rnrCtx, sinfo->fTranspElements, kTRUE);
00623 }
00624 
00625 //______________________________________________________________________________
00626 void TGLScene::RenderSelOpaque(TGLRnrCtx& rnrCtx)
00627 {
00628    // Render selected opaque elements.
00629 
00630    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00631    if (!sinfo->fSelOpaqueElements.empty())
00632        RenderAllPasses(rnrCtx, sinfo->fSelOpaqueElements, kFALSE);
00633 }
00634 
00635 //______________________________________________________________________________
00636 void TGLScene::RenderSelTransp(TGLRnrCtx& rnrCtx)
00637 {
00638    // Render selected transparent elements.
00639 
00640    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00641    if (!sinfo->fSelTranspElements.empty())
00642        RenderAllPasses(rnrCtx, sinfo->fSelTranspElements, kFALSE);
00643 }
00644 
00645 //______________________________________________________________________________
00646 void TGLScene::PostDraw(TGLRnrCtx& rnrCtx)
00647 {
00648    // Called after the rendering is finished.
00649    // In debug mode draw statistcs is dumped.
00650    // Parent's PostDraw is called for GL cleanup.
00651 
00652    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00653 
00654    if (gDebug)
00655       sinfo->DumpDrawStats();
00656 
00657    sinfo->PostDraw();
00658 
00659    TGLSceneBase::PostDraw(rnrCtx);
00660 }
00661 
00662 //______________________________________________________________________________
00663 void TGLScene::RenderAllPasses(TGLRnrCtx&           rnrCtx,
00664                                DrawElementPtrVec_t& elVec,
00665                                Bool_t               check_timeout)
00666 {
00667    // Do full rendering of scene.
00668    //
00669    // First draw the opaques, then the transparents. For each we do
00670    // the number of passes required by draw mode and clipping setup.
00671 
00672    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00673    assert(sinfo != 0);
00674 
00675    Short_t sceneStyle = rnrCtx.SceneStyle();
00676 
00677    // Setup GL for current draw style - fill, wireframe, outline
00678    Int_t        reqPasses  = 1; // default
00679 
00680    Short_t      rnrPass[2];
00681    rnrPass[0] = rnrPass[1] = TGLRnrCtx::kPassUndef;
00682 
00683    switch (sceneStyle)
00684    {
00685       case TGLRnrCtx::kFill:
00686       case TGLRnrCtx::kOutline:
00687       {
00688          glEnable(GL_LIGHTING);
00689          if (sinfo->ShouldClip()) {
00690             // Clip object - two sided lighting, two side polygons, don't cull (BACK) faces
00691             glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00692             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00693             glDisable(GL_CULL_FACE);
00694          }
00695          // No clip - default single side lighting,
00696          // front polygons, cull (BACK) faces ok
00697          if (sceneStyle == TGLRnrCtx::kOutline) {
00698             reqPasses = 2;   // Outline needs two full draws
00699             rnrPass[0] = TGLRnrCtx::kPassOutlineFill;
00700             rnrPass[1] = TGLRnrCtx::kPassOutlineLine;
00701          } else {
00702             rnrPass[0] = TGLRnrCtx::kPassFill;
00703          }
00704          break;
00705       }
00706       case TGLRnrCtx::kWireFrame:
00707       {
00708          rnrPass[0] = TGLRnrCtx::kPassWireFrame;
00709          glDisable(GL_LIGHTING);
00710          glDisable(GL_CULL_FACE);
00711          glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00712          break;
00713       }
00714       default:
00715       {
00716          assert(kFALSE);
00717       }
00718    }
00719 
00720    for (Int_t i = 0; i < reqPasses; ++i)
00721    {
00722       // For outline two full draws (fill + wireframe) required.
00723       // Do it this way to avoid costly GL state swaps on per drawable basis
00724 
00725       Short_t pass = rnrPass[i];
00726       rnrCtx.SetDrawPass(pass);
00727 
00728       if (pass == TGLRnrCtx::kPassOutlineFill)
00729       {
00730          // First pass - filled polygons
00731          glEnable(GL_POLYGON_OFFSET_FILL);
00732          glPolygonOffset(0.5f, 0.5f);
00733       }
00734       else if (pass == TGLRnrCtx::kPassOutlineLine)
00735       {
00736          // Second pass - outline (wireframe)
00737          TGLUtil::LineWidth(rnrCtx.SceneOLLineW());
00738          glDisable(GL_POLYGON_OFFSET_FILL);
00739          glDisable(GL_LIGHTING);
00740 
00741          // We are only showing back faces with clipping as a
00742          // better solution than completely invisible faces.
00743          // *Could* cull back faces and only outline on front like this:
00744          //    glEnable(GL_CULL_FACE);
00745          //    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00746          // However this means clipped back edges not shown - so do inside and out....
00747          glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00748       }
00749       else if (pass == TGLRnrCtx::kPassWireFrame)
00750       {
00751          TGLUtil::LineWidth(rnrCtx.SceneWFLineW());
00752       }
00753 
00754       // If no clip object no plane sets to extract/pass
00755       if ( ! sinfo->ShouldClip())
00756       {
00757          RenderElements(rnrCtx, elVec, check_timeout);
00758       }
00759       else
00760       {
00761          // Get the clip plane set from the clipping object
00762          TGLPlaneSet_t & planeSet = sinfo->ClipPlanes();
00763 
00764          if (gDebug > 3)
00765          {
00766             Info("TGLScene::RenderAllPasses()",
00767                  "%ld active clip planes", (Long_t)planeSet.size());
00768          }
00769          // Limit to smaller of plane set size or GL implementation plane support
00770          Int_t maxGLPlanes;
00771          glGetIntegerv(GL_MAX_CLIP_PLANES, &maxGLPlanes);
00772          UInt_t maxPlanes = maxGLPlanes;
00773          UInt_t planeInd;
00774          if (planeSet.size() < maxPlanes) {
00775             maxPlanes = planeSet.size();
00776          }
00777 
00778          if (sinfo->ClipMode() == TGLSceneInfo::kClipOutside)
00779          {
00780             // Clip away scene outside of the clip object.
00781             // Load all clip planes (up to max) at once.
00782             for (UInt_t ii=0; ii<maxPlanes; ii++) {
00783                glClipPlane(GL_CLIP_PLANE0+ii, planeSet[ii].CArr());
00784                glEnable(GL_CLIP_PLANE0+ii);
00785             }
00786 
00787             // Draw scene once with full time slot, physicals have been
00788             // clipped during UpdateSceneInfo, so no need to repeat that.
00789             RenderElements(rnrCtx, elVec, check_timeout);
00790          }
00791          else
00792          {
00793             // Clip away scene inside of the clip object.
00794             // This requires number-of-clip-planes passes and can not
00795             // be entirely pre-computed (non-relevant planes are removed).
00796             std::vector<TGLPlane> activePlanes;
00797             for (planeInd=0; planeInd<maxPlanes; planeInd++)
00798             {
00799                activePlanes.push_back(planeSet[planeInd]);
00800                TGLPlane& p = activePlanes.back();
00801                p.Negate();
00802                glClipPlane(GL_CLIP_PLANE0+planeInd, p.CArr());
00803                glEnable(GL_CLIP_PLANE0+planeInd);
00804 
00805                // Draw scene with active planes, allocating fraction of time
00806                // for total planes.
00807                RenderElements(rnrCtx, elVec, check_timeout, &activePlanes);
00808 
00809                p.Negate();
00810                glClipPlane(GL_CLIP_PLANE0+planeInd, p.CArr());
00811             }
00812          }
00813          // Ensure all clip planes turned off again
00814          for (planeInd=0; planeInd<maxPlanes; planeInd++) {
00815             glDisable(GL_CLIP_PLANE0+planeInd);
00816          }
00817       }
00818    } // end for reqPasses
00819 
00820    // Reset gl modes to defaults
00821    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
00822    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00823    glEnable(GL_CULL_FACE);
00824    glEnable(GL_LIGHTING);
00825 }
00826 
00827 //______________________________________________________________________________
00828 void TGLScene::RenderElements(TGLRnrCtx&           rnrCtx,
00829                               DrawElementPtrVec_t& elVec,
00830                               Bool_t               check_timeout,
00831                               const TGLPlaneSet_t* clipPlanes)
00832 {
00833    // Render DrawElements in elementVec with given timeout.
00834    // If clipPlanes is non-zero, test each element against its
00835    // clipping planes.
00836 
00837    TSceneInfo* sinfo = dynamic_cast<TSceneInfo*>(rnrCtx.GetSceneInfo());
00838    assert(sinfo != 0);
00839 
00840    Int_t drawCount = 0;
00841 
00842    for (DrawElementPtrVec_i i = elVec.begin(); i != elVec.end(); ++i)
00843    {
00844       const TGLPhysicalShape * drawShape = (*i)->fPhysical;
00845 
00846       Bool_t drawNeeded = kTRUE;
00847 
00848       // If clipping planes are passed as argument, we test against them.
00849       if (clipPlanes && IsOutside(drawShape->BoundingBox(), *clipPlanes))
00850          drawNeeded = kFALSE;
00851 
00852       // Draw?
00853       if (drawNeeded)
00854       {
00855          rnrCtx.SetShapeLOD((*i)->fFinalLOD);
00856          rnrCtx.SetShapePixSize((*i)->fPixelSize);
00857          glPushName(drawShape->ID());
00858          drawShape->Draw(rnrCtx);
00859          glPopName();
00860          ++drawCount;
00861          sinfo->UpdateDrawStats(*drawShape, rnrCtx.ShapeLOD());
00862       }
00863 
00864       // Terminate the draw if over opaque fraction timeout.
00865       // Only test every 2000 objects as this is somewhat costly.
00866       if (check_timeout && (drawCount % 2000) == 0 &&
00867           rnrCtx.HasStopwatchTimedOut())
00868       {
00869          if (rnrCtx.ViewerLOD() == TGLRnrCtx::kLODHigh)
00870              Warning("TGLScene::RenderElements",
00871                      "Timeout reached, not all elements rendered.");
00872          break;
00873       }
00874    }
00875 }
00876 
00877 
00878 /**************************************************************************/
00879 // Selection
00880 /**************************************************************************/
00881 
00882 //______________________________________________________________________________
00883 Bool_t TGLScene::ResolveSelectRecord(TGLSelectRecord& rec, Int_t curIdx)
00884 {
00885    // Process selection record rec.
00886    // 'curIdx' is the item position where the scene should start
00887    // its processing.
00888    // Return TRUE if an object has been identified or FALSE otherwise.
00889    // The scene-info member of the record is already set by the caller.
00890 
00891    if (curIdx >= rec.GetN())
00892       return kFALSE;
00893 
00894    TGLPhysicalShape* pshp = FindPhysical(rec.GetItem(curIdx));
00895    if (pshp)
00896    {
00897       rec.SetTransparent(pshp->IsTransparent());
00898       rec.SetPhysShape(pshp);
00899       rec.SetObject(pshp->GetLogical()->GetExternal());
00900       rec.SetSpecific(0);
00901       return kTRUE;
00902    }
00903    return kFALSE;
00904 }
00905 
00906 
00907 /**************************************************************************/
00908 // Bounding-box
00909 /**************************************************************************/
00910 
00911 //______________________________________________________________________________
00912 void TGLScene::CalcBoundingBox() const
00913 {
00914    // Encapsulates all physical shapes bounding box with axes aligned box.
00915    // Validity checked in the base-class.
00916 
00917    Double_t xMin, xMax, yMin, yMax, zMin, zMax;
00918    xMin = xMax = yMin = yMax = zMin = zMax = 0.0;
00919    PhysicalShapeMapCIt_t physicalShapeIt = fPhysicalShapes.begin();
00920    const TGLPhysicalShape * physicalShape;
00921    while (physicalShapeIt != fPhysicalShapes.end())
00922    {
00923       physicalShape = physicalShapeIt->second;
00924       if (!physicalShape)
00925       {
00926          assert(kFALSE);
00927          continue;
00928       }
00929       const TGLBoundingBox& box = physicalShape->BoundingBox();
00930       if (physicalShapeIt == fPhysicalShapes.begin()) {
00931          xMin = box.XMin(); xMax = box.XMax();
00932          yMin = box.YMin(); yMax = box.YMax();
00933          zMin = box.ZMin(); zMax = box.ZMax();
00934       } else {
00935          if (box.XMin() < xMin) { xMin = box.XMin(); }
00936          if (box.XMax() > xMax) { xMax = box.XMax(); }
00937          if (box.YMin() < yMin) { yMin = box.YMin(); }
00938          if (box.YMax() > yMax) { yMax = box.YMax(); }
00939          if (box.ZMin() < zMin) { zMin = box.ZMin(); }
00940          if (box.ZMax() > zMax) { zMax = box.ZMax(); }
00941       }
00942       ++physicalShapeIt;
00943    }
00944    fBoundingBox.SetAligned(TGLVertex3(xMin,yMin,zMin), TGLVertex3(xMax,yMax,zMax));
00945    fBoundingBoxValid = kTRUE;
00946 }
00947 
00948 /**************************************************************************/
00949 // Logical shapes
00950 /**************************************************************************/
00951 
00952 //______________________________________________________________________________
00953 void TGLScene::AdoptLogical(TGLLogicalShape& shape)
00954 {
00955    // Adopt dynamically created logical 'shape' - add to internal map
00956    // and take responsibility for deleting.
00957 
00958    if (fLock != kModifyLock) {
00959       Error("TGLScene::AdoptLogical", "expected ModifyLock");
00960       return;
00961    }
00962 
00963    shape.fScene = this;
00964    fLogicalShapes.insert(LogicalShapeMapValueType_t(shape.ID(), &shape));
00965 }
00966 
00967 //______________________________________________________________________________
00968 Bool_t TGLScene::DestroyLogical(TObject* logid, Bool_t mustFind)
00969 {
00970    // Destroy logical shape defined by unique 'ID'.
00971    // Returns kTRUE if found/destroyed - kFALSE otherwise.
00972    //
00973    // If mustFind is true, an error is reported if the logical is not
00974    // found.
00975 
00976    if (fLock != kModifyLock) {
00977       Error("TGLScene::DestroyLogical", "expected ModifyLock");
00978       return kFALSE;
00979    }
00980 
00981    LogicalShapeMapIt_t lit = fLogicalShapes.find(logid);
00982 
00983    if (lit == fLogicalShapes.end()) {
00984       if (mustFind)
00985          Error("TGLScene::DestroyLogical", "logical not found in map.");
00986       return kFALSE;
00987    }
00988 
00989    TGLLogicalShape * logical = lit->second;
00990    UInt_t phid;
00991    while ((phid = logical->UnrefFirstPhysical()) != 0)
00992    {
00993       PhysicalShapeMapIt_t pit = fPhysicalShapes.find(phid);
00994       if (pit != fPhysicalShapes.end())
00995          DestroyPhysicalInternal(pit);
00996       else
00997          Warning("TGLScene::DestroyLogical", "an attached physical not found in map.");
00998    }
00999    assert(logical->Ref() == 0);
01000    fLogicalShapes.erase(lit);
01001    delete logical;
01002    InvalidateBoundingBox();
01003    IncTimeStamp();
01004    return kTRUE;
01005 }
01006 
01007 //______________________________________________________________________________
01008 Int_t TGLScene::DestroyLogicals()
01009 {
01010    // Destroy all logical shapes in scene.
01011    // Return number of destroyed logicals.
01012 
01013    if (fLock != kModifyLock) {
01014       Error("TGLScene::DestroyLogicals", "expected ModifyLock");
01015       return 0;
01016    }
01017 
01018    Int_t count = 0;
01019    LogicalShapeMapIt_t logicalShapeIt = fLogicalShapes.begin();
01020    const TGLLogicalShape * logicalShape;
01021    while (logicalShapeIt != fLogicalShapes.end()) {
01022       logicalShape = logicalShapeIt->second;
01023       if (logicalShape) {
01024          if (logicalShape->Ref() == 0) {
01025             fLogicalShapes.erase(logicalShapeIt++);
01026             delete logicalShape;
01027             ++count;
01028             continue;
01029          } else {
01030             assert(kFALSE);
01031          }
01032       } else {
01033          assert(kFALSE);
01034       }
01035       ++logicalShapeIt;
01036    }
01037 
01038    return count;
01039 }
01040 
01041 //______________________________________________________________________________
01042 TGLLogicalShape * TGLScene::FindLogical(TObject* logid) const
01043 {
01044    // Find and return logical shape identified by unqiue logid.
01045    // Returns 0 if not found.
01046 
01047    LogicalShapeMapCIt_t lit = fLogicalShapes.find(logid);
01048    if (lit != fLogicalShapes.end()) {
01049       return lit->second;
01050    } else {
01051       if (fInSmartRefresh)
01052          return FindLogicalSmartRefresh(logid);
01053       else
01054          return 0;
01055    }
01056 }
01057 
01058 
01059 /**************************************************************************/
01060 // Physical shapes
01061 /**************************************************************************/
01062 
01063 //______________________________________________________________________________
01064 void TGLScene::AdoptPhysical(TGLPhysicalShape & shape)
01065 {
01066    // Adopt dynamically created physical 'shape' - add to internal map and take
01067    // responsibility for deleting
01068    if (fLock != kModifyLock) {
01069       Error("TGLScene::AdoptPhysical", "expected ModifyLock");
01070       return;
01071    }
01072    // TODO: Very inefficient check - disable
01073    assert(fPhysicalShapes.find(shape.ID()) == fPhysicalShapes.end());
01074 
01075    fPhysicalShapes.insert(PhysicalShapeMapValueType_t(shape.ID(), &shape));
01076 
01077    InvalidateBoundingBox();
01078    IncTimeStamp();
01079 }
01080 
01081 //______________________________________________________________________________
01082 void TGLScene::DestroyPhysicalInternal(PhysicalShapeMapIt_t pit)
01083 {
01084    // Virtual function to destroy a physical. Sub-classes might have
01085    // special checks to perform.
01086    // Caller should also invalidate the draw-list.
01087 
01088    delete pit->second;
01089    fPhysicalShapes.erase(pit);
01090 }
01091 
01092 //______________________________________________________________________________
01093 Bool_t TGLScene::DestroyPhysical(UInt_t phid)
01094 {
01095    // Destroy physical shape defined by unique 'ID'.
01096    // Returns kTRUE if found/destroyed - kFALSE otherwise.
01097 
01098    if (fLock != kModifyLock) {
01099       Error("TGLScene::DestroyPhysical", "expected ModifyLock.");
01100       return kFALSE;
01101    }
01102 
01103    PhysicalShapeMapIt_t pit = fPhysicalShapes.find(phid);
01104 
01105    if (pit == fPhysicalShapes.end()) {
01106       Error("TGLScene::DestroyPhysical::UpdatePhysical", "physical not found.");
01107       return kFALSE;
01108    }
01109 
01110    DestroyPhysicalInternal(pit);
01111 
01112    InvalidateBoundingBox();
01113 
01114    return kTRUE;
01115 }
01116 
01117 //______________________________________________________________________________
01118 Int_t TGLScene::DestroyPhysicals()
01119 {
01120    // Destroy physical shapes.
01121 
01122    if (fLock != kModifyLock) {
01123       Error("TGLScene::DestroyPhysicals", "expected ModifyLock");
01124       return 0;
01125    }
01126 
01127    // Loop over logicals -- it is much more efficient that way.
01128 
01129    UInt_t count = 0;
01130 
01131    LogicalShapeMapIt_t lit = fLogicalShapes.begin();
01132    while (lit != fLogicalShapes.end())
01133    {
01134       TGLLogicalShape *lshp = lit->second;
01135       if (lshp && lshp->Ref() != 0)
01136       {
01137          count += lshp->Ref();
01138          lshp->DestroyPhysicals();
01139       }
01140       ++lit;
01141    }
01142 
01143    assert (count == fPhysicalShapes.size());
01144    fPhysicalShapes.clear();
01145 
01146    if (count > 0) {
01147       InvalidateBoundingBox();
01148       IncTimeStamp();
01149    }
01150 
01151    return count;
01152 }
01153 
01154 //______________________________________________________________________________
01155 TGLPhysicalShape* TGLScene::FindPhysical(UInt_t phid) const
01156 {
01157    // Find and return physical shape identified by unqiue 'ID'.
01158    // Returns 0 if not found.
01159 
01160    PhysicalShapeMapCIt_t pit = fPhysicalShapes.find(phid);
01161    return (pit != fPhysicalShapes.end()) ? pit->second : 0;
01162 }
01163 
01164 //______________________________________________________________________________
01165 UInt_t TGLScene::GetMaxPhysicalID()
01166 {
01167    // Returns the maximum used physical id.
01168    // Returns 0 if empty.
01169 
01170    if (fPhysicalShapes.empty()) return 0;
01171    return (--fPhysicalShapes.end())->first;
01172 }
01173 
01174 
01175 /**************************************************************************/
01176 // Update methods
01177 /**************************************************************************/
01178 
01179 //______________________________________________________________________________
01180 Bool_t TGLScene::BeginUpdate()
01181 {
01182    // Put scene in update mode, return true if lock acquired.
01183 
01184    Bool_t ok = TakeLock(kModifyLock);
01185    return ok;
01186 }
01187 
01188 //______________________________________________________________________________
01189 void TGLScene::EndUpdate(Bool_t minorChange, Bool_t sceneChanged, Bool_t updateViewers)
01190 {
01191    // Exit scene update mode.
01192    //
01193    // If sceneChanged is true (default), the scene timestamp is
01194    // increased and basic draw-lists etc will be rebuild on next draw
01195    // request. If you only changed colors or some other visual
01196    // parameters that do not affect object bounding-box or
01197    // transformation matrix, you can set it to false.
01198    //
01199    // If updateViewers is true (default), the viewers using this scene
01200    // will be tagged as changed. If sceneChanged is true the
01201    // updateViewers should be true as well, unless you take care of
01202    // the viewers elsewhere or in some other way.
01203 
01204    if (minorChange)
01205       IncMinorStamp();
01206 
01207    if (sceneChanged)
01208       IncTimeStamp();
01209 
01210    ReleaseLock(kModifyLock);
01211 
01212    if (updateViewers)
01213       TagViewersChanged();
01214 }
01215 
01216 //______________________________________________________________________________
01217 void TGLScene::UpdateLogical(TObject* logid)
01218 {
01219    // Drop display-lists for the logical (assume TGLObject/direct rendering).
01220    // Re-calculate the bounding box (also for all physicals).
01221 
01222    if (fLock != kModifyLock) {
01223       Error("TGLScene::UpdateLogical", "expected ModifyLock");
01224       return;
01225    }
01226 
01227    TGLLogicalShape* log = FindLogical(logid);
01228 
01229    if (log == 0) {
01230       Error("TGLScene::UpdateLogical", "logical not found");
01231       return;
01232    }
01233 
01234    log->DLCacheClear();
01235    log->UpdateBoundingBox();
01236 }
01237 
01238 //______________________________________________________________________________
01239 void TGLScene::UpdatePhysical(UInt_t phid, Double_t* trans, UChar_t* col)
01240 {
01241    // Reposition/recolor physical shape.
01242 
01243    if (fLock != kModifyLock) {
01244       Error("TGLScene::UpdatePhysical", "expected ModifyLock");
01245       return;
01246    }
01247 
01248    TGLPhysicalShape* phys = FindPhysical(phid);
01249 
01250    if (phys == 0) {
01251       Error("TGLScene::UpdatePhysical", "physical not found");
01252       return;
01253    }
01254 
01255    if (trans)  phys->SetTransform(trans);
01256    if (col)    phys->SetDiffuseColor(col);
01257 }
01258 
01259 //______________________________________________________________________________
01260 void TGLScene::UpdatePhysical(UInt_t phid, Double_t* trans, Color_t cidx, UChar_t transp)
01261 {
01262    // Reposition/recolor physical shape.
01263 
01264    if (fLock != kModifyLock) {
01265       Error("TGLScene::UpdatePhysical", "expected ModifyLock");
01266       return;
01267    }
01268 
01269    TGLPhysicalShape* phys = FindPhysical(phid);
01270 
01271    if (phys == 0) {
01272       Error("TGLScene::UpdatePhysical", "physical not found");
01273       return;
01274    }
01275 
01276    if (trans)
01277       phys->SetTransform(trans);
01278    if (cidx >= 0) {
01279       Float_t rgba[4];
01280       RGBAFromColorIdx(rgba, cidx, transp);
01281       phys->SetDiffuseColor(rgba);
01282    }
01283 }
01284 
01285 //______________________________________________________________________________
01286 void TGLScene::UpdatePhysioLogical(TObject* logid, Double_t* trans, UChar_t* col)
01287 {
01288    // Reposition/recolor physical for given logical (assume TGLObject and
01289    // a single physical).
01290 
01291    if (fLock != kModifyLock) {
01292       Error("TGLScene::UpdatePhysioLogical", "expected ModifyLock");
01293       return;
01294    }
01295 
01296    TGLLogicalShape* log = FindLogical(logid);
01297 
01298    if (log == 0) {
01299       Error("TGLScene::UpdatePhysioLogical", "logical not found");
01300       return;
01301    }
01302 
01303    if (log->Ref() != 1) {
01304       Warning("TGLScene::UpdatePhysioLogical", "expecting a single physical (%d).", log->Ref());
01305    }
01306 
01307    TGLPhysicalShape* phys = log->fFirstPhysical;
01308    if (trans)  phys->SetTransform(trans);
01309    if (col)    phys->SetDiffuseColor(col);
01310 }
01311 
01312 //______________________________________________________________________________
01313 void TGLScene::UpdatePhysioLogical(TObject* logid, Double_t* trans, Color_t cidx, UChar_t transp)
01314 {
01315    // Reposition/recolor physical for given logical (assume TGLObject and
01316    // a single physical).
01317 
01318    if (fLock != kModifyLock) {
01319       Error("TGLScene::UpdatePhysioLogical", "expected ModifyLock");
01320       return;
01321    }
01322 
01323    TGLLogicalShape* log = FindLogical(logid);
01324 
01325    if (log == 0) {
01326       Error("TGLScene::UpdatePhysioLogical", "logical not found");
01327       return;
01328    }
01329 
01330    if (log->Ref() != 1) {
01331       Warning("TGLScene::UpdatePhysioLogical", "expecting a single physical (%d).", log->Ref());
01332    }
01333 
01334    TGLPhysicalShape* phys = log->fFirstPhysical;
01335    if (trans)
01336       phys->SetTransform(trans);
01337    if (cidx >= 0) {
01338       Float_t rgba[4];
01339       RGBAFromColorIdx(rgba, cidx, transp);
01340       phys->SetDiffuseColor(rgba);
01341    }
01342 }
01343 
01344 
01345 /**************************************************************************/
01346 // Smart refresh
01347 /**************************************************************************/
01348 
01349 //______________________________________________________________________________
01350 UInt_t TGLScene::BeginSmartRefresh()
01351 {
01352    // Moves logicals that support smart-refresh to intermediate cache.
01353    // Destroys the others and returns the number of destroyed ones.
01354 
01355    fSmartRefreshCache.swap(fLogicalShapes);
01356    // Remove all logicals that don't survive a refresh.
01357    UInt_t count = 0;
01358    LogicalShapeMapIt_t i = fSmartRefreshCache.begin();
01359    while (i != fSmartRefreshCache.end()) {
01360       if (i->second->KeepDuringSmartRefresh() == kFALSE) {
01361          LogicalShapeMapIt_t j = i++;
01362          delete j->second;
01363          fSmartRefreshCache.erase(j);
01364          ++count;
01365       } else {
01366          ++i;
01367       }
01368    }
01369    fInSmartRefresh = kTRUE;
01370    return count;
01371 }
01372 
01373 //______________________________________________________________________________
01374 void TGLScene::EndSmartRefresh()
01375 {
01376    // Wipes logicals in refresh-cache.
01377 
01378    fInSmartRefresh = kFALSE;
01379 
01380    LogicalShapeMapIt_t i = fSmartRefreshCache.begin();
01381    while (i != fSmartRefreshCache.end()) {
01382       delete i->second;
01383       ++i;
01384    }
01385    fSmartRefreshCache.clear();
01386 }
01387 
01388 //______________________________________________________________________________
01389 TGLLogicalShape * TGLScene::FindLogicalSmartRefresh(TObject* ID) const
01390 {
01391    // Find and return logical shape identified by unqiue 'ID' in refresh-cache.
01392    // Returns 0 if not found.
01393 
01394    LogicalShapeMapIt_t it = fSmartRefreshCache.find(ID);
01395    if (it != fSmartRefreshCache.end())
01396    {
01397       TGLLogicalShape* l_shape = it->second;
01398       fSmartRefreshCache.erase(it);
01399       if (l_shape->IsA() != TGLObject::GetGLRenderer(ID->IsA()))
01400       {
01401          Warning("TGLScene::FindLogicalSmartRefresh", "Wrong renderer-type found in cache.");
01402          delete l_shape;
01403          return 0;
01404       }
01405       // printf("TGLScene::SmartRefresh found cached: %p '%s' [%s] for %p\n",
01406       //    l_shape, l_shape->GetExternal()->GetName(),
01407       //    l_shape->GetExternal()->IsA()->GetName(), (void*) ID);
01408       LogicalShapeMap_t* lsm = const_cast<LogicalShapeMap_t*>(&fLogicalShapes);
01409       lsm->insert(LogicalShapeMapValueType_t(l_shape->ID(), l_shape));
01410       l_shape->DLCacheClear();
01411       l_shape->UpdateBoundingBox();
01412       return l_shape;
01413    } else {
01414       return 0;
01415    }
01416 }
01417 
01418 
01419 /**************************************************************************/
01420 // Helpers
01421 /**************************************************************************/
01422 
01423 //______________________________________________________________________________
01424 UInt_t TGLScene::SizeOfScene() const
01425 {
01426    // Return memory cost of scene.
01427    // Warning: NOT CORRECT at present - doesn't correctly calculate size.
01428    // of logical shapes with dynamic internal contents.
01429 
01430    UInt_t size = sizeof(*this);
01431 
01432    printf("Size: Scene Only %u\n", size);
01433 
01434    LogicalShapeMapCIt_t logicalShapeIt = fLogicalShapes.begin();
01435    const TGLLogicalShape * logicalShape;
01436    while (logicalShapeIt != fLogicalShapes.end()) {
01437       logicalShape = logicalShapeIt->second;
01438       size += sizeof(*logicalShape);
01439       ++logicalShapeIt;
01440    }
01441 
01442    printf("Size: Scene + Logical Shapes %u\n", size);
01443 
01444    PhysicalShapeMapCIt_t physicalShapeIt = fPhysicalShapes.begin();
01445    const TGLPhysicalShape * physicalShape;
01446    while (physicalShapeIt != fPhysicalShapes.end()) {
01447       physicalShape = physicalShapeIt->second;
01448       size += sizeof(*physicalShape);
01449       ++physicalShapeIt;
01450    }
01451 
01452    printf("Size: Scene + Logical Shapes + Physical Shapes %u\n", size);
01453 
01454    return size;
01455 }
01456 
01457 //______________________________________________________________________________
01458 void TGLScene::DumpMapSizes() const
01459 {
01460    // Print sizes of logical nad physical-shape maps.
01461 
01462    printf("Scene: %u Logicals / %u Physicals\n",
01463           (UInt_t) fLogicalShapes.size(), (UInt_t) fPhysicalShapes.size());
01464 }
01465 
01466 //______________________________________________________________________________
01467 void TGLScene::RGBAFromColorIdx(Float_t rgba[4], Color_t ci, Char_t transp)
01468 {
01469    // Fill rgba color from ROOT color-index ci and transparency (0->100).
01470 
01471    TColor* c = gROOT->GetColor(ci);
01472    if(c)   c->GetRGB(rgba[0], rgba[1], rgba[2]);
01473    else    rgba[0] = rgba[1] = rgba[2] = 0.5;
01474    rgba[3] = 1.0f - transp/100.0f;
01475 }
01476 
01477 //______________________________________________________________________________
01478 Bool_t TGLScene::IsOutside(const TGLBoundingBox & box,
01479                            const TGLPlaneSet_t  & planes)
01480 {
01481    // Check if box is outside of all planes.
01482 
01483    for (TGLPlaneSet_ci p=planes.begin(); p!=planes.end(); ++p)
01484       if (box.Overlap(*p) == kOutside)
01485          return kTRUE;
01486    return kFALSE;
01487 }

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