// @(#)root/gl:$Name:  $:$Id: TGLManip.cxx
// Author:  Richard Maunder  16/09/2005

/*************************************************************************
 * Copyright (C) 1995-2005, 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 "TGLManip.h"
#include "TGLUtil.h"
#include "TGLCamera.h"
#include "TGLViewer.h"
#include "TGLPhysicalShape.h"
#include "TGLIncludes.h"

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGLManip                                                             //
//                                                                      //
// Abstract base class for viewer manipulators, which allow direct in   //
// viewer manipulation of a (TGlPhysicalShape) object - currently       //
// translation, scaling and rotation along/round objects local axes.    //
// See derived classes for these implementations.                       //
//                                                                      //
// This class provides binding to the zero or one manipulated physical, //
// hit testing (selection) for manipulator sub component (widget), and  //
// some common mouse action handling/tracking.                          //
//////////////////////////////////////////////////////////////////////////

ClassImp(TGLManip)

Float_t TGLManip::fgRed[4]    = {0.8, 0.0, 0.0, 1.0 };
Float_t TGLManip::fgGreen[4]  = {0.0, 0.8, 0.0, 1.0 };
Float_t TGLManip::fgBlue[4]   = {0.0, 0.0, 0.8, 1.0 };
Float_t TGLManip::fgYellow[4] = {0.8, 0.8, 0.0, 1.0 };
Float_t TGLManip::fgWhite[4]  = {1.0, 1.0, 1.0, 1.0 };
Float_t TGLManip::fgGrey[4]   = {0.5, 0.5, 0.5, 0.4 };

//______________________________________________________________________________
TGLManip::TGLManip(TGLViewer & viewer) : 
   fViewer(viewer), fShape(0), 
   fSelectedWidget(0), fActive(kFALSE),
   fFirstMouse(0, 0), 
   fLastMouse(0, 0)
{
   // Construct a manipulator object, bound to supplied viewer, and no physical shape
   
   // TODO: The requirement to attach to viewer is needed for cross thread selection
   // callback under Windows - when the design of TGLKernel / TGLManager is finally
   // resolved this can probably be removed.
}

//______________________________________________________________________________
TGLManip::TGLManip(TGLViewer & viewer, TGLPhysicalShape * shape) : 
   fViewer(viewer), fShape(shape), 
   fSelectedWidget(0), fActive(kFALSE),
   fFirstMouse(0, 0), 
   fLastMouse(0, 0)
{
   // Construct a manipulator object, bound to supplied viewer, and physical shape
   
   // TODO: The requirement to attach to viewer is needed for cross thread selection
   // callback under Windows - when the design of TGLKernel / TGLManager is finally
   // resolved this can probably be removed.
}

//______________________________________________________________________________
 TGLManip::~TGLManip() 
{
   // Destroy manipulator object
}

//______________________________________________________________________________
 void TGLManip::Select(const TGLCamera & camera) 
{
   // Perform selection (hit testing) to find selected widget (component)
   // of the manipulator - stored in fSelectedWidget
   static UInt_t selectBuffer[4*4];
   glSelectBuffer(4*4, &selectBuffer[0]);
   glRenderMode(GL_SELECT);
   glInitNames();
   Draw(camera);
   Int_t hits = glRenderMode(GL_RENDER);
   TGLUtil::CheckError();
   if (hits < 0) {
      Error("TGLManip::Select", "selection buffer overflow");
      return;
   }

   if (hits > 0) {
      fSelectedWidget = 0;
      UInt_t minDepth = kMaxUInt;
      for (Int_t i = 0; i < hits; i++) {
         // Skip selection on unnamed hits
         if (selectBuffer[i * 4] == 0) {
            continue;
         }
         if (selectBuffer[i * 4 + 1] < minDepth) {
            fSelectedWidget = selectBuffer[i * 4 + 3];
            minDepth = selectBuffer[i * 4 + 1];
         }
      }
   } else {
      fSelectedWidget = 0;
   }
}

//______________________________________________________________________________
 Bool_t TGLManip::HandleButton(const Event_t * event, const TGLCamera & /*camera*/)
{
   // Handle a mouse button event - return kTRUE if processed, kFALSE otherwise
   
   // Only interested in Left mouse button actions
   if (event->fCode != kButton1) {
      return kFALSE;
   }

   // Mouse down on selected widget?
   if (event->fType == kButtonPress && fSelectedWidget != 0) {
      fFirstMouse.SetX(event->fX);
      fFirstMouse.SetY(event->fY);
      fLastMouse.SetX(event->fX);
      fLastMouse.SetY(event->fY);
      fActive = kTRUE;
      return kTRUE;
   } else if (event->fType == kButtonRelease && fActive) {
      fActive = kFALSE;
      return kTRUE;
   } else {
      return kFALSE;
   }
}

//______________________________________________________________________________
 Bool_t TGLManip::HandleMotion(const Event_t * event, const TGLCamera & /*camera*/)
{
   // Handle a mouse button event - return kTRUE if widget selection change
   // kFALSE otherwise
   
   TGLRect selectRect(event->fX, event->fY, 3, 3);
   // Need to do this cross thread under Windows for gVirtualGL context - very ugly...
   // TODO: When the design of TGLKernel / TGLManager is finally resolved this can probably 
   // be removed.
   UInt_t oldSelection = fSelectedWidget;
   fViewer.RequestSelectManip(selectRect);
   return (fSelectedWidget != oldSelection);
}

//______________________________________________________________________________
 Double_t TGLManip::CalcDrawScale(const TGLBoundingBox & box, const TGLCamera & camera) const
{
   // Calculates a scale factor (in world units) for drawing manipulators with 
   // reasonable size range in current camera.
   TGLVector3 pixelInWorld = camera.ViewportDeltaToWorld(box.Center(), 1, 1);
   Double_t pixelScale = pixelInWorld.Mag();
   Double_t scale = box.Extents().Mag() / 100.0;
   
   // Allow some variation so zooming is noticable
   if (scale < pixelScale * 3.0) {
      scale = pixelScale * 3.0;
   } else if (scale > pixelScale * 5.0) {
      scale = pixelScale * 5.0;
   }
   return scale;
}


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.