TGLPhysicalShape.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLPhysicalShape.cxx 34245 2010-06-30 13:36:29Z brun $
00002 // Author:  Richard Maunder  25/05/2005
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, 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 "TGLPhysicalShape.h"
00013 #include "TGLLogicalShape.h"
00014 #include "TGLPShapeRef.h"
00015 #include "TGLCamera.h"
00016 #include "TGLRnrCtx.h"
00017 #include "TGLIncludes.h"
00018 
00019 #include "TGLScene.h"
00020 
00021 #include "TColor.h"
00022 #include "TROOT.h"
00023 
00024 #include <cmath>
00025 
00026 // For debug tracing
00027 #include "TClass.h"
00028 #include "TError.h"
00029 
00030 /******************************************************************************/
00031 // TGLPhysicalShape
00032 /******************************************************************************/
00033 
00034 //______________________________________________________________________________
00035 //
00036 // Concrete physical shape - a GL drawable. Physical shapes are the
00037 // objects the user can actually see, select, move in the viewer. It is
00038 // a placement of the associated local frame TGLLogicaShape into the
00039 // world frame. The draw process is:
00040 //
00041 // Load attributes - material colors etc
00042 // Load translation matrix - placement
00043 // Load gl name (for selection)
00044 // Call our associated logical shape Draw() to draw placed shape
00045 //
00046 // The physical shape supports translation, scaling and rotation,
00047 // selection, color changes, and permitted modification flags etc.
00048 // A physical shape cannot modify or be bound to another (or no)
00049 // logical shape - hence const & handle. It can perform mutable
00050 // reference counting on the logical to enable purging.
00051 //
00052 // Physical shape also maintains a list of references to it and
00053 // provides notifications of change and destruction.
00054 // See class TGLPShapeRef which needs to be sub-classes for real use.
00055 //
00056 // See base/src/TVirtualViewer3D for description of common external 3D
00057 // viewer architecture and how external viewer clients use it.
00058 //
00059 
00060 ClassImp(TGLPhysicalShape)
00061 
00062 //______________________________________________________________________________
00063 TGLPhysicalShape::TGLPhysicalShape(UInt_t id, const TGLLogicalShape & logicalShape,
00064                                    const TGLMatrix & transform, Bool_t invertedWind,
00065                                    const Float_t rgba[4]) :
00066    fLogicalShape (&logicalShape),
00067    fNextPhysical (0),
00068    fFirstPSRef   (0),
00069    fID           (id),
00070    fTransform    (transform),
00071    fSelected     (0),
00072    fInvertedWind (invertedWind),
00073    fModified     (kFALSE),
00074    fManip        (kManipAll)
00075 {
00076    // Construct a physical shape using arguments:
00077    //    ID             - unique drawable id.
00078    //    logicalShape   - bound logical shape
00079    //    transform      - transform for placement of logical drawing
00080    //    invertedWind   - use inverted face polygon winding?
00081    //    rgba           - basic four component (RGBA) diffuse color
00082 
00083    fLogicalShape->AddRef(this);
00084    UpdateBoundingBox();
00085 
00086    // Initialise color
00087    InitColor(rgba);
00088 }
00089 
00090 //______________________________________________________________________________
00091 TGLPhysicalShape::TGLPhysicalShape(UInt_t id, const TGLLogicalShape & logicalShape,
00092                                    const Double_t * transform, Bool_t invertedWind,
00093                                    const Float_t rgba[4]) :
00094    fLogicalShape (&logicalShape),
00095    fNextPhysical (0),
00096    fFirstPSRef   (0),
00097    fID           (id),
00098    fTransform    (transform),
00099    fSelected     (0),
00100    fInvertedWind (invertedWind),
00101    fModified     (kFALSE),
00102    fManip        (kManipAll)
00103 {
00104    // Construct a physical shape using arguments:
00105    //    id             - unique drawable id.
00106    //    logicalShape   - bound logical shape
00107    //    transform      - 16 Double_t component transform for placement of logical drawing
00108    //    invertedWind   - use inverted face polygon winding?
00109    //    rgba           - basic four component (RGBA) diffuse color
00110 
00111    fLogicalShape->AddRef(this);
00112 
00113    // Temporary hack - invert the 3x3 part of martix as TGeo sends this
00114    // in opp layout to shear/translation parts. Speak to Andrei about best place
00115    // to fix - probably when filling TBuffer3D - should always be OGL convention?
00116    fTransform.Transpose3x3();
00117    UpdateBoundingBox();
00118 
00119    // Initialise color
00120    InitColor(rgba);
00121 }
00122 
00123 //______________________________________________________________________________
00124 TGLPhysicalShape::~TGLPhysicalShape()
00125 {
00126    // Destroy the physical shape.
00127 
00128    // If destroyed from the logical shape itself the pointer has already
00129    // been cleared.
00130    if (fLogicalShape) fLogicalShape->SubRef(this);
00131 
00132    // Remove all references.
00133    while (fFirstPSRef) {
00134       fFirstPSRef->SetPShape(0);
00135    }
00136 }
00137 
00138 //______________________________________________________________________________
00139 void TGLPhysicalShape::AddReference(TGLPShapeRef* ref)
00140 {
00141    // Add reference ref.
00142 
00143    assert(ref != 0);
00144 
00145    ref->fNextPSRef = fFirstPSRef;
00146    fFirstPSRef = ref;
00147 }
00148 
00149 //______________________________________________________________________________
00150 void TGLPhysicalShape::RemoveReference(TGLPShapeRef* ref)
00151 {
00152    // Remove reference ref.
00153 
00154    assert(ref != 0);
00155 
00156    Bool_t found = kFALSE;
00157    if (fFirstPSRef == ref) {
00158       fFirstPSRef = ref->fNextPSRef;
00159       found = kTRUE;
00160    } else {
00161       TGLPShapeRef *shp1 = fFirstPSRef, *shp2;
00162       while ((shp2 = shp1->fNextPSRef) != 0) {
00163          if (shp2 == ref) {
00164             shp1->fNextPSRef = shp2->fNextPSRef;
00165             found = kTRUE;
00166             break;
00167          }
00168          shp1 = shp2;
00169       }
00170    }
00171    if (found) {
00172       ref->fNextPSRef = 0;
00173    } else {
00174       Error("TGLPhysicalShape::RemoveReference", "Attempt to un-ref an unregistered shape-ref.");
00175    }
00176 }
00177 
00178 //______________________________________________________________________________
00179 void TGLPhysicalShape::Modified()
00180 {
00181    // Call this after modifying the physical so that the information
00182    // can be propagated to the object referencing it.
00183 
00184    fModified = kTRUE;
00185    TGLPShapeRef * ref = fFirstPSRef;
00186    while (ref) {
00187       ref->PShapeModified();
00188       ref = ref->fNextPSRef;
00189    }
00190 }
00191 
00192 //______________________________________________________________________________
00193 void TGLPhysicalShape::UpdateBoundingBox()
00194 {
00195    // Update our internal bounding box (in global frame).
00196 
00197    fBoundingBox.Set(fLogicalShape->BoundingBox());
00198    fBoundingBox.Transform(fTransform);
00199 
00200    if (fLogicalShape->GetScene())
00201       fLogicalShape->GetScene()->InvalidateBoundingBox();
00202 }
00203 
00204 //______________________________________________________________________________
00205 void TGLPhysicalShape::InitColor(const Float_t rgba[4])
00206 {
00207    // Initialise the colors, using basic RGBA diffuse material color supplied
00208 
00209    // TODO: Make a color class
00210    fColor[0] = rgba[0];
00211    fColor[1] = rgba[1];
00212    fColor[2] = rgba[2];
00213    fColor[3] = rgba[3];
00214 
00215    fColor[4]  = fColor[5]  = fColor[6]  = 0.0f; //ambient
00216    fColor[8]  = fColor[9]  = fColor[10] = 0.7f; //specular
00217    fColor[12] = fColor[13] = fColor[14] = 0.0f; //emission
00218    fColor[7]  = fColor[11] = fColor[15] = 1.0f; //alpha
00219    fColor[16] = 60.0f;                          //shininess
00220 }
00221 
00222 //______________________________________________________________________________
00223 void TGLPhysicalShape::SetColor(const Float_t color[17])
00224 {
00225    // Set full color attributes - see OpenGL material documentation
00226    // for full description.
00227    // 0->3 diffuse, 4->7 ambient, 8->11 specular, 12->15 emission, 16 shininess
00228 
00229    // TODO: Make a color class
00230    for (UInt_t i = 0; i < 17; i++) {
00231       fColor[i] = color[i];
00232    }
00233 
00234    Modified();
00235 }
00236 
00237 //______________________________________________________________________________
00238 void TGLPhysicalShape::SetColorOnFamily(const Float_t color[17])
00239 {
00240    // Set full color attributes to all physicals sharing the same
00241    // logical with this object.
00242 
00243    TGLPhysicalShape* pshp = const_cast<TGLPhysicalShape*>(fLogicalShape->GetFirstPhysical());
00244    while (pshp)
00245    {
00246       pshp->SetColor(color);
00247       pshp = pshp->fNextPhysical;
00248    }
00249 }
00250 
00251 //______________________________________________________________________________
00252 void TGLPhysicalShape::SetDiffuseColor(const Float_t rgba[4])
00253 {
00254    // Set color from ROOT color index and transparency [0,100].
00255 
00256    for (Int_t i=0; i<4; ++i)
00257       fColor[i] = rgba[i];
00258    Modified();
00259 }
00260 
00261 //______________________________________________________________________________
00262 void TGLPhysicalShape::SetDiffuseColor(const UChar_t rgba[4])
00263 {
00264    // Set color from RGBA quadruplet.
00265 
00266    for (Int_t i=0; i<4; ++i)
00267       fColor[i] = rgba[i]/255.0f;
00268    Modified();
00269 }
00270 
00271 //______________________________________________________________________________
00272 void TGLPhysicalShape::SetDiffuseColor(Color_t ci, UChar_t transparency)
00273 {
00274    // Set color from standard ROOT representation, that is color index
00275    // + transparency in range [0, 100].
00276 
00277    if (ci < 0) ci = 1;
00278    TColor* c = gROOT->GetColor(ci);
00279    if (c) {
00280       fColor[0] = c->GetRed();
00281       fColor[1] = c->GetGreen();
00282       fColor[2] = c->GetBlue();
00283       fColor[3] = 1.0f - 0.01*transparency;
00284    }
00285    Modified();
00286 }
00287 
00288 //______________________________________________________________________________
00289 void TGLPhysicalShape::SetupGLColors(TGLRnrCtx & rnrCtx, const Float_t* color) const
00290 {
00291    // Setup colors - avoid setting things not required
00292    // for current draw flags.
00293 
00294    if (color == 0) color = fColor;
00295 
00296    switch (rnrCtx.DrawPass()) {
00297       case TGLRnrCtx::kPassWireFrame:
00298       {
00299          // Wireframe needs basic color only
00300          glColor4fv(color);
00301          break;
00302       }
00303       case TGLRnrCtx::kPassFill:
00304       case TGLRnrCtx::kPassOutlineFill:
00305       {
00306          // Both need material colors
00307 
00308          // Set back diffuse only for clipping where inner (back) faces
00309          // are shown. Don't set shinneness or specular as we want
00310          // back face to appear as 'flat' as possible as crude visual
00311          // approximation to proper capped clipped solid
00312          glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
00313          glMaterialfv(GL_FRONT, GL_AMBIENT,  color + 4);
00314          glMaterialfv(GL_FRONT, GL_SPECULAR, color + 8);
00315          glMaterialfv(GL_FRONT, GL_EMISSION, color + 12);
00316          glMaterialf(GL_FRONT, GL_SHININESS, color[16]);
00317          // Some objects use point/line graphics. Material mode disabled.
00318          glColor4fv(color);
00319          break;
00320       }
00321       case TGLRnrCtx::kPassOutlineLine:
00322       {
00323          // Outline also needs grey wireframe but respecting
00324          // transparency of main diffuse color.
00325          TGLUtil::ColorAlpha(rnrCtx.ColorSet().Outline(), 0.5f*color[3]);
00326          break;
00327       }
00328       default:
00329       {
00330          assert(kFALSE);
00331       }
00332    }
00333 }
00334 
00335 static const Float_t selColor[] =
00336 {
00337    1,   1,   1,   1,     // base color
00338    0,   0,   0,   1,     // ambient
00339    0,   0,   0,   1,     // specular
00340    0.5, 0,   0,   1,     // emission
00341    0                     // shininess
00342 };
00343 
00344 //______________________________________________________________________________
00345 void TGLPhysicalShape::Draw(TGLRnrCtx & rnrCtx) const
00346 {
00347    // Draw physical shape, using LOD flags, potential from display list cache
00348 
00349    // Debug tracing
00350    if (gDebug > 4) {
00351       Info("TGLPhysicalShape::Draw", "this %ld (class %s) LOD %d",
00352            (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD());
00353    }
00354 
00355    // If LOD is pixel or less can draw pixel(point) directly, skipping
00356    // any logical call, caching etc.
00357    if (rnrCtx.ShapeLOD() == TGLRnrCtx::kLODPixel)
00358    {
00359       if (!rnrCtx.IsDrawPassOutlineLine())
00360       {
00361          glColor4fv(fColor);
00362          glBegin(GL_POINTS);
00363          glVertex3dv(&fTransform.CArr()[12]);
00364          glEnd();
00365       }
00366       return;
00367    }
00368 
00369    if (gDebug > 4) {
00370       Info("TGLPhysicalShape::Draw", "this %ld (class %s) LOD %d",
00371            (Long_t)this, IsA()->GetName(), rnrCtx.ShapeLOD());
00372    }
00373 
00374    glPushMatrix();
00375    glMultMatrixd(fTransform.CArr());
00376    if (fInvertedWind)  glFrontFace(GL_CW);
00377    if (rnrCtx.Highlight() && !rnrCtx.Selection() && !rnrCtx.IsDrawPassOutlineLine())
00378    {
00379       fLogicalShape->DrawHighlight(rnrCtx, this);
00380    }
00381    else
00382    {
00383       SetupGLColors(rnrCtx);
00384       if (rnrCtx.IsDrawPassOutlineLine())
00385          TGLUtil::LockColor();
00386       fLogicalShape->Draw(rnrCtx);
00387       if (rnrCtx.IsDrawPassOutlineLine())
00388          TGLUtil::UnlockColor();
00389    }
00390    if (fInvertedWind) glFrontFace(GL_CCW);
00391    glPopMatrix();
00392 }
00393 
00394 //______________________________________________________________________________
00395 void TGLPhysicalShape::CalculateShapeLOD(TGLRnrCtx& rnrCtx, Float_t& pixSize, Short_t& shapeLOD) const
00396 {
00397    // Calculate shape-lod, suitible for use under
00398    // projection defined by 'rnrCtx', taking account of which local
00399    // axes of the shape support LOD adjustment, and the global
00400    // 'sceneFlags' passed.
00401    //
00402    // Returned shapeLOD component is from 0 (kLODPixel - lowest
00403    // quality) to 100 (kLODHigh - highest quality).
00404    //
00405    // Scene flags are not used. LOD quantization is not done.  RnrCtx
00406    // is not modified as this is called via lodification stage of
00407    // rendering.
00408 
00409    TGLLogicalShape::ELODAxes lodAxes = fLogicalShape->SupportedLODAxes();
00410 
00411    if (lodAxes == TGLLogicalShape::kLODAxesNone)
00412    {  // Shape doesn't support LOD along any axes return special
00413       // unsupported LOD draw/cache flag.
00414       // TODO: Still ... could check for kLODPixel when very small,
00415       //    by using diagonal from bounding-box and some special camera foo.
00416       pixSize  = 100; // Make up something / irrelevant.
00417       shapeLOD = TGLRnrCtx::kLODHigh;
00418       return;
00419    }
00420 
00421    std::vector <Double_t> boxViewportDiags;
00422    const TGLBoundingBox & box        = BoundingBox();
00423    const TGLCamera      & camera     = rnrCtx.RefCamera();
00424 
00425    if (lodAxes == TGLLogicalShape::kLODAxesAll) {
00426       // Shape supports LOD along all axes - basis LOD hint on diagonal of viewport
00427       // projection rect round whole bounding box
00428       boxViewportDiags.push_back(camera.ViewportRect(box).Diagonal());
00429    } else if (lodAxes == (TGLLogicalShape::kLODAxesY | TGLLogicalShape::kLODAxesZ)) {
00430       // Shape supports LOD along Y/Z axes (not X). LOD hint based on longest
00431       // diagonal (largest rect) of either of the X axis end faces
00432       boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceLowX).Diagonal());
00433       boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceHighX).Diagonal());
00434    } else if (lodAxes == (TGLLogicalShape::kLODAxesX | TGLLogicalShape::kLODAxesZ)) {
00435       // Shape supports LOD along X/Z axes (not Y). See above for Y/Z
00436       boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceLowY).Diagonal());
00437       boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceHighY).Diagonal());
00438    } else if (lodAxes == (TGLLogicalShape::kLODAxesX | TGLLogicalShape::kLODAxesY)) {
00439       // Shape supports LOD along X/Y axes (not Z). See above for Y/Z
00440       boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceLowZ).Diagonal());
00441       boxViewportDiags.push_back(camera.ViewportRect(box, TGLBoundingBox::kFaceHighZ).Diagonal());
00442    } else {
00443       // Don't bother to implement LOD calc for shapes supporting LOD along single
00444       // axis only. Not needed at present + unlikely case - but could be done based
00445       // on longest of projection of 4 edges of BBox along LOD axis. However this would
00446       // probably be more costly than just using whole BB projection (as for all axes)
00447       Error("TGLPhysicalShape::CalcPhysicalLOD", "LOD calculation for single axis not implemented presently");
00448       shapeLOD = TGLRnrCtx::kLODMed;
00449       return;
00450    }
00451 
00452    // Find largest of the projected diagonals
00453    Double_t largestDiagonal = 0.0;
00454    for (UInt_t i = 0; i < boxViewportDiags.size(); i++) {
00455       if (boxViewportDiags[i] > largestDiagonal) {
00456          largestDiagonal = boxViewportDiags[i];
00457       }
00458    }
00459    pixSize = largestDiagonal;
00460 
00461    if (largestDiagonal <= 1.0) {
00462       shapeLOD = TGLRnrCtx::kLODPixel;
00463    } else {
00464       // TODO: Get real screen size - assuming 2000 pixel screen at present
00465       // Calculate a non-linear sizing hint for this shape based on diagonal.
00466       // Needs more experimenting with...
00467       UInt_t lodApp = static_cast<UInt_t>(std::pow(largestDiagonal,0.4) * 100.0 / std::pow(2000.0,0.4));
00468       if (lodApp > 1000) lodApp = 1000;
00469       shapeLOD = (Short_t) lodApp;
00470    }
00471 }
00472 
00473 //______________________________________________________________________________
00474 void TGLPhysicalShape::QuantizeShapeLOD(Short_t shapeLOD, Short_t combiLOD, Short_t& quantLOD) const
00475 {
00476    // Factor in scene/vierer LOD and Quantize ... forward to
00477    // logical shape.
00478 
00479    quantLOD = fLogicalShape->QuantizeShapeLOD(shapeLOD, combiLOD);
00480 }
00481 
00482 //______________________________________________________________________________
00483 void TGLPhysicalShape::InvokeContextMenu(TContextMenu & menu, UInt_t x, UInt_t y) const
00484 {
00485    // Request creation of context menu on shape, attached to 'menu' at screen position
00486    // 'x' 'y'
00487 
00488    // Just defer to our logical at present
00489    fLogicalShape->InvokeContextMenu(menu, x, y);
00490 }

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