TGLLogicalShape.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLLogicalShape.cxx 36884 2010-11-23 17:52:08Z matevz $
00002 // Author:  Richard Maunder  25/05/2005
00003 
00004 #include "TGLLogicalShape.h"
00005 #include "TGLPhysicalShape.h"
00006 #include "TGLRnrCtx.h"
00007 #include "TGLScene.h"
00008 #include "TGLCamera.h"
00009 #include "TGLSelectRecord.h"
00010 #include "TGLContext.h"
00011 #include "TGLIncludes.h"
00012 
00013 #include "TBuffer3D.h"
00014 #include "TClass.h"
00015 #include "TContextMenu.h"
00016 
00017 
00018 //==============================================================================
00019 // TGLLogicalShape
00020 //==============================================================================
00021 
00022 //______________________________________________________________________________
00023 //
00024 // Abstract logical shape - a GL 'drawable' - base for all shapes -
00025 // faceset sphere etc. Logical shapes are a unique piece of geometry,
00026 // described in it's local frame - e.g if we have three spheres in :
00027 // Sphere A - Radius r1, center v1
00028 // Sphere B - Radius r2, center v2
00029 // Sphere C - Radius r1, center v3
00030 //
00031 // Spheres A and C can share a common logical sphere of radius r1 - and
00032 // place them with two physicals with translations of v1 & v2.  Sphere B
00033 // requires a different logical (radius r2), placed with physical with
00034 // translation v2.
00035 //
00036 // Physical shapes know about and can share logicals. Logicals do not
00037 // about (aside from reference counting) physicals or share them.
00038 //
00039 // This sharing of logical shapes greatly reduces memory consumption and
00040 // scene (re)build times in typical detector geometries which have many
00041 // repeated objects placements.
00042 //
00043 // TGLLogicalShapes have reference counting, performed by the client
00044 // physical shapes which are using it.
00045 //
00046 // Display list information is also stored here, possibly per LOD
00047 // level. Most classes does not support LOD (only sphere and tube) and
00048 // therefore reasonable defaults are encoded in the following virtual
00049 // functions:
00050 //
00051 // * ELODAxes SupportedLODAxes()  { return kLODAxesNone; }
00052 // * Int_t    DLCacheSize()       { return 1; }
00053 // * UInt_t   DLOffset(lod);      // Transform lod into DL offset.
00054 // * Short_t  QuantizeShapeLOD(); // Quantize lod.
00055 //
00056 // Classes that have per-LOD display-lists than override these functions.
00057 // 'UShort_t fDLValid' is used as a bit-field determining validity of
00058 // each quantized LOD-level; hopefully one will not have more than 16
00059 // LOD levels per class.
00060 // See also: TGLPhysicalShape::CalculateShapeLOD() where LOD is calculated.
00061 //
00062 // See base/src/TVirtualViewer3D for description of common external 3D
00063 // viewer architecture and how external viewer clients use it.
00064 //
00065 
00066 ClassImp(TGLLogicalShape);
00067 
00068 //______________________________________________________________________________
00069 TGLLogicalShape::TGLLogicalShape() :
00070    fRef           (0),
00071    fFirstPhysical (0),
00072    fExternalObj   (0),
00073    fScene         (0),
00074    fDLBase        (0),
00075    fDLSize        (1),
00076    fDLValid       (0),
00077    fDLCache       (kTRUE),
00078    fRefStrong     (kFALSE),
00079    fOwnExtObj     (kFALSE)
00080 {
00081    // Constructor.
00082 }
00083 
00084 //______________________________________________________________________________
00085 TGLLogicalShape::TGLLogicalShape(TObject* obj) :
00086    fRef           (0),
00087    fFirstPhysical (0),
00088    fExternalObj   (obj),
00089    fScene         (0),
00090    fDLBase        (0),
00091    fDLSize        (1),
00092    fDLValid       (0),
00093    fDLCache       (kTRUE),
00094    fRefStrong     (kFALSE),
00095    fOwnExtObj     (kFALSE)
00096 {
00097    // Constructor with external object.
00098 }
00099 
00100 //______________________________________________________________________________
00101 TGLLogicalShape::TGLLogicalShape(const TBuffer3D & buffer) :
00102    fRef           (0),
00103    fFirstPhysical (0),
00104    fExternalObj   (buffer.fID),
00105    fScene         (0),
00106    fDLBase        (0),
00107    fDLSize        (1),
00108    fDLValid       (0),
00109    fDLCache       (kTRUE),
00110    fRefStrong     (kFALSE),
00111    fOwnExtObj     (kFALSE)
00112 {
00113    // Constructor from TBuffer3D.
00114 
00115    // Use the bounding box in buffer if valid
00116    if (buffer.SectionsValid(TBuffer3D::kBoundingBox)) {
00117       fBoundingBox.Set(buffer.fBBVertex);
00118    } else if (buffer.SectionsValid(TBuffer3D::kRaw)) {
00119    // otherwise use the raw points to generate one
00120       fBoundingBox.SetAligned(buffer.NbPnts(), buffer.fPnts);
00121    }
00122 
00123    // If the logical is created without an external object reference,
00124    // we create a generic  here and delete it during the destruction.
00125    if (fExternalObj == 0)
00126    {
00127       fExternalObj = new TNamed("Generic object", "Internal object created for bookkeeping.");
00128       fOwnExtObj = kTRUE;
00129    }
00130 }
00131 
00132 //______________________________________________________________________________
00133 TGLLogicalShape::~TGLLogicalShape()
00134 {
00135    // Destroy logical shape.
00136 
00137    // Physicals should have been cleared elsewhere as they are managed
00138    // by the scene. But this could change.
00139    if (fRef > 0) {
00140       Warning("TGLLogicalShape::~TGLLogicalShape", "some physicals still lurking around.");
00141       DestroyPhysicals();
00142    }
00143    DLCachePurge();
00144    if (fOwnExtObj)
00145    {
00146       delete fExternalObj;
00147    }
00148 }
00149 
00150 
00151 /**************************************************************************/
00152 // Physical shape ref-counting, replica management
00153 /**************************************************************************/
00154 
00155 //______________________________________________________________________________
00156 void TGLLogicalShape::AddRef(TGLPhysicalShape* phys) const
00157 {
00158    // Add reference to given physical shape.
00159 
00160    phys->fNextPhysical = fFirstPhysical;
00161    fFirstPhysical = phys;
00162    ++fRef;
00163 }
00164 
00165 //______________________________________________________________________________
00166 void TGLLogicalShape::SubRef(TGLPhysicalShape* phys) const
00167 {
00168    // Remove reference to given physical shape, potentially deleting
00169    // *this* object when hitting zero ref-count (if fRefStrong is
00170    // true).
00171 
00172    assert(phys != 0);
00173 
00174    Bool_t found = kFALSE;
00175    if (fFirstPhysical == phys) {
00176       fFirstPhysical = phys->fNextPhysical;
00177       found = kTRUE;
00178    } else {
00179       TGLPhysicalShape *shp1 = fFirstPhysical, *shp2;
00180       while ((shp2 = shp1->fNextPhysical) != 0) {
00181          if (shp2 == phys) {
00182             shp1->fNextPhysical = shp2->fNextPhysical;
00183             found = kTRUE;
00184             break;
00185          }
00186          shp1 = shp2;
00187       }
00188    }
00189    if (found == kFALSE) {
00190       Error("TGLLogicalShape::SubRef", "Attempt to un-ref an unregistered physical.");
00191       return;
00192    }
00193 
00194    if (--fRef == 0 && fRefStrong)
00195       delete this;
00196 }
00197 
00198 //______________________________________________________________________________
00199 void TGLLogicalShape::DestroyPhysicals()
00200 {
00201    // Destroy all physicals attached to this logical.
00202 
00203    TGLPhysicalShape *curr = fFirstPhysical, *next;
00204    while (curr)
00205    {
00206       next = curr->fNextPhysical;
00207       curr->fLogicalShape = 0;
00208       --fRef;
00209       delete curr;
00210       curr = next;
00211    }
00212    assert (fRef == 0);
00213    fFirstPhysical = 0;
00214 }
00215 
00216 //______________________________________________________________________________
00217 UInt_t TGLLogicalShape::UnrefFirstPhysical()
00218 {
00219    // Unreference first physical in the list, returning its id and
00220    // making it fit for destruction somewhere else.
00221    // Returns 0 if there are no replicas attached.
00222 
00223    if (fFirstPhysical == 0) return 0;
00224 
00225    TGLPhysicalShape *phys = fFirstPhysical;
00226    UInt_t            phid = phys->ID();
00227    fFirstPhysical = phys->fNextPhysical;
00228    phys->fLogicalShape = 0;
00229    --fRef;
00230    return phid;
00231 }
00232 
00233 
00234 /**************************************************************************/
00235 // Bounding-boxes
00236 /**************************************************************************/
00237 
00238 //______________________________________________________________________________
00239 void TGLLogicalShape::UpdateBoundingBoxesOfPhysicals()
00240 {
00241    // Update bounding-boxed of all dependent physicals.
00242 
00243    TGLPhysicalShape* pshp = fFirstPhysical;
00244    while (pshp)
00245    {
00246       pshp->UpdateBoundingBox();
00247       pshp = pshp->fNextPhysical;
00248    }
00249 }
00250 
00251 
00252 /**************************************************************************/
00253 // Display-list cache
00254 /**************************************************************************/
00255 
00256 //______________________________________________________________________________
00257 Bool_t TGLLogicalShape::SetDLCache(Bool_t cache)
00258 {
00259    // Modify capture of draws into display list cache kTRUE - capture,
00260    // kFALSE direct draw. Return kTRUE is state changed, kFALSE if not.
00261 
00262    if (cache == fDLCache)
00263       return kFALSE;
00264 
00265    if (fDLCache)
00266       DLCachePurge();
00267    fDLCache = cache;
00268    return kTRUE;
00269 }
00270 
00271 //______________________________________________________________________________
00272 Bool_t TGLLogicalShape::ShouldDLCache(const TGLRnrCtx& rnrCtx) const
00273 {
00274    // Returns kTRUE if draws should be display list cached
00275    // kFALSE otherwise.
00276    //
00277    // Here we check that:
00278    // a) fScene is set (Scene manages link to GL-context);
00279    // b) secondary selection is not in progress as different
00280    //    render-path is usually taken in this case.
00281    //
00282    // Otherwise we return internal bool.
00283    //
00284    // Override this in sub-class if different behaviour is required.
00285 
00286    if (!fDLCache || !fScene   ||
00287        (rnrCtx.SecSelection() && SupportsSecondarySelect()))
00288    {
00289       return kFALSE;
00290    }
00291    return kTRUE;
00292 }
00293 
00294 //______________________________________________________________________________
00295 void TGLLogicalShape::DLCacheClear()
00296 {
00297    // Clear all entries for all LODs for this drawable from the
00298    // display list cache but keeping the reserved ids from GL context.
00299 
00300    fDLValid = 0;
00301 }
00302 
00303 //______________________________________________________________________________
00304 void TGLLogicalShape::DLCacheDrop()
00305 {
00306    // Drop all entries for all LODs for this drawable from the display
00307    // list cache, WITHOUT returning the reserved ids to GL context.
00308    //
00309    // This is called by scene if it realized that the GL context was
00310    // destroyed.
00311 
00312    fDLBase  = 0;
00313    fDLValid = 0;
00314 }
00315 
00316 //______________________________________________________________________________
00317 void TGLLogicalShape::DLCachePurge()
00318 {
00319    // Purge all entries for all LODs for this drawable from the
00320    // display list cache, returning the reserved ids to GL context.
00321    //
00322    // If you override this function:
00323    // 1. call the base-class version from it;
00324    // 2. call it from the destructor of the derived class!
00325 
00326    if (fDLBase != 0)
00327    {
00328       PurgeDLRange(fDLBase, fDLSize);
00329       fDLBase  = 0;
00330       fDLValid = 0;
00331    }
00332 }
00333 
00334 //______________________________________________________________________________
00335 void TGLLogicalShape::PurgeDLRange(UInt_t base, Int_t size) const
00336 {
00337    // Purge given display-list range.
00338    // Utility function.
00339 
00340    if (fScene)
00341    {
00342       fScene->GetGLCtxIdentity()->RegisterDLNameRangeToWipe(base, size);
00343    }
00344    else
00345    {
00346       Warning("TGLLogicalShape::PurgeDLRange", "Scene unknown, attempting direct deletion.");
00347       glDeleteLists(base, size);
00348    }
00349 }
00350 
00351 //______________________________________________________________________________
00352 Short_t TGLLogicalShape::QuantizeShapeLOD(Short_t shapeLOD,
00353                                           Short_t /*combiLOD*/) const
00354 {
00355    // Logical shapes usually support only discreet LOD values,
00356    // especially in view of display-list caching.
00357    // This function should be overriden to perform the desired quantization.
00358    // See TGLSphere.
00359 
00360    return shapeLOD;
00361 }
00362 
00363 //______________________________________________________________________________
00364 void TGLLogicalShape::Draw(TGLRnrCtx& rnrCtx) const
00365 {
00366    // Draw the GL drawable, using draw flags. If DL caching is enabled
00367    // (see SetDLCache) then attempt to draw from the cache, if not found
00368    // attempt to capture the draw - done by DirectDraw() - into a new cache entry.
00369    // If not cached just call DirectDraw() for normal non DL cached drawing.
00370 
00371    // Debug tracing
00372    if (gDebug > 4) {
00373       Info("TGLLogicalShape::Draw", "this %ld (class %s) LOD %d", (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD());
00374    }
00375 
00376 entry_point:
00377    // If shape is not cached, or a capture to cache is already in
00378    // progress perform a direct draw DL can be nested, but not created
00379    // in nested fashion. As we only build DL on draw demands have to
00380    // protected against this here.
00381    // MT: I can't see how this could happen right now ... with
00382    // rendering from a flat drawable-list.
00383 
00384    if (!ShouldDLCache(rnrCtx) || rnrCtx.IsDLCaptureOpen())
00385    {
00386       DirectDraw(rnrCtx);
00387       return;
00388    }
00389 
00390    if (fDLBase == 0)
00391    {
00392       fDLBase = glGenLists(fDLSize);
00393       if (fDLBase == 0)
00394       {
00395          Warning("TGLLogicalShape::Draw", "display-list registration failed.");
00396          fDLCache = kFALSE;
00397          goto entry_point;
00398       }
00399    }
00400 
00401    Short_t lod = rnrCtx.ShapeLOD();
00402    UInt_t  off = DLOffset(lod);
00403    if ((1<<off) & fDLValid)
00404    {
00405       glCallList(fDLBase + off);
00406    }
00407    else
00408    {
00409       rnrCtx.OpenDLCapture();
00410       glNewList(fDLBase + off, GL_COMPILE_AND_EXECUTE);
00411       DirectDraw(rnrCtx);
00412       glEndList();
00413       rnrCtx.CloseDLCapture();
00414       fDLValid |= (1<<off);
00415    }
00416 }
00417 
00418 //______________________________________________________________________________
00419 void TGLLogicalShape::DrawHighlight(TGLRnrCtx& rnrCtx, const TGLPhysicalShape* pshp, Int_t lvl) const
00420 {
00421    // Draw the logical shape in highlight mode.
00422    // If lvl argument is less than 0 (-1 by default), the index into color-set
00423    // is taken from the physical shape itself.
00424 
00425    const TGLRect& vp = rnrCtx.RefCamera().RefViewport();
00426    Int_t inner[4][2] = { { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0} };
00427    Int_t outer[8][2] = { {-1,-1}, { 1,-1}, { 1, 1}, {-1, 1},
00428                          { 0,-2}, { 2, 0}, { 0, 2}, {-2, 0} };
00429 
00430    if (lvl < 0) lvl = pshp->GetSelected();
00431 
00432    rnrCtx.SetHighlightOutline(kTRUE);
00433    TGLUtil::LockColor();
00434    Int_t first_outer = (rnrCtx.CombiLOD() == TGLRnrCtx::kLODHigh) ? 0 : 4;
00435    for (int i = first_outer; i < 8; ++i)
00436    {
00437       glViewport(vp.X() + outer[i][0], vp.Y() + outer[i][1], vp.Width(), vp.Height());
00438       glColor4ubv(rnrCtx.ColorSet().Selection(lvl).CArr());
00439       Draw(rnrCtx);
00440    }
00441    TGLUtil::UnlockColor();
00442    rnrCtx.SetHighlightOutline(kFALSE);
00443 
00444    pshp->SetupGLColors(rnrCtx);
00445    for (int i = 0; i < 4; ++i)
00446    {
00447       glViewport(vp.X() + inner[i][0], vp.Y() + inner[i][1], vp.Width(), vp.Height());
00448       glColor4fv(pshp->Color());
00449       Draw(rnrCtx);
00450    }
00451    glViewport(vp.X(), vp.Y(), vp.Width(), vp.Height());
00452 
00453    pshp->SetupGLColors(rnrCtx);
00454    Float_t dr[2];
00455    glGetFloatv(GL_DEPTH_RANGE,dr);
00456    glDepthRange(dr[0], 0.5*dr[1]);
00457    Draw(rnrCtx);
00458    glDepthRange(dr[0], dr[1]);
00459 }
00460 
00461 //______________________________________________________________________________
00462 void TGLLogicalShape::ProcessSelection(TGLRnrCtx& /*rnrCtx*/, TGLSelectRecord& rec)
00463 {
00464    // Virtual method called-back after a secondary selection hit
00465    // is recorded (see TGLViewer::HandleButton(), Ctrl-Button1).
00466    // The ptr argument holds the GL pick-record of the closest hit.
00467    //
00468    // This base-class implementation simply prints out the result.
00469 
00470    printf("TGLLogicalShape::ProcessSelection %d names on the stack (z1=%g, z2=%g).\n",
00471           rec.GetN(), rec.GetMinZ(), rec.GetMaxZ());
00472    printf("  Names: ");
00473    for (Int_t j=0; j<rec.GetN(); ++j) printf ("%u ", rec.GetItem(j));
00474    printf("\n");
00475 }
00476 
00477 //______________________________________________________________________________
00478 void TGLLogicalShape::InvokeContextMenu(TContextMenu& menu, UInt_t x, UInt_t y) const
00479 {
00480    // Invoke popup menu or our bound external TObject (if any), using passed
00481    // 'menu' object, at location 'x' 'y'
00482    if (fExternalObj) {
00483       menu.Popup(x, y, fExternalObj);
00484    }
00485 }

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