// @(#)root/gl:$Name:  $:$Id: TGLOrthoCamera.cxx,v 1.13 2006/01/26 11:59:41 brun Exp $
// Author:  Richard Maunder  25/05/2005

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TGLOrthoCamera.h"
#include "TGLUtil.h"
#include "TGLIncludes.h"

#include "TMath.h"

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGLOrthoCamera                                                       //
//                                                                      //
// Orthographic projection camera. Currently limited to three types     //
// defined at construction time - kXOY, kXOZ, kZOY - where this refers  //
// to the viewport plane axis - e.g. kXOY has X axis horizontal, Y      //
// vertical - i.e. looking down Z axis with Y vertical.                 //
//
// The plane types restriction could easily be removed to supported     //
// arbitary ortho projections along any axis/orientation with free      //
// rotations about them.                                                //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

ClassImp(TGLOrthoCamera)

UInt_t   TGLOrthoCamera::fgZoomDeltaSens = 500;

//______________________________________________________________________________
TGLOrthoCamera::TGLOrthoCamera(EType type) :
   fType(type), fZoomMin(0.01), fZoomDefault(0.78), fZoomMax(1000.0),
   fVolume(TGLVertex3(-100.0, -100.0, -100.0), TGLVertex3(100.0, 100.0, 100.0)),
   fZoom(1.0), fTruck(0.0, 0.0, 0.0), fMatrix()
{
   // Construct orthographic camera with 'type' defining fixed view direction
   // & orientation (in world frame):
   //
   // kXOY : X Horz. / Y Vert (looking towards +Z, Y up)
   // kXOZ : X Horz. / Z Vert (looking towards +Y, Z up)
   // kZOY : Z Horz. / Y Vert (looking towards +X, Y up)
   //
   Setup(TGLBoundingBox(TGLVertex3(-100,-100,-100), TGLVertex3(100,100,100)));
}

//______________________________________________________________________________
TGLOrthoCamera::~TGLOrthoCamera()
{
   // Destroy orthographic camera
}

//______________________________________________________________________________
void TGLOrthoCamera::Setup(const TGLBoundingBox & box)
{
   // Setup camera limits suitible to view the world volume defined by 'box'
   // and call Reset() to initialise camera.
   static const Double_t rotMatrixXOY[] = { 1.,  0.,  0.,  0.,
                                            0.,  1.,  0.,  0.,
                                            0.,  0.,  1.,  0.,
                                            0.,  0.,  0.,  1. };

   static const Double_t rotMatrixXOZ[] = { 1.,  0.,  0.,  0.,
                                            0.,  0., -1.,  0.,
                                            0.,  1.,  0.,  0.,
                                            0.,  0.,  0.,  1. };

   static const Double_t rotMatrixZOY[] = { 0.,  0.,  -1.,  0.,
                                            0.,  1.,  0.,  0.,
                                            1.,  0.,  0.,  0.,
                                            0.,  0.,  0.,  1. };
	
   switch (fType) {
		// Looking down Z axis, X horz, Y vert
      case (kXOY): {
         // X -> X
         // Y -> Y
         // Z -> Z
         fVolume = box;
         fMatrix.Set(rotMatrixXOY);
         break;
      }
		// Looking down Y axis, X horz, Z vert
      case (kXOZ): {
         // X -> X
         // Z -> Y
         // Y -> Z
         fVolume.SetAligned(TGLVertex3(box.XMin(), box.ZMin(), box.YMin()),
                            TGLVertex3(box.XMax(), box.ZMax(), box.YMax()));
         fMatrix.Set(rotMatrixXOZ);
         break;
      }
		// Looking down X axis, Z horz, Y vert
      case (kZOY): {
         // Z -> X
         // Y -> Y
         // X -> Z
         fVolume.SetAligned(TGLVertex3(box.ZMin(), box.YMin(), box.XMin()),
                            TGLVertex3(box.ZMax(), box.YMax(), box.XMax()));
         fMatrix.Set(rotMatrixZOY);
         break;
      }
   }
   Reset();
}

