#include "TGLViewer.h"
#include "TGLIncludes.h"
#include "TGLStopwatch.h"
#include "TGLRnrCtx.h"
#include "TGLSelectBuffer.h"
#include "TGLLightSet.h"
#include "TGLClip.h"
#include "TGLManipSet.h"
#include "TGLScenePad.h"
#include "TGLLogicalShape.h"
#include "TGLPhysicalShape.h"
#include "TGLObject.h"
#include "TGLStopwatch.h"
#include "TBuffer3D.h"
#include "TBuffer3DTypes.h"
#include "TGLOutput.h"
#include "TVirtualPad.h" 
#include "TAtt3D.h"      
#include "TVirtualX.h"
#include "TMath.h"
#include "TColor.h"
#include "TError.h"
#include "TClass.h"
#include "TROOT.h"
#include "Buttons.h"
#include "GuiTypes.h"
#include "TVirtualGL.h"
#include "TGLWidget.h"
#include "TGLViewerEditor.h"
#include "KeySymbols.h"
#include "TContextMenu.h"
ClassImp(TGLViewer)
TGLViewer::TGLViewer(TVirtualPad * pad, Int_t x, Int_t y,
                     Int_t width, Int_t height) :
   fPad(pad),
   fContextMenu(0),
   fPerspectiveCameraXOZ(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), 
   fPerspectiveCameraYOZ(TGLVector3( 0.0,-1.0, 0.0), TGLVector3(1.0, 0.0, 0.0)), 
   fPerspectiveCameraXOY(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), 
   fOrthoXOYCamera(TGLVector3( 0.0, 0.0, 1.0), TGLVector3(0.0, 1.0, 0.0)), 
   fOrthoXOZCamera(TGLVector3( 0.0,-1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), 
   fOrthoZOYCamera(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), 
   fCurrentCamera(&fPerspectiveCameraXOZ),
   fLightSet          (0),
   fClipSet           (0),
   fSelectedPShapeRef (0),
   fCurrentOvlElm     (0),
   fPushAction(kPushStd), fAction(kDragNone), fLastPos(0,0), fActiveButtonID(0),
   fRedrawTimer(0),
   fMaxSceneDrawTimeHQ(5000),
   fMaxSceneDrawTimeLQ(100),
   fClearColor(1),
   fAxesType(TGLUtil::kAxesNone),
   fAxesDepthTest(kTRUE),
   fReferenceOn(kFALSE),
   fReferencePos(0.0, 0.0, 0.0),
   fDrawCameraCenter(kFALSE),
   fCameraMarkup(0),
   fInitGL(kFALSE),
   fSmartRefresh(kFALSE),
   fDebugMode(kFALSE),
   fIsPrinting(kFALSE),
   fGLWindow(0),
   fGLDevice(-1),
   fGLCtxId(0),
   fIgnoreSizesOnUpdate(kFALSE),
   fResetCamerasOnUpdate(kTRUE),
   fResetCamerasOnNextUpdate(kFALSE),
   fResetCameraOnDoubleClick(kTRUE)
{
   
   
   
   
   InitSecondaryObjects();
   SetViewport(x, y, width, height);
}
TGLViewer::TGLViewer(TVirtualPad * pad) :
   fPad(pad),
   fContextMenu(0),
   fPerspectiveCameraXOZ(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), 
   fPerspectiveCameraYOZ(TGLVector3( 0.0,-1.0, 0.0), TGLVector3(1.0, 0.0, 0.0)), 
   fPerspectiveCameraXOY(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), 
   fOrthoXOYCamera(TGLVector3( 0.0, 0.0, 1.0), TGLVector3(0.0, 1.0, 0.0)), 
   fOrthoXOZCamera(TGLVector3( 0.0,-1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), 
   fOrthoZOYCamera(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), 
   fCurrentCamera(&fPerspectiveCameraXOZ),
   fLightSet          (0),
   fClipSet           (0),
   fSelectedPShapeRef (0),
   fCurrentOvlElm     (0),
   fPushAction(kPushStd), fAction(kDragNone), fLastPos(0,0), fActiveButtonID(0),
   fRedrawTimer(0),
   fMaxSceneDrawTimeHQ(5000),
   fMaxSceneDrawTimeLQ(100),
   fClearColor(1),
   fAxesType(TGLUtil::kAxesNone),
   fAxesDepthTest(kTRUE),
   fReferenceOn(kFALSE),
   fReferencePos(0.0, 0.0, 0.0),
   fDrawCameraCenter(kFALSE),
   fCameraMarkup(0),
   fInitGL(kFALSE),
   fSmartRefresh(kFALSE),
   fDebugMode(kFALSE),
   fIsPrinting(kFALSE),
   fGLWindow(0),
   fGLDevice(fPad->GetGLDevice()),
   fGLCtxId(0),
   fIgnoreSizesOnUpdate(kFALSE),
   fResetCamerasOnUpdate(kTRUE),
   fResetCamerasOnNextUpdate(kFALSE),
   fResetCameraOnDoubleClick(kTRUE)
{
   
   
   
   
   
   InitSecondaryObjects();
   if (fGLDevice != -1) {
      
      fGLCtxId = new TGLContextIdentity;
      fGLCtxId->AddRef(0);
      Int_t viewport[4] = {0};
      gGLManager->ExtractViewport(fGLDevice, viewport);
      SetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
   }
}
void TGLViewer::InitSecondaryObjects()
{
   
   fLightSet = new TGLLightSet;
   fClipSet  = new TGLClipSet;  fOverlay.push_back(fClipSet);
   fSelectedPShapeRef = new TGLManipSet; fOverlay.push_back(fSelectedPShapeRef);
   fSelectedPShapeRef->SetDrawBBox(kTRUE);
   fCameraMarkup = new TGLCameraMarkupStyle;
   fRedrawTimer = new TGLRedrawTimer(*this);
}
TGLViewer::~TGLViewer()
{
   
   delete fLightSet;
   delete fClipSet;
   delete fSelectedPShapeRef;
   delete fCameraMarkup;
   delete fContextMenu;
   delete fRedrawTimer;
   if (fPad)
      fPad->ReleaseViewer3D();
   if (fGLDevice != -1)
      fGLCtxId->Release(0);
}
void TGLViewer::PadPaint(TVirtualPad* pad)
{
   
   
   
   
   
   TGLScenePad* scenepad = 0;
   for (SceneInfoList_i si = fScenes.begin(); si != fScenes.end(); ++si)
   {
      scenepad = dynamic_cast<TGLScenePad*>((*si)->GetScene());
      if (scenepad && scenepad->GetPad() == pad)
         break;
      scenepad = 0;
   }
   if (scenepad == 0)
   {
      scenepad = new TGLScenePad(pad);
      AddScene(scenepad);
   }
   scenepad->PadPaintFromViewer(this);
   PostSceneBuildSetup(fResetCamerasOnNextUpdate || fResetCamerasOnUpdate);
   fResetCamerasOnNextUpdate = kFALSE;
   RequestDraw();
}
void TGLViewer::UpdateScene()
{
   
   
   
   fRedrawTimer->Stop();
   for (SceneInfoList_i si = fScenes.begin(); si != fScenes.end(); ++si)
   {
      TGLScenePad* scenepad = dynamic_cast<TGLScenePad*>((*si)->GetScene());
      if (scenepad)
         scenepad->PadPaintFromViewer(this);
   }
   PostSceneBuildSetup(fResetCamerasOnNextUpdate || fResetCamerasOnUpdate);
   fResetCamerasOnNextUpdate = kFALSE;
   RequestDraw();
}
void TGLViewer::ResetCurrentCamera()
{
   
   MergeSceneBBoxes(fOverallBoundingBox);
   CurrentCamera().Setup(fOverallBoundingBox, kTRUE);
}
void TGLViewer::SetupCameras(Bool_t reset)
{
   
   if (IsLocked()) {
      Error("TGLViewer::SetupCameras", "expected kUnlocked, found %s", LockName(CurrentLock()));
      return;
   }
   
   const TGLBoundingBox & box = fOverallBoundingBox;
   if (!box.IsEmpty()) {
      fPerspectiveCameraYOZ.Setup(box, reset);
      fPerspectiveCameraXOZ.Setup(box, reset);
      fPerspectiveCameraXOY.Setup(box, reset);
      fOrthoXOYCamera.Setup(box, reset);
      fOrthoXOZCamera.Setup(box, reset);
      fOrthoZOYCamera.Setup(box, reset);
   }
}
void TGLViewer::PostSceneBuildSetup(Bool_t resetCameras)
{
   
   MergeSceneBBoxes(fOverallBoundingBox);
   SetupCameras(resetCameras);
   
   fReferencePos.Set(fOverallBoundingBox.Center());
   RefreshPadEditor(this);
}
void TGLViewer::InitGL()
{
   
   if (fInitGL) {
      Error("TGLViewer::InitGL", "GL already initialised");
   }
   
   glEnable(GL_LIGHTING);
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_CULL_FACE);
   glCullFace(GL_BACK);
   glClearColor(0.f, 0.f, 0.f, 1.f);
   glClearDepth(1.0);
   glMaterialf(GL_BACK, GL_SHININESS, 0.0);
   glPolygonMode(GL_FRONT, GL_FILL);
   glDisable(GL_BLEND);
   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
   Float_t lmodelAmb[] = {0.5f, 0.5f, 1.f, 1.f};
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodelAmb);
   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
   TGLUtil::CheckError("TGLViewer::InitGL");
   fInitGL = kTRUE;
}
void TGLViewer::RequestDraw(Short_t LOD)
{
   
   
   fRedrawTimer->Stop();
   
   
   if (!fGLWindow && fGLDevice == -1) {
      fRedrawTimer->RequestDraw(100, LOD);
      return;
   }
   
   if ( ! TakeLock(kDrawLock)) {
      
      
      if (gDebug>3) {
         Info("TGLViewer::RequestDraw", "viewer locked - requesting another draw.");
      }
      fRedrawTimer->RequestDraw(100, LOD);
      return;
   }
   fLOD = LOD;
   if (!gVirtualX->IsCmdThread())
      gROOT->ProcessLineFast(Form("((TGLViewer *)0x%x)->DoDraw()", this));
   else
      DoDraw();
}
void TGLViewer::PreRender()
{
   fCamera = fCurrentCamera;
   fClip   = fClipSet->GetCurrentClip();
   if (fGLDevice != -1)
   {
      fRnrCtx->SetGLCtxIdentity(fGLCtxId);
      fGLCtxId->DeleteDisplayLists();
   }
   TGLViewerBase::PreRender();
   
   fLightSet->StdSetupLights(fOverallBoundingBox, *fCamera, fDebugMode);
   fClipSet->SetupClips(fOverallBoundingBox);
}
void TGLViewer::DoDraw()
{
   
   
   
   
   
   fRedrawTimer->Stop();
   if (CurrentLock() != kDrawLock) {
      if ( ! TakeLock(kDrawLock)) {
         Error("TGLViewer::DoDraw", "viewer is %s", LockName(CurrentLock()));
         return;
      }
   }
   if (fGLDevice != -1) {
      Int_t viewport[4] = {};
      gGLManager->ExtractViewport(fGLDevice, viewport);
      SetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
   }
   TGLStopwatch timer;
   if (gDebug>2) {
      timer.Start();
   }
   
   fRnrCtx->SetRenderTimeout(fLOD == TGLRnrCtx::kLODHigh ?
                             fMaxSceneDrawTimeHQ :
                             fMaxSceneDrawTimeLQ);
   
   if (!fIsPrinting) PreDraw();
   PreRender();
   Render();
   DrawGuides();
   glClear(GL_DEPTH_BUFFER_BIT);
   RenderOverlay();
   DrawCameraMarkup();
   DrawDebugInfo();
   PostRender();
   PostDraw();
   ReleaseLock(kDrawLock);
   if (gDebug>2) {
      Info("TGLViewer::DoDraw()", "Took %f msec", timer.End());
   }
   
   if (CurrentCamera().UpdateInterest(kFALSE)) {
      
      ResetSceneInfos();
      fRedrawTimer->RequestDraw(0, fLOD);
   }
   if (fLOD != TGLRnrCtx::kLODHigh &&
       (fAction < kDragCameraRotate || fAction > kDragCameraDolly))
   {
      
      fRedrawTimer->RequestDraw(100, TGLRnrCtx::kLODHigh);
   }
}
void TGLViewer::DrawGuides()
{
   
   Bool_t disabled = kFALSE;
   if (fReferenceOn)
   {
      glDisable(GL_DEPTH_TEST);
      TGLUtil::DrawReferenceMarker(*fCamera, fReferencePos);
      disabled = kTRUE;
   }
   if (fDrawCameraCenter)
   {
      glDisable(GL_DEPTH_TEST);
      Float_t radius = fCamera->ViewportDeltaToWorld(TGLVertex3(fCamera->GetCenterVec()), 3, 3).Mag();
      const Float_t rgba[4] = { 0, 1, 1, 1.0 };
      TGLUtil::DrawSphere(fCamera->GetCenterVec(), radius, rgba);
      disabled = kTRUE;
   }
   if(fAxesDepthTest && disabled)
   {
      glEnable(GL_DEPTH_TEST);
      disabled = kFALSE;
   }
   else if (fAxesDepthTest == kFALSE && disabled == kFALSE)
   {
      glDisable(GL_DEPTH_TEST);
      disabled = kTRUE;
   }
   TGLUtil::DrawSimpleAxes(*fCamera, fOverallBoundingBox, fAxesType);
   if(disabled)
      glEnable(GL_DEPTH_TEST);
}
void TGLViewer::DrawCameraMarkup()
{
   
   if (fCameraMarkup && fCameraMarkup->Show())
   {
      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glLoadIdentity();
      const TGLRect& vp = fRnrCtx->RefCamera().RefViewport();
      gluOrtho2D(0., vp.Width(), 0., vp.Height());
      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glLoadIdentity();
      glDisable(GL_LIGHTING);
      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      glDisable(GL_DEPTH_TEST);
      fRnrCtx->RefCamera().Markup(fCameraMarkup);
      glEnable(GL_DEPTH_TEST);
      glEnable(GL_LIGHTING);
      glMatrixMode(GL_PROJECTION);
      glPopMatrix();
      glMatrixMode(GL_MODELVIEW);
      glPopMatrix();
   }
}
void TGLViewer::DrawDebugInfo()
{
   
   if (fDebugMode)
   {
      glDisable(GL_LIGHTING);
      CurrentCamera().DrawDebugAids();
      
      glColor3d(0.0, 1.0, 0.0);
      fOverallBoundingBox.Draw();
      
      glDisable(GL_DEPTH_TEST);
      Double_t size = fOverallBoundingBox.Extents().Mag() / 200.0;
      static Float_t white[4] = {1.0, 1.0, 1.0, 1.0};
      TGLUtil::DrawSphere(TGLVertex3(0.0, 0.0, 0.0), size, white);
      static Float_t green[4] = {0.0, 1.0, 0.0, 1.0};
      const TGLVertex3 & center = fOverallBoundingBox.Center();
      TGLUtil::DrawSphere(center, size, green);
      glEnable(GL_DEPTH_TEST);
      glEnable(GL_LIGHTING);
   }
}
void TGLViewer::PreDraw()
{
   
   MakeCurrent();
   
   if (!fInitGL) {
      InitGL();
   }
   
   Color_t ci = (fGLDevice != -1) ? gPad->GetFillColor() : fClearColor;
   TColor *color = gROOT->GetColor(ci);
   Float_t sc[3] = {1.f, 1.f, 1.f};
   if (color)
      color->GetRGB(sc[0], sc[1], sc[2]);
   glClearColor(sc[0], sc[1], sc[2], 1.);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   TGLUtil::CheckError("TGLViewer::PreDraw");
}
void TGLViewer::PostDraw()
{
   
   glFlush();
   SwapBuffers();
   
   
   TGLUtil::CheckError("TGLViewer::PostDraw");
}
void TGLViewer::MakeCurrent() const
{
   
   if (fGLDevice == -1)
      fGLWindow->MakeCurrent();
   else gGLManager->MakeCurrent(fGLDevice);
   
   
   
   
}
void TGLViewer::SwapBuffers() const
{
   
   if ( ! IsDrawOrSelectLock()) {
      Error("TGLViewer::SwapBuffers", "viewer is %s", LockName(CurrentLock()));
   }
   if (fGLDevice == -1)
      fGLWindow->SwapBuffers();
   else {
      gGLManager->ReadGLBuffer(fGLDevice);
      gGLManager->Flush(fGLDevice);
      gGLManager->MarkForDirectCopy(fGLDevice, kFALSE);
   }
}
Bool_t TGLViewer::RequestSelect(Int_t x, Int_t y, Bool_t trySecSel)
{
   
   
   
   
   
   
   if ( ! TakeLock(kSelectLock)) {
      return kFALSE;
   }
   if (!gVirtualX->IsCmdThread())
      return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%x)->DoSelect(%d, %d, %s)", this, x, y, trySecSel ? "kTRUE" : "kFALSE")));
   else
      return DoSelect(x, y, trySecSel);
}
Bool_t TGLViewer::DoSelect(Int_t x, Int_t y, Bool_t trySecSel)
{
   
   
   
   
   
   if (CurrentLock() != kSelectLock) {
      Error("TGLViewer::DoSelect", "expected kSelectLock, found %s", LockName(CurrentLock()));
      return kFALSE;
   }
   MakeCurrent();
   fRnrCtx->BeginSelection(x, y, 3);
   glRenderMode(GL_SELECT);
   PreRender();
   Render();
   PostRender();
   Int_t nHits = glRenderMode(GL_RENDER);
   fRnrCtx->EndSelection(nHits);
   
   if (gDebug > 0) Info("TGLViewer::DoSelect", "Primary select nHits=%d.", nHits);
   if (nHits > 0)
   {
      Int_t idx = 0;
      if (FindClosestRecord(fSelRec, idx))
      {
         if (fSelRec.GetTransparent())
         {
            TGLSelectRecord opaque;
            if (FindClosestOpaqueRecord(opaque, ++idx))
               fSelRec = opaque;
         }
         if (gDebug > 1) fSelRec.Print();
      }
   } else {
      fSelRec.Reset();
   }
   if ( ! trySecSel)
   {
      ReleaseLock(kSelectLock);
      return ! TGLSelectRecord::AreSameSelectionWise(fSelRec, fCurrentSelRec);
   }
   
   {
      if ( nHits < 1 || ! fSelRec.GetSceneInfo() || ! fSelRec.GetPhysShape() ||
           ! fSelRec.GetPhysShape()->GetLogical()->SupportsSecondarySelect())
      {
         if (gDebug > 0)
            Info("TGLViewer::DoSelect", "Skipping secondary selection "
                 "(nPrimHits=%d, sinfo=0x%lx, pshape=0x%lx).\n",
                 nHits, fSelRec.GetSceneInfo(), fSelRec.GetPhysShape());
         ReleaseLock(kSelectLock);
         fSecSelRec.Reset();
         return kFALSE;
      }
      TGLSceneInfo*    sinfo = fSelRec.GetSceneInfo();
      TGLSceneBase*    scene = sinfo->GetScene();
      TGLPhysicalShape* pshp = fSelRec.GetPhysShape();
      SceneInfoList_t foo;
      foo.push_back(sinfo);
      fScenes.swap(foo);
      fRnrCtx->BeginSelection(x, y, 3);
      fRnrCtx->SetSecSelection(kTRUE);
      glRenderMode(GL_SELECT);
      PreRender();
      fRnrCtx->SetSceneInfo(sinfo);
      scene->PreRender(*fRnrCtx);
      fRnrCtx->SetDrawPass(TGLRnrCtx::kPassFill);
      fRnrCtx->SetShapeLOD(TGLRnrCtx::kLODHigh);
      glPushName(pshp->ID());
      
      pshp->Draw(*fRnrCtx);
      glPopName();
      scene->PostRender(*fRnrCtx);
      fRnrCtx->SetSceneInfo(0);
      PostRender();
      Int_t nSecHits = glRenderMode(GL_RENDER);
      fRnrCtx->EndSelection(nSecHits);
      fScenes.swap(foo);
      if (gDebug > 0) Info("TGLViewer::DoSelect", "Secondary select nSecHits=%d.", nSecHits);
      ReleaseLock(kSelectLock);
      if (nSecHits > 0)
      {
         fSecSelRec = fSelRec;
         fSecSelRec.SetRawOnly(fRnrCtx->GetSelectBuffer()->RawRecord(0));
         if (gDebug > 1) fSecSelRec.Print();
         return kTRUE;
      } else {
         fSecSelRec.Reset();
         return kFALSE;
      }
   }
}
void TGLViewer::ApplySelection()
{
   
   
   
   fCurrentSelRec = fSelRec;
   TGLPhysicalShape * selPhys = fSelRec.GetPhysShape();
   fSelectedPShapeRef->SetPShape(selPhys);
   
   SelectionChanged();
   RequestDraw(TGLRnrCtx::kLODHigh);
}
Bool_t TGLViewer::RequestOverlaySelect(Int_t x, Int_t y)
{
   
   
   
   
   
   
   if ( ! TakeLock(kSelectLock)) {
      return kFALSE;
   }
   if (!gVirtualX->IsCmdThread())
      return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%x)->DoSelect(%d, %d)", this, x, y)));
   else
      return DoOverlaySelect(x, y);
}
Bool_t TGLViewer::DoOverlaySelect(Int_t x, Int_t y)
{
   
   
   if (CurrentLock() != kSelectLock) {
      Error("TGLViewer::DoOverlaySelect", "expected kSelectLock, found %s", LockName(CurrentLock()));
      return kFALSE;
   }
   MakeCurrent();
   fRnrCtx->BeginSelection(x, y, 3);
   glRenderMode(GL_SELECT);
   PreRenderOverlaySelection();
   RenderOverlay();
   PostRenderOverlaySelection();
   Int_t nHits = glRenderMode(GL_RENDER);
   fRnrCtx->EndSelection(nHits);
   
   TGLOverlayElement * selElm = 0;
   if (nHits > 0)
   {
      Int_t idx = 0;
      while (idx < nHits && FindClosestOverlayRecord(fOvlSelRec, idx))
      {
         TGLOverlayElement* el = fOvlSelRec.GetOvlElement();
         if (el == fCurrentOvlElm)
         {
            if (el->MouseStillInside(fOvlSelRec))
            {
               selElm = el;
               break;
            }
         }
         else if (el->MouseEnter(fOvlSelRec))
         {
            selElm = el;
            break;
         }
      }
   }
   else
   {
      fOvlSelRec.Reset();
   }
   ReleaseLock(kSelectLock);
   if (fCurrentOvlElm != selElm)
   {
      if (fCurrentOvlElm) fCurrentOvlElm->MouseLeave();
      fCurrentOvlElm = selElm;
      return kTRUE;
   }
   else
   {
      return kFALSE;
   }
}
void TGLViewer::SetViewport(Int_t x, Int_t y, Int_t width, Int_t height)
{
   
   
   if (IsLocked() && fGLDevice == -1) {
      Error("TGLViewer::SetViewport", "expected kUnlocked, found %s", LockName(CurrentLock()));
      return;
   }
   
   if (fViewport.X() == x && fViewport.Y() == y &&
       fViewport.Width() == width && fViewport.Height() == height) {
      return;
   }
   fViewport.Set(x, y, width, height);
   fCurrentCamera->SetViewport(fViewport);
   if (gDebug>2) {
      Info("TGLViewer::SetViewport", "updated - corner %d,%d dimensions %d,%d", x, y, width, height);
   }
}
TGLCamera& TGLViewer::RefCamera(ECameraType cameraType)
{
   
   
   switch(cameraType) {
      case kCameraPerspXOZ:
         return fPerspectiveCameraXOZ;
      case kCameraPerspYOZ:
         return fPerspectiveCameraYOZ;
      case kCameraPerspXOY:
         return fPerspectiveCameraXOY;
      case kCameraOrthoXOY:
         return fOrthoXOYCamera;
      case kCameraOrthoXOZ:
         return fOrthoXOZCamera;
      case kCameraOrthoZOY:
         return fOrthoZOYCamera;
      default:
         Error("TGLViewer::SetCurrentCamera", "invalid camera type");
         return *fCurrentCamera;
   }
}
void TGLViewer::SetCurrentCamera(ECameraType cameraType)
{
   
   
   
   if (IsLocked()) {
      Error("TGLViewer::SetCurrentCamera", "expected kUnlocked, found %s", LockName(CurrentLock()));
      return;
   }
   
   switch(cameraType) {
      case kCameraPerspXOZ: {
         fCurrentCamera = &fPerspectiveCameraXOZ;
         break;
      }
      case kCameraPerspYOZ: {
         fCurrentCamera = &fPerspectiveCameraYOZ;
         break;
      }
      case kCameraPerspXOY: {
         fCurrentCamera = &fPerspectiveCameraXOY;
         break;
      }
      case kCameraOrthoXOY: {
         fCurrentCamera = &fOrthoXOYCamera;
         break;
      }
      case kCameraOrthoXOZ: {
         fCurrentCamera = &fOrthoXOZCamera;
         break;
      }
      case kCameraOrthoZOY: {
         fCurrentCamera = &fOrthoZOYCamera;
         break;
      }
      default: {
         Error("TGLViewer::SetCurrentCamera", "invalid camera type");
         break;
      }
   }
   
   fCurrentCamera->SetViewport(fViewport);
   RefreshPadEditor(this);
   
   RequestDraw(TGLRnrCtx::kLODHigh);
}
void TGLViewer::SetOrthoCamera(ECameraType camera,
                                     Double_t zoom, Double_t dolly,
                                     Double_t center[3],
                                     Double_t hRotate, Double_t vRotate)
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   switch(camera) {
      case kCameraOrthoXOY: {
         fOrthoXOYCamera.Configure(zoom, dolly, center, hRotate, vRotate);
         if (fCurrentCamera == &fOrthoXOYCamera) {
            RequestDraw(TGLRnrCtx::kLODHigh);
         }
         break;
      }
      case kCameraOrthoXOZ: {
         fOrthoXOZCamera.Configure(zoom, dolly, center, hRotate, vRotate);
         if (fCurrentCamera == &fOrthoXOZCamera) {
            RequestDraw(TGLRnrCtx::kLODHigh);
         }
         break;
      }
      case kCameraOrthoZOY: {
         fOrthoZOYCamera.Configure(zoom, dolly, center, hRotate, vRotate);
         if (fCurrentCamera == &fOrthoZOYCamera) {
            RequestDraw(TGLRnrCtx::kLODHigh);
         }
         break;
      }
      default: {
         Error("TGLViewer::SetOrthoCamera", "invalid camera type");
         break;
      }
   }
}
void TGLViewer::SetPerspectiveCamera(ECameraType camera,
                                     Double_t fov, Double_t dolly,
                                     Double_t center[3],
                                     Double_t hRotate, Double_t vRotate)
{
   
   
   
   
   
   
   
   
   
   
   
   
   switch(camera) {
      case kCameraPerspXOZ: {
         fPerspectiveCameraXOZ.Configure(fov, dolly, center, hRotate, vRotate);
         if (fCurrentCamera == &fPerspectiveCameraXOZ) {
            RequestDraw(TGLRnrCtx::kLODHigh);
         }
         break;
      }
      case kCameraPerspYOZ: {
         fPerspectiveCameraYOZ.Configure(fov, dolly, center, hRotate, vRotate);
         if (fCurrentCamera == &fPerspectiveCameraYOZ) {
            RequestDraw(TGLRnrCtx::kLODHigh);
         }
         break;
      }
      case kCameraPerspXOY: {
         fPerspectiveCameraXOY.Configure(fov, dolly, center, hRotate, vRotate);
         if (fCurrentCamera == &fPerspectiveCameraXOY) {
            RequestDraw(TGLRnrCtx::kLODHigh);
         }
         break;
      }
      default: {
         Error("TGLViewer::SetPerspectiveCamera", "invalid camera type");
         break;
      }
   }
}
void TGLViewer::GetGuideState(Int_t & axesType, Bool_t & axesDepthTest, Bool_t & referenceOn, Double_t referencePos[3]) const
{
   
   axesType = fAxesType;
   axesDepthTest = fAxesDepthTest;
   referenceOn = fReferenceOn;
   referencePos[0] = fReferencePos.X();
   referencePos[1] = fReferencePos.Y();
   referencePos[2] = fReferencePos.Z();
}
void TGLViewer::SetGuideState(Int_t axesType, Bool_t axesDepthTest, Bool_t referenceOn, const Double_t referencePos[3])
{
   
   fAxesType    = axesType;
   fAxesDepthTest = axesDepthTest;
   fReferenceOn = referenceOn;
   if (referencePos)
      fReferencePos.Set(referencePos[0], referencePos[1], referencePos[2]);
   if (fGLDevice != -1)
      gGLManager->MarkForDirectCopy(fGLDevice, kTRUE);
   RequestDraw();
}
void TGLViewer::SetDrawCameraCenter(Bool_t x)
{
   
   fDrawCameraCenter = x;
   RequestDraw();
}
const TGLPhysicalShape * TGLViewer::GetSelected() const
{
   
   return fSelectedPShapeRef->GetPShape();
}
void TGLViewer::SelectionChanged()
{
   
   Emit("SelectionChanged()");
}
void TGLViewer::OverlayDragFinished()
{
   
   Emit("OverlayDragFinished()");
}
Int_t TGLViewer::DistancetoPrimitive(Int_t , Int_t )
{
   
   
   
   
   
   gPad->SetSelected(this);
   return 0;
}
void TGLViewer::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
   
   
   
   
   
   
   Event_t eventSt;
   eventSt.fX = px;
   eventSt.fY = py;
   eventSt.fState = 0;
   if (event != kKeyPress) {
      eventSt.fY -= Int_t((1 - gPad->GetHNDC() - gPad->GetYlowNDC()) * gPad->GetWh());
      eventSt.fX -= Int_t(gPad->GetXlowNDC() * gPad->GetWw());
   }
   switch (event) {
      case kMouseMotion:
         eventSt.fCode = kMouseMotion;
         eventSt.fType = kMotionNotify;
         HandleMotion(&eventSt);
         break;
      case kButton1Down:
      case kButton1Up:
      {
         eventSt.fCode = kButton1;
         eventSt.fType = event == kButton1Down ? kButtonPress:kButtonRelease;
         HandleButton(&eventSt);
      }
      break;
      case kButton2Down:
      case kButton2Up:
      {
         eventSt.fCode = kButton2;
         eventSt.fType = event == kButton2Down ? kButtonPress:kButtonRelease;
         HandleButton(&eventSt);
      }
      break;
      case kButton3Down:
      {
         eventSt.fState = kKeyShiftMask;
         eventSt.fCode = kButton1;
         eventSt.fType = kButtonPress;
         HandleButton(&eventSt);
      }
      break;
      case kButton3Up:
      {
         eventSt.fCode = kButton3;
         eventSt.fType = kButtonRelease;
         HandleButton(&eventSt);
      }
      break;
      case kButton1Double:
      case kButton2Double:
      case kButton3Double:
      {
         eventSt.fCode = kButton1Double ? kButton1 : kButton2Double ? kButton2 : kButton3;
         eventSt.fType = kButtonDoubleClick;
         HandleDoubleClick(&eventSt);
      }
      break;
      case kButton1Motion:
      case kButton2Motion:
      case kButton3Motion:
      {
         eventSt.fCode = event == kButton1Motion ? kButton1 : event == kButton2Motion ? kButton2 : kButton3;
         eventSt.fType = kMotionNotify;
         HandleMotion(&eventSt);
      }
      break;
      case kKeyPress: 
      {
         eventSt.fType = kGKeyPress;
         eventSt.fCode = py; 
         HandleKey(&eventSt);
      }
      break;
      case 6:
         if (CurrentCamera().Zoom(+50, kFALSE, kFALSE)) { 
            if (fGLDevice != -1) {
               gGLManager->MarkForDirectCopy(fGLDevice, kTRUE);
               gVirtualX->SetDrawMode(TVirtualX::kCopy);
            }
            RequestDraw();
         }
         break;
      case 5:
         if (CurrentCamera().Zoom(-50, kFALSE, kFALSE)) { 
            if (fGLDevice != -1) {
               gGLManager->MarkForDirectCopy(fGLDevice, kTRUE);
               gVirtualX->SetDrawMode(TVirtualX::kCopy);
            }
            RequestDraw();
         }
         break;
      case 7:
         eventSt.fState = kKeyShiftMask;
         eventSt.fCode = kButton1;
         eventSt.fType = kButtonPress;
         HandleButton(&eventSt);
         break;
      default:
      {
        
      }
   }
}
Bool_t TGLViewer::HandleEvent(Event_t *event)
{
   
   
   if (event->fType == kFocusIn) {
      if (fAction != kNone) {
         Error("TGLViewer::HandleEvent", "active action at focus in");
      }
      fAction = kDragNone;
   }
   if (event->fType == kFocusOut) {
      fAction = kDragNone;
   }
   return kTRUE;
}
Bool_t TGLViewer::HandleButton(Event_t * event)
{
   
   if (IsLocked()) {
      if (gDebug>2) {
         Info("TGLViewer::HandleButton", "ignored - viewer is %s", LockName(CurrentLock()));
      }
      return kFALSE;
   }
   
   if (event->fType == kButtonPress)
   {
      
      if (fAction != kNone)
         return kFALSE;
      if (fPushAction == kPushCamCenter)
      {
         fPushAction = kPushStd;
         RequestSelect(event->fX, event->fY);
         if (fSelRec.GetN() > 0)
         {
            TGLVector3 v(event->fX, event->fY, 0.5*fSelRec.GetMinZ());
            fCurrentCamera->WindowToViewport(v);
            v = fCurrentCamera->ViewportToWorld(v);
            fCurrentCamera->SetExternalCenter(kTRUE);
            fCurrentCamera->SetCenterVec(v.X(), v.Y(), v.Z());
            RequestDraw();
         }
         RefreshPadEditor(this);
         return kTRUE;
      }
      Bool_t grabPointer = kFALSE;
      Bool_t handled     = kFALSE;
      
      fActiveButtonID = event->fCode;
      if (fAction == kDragNone && fCurrentOvlElm)
      {
         if (fCurrentOvlElm->Handle(*fRnrCtx, fOvlSelRec, event))
         {
            handled     = kTRUE;
            grabPointer = kTRUE;
            fAction     = kDragOverlay;
            RequestDraw();
         }
      }
      if ( ! handled)
      {
         switch(event->fCode)
         {
            
            case kButton1:
            {
               if (event->fState & kKeyShiftMask) {
                  if (RequestSelect(event->fX, event->fY)) {
                     ApplySelection();
                     handled = kTRUE;
                  } else {
                     SelectionChanged(); 
                  }
               } else if (event->fState & kKeyControlMask) {
                  RequestSelect(event->fX, event->fY, kTRUE);
                  if (fSecSelRec.GetPhysShape() != 0) {
                     TGLLogicalShape& lshape = const_cast<TGLLogicalShape&>
                        (*fSecSelRec.GetPhysShape()->GetLogical());
                     lshape.ProcessSelection(*fRnrCtx, fSecSelRec);
                     handled = kTRUE;
                  }
               }
               if ( ! handled) {
                  fAction = kDragCameraRotate;
                  grabPointer = kTRUE;
               }
               break;
            }
               
            case kButton2:
            {
               fAction = kDragCameraTruck;
               grabPointer = kTRUE;
               break;
            }
               
            case kButton3:
            {
               
               if (event->fState & kKeyShiftMask) {
                  RequestSelect(event->fX, event->fY);
                  const TGLPhysicalShape * selected = fSelRec.GetPhysShape();
                  if (selected) {
                     if (!fContextMenu) {
                        fContextMenu = new TContextMenu("glcm", "GL Viewer Context Menu");
                     }
                     Int_t    x, y;
                     Window_t childdum;
                     gVirtualX->TranslateCoordinates(fGLWindow->GetId(),
                                                     gClient->GetDefaultRoot()->GetId(),
                                                     event->fX, event->fY, x, y, childdum);
                     selected->InvokeContextMenu(*fContextMenu, x, y);
                  }
               } else {
                  fAction = kDragCameraDolly;
                  grabPointer = kTRUE;
               }
               break;
            }
         }
      }
   }
   
   else if (event->fType == kButtonRelease)
   {
      if (fAction == kDragOverlay)
      {
         fCurrentOvlElm->Handle(*fRnrCtx, fOvlSelRec, event);
         OverlayDragFinished();
         if (RequestOverlaySelect(event->fX, event->fY))
            RequestDraw();
      }
      else if (fAction >= kDragCameraRotate && fAction <= kDragCameraDolly)
      {
         RequestDraw(TGLRnrCtx::kLODHigh);
      }
      
      
      switch(event->fCode) {
         
         
         
         case kButton5: {
            
            if (CurrentCamera().Zoom(+50, kFALSE, kFALSE)) { 
               RequestDraw();
            }
            break;
         }
         case kButton4: {
            
            if (CurrentCamera().Zoom(-50, kFALSE, kFALSE)) { 
               RequestDraw();
            }
            break;
         }
      }
      fAction = kDragNone;
      if (fGLDevice != -1)
         gGLManager->MarkForDirectCopy(fGLDevice, kFALSE);
   }
   return kTRUE;
}
Bool_t TGLViewer::HandleDoubleClick(Event_t *event)
{
   
   if (IsLocked()) {
      if (gDebug>3) {
         Info("TGLViewer::HandleDoubleClick", "ignored - viewer is %s", LockName(CurrentLock()));
      }
      return kFALSE;
   }
   
   
   if (event->fCode != kButton4 && event->fCode != kButton5) {
      if (fResetCameraOnDoubleClick) {
         ResetCurrentCamera();
         RequestDraw();
      }
   }
   return kTRUE;
}
Bool_t TGLViewer::HandleConfigureNotify(Event_t *event)
{
   
   if (IsLocked()) {
      if (gDebug > 0) {
         Info("TGLViewer::HandleConfigureNotify", "ignored - viewer is %s", LockName(CurrentLock()));
      }
      return kFALSE;
   }
   if (event) {
      SetViewport(event->fX, event->fY, event->fWidth, event->fHeight);
      RequestDraw(TGLRnrCtx::kLODMed);
   }
   return kTRUE;
}
Bool_t TGLViewer::HandleKey(Event_t *event)
{
   
   if (IsLocked()) {
      if (gDebug>3) {
         Info("TGLViewer::HandleKey", "ignored - viewer is %s", LockName(CurrentLock()));
      }
      return kFALSE;
   }
   char tmp[10] = {0};
   UInt_t keysym = 0;
   if (fGLDevice == -1)
      gVirtualX->LookupString(event, tmp, sizeof(tmp), keysym);
   else
      keysym = event->fCode;
   fRnrCtx->SetEventKeySym(keysym);
   Bool_t redraw = kFALSE;
   if (fCurrentOvlElm && fCurrentOvlElm->Handle(*fRnrCtx, fOvlSelRec, event))
   {
      redraw = kTRUE;
   }
   else
   {
      switch (keysym)
      {
         case kKey_R:
         case kKey_r:
            SetStyle(TGLRnrCtx::kFill);
            if (fClearColor == 0) {
               fClearColor = 1; 
               RefreshPadEditor(this);
            }
            redraw = kTRUE;
            break;
         case kKey_W:
         case kKey_w:
            SetStyle(TGLRnrCtx::kWireFrame);
            if (fClearColor == 0) {
               fClearColor = 1; 
               RefreshPadEditor(this);
            }
            redraw = kTRUE;
            break;
         case kKey_T:
         case kKey_t:
            SetStyle(TGLRnrCtx::kOutline);
            if (fClearColor == 1) {
               fClearColor = 0; 
               RefreshPadEditor(this);
            }
            redraw = kTRUE;
            break;
            
         case kKey_Plus:
         case kKey_J:
         case kKey_j:
            redraw = CurrentCamera().Dolly(10, event->fState & kKeyControlMask,
                                           event->fState & kKeyShiftMask); 
            break;
         case kKey_Minus:
         case kKey_K:
         case kKey_k:
            redraw = CurrentCamera().Dolly(-10, event->fState & kKeyControlMask,
                                           event->fState & kKeyShiftMask); 
            break;
         case kKey_Up:
            redraw = CurrentCamera().Truck(fViewport.CenterX(), fViewport.CenterY(), 0, 5);
            break;
         case kKey_Down:
            redraw = CurrentCamera().Truck(fViewport.CenterX(), fViewport.CenterY(), 0, -5);
            break;
         case kKey_Left:
            redraw = CurrentCamera().Truck(fViewport.CenterX(), fViewport.CenterY(), -5, 0);
            break;
         case kKey_Right:
            redraw = CurrentCamera().Truck(fViewport.CenterX(), fViewport.CenterY(), 5, 0);
            break;
         case kKey_Home:
            ResetCurrentCamera();
            redraw = kTRUE;
            break;
            
         case kKey_D:
         case kKey_d:
            fDebugMode = !fDebugMode;
            redraw = kTRUE;
            Info("OpenGL viewer debug mode : ", fDebugMode ? "ON" : "OFF");
            break;
            
         case kKey_Space:
            if (fDebugMode) {
               Info("OpenGL viewer FORCED rebuild", "");
               UpdateScene();
            }
         default:;
      } 
   }
   if (redraw) {
      if (fGLDevice != -1)
         gGLManager->MarkForDirectCopy(fGLDevice, kTRUE);
      RequestDraw();
   }
   return kTRUE;
}
Bool_t TGLViewer::HandleMotion(Event_t * event)
{
   
   if (IsLocked()) {
      if (gDebug>3) {
         Info("TGLViewer::HandleMotion", "ignored - viewer is %s", LockName(CurrentLock()));
      }
      return kFALSE;
   }
   assert (event); 
   Bool_t processed = kFALSE, changed = kFALSE;
   Short_t lod = TGLRnrCtx::kLODMed;
   
   Int_t  xDelta = event->fX - fLastPos.fX;
   Int_t  yDelta = event->fY - fLastPos.fY;
   Bool_t mod1   = event->fState & kKeyControlMask;
   Bool_t mod2   = event->fState & kKeyShiftMask;
   if (fAction == kDragNone)
   {
      changed = RequestOverlaySelect(event->fX, event->fY);
      if (fCurrentOvlElm)
         processed = fCurrentOvlElm->Handle(*fRnrCtx, fOvlSelRec, event);
      lod = TGLRnrCtx::kLODHigh;
   } else if (fAction == kDragCameraRotate) {
      processed = CurrentCamera().Rotate(xDelta, -yDelta, mod1, mod2);
   } else if (fAction == kDragCameraTruck) {
      processed = CurrentCamera().Truck(xDelta, -yDelta, mod1, mod2);
   } else if (fAction == kDragCameraDolly) {
      processed = CurrentCamera().Dolly(xDelta, mod1, mod2);
   } else if (fAction == kDragOverlay) {
      processed = fCurrentOvlElm->Handle(*fRnrCtx, fOvlSelRec, event);
   }
   fLastPos.fX = event->fX;
   fLastPos.fY = event->fY;
   if (processed || changed) {
      if (fGLDevice != -1) {
         gGLManager->MarkForDirectCopy(fGLDevice, kTRUE);
         gVirtualX->SetDrawMode(TVirtualX::kCopy);
      }
      RequestDraw(lod);
   }
   return processed;
}
Bool_t TGLViewer::HandleExpose(Event_t * event)
{
   
   if (event->fCount != 0) return kTRUE;
   if (IsLocked()) {
      if (gDebug > 0) {
         Info("TGLViewer::HandleExpose", "ignored - viewer is %s", LockName(CurrentLock()));
      }
      return kFALSE;
   }
   fRedrawTimer->RequestDraw(20, TGLRnrCtx::kLODHigh);
   return kTRUE;
}
void TGLViewer::Repaint()
{
   
   if (IsLocked()) {
      if (gDebug > 0) {
         Info("TGLViewer::HandleExpose", "ignored - viewer is %s", LockName(CurrentLock()));
      }
      return;
   }
   fRedrawTimer->RequestDraw(20, TGLRnrCtx::kLODHigh);
}
void TGLViewer::PrintObjects()
{
   
   TGLOutput::Capture(*this);
}
Last update: Thu Jan 17 08:52:29 2008
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.