#include "TGLViewer.h"
#include "TGLIncludes.h"
#include "TGLStopwatch.h"
#include "TGLRnrCtx.h"
#include "TGLSelectBuffer.h"
#include "TGLLightSet.h"
#include "TGLManipSet.h"
#include "TGLCameraOverlay.h"
#include "TGLAutoRotator.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 "TROOT.h"
#include "TVirtualMutex.h"
#include "TVirtualPad.h"
#include "TVirtualX.h"
#include "TMath.h"
#include "TColor.h"
#include "TError.h"
#include "TClass.h"
#include "TROOT.h"
#include "TEnv.h"
#include "Buttons.h"
#include "GuiTypes.h"
#include "TVirtualGL.h"
#include "TGLWidget.h"
#include "TGLFBO.h"
#include "TGLViewerEditor.h"
#include "TGedEditor.h"
#include "TGLPShapeObj.h"
#include "KeySymbols.h"
#include "TContextMenu.h"
#include "TImage.h"
#include <stdexcept>
#ifndef GL_BGRA
#define GL_BGRA GL_BGRA_EXT
#endif
ClassImp(TGLViewer);
TGLColorSet TGLViewer::fgDefaultColorSet;
Bool_t TGLViewer::fgUseDefaultColorSetForNewViewers = kFALSE;
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 (TGLOrthoCamera::kXOY, TGLVector3( 0.0, 0.0, 1.0), TGLVector3(0.0, 1.0, 0.0)),
fOrthoXOZCamera (TGLOrthoCamera::kXOZ, TGLVector3( 0.0,-1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)),
fOrthoZOYCamera (TGLOrthoCamera::kZOY, TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)),
fOrthoXnOYCamera(TGLOrthoCamera::kXnOY, TGLVector3( 0.0, 0.0,-1.0), TGLVector3(0.0, 1.0, 0.0)),
fOrthoXnOZCamera(TGLOrthoCamera::kXnOZ, TGLVector3( 0.0, 1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)),
fOrthoZnOYCamera(TGLOrthoCamera::kZnOY, TGLVector3( 1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)),
fCurrentCamera(&fPerspectiveCameraXOZ),
fAutoRotator(0),
fStereo (kFALSE),
fStereoQuadBuf (kFALSE),
fStereoZeroParallax (0.03f),
fStereoEyeOffsetFac (1.0f),
fStereoFrustumAsymFac (1.0f),
fLightSet (0),
fClipSet (0),
fSelectedPShapeRef (0),
fCurrentOvlElm (0),
fEventHandler(0),
fGedEditor(0),
fPShapeWrap(0),
fPushAction(kPushStd), fDragAction(kDragNone),
fRedrawTimer(0),
fMaxSceneDrawTimeHQ(5000),
fMaxSceneDrawTimeLQ(100),
fPointScale (1), fLineScale(1), fSmoothPoints(kFALSE), fSmoothLines(kFALSE),
fAxesType(TGLUtil::kAxesNone),
fAxesDepthTest(kTRUE),
fReferenceOn(kFALSE),
fReferencePos(0.0, 0.0, 0.0),
fDrawCameraCenter(kFALSE),
fCameraOverlay(0),
fSmartRefresh(kFALSE),
fDebugMode(kFALSE),
fIsPrinting(kFALSE),
fPictureFileName("viewer.jpg"),
fFader(0),
fGLWidget(0),
fGLDevice(-1),
fGLCtxId(0),
fIgnoreSizesOnUpdate(kFALSE),
fResetCamerasOnUpdate(kTRUE),
fResetCamerasOnNextUpdate(kFALSE)
{
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 (TGLOrthoCamera::kXOY, TGLVector3( 0.0, 0.0, 1.0), TGLVector3(0.0, 1.0, 0.0)),
fOrthoXOZCamera (TGLOrthoCamera::kXOZ, TGLVector3( 0.0,-1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)),
fOrthoZOYCamera (TGLOrthoCamera::kZOY, TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)),
fOrthoXnOYCamera(TGLOrthoCamera::kXnOY, TGLVector3( 0.0, 0.0,-1.0), TGLVector3(0.0, 1.0, 0.0)),
fOrthoXnOZCamera(TGLOrthoCamera::kXnOZ, TGLVector3( 0.0, 1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)),
fOrthoZnOYCamera(TGLOrthoCamera::kZnOY, TGLVector3( 1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)),
fCurrentCamera(&fPerspectiveCameraXOZ),
fAutoRotator(0),
fStereo (kFALSE),
fStereoQuadBuf (kFALSE),
fStereoZeroParallax (0.03f),
fStereoEyeOffsetFac (1.0f),
fStereoFrustumAsymFac (1.0f),
fLightSet (0),
fClipSet (0),
fSelectedPShapeRef (0),
fCurrentOvlElm (0),
fEventHandler(0),
fGedEditor(0),
fPShapeWrap(0),
fPushAction(kPushStd), fDragAction(kDragNone),
fRedrawTimer(0),
fMaxSceneDrawTimeHQ(5000),
fMaxSceneDrawTimeLQ(100),
fPointScale (1), fLineScale(1), fSmoothPoints(kFALSE), fSmoothLines(kFALSE),
fAxesType(TGLUtil::kAxesNone),
fAxesDepthTest(kTRUE),
fReferenceOn(kFALSE),
fReferencePos(0.0, 0.0, 0.0),
fDrawCameraCenter(kFALSE),
fCameraOverlay(0),
fSmartRefresh(kFALSE),
fDebugMode(kFALSE),
fIsPrinting(kFALSE),
fPictureFileName("viewer.jpg"),
fFader(0),
fGLWidget(0),
fGLDevice(fPad->GetGLDevice()),
fGLCtxId(0),
fIgnoreSizesOnUpdate(kFALSE),
fResetCamerasOnUpdate(kTRUE),
fResetCamerasOnNextUpdate(kFALSE)
{
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;
AddOverlayElement(fClipSet);
fSelectedPShapeRef = new TGLManipSet;
fSelectedPShapeRef->SetDrawBBox(kTRUE);
AddOverlayElement(fSelectedPShapeRef);
fPShapeWrap = new TGLPShapeObj(0, this);
fLightColorSet.StdLightBackground();
if (fgUseDefaultColorSetForNewViewers) {
fRnrCtx->ChangeBaseColorSet(&fgDefaultColorSet);
} else {
if (fPad) {
fRnrCtx->ChangeBaseColorSet(&fLightColorSet);
fLightColorSet.Background().SetColor(fPad->GetFillColor());
fLightColorSet.Foreground().SetColor(fPad->GetLineColor());
} else {
fRnrCtx->ChangeBaseColorSet(&fDarkColorSet);
}
}
fCameraOverlay = new TGLCameraOverlay(kFALSE, kFALSE);
AddOverlayElement(fCameraOverlay);
fRedrawTimer = new TGLRedrawTimer(*this);
}
TGLViewer::~TGLViewer()
{
delete fAutoRotator;
delete fLightSet;
delete fContextMenu;
delete fRedrawTimer;
if (fEventHandler) {
if (fGLWidget)
fGLWidget->SetEventHandler(0);
delete fEventHandler;
}
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(Bool_t redraw)
{
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;
if (redraw)
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);
fOrthoXnOYCamera.Setup(box, reset);
fOrthoXnOZCamera.Setup(box, reset);
fOrthoZnOYCamera.Setup(box, reset);
}
}
void TGLViewer::PostSceneBuildSetup(Bool_t resetCameras)
{
MergeSceneBBoxes(fOverallBoundingBox);
SetupCameras(resetCameras);
fReferencePos.Set(fOverallBoundingBox.Center());
RefreshPadEditor(this);
}
void TGLViewer::InitGL()
{
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glClearColor(0.f, 0.f, 0.f, 0.f);
glClearDepth(1.0);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
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);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
TGLUtil::CheckError("TGLViewer::InitGL");
}
void TGLViewer::RequestDraw(Short_t LODInput)
{
fRedrawTimer->Stop();
if ((!fGLWidget && fGLDevice == -1) || (fGLWidget && !fGLWidget->IsMapped()))
{
return;
}
if ( ! TakeLock(kDrawLock)) {
if (gDebug>3) {
Info("TGLViewer::RequestDraw", "viewer locked - requesting another draw.");
}
fRedrawTimer->RequestDraw(100, LODInput);
return;
}
fLOD = LODInput;
if (!gVirtualX->IsCmdThread())
gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw()", (ULong_t)this));
else
DoDraw();
}
void TGLViewer::SetupClipObject()
{
if (GetClipAutoUpdate())
{
fClipSet->SetupCurrentClip(fOverallBoundingBox);
}
else
{
fClipSet->SetupCurrentClipIfInvalid(fOverallBoundingBox);
}
}
void TGLViewer::PreRender()
{
fCamera = fCurrentCamera;
fClip = fClipSet->GetCurrentClip();
if (fGLDevice != -1)
{
fRnrCtx->SetGLCtxIdentity(fGLCtxId);
fGLCtxId->DeleteGLResources();
}
TGLUtil::SetPointSizeScale(fPointScale * fRnrCtx->GetRenderScale());
TGLUtil::SetLineWidthScale(fLineScale * fRnrCtx->GetRenderScale());
if (fSmoothPoints) glEnable(GL_POINT_SMOOTH); else glDisable(GL_POINT_SMOOTH);
if (fSmoothLines) glEnable(GL_LINE_SMOOTH); else glDisable(GL_LINE_SMOOTH);
if (fSmoothPoints || fSmoothLines)
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
}
else
{
glDisable(GL_BLEND);
}
TGLViewerBase::PreRender();
fLightSet->StdSetupLights(fOverallBoundingBox, *fCamera, fDebugMode);
}
void TGLViewer::Render()
{
TGLViewerBase::Render();
DrawGuides();
RenderOverlay(TGLOverlayElement::kAllVisible, kFALSE);
if ( ! fRnrCtx->Selection())
{
RenderSelectedForHighlight();
}
glClear(GL_DEPTH_BUFFER_BIT);
DrawDebugInfo();
}
void TGLViewer::PostRender()
{
TGLViewerBase::PostRender();
TGLUtil::SetPointSizeScale(1);
TGLUtil::SetLineWidthScale(1);
}
void TGLViewer::DoDraw(Bool_t swap_buffers)
{
R__LOCKGUARD2(gROOTMutex);
fRedrawTimer->Stop();
if (CurrentLock() != kDrawLock) {
if ( ! TakeLock(kDrawLock)) {
Error("TGLViewer::DoDraw", "viewer is %s", LockName(CurrentLock()));
return;
}
}
TUnlocker ulck(this);
if (fGLDevice == -1 && (fViewport.Width() <= 1 || fViewport.Height() <= 1)) {
if (gDebug > 2) {
Info("TGLViewer::DoDraw()", "zero surface area, draw skipped.");
}
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 (fStereo && fCurrentCamera->IsPerspective() && !fRnrCtx->GetGrabImage() &&
!fIsPrinting)
{
DoDrawStereo(swap_buffers);
}
else
{
DoDrawMono(swap_buffers);
}
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 &&
(fDragAction < kDragCameraRotate || fDragAction > kDragCameraDolly))
{
fRedrawTimer->RequestDraw(100, TGLRnrCtx::kLODHigh);
}
}
void TGLViewer::DoDrawMono(Bool_t swap_buffers)
{
MakeCurrent();
if (!fIsPrinting) PreDraw();
PreRender();
fRnrCtx->StartStopwatch();
if (fFader < 1)
{
Render();
}
fRnrCtx->StopStopwatch();
PostRender();
if (fFader > 0)
{
FadeView(fFader);
}
PostDraw();
if (swap_buffers)
{
SwapBuffers();
}
}
void TGLViewer::DoDrawStereo(Bool_t swap_buffers)
{
TGLPerspectiveCamera &c = *dynamic_cast<TGLPerspectiveCamera*>(fCurrentCamera);
Float_t gl_near, gl_far, zero_p_dist;
Float_t h_half, w_half;
Float_t x_len_at_zero_parallax;
Float_t stereo_offset;
Float_t frustum_asym;
MakeCurrent();
if (fStereoQuadBuf)
{
glDrawBuffer(GL_BACK_LEFT);
}
else
{
glScissor(0, 0, fViewport.Width(), fViewport.Height());
glEnable(GL_SCISSOR_TEST);
}
PreDraw();
PreRender();
gl_near = c.GetNearClip();
gl_far = c.GetFarClip();
zero_p_dist = gl_near + fStereoZeroParallax*(gl_far-gl_near);
h_half = TMath::Tan(0.5*TMath::DegToRad()*c.GetFOV()) * gl_near;
w_half = h_half * fViewport.Aspect();
x_len_at_zero_parallax = 2.0f * w_half * zero_p_dist / gl_near;
stereo_offset = 0.035f * x_len_at_zero_parallax * fStereoEyeOffsetFac;
frustum_asym = stereo_offset * gl_near / zero_p_dist * fStereoFrustumAsymFac;
TGLMatrix abs_trans(c.RefCamBase());
abs_trans *= c.RefCamTrans();
TGLVector3 left_vec = abs_trans.GetBaseVec(2);
glTranslatef(stereo_offset*left_vec[0], stereo_offset*left_vec[1], stereo_offset*left_vec[2]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-w_half + frustum_asym, w_half + frustum_asym,
-h_half, h_half, gl_near, gl_far);
glMatrixMode(GL_MODELVIEW);
fRnrCtx->StartStopwatch();
if (fFader < 1)
{
Render();
}
fRnrCtx->StopStopwatch();
PostRender();
if (fFader > 0)
{
FadeView(fFader);
}
PostDraw();
if (fStereoQuadBuf)
{
glDrawBuffer(GL_BACK_RIGHT);
}
else
{
glScissor(fViewport.Width(), 0, fViewport.Width(), fViewport.Height());
}
PreDraw();
PreRender();
if ( ! fStereoQuadBuf)
{
glViewport(fViewport.Width(), 0, fViewport.Width(), fViewport.Height());
}
glTranslatef(-stereo_offset*left_vec[0], -stereo_offset*left_vec[1], -stereo_offset*left_vec[2]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-w_half - frustum_asym, w_half - frustum_asym,
-h_half, h_half, gl_near, gl_far);
glMatrixMode(GL_MODELVIEW);
fRnrCtx->StartStopwatch();
if (fFader < 1)
{
Render();
}
fRnrCtx->StopStopwatch();
PostRender();
if (fFader > 0)
{
FadeView(fFader);
}
PostDraw();
if (swap_buffers)
{
SwapBuffers();
}
if (fStereoQuadBuf)
{
glDrawBuffer(GL_BACK);
}
else
{
glDisable(GL_SCISSOR_TEST);
glViewport(0, 0, fViewport.Width(), fViewport.Height());
}
}
Bool_t TGLViewer::SavePicture()
{
return SavePicture(fPictureFileName);
}
Bool_t TGLViewer::SavePicture(const TString &fileName)
{
if (fileName.EndsWith(".eps"))
{
return TGLOutput::Capture(*this, TGLOutput::kEPS_BSP, fileName.Data());
}
else if (fileName.EndsWith(".pdf"))
{
return TGLOutput::Capture(*this, TGLOutput::kPDF_BSP, fileName.Data());
}
else
{
if (GLEW_EXT_framebuffer_object && gEnv->GetValue("OpenGL.SavePicturesViaFBO", 1))
{
return SavePictureUsingFBO(fileName, fViewport.Width(), fViewport.Height(), kFALSE);
}
else
{
return SavePictureUsingBB(fileName);
}
}
}
Bool_t TGLViewer::SavePictureUsingBB(const TString &fileName)
{
static const TString eh("TGLViewer::SavePictureUsingBB");
if (! fileName.EndsWith(".gif") && ! fileName.Contains(".gif+") &&
! fileName.EndsWith(".jpg") && ! fileName.EndsWith(".png"))
{
Warning(eh, "file %s cannot be saved with this extension.", fileName.Data());
return kFALSE;
}
if ( ! TakeLock(kDrawLock)) {
Error(eh, "viewer locked - try later.");
return kFALSE;
}
TUnlocker ulck(this);
fLOD = TGLRnrCtx::kLODHigh;
fRnrCtx->SetGrabImage(kTRUE);
if (!gVirtualX->IsCmdThread())
gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this));
else
DoDraw(kFALSE);
fRnrCtx->SetGrabImage(kFALSE);
glReadBuffer(GL_BACK);
UChar_t* xx = new UChar_t[4 * fViewport.Width() * fViewport.Height()];
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, fViewport.Width(), fViewport.Height(),
GL_BGRA, GL_UNSIGNED_BYTE, xx);
std::auto_ptr<TImage> image(TImage::Create());
image->FromGLBuffer(xx, fViewport.Width(), fViewport.Height());
image->WriteImage(fileName);
delete [] xx;
return kTRUE;
}
Bool_t TGLViewer::SavePictureUsingFBO(const TString &fileName, Int_t w, Int_t h,
Float_t pixel_object_scale)
{
static const TString eh("TGLViewer::SavePictureUsingFBO");
if (! fileName.EndsWith(".gif") && ! fileName.Contains(".gif+") &&
! fileName.EndsWith(".jpg") && ! fileName.EndsWith(".png"))
{
Warning(eh, "file %s cannot be saved with this extension.", fileName.Data());
return kFALSE;
}
if ( ! TakeLock(kDrawLock)) {
Error(eh, "viewer locked - try later.");
return kFALSE;
}
TUnlocker ulck(this);
MakeCurrent();
TGLFBO *fbo = new TGLFBO();
try
{
fbo->Init(w, h, fGLWidget->GetPixelFormat()->GetSamples());
}
catch (std::runtime_error& exc)
{
Error(eh, "%s",exc.what());
if (gEnv->GetValue("OpenGL.SavePictureFallbackToBB", 1)) {
Info(eh, "Falling back to saving image via back-buffer. Window must be fully visible.");
if (w != fViewport.Width() || h != fViewport.Height())
Warning(eh, "Back-buffer does not support image scaling, window size will be used.");
return SavePictureUsingBB(fileName);
} else {
return kFALSE;
}
}
TGLRect old_vp(fViewport);
SetViewport(0, 0, w, h);
Float_t old_scale = 1;
if (pixel_object_scale != 0)
{
old_scale = fRnrCtx->GetRenderScale();
fRnrCtx->SetRenderScale(old_scale * pixel_object_scale);
}
fbo->Bind();
fLOD = TGLRnrCtx::kLODHigh;
fRnrCtx->SetGrabImage(kTRUE);
if (!gVirtualX->IsCmdThread())
gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this));
else
DoDraw(kFALSE);
fRnrCtx->SetGrabImage(kFALSE);
fbo->Unbind();
fbo->SetAsReadBuffer();
UChar_t* xx = new UChar_t[4 * fViewport.Width() * fViewport.Height()];
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, fViewport.Width(), fViewport.Height(),
GL_BGRA, GL_UNSIGNED_BYTE, xx);
std::auto_ptr<TImage> image(TImage::Create());
image->FromGLBuffer(xx, fViewport.Width(), fViewport.Height());
image->WriteImage(fileName);
delete [] xx;
delete fbo;
if (pixel_object_scale != 0)
{
fRnrCtx->SetRenderScale(old_scale);
}
SetViewport(old_vp);
return kTRUE;
}
TImage* TGLViewer::GetPictureUsingBB()
{
static const TString eh("TGLViewer::GetPictureUsingBB");
if ( ! TakeLock(kDrawLock)) {
Error(eh, "viewer locked - try later.");
return NULL;
}
TUnlocker ulck(this);
fLOD = TGLRnrCtx::kLODHigh;
fRnrCtx->SetGrabImage(kTRUE);
if (!gVirtualX->IsCmdThread())
gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this));
else
DoDraw(kFALSE);
fRnrCtx->SetGrabImage(kFALSE);
glReadBuffer(GL_BACK);
UChar_t* xx = new UChar_t[4 * fViewport.Width() * fViewport.Height()];
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, fViewport.Width(), fViewport.Height(),
GL_BGRA, GL_UNSIGNED_BYTE, xx);
TImage *image(TImage::Create());
image->FromGLBuffer(xx, fViewport.Width(), fViewport.Height());
delete [] xx;
return image;
}
TImage* TGLViewer::GetPictureUsingFBO(Int_t w, Int_t h,Float_t pixel_object_scale)
{
static const TString eh("TGLViewer::GetPictureUsingFBO");
if ( ! TakeLock(kDrawLock)) {
Error(eh, "viewer locked - try later.");
return NULL;
}
TUnlocker ulck(this);
MakeCurrent();
TGLFBO *fbo = new TGLFBO();
try
{
fbo->Init(w, h, fGLWidget->GetPixelFormat()->GetSamples());
}
catch (std::runtime_error& exc)
{
Error(eh, "%s",exc.what());
if (gEnv->GetValue("OpenGL.GetPictureFallbackToBB", 1)) {
Info(eh, "Falling back to saving image via back-buffer. Window must be fully visible.");
if (w != fViewport.Width() || h != fViewport.Height())
Warning(eh, "Back-buffer does not support image scaling, window size will be used.");
return GetPictureUsingBB();
} else {
return NULL;
}
}
TGLRect old_vp(fViewport);
SetViewport(0, 0, w, h);
Float_t old_scale = 1;
if (pixel_object_scale != 0)
{
old_scale = fRnrCtx->GetRenderScale();
fRnrCtx->SetRenderScale(old_scale * pixel_object_scale);
}
fbo->Bind();
fLOD = TGLRnrCtx::kLODHigh;
fRnrCtx->SetGrabImage(kTRUE);
if (!gVirtualX->IsCmdThread())
gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this));
else
DoDraw(kFALSE);
fRnrCtx->SetGrabImage(kFALSE);
fbo->Unbind();
fbo->SetAsReadBuffer();
UChar_t* xx = new UChar_t[4 * fViewport.Width() * fViewport.Height()];
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, fViewport.Width(), fViewport.Height(),
GL_BGRA, GL_UNSIGNED_BYTE, xx);
TImage *image(TImage::Create());
image->FromGLBuffer(xx, fViewport.Width(), fViewport.Height());
delete [] xx;
delete fbo;
return image;
}
Bool_t TGLViewer::SavePictureWidth(const TString &fileName, Int_t width,
Bool_t pixel_object_scale)
{
Float_t scale = Float_t(width) / fViewport.Width();
Int_t height = TMath::Nint(scale*fViewport.Height());
return SavePictureUsingFBO(fileName, width, height, pixel_object_scale ? scale : 0);
}
Bool_t TGLViewer::SavePictureHeight(const TString &fileName, Int_t height,
Bool_t pixel_object_scale)
{
Float_t scale = Float_t(height) / fViewport.Height();
Int_t width = TMath::Nint(scale*fViewport.Width());
return SavePictureUsingFBO(fileName, width, height, pixel_object_scale ? scale : 0);
}
Bool_t TGLViewer::SavePictureScale (const TString &fileName, Float_t scale,
Bool_t pixel_object_scale)
{
Int_t w = TMath::Nint(scale*fViewport.Width());
Int_t h = TMath::Nint(scale*fViewport.Height());
return SavePictureUsingFBO(fileName, w, h, pixel_object_scale ? scale : 0);
}
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 UChar_t rgba[4] = { 0, 255, 255, 255 };
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::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;
TGLUtil::DrawSphere(TGLVertex3(0.0, 0.0, 0.0), size, TGLUtil::fgWhite);
const TGLVertex3 & center = fOverallBoundingBox.Center();
TGLUtil::DrawSphere(center, size, TGLUtil::fgGreen);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
}
}
void TGLViewer::PreDraw()
{
InitGL();
{
Color_t ci = (fGLDevice != -1) ? gPad->GetFillColor() : fRnrCtx->ColorSet().Background().GetColorIndex();
TColor *color = gROOT->GetColor(ci);
Float_t rgb[3];
if (color)
color->GetRGB(rgb[0], rgb[1], rgb[2]);
else
rgb[0] = rgb[1] = rgb[2] = 0.0f;
glClearColor(rgb[0], rgb[1], rgb[2], 0.0f);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
TGLUtil::CheckError("TGLViewer::PreDraw");
}
void TGLViewer::PostDraw()
{
glFlush();
TGLUtil::CheckError("TGLViewer::PostDraw");
}
void TGLViewer::FadeView(Float_t alpha)
{
static const Float_t z = -1.0f;
glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
{
TGLCapabilitySwitch blend(GL_BLEND, kTRUE);
TGLCapabilitySwitch light(GL_LIGHTING, kFALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
TGLUtil::ColorAlpha(fRnrCtx->ColorSet().Background(), alpha);
glBegin(GL_QUADS);
glVertex3f(-1, -1, z); glVertex3f( 1, -1, z);
glVertex3f( 1, 1, z); glVertex3f(-1, 1, z);
glEnd();
}
glMatrixMode(GL_PROJECTION); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glPopMatrix();
}
void TGLViewer::MakeCurrent() const
{
if (fGLDevice == -1)
fGLWidget->MakeCurrent();
else
gGLManager->MakeCurrent(fGLDevice);
}
void TGLViewer::SwapBuffers() const
{
if ( ! IsDrawOrSelectLock()) {
Error("TGLViewer::SwapBuffers", "viewer is %s", LockName(CurrentLock()));
}
if (fGLDevice == -1)
fGLWidget->SwapBuffers();
else {
gGLManager->ReadGLBuffer(fGLDevice);
gGLManager->Flush(fGLDevice);
gGLManager->MarkForDirectCopy(fGLDevice, kFALSE);
}
}
Bool_t TGLViewer::RequestSelect(Int_t x, Int_t y)
{
if ( ! TakeLock(kSelectLock)) {
return kFALSE;
}
if (!gVirtualX->IsCmdThread())
return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoSelect(%d, %d)", (ULong_t)this, x, y)));
else
return DoSelect(x, y);
}
Bool_t TGLViewer::DoSelect(Int_t x, Int_t y)
{
R__LOCKGUARD2(gROOTMutex);
if (CurrentLock() != kSelectLock) {
Error("TGLViewer::DoSelect", "expected kSelectLock, found %s", LockName(CurrentLock()));
return kFALSE;
}
TGLUtil::PointToViewport(x, y);
TUnlocker ulck(this);
MakeCurrent();
fRnrCtx->BeginSelection(x, y, TGLUtil::GetPickingRadius());
glRenderMode(GL_SELECT);
PreRender();
TGLViewerBase::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() && fRnrCtx->SelectTransparents() != TGLRnrCtx::kIfClosest)
{
TGLSelectRecord opaque;
if (FindClosestOpaqueRecord(opaque, ++idx))
fSelRec = opaque;
else if (fRnrCtx->SelectTransparents() == TGLRnrCtx::kNever)
fSelRec.Reset();
}
if (gDebug > 1) fSelRec.Print();
}
} else {
fSelRec.Reset();
}
ReleaseLock(kSelectLock);
return ! TGLSelectRecord::AreSameSelectionWise(fSelRec, fCurrentSelRec);
}
Bool_t TGLViewer::RequestSecondarySelect(Int_t x, Int_t y)
{
if ( ! TakeLock(kSelectLock)) {
return kFALSE;
}
if (!gVirtualX->IsCmdThread())
return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoSecondarySelect(%d, %d)", (ULong_t)this, x, y)));
else
return DoSecondarySelect(x, y);
}
Bool_t TGLViewer::DoSecondarySelect(Int_t x, Int_t y)
{
R__LOCKGUARD2(gROOTMutex);
if (CurrentLock() != kSelectLock) {
Error("TGLViewer::DoSecondarySelect", "expected kSelectLock, found %s", LockName(CurrentLock()));
return kFALSE;
}
TGLUtil::PointToViewport(x, y);
TUnlocker ulck(this);
if (! fSelRec.GetSceneInfo() || ! fSelRec.GetPhysShape() ||
! fSelRec.GetLogShape()->SupportsSecondarySelect())
{
if (gDebug > 0)
Info("TGLViewer::SecondarySelect", "Skipping secondary selection "
"(sinfo=0x%lx, pshape=0x%lx).\n",
(Long_t)fSelRec.GetSceneInfo(), (Long_t)fSelRec.GetPhysShape());
fSecSelRec.Reset();
return kFALSE;
}
MakeCurrent();
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, TGLUtil::GetPickingRadius());
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%lx)->DoOverlaySelect(%d, %d)", (ULong_t)this, x, y)));
else
return DoOverlaySelect(x, y);
}
Bool_t TGLViewer::DoOverlaySelect(Int_t x, Int_t y)
{
R__LOCKGUARD2(gROOTMutex);
if (CurrentLock() != kSelectLock) {
Error("TGLViewer::DoOverlaySelect", "expected kSelectLock, found %s", LockName(CurrentLock()));
return kFALSE;
}
TGLUtil::PointToViewport(x, y);
TUnlocker ulck(this);
MakeCurrent();
fRnrCtx->BeginSelection(x, y, TGLUtil::GetPickingRadius());
glRenderMode(GL_SELECT);
PreRenderOverlaySelection();
RenderOverlay(TGLOverlayElement::kActive, kTRUE);
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;
}
++idx;
}
}
else
{
fOvlSelRec.Reset();
}
ReleaseLock(kSelectLock);
if (fCurrentOvlElm != selElm)
{
if (fCurrentOvlElm) fCurrentOvlElm->MouseLeave();
fCurrentOvlElm = selElm;
return kTRUE;
}
else
{
return kFALSE;
}
}
void TGLFaderHelper::MakeFadeStep()
{
Float_t fade = fViewer->GetFader();
if (fade == fFadeTarget) {
delete this; return;
}
if (TMath::Abs(fFadeTarget - fade) < 1e-3) {
fViewer->SetFader(fFadeTarget);
fViewer->RequestDraw(TGLRnrCtx::kLODHigh);
delete this;
return;
}
Float_t dt = fTime/fNSteps;
Float_t df = (fFadeTarget - fade)/fNSteps;
fViewer->SetFader(fade + df);
fViewer->RequestDraw(TGLRnrCtx::kLODHigh);
fTime -= dt; --fNSteps;
TTimer::SingleShot(TMath::CeilNint(1000*dt),
"TGLFaderHelper", this, "MakeFadeStep()");
}
void TGLViewer::AutoFade(Float_t fade, Float_t time, Int_t steps)
{
TGLFaderHelper* fh = new TGLFaderHelper(this, fade, time, steps);
fh->MakeFadeStep();
}
void TGLViewer::UseDarkColorSet()
{
fRnrCtx->ChangeBaseColorSet(&fDarkColorSet);
RefreshPadEditor(this);
}
void TGLViewer::UseLightColorSet()
{
fRnrCtx->ChangeBaseColorSet(&fLightColorSet);
RefreshPadEditor(this);
}
void TGLViewer::SwitchColorSet()
{
if (IsUsingDefaultColorSet())
{
Info("SwitchColorSet()", "Global color-set is in use, switch not supported.");
return;
}
if (fRnrCtx->GetBaseColorSet() == &fLightColorSet)
UseDarkColorSet();
else
UseLightColorSet();
}
void TGLViewer::UseDefaultColorSet(Bool_t x)
{
if (x)
fRnrCtx->ChangeBaseColorSet(&fgDefaultColorSet);
else
fRnrCtx->ChangeBaseColorSet(&fDarkColorSet);
RefreshPadEditor(this);
}
Bool_t TGLViewer::IsUsingDefaultColorSet() const
{
return fRnrCtx->GetBaseColorSet() == &fgDefaultColorSet;
}
void TGLViewer::SetClearColor(Color_t col)
{
fRnrCtx->GetBaseColorSet()->Background().SetColor(col);
}
TGLColorSet& TGLViewer::GetDefaultColorSet()
{
return fgDefaultColorSet;
}
void TGLViewer::UseDefaultColorSetForNewViewers(Bool_t x)
{
fgUseDefaultColorSetForNewViewers = x;
}
Bool_t TGLViewer::IsUsingDefaultColorSetForNewViewers()
{
return fgUseDefaultColorSetForNewViewers;
}
Bool_t TGLViewer::IsColorSetDark() const
{
return fRnrCtx->GetBaseColorSet() == &fDarkColorSet;
}
void TGLViewer::SetViewport(Int_t x, Int_t y, Int_t width, Int_t height)
{
if (fStereo && ! fStereoQuadBuf) width /= 2;
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);
}
}
void TGLViewer::SetViewport(const TGLRect& vp)
{
SetViewport(vp.X(), vp.Y(), vp.Width(), vp.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;
case kCameraOrthoXnOY:
return fOrthoXnOYCamera;
case kCameraOrthoXnOZ:
return fOrthoXnOZCamera;
case kCameraOrthoZnOY:
return fOrthoZnOYCamera;
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;
}
TGLCamera *prev = fCurrentCamera;
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;
}
case kCameraOrthoXnOY: {
fCurrentCamera = &fOrthoXnOYCamera;
break;
}
case kCameraOrthoXnOZ: {
fCurrentCamera = &fOrthoXnOZCamera;
break;
}
case kCameraOrthoZnOY: {
fCurrentCamera = &fOrthoZnOYCamera;
break;
}
default: {
Error("TGLViewer::SetCurrentCamera", "invalid camera type");
break;
}
}
if (fCurrentCamera != prev)
{
fCurrentCamera->SetViewport(fViewport);
RefreshPadEditor(this);
if (fAutoRotator)
{
if (fAutoRotator->IsRunning())
{
fAutoRotator->Stop();
}
else
{
if (fAutoRotator->GetCamera() == fCurrentCamera)
{
fAutoRotator->Start();
}
}
}
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::ReinitializeCurrentCamera(const TGLVector3& hAxis, const TGLVector3& vAxis, Bool_t redraw)
{
TGLMatrix& cb = fCurrentCamera->RefCamBase();
cb.Set(cb.GetTranslation(), vAxis, hAxis);
fCurrentCamera->Setup(fOverallBoundingBox, kTRUE);
if (redraw)
RequestDraw();
}
TGLAutoRotator* TGLViewer::GetAutoRotator()
{
if (fAutoRotator == 0)
fAutoRotator = new TGLAutoRotator(this);
return fAutoRotator;
}
void TGLViewer::SetAutoRotator(TGLAutoRotator* ar)
{
delete fAutoRotator;
fAutoRotator = ar;
}
void TGLViewer::SetStereo(Bool_t stereo, Bool_t quad_buf)
{
if (stereo != fStereo)
{
fStereo = stereo;
fStereoQuadBuf = quad_buf;
if (fStereo)
SetViewport(fViewport.X(), fViewport.Y(), fViewport.Width(), fViewport.Height());
else
SetViewport(fViewport.X(), fViewport.Y(), 2*fViewport.Width(), fViewport.Height());
}
RequestDraw(TGLRnrCtx::kLODHigh);
}
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::MouseOver(TGLPhysicalShape *shape)
{
Emit("MouseOver(TGLPhysicalShape*)", (Long_t)shape);
}
void TGLViewer::MouseOver(TGLPhysicalShape *shape, UInt_t state)
{
Long_t args[2];
args[0] = (Long_t)shape;
args[1] = state;
Emit("MouseOver(TGLPhysicalShape*,UInt_t)", args);
}
void TGLViewer::MouseOver(TObject *obj, UInt_t state)
{
Long_t args[2];
args[0] = (Long_t)obj;
args[1] = state;
Emit("MouseOver(TObject*,UInt_t)", args);
}
void TGLViewer::ReMouseOver(TObject *obj, UInt_t state)
{
Long_t args[2];
args[0] = (Long_t)obj;
args[1] = state;
Emit("ReMouseOver(TObject*,UInt_t)", args);
}
void TGLViewer::UnMouseOver(TObject *obj, UInt_t state)
{
Long_t args[2];
args[0] = (Long_t)obj;
args[1] = state;
Emit("UnMouseOver(TObject*,UInt_t)", args);
}
void TGLViewer::Clicked(TObject *obj)
{
Emit("Clicked(TObject*)", (Long_t)obj);
}
void TGLViewer::Clicked(TObject *obj, UInt_t button, UInt_t state)
{
Long_t args[3];
args[0] = (Long_t)obj;
args[1] = button;
args[2] = state;
Emit("Clicked(TObject*,UInt_t,UInt_t)", args);
}
void TGLViewer::ReClicked(TObject *obj, UInt_t button, UInt_t state)
{
Long_t args[3];
args[0] = (Long_t)obj;
args[1] = button;
args[2] = state;
Emit("ReClicked(TObject*,UInt_t,UInt_t)", args);
}
void TGLViewer::UnClicked(TObject *obj, UInt_t button, UInt_t state)
{
Long_t args[3];
args[0] = (Long_t)obj;
args[1] = button;
args[2] = state;
Emit("UnClicked(TObject*,UInt_t,UInt_t)", args);
}
void TGLViewer::MouseIdle(TGLPhysicalShape *shape, UInt_t posx, UInt_t posy)
{
Long_t args[3];
static UInt_t oldx = 0, oldy = 0;
if (oldx != posx || oldy != posy) {
args[0] = (Long_t)shape;
args[1] = posx;
args[2] = posy;
Emit("MouseIdle(TGLPhysicalShape*,UInt_t,UInt_t)", args);
oldx = posx;
oldy = posy;
}
}
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)
{
if (fEventHandler)
return fEventHandler->ExecuteEvent(event, px, py);
}
void TGLViewer::PrintObjects()
{
TGLOutput::Capture(*this);
}
void TGLViewer::SelectionChanged()
{
if (!fGedEditor)
return;
TGLPhysicalShape *selected = const_cast<TGLPhysicalShape*>(GetSelected());
if (selected) {
fPShapeWrap->fPShape = selected;
fGedEditor->SetModel(fPad, fPShapeWrap, kButton1Down);
} else {
fPShapeWrap->fPShape = 0;
fGedEditor->SetModel(fPad, this, kButton1Down);
}
}
void TGLViewer::OverlayDragFinished()
{
if (fGedEditor)
{
fGedEditor->SetModel(fPad, fGedEditor->GetModel(), kButton1Down);
}
}
void TGLViewer::RefreshPadEditor(TObject* obj)
{
if (fGedEditor && (obj == 0 || fGedEditor->GetModel() == obj))
{
fGedEditor->SetModel(fPad, fGedEditor->GetModel(), kButton1Down);
}
}
void TGLViewer::SetEventHandler(TGEventHandler *handler)
{
if (fEventHandler)
delete fEventHandler;
fEventHandler = handler;
if (fGLWidget)
fGLWidget->SetEventHandler(fEventHandler);
}
void TGLViewer::RemoveOverlayElement(TGLOverlayElement* el)
{
if (el == fCurrentOvlElm)
{
fCurrentOvlElm = 0;
}
TGLViewerBase::RemoveOverlayElement(el);
}
void TGLViewer::ClearCurrentOvlElm()
{
if (fCurrentOvlElm)
{
fCurrentOvlElm->MouseLeave();
fCurrentOvlElm = 0;
RequestDraw();
}
}