Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLViewer.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Richard Maunder 25/05/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TGLViewer.h"
13 #include "TGLIncludes.h"
14 #include "TGLStopwatch.h"
15 #include "TGLRnrCtx.h"
16 #include "TGLSelectBuffer.h"
17 #include "TGLLightSet.h"
18 #include "TGLManipSet.h"
19 #include "TGLCameraOverlay.h"
20 #include "TGLAutoRotator.h"
21 
22 #include "TGLScenePad.h"
23 #include "TGLLogicalShape.h"
24 #include "TGLPhysicalShape.h"
25 #include "TGLObject.h"
26 #include "TGLStopwatch.h"
27 #include "TBuffer3D.h"
28 #include "TBuffer3DTypes.h"
29 
30 #include "TGLOutput.h"
31 
32 #include "TROOT.h"
33 #include "TVirtualMutex.h"
34 
35 #include "TVirtualPad.h" // Remove when pad removed - use signal
36 #include "TVirtualX.h"
37 
38 #include "TMath.h"
39 #include "TColor.h"
40 #include "TError.h"
41 #include "TClass.h"
42 #include "TROOT.h"
43 #include "TEnv.h"
44 
45 // For event type translation ExecuteEvent
46 #include "Buttons.h"
47 #include "GuiTypes.h"
48 
49 #include "TVirtualGL.h"
50 
51 #include "TGLWidget.h"
52 #include "TGLFBO.h"
53 #include "TGLViewerEditor.h"
54 #include "TGedEditor.h"
55 #include "TGLPShapeObj.h"
56 
57 #include "KeySymbols.h"
58 #include "TContextMenu.h"
59 #include "TImage.h"
60 
61 #include <stdexcept>
62 
63 #ifndef GL_BGRA
64 #define GL_BGRA GL_BGRA_EXT
65 #endif
66 
67 /** \class TGLViewer
68 \ingroup opengl
69 Base GL viewer object - used by both standalone and embedded (in pad)
70 GL. Contains core viewer objects :
71 
72 GL scene - collection of main drawn objects - see TGLStdScene
73 Cameras (fXyzzCamera) - ortho and perspective cameras - see TGLCamera
74 Clipping (fClipXyzz) - collection of clip objects - see TGLClip
75 Manipulators (fXyzzManip) - collection of manipulators - see TGLManip
76 
77 It maintains the current active draw styles, clipping object,
78 manipulator, camera etc.
79 
80 TGLViewer is 'GUI free' in that it does not derive from any ROOT GUI
81 TGFrame etc - see TGLSAViewer for this. However it contains GUI
82 GUI style methods HandleButton() etc to which GUI events can be
83 directed from standalone frame or embedding pad to perform
84 interaction.
85 
86 Also, the TGLWidget needs to be created externally. It is not owned
87 by the viewer.
88 
89 For embedded (pad) GL this viewer is created directly by plugin
90 manager. For standalone the derived TGLSAViewer is.
91 */
92 
93 ClassImp(TGLViewer);
94 
95 TGLColorSet TGLViewer::fgDefaultColorSet;
96 Bool_t TGLViewer::fgUseDefaultColorSetForNewViewers = kFALSE;
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 
100 TGLViewer::TGLViewer(TVirtualPad * pad, Int_t x, Int_t y,
101  Int_t width, Int_t height) :
102  fPad(pad),
103  fContextMenu(0),
104  fPerspectiveCameraXOZ(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), // XOZ floor
105  fPerspectiveCameraYOZ(TGLVector3( 0.0,-1.0, 0.0), TGLVector3(1.0, 0.0, 0.0)), // YOZ floor
106  fPerspectiveCameraXOY(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), // XOY floor
107  fOrthoXOYCamera (TGLOrthoCamera::kXOY, TGLVector3( 0.0, 0.0, 1.0), TGLVector3(0.0, 1.0, 0.0)), // Looking down Z axis, X horz, Y vert
108  fOrthoXOZCamera (TGLOrthoCamera::kXOZ, TGLVector3( 0.0,-1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), // Looking along Y axis, X horz, Z vert
109  fOrthoZOYCamera (TGLOrthoCamera::kZOY, TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), // Looking along X axis, Z horz, Y vert
110  fOrthoZOXCamera (TGLOrthoCamera::kZOX, TGLVector3( 0.0,-1.0, 0.0), TGLVector3(1.0, 0.0, 0.0)), // Looking along Y axis, Z horz, X vert
111  fOrthoXnOYCamera(TGLOrthoCamera::kXnOY, TGLVector3( 0.0, 0.0,-1.0), TGLVector3(0.0, 1.0, 0.0)), // Looking along Z axis, -X horz, Y vert
112  fOrthoXnOZCamera(TGLOrthoCamera::kXnOZ, TGLVector3( 0.0, 1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), // Looking down Y axis, -X horz, Z vert
113  fOrthoZnOYCamera(TGLOrthoCamera::kZnOY, TGLVector3( 1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), // Looking down X axis, -Z horz, Y vert
114  fOrthoZnOXCamera(TGLOrthoCamera::kZnOX, TGLVector3( 0.0, 1.0, 0.0), TGLVector3(1.0, 0.0, 0.0)), // Looking down Y axis, -Z horz, X vert
115  fCurrentCamera(&fPerspectiveCameraXOZ),
116  fAutoRotator(0),
117 
118  fStereo (kFALSE),
119  fStereoQuadBuf (kFALSE),
120  fStereoZeroParallax (0.03f),
121  fStereoEyeOffsetFac (1.0f),
122  fStereoFrustumAsymFac (1.0f),
123 
124  fLightSet (0),
125  fClipSet (0),
126  fSelectedPShapeRef (0),
127  fCurrentOvlElm (0),
128 
129  fEventHandler(0),
130  fGedEditor(0),
131  fPShapeWrap(0),
132  fPushAction(kPushStd), fDragAction(kDragNone),
133  fRedrawTimer(0),
134  fMaxSceneDrawTimeHQ(5000),
135  fMaxSceneDrawTimeLQ(100),
136  fPointScale (1), fLineScale(1), fSmoothPoints(kFALSE), fSmoothLines(kFALSE),
137  fAxesType(TGLUtil::kAxesNone),
138  fAxesDepthTest(kTRUE),
139  fReferenceOn(kFALSE),
140  fReferencePos(0.0, 0.0, 0.0),
141  fDrawCameraCenter(kFALSE),
142  fCameraOverlay(0),
143  fSmartRefresh(kFALSE),
144  fDebugMode(kFALSE),
145  fIsPrinting(kFALSE),
146  fPictureFileName("viewer.jpg"),
147  fFader(0),
148  fGLWidget(0),
149  fGLDevice(-1),
150  fGLCtxId(0),
151  fIgnoreSizesOnUpdate(kFALSE),
152  fResetCamerasOnUpdate(kTRUE),
153  fResetCamerasOnNextUpdate(kFALSE)
154 {
155  // Construct the viewer object, with following arguments:
156  // 'pad' - external pad viewer is bound to
157  // 'x', 'y' - initial top left position
158  // 'width', 'height' - initial width/height
159 
160  InitSecondaryObjects();
161 
162  SetViewport(x, y, width, height);
163 }
164 
165 ////////////////////////////////////////////////////////////////////////////////
166 
167 TGLViewer::TGLViewer(TVirtualPad * pad) :
168  fPad(pad),
169  fContextMenu(0),
170  fPerspectiveCameraXOZ(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), // XOZ floor
171  fPerspectiveCameraYOZ(TGLVector3( 0.0,-1.0, 0.0), TGLVector3(1.0, 0.0, 0.0)), // YOZ floor
172  fPerspectiveCameraXOY(TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), // XOY floor
173  fOrthoXOYCamera (TGLOrthoCamera::kXOY, TGLVector3( 0.0, 0.0, 1.0), TGLVector3(0.0, 1.0, 0.0)), // Looking down Z axis, X horz, Y vert
174  fOrthoXOZCamera (TGLOrthoCamera::kXOZ, TGLVector3( 0.0,-1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), // Looking along Y axis, X horz, Z vert
175  fOrthoZOYCamera (TGLOrthoCamera::kZOY, TGLVector3(-1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), // Looking along X axis, Z horz, Y vert
176  fOrthoZOXCamera (TGLOrthoCamera::kZOX, TGLVector3( 0.0,-1.0, 0.0), TGLVector3(1.0, 0.0, 0.0)), // Looking along Y axis, Z horz, X vert
177  fOrthoXnOYCamera(TGLOrthoCamera::kXnOY, TGLVector3( 0.0, 0.0,-1.0), TGLVector3(0.0, 1.0, 0.0)), // Looking along Z axis, -X horz, Y vert
178  fOrthoXnOZCamera(TGLOrthoCamera::kXnOZ, TGLVector3( 0.0, 1.0, 0.0), TGLVector3(0.0, 0.0, 1.0)), // Looking down Y axis, -X horz, Z vert
179  fOrthoZnOYCamera(TGLOrthoCamera::kZnOY, TGLVector3( 1.0, 0.0, 0.0), TGLVector3(0.0, 1.0, 0.0)), // Looking down X axis, -Z horz, Y vert
180  fOrthoZnOXCamera(TGLOrthoCamera::kZnOX, TGLVector3( 0.0, 1.0, 0.0), TGLVector3(1.0, 0.0, 0.0)), // Looking down Y axis, -Z horz, X vert
181  fCurrentCamera(&fPerspectiveCameraXOZ),
182  fAutoRotator(0),
183 
184  fStereo (kFALSE),
185  fStereoQuadBuf (kFALSE),
186  fStereoZeroParallax (0.03f),
187  fStereoEyeOffsetFac (1.0f),
188  fStereoFrustumAsymFac (1.0f),
189 
190  fLightSet (0),
191  fClipSet (0),
192  fSelectedPShapeRef (0),
193  fCurrentOvlElm (0),
194 
195  fEventHandler(0),
196  fGedEditor(0),
197  fPShapeWrap(0),
198  fPushAction(kPushStd), fDragAction(kDragNone),
199  fRedrawTimer(0),
200  fMaxSceneDrawTimeHQ(5000),
201  fMaxSceneDrawTimeLQ(100),
202  fPointScale (1), fLineScale(1), fSmoothPoints(kFALSE), fSmoothLines(kFALSE),
203  fAxesType(TGLUtil::kAxesNone),
204  fAxesDepthTest(kTRUE),
205  fReferenceOn(kFALSE),
206  fReferencePos(0.0, 0.0, 0.0),
207  fDrawCameraCenter(kFALSE),
208  fCameraOverlay(0),
209  fSmartRefresh(kFALSE),
210  fDebugMode(kFALSE),
211  fIsPrinting(kFALSE),
212  fPictureFileName("viewer.jpg"),
213  fFader(0),
214  fGLWidget(0),
215  fGLDevice(fPad->GetGLDevice()),
216  fGLCtxId(0),
217  fIgnoreSizesOnUpdate(kFALSE),
218  fResetCamerasOnUpdate(kTRUE),
219  fResetCamerasOnNextUpdate(kFALSE)
220 {
221  //gl-embedded viewer's ctor
222  // Construct the viewer object, with following arguments:
223  // 'pad' - external pad viewer is bound to
224  // 'x', 'y' - initial top left position
225  // 'width', 'height' - initial width/height
226 
227  InitSecondaryObjects();
228 
229  if (fGLDevice != -1) {
230  // For the moment instantiate a fake context identity.
231  fGLCtxId = new TGLContextIdentity;
232  fGLCtxId->AddRef(0);
233  Int_t viewport[4] = {0};
234  gGLManager->ExtractViewport(fGLDevice, viewport);
235  SetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
236  }
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// Common initialization.
241 
242 void TGLViewer::InitSecondaryObjects()
243 {
244  fLightSet = new TGLLightSet;
245  fClipSet = new TGLClipSet;
246  AddOverlayElement(fClipSet);
247 
248  fSelectedPShapeRef = new TGLManipSet;
249  fSelectedPShapeRef->SetDrawBBox(kTRUE);
250  AddOverlayElement(fSelectedPShapeRef);
251 
252  fPShapeWrap = new TGLPShapeObj(0, this);
253 
254  fLightColorSet.StdLightBackground();
255  if (fgUseDefaultColorSetForNewViewers) {
256  fRnrCtx->ChangeBaseColorSet(&fgDefaultColorSet);
257  } else {
258  if (fPad) {
259  fRnrCtx->ChangeBaseColorSet(&fLightColorSet);
260  fLightColorSet.Background().SetColor(fPad->GetFillColor());
261  fLightColorSet.Foreground().SetColor(fPad->GetLineColor());
262  } else {
263  fRnrCtx->ChangeBaseColorSet(&fDarkColorSet);
264  }
265  }
266 
267  fCameraOverlay = new TGLCameraOverlay(kFALSE, kFALSE);
268  AddOverlayElement(fCameraOverlay);
269 
270  fRedrawTimer = new TGLRedrawTimer(*this);
271 }
272 
273 ////////////////////////////////////////////////////////////////////////////////
274 /// Destroy viewer object.
275 
276 TGLViewer::~TGLViewer()
277 {
278  delete fAutoRotator;
279 
280  delete fLightSet;
281  // fClipSet, fSelectedPShapeRef and fCameraOverlay deleted via overlay.
282 
283  delete fContextMenu;
284  delete fRedrawTimer;
285 
286  if (fEventHandler) {
287  if (fGLWidget)
288  fGLWidget->SetEventHandler(0);
289  delete fEventHandler;
290  }
291 
292  if (fPad)
293  fPad->ReleaseViewer3D();
294  if (fGLDevice != -1)
295  fGLCtxId->Release(0);
296 }
297 
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// Entry point for updating viewer contents via VirtualViewer3D
301 /// interface.
302 /// We search and forward the request to appropriate TGLScenePad.
303 /// If it is not found we create a new TGLScenePad so this can
304 /// potentially also be used for registration of new pads.
305 
306 void TGLViewer::PadPaint(TVirtualPad* pad)
307 {
308  TGLScenePad* scenepad = 0;
309  for (SceneInfoList_i si = fScenes.begin(); si != fScenes.end(); ++si)
310  {
311  scenepad = dynamic_cast<TGLScenePad*>((*si)->GetScene());
312  if (scenepad && scenepad->GetPad() == pad)
313  break;
314  scenepad = 0;
315  }
316  if (scenepad == 0)
317  {
318  scenepad = new TGLScenePad(pad);
319  AddScene(scenepad);
320  }
321 
322  scenepad->PadPaintFromViewer(this);
323 
324  PostSceneBuildSetup(fResetCamerasOnNextUpdate || fResetCamerasOnUpdate);
325  fResetCamerasOnNextUpdate = kFALSE;
326 
327  RequestDraw();
328 }
329 
330 
331 /**************************************************************************/
332 /**************************************************************************/
333 
334 ////////////////////////////////////////////////////////////////////////////////
335 /// Force update of pad-scenes. Eventually this could be generalized
336 /// to all scene-types via a virtual function in TGLSceneBase.
337 
338 void TGLViewer::UpdateScene(Bool_t redraw)
339 {
340  // Cancel any pending redraw timer.
341  fRedrawTimer->Stop();
342 
343  for (SceneInfoList_i si = fScenes.begin(); si != fScenes.end(); ++si)
344  {
345  TGLScenePad* scenepad = dynamic_cast<TGLScenePad*>((*si)->GetScene());
346  if (scenepad)
347  scenepad->PadPaintFromViewer(this);
348  }
349 
350  PostSceneBuildSetup(fResetCamerasOnNextUpdate || fResetCamerasOnUpdate);
351  fResetCamerasOnNextUpdate = kFALSE;
352 
353  if (redraw)
354  RequestDraw();
355 }
356 
357 ////////////////////////////////////////////////////////////////////////////////
358 /// Resets position/rotation of current camera to default values.
359 
360 void TGLViewer::ResetCurrentCamera()
361 {
362  MergeSceneBBoxes(fOverallBoundingBox);
363  CurrentCamera().Setup(fOverallBoundingBox, kTRUE);
364 }
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 /// Setup cameras for current bounding box.
368 
369 void TGLViewer::SetupCameras(Bool_t reset)
370 {
371  if (IsLocked()) {
372  Error("TGLViewer::SetupCameras", "expected kUnlocked, found %s", LockName(CurrentLock()));
373  return;
374  }
375 
376  // Setup cameras if scene box is not empty
377  const TGLBoundingBox & box = fOverallBoundingBox;
378  if (!box.IsEmpty()) {
379  fPerspectiveCameraYOZ.Setup(box, reset);
380  fPerspectiveCameraXOZ.Setup(box, reset);
381  fPerspectiveCameraXOY.Setup(box, reset);
382  fOrthoXOYCamera.Setup(box, reset);
383  fOrthoXOZCamera.Setup(box, reset);
384  fOrthoZOYCamera.Setup(box, reset);
385  fOrthoXnOYCamera.Setup(box, reset);
386  fOrthoXnOZCamera.Setup(box, reset);
387  fOrthoZnOYCamera.Setup(box, reset);
388  }
389 }
390 
391 ////////////////////////////////////////////////////////////////////////////////
392 /// Perform post scene-build setup.
393 
394 void TGLViewer::PostSceneBuildSetup(Bool_t resetCameras)
395 {
396  MergeSceneBBoxes(fOverallBoundingBox);
397  SetupCameras(resetCameras);
398 
399  // Set default reference to center
400  fReferencePos.Set(fOverallBoundingBox.Center());
401  RefreshPadEditor(this);
402 }
403 
404 
405 /**************************************************************************/
406 /**************************************************************************/
407 
408 ////////////////////////////////////////////////////////////////////////////////
409 /// Initialise GL state.
410 
411 void TGLViewer::InitGL()
412 {
413  glEnable(GL_LIGHTING);
414  glEnable(GL_DEPTH_TEST);
415  glEnable(GL_CULL_FACE);
416  glCullFace(GL_BACK);
417  glClearColor(0.f, 0.f, 0.f, 0.f);
418  glClearDepth(1.0);
419  glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
420  glEnable(GL_COLOR_MATERIAL);
421  glMaterialf(GL_BACK, GL_SHININESS, 0.0);
422  glPolygonMode(GL_FRONT, GL_FILL);
423  glDisable(GL_BLEND);
424 
425  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
426  Float_t lmodelAmb[] = {0.5f, 0.5f, 1.f, 1.f};
427  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodelAmb);
428  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
429 
430  glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
431  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
432 
433  TGLUtil::CheckError("TGLViewer::InitGL");
434 }
435 
436 ////////////////////////////////////////////////////////////////////////////////
437 /// Post request for redraw of viewer at level of detail 'LOD'
438 /// Request is directed via cross thread gVirtualGL object.
439 
440 void TGLViewer::RequestDraw(Short_t LODInput)
441 {
442  fRedrawTimer->Stop();
443  // Ignore request if GL window or context not yet available or shown.
444  if ((!fGLWidget && fGLDevice == -1) || (fGLWidget && !fGLWidget->IsMapped()))
445  {
446  return;
447  }
448 
449  // Take scene draw lock - to be revisited
450  if ( ! TakeLock(kDrawLock)) {
451  // If taking drawlock fails the previous draw is still in progress
452  // set timer to do this one later
453  if (gDebug>3) {
454  Info("TGLViewer::RequestDraw", "viewer locked - requesting another draw.");
455  }
456  fRedrawTimer->RequestDraw(100, LODInput);
457  return;
458  }
459  fLOD = LODInput;
460 
461  if (!gVirtualX->IsCmdThread())
462  gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw()", (ULong_t)this));
463  else
464  DoDraw();
465 }
466 
467 ////////////////////////////////////////////////////////////////////////////////
468 /// Setup clip-object. Protected virtual method.
469 
470 void TGLViewer::SetupClipObject()
471 {
472  if (GetClipAutoUpdate())
473  {
474  fClipSet->SetupCurrentClip(fOverallBoundingBox);
475  }
476  else
477  {
478  fClipSet->SetupCurrentClipIfInvalid(fOverallBoundingBox);
479  }
480 }
481 ////////////////////////////////////////////////////////////////////////////////
482 /// Initialize objects that influence rendering.
483 /// Called before every render.
484 
485 void TGLViewer::PreRender()
486 {
487  fCamera = fCurrentCamera;
488  fClip = fClipSet->GetCurrentClip();
489  if (fGLDevice != -1)
490  {
491  fRnrCtx->SetGLCtxIdentity(fGLCtxId);
492  fGLCtxId->DeleteGLResources();
493  }
494 
495  TGLUtil::SetPointSizeScale(fPointScale * fRnrCtx->GetRenderScale());
496  TGLUtil::SetLineWidthScale(fLineScale * fRnrCtx->GetRenderScale());
497 
498  if (fSmoothPoints) glEnable(GL_POINT_SMOOTH); else glDisable(GL_POINT_SMOOTH);
499  if (fSmoothLines) glEnable(GL_LINE_SMOOTH); else glDisable(GL_LINE_SMOOTH);
500  if (fSmoothPoints || fSmoothLines)
501  {
502  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
503  glEnable(GL_BLEND);
504  }
505  else
506  {
507  glDisable(GL_BLEND);
508  }
509 
510  TGLViewerBase::PreRender();
511 
512  // Setup lighting
513  fLightSet->StdSetupLights(fOverallBoundingBox, *fCamera, fDebugMode);
514 }
515 
516 ////////////////////////////////////////////////////////////////////////////////
517 /// Normal rendering, used by mono and stereo rendering.
518 
519 void TGLViewer::Render()
520 {
521  TGLViewerBase::Render();
522 
523  DrawGuides();
524  RenderOverlay(TGLOverlayElement::kAllVisible, kFALSE);
525 
526  if ( ! fRnrCtx->Selection())
527  {
528  RenderSelectedForHighlight();
529  }
530 
531  glClear(GL_DEPTH_BUFFER_BIT);
532  DrawDebugInfo();
533 }
534 
535 ////////////////////////////////////////////////////////////////////////////////
536 /// Restore state set in PreRender().
537 /// Called after every render.
538 
539 void TGLViewer::PostRender()
540 {
541  TGLViewerBase::PostRender();
542 
543  TGLUtil::SetPointSizeScale(1);
544  TGLUtil::SetLineWidthScale(1);
545 }
546 
547 ////////////////////////////////////////////////////////////////////////////////
548 /// Draw out the viewer.
549 
550 void TGLViewer::DoDraw(Bool_t swap_buffers)
551 {
552  // Locking mainly for Win32 multi thread safety - but no harm in all using it
553  // During normal draws a draw lock is taken in other thread (Win32) in RequestDraw()
554  // to ensure thread safety. For PrintObjects repeated Draw() calls are made.
555  // If no draw lock taken get one now.
556 
557  R__LOCKGUARD(gROOTMutex);
558 
559  fRedrawTimer->Stop();
560 
561  if (CurrentLock() != kDrawLock) {
562  if ( ! TakeLock(kDrawLock)) {
563  Error("TGLViewer::DoDraw", "viewer is %s", LockName(CurrentLock()));
564  return;
565  }
566  }
567 
568  TUnlocker ulck(this);
569 
570  if (fGLDevice == -1 && (fViewport.Width() <= 1 || fViewport.Height() <= 1)) {
571  if (gDebug > 2) {
572  Info("TGLViewer::DoDraw()", "zero surface area, draw skipped.");
573  }
574  return;
575  }
576 
577  if (fGLDevice != -1) {
578  Int_t viewport[4] = {};
579  gGLManager->ExtractViewport(fGLDevice, viewport);
580  SetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
581  }
582 
583  TGLStopwatch timer;
584  if (gDebug>2) {
585  timer.Start();
586  }
587 
588  // Setup scene draw time
589  fRnrCtx->SetRenderTimeOut(fLOD == TGLRnrCtx::kLODHigh ?
590  fMaxSceneDrawTimeHQ :
591  fMaxSceneDrawTimeLQ);
592 
593  if (fStereo && fCurrentCamera->IsPerspective() && !fRnrCtx->GetGrabImage() &&
594  !fIsPrinting)
595  {
596  DoDrawStereo(swap_buffers);
597  }
598  else
599  {
600  DoDrawMono(swap_buffers);
601  }
602 
603  ReleaseLock(kDrawLock);
604 
605  if (gDebug>2) {
606  Info("TGLViewer::DoDraw()", "Took %f msec", timer.End());
607  }
608 
609  // Check if further redraws are needed and schedule them.
610 
611  if (CurrentCamera().UpdateInterest(kFALSE)) {
612  // Reset major view-dependant cache.
613  ResetSceneInfos();
614  fRedrawTimer->RequestDraw(0, fLOD);
615  }
616 
617  if (fLOD != TGLRnrCtx::kLODHigh &&
618  (fDragAction < kDragCameraRotate || fDragAction > kDragCameraDolly))
619  {
620  // Request final draw pass.
621  fRedrawTimer->RequestDraw(100, TGLRnrCtx::kLODHigh);
622  }
623 }
624 
625 ////////////////////////////////////////////////////////////////////////////////
626 /// Draw out in monoscopic mode.
627 
628 void TGLViewer::DoDrawMono(Bool_t swap_buffers)
629 {
630  MakeCurrent();
631 
632  if (!fIsPrinting) PreDraw();
633  PreRender();
634 
635  fRnrCtx->StartStopwatch();
636  if (fFader < 1)
637  {
638  Render();
639  }
640  fRnrCtx->StopStopwatch();
641 
642  PostRender();
643 
644  if (fFader > 0)
645  {
646  FadeView(fFader);
647  }
648 
649  PostDraw();
650 
651  if (swap_buffers)
652  {
653  SwapBuffers();
654  }
655 }
656 
657 ////////////////////////////////////////////////////////////////////////////////
658 /// Draw out in stereoscopic mode.
659 
660 void TGLViewer::DoDrawStereo(Bool_t swap_buffers)
661 {
662  TGLPerspectiveCamera &c = *dynamic_cast<TGLPerspectiveCamera*>(fCurrentCamera);
663 
664  Float_t gl_near, gl_far, zero_p_dist;
665  Float_t h_half, w_half;
666  Float_t x_len_at_zero_parallax;
667  Float_t stereo_offset;
668  Float_t frustum_asym;
669 
670  MakeCurrent();
671 
672  // Draw left
673  if (fStereoQuadBuf)
674  {
675  glDrawBuffer(GL_BACK_LEFT);
676  }
677  else
678  {
679  glScissor(0, 0, fViewport.Width(), fViewport.Height());
680  glEnable(GL_SCISSOR_TEST);
681  }
682  PreDraw();
683  PreRender();
684 
685  gl_near = c.GetNearClip();
686  gl_far = c.GetFarClip();
687  zero_p_dist = gl_near + fStereoZeroParallax*(gl_far-gl_near);
688 
689  h_half = TMath::Tan(0.5*TMath::DegToRad()*c.GetFOV()) * gl_near;
690  w_half = h_half * fViewport.Aspect();
691 
692  x_len_at_zero_parallax = 2.0f * w_half * zero_p_dist / gl_near;
693  stereo_offset = 0.035f * x_len_at_zero_parallax * fStereoEyeOffsetFac;
694 
695  frustum_asym = stereo_offset * gl_near / zero_p_dist * fStereoFrustumAsymFac;
696 
697  TGLMatrix abs_trans(c.RefCamBase());
698  abs_trans *= c.RefCamTrans();
699  TGLVector3 left_vec = abs_trans.GetBaseVec(2);
700 
701  glTranslatef(stereo_offset*left_vec[0], stereo_offset*left_vec[1], stereo_offset*left_vec[2]);
702 
703  glMatrixMode(GL_PROJECTION);
704  glLoadIdentity();
705  glFrustum(-w_half + frustum_asym, w_half + frustum_asym,
706  -h_half, h_half, gl_near, gl_far);
707  glMatrixMode(GL_MODELVIEW);
708 
709  fRnrCtx->StartStopwatch();
710  if (fFader < 1)
711  {
712  Render();
713  }
714  fRnrCtx->StopStopwatch();
715 
716  PostRender();
717 
718  if (fFader > 0)
719  {
720  FadeView(fFader);
721  }
722  PostDraw();
723 
724  // Draw right
725  if (fStereoQuadBuf)
726  {
727  glDrawBuffer(GL_BACK_RIGHT);
728  }
729  else
730  {
731  glScissor(fViewport.Width(), 0, fViewport.Width(), fViewport.Height());
732  }
733  PreDraw();
734  PreRender();
735  if ( ! fStereoQuadBuf)
736  {
737  glViewport(fViewport.Width(), 0, fViewport.Width(), fViewport.Height());
738  }
739 
740  glTranslatef(-stereo_offset*left_vec[0], -stereo_offset*left_vec[1], -stereo_offset*left_vec[2]);
741 
742  glMatrixMode(GL_PROJECTION);
743  glLoadIdentity();
744  glFrustum(-w_half - frustum_asym, w_half - frustum_asym,
745  -h_half, h_half, gl_near, gl_far);
746  glMatrixMode(GL_MODELVIEW);
747 
748  fRnrCtx->StartStopwatch();
749  if (fFader < 1)
750  {
751  Render();
752  }
753  fRnrCtx->StopStopwatch();
754 
755  PostRender();
756 
757  if (fFader > 0)
758  {
759  FadeView(fFader);
760  }
761  PostDraw();
762 
763  // End
764  if (swap_buffers)
765  {
766  SwapBuffers();
767  }
768 
769  if (fStereoQuadBuf)
770  {
771  glDrawBuffer(GL_BACK);
772  }
773  else
774  {
775  glDisable(GL_SCISSOR_TEST);
776  glViewport(0, 0, fViewport.Width(), fViewport.Height());
777  }
778 }
779 
780 ////////////////////////////////////////////////////////////////////////////////
781 /// Save current image using the default file name which can be set
782 /// via SetPictureFileName() and defaults to "viewer.jpg".
783 /// Really useful for the files ending with 'gif+'.
784 
785 Bool_t TGLViewer::SavePicture()
786 {
787  return SavePicture(fPictureFileName);
788 }
789 
790 ////////////////////////////////////////////////////////////////////////////////
791 /// Save current image in various formats (gif, gif+, jpg, png, eps, pdf).
792 /// 'gif+' will append image to an existing file (animated gif).
793 /// 'eps' and 'pdf' do not fully support transparency and texturing.
794 /// The viewer window most be fully contained within the desktop but
795 /// can be covered by other windows.
796 /// Returns false if something obvious goes wrong, true otherwise.
797 ///
798 /// The mage is saved using a frame-buffer object if the GL implementation
799 /// claims to support it -- this claim is not always true, especially when
800 /// running over ssh with drastically different GL implementations on the
801 /// client and server sides. Set this in .rootrc to enforce creation of
802 /// pictures using the back-buffer:
803 /// OpenGL.SavePicturesViaFBO: off
804 
805 Bool_t TGLViewer::SavePicture(const TString &fileName)
806 {
807  if (fileName.EndsWith(".eps"))
808  {
809  return TGLOutput::Capture(*this, TGLOutput::kEPS_BSP, fileName.Data());
810  }
811  else if (fileName.EndsWith(".pdf"))
812  {
813  return TGLOutput::Capture(*this, TGLOutput::kPDF_BSP, fileName.Data());
814  }
815  else
816  {
817  if (GLEW_EXT_framebuffer_object && gEnv->GetValue("OpenGL.SavePicturesViaFBO", 1))
818  {
819  return SavePictureUsingFBO(fileName, fViewport.Width(), fViewport.Height(), kFALSE);
820  }
821  else
822  {
823  return SavePictureUsingBB(fileName);
824  }
825  }
826 }
827 
828 ////////////////////////////////////////////////////////////////////////////////
829 /// Save current image in various formats (gif, gif+, jpg, png).
830 /// 'gif+' will append image to an existing file (animated gif).
831 /// Back-Buffer is used for capturing of the image.
832 /// The viewer window most be fully contained within the desktop but
833 /// can be covered by other windows.
834 /// Returns false if something obvious goes wrong, true otherwise.
835 
836 Bool_t TGLViewer::SavePictureUsingBB(const TString &fileName)
837 {
838  static const TString eh("TGLViewer::SavePictureUsingBB");
839 
840  if (! fileName.EndsWith(".gif") && ! fileName.Contains(".gif+") &&
841  ! fileName.EndsWith(".jpg") && ! fileName.EndsWith(".png"))
842  {
843  Warning(eh, "file %s cannot be saved with this extension.", fileName.Data());
844  return kFALSE;
845  }
846 
847  if ( ! TakeLock(kDrawLock)) {
848  Error(eh, "viewer locked - try later.");
849  return kFALSE;
850  }
851 
852  TUnlocker ulck(this);
853 
854  fLOD = TGLRnrCtx::kLODHigh;
855  fRnrCtx->SetGrabImage(kTRUE);
856 
857  if (!gVirtualX->IsCmdThread())
858  gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this));
859  else
860  DoDraw(kFALSE);
861 
862  fRnrCtx->SetGrabImage(kFALSE);
863 
864  glReadBuffer(GL_BACK);
865 
866  UChar_t* xx = new UChar_t[4 * fViewport.Width() * fViewport.Height()];
867  glPixelStorei(GL_PACK_ALIGNMENT, 1);
868  glReadPixels(0, 0, fViewport.Width(), fViewport.Height(),
869  GL_BGRA, GL_UNSIGNED_BYTE, xx);
870 
871  std::unique_ptr<TImage> image(TImage::Create());
872  image->FromGLBuffer(xx, fViewport.Width(), fViewport.Height());
873  image->WriteImage(fileName);
874 
875  delete [] xx;
876 
877  return kTRUE;
878 }
879 
880 ////////////////////////////////////////////////////////////////////////////////
881 /// Save current image in various formats (gif, gif+, jpg, png).
882 /// 'gif+' will append image to an existing file (animated gif).
883 /// Frame-Buffer-Object is used for capturing of the image - OpenGL
884 /// 1.5 is required.
885 /// The viewer window does not have to be visible at all.
886 /// Returns false if something obvious goes wrong, true otherwise.
887 ///
888 /// pixel_object_scale is used to scale (as much as possible) the
889 /// objects whose representation size is pixel based (point-sizes,
890 /// line-widths, bitmap/pixmap font-sizes).
891 /// If set to 0 (default) no scaling is applied.
892 
893 Bool_t TGLViewer::SavePictureUsingFBO(const TString &fileName, Int_t w, Int_t h,
894  Float_t pixel_object_scale)
895 {
896  static const TString eh("TGLViewer::SavePictureUsingFBO");
897 
898  if (! fileName.EndsWith(".gif") && ! fileName.Contains(".gif+") &&
899  ! fileName.EndsWith(".jpg") && ! fileName.EndsWith(".png"))
900  {
901  Warning(eh, "file %s cannot be saved with this extension.", fileName.Data());
902  return kFALSE;
903  }
904 
905  if ( ! TakeLock(kDrawLock)) {
906  Error(eh, "viewer locked - try later.");
907  return kFALSE;
908  }
909 
910  TUnlocker ulck(this);
911 
912  MakeCurrent();
913 
914  TGLFBO *fbo = new TGLFBO();
915  try
916  {
917  fbo->Init(w, h, fGLWidget->GetPixelFormat()->GetSamples());
918  }
919  catch (std::runtime_error& exc)
920  {
921  Error(eh, "%s",exc.what());
922  if (gEnv->GetValue("OpenGL.SavePictureFallbackToBB", 1)) {
923  Info(eh, "Falling back to saving image via back-buffer. Window must be fully visible.");
924  if (w != fViewport.Width() || h != fViewport.Height())
925  Warning(eh, "Back-buffer does not support image scaling, window size will be used.");
926  return SavePictureUsingBB(fileName);
927  } else {
928  return kFALSE;
929  }
930  }
931 
932  TGLRect old_vp(fViewport);
933  SetViewport(0, 0, w, h);
934 
935  Float_t old_scale = 1;
936  if (pixel_object_scale != 0)
937  {
938  old_scale = fRnrCtx->GetRenderScale();
939  fRnrCtx->SetRenderScale(old_scale * pixel_object_scale);
940  }
941 
942  fbo->Bind();
943 
944  fLOD = TGLRnrCtx::kLODHigh;
945  fRnrCtx->SetGrabImage(kTRUE);
946 
947  if (!gVirtualX->IsCmdThread())
948  gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this));
949  else
950  DoDraw(kFALSE);
951 
952  fRnrCtx->SetGrabImage(kFALSE);
953 
954  fbo->Unbind();
955 
956  fbo->SetAsReadBuffer();
957 
958  UChar_t* xx = new UChar_t[4 * fViewport.Width() * fViewport.Height()];
959  glPixelStorei(GL_PACK_ALIGNMENT, 1);
960  glReadPixels(0, 0, fViewport.Width(), fViewport.Height(),
961  GL_BGRA, GL_UNSIGNED_BYTE, xx);
962 
963  std::unique_ptr<TImage> image(TImage::Create());
964  image->FromGLBuffer(xx, fViewport.Width(), fViewport.Height());
965  image->WriteImage(fileName);
966 
967  delete [] xx;
968 
969  delete fbo;
970 
971  if (pixel_object_scale != 0)
972  {
973  fRnrCtx->SetRenderScale(old_scale);
974  }
975 
976  SetViewport(old_vp);
977 
978  return kTRUE;
979 }
980 
981 ////////////////////////////////////////////////////////////////////////////////
982 /// Returns current image.
983 /// Back-Buffer is used for capturing of the image.
984 /// The viewer window most be fully contained within the desktop but
985 /// can be covered by other windows.
986 
987 TImage* TGLViewer::GetPictureUsingBB()
988 {
989  static const TString eh("TGLViewer::GetPictureUsingBB");
990 
991  if ( ! TakeLock(kDrawLock)) {
992  Error(eh, "viewer locked - try later.");
993  return NULL;
994  }
995 
996  TUnlocker ulck(this);
997 
998  fLOD = TGLRnrCtx::kLODHigh;
999  fRnrCtx->SetGrabImage(kTRUE);
1000 
1001  if (!gVirtualX->IsCmdThread())
1002  gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this));
1003  else
1004  DoDraw(kFALSE);
1005 
1006  fRnrCtx->SetGrabImage(kFALSE);
1007 
1008  glReadBuffer(GL_BACK);
1009 
1010  UChar_t* xx = new UChar_t[4 * fViewport.Width() * fViewport.Height()];
1011  glPixelStorei(GL_PACK_ALIGNMENT, 1);
1012  glReadPixels(0, 0, fViewport.Width(), fViewport.Height(),
1013  GL_BGRA, GL_UNSIGNED_BYTE, xx);
1014 
1015  TImage *image(TImage::Create());
1016  image->FromGLBuffer(xx, fViewport.Width(), fViewport.Height());
1017 
1018  delete [] xx;
1019 
1020  return image;
1021 }
1022 
1023 ////////////////////////////////////////////////////////////////////////////////
1024 /// Returns current image.
1025 /// Frame-Buffer-Object is used for capturing of the image - OpenGL
1026 /// 1.5 is required.
1027 /// The viewer window does not have to be visible at all.
1028 ///
1029 /// pixel_object_scale is used to scale (as much as possible) the
1030 /// objects whose representation size is pixel based (point-sizes,
1031 /// line-widths, bitmap/pixmap font-sizes).
1032 /// If set to 0 (default) no scaling is applied.
1033 
1034 TImage* TGLViewer::GetPictureUsingFBO(Int_t w, Int_t h,Float_t pixel_object_scale)
1035 {
1036  static const TString eh("TGLViewer::GetPictureUsingFBO");
1037 
1038  if ( ! TakeLock(kDrawLock)) {
1039  Error(eh, "viewer locked - try later.");
1040  return NULL;
1041  }
1042 
1043  TUnlocker ulck(this);
1044 
1045  MakeCurrent();
1046 
1047  TGLFBO *fbo = new TGLFBO();
1048  try
1049  {
1050  fbo->Init(w, h, fGLWidget->GetPixelFormat()->GetSamples());
1051  }
1052  catch (std::runtime_error& exc)
1053  {
1054  Error(eh, "%s",exc.what());
1055  if (gEnv->GetValue("OpenGL.GetPictureFallbackToBB", 1)) {
1056  Info(eh, "Falling back to saving image via back-buffer. Window must be fully visible.");
1057  if (w != fViewport.Width() || h != fViewport.Height())
1058  Warning(eh, "Back-buffer does not support image scaling, window size will be used.");
1059  return GetPictureUsingBB();
1060  } else {
1061  return NULL;
1062  }
1063  }
1064 
1065  TGLRect old_vp(fViewport);
1066  SetViewport(0, 0, w, h);
1067 
1068  Float_t old_scale = 1;
1069  if (pixel_object_scale != 0)
1070  {
1071  old_scale = fRnrCtx->GetRenderScale();
1072  fRnrCtx->SetRenderScale(old_scale * pixel_object_scale);
1073  }
1074 
1075  fbo->Bind();
1076 
1077  fLOD = TGLRnrCtx::kLODHigh;
1078  fRnrCtx->SetGrabImage(kTRUE);
1079 
1080  if (!gVirtualX->IsCmdThread())
1081  gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoDraw(kFALSE)", (ULong_t)this));
1082  else
1083  DoDraw(kFALSE);
1084 
1085  fRnrCtx->SetGrabImage(kFALSE);
1086 
1087  fbo->Unbind();
1088 
1089  fbo->SetAsReadBuffer();
1090 
1091  UChar_t* xx = new UChar_t[4 * fViewport.Width() * fViewport.Height()];
1092  glPixelStorei(GL_PACK_ALIGNMENT, 1);
1093  glReadPixels(0, 0, fViewport.Width(), fViewport.Height(),
1094  GL_BGRA, GL_UNSIGNED_BYTE, xx);
1095 
1096  TImage *image(TImage::Create());
1097  image->FromGLBuffer(xx, fViewport.Width(), fViewport.Height());
1098 
1099  delete [] xx;
1100  delete fbo;
1101 
1102  if (pixel_object_scale != 0)
1103  {
1104  fRnrCtx->SetRenderScale(old_scale);
1105  }
1106 
1107  SetViewport(old_vp);
1108 
1109  return image;
1110 }
1111 
1112 
1113 ////////////////////////////////////////////////////////////////////////////////
1114 /// Save picture with given width (height scaled proportionally).
1115 /// If pixel_object_scale is true (default), the corresponding
1116 /// scaling gets calculated from the current window size.
1117 
1118 Bool_t TGLViewer::SavePictureWidth(const TString &fileName, Int_t width,
1119  Bool_t pixel_object_scale)
1120 {
1121  Float_t scale = Float_t(width) / fViewport.Width();
1122  Int_t height = TMath::Nint(scale*fViewport.Height());
1123 
1124  return SavePictureUsingFBO(fileName, width, height, pixel_object_scale ? scale : 0);
1125 }
1126 
1127 ////////////////////////////////////////////////////////////////////////////////
1128 /// Save picture with given height (width scaled proportionally).
1129 /// If pixel_object_scale is true (default), the corresponding
1130 /// scaling gets calculated from the current window size.
1131 
1132 Bool_t TGLViewer::SavePictureHeight(const TString &fileName, Int_t height,
1133  Bool_t pixel_object_scale)
1134 {
1135  Float_t scale = Float_t(height) / fViewport.Height();
1136  Int_t width = TMath::Nint(scale*fViewport.Width());
1137 
1138  return SavePictureUsingFBO(fileName, width, height, pixel_object_scale ? scale : 0);
1139 }
1140 
1141 ////////////////////////////////////////////////////////////////////////////////
1142 /// Save picture with given scale to current window size.
1143 /// If pixel_object_scale is true (default), the same scaling is
1144 /// used.
1145 
1146 Bool_t TGLViewer::SavePictureScale (const TString &fileName, Float_t scale,
1147  Bool_t pixel_object_scale)
1148 {
1149  Int_t w = TMath::Nint(scale*fViewport.Width());
1150  Int_t h = TMath::Nint(scale*fViewport.Height());
1151 
1152  return SavePictureUsingFBO(fileName, w, h, pixel_object_scale ? scale : 0);
1153 }
1154 
1155 ////////////////////////////////////////////////////////////////////////////////
1156 /// Draw reference marker and coordinate axes.
1157 
1158 void TGLViewer::DrawGuides()
1159 {
1160  Bool_t disabled = kFALSE;
1161  if (fReferenceOn)
1162  {
1163  glDisable(GL_DEPTH_TEST);
1164  TGLUtil::DrawReferenceMarker(*fCamera, fReferencePos);
1165  disabled = kTRUE;
1166  }
1167  if (fDrawCameraCenter)
1168  {
1169  glDisable(GL_DEPTH_TEST);
1170  Float_t radius = fCamera->ViewportDeltaToWorld(TGLVertex3(fCamera->GetCenterVec()), 3, 3).Mag();
1171  const UChar_t rgba[4] = { 0, 255, 255, 255 };
1172  TGLUtil::DrawSphere(fCamera->GetCenterVec(), radius, rgba);
1173  disabled = kTRUE;
1174  }
1175  if (fAxesDepthTest && disabled)
1176  {
1177  glEnable(GL_DEPTH_TEST);
1178  disabled = kFALSE;
1179  }
1180  else if (fAxesDepthTest == kFALSE && disabled == kFALSE)
1181  {
1182  glDisable(GL_DEPTH_TEST);
1183  disabled = kTRUE;
1184  }
1185  TGLUtil::DrawSimpleAxes(*fCamera, fOverallBoundingBox, fAxesType);
1186  if (disabled)
1187  glEnable(GL_DEPTH_TEST);
1188 }
1189 
1190 ////////////////////////////////////////////////////////////////////////////////
1191 /// If in debug mode draw camera aids and overall bounding box.
1192 
1193 void TGLViewer::DrawDebugInfo()
1194 {
1195  if (fDebugMode)
1196  {
1197  glDisable(GL_LIGHTING);
1198  CurrentCamera().DrawDebugAids();
1199 
1200  // Green scene bounding box
1201  glColor3d(0.0, 1.0, 0.0);
1202  fOverallBoundingBox.Draw();
1203 
1204  // Scene bounding box center sphere (green) and
1205  glDisable(GL_DEPTH_TEST);
1206  Double_t size = fOverallBoundingBox.Extents().Mag() / 200.0;
1207  TGLUtil::DrawSphere(TGLVertex3(0.0, 0.0, 0.0), size, TGLUtil::fgWhite);
1208  const TGLVertex3 & center = fOverallBoundingBox.Center();
1209  TGLUtil::DrawSphere(center, size, TGLUtil::fgGreen);
1210  glEnable(GL_DEPTH_TEST);
1211 
1212  glEnable(GL_LIGHTING);
1213  }
1214 }
1215 
1216 ////////////////////////////////////////////////////////////////////////////////
1217 /// Perform GL work which must be done before each draw.
1218 
1219 void TGLViewer::PreDraw()
1220 {
1221  InitGL();
1222 
1223  // For embedded gl clear color must be pad's background color.
1224  {
1225  Color_t ci = (fGLDevice != -1) ? gPad->GetFillColor() : fRnrCtx->ColorSet().Background().GetColorIndex();
1226  TColor *color = gROOT->GetColor(ci);
1227  Float_t rgb[3];
1228  if (color)
1229  color->GetRGB(rgb[0], rgb[1], rgb[2]);
1230  else
1231  rgb[0] = rgb[1] = rgb[2] = 0.0f;
1232 
1233  glClearColor(rgb[0], rgb[1], rgb[2], 0.0f);
1234  }
1235 
1236  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1237 
1238  TGLUtil::CheckError("TGLViewer::PreDraw");
1239 }
1240 
1241 ////////////////////////////////////////////////////////////////////////////////
1242 /// Perform GL work which must be done after each draw.
1243 
1244 void TGLViewer::PostDraw()
1245 {
1246  glFlush();
1247  TGLUtil::CheckError("TGLViewer::PostDraw");
1248 }
1249 
1250 ////////////////////////////////////////////////////////////////////////////////
1251 /// Draw a rectangle (background color and given alpha) across the
1252 /// whole viewport.
1253 
1254 void TGLViewer::FadeView(Float_t alpha)
1255 {
1256  static const Float_t z = -1.0f;
1257 
1258  glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
1259  glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();
1260 
1261  {
1262  TGLCapabilitySwitch blend(GL_BLEND, kTRUE);
1263  TGLCapabilitySwitch light(GL_LIGHTING, kFALSE);
1264  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1265  TGLUtil::ColorAlpha(fRnrCtx->ColorSet().Background(), alpha);
1266  glBegin(GL_QUADS);
1267  glVertex3f(-1, -1, z); glVertex3f( 1, -1, z);
1268  glVertex3f( 1, 1, z); glVertex3f(-1, 1, z);
1269  glEnd();
1270  }
1271 
1272  glMatrixMode(GL_PROJECTION); glPopMatrix();
1273  glMatrixMode(GL_MODELVIEW); glPopMatrix();
1274 }
1275 
1276 ////////////////////////////////////////////////////////////////////////////////
1277 /// Make GL context current
1278 
1279 void TGLViewer::MakeCurrent() const
1280 {
1281  if (fGLDevice == -1)
1282  fGLWidget->MakeCurrent();
1283  else
1284  gGLManager->MakeCurrent(fGLDevice);
1285 }
1286 
1287 ////////////////////////////////////////////////////////////////////////////////
1288 /// Swap GL buffers
1289 
1290 void TGLViewer::SwapBuffers() const
1291 {
1292  if ( ! IsDrawOrSelectLock()) {
1293  Error("TGLViewer::SwapBuffers", "viewer is %s", LockName(CurrentLock()));
1294  }
1295  if (fGLDevice == -1)
1296  fGLWidget->SwapBuffers();
1297  else {
1298  gGLManager->ReadGLBuffer(fGLDevice);
1299  gGLManager->Flush(fGLDevice);
1300  gGLManager->MarkForDirectCopy(fGLDevice, kFALSE);
1301  }
1302 }
1303 
1304 ////////////////////////////////////////////////////////////////////////////////
1305 /// Post request for selection render pass viewer, picking objects
1306 /// around the window point (x,y).
1307 
1308 Bool_t TGLViewer::RequestSelect(Int_t x, Int_t y)
1309 {
1310  // Take select lock on scene immediately we enter here - it is released
1311  // in the other (drawing) thread - see TGLViewer::DoSelect()
1312 
1313  if ( ! TakeLock(kSelectLock)) {
1314  return kFALSE;
1315  }
1316 
1317  if (!gVirtualX->IsCmdThread())
1318  return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoSelect(%d, %d)", (ULong_t)this, x, y)));
1319  else
1320  return DoSelect(x, y);
1321 }
1322 
1323 ////////////////////////////////////////////////////////////////////////////////
1324 /// Perform GL selection, picking objects overlapping WINDOW
1325 /// area described by 'rect'. Return kTRUE if selection should be
1326 /// changed, kFALSE otherwise.
1327 /// Select lock should already been taken in other thread in
1328 /// TGLViewer::ReqSelect().
1329 
1330 Bool_t TGLViewer::DoSelect(Int_t x, Int_t y)
1331 {
1332  R__LOCKGUARD(gROOTMutex);
1333 
1334  if (CurrentLock() != kSelectLock) {
1335  Error("TGLViewer::DoSelect", "expected kSelectLock, found %s", LockName(CurrentLock()));
1336  return kFALSE;
1337  }
1338 
1339  TGLUtil::PointToViewport(x, y);
1340 
1341  TUnlocker ulck(this);
1342 
1343  MakeCurrent();
1344 
1345  fRnrCtx->BeginSelection(x, y, TGLUtil::GetPickingRadius());
1346  glRenderMode(GL_SELECT);
1347 
1348  PreRender();
1349  TGLViewerBase::Render();
1350  PostRender();
1351 
1352  Int_t nHits = glRenderMode(GL_RENDER);
1353  fRnrCtx->EndSelection(nHits);
1354 
1355  // Process selection.
1356  if (gDebug > 0) Info("TGLViewer::DoSelect", "Primary select nHits=%d.", nHits);
1357 
1358  if (nHits > 0)
1359  {
1360  Int_t idx = 0;
1361  if (FindClosestRecord(fSelRec, idx))
1362  {
1363  if (fSelRec.GetTransparent() && fRnrCtx->SelectTransparents() != TGLRnrCtx::kIfClosest)
1364  {
1365  TGLSelectRecord opaque;
1366  if (FindClosestOpaqueRecord(opaque, ++idx))
1367  fSelRec = opaque;
1368  else if (fRnrCtx->SelectTransparents() == TGLRnrCtx::kNever)
1369  fSelRec.Reset();
1370  }
1371  if (gDebug > 1) fSelRec.Print();
1372  }
1373  } else {
1374  fSelRec.Reset();
1375  }
1376 
1377  ReleaseLock(kSelectLock);
1378  return ! TGLSelectRecord::AreSameSelectionWise(fSelRec, fCurrentSelRec);
1379 }
1380 
1381 ////////////////////////////////////////////////////////////////////////////////
1382 /// Request secondary select.
1383 
1384 Bool_t TGLViewer::RequestSecondarySelect(Int_t x, Int_t y)
1385 {
1386  if ( ! TakeLock(kSelectLock)) {
1387  return kFALSE;
1388  }
1389 
1390  if (!gVirtualX->IsCmdThread())
1391  return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoSecondarySelect(%d, %d)", (ULong_t)this, x, y)));
1392  else
1393  return DoSecondarySelect(x, y);
1394 }
1395 
1396 ////////////////////////////////////////////////////////////////////////////////
1397 /// Secondary selection.
1398 
1399 Bool_t TGLViewer::DoSecondarySelect(Int_t x, Int_t y)
1400 {
1401  R__LOCKGUARD(gROOTMutex);
1402 
1403  if (CurrentLock() != kSelectLock) {
1404  Error("TGLViewer::DoSecondarySelect", "expected kSelectLock, found %s", LockName(CurrentLock()));
1405  return kFALSE;
1406  }
1407 
1408  TGLUtil::PointToViewport(x, y);
1409 
1410  TUnlocker ulck(this);
1411 
1412  if (! fSelRec.GetSceneInfo() || ! fSelRec.GetPhysShape() ||
1413  ! fSelRec.GetLogShape()->SupportsSecondarySelect())
1414  {
1415  if (gDebug > 0)
1416  Info("TGLViewer::SecondarySelect", "Skipping secondary selection "
1417  "(sinfo=0x%lx, pshape=0x%lx).\n",
1418  (Long_t)fSelRec.GetSceneInfo(), (Long_t)fSelRec.GetPhysShape());
1419  fSecSelRec.Reset();
1420  return kFALSE;
1421  }
1422 
1423  MakeCurrent();
1424 
1425  TGLSceneInfo* sinfo = fSelRec.GetSceneInfo();
1426  TGLSceneBase* scene = sinfo->GetScene();
1427  TGLPhysicalShape* pshp = fSelRec.GetPhysShape();
1428 
1429  SceneInfoList_t foo;
1430  foo.push_back(sinfo);
1431  fScenes.swap(foo);
1432  fRnrCtx->BeginSelection(x, y, TGLUtil::GetPickingRadius());
1433  fRnrCtx->SetSecSelection(kTRUE);
1434  glRenderMode(GL_SELECT);
1435 
1436  PreRender();
1437  fRnrCtx->SetSceneInfo(sinfo);
1438  scene->PreRender(*fRnrCtx);
1439  fRnrCtx->SetDrawPass(TGLRnrCtx::kPassFill);
1440  fRnrCtx->SetShapeLOD(TGLRnrCtx::kLODHigh);
1441  glPushName(pshp->ID());
1442  // !!! Hack: does not use clipping and proper draw-pass settings.
1443  pshp->Draw(*fRnrCtx);
1444  glPopName();
1445  scene->PostRender(*fRnrCtx);
1446  fRnrCtx->SetSceneInfo(0);
1447  PostRender();
1448 
1449  Int_t nSecHits = glRenderMode(GL_RENDER);
1450  fRnrCtx->EndSelection(nSecHits);
1451  fScenes.swap(foo);
1452 
1453  if (gDebug > 0) Info("TGLViewer::DoSelect", "Secondary select nSecHits=%d.", nSecHits);
1454 
1455  ReleaseLock(kSelectLock);
1456 
1457  if (nSecHits > 0)
1458  {
1459  fSecSelRec = fSelRec;
1460  fSecSelRec.SetRawOnly(fRnrCtx->GetSelectBuffer()->RawRecord(0));
1461  if (gDebug > 1) fSecSelRec.Print();
1462  return kTRUE;
1463  } else {
1464  fSecSelRec.Reset();
1465  return kFALSE;
1466  }
1467 }
1468 
1469 ////////////////////////////////////////////////////////////////////////////////
1470 /// Process result from last selection (in fSelRec) and
1471 /// extract a new current selection from it.
1472 /// Here we only use physical shape.
1473 
1474 void TGLViewer::ApplySelection()
1475 {
1476  fCurrentSelRec = fSelRec;
1477 
1478  TGLPhysicalShape *selPhys = fSelRec.GetPhysShape();
1479  fSelectedPShapeRef->SetPShape(selPhys);
1480 
1481  // Inform external client selection has been modified.
1482  SelectionChanged();
1483 
1484  RequestDraw(TGLRnrCtx::kLODHigh);
1485 }
1486 
1487 ////////////////////////////////////////////////////////////////////////////////
1488 /// Post request for secondary selection rendering of selected object
1489 /// around the window point (x,y).
1490 
1491 Bool_t TGLViewer::RequestOverlaySelect(Int_t x, Int_t y)
1492 {
1493  // Take select lock on viewer immediately - it is released
1494  // in the other (drawing) thread - see TGLViewer::DoSecondarySelect().
1495 
1496  if ( ! TakeLock(kSelectLock)) {
1497  return kFALSE;
1498  }
1499 
1500  if (!gVirtualX->IsCmdThread())
1501  return Bool_t(gROOT->ProcessLineFast(Form("((TGLViewer *)0x%lx)->DoOverlaySelect(%d, %d)", (ULong_t)this, x, y)));
1502  else
1503  return DoOverlaySelect(x, y);
1504 }
1505 
1506 ////////////////////////////////////////////////////////////////////////////////
1507 /// Perform GL selection, picking overlay objects only.
1508 /// Return TRUE if the selected overlay-element has changed.
1509 
1510 Bool_t TGLViewer::DoOverlaySelect(Int_t x, Int_t y)
1511 {
1512  R__LOCKGUARD(gROOTMutex);
1513 
1514  if (CurrentLock() != kSelectLock) {
1515  Error("TGLViewer::DoOverlaySelect", "expected kSelectLock, found %s", LockName(CurrentLock()));
1516  return kFALSE;
1517  }
1518 
1519  TGLUtil::PointToViewport(x, y);
1520 
1521  TUnlocker ulck(this);
1522 
1523  MakeCurrent();
1524 
1525  fRnrCtx->BeginSelection(x, y, TGLUtil::GetPickingRadius());
1526  glRenderMode(GL_SELECT);
1527 
1528  PreRenderOverlaySelection();
1529  RenderOverlay(TGLOverlayElement::kActive, kTRUE);
1530  PostRenderOverlaySelection();
1531 
1532  Int_t nHits = glRenderMode(GL_RENDER);
1533  fRnrCtx->EndSelection(nHits);
1534 
1535  // Process overlay selection.
1536  TGLOverlayElement * selElm = 0;
1537  if (nHits > 0)
1538  {
1539  Int_t idx = 0;
1540  while (idx < nHits && FindClosestOverlayRecord(fOvlSelRec, idx))
1541  {
1542  TGLOverlayElement* el = fOvlSelRec.GetOvlElement();
1543  if (el == fCurrentOvlElm)
1544  {
1545  if (el->MouseStillInside(fOvlSelRec))
1546  {
1547  selElm = el;
1548  break;
1549  }
1550  }
1551  else if (el->MouseEnter(fOvlSelRec))
1552  {
1553  selElm = el;
1554  break;
1555  }
1556  ++idx;
1557  }
1558  }
1559  else
1560  {
1561  fOvlSelRec.Reset();
1562  }
1563 
1564  ReleaseLock(kSelectLock);
1565 
1566  if (fCurrentOvlElm != selElm)
1567  {
1568  if (fCurrentOvlElm) fCurrentOvlElm->MouseLeave();
1569  fCurrentOvlElm = selElm;
1570  return kTRUE;
1571  }
1572  else
1573  {
1574  return kFALSE;
1575  }
1576 }
1577 
1578 ////////////////////////////////////////////////////////////////////////////////
1579 /// Make one fading step and request redraw.
1580 
1581 void TGLFaderHelper::MakeFadeStep()
1582 {
1583  Float_t fade = fViewer->GetFader();
1584 
1585  if (fade == fFadeTarget) {
1586  delete this; return;
1587  }
1588  if (TMath::Abs(fFadeTarget - fade) < 1e-3) {
1589  fViewer->SetFader(fFadeTarget);
1590  fViewer->RequestDraw(TGLRnrCtx::kLODHigh);
1591  delete this;
1592  return;
1593  }
1594 
1595  Float_t dt = fTime/fNSteps;
1596  Float_t df = (fFadeTarget - fade)/fNSteps;
1597  fViewer->SetFader(fade + df);
1598  fViewer->RequestDraw(TGLRnrCtx::kLODHigh);
1599  fTime -= dt; --fNSteps;
1600  TTimer::SingleShot(TMath::CeilNint(1000*dt),
1601  "TGLFaderHelper", this, "MakeFadeStep()");
1602 }
1603 
1604 ////////////////////////////////////////////////////////////////////////////////
1605 /// Animate fading from current value to fade over given time (sec)
1606 /// and number of steps.
1607 
1608 void TGLViewer::AutoFade(Float_t fade, Float_t time, Int_t steps)
1609 {
1610  TGLFaderHelper* fh = new TGLFaderHelper(this, fade, time, steps);
1611  fh->MakeFadeStep();
1612 }
1613 
1614 ////////////////////////////////////////////////////////////////////////////////
1615 /// Use the dark color-set.
1616 
1617 void TGLViewer::UseDarkColorSet()
1618 {
1619  fRnrCtx->ChangeBaseColorSet(&fDarkColorSet);
1620  RefreshPadEditor(this);
1621 }
1622 
1623 ////////////////////////////////////////////////////////////////////////////////
1624 /// Use the light color-set.
1625 
1626 void TGLViewer::UseLightColorSet()
1627 {
1628  fRnrCtx->ChangeBaseColorSet(&fLightColorSet);
1629  RefreshPadEditor(this);
1630 }
1631 
1632 ////////////////////////////////////////////////////////////////////////////////
1633 /// Switch between dark and light colorsets.
1634 
1635 void TGLViewer::SwitchColorSet()
1636 {
1637  if (IsUsingDefaultColorSet())
1638  {
1639  Info("SwitchColorSet()", "Global color-set is in use, switch not supported.");
1640  return;
1641  }
1642 
1643  if (fRnrCtx->GetBaseColorSet() == &fLightColorSet)
1644  UseDarkColorSet();
1645  else
1646  UseLightColorSet();
1647 }
1648 
1649 ////////////////////////////////////////////////////////////////////////////////
1650 /// Set usage of the default color set.
1651 
1652 void TGLViewer::UseDefaultColorSet(Bool_t x)
1653 {
1654  if (x)
1655  fRnrCtx->ChangeBaseColorSet(&fgDefaultColorSet);
1656  else
1657  fRnrCtx->ChangeBaseColorSet(&fDarkColorSet);
1658  RefreshPadEditor(this);
1659 }
1660 
1661 ////////////////////////////////////////////////////////////////////////////////
1662 /// Check if the viewer is using the default color set.
1663 /// If yes, some operations might be disabled.
1664 
1665 Bool_t TGLViewer::IsUsingDefaultColorSet() const
1666 {
1667  return fRnrCtx->GetBaseColorSet() == &fgDefaultColorSet;
1668 }
1669 
1670 ////////////////////////////////////////////////////////////////////////////////
1671 /// Set background method.
1672 /// Deprecated method - set background color in the color-set.
1673 
1674 void TGLViewer::SetClearColor(Color_t col)
1675 {
1676  fRnrCtx->GetBaseColorSet()->Background().SetColor(col);
1677 }
1678 
1679 ////////////////////////////////////////////////////////////////////////////////
1680 /// Returns reference to the default color-set.
1681 /// Static function.
1682 
1683 TGLColorSet& TGLViewer::GetDefaultColorSet()
1684 {
1685  return fgDefaultColorSet;
1686 }
1687 
1688 ////////////////////////////////////////////////////////////////////////////////
1689 /// Sets static flag that determines if new viewers should use the
1690 /// default color-set.
1691 /// This is false at startup.
1692 
1693 void TGLViewer::UseDefaultColorSetForNewViewers(Bool_t x)
1694 {
1695  fgUseDefaultColorSetForNewViewers = x;
1696 }
1697 
1698 ////////////////////////////////////////////////////////////////////////////////
1699 /// Returns the value of the static flag that determines if new
1700 /// viewers should use the default color-set.
1701 /// This is false at startup.
1702 
1703 Bool_t TGLViewer::IsUsingDefaultColorSetForNewViewers()
1704 {
1705  return fgUseDefaultColorSetForNewViewers;
1706 }
1707 
1708 ////////////////////////////////////////////////////////////////////////////////
1709 /// Returns true if current color set is dark.
1710 
1711 Bool_t TGLViewer::IsColorSetDark() const
1712 {
1713  return fRnrCtx->GetBaseColorSet() == &fDarkColorSet;
1714 }
1715 
1716 /**************************************************************************/
1717 // Viewport
1718 /**************************************************************************/
1719 
1720 ////////////////////////////////////////////////////////////////////////////////
1721 /// Set viewer viewport (window area) with bottom/left at (x,y), with
1722 /// dimensions 'width'/'height'
1723 
1724 void TGLViewer::SetViewport(Int_t x, Int_t y, Int_t width, Int_t height)
1725 {
1726  if (fStereo && ! fStereoQuadBuf) width /= 2;
1727 
1728  // Only process if changed
1729  if (fViewport.X() == x && fViewport.Y() == y &&
1730  fViewport.Width() == width && fViewport.Height() == height) {
1731  return;
1732  }
1733 
1734  fViewport.Set(x, y, width, height);
1735  fCurrentCamera->SetViewport(fViewport);
1736 
1737  if (gDebug > 2) {
1738  Info("TGLViewer::SetViewport", "updated - corner %d,%d dimensions %d,%d", x, y, width, height);
1739  }
1740 }
1741 
1742 void TGLViewer::SetViewport(const TGLRect& vp)
1743 {
1744  // Set viewer viewport from TGLRect.
1745 
1746  SetViewport(vp.X(), vp.Y(), vp.Width(), vp.Height());
1747 }
1748 
1749 /**************************************************************************/
1750 // Camera methods
1751 /**************************************************************************/
1752 
1753 ////////////////////////////////////////////////////////////////////////////////
1754 /// Return camera reference by type.
1755 
1756 TGLCamera& TGLViewer::RefCamera(ECameraType cameraType)
1757 {
1758  // TODO: Move these into a vector!
1759  switch(cameraType) {
1760  case kCameraPerspXOZ:
1761  return fPerspectiveCameraXOZ;
1762  case kCameraPerspYOZ:
1763  return fPerspectiveCameraYOZ;
1764  case kCameraPerspXOY:
1765  return fPerspectiveCameraXOY;
1766  case kCameraOrthoXOY:
1767  return fOrthoXOYCamera;
1768  case kCameraOrthoXOZ:
1769  return fOrthoXOZCamera;
1770  case kCameraOrthoZOY:
1771  return fOrthoZOXCamera;
1772  case kCameraOrthoZOX:
1773  return fOrthoZOYCamera;
1774  case kCameraOrthoXnOY:
1775  return fOrthoXnOYCamera;
1776  case kCameraOrthoXnOZ:
1777  return fOrthoXnOZCamera;
1778  case kCameraOrthoZnOY:
1779  return fOrthoZnOYCamera;
1780  case kCameraOrthoZnOX:
1781  return fOrthoZnOXCamera;
1782  default:
1783  Error("TGLViewer::SetCurrentCamera", "invalid camera type");
1784  return *fCurrentCamera;
1785  }
1786 }
1787 
1788 ////////////////////////////////////////////////////////////////////////////////
1789 /// Set current active camera - 'cameraType' one of:
1790 /// kCameraPerspX, kCameraPerspY, kCameraPerspZ,
1791 /// kCameraOrthoXOY, kCameraOrthoXOZ, kCameraOrthoZOY,
1792 /// kCameraOrthoXnOY, kCameraOrthoXnOZ, kCameraOrthoZnOY
1793 
1794 void TGLViewer::SetCurrentCamera(ECameraType cameraType)
1795 {
1796  if (IsLocked()) {
1797  Error("TGLViewer::SetCurrentCamera", "expected kUnlocked, found %s", LockName(CurrentLock()));
1798  return;
1799  }
1800 
1801  // TODO: Move these into a vector!
1802  TGLCamera *prev = fCurrentCamera;
1803  switch (cameraType)
1804  {
1805  case kCameraPerspXOZ: {
1806  fCurrentCamera = &fPerspectiveCameraXOZ;
1807  break;
1808  }
1809  case kCameraPerspYOZ: {
1810  fCurrentCamera = &fPerspectiveCameraYOZ;
1811  break;
1812  }
1813  case kCameraPerspXOY: {
1814  fCurrentCamera = &fPerspectiveCameraXOY;
1815  break;
1816  }
1817  case kCameraOrthoXOY: {
1818  fCurrentCamera = &fOrthoXOYCamera;
1819  break;
1820  }
1821  case kCameraOrthoXOZ: {
1822  fCurrentCamera = &fOrthoXOZCamera;
1823  break;
1824  }
1825  case kCameraOrthoZOY: {
1826  fCurrentCamera = &fOrthoZOYCamera;
1827  break;
1828  }
1829  case kCameraOrthoZOX: {
1830  fCurrentCamera = &fOrthoZOXCamera;
1831  break;
1832  }
1833  case kCameraOrthoXnOY: {
1834  fCurrentCamera = &fOrthoXnOYCamera;
1835  break;
1836  }
1837  case kCameraOrthoXnOZ: {
1838  fCurrentCamera = &fOrthoXnOZCamera;
1839  break;
1840  }
1841  case kCameraOrthoZnOY: {
1842  fCurrentCamera = &fOrthoZnOYCamera;
1843  break;
1844  }
1845  case kCameraOrthoZnOX: {
1846  fCurrentCamera = &fOrthoZnOXCamera;
1847  break;
1848  }
1849  default: {
1850  Error("TGLViewer::SetCurrentCamera", "invalid camera type");
1851  break;
1852  }
1853  }
1854 
1855  if (fCurrentCamera != prev)
1856  {
1857  // Ensure any viewport has been propagated to the current camera
1858  fCurrentCamera->SetViewport(fViewport);
1859  RefreshPadEditor(this);
1860 
1861  if (fAutoRotator)
1862  {
1863  if (fAutoRotator->IsRunning())
1864  {
1865  fAutoRotator->Stop();
1866  }
1867  else
1868  {
1869  if (fAutoRotator->GetCamera() == fCurrentCamera)
1870  {
1871  fAutoRotator->Start();
1872  }
1873  }
1874  }
1875 
1876  RequestDraw(TGLRnrCtx::kLODHigh);
1877  }
1878 }
1879 
1880 ////////////////////////////////////////////////////////////////////////////////
1881 /// Set an orthographic camera to supplied configuration - note this
1882 /// does not need to be the current camera - though you will not see
1883 /// the effect if it is not.
1884 ///
1885 /// 'camera' defines the ortho camera - one of kCameraOrthoXOY / XOZ / ZOY
1886 /// 'left' / 'right' / 'top' / 'bottom' define the WORLD coordinates which
1887 /// correspond with the left/right/top/bottom positions on the GL viewer viewport
1888 /// E.g. for kCameraOrthoXOY camera left/right are X world coords,
1889 /// top/bottom are Y world coords
1890 /// As this is an orthographic camera the other axis (in eye direction) is
1891 /// no relevant. The near/far clip planes are set automatically based in scene
1892 /// contents
1893 
1894 void TGLViewer::SetOrthoCamera(ECameraType camera,
1895  Double_t zoom, Double_t dolly,
1896  Double_t center[3],
1897  Double_t hRotate, Double_t vRotate)
1898 {
1899  // TODO: Move these into a vector!
1900  switch(camera) {
1901  case kCameraOrthoXOY: {
1902  fOrthoXOYCamera.Configure(zoom, dolly, center, hRotate, vRotate);
1903  if (fCurrentCamera == &fOrthoXOYCamera) {
1904  RequestDraw(TGLRnrCtx::kLODHigh);
1905  }
1906  break;
1907  }
1908  case kCameraOrthoXOZ: {
1909  fOrthoXOZCamera.Configure(zoom, dolly, center, hRotate, vRotate);
1910  if (fCurrentCamera == &fOrthoXOZCamera) {
1911  RequestDraw(TGLRnrCtx::kLODHigh);
1912  }
1913  break;
1914  }
1915  case kCameraOrthoZOY: {
1916  fOrthoZOYCamera.Configure(zoom, dolly, center, hRotate, vRotate);
1917  if (fCurrentCamera == &fOrthoZOYCamera) {
1918  RequestDraw(TGLRnrCtx::kLODHigh);
1919  }
1920  break;
1921  }
1922  case kCameraOrthoZOX: {
1923  fOrthoZOXCamera.Configure(zoom, dolly, center, hRotate, vRotate);
1924  if (fCurrentCamera == &fOrthoZOXCamera) {
1925  RequestDraw(TGLRnrCtx::kLODHigh);
1926  }
1927  break;
1928  }
1929  default: {
1930  Error("TGLViewer::SetOrthoCamera", "invalid camera type");
1931  break;
1932  }
1933  }
1934 }
1935 
1936 ////////////////////////////////////////////////////////////////////////////////
1937 /// Set a perspective camera to supplied configuration - note this
1938 /// does not need to be the current camera - though you will not see
1939 /// the effect if it is not.
1940 ///
1941 /// - 'camera' defines the persp camera - one of kCameraPerspXOZ, kCameraPerspYOZ, kCameraPerspXOY
1942 /// - 'fov' - field of view (lens angle) in degrees (clamped to 0.1 - 170.0)
1943 /// - 'dolly' - distance from 'center'
1944 /// - 'center' - world position from which dolly/hRotate/vRotate are measured
1945 /// camera rotates round this, always facing in (in center of viewport)
1946 /// - 'hRotate' - horizontal rotation from initial configuration in degrees
1947 /// - 'hRotate' - vertical rotation from initial configuration in degrees
1948 
1949 void TGLViewer::SetPerspectiveCamera(ECameraType camera,
1950  Double_t fov, Double_t dolly,
1951  Double_t center[3],
1952  Double_t hRotate, Double_t vRotate)
1953 {
1954  // TODO: Move these into a vector!
1955  switch(camera) {
1956  case kCameraPerspXOZ: {
1957  fPerspectiveCameraXOZ.Configure(fov, dolly, center, hRotate, vRotate);
1958  if (fCurrentCamera == &fPerspectiveCameraXOZ) {
1959  RequestDraw(TGLRnrCtx::kLODHigh);
1960  }
1961  break;
1962  }
1963  case kCameraPerspYOZ: {
1964  fPerspectiveCameraYOZ.Configure(fov, dolly, center, hRotate, vRotate);
1965  if (fCurrentCamera == &fPerspectiveCameraYOZ) {
1966  RequestDraw(TGLRnrCtx::kLODHigh);
1967  }
1968  break;
1969  }
1970  case kCameraPerspXOY: {
1971  fPerspectiveCameraXOY.Configure(fov, dolly, center, hRotate, vRotate);
1972  if (fCurrentCamera == &fPerspectiveCameraXOY) {
1973  RequestDraw(TGLRnrCtx::kLODHigh);
1974  }
1975  break;
1976  }
1977  default: {
1978  Error("TGLViewer::SetPerspectiveCamera", "invalid camera type");
1979  break;
1980  }
1981  }
1982 }
1983 
1984 ////////////////////////////////////////////////////////////////////////////////
1985 /// Change base-vectors defining the camera-base transformation of current
1986 /// camera. hAxis and vAxis are the default directions for forward
1987 /// (inverted) and upwards.
1988 
1989 void TGLViewer::ReinitializeCurrentCamera(const TGLVector3& hAxis, const TGLVector3& vAxis, Bool_t redraw)
1990 {
1991  TGLMatrix& cb = fCurrentCamera->RefCamBase();
1992  cb.Set(cb.GetTranslation(), vAxis, hAxis);
1993  fCurrentCamera->Setup(fOverallBoundingBox, kTRUE);
1994  if (redraw)
1995  RequestDraw();
1996 }
1997 
1998 ////////////////////////////////////////////////////////////////////////////////
1999 /// Get the auto-rotator for this viewer.
2000 
2001 TGLAutoRotator* TGLViewer::GetAutoRotator()
2002 {
2003  if (fAutoRotator == 0)
2004  fAutoRotator = new TGLAutoRotator(this);
2005  return fAutoRotator;
2006 }
2007 
2008 ////////////////////////////////////////////////////////////////////////////////
2009 /// Set the auto-rotator for this viewer. The old rotator is deleted.
2010 
2011 void TGLViewer::SetAutoRotator(TGLAutoRotator* ar)
2012 {
2013  delete fAutoRotator;
2014  fAutoRotator = ar;
2015 }
2016 
2017 ////////////////////////////////////////////////////////////////////////////////
2018 /// Enable stereo rendering.
2019 /// If quad_buf is true rendering is done into separate left and right GL
2020 /// buffers. This requires hardware support. Otherwise left and right images
2021 /// get rendered into left and right half of the window.
2022 /// Note that mouse highlighting and selection will not work exactly right
2023 /// as image for each eye gets slightly shifted and there are two different
2024 /// directions through the mouse pointer, one for each eye.
2025 
2026 void TGLViewer::SetStereo(Bool_t stereo, Bool_t quad_buf)
2027 {
2028  if (stereo != fStereo)
2029  {
2030  fStereo = stereo;
2031  fStereoQuadBuf = quad_buf;
2032  if (fStereo)
2033  SetViewport(fViewport.X(), fViewport.Y(), fViewport.Width(), fViewport.Height());
2034  else
2035  SetViewport(fViewport.X(), fViewport.Y(), 2*fViewport.Width(), fViewport.Height());
2036  }
2037  RequestDraw(TGLRnrCtx::kLODHigh);
2038 }
2039 
2040 /**************************************************************************/
2041 // Guide methods
2042 /**************************************************************************/
2043 
2044 ////////////////////////////////////////////////////////////////////////////////
2045 /// Fetch the state of guides (axes & reference markers) into arguments
2046 
2047 void TGLViewer::GetGuideState(Int_t & axesType, Bool_t & axesDepthTest, Bool_t & referenceOn, Double_t referencePos[3]) const
2048 {
2049  axesType = fAxesType;
2050  axesDepthTest = fAxesDepthTest;
2051 
2052  referenceOn = fReferenceOn;
2053  referencePos[0] = fReferencePos.X();
2054  referencePos[1] = fReferencePos.Y();
2055  referencePos[2] = fReferencePos.Z();
2056 }
2057 
2058 ////////////////////////////////////////////////////////////////////////////////
2059 /// Set the state of guides (axes & reference markers) from arguments.
2060 
2061 void TGLViewer::SetGuideState(Int_t axesType, Bool_t axesDepthTest, Bool_t referenceOn, const Double_t referencePos[3])
2062 {
2063  fAxesType = axesType;
2064  fAxesDepthTest = axesDepthTest;
2065  fReferenceOn = referenceOn;
2066  if (referencePos)
2067  fReferencePos.Set(referencePos[0], referencePos[1], referencePos[2]);
2068  if (fGLDevice != -1)
2069  gGLManager->MarkForDirectCopy(fGLDevice, kTRUE);
2070  RequestDraw();
2071 }
2072 
2073 ////////////////////////////////////////////////////////////////////////////////
2074 /// Draw camera look at and rotation point.
2075 
2076 void TGLViewer::SetDrawCameraCenter(Bool_t x)
2077 {
2078  fDrawCameraCenter = x;
2079  RequestDraw();
2080 }
2081 
2082 // Selected physical
2083 ////////////////////////////////////////////////////////////////////////////////
2084 /// Return selected physical shape.
2085 
2086 const TGLPhysicalShape * TGLViewer::GetSelected() const
2087 {
2088  return fSelectedPShapeRef->GetPShape();
2089 }
2090 
2091 /**************************************************************************/
2092 /**************************************************************************/
2093 
2094 ////////////////////////////////////////////////////////////////////////////////
2095 /// Emit MouseOver signal.
2096 
2097 void TGLViewer::MouseOver(TGLPhysicalShape *shape)
2098 {
2099  Emit("MouseOver(TGLPhysicalShape*)", (Long_t)shape);
2100 }
2101 
2102 ////////////////////////////////////////////////////////////////////////////////
2103 /// Emit MouseOver signal.
2104 
2105 void TGLViewer::MouseOver(TGLPhysicalShape *shape, UInt_t state)
2106 {
2107  Long_t args[2];
2108  args[0] = (Long_t)shape;
2109  args[1] = state;
2110  Emit("MouseOver(TGLPhysicalShape*,UInt_t)", args);
2111 }
2112 
2113 ////////////////////////////////////////////////////////////////////////////////
2114 /// Emit MouseOver signal.
2115 
2116 void TGLViewer::MouseOver(TObject *obj, UInt_t state)
2117 {
2118  Long_t args[2];
2119  args[0] = (Long_t)obj;
2120  args[1] = state;
2121  Emit("MouseOver(TObject*,UInt_t)", args);
2122 }
2123 
2124 ////////////////////////////////////////////////////////////////////////////////
2125 /// Emit MouseOver signal.
2126 
2127 void TGLViewer::ReMouseOver(TObject *obj, UInt_t state)
2128 {
2129  Long_t args[2];
2130  args[0] = (Long_t)obj;
2131  args[1] = state;
2132  Emit("ReMouseOver(TObject*,UInt_t)", args);
2133 }
2134 
2135 
2136 ////////////////////////////////////////////////////////////////////////////////
2137 /// Emit UnMouseOver signal.
2138 
2139 void TGLViewer::UnMouseOver(TObject *obj, UInt_t state)
2140 {
2141  Long_t args[2];
2142  args[0] = (Long_t)obj;
2143  args[1] = state;
2144  Emit("UnMouseOver(TObject*,UInt_t)", args);
2145 }
2146 
2147 ////////////////////////////////////////////////////////////////////////////////
2148 /// Emit Clicked signal.
2149 
2150 void TGLViewer::Clicked(TObject *obj)
2151 {
2152  Emit("Clicked(TObject*)", (Long_t)obj);
2153 }
2154 
2155 ////////////////////////////////////////////////////////////////////////////////
2156 /// Emit Clicked signal with button id and modifier state.
2157 
2158 void TGLViewer::Clicked(TObject *obj, UInt_t button, UInt_t state)
2159 {
2160  Long_t args[3];
2161  args[0] = (Long_t)obj;
2162  args[1] = button;
2163  args[2] = state;
2164  Emit("Clicked(TObject*,UInt_t,UInt_t)", args);
2165 }
2166 
2167 
2168 ////////////////////////////////////////////////////////////////////////////////
2169 /// Emit ReClicked signal with button id and modifier state.
2170 
2171 void TGLViewer::ReClicked(TObject *obj, UInt_t button, UInt_t state)
2172 {
2173  Long_t args[3];
2174  args[0] = (Long_t)obj;
2175  args[1] = button;
2176  args[2] = state;
2177  Emit("ReClicked(TObject*,UInt_t,UInt_t)", args);
2178 }
2179 
2180 ////////////////////////////////////////////////////////////////////////////////
2181 /// Emit UnClicked signal with button id and modifier state.
2182 
2183 void TGLViewer::UnClicked(TObject *obj, UInt_t button, UInt_t state)
2184 {
2185  Long_t args[3];
2186  args[0] = (Long_t)obj;
2187  args[1] = button;
2188  args[2] = state;
2189  Emit("UnClicked(TObject*,UInt_t,UInt_t)", args);
2190 }
2191 
2192 ////////////////////////////////////////////////////////////////////////////////
2193 /// Emit MouseIdle signal.
2194 
2195 void TGLViewer::MouseIdle(TGLPhysicalShape *shape, UInt_t posx, UInt_t posy)
2196 {
2197  Long_t args[3];
2198  static UInt_t oldx = 0, oldy = 0;
2199 
2200  if (oldx != posx || oldy != posy) {
2201  args[0] = (Long_t)shape;
2202  args[1] = posx;
2203  args[2] = posy;
2204  Emit("MouseIdle(TGLPhysicalShape*,UInt_t,UInt_t)", args);
2205  oldx = posx;
2206  oldy = posy;
2207  }
2208 }
2209 
2210 /**************************************************************************/
2211 /**************************************************************************/
2212 ////////////////////////////////////////////////////////////////////////////////
2213 /// Calculate and return pixel distance to nearest viewer object from
2214 /// window location px, py
2215 /// This is provided for use when embedding GL viewer into pad
2216 
2217 Int_t TGLViewer::DistancetoPrimitive(Int_t /*px*/, Int_t /*py*/)
2218 {
2219  // Can't track the indvidual objects in rollover. Just set the viewer as the
2220  // selected object, and return 0 (object identified) so we receive ExecuteEvent calls
2221  gPad->SetSelected(this);
2222  return 0;
2223 }
2224 
2225 ////////////////////////////////////////////////////////////////////////////////
2226 /// Process event of type 'event' - one of EEventType types,
2227 /// occurring at window location px, py
2228 /// This is provided for use when embedding GL viewer into pad
2229 
2230 void TGLViewer::ExecuteEvent(Int_t event, Int_t px, Int_t py)
2231 {
2232  if (fEventHandler)
2233  return fEventHandler->ExecuteEvent(event, px, py);
2234 }
2235 
2236 ////////////////////////////////////////////////////////////////////////////////
2237 /// Pass viewer for print capture by TGLOutput.
2238 
2239 void TGLViewer::PrintObjects()
2240 {
2241  TGLOutput::Capture(*this);
2242 }
2243 
2244 ////////////////////////////////////////////////////////////////////////////////
2245 /// Update GUI components for embedded viewer selection change.
2246 
2247 void TGLViewer::SelectionChanged()
2248 {
2249  if (!fGedEditor)
2250  return;
2251 
2252  TGLPhysicalShape *selected = const_cast<TGLPhysicalShape*>(GetSelected());
2253 
2254  if (selected) {
2255  fPShapeWrap->fPShape = selected;
2256  fGedEditor->SetModel(fPad, fPShapeWrap, kButton1Down);
2257  } else {
2258  fPShapeWrap->fPShape = 0;
2259  fGedEditor->SetModel(fPad, this, kButton1Down);
2260  }
2261 }
2262 
2263 ////////////////////////////////////////////////////////////////////////////////
2264 /// An overlay operation can result in change to an object.
2265 /// Refresh geditor.
2266 
2267 void TGLViewer::OverlayDragFinished()
2268 {
2269  if (fGedEditor)
2270  {
2271  fGedEditor->SetModel(fPad, fGedEditor->GetModel(), kButton1Down);
2272  }
2273 }
2274 
2275 ////////////////////////////////////////////////////////////////////////////////
2276 /// Update GED editor if it is set.
2277 
2278 void TGLViewer::RefreshPadEditor(TObject* obj)
2279 {
2280  if (fGedEditor && (obj == 0 || fGedEditor->GetModel() == obj))
2281  {
2282  fGedEditor->SetModel(fPad, fGedEditor->GetModel(), kButton1Down);
2283  }
2284 }
2285 
2286 ////////////////////////////////////////////////////////////////////////////////
2287 /// Set the event-handler. The event-handler is owned by the viewer.
2288 /// If GLWidget is set, the handler is propagated to it.
2289 ///
2290 /// If called with handler=0, the current handler will be deleted
2291 /// (also from TGLWidget).
2292 
2293 void TGLViewer::SetEventHandler(TGEventHandler *handler)
2294 {
2295  if (fEventHandler)
2296  delete fEventHandler;
2297 
2298  fEventHandler = handler;
2299  if (fGLWidget)
2300  fGLWidget->SetEventHandler(fEventHandler);
2301 }
2302 
2303 ////////////////////////////////////////////////////////////////////////////////
2304 /// Remove overlay element.
2305 
2306 void TGLViewer::RemoveOverlayElement(TGLOverlayElement* el)
2307 {
2308  if (el == fCurrentOvlElm)
2309  {
2310  fCurrentOvlElm = 0;
2311  }
2312  TGLViewerBase::RemoveOverlayElement(el);
2313 }
2314 
2315 ////////////////////////////////////////////////////////////////////////////////
2316 /// Reset current overlay-element to zero, eventually notifying the
2317 /// old one that the mouse has left.
2318 /// Usually called when mouse leaves the window.
2319 
2320 void TGLViewer::ClearCurrentOvlElm()
2321 {
2322  if (fCurrentOvlElm)
2323  {
2324  fCurrentOvlElm->MouseLeave();
2325  fCurrentOvlElm = 0;
2326  RequestDraw();
2327  }
2328 }