//______________________________________________________________________________
void TGLOrthoCamera::Reset()
{
   // Reset the camera to defaults - trucking, zooming to reframe the world volume
   // established in Setup(). Note: limits defined in Setup() are not adjusted.
   fTruck.Set(0.0, 0.0, 0.0);
   fZoom   = fZoomDefault;
   fCacheDirty = kTRUE;
}

//______________________________________________________________________________
Bool_t TGLOrthoCamera::Dolly(Int_t delta, Bool_t mod1, Bool_t mod2)
{
   // Dolly the camera - 'move camera along eye line, retaining lens focal length'.
   // Arguments are:
   //
   // 'delta' - mouse viewport delta (pixels) - +ive dolly in, -ive dolly out
   // 'mod1' / 'mod2' - sensitivity modifiers - see TGLCamera::AdjustAndClampVal()
   //
   // For an orthographic camera dollying and zooming are identical and both equate
   // logically to a rescaling of the viewport limits - without center shift.
   // There is no perspective foreshortening or lens 'focal length'.
   //
   // Returns kTRUE is redraw required (camera change), kFALSE otherwise.

   // TODO: Bring all mouse handling into camera classes - would simplify interface and
   // remove these non-generic cases.
   return Zoom(delta, mod1, mod2);
}

//______________________________________________________________________________
Bool_t TGLOrthoCamera::Zoom (Int_t delta, Bool_t mod1, Bool_t mod2)
{
   // Zoom the camera - 'adjust lens focal length, retaining camera position'.
   // Arguments are:
   //
   // 'delta' - mouse viewport delta (pixels) - +ive zoom in, -ive zoom out
   // 'mod1' / 'mod2' - sensitivity modifiers - see TGLCamera::AdjustAndClampVal()
   //
   // For an orthographic camera dollying and zooming are identical and both equate
   // logically to a rescaling of the viewport limits - without center shift.
   // There is no perspective foreshortening or lens 'focal length'.
   //
   // Returns kTRUE is redraw required (camera change), kFALSE otherwise.

   // TODO: Bring all mouse handling into camera classes - would simplify interface and
   // remove these non-generic cases.
   if (AdjustAndClampVal(fZoom, fZoomMin, fZoomMax, -delta*2, fgZoomDeltaSens, mod1, mod2))
   {
      fCacheDirty = kTRUE;
      return kTRUE;
   }
   else
   {
      return kFALSE;
   }
}

//______________________________________________________________________________
Bool_t TGLOrthoCamera::Truck(Int_t x, Int_t y, Int_t xDelta, Int_t yDelta)
{
   // Truck the camera - 'move camera parallel to film plane'. The film
   // plane is defined by the EyePoint() / EyeDirection() pair. Define motion
   // using center point (x/y) and delta (xDelta/yDelta) - the mouse motion.
   //
   // Returns kTRUE is redraw required (camera change), kFALSE otherwise.
   //
   // Note: Trucking is often mistakenly refered to as 'pan' or 'panning'.
   // Panning is swivelling the camera on it's own axis - the eye point.

   //TODO: Convert TGLRect so this not required
   GLint viewport[4] = { fViewport.X(), fViewport.Y(), fViewport.Width(), fViewport.Height() };
   TGLVertex3 start, end;
   // Trucking done at near clipping plane
   gluUnProject(x, y, 0.0, fModVM.CArr(), fProjM.CArr(), viewport, &start.X(), &start.Y(), &start.Z());
   gluUnProject(x + xDelta, y + yDelta, 0.0, fModVM.CArr(), fProjM.CArr(), viewport, &end.X(), &end.Y(), &end.Z());
   fTruck = fTruck + (end - start);
   fCacheDirty = kTRUE;
   return kTRUE;
}

//______________________________________________________________________________
Bool_t TGLOrthoCamera::Rotate(Int_t /*xDelta*/, Int_t /*yDelta*/)
{
   // Rotate the camera - 'swivel round the view volume center'.
   // Ignored at present for orthographic cameras - have a fixed direction.
   // Could let the user or external code create non-axis
   // ortho projects by adjusting H/V rotations in future.
   //
   // Returns kTRUE is redraw required (camera change), kFALSE otherwise.

   return kFALSE;
}

//______________________________________________________________________________
void TGLOrthoCamera::Apply(const TGLBoundingBox & /*box*/, const TGLRect * pickRect) const
{
   // Apply the camera to the current GL context, setting the viewport, projection
   // and modelview matricies. After this verticies etc can be directly entered
   // in the world frame. This also updates the cached frustum values, enabling
   // all the projection, overlap tests etc defined in TGLCamera to be used.
   //
   // Arguments are:
   // 'box' - view volume box - ignored for ortho camera. Assumed to be same
   // as one passed to Setup().
   // 'pickRect' - optional picking rect. If non-null, restrict drawing to this
   // viewport rect.
   glViewport(fViewport.X(), fViewport.Y(), fViewport.Width(), fViewport.Height());

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   // Load up any picking rect
   if (pickRect) {
      //TODO: Convert TGLRect so this not required
      GLint viewport[4] = { fViewport.X(), fViewport.Y(), fViewport.Width(), fViewport.Height() };
      gluPickMatrix(pickRect->X(), pickRect->Y(),
                    pickRect->Width(), pickRect->Height(),
                    viewport);
   }

   if(fViewport.Width() == 0 || fViewport.Height() == 0) {
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      return;
   }

   TGLVector3 extents = fVolume.Extents();
   Double_t width = extents.X();
   Double_t height = extents.Y();
   Double_t halfRange;
   if (width > height) {
      halfRange = width / 2.0;
   } else {
      halfRange = height / 2.0;
   }
   halfRange /= fZoom;

   // For near/far clipping half depth give extra slack so clip objects/manips
   // are visible
   Double_t halfDepth = extents.Mag();
   const TGLVertex3 & center = fVolume.Center();

   glOrtho(center.X() - halfRange,
           center.X() + halfRange,
           center.Y() - halfRange,
           center.Y() + halfRange,
           center.Z() - halfDepth,
           center.Z() + halfDepth);


   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   glScaled(1.0 / fViewport.Aspect(), 1.0, 1.0); 	

   // Debug aid - show current volume
   /*glDisable(GL_LIGHTING);
   glColor3d(0.0, 0.0, 1.0);
   fVolume.Draw();
   glEnable(GL_LIGHTING);*/

   glMultMatrixd(fMatrix.CArr());
   glTranslated(fTruck.X(), fTruck.Y(), fTruck.Z());

   if (fCacheDirty) {
      UpdateCache();
   }
}

//______________________________________________________________________________
void TGLOrthoCamera::Configure(Double_t left, Double_t right,
                               Double_t top, Double_t bottom)
{
   // Configure the camera state
   Double_t width = right - left;
   Double_t height = top - bottom;

   Double_t xZoom = width/fVolume.Extents().X();
   Double_t yZoom = height/fVolume.Extents().Y();

   fZoom = (xZoom > yZoom) ? xZoom : yZoom;

   // kXOY : X Horz. / Y Vert (looking towards +Z, Y up)
   // kXOZ : X Horz. / Z Vert (looking towards +Y, Z up)
   // kZOY : Z Horz. / Y Vert (looking towards +X, Y up)
   if (fType == kXOY) {
      fTruck.X() = right - left;
      fTruck.Y() = top - bottom;
   } else if (fType == kXOZ) {
      fTruck.X() = right - left;
      fTruck.Z() = top - bottom;
   } else if (fType == kZOY) {
      fTruck.Z() = right - left;
      fTruck.Y() = top - bottom;
   }
   fCacheDirty = kTRUE;
}


ROOT page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.