#include "TGLScenePad.h"
#include "TGLViewer.h"
#include "TGLLogicalShape.h"
#include "TGLPhysicalShape.h"
#include "TGLObject.h"
#include "TGLStopwatch.h"
#include "TBuffer3D.h"
#include "TBuffer3DTypes.h"
#include "TGLFaceSet.h"
#include "TGLPolyLine.h"
#include "TGLPolyMarker.h"
#include "TGLCylinder.h"
#include "TGLSphere.h"
#include "TVirtualPad.h"
#include "TAtt3D.h"
#include "TClass.h"
#include "TList.h"
#include "TMath.h"
#include "TH2.h"         
#include "TH2GL.h"
#include "TF2.h"
#include "TF2GL.h"
#include "TGLParametric.h"
#include "TGLParametricEquationGL.h"
ClassImp(TGLScenePad)
TGLScenePad::TGLScenePad(TVirtualPad* pad) :
   TVirtualViewer3D(),
   TGLScene(),
   fPad               (pad),
   fInternalPIDs      (kFALSE),
   fNextInternalPID   (1), 
   fLastPID           (0), 
   fAcceptedPhysicals (0),
   fComposite         (0),
   fCSLevel           (0),
   fSmartRefresh      (kFALSE)
{
   
}
void TGLScenePad::AddHistoPhysical(TGLLogicalShape* log)
{
   
   Double_t how = ((Double_t) gPad->GetWh()) / gPad->GetWw();
   Double_t lw = gPad->GetAbsWNDC();
   Double_t lh = gPad->GetAbsHNDC() * how;
   Double_t lm = TMath::Min(lw, lh);
   const TGLBoundingBox& bb = log->BoundingBox();
   
   Double_t size  = TMath::Sqrt(3) * (bb.XMax() - bb.XMin());
   Double_t scale = lm / size;
   TGLVector3 scaleVec(scale, scale, scale);
   Double_t tx = gPad->GetAbsXlowNDC() + lw;
   Double_t ty = gPad->GetAbsYlowNDC() * how + lh;
   TGLVector3 transVec(0, ty, tx); 
   TGLMatrix mat;
   mat.Scale(scaleVec);
   mat.Translate(transVec);
   mat.RotateLF(3, 2, TMath::PiOver2());
   mat.RotateLF(1, 3, TMath::DegToRad()*gPad->GetTheta());
   mat.RotateLF(1, 2, TMath::DegToRad()*(gPad->GetPhi() - 90));
   Float_t rgba[4] = { 1, 1, 1, 1};
   TGLPhysicalShape* phys = new TGLPhysicalShape
      (fNextInternalPID++, *log, mat, false, rgba);
   AdoptPhysical(*phys);
}
void TGLScenePad::SubPadPaint(TVirtualPad* pad)
{
   
   TVirtualPad      *padsav  = gPad;
   TVirtualViewer3D *vv3dsav = pad->GetViewer3D();
   gPad = pad;
   pad->SetViewer3D(this);
   TList       *prims = pad->GetListOfPrimitives();
   TObjOptLink *lnk   = (prims) ? (TObjOptLink*)prims->FirstLink() : 0;
   while (lnk)
   {
      ObjectPaint(lnk->GetObject(), lnk->GetOption());
      lnk = (TObjOptLink*)lnk->Next();
   }
   pad->SetViewer3D(vv3dsav);
   gPad = padsav;
}
void TGLScenePad::ObjectPaint(TObject* obj, Option_t* opt)
{
   
   
   
   if (obj->InheritsFrom(TAtt3D::Class()))
   {
      
      obj->Paint(opt);
   }
   else if (obj->InheritsFrom(TH2::Class()))
   {
      
      TGLObject* log = new TH2GL();
      log->SetModel(obj, opt);
      log->SetBBox();
      AdoptLogical(*log);
      AddHistoPhysical(log);
   }
   else if (obj->InheritsFrom(TF2::Class()))
   {
      
      TGLObject* log = new TF2GL();
      log->SetModel(obj, opt);
      log->SetBBox();
      AdoptLogical(*log);
      AddHistoPhysical(log);
   }
   else if (obj->InheritsFrom(TGLParametricEquation::Class()))
   {
      
      TGLObject* log = new TGLParametricEquationGL();
      log->SetModel(obj, opt);
      log->SetBBox();
      AdoptLogical(*log);
      AddHistoPhysical(log);
   }
   else if (obj->InheritsFrom(TVirtualPad::Class()))
   {
      SubPadPaint(dynamic_cast<TVirtualPad*>(obj));
   }
   else
   {
      
      
      
      obj->Paint(opt);
   }
}
void TGLScenePad::PadPaintFromViewer(TGLViewer* viewer)
{
   
   
   Bool_t sr = fSmartRefresh;
   fSmartRefresh = viewer->GetSmartRefresh();
   PadPaint(fPad);
   fSmartRefresh = sr;
}
void TGLScenePad::PadPaint(TVirtualPad* pad)
{
   
   
   
   
   if (pad != fPad)
   {
      Error("TGLScenePad::PadPaint", "Mismatch between pad argument and data-member!");
      return;
   }
   BeginScene();
   SubPadPaint(fPad);
   EndScene();
}
void TGLScenePad::BeginScene()
{
   
   
   
   
   
   
   if (gDebug>2) {
      Info("TGLScenePad::BeginScene", "entering.");
   }
   if ( ! BeginUpdate()) {
      Error("TGLScenePad::BeginScene", "could not take scene lock.");
      return;
   }
   UInt_t destroyedLogicals  = 0;
   UInt_t destroyedPhysicals = 0;
   TGLStopwatch stopwatch;
   if (gDebug > 2) {
      stopwatch.Start();
   }
   
   
   
   destroyedPhysicals = DestroyPhysicals(kTRUE); 
   if (fSmartRefresh) {
      destroyedLogicals = BeginSmartRefresh();
   } else {
      destroyedLogicals = DestroyLogicals();
   }
   
   fInternalPIDs = kFALSE;
   
   fNextInternalPID = 1;
   fLastPID         = 0;
   
   fAcceptedPhysicals = 0;
   if (gDebug > 2) {
      Info("TGLScenePad::BeginScene", "destroyed %d physicals %d logicals in %f msec",
            destroyedPhysicals, destroyedLogicals, stopwatch.End());
      DumpMapSizes();
   }
}
void TGLScenePad::EndScene()
{
   
   
   
   if (fSmartRefresh) {
      EndSmartRefresh();
   }
   EndUpdate();
   if (gDebug > 2) {
      Info("TGLScenePad::EndScene", "Accepted %d physicals", fAcceptedPhysicals);
      DumpMapSizes();
   }
}
Int_t TGLScenePad::AddObject(const TBuffer3D& buffer, Bool_t* addChildren)
{
   
   
   
   
   fInternalPIDs = kTRUE;
   Int_t sections = AddObject(fNextInternalPID, buffer, addChildren);
   return sections;
}
Int_t TGLScenePad::AddObject(UInt_t physicalID, const TBuffer3D& buffer, Bool_t* addChildren)
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   if (physicalID == 0) {
      Error("TGLScenePad::AddObject", "0 physical ID reserved");
      return TBuffer3D::kNone;
   }
   
   if (fInternalPIDs && physicalID != fNextInternalPID) {
      Error("TGLScenePad::AddObject", "invalid next physical ID - mix of internal + external IDs?");
      return TBuffer3D::kNone;
   }
   
   if (addChildren)
      *addChildren = kTRUE;
   
   if (CurrentLock() != kModifyLock) {
      Error("TGLScenePad::AddObject", "expected scene to be modify-locked.");
      return TBuffer3D::kNone;
   }
   
   
   
   if (fComposite) {
      RootCsg::TBaseMesh *newMesh = RootCsg::ConvertToMesh(buffer);
      
      fCSTokens.push_back(std::make_pair(static_cast<UInt_t>(TBuffer3D::kCSNoOp), newMesh));
      return TBuffer3D::kNone;
   }
   
   TGLPhysicalShape *physical = FindPhysical(physicalID);
   TGLLogicalShape  *logical  = 0;
   
   
   if (buffer.fID)
   {
      logical = FindLogical(buffer.fID);
      if (!logical)
         logical = AttemptDirectRenderer(buffer.fID);
   }
   
   if (physicalID != fLastPID)
   {
      
      
      if (physical)
      {
         
         if (!logical) {
            Error("TGLScenePad::AddObject", "cached physical with no assocaited cached logical");
         }
         
         
         if (fInternalPIDs)
            ++fNextInternalPID;
         return TBuffer3D::kNone;
      }
      
      Bool_t includeRaw    = (logical == 0);
      Int_t  extraSections = ValidateObjectBuffer(buffer, includeRaw);
      if (extraSections != TBuffer3D::kNone)
         return extraSections;
      fLastPID = physicalID;
   }
   if (fLastPID != physicalID) {
      Error("TGLScenePad::AddObject", "internal physical ID tracking error?");
   }
   
   if (physical) {
      Error("TGLScenePad::AddObject", "expecting to require physical");
      return TBuffer3D::kNone;
   }
   
   if (!logical)
   {
      logical = CreateNewLogical(buffer);
      if (!logical) {
         Error("TGLScenePad::AddObject", "failed to create logical");
         return TBuffer3D::kNone;
      }
      
      AdoptLogical(*logical);
   }
   
   physical = CreateNewPhysical(physicalID, buffer, *logical);
   if (physical)
   {
      AdoptPhysical(*physical);
      buffer.fPhysicalID = physicalID;
      ++fAcceptedPhysicals;
      if (gDebug>3 && fAcceptedPhysicals%1000 == 0) {
         Info("TGLScenePad::AddObject", "added %d physicals", fAcceptedPhysicals);
      }
   }
   else
   {
      Error("TGLScenePad::AddObject", "failed to create physical");
   }
   
   if (fInternalPIDs)
      fNextInternalPID++;
   return TBuffer3D::kNone;
}
Bool_t TGLScenePad::OpenComposite(const TBuffer3D& buffer, Bool_t* addChildren)
{
   
   
   
   if (fComposite) {
      Error("TGLScenePad::OpenComposite", "composite already open");
      return kFALSE;
   }
   UInt_t extraSections = AddObject(buffer, addChildren);
   if (extraSections != TBuffer3D::kNone) {
      Error("TGLScenePad::OpenComposite", "expected top level composite to not require extra buffer sections");
   }
   
   
   if (fComposite) {
      return kTRUE;
   } else {
      return kFALSE;
   }
}
void TGLScenePad::CloseComposite()
{
   
   
   
   
   if (fComposite) {
      
      fCSLevel = 0;
      RootCsg::TBaseMesh *resultMesh = BuildComposite();
      fComposite->SetFromMesh(resultMesh);
      delete resultMesh;
      for (UInt_t i = 0; i < fCSTokens.size(); ++i) delete fCSTokens[i].second;
      fCSTokens.clear();
      fComposite = 0;
   }
}
void TGLScenePad::AddCompositeOp(UInt_t operation)
{
   
   
   
   fCSTokens.push_back(std::make_pair(operation, (RootCsg::TBaseMesh *)0));
}
Int_t TGLScenePad::ValidateObjectBuffer(const TBuffer3D& buffer, Bool_t includeRaw) const
{
   
   
   
   
   
   
   if (!buffer.SectionsValid(TBuffer3D::kCore)) {
      Error("TGLScenePad::ValidateObjectBuffer", "kCore section of buffer should be filled always");
      return TBuffer3D::kNone;
   }
   
   if (!includeRaw) {
      return TBuffer3D::kNone;
   }
   
   Bool_t needRaw = kFALSE;
   
   
   
   if (buffer.Type() != TBuffer3DTypes::kSphere  &&
       buffer.Type() != TBuffer3DTypes::kTube    &&
       buffer.Type() != TBuffer3DTypes::kTubeSeg &&
       buffer.Type() != TBuffer3DTypes::kCutTube &&
       buffer.Type() != TBuffer3DTypes::kComposite)
   {
      needRaw = kTRUE;
   }
   
   
   else if (buffer.Type() == TBuffer3DTypes::kSphere)
   {
      const TBuffer3DSphere * sphereBuffer = dynamic_cast<const TBuffer3DSphere *>(&buffer);
      if (sphereBuffer) {
         if (!sphereBuffer->IsSolidUncut()) {
            needRaw = kTRUE;
         }
      } else {
         Error("TGLScenePad::ValidateObjectBuffer", "failed to cast buffer of type 'kSphere' to TBuffer3DSphere");
         return TBuffer3D::kNone;
      }
   }
   
   else if (!buffer.SectionsValid(TBuffer3D::kBoundingBox))
   {
      needRaw = kTRUE;
   }
   
   else if (!buffer.SectionsValid(TBuffer3D::kShapeSpecific) &&
             buffer.Type() != TBuffer3DTypes::kComposite)
   {
      needRaw = kTRUE;
   }
   
   else if (fComposite)
   {
      needRaw = kTRUE;
   }
   if (needRaw && !buffer.SectionsValid(TBuffer3D::kRawSizes|TBuffer3D::kRaw)) {
      return TBuffer3D::kRawSizes|TBuffer3D::kRaw;
   } else {
      return TBuffer3D::kNone;
   }
}
TGLLogicalShape* TGLScenePad::CreateNewLogical(const TBuffer3D& buffer) const
{
   
   TGLLogicalShape * newLogical = 0;
   if (buffer.fColor == 1) 
      const_cast<TBuffer3D&>(buffer).fColor = 42;
   switch (buffer.Type())
   {
      case TBuffer3DTypes::kLine:
         newLogical = new TGLPolyLine(buffer);
         break;
      case TBuffer3DTypes::kMarker:
         newLogical = new TGLPolyMarker(buffer);
         break;
      case TBuffer3DTypes::kSphere:
      {
         const TBuffer3DSphere * sphereBuffer = dynamic_cast<const TBuffer3DSphere *>(&buffer);
         if (sphereBuffer)
         {
            
            
            if (sphereBuffer->IsSolidUncut() && !buffer.SectionsValid(TBuffer3D::kRawSizes|TBuffer3D::kRaw))
            {
               newLogical = new TGLSphere(*sphereBuffer);
            } else {
               newLogical = new TGLFaceSet(buffer);
            }
         } else {
            Error("TGLScenePad::CreateNewLogical", "failed to cast buffer of type 'kSphere' to TBuffer3DSphere");
         }
         break;
      }
      case TBuffer3DTypes::kTube:
      case TBuffer3DTypes::kTubeSeg:
      case TBuffer3DTypes::kCutTube:
      {
         const TBuffer3DTube * tubeBuffer = dynamic_cast<const TBuffer3DTube *>(&buffer);
         if (tubeBuffer)
         {
            
            if (!buffer.SectionsValid(TBuffer3D::kRawSizes|TBuffer3D::kRaw)) {
               newLogical = new TGLCylinder(*tubeBuffer);
            } else {
               newLogical = new TGLFaceSet(buffer);
            }
         } else {
            Error("TGLScenePad::CreateNewLogical", "failed to cast buffer of type 'kTube/kTubeSeg/kCutTube' to TBuffer3DTube");
         }
         break;
      }
      case TBuffer3DTypes::kComposite:
      {
         
         
         if (fComposite)
         {
            Error("TGLScenePad::CreateNewLogical", "composite already open");
         }
         fComposite = new TGLFaceSet(buffer);
         newLogical = fComposite;
         break;
      }
      default:
         newLogical = new TGLFaceSet(buffer);
         break;
   }
   return newLogical;
}
TGLPhysicalShape*
TGLScenePad::CreateNewPhysical(UInt_t ID, const TBuffer3D& buffer,
                               const TGLLogicalShape& logical) const
{
   
   
   
   
   
   Int_t colorIndex = buffer.fColor;
   if (colorIndex < 0) colorIndex = 42;
   Float_t rgba[4];
   TGLScene::RGBAFromColorIdx(rgba, colorIndex, buffer.fTransparency);
   return new TGLPhysicalShape(ID, logical, buffer.fLocalMaster,
                               buffer.fReflection, rgba);
}
RootCsg::TBaseMesh* TGLScenePad::BuildComposite()
{
   
   const CSPart_t &currToken = fCSTokens[fCSLevel];
   UInt_t opCode = currToken.first;
   if (opCode != TBuffer3D::kCSNoOp) {
      ++fCSLevel;
      RootCsg::TBaseMesh *left = BuildComposite();
      RootCsg::TBaseMesh *right = BuildComposite();
      
      switch (opCode) {
      case TBuffer3D::kCSUnion:
         return RootCsg::BuildUnion(left, right);
      case TBuffer3D::kCSIntersection:
         return RootCsg::BuildIntersection(left, right);
      case TBuffer3D::kCSDifference:
         return RootCsg::BuildDifference(left, right);
      default:
         Error("BuildComposite", "Wrong operation code %d\n", opCode);
         return 0;
      }
   } else return fCSTokens[fCSLevel++].second;
}
TGLLogicalShape* TGLScenePad::AttemptDirectRenderer(TObject* id)
{
   
   
   
   TClass* cls = TGLObject::GetGLRenderer(id->IsA());
   if (cls == 0)
      return 0;
   TGLObject* rnr = reinterpret_cast<TGLObject*>(cls->New());
   if (rnr) {
      if (rnr->SetModel(id) == kFALSE) {
         Warning("TGLScenePad::AttemptDirectRenderer", "failed initializing direct rendering.");
         delete rnr;
         return 0;
      }
      rnr->SetBBox();
      AdoptLogical(*rnr);
   }
   return rnr;
}
Last change: Mon Nov 24 08:19:20 2008
Last generated: 2008-11-24 08:19
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.