From cf4a3500ec51c451ed0e275f70d9101875546509 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 9 May 2002 10:31:03 +0000 Subject: [PATCH] Added new osgGA - GUI Adapter library submitted by Neil Salter. This will replace the current GUI adapter code inside osgUtil. --- Make/makedirdefs | 1 + VisualStudio/VisualStudio.dsw | 63 +++ VisualStudio/osgGA/osgGA.dsp | 201 ++++++++ include/osgGA/CameraManipulator | 70 +++ include/osgGA/DriveManipulator | 75 +++ include/osgGA/Export | 53 +++ include/osgGA/FlightManipulator | 76 +++ include/osgGA/GUIActionAdapter | 55 +++ include/osgGA/GUIEventAdapter | 89 ++++ include/osgGA/GUIEventHandler | 123 +++++ include/osgGA/GUIEventHandlerVisitor | 55 +++ include/osgGA/KeySwitchCameraManipulator | 70 +++ include/osgGA/SetSceneViewVisitor | 40 ++ include/osgGA/StateSetManipulator | 51 ++ include/osgGA/TrackballManipulator | 77 +++ include/osgGA/Version | 39 ++ src/osgGA/CameraManipulator.cpp | 37 ++ src/osgGA/DriveManipulator.cpp | 565 +++++++++++++++++++++++ src/osgGA/FlightManipulator.cpp | 245 ++++++++++ src/osgGA/GUIEventHandler.cpp | 43 ++ src/osgGA/GUIEventHandlerVisitor.cpp | 9 + src/osgGA/KeySwitchCameraManipulator.cpp | 45 ++ src/osgGA/Makefile | 24 + src/osgGA/SetSceneViewVisitor.cpp | 16 + src/osgGA/StateSetManipulator.cpp | 73 +++ src/osgGA/TrackballManipulator.cpp | 397 ++++++++++++++++ src/osgGA/Version.cpp | 12 + src/osgUtil/SceneView.cpp | 13 + 28 files changed, 2617 insertions(+) create mode 100755 VisualStudio/osgGA/osgGA.dsp create mode 100644 include/osgGA/CameraManipulator create mode 100644 include/osgGA/DriveManipulator create mode 100644 include/osgGA/Export create mode 100644 include/osgGA/FlightManipulator create mode 100644 include/osgGA/GUIActionAdapter create mode 100644 include/osgGA/GUIEventAdapter create mode 100644 include/osgGA/GUIEventHandler create mode 100644 include/osgGA/GUIEventHandlerVisitor create mode 100644 include/osgGA/KeySwitchCameraManipulator create mode 100644 include/osgGA/SetSceneViewVisitor create mode 100644 include/osgGA/StateSetManipulator create mode 100644 include/osgGA/TrackballManipulator create mode 100644 include/osgGA/Version create mode 100644 src/osgGA/CameraManipulator.cpp create mode 100644 src/osgGA/DriveManipulator.cpp create mode 100644 src/osgGA/FlightManipulator.cpp create mode 100644 src/osgGA/GUIEventHandler.cpp create mode 100644 src/osgGA/GUIEventHandlerVisitor.cpp create mode 100644 src/osgGA/KeySwitchCameraManipulator.cpp create mode 100644 src/osgGA/Makefile create mode 100644 src/osgGA/SetSceneViewVisitor.cpp create mode 100644 src/osgGA/StateSetManipulator.cpp create mode 100644 src/osgGA/TrackballManipulator.cpp create mode 100644 src/osgGA/Version.cpp diff --git a/Make/makedirdefs b/Make/makedirdefs index 365909fc4..1ff586505 100644 --- a/Make/makedirdefs +++ b/Make/makedirdefs @@ -10,6 +10,7 @@ SRC_DIRS = \ osg\ osgUtil\ osgDB\ + osgGA\ osgGLUT\ osgPlugins\ osgText\ diff --git a/VisualStudio/VisualStudio.dsw b/VisualStudio/VisualStudio.dsw index 96f6a9761..480541a6b 100644 --- a/VisualStudio/VisualStudio.dsw +++ b/VisualStudio/VisualStudio.dsw @@ -30,6 +30,24 @@ Package=<4> ############################################################################### +Project: "Core osgGA"=".\osgGA\osgGA.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name Core osg + End Project Dependency + Begin Project Dependency + Project_Dep_Name Core osgUtil + End Project Dependency +}}} + +############################################################################### + Project: "Core osgGLUT"=".\osgGLUT\osgGLUT.dsp" - Package Owner=<4> Package=<5> @@ -45,6 +63,9 @@ Package=<4> Project_Dep_Name Core osgUtil End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgDB End Project Dependency }}} @@ -99,6 +120,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -123,6 +147,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -168,6 +195,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -192,6 +222,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -216,6 +249,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -240,6 +276,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -267,6 +306,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -291,6 +333,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -315,6 +360,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -339,6 +387,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -363,6 +414,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -390,6 +444,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -429,6 +486,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency @@ -453,6 +513,9 @@ Package=<4> Project_Dep_Name Core osgDB End Project Dependency Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency Project_Dep_Name Core osgGLUT End Project Dependency Begin Project Dependency diff --git a/VisualStudio/osgGA/osgGA.dsp b/VisualStudio/osgGA/osgGA.dsp new file mode 100755 index 000000000..ecb790e6c --- /dev/null +++ b/VisualStudio/osgGA/osgGA.dsp @@ -0,0 +1,201 @@ +# Microsoft Developer Studio Project File - Name="Core osgGA" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Core osgGA - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "osgGA.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "osgGA.mak" CFG="Core osgGA - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Core osgGA - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Core osgGA - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Core osgGA - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "../../lib" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../../lib" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "../../include" /D "NDEBUG" /D "_MBCS" /D "_USRDLL" /D "OSGUTIL_LIBRARY" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib /nologo /dll /pdb:none /machine:I386 /out:"../../bin/osgGA.dll" /libpath:"../../lib" + +!ELSEIF "$(CFG)" == "Core osgGA - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../../lib" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /vmg /vd0 /GR /GX /Zi /Od /I "../../include" /D "OSGUTIL_LIBRARY" /D "_WINDOWS" /D "WIN32" /D "_DEBUG" /D "OSG_USE_MEMORY_MANAGER" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/osgGAd.dll" /pdbtype:sept /libpath:"../../lib" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "Core osgGA - Win32 Release" +# Name "Core osgGA - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\src\osgGA\ +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\CameraManipulator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\DriveManipulator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\FlightManipulator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\GUIEventHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\GUIEventHandlerVisitor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\KeySwitchCameraManipulator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\SetSceneViewVisitor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\StateSetManipulator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\TrackballManipulator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\osgGA\Version.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter ";h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\Include\osgGA\CameraManipulator +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\DriveManipulator +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\FlightManipulator +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\GUIActionAdapter +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\GUIEventAdapter +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\GUIEventHandler +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\GUIEventHandlerVisitor +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\KeySwitchCameraManipulator +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\SetSceneViewVisitor +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\StateSetManipulator +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\TrackballManipulator +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\Export +# End Source File +# Begin Source File + +SOURCE=..\..\Include\osgGA\Version +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project +\c diff --git a/include/osgGA/CameraManipulator b/include/osgGA/CameraManipulator new file mode 100644 index 000000000..4d42f7c4d --- /dev/null +++ b/include/osgGA/CameraManipulator @@ -0,0 +1,70 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_CAMERAMANIPULATOR +#define OSGGA_CAMERAMANIPULATOR 1 + +#include +#include + +#include +#include +#include +#include + +namespace osgGA{ + +class OSGGA_EXPORT CameraManipulator : public GUIEventHandler +{ + public: + + CameraManipulator(); + virtual ~CameraManipulator(); + + /** attach a camera to the manipulator to be used for specifying view.*/ + virtual void setCamera(osg::Camera*); + + /** get the attached camera.*/ + virtual const osg::Camera * getCamera() const; + + /** get the attached camera.*/ + virtual osg::Camera * getCamera(); + + /** Attach a node to the manipulator. + Automatically detaches previously attached node. + setNode(NULL) detaches previously nodes. + Is ignored by manipulators which do not require a reference model.*/ + virtual void setNode(osg::Node*) {} + + /** Return node if attached.*/ + virtual const osg::Node* getNode() const { return NULL; } + + /** Return node if attached.*/ + virtual osg::Node* getNode() { return NULL; } + + /** Move the camera to the default position. + May be ignored by manipulators if home functionality is not appropriate.*/ + virtual void home(const GUIEventAdapter& ,GUIActionAdapter&) {} + + /** Start/restart the manipulator.*/ + virtual void init(const GUIEventAdapter& ,GUIActionAdapter&) {} + + /** Handle events, return true if handled, false otherwise.*/ + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us); + + /** Handle visitations */ + virtual void accept(GUIEventHandlerVisitor& v) { v.visit(*this); } + + + protected: + + // Reference pointer to a camera + osg::ref_ptr _camera; + +}; + +} + +#endif + diff --git a/include/osgGA/DriveManipulator b/include/osgGA/DriveManipulator new file mode 100644 index 000000000..6214b3c21 --- /dev/null +++ b/include/osgGA/DriveManipulator @@ -0,0 +1,75 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_DRIVEMANIPULATOR +#define OSGGA_DRIVEMANIPULATOR 1 + +#include + +namespace osgGA{ + +class OSGGA_EXPORT DriveManipulator : public CameraManipulator +{ + public: + + DriveManipulator(); + virtual ~DriveManipulator(); + + /** Attach a node to the manipulator. + Automatically detaches previously attached node. + setNode(NULL) detaches previously nodes. + Is ignored by manipulators which do not require a reference model.*/ + virtual void setNode(osg::Node*); + + /** Return node if attached.*/ + virtual const osg::Node* getNode() const; + + /** Return node if attached.*/ + virtual osg::Node* getNode(); + + /** Move the camera to the default position. + May be ignored by manipulators if home functionality is not appropriate.*/ + virtual void home(const GUIEventAdapter& ea,GUIActionAdapter& us); + + /** Start/restart the manipulator.*/ + virtual void init(const GUIEventAdapter& ea,GUIActionAdapter& us); + + /** handle events, return true if handled, false otherwise.*/ + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us); + + private: + + /** Reset the internal GUIEvent stack.*/ + void flushMouseEventStack(); + /** Add the current mouse GUIEvent to internal stack.*/ + void addMouseEvent(const GUIEventAdapter& ea); + + /** For the give mouse movement calculate the movement of the camera. + Return true is camera has moved and a redraw is required.*/ + bool calcMovement(); + + // Internal event stack comprising last three mouse events. + osg::ref_ptr _ga_t1; + osg::ref_ptr _ga_t0; + + osg::ref_ptr _node; + + float _modelScale; + float _velocity; + float _height; + float _buffer; + + enum SpeedControlMode { + USE_MOUSE_Y_FOR_SPEED, + USE_MOUSE_BUTTONS_FOR_SPEED + }; + + SpeedControlMode _speedMode; + +}; + +} + +#endif + diff --git a/include/osgGA/Export b/include/osgGA/Export new file mode 100644 index 000000000..ece41e1d9 --- /dev/null +++ b/include/osgGA/Export @@ -0,0 +1,53 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +// The following symbol has a underscore suffix for compatibility. +#ifndef OSGGA_EXPORT_ +#define OSGGA_EXPORT_ 1 + +#if defined(WIN32) && !(defined(__CYGWIN__) || defined(__MINGW32__)) + #pragma warning( disable : 4244 ) + #pragma warning( disable : 4251 ) + #pragma warning( disable : 4275 ) + #pragma warning( disable : 4786 ) +#endif + +#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined( __BCPLUSPLUS__) || defined( __MWERKS__) + # ifdef OSGGA_LIBRARY + # define OSGGA_EXPORT __declspec(dllexport) + # else + # define OSGGA_EXPORT __declspec(dllimport) + #endif /* OSGUTIL_LIBRARY */ +#else + #define OSGGA_EXPORT +#endif + +#endif + + +/** + +\namespace osgGA + +The 'GA' in osgGA stands for 'GUI Abstraction'. + +As the OpenSceneGraph is a cross-platform, window system-agnostic class library, +it has no direct ties to any given windowing environment. Viewers, however, must at +some level interact with a window system - where Window system may refer to a windowing +API, e.g. GLUT, Qt, FLTK, MFC, ... + +There is much commonality in the implementation of Viewers for varying windowing +environments. E.g. most Viewers will update a Camera position in response to a mouse +event, and may request that a timer be started as a result of a model being 'spun'. + +The purpose of the osgGA namespace is to centralise the common areas of this +functionality. With this centralised, the viewer writer needs only write a +GUIEventAdapter, a GUIActionAdapter, and assemble a collection of GUIEventHandlers +as appropriate for the viewer. + +Events from the windowing environment are adpated, and then fed into the GUIEventHandlers. +The GUIEventHandlers analyse and take action, and make requests of the windowing +environemnt via the GUIActionAdapter. The viewer writer should honour these requests. + +*/ diff --git a/include/osgGA/FlightManipulator b/include/osgGA/FlightManipulator new file mode 100644 index 000000000..42a502b6c --- /dev/null +++ b/include/osgGA/FlightManipulator @@ -0,0 +1,76 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_FLIGHTMANIPULATOR +#define OSGGA_FLIGHTMANIPULATOR 1 + +#include + +namespace osgGA{ + +class OSGGA_EXPORT FlightManipulator : public CameraManipulator +{ + public: + + FlightManipulator(); + virtual ~FlightManipulator(); + + /** Attach a node to the manipulator. + Automatically detaches previously attached node. + setNode(NULL) detaches previously nodes. + Is ignored by manipulators which do not require a reference model.*/ + virtual void setNode(osg::Node*); + + /** Return node if attached.*/ + virtual const osg::Node* getNode() const; + + /** Return node if attached.*/ + virtual osg::Node* getNode(); + + /** Move the camera to the default position. + May be ignored by manipulators if home functionality is not appropriate.*/ + virtual void home(const GUIEventAdapter& ea,GUIActionAdapter& us); + + /** Start/restart the manipulator.*/ + virtual void init(const GUIEventAdapter& ea,GUIActionAdapter& us); + + /** handle events, return true if handled, false otherwise.*/ + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us); + + enum YawControlMode { + YAW_AUTOMATICALLY_WHEN_BANKED, + NO_AUTOMATIC_YAW + }; + + /** Set the yaw control between no yaw and yawing when banked.*/ + void setYawControlMode(YawControlMode ycm) { _yawMode = ycm; } + + private: + + /** Reset the internal GUIEvent stack.*/ + void flushMouseEventStack(); + /** Add the current mouse GUIEvent to internal stack.*/ + void addMouseEvent(const GUIEventAdapter& ea); + + /** For the give mouse movement calculate the movement of the camera. + Return true is camera has moved and a redraw is required.*/ + bool calcMovement(); + + // Internal event stack comprising last three mouse events. + osg::ref_ptr _ga_t1; + osg::ref_ptr _ga_t0; + + osg::ref_ptr _node; + + float _modelScale; + float _velocity; + + YawControlMode _yawMode; + +}; + +} + +#endif + diff --git a/include/osgGA/GUIActionAdapter b/include/osgGA/GUIActionAdapter new file mode 100644 index 000000000..293ff253d --- /dev/null +++ b/include/osgGA/GUIActionAdapter @@ -0,0 +1,55 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_GUIACTIONADAPTER +#define OSGGA_GUIACTIONADAPTER 1 + +#include + +namespace osgGA{ + + +/** Pure virtual base class for adapting the GUI actions requested by CameraManipulators + * into actions which are handled by the GUI toolkit of the users application. + * + * There are several was of using the ActionAdapter either inheriting it as + * done with osgGLUT::Viewer class or passing a simple struct to the camera + * manipulator then unpacking the results and working out what to do to respond + * to the requests. + * + * Also there are several ways to run your app and handle the updating of + * the window. osgGLUT::Viewer always has a idle callback registered which does a + * redraw all the time. osgGLUT::Viewer can safely ignore both requestRedraw() and + * requestContinousUpdate() as these are happening all the time anyway. + * + * Other apps will probably want to respond to the requestRedraw() and + * requestContinousUpdate(bool) and again there is more than one way to handle it. + * You can override requestRedraw() and implement to call your own window + * redraw straight away. Or you can implement so that a flag is set and + * then you then respond the flag being set in your own leisure. + * + * requestContinousUpdate(bool) is for enabling a throw or idle + * callback to be requested by the camera manipulator. Again you can respond + * to this immediately by registering a idle callback or a timed callback, or + * you can delay setting the callback and do at you own leisure. + * + * requestWarpPointer(int,int) is requesting a respositioning of a mouse pointer + * to a specified x,y location on the window. Used by some camera manipulators + * to initialize the mouse pointer when mouse position relative to a controls + * neutral mouse position is required, i.e when mimicking a aircrafts joystick. + */ +class GUIActionAdapter +{ + public: + + virtual void requestRedraw() = 0; + virtual void requestContinuousUpdate(bool needed=true) = 0; + virtual void requestWarpPointer(int x,int y) = 0; + +}; + +} + +#endif + diff --git a/include/osgGA/GUIEventAdapter b/include/osgGA/GUIEventAdapter new file mode 100644 index 000000000..1c948fbb1 --- /dev/null +++ b/include/osgGA/GUIEventAdapter @@ -0,0 +1,89 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_GUIEVENTADAPTER +#define OSGGA_GUIEVENTADAPTER 1 + +#include +#include + +namespace osgGA{ + + +/** Pure virtual base class for adapting platform specific events into + * generic keyboard and mouse events. + * + * Used as GUI toolkit independent input into the osgUtil::CameraManipualor's. + * For an example of how GUIEventAdapter is specialised for a particular GUI + * Toolkit see osgGLUT::GLUTEventAdapter. + */ +class GUIEventAdapter : public osg::Referenced +{ + public: + + GUIEventAdapter() {} + + + enum MouseButtonMask { + LEFT_MOUSE_BUTTON=1, + MIDDLE_MOUSE_BUTTON=2, + RIGHT_MOUSE_BUTTON=4 + }; + + enum EventType { + PUSH, + RELEASE, + DRAG, + MOVE, + KEYBOARD, + FRAME, + RESIZE, + NONE + }; + + /** Get the EventType of the GUI event.*/ + virtual EventType getEventType() const = 0; + + /** key pressed, return -1 if inappropriate for this event. */ + virtual int getKey() const = 0; + + /** button pressed/released, return -1 if inappropriate for this event.*/ + virtual int getButton() const = 0; + + /** window minimum x. */ + virtual int getXmin() const = 0; + + /** window maximum x. */ + virtual int getXmax() const = 0; + + /** window minimum y. */ + virtual int getYmin() const = 0; + + /** window maximum y. */ + virtual int getYmax() const = 0; + + /** current mouse x position.*/ + virtual int getX() const = 0; + + /** current mouse y position.*/ + virtual int getY() const = 0; + + /** current mouse button state */ + virtual unsigned int getButtonMask() const = 0; + + /** time in seconds of event. */ + virtual float time() const = 0; + + + protected: + + /** Force users to create on heap, so that multiple referencing is safe.*/ + virtual ~GUIEventAdapter() {} + +}; + +} + +#endif + diff --git a/include/osgGA/GUIEventHandler b/include/osgGA/GUIEventHandler new file mode 100644 index 000000000..629769e15 --- /dev/null +++ b/include/osgGA/GUIEventHandler @@ -0,0 +1,123 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_GUIEVENTHANDLER +#define OSGGA_GUIEVENTHANDLER 1 + +#include + +#include + +#include +#include +#include +#include + +namespace osgGA{ + +class CompositeGUIEventHandler; + +/** + +GUIEventHandler provides a basic interface for any class which wants to handle +a GUI Events. + +The GUIEvent is supplied by a GUIEventAdapter. Feedback resulting from the +handle method is supplied by a GUIActionAdapter, which allows the GUIEventHandler +to ask the GUI to take some action in response to an incoming event. + +For example, consider a Trackball Viewer class which takes mouse events and +manipulates a scene camera in response. The Trackball Viewer is a GUIEventHandler, +and receives the events via the handle method. If the user 'throws' the model, +the Trackball Viewer class can detect this via the incoming events, and +request that the GUI set up a timer callback to continually redraw the view. +This request is made via the GUIActionAdapter class. + +*/ + +class OSGGA_EXPORT GUIEventHandler : public osg::Referenced +{ + public: + + /** Handle events, return true if handled, false otherwise.*/ + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us)=0; + + /** Is this const GUIEventHandler a composite? */ + virtual const CompositeGUIEventHandler* getComposite() const { return 0; } + + /** Is this non-const GUIEventHandler a composite? */ + virtual CompositeGUIEventHandler* getComposite() { return 0; } + + /** Accept visits from GUIEventHandler visitors */ + virtual void accept(GUIEventHandlerVisitor&) = 0; + //virtual void accept(GUIEventHandlerVisitor&) { } + +}; + + +/** +CompositeGUIEventHandler allows GUIEventHandlers to be composed into hierarchies. +*/ + +class OSGGA_EXPORT CompositeGUIEventHandler : public GUIEventHandler +{ + public: + + typedef std::vector< osg::ref_ptr > ChildList; + + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& aa); + + virtual const CompositeGUIEventHandler* getComposite() const { return this; } + + virtual CompositeGUIEventHandler* getComposite() { return this; } + + virtual void accept(GUIEventHandlerVisitor& v) { v.visit(*this); } + + + + /* Composite-specific methods below */ + + virtual bool addChild(GUIEventHandler *geh); + + virtual bool removeChild(GUIEventHandler *geh); + + const int getNumChildren() const { return _children.size(); } + + GUIEventHandler *getChild( int i) { return _children[i].get(); } + + const GUIEventHandler *getChild( int i ) const { return _children[i].get(); } + + bool containsNode( const GUIEventHandler* node ) const + { + + for (ChildList::const_iterator itr=_children.begin(); + itr!=_children.end(); + ++itr) + { + if (itr->get()==node) return true; + } + return false; + } + + ChildList::iterator findChild( const GUIEventHandler* node ) + { + for (ChildList::iterator itr=_children.begin(); + itr!=_children.end(); + ++itr) + { + if (itr->get()==node) return itr; + } + return _children.end(); + } + + private: + + ChildList _children; + +}; + + +} + +#endif diff --git a/include/osgGA/GUIEventHandlerVisitor b/include/osgGA/GUIEventHandlerVisitor new file mode 100644 index 000000000..3e4fd5903 --- /dev/null +++ b/include/osgGA/GUIEventHandlerVisitor @@ -0,0 +1,55 @@ +#ifndef OSGGA_GUIEVENTHANDLERVISITOR +#define OSGGA_GUIEVENTHANDLERVISITOR 1 + +#include +#include +#include + +namespace osgGA{ + +// Some forward declarations +class GUIActionAdapter; +class CompositeGUIEventHandler; +class CameraManipulator; +class StateSetManipulator; + +/** Base class primarily for visiting GUIEventHandlers. + +A Default Visitor, (Might want to make it an Extrinsic Visitor at some point). +By default, it does nothing to the things it visits. Sub classes of this Visitor +need only override visit operations for the types of object they're interested in. + +*/ + + +class OSGGA_EXPORT GUIEventHandlerVisitor +{ + public: + + virtual void visit(CompositeGUIEventHandler&); + virtual void visit(CameraManipulator&) {}; + virtual void visit(StateSetManipulator&) {}; + + // Accessors + + /** Get the GUI EventAdapter associated with this GUIEventHandlerVisitor */ + const GUIEventAdapter *getGUIEventAdapter() { return _gea.get(); } + + /** Get the GUI Action Adapter associated with this GEH Visitor */ + GUIActionAdapter *getGUIActionAdapter() { return _gaa; } + + protected: + + GUIEventHandlerVisitor(GUIEventAdapter* in, GUIActionAdapter* out):_gea(in),_gaa(out) {} + virtual ~GUIEventHandlerVisitor() {} + + private: + + osg::ref_ptr _gea; + GUIActionAdapter* _gaa; // Just a pointer. NOT owned by this object. + +}; + +}; + +#endif diff --git a/include/osgGA/KeySwitchCameraManipulator b/include/osgGA/KeySwitchCameraManipulator new file mode 100644 index 000000000..1bfacefce --- /dev/null +++ b/include/osgGA/KeySwitchCameraManipulator @@ -0,0 +1,70 @@ +#ifndef OSGUTIL_KEYSWITCCAMERAMANIPULATORHER +#define OSGUTIL_KEYSWITCHCAMERAMANIPULATORER 1 + +#include +#include +#include +#include +//#include + +namespace osgGA{ + +class GUIEventAdapter; +class GUIActionAdapter; + +class OSGGA_EXPORT KeySwitchCameraManipulator : public CameraManipulator +{ + public: + + // Local methods + + void addCameraManipulator(int key, std::string name, CameraManipulator *cm); + + //typedef void (* Callback)(KeySwitchCameraManipulator *); + +// class Callback: public osgUtil::CallbackList::Callback { +// public: +// virtual ~Callback() {}; +// virtual void operator()(KeySwitchCameraManipulator *) = 0; +// }; +// +// void addCallback(Callback*); +// +// void removeCallback(Callback*); + + // Overrides from CameraManipulator... + + virtual void setCamera(osg::Camera* c) { _current->setCamera(c); } + + virtual const osg::Camera * getCamera() const { return _current->getCamera(); } + + virtual osg::Camera * getCamera() { return _current->getCamera(); } + + virtual void setNode(osg::Node* n) { _current->setNode(n); } + + virtual const osg::Node* getNode() const { return _current->getNode(); } + + virtual osg::Node* getNode() { return _current->getNode(); } + + virtual void home(const GUIEventAdapter& ee,GUIActionAdapter& aa) { _current->home(ee,aa); } + + virtual void init(const GUIEventAdapter& ee,GUIActionAdapter& aa) { _current->init(ee,aa); } + + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us); + + private: + + typedef std::pair > NamedManipulator; + typedef std::map KeyManipMap; + KeyManipMap _manips; + + osg::ref_ptr _current; + + // Callbacks + //CallbackList _cameraManipChangeCallbacks; + +}; + +}; + +#endif diff --git a/include/osgGA/SetSceneViewVisitor b/include/osgGA/SetSceneViewVisitor new file mode 100644 index 000000000..56f8e341d --- /dev/null +++ b/include/osgGA/SetSceneViewVisitor @@ -0,0 +1,40 @@ +#ifndef OSGGA_SETSCENEVIEWGEHVISITOR +#define OSGGA_SETSCENEVIEWGEHVISITOR 1 + +#include +#include + +namespace osgGA{ + +// Some forward declarations +class GUIEventHandler; +class CameraManipulator; + +/** SetSceneViewGUIEventHandlerVisitor which visits various types of GUIEventHandler and +sets them up appropriately, given a new scene view. +. */ + +class OSGGA_EXPORT SetSceneViewVisitor: public GUIEventHandlerVisitor +{ + public: + + SetSceneViewVisitor(GUIEventAdapter* in, + GUIActionAdapter* out, + osgUtil::SceneView* sv): + GUIEventHandlerVisitor(in,out), + _sceneView(sv) {} + + virtual ~SetSceneViewVisitor() {} + + virtual void visit(CameraManipulator& cm); + virtual void visit(StateSetManipulator& cm); + + private: + + osg::ref_ptr _sceneView; + +}; + +}; + +#endif diff --git a/include/osgGA/StateSetManipulator b/include/osgGA/StateSetManipulator new file mode 100644 index 000000000..86f5baa08 --- /dev/null +++ b/include/osgGA/StateSetManipulator @@ -0,0 +1,51 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_GEOSTATE_MANIPULATOR +#define OSGGA_GEOSTATE_MANIPULATOR 1 + +#include + +#include +#include +#include +#include + +namespace osgGA{ + +class OSGGA_EXPORT StateSetManipulator : public GUIEventHandler +{ + public: + + StateSetManipulator(); + virtual ~StateSetManipulator(); + + /** attach a geostate to the manipulator to be used for specifying view.*/ + virtual void setStateSet(osg::StateSet*); + + /** get the attached a geostate.*/ + virtual osg::StateSet * getStateSet(); + + /** get the attached a geostate.*/ + virtual const osg::StateSet * getStateSet() const; + + /** Handle events, return true if handled, false otherwise.*/ + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us); + + /** Handle visitations */ + virtual void accept(GUIEventHandlerVisitor&); + + protected: + + // Reference pointer to a geostate + osg::ref_ptr _drawState; + + bool _backface; + bool _lighting; + bool _texture; +}; + +} + +#endif diff --git a/include/osgGA/TrackballManipulator b/include/osgGA/TrackballManipulator new file mode 100644 index 000000000..61076708c --- /dev/null +++ b/include/osgGA/TrackballManipulator @@ -0,0 +1,77 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_TRACKBALLMANIPULATOR +#define OSGGA_TRACKBALLMANIPULATOR 1 + +#include + +namespace osgGA{ + +class OSGGA_EXPORT TrackballManipulator : public CameraManipulator +{ + public: + + TrackballManipulator(); + virtual ~TrackballManipulator(); + + /** Attach a node to the manipulator. + Automatically detaches previously attached node. + setNode(NULL) detaches previously nodes. + Is ignored by manipulators which do not require a reference model.*/ + virtual void setNode(osg::Node*); + + /** Return node if attached.*/ + virtual const osg::Node* getNode() const; + + /** Return node if attached.*/ + virtual osg::Node* getNode(); + + /** Move the camera to the default position. + May be ignored by manipulators if home functionality is not appropriate.*/ + virtual void home(const GUIEventAdapter& ea,GUIActionAdapter& us); + + /** Start/restart the manipulator.*/ + virtual void init(const GUIEventAdapter& ea,GUIActionAdapter& us); + + + /** handle events, return true if handled, false otherwise.*/ + virtual bool handle(const GUIEventAdapter& ea,GUIActionAdapter& us); + + private: + + /** Reset the internal GUIEvent stack.*/ + void flushMouseEventStack(); + /** Add the current mouse GUIEvent to internal stack.*/ + void addMouseEvent(const GUIEventAdapter& ea); + + /** For the give mouse movement calculate the movement of the camera. + Return true is camera has moved and a redraw is required.*/ + bool calcMovement(); + + void trackball(osg::Vec3& axis,float& angle, float p1x, float p1y, float p2x, float p2y); + float tb_project_to_sphere(float r, float x, float y); + + + /** Check the speed at which the mouse is moving. + If speed is below a threshold then return false, otherwise return true.*/ + bool isMouseMoving(); + + // Internal event stack comprising last three mouse events. + osg::ref_ptr _ga_t1; + osg::ref_ptr _ga_t0; + + osg::ref_ptr _node; + + float _modelScale; + float _minimumZoomScale; + + bool _thrown; + +}; + +} + +#endif + diff --git a/include/osgGA/Version b/include/osgGA/Version new file mode 100644 index 000000000..f1640762e --- /dev/null +++ b/include/osgGA/Version @@ -0,0 +1,39 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGGA_VERSION +#define OSGGA_VERSION 1 + +#include + + +extern "C" { + +/** + * getVersion_osgGA() returns the library version number. + * Numbering convention : osg_src-0.8-31 will return 0.8.31 from getVersion_osgGA. + * + * This C function can be also used to check for the existence of the OpenSceneGraph + * library using autoconf and its m4 macro AC_CHECK_LIB. + * + * Here is the code to add to your configure.in: + \verbatim + # + # Check for the OpenSceneGraph (OSG) utility library + # + AC_CHECK_LIB(osg, osgGAGetVersion, , + [AC_MSG_ERROR(OpenSceneGraph utility library not found. See http://www.openscenegraph.org)],) + \endverbatim +*/ +extern OSGGA_EXPORT const char* osgGAGetVersion(); + +/** + * getLibraryName_osgGA() returns the library name in human friendly form. +*/ +extern OSGGA_EXPORT const char* osgGAGetLibraryName(); + +} + +#endif + diff --git a/src/osgGA/CameraManipulator.cpp b/src/osgGA/CameraManipulator.cpp new file mode 100644 index 000000000..b5d88df6d --- /dev/null +++ b/src/osgGA/CameraManipulator.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +using namespace osg; +using namespace osgGA; + +CameraManipulator::CameraManipulator(): _camera(NULL) +{ +} + + +CameraManipulator::~CameraManipulator() +{ +} + + +void CameraManipulator::setCamera(Camera *camera) +{ + _camera=camera; +} + + +const Camera *CameraManipulator::getCamera() const +{ + return _camera.get(); +} + +Camera *CameraManipulator::getCamera() +{ + return _camera.get(); +} + +bool CameraManipulator::handle(const GUIEventAdapter&,GUIActionAdapter&) +{ + return false; +} diff --git a/src/osgGA/DriveManipulator.cpp b/src/osgGA/DriveManipulator.cpp new file mode 100644 index 000000000..d015c7b2c --- /dev/null +++ b/src/osgGA/DriveManipulator.cpp @@ -0,0 +1,565 @@ +#if defined(_MSC_VER) + #pragma warning( disable : 4786 ) +#endif + +#include +#include +#include + +using namespace osg; +using namespace osgGA; + +DriveManipulator::DriveManipulator() +{ + _modelScale = 0.01f; + _velocity = 0.0f; + //_speedMode = USE_MOUSE_Y_FOR_SPEED; + _speedMode = USE_MOUSE_BUTTONS_FOR_SPEED; +} + + +DriveManipulator::~DriveManipulator() +{ +} + + +void DriveManipulator::setNode(osg::Node* node) +{ + _node = node; + if (_node.get()) + { + const osg::BoundingSphere& boundingSphere=_node->getBound(); + _modelScale = boundingSphere._radius; + _height = sqrtf(_modelScale)*0.03f; + _buffer = sqrtf(_modelScale)*0.05f; + } +} + + +const osg::Node* DriveManipulator::getNode() const +{ + return _node.get(); +} + + +osg::Node* DriveManipulator::getNode() +{ + return _node.get(); +} + +void DriveManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + + if(_node.get() && _camera.get()) + { + + const osg::BoundingSphere& boundingSphere=_node->getBound(); + + osg::Vec3 ep = boundingSphere._center; + osg::Vec3 bp = ep; + ep.z() -= _modelScale*0.0001f; + bp.z() -= _modelScale; + + // check to see if any obstruction in front. + osgUtil::IntersectVisitor iv; + + bool cameraSet = false; + + osg::ref_ptr segDown = new osg::LineSegment; + segDown->set(ep,bp); + iv.addLineSegment(segDown.get()); + + _node->accept(iv); + + if (iv.hits()) + { + osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get()); + if (!hitList.empty()) + { + // notify(INFO) << "Hit terrain ok"<< std::endl; + osg::Vec3 ip = hitList.front().getWorldIntersectPoint(); + osg::Vec3 np = hitList.front().getWorldIntersectNormal(); + + osg::Vec3 uv; + if (np.z()>0.0f) uv = np; + else uv = -np; + + float lookDistance = _modelScale*0.1f; + + ep = ip; + ep.z() += _height; + osg::Vec3 lv = uv^osg::Vec3(1.0f,0.0f,0.0f); + osg::Vec3 cp = ep+lv*lookDistance; + + _camera->setLookAt(ep,cp,uv); + + cameraSet = true; + + } + + } + + if (!cameraSet) + { + bp = ep; + bp.z() += _modelScale; + + osg::ref_ptr segUp = new osg::LineSegment; + segUp->set(ep,bp); + iv.addLineSegment(segUp.get()); + + _node->accept(iv); + + if (iv.hits()) + { + osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get()); + if (!hitList.empty()) + { + // notify(INFO) << "Hit terrain ok"<< std::endl; + osg::Vec3 ip = hitList.front().getWorldIntersectPoint(); + osg::Vec3 np = hitList.front().getWorldIntersectNormal(); + + osg::Vec3 uv; + if (np.z()>0.0f) uv = np; + else uv = -np; + + float lookDistance = _modelScale*0.1f; + + ep = ip; + ep.z() += _height; + osg::Vec3 lv = uv^osg::Vec3(1.0f,0.0f,0.0f); + osg::Vec3 cp = ep+lv*lookDistance; + + _camera->setLookAt(ep,cp,uv); + + cameraSet = true; + + } + + } + } + + if (!cameraSet) + { + // eye + _camera->setLookAt(boundingSphere._center+osg::Vec3( 0.0,-2.0f * boundingSphere._radius,0.0f), + // look + boundingSphere._center, + // up + osg::Vec3(0.0f,0.0f,1.0f)); + } + + } + + _velocity = 0.0f; + + us.requestRedraw(); + + us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2); + + flushMouseEventStack(); + +} + + +void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + flushMouseEventStack(); + + us.requestContinuousUpdate(false); + + _velocity = 0.0f; + + osg::Vec3 ep = _camera->getEyePoint(); + osg::Vec3 sv = _camera->getSideVector(); + osg::Vec3 bp = ep; + bp.z() -= _modelScale; + + // check to see if any obstruction in front. + osgUtil::IntersectVisitor iv; + + bool cameraSet = false; + + osg::ref_ptr segDown = new osg::LineSegment; + segDown->set(ep,bp); + iv.addLineSegment(segDown.get()); + + _node->accept(iv); + + if (iv.hits()) + { + osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get()); + if (!hitList.empty()) + { + // notify(INFO) << "Hit terrain ok"<< std::endl; + osg::Vec3 ip = hitList.front().getWorldIntersectPoint(); + osg::Vec3 np = hitList.front().getWorldIntersectNormal(); + + osg::Vec3 uv; + if (np.z()>0.0f) uv = np; + else uv = -np; + + float lookDistance = _modelScale*0.1f; + + ep = ip+uv*_height; + osg::Vec3 lv = uv^sv; + osg::Vec3 lp = ep+lv*lookDistance; + + _camera->setLookAt(ep,lp,uv); + _camera->ensureOrthogonalUpVector(); + + cameraSet = true; + + } + + } + + if (!cameraSet) + { + bp = ep; + bp.z() += _modelScale; + + osg::ref_ptr segUp = new osg::LineSegment; + segUp->set(ep,bp); + iv.addLineSegment(segUp.get()); + + _node->accept(iv); + + if (iv.hits()) + { + osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get()); + if (!hitList.empty()) + { + // notify(INFO) << "Hit terrain ok"<< std::endl; + osg::Vec3 ip = hitList.front().getWorldIntersectPoint(); + osg::Vec3 np = hitList.front().getWorldIntersectNormal(); + + osg::Vec3 uv; + if (np.z()>0.0f) uv = np; + else uv = -np; + + float lookDistance = _modelScale*0.1f; + + ep = ip+uv*_height; + osg::Vec3 lv = uv^sv; + osg::Vec3 lp = ep+lv*lookDistance; + + _camera->setLookAt(ep,lp,uv); + _camera->ensureOrthogonalUpVector(); + + cameraSet = true; + + } + + } + } + + us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2); + +} + + +bool DriveManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + if(!_camera.get()) return false; + + switch(ea.getEventType()) + { + case(GUIEventAdapter::PUSH): + { + + addMouseEvent(ea); + us.requestContinuousUpdate(true); + if (calcMovement()) us.requestRedraw(); + return true; + } + + case(GUIEventAdapter::RELEASE): + { + + addMouseEvent(ea); + us.requestContinuousUpdate(true); + if (calcMovement()) us.requestRedraw(); + return true; + } + + case(GUIEventAdapter::DRAG): + { + + addMouseEvent(ea); + us.requestContinuousUpdate(true); + if (calcMovement()) us.requestRedraw(); + return true; + } + + case(GUIEventAdapter::MOVE): + { + + addMouseEvent(ea); + us.requestContinuousUpdate(true); + if (calcMovement()) us.requestRedraw(); + return true; + } + + case(GUIEventAdapter::KEYBOARD): + { + if (ea.getKey()==' ') + { + flushMouseEventStack(); + home(ea,us); + us.requestRedraw(); + us.requestContinuousUpdate(false); + return true; + } + else if (ea.getKey()=='q') + { + _speedMode = USE_MOUSE_Y_FOR_SPEED; + return true; + } + else if (ea.getKey()=='a') + { + _speedMode = USE_MOUSE_BUTTONS_FOR_SPEED; + return true; + } + else if (ea.getKey()=='+') + { + _camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()*1.25f); + return true; + } + else if (ea.getKey()=='-') + { + _camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()/1.25f); + return true; + } + return false; + } + + case(GUIEventAdapter::FRAME): + { + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + return true; + } + + case(GUIEventAdapter::RESIZE): + { + init(ea,us); + us.requestRedraw(); + return true; + } + + default: + return false; + } +} + + +void DriveManipulator::flushMouseEventStack() +{ + _ga_t1 = NULL; + _ga_t0 = NULL; +} + + +void DriveManipulator::addMouseEvent(const GUIEventAdapter& ea) +{ + _ga_t1 = _ga_t0; + _ga_t0 = &ea; +} + + +bool DriveManipulator::calcMovement() +{ + _camera->setFusionDistanceMode(osg::Camera::PROPORTIONAL_TO_SCREEN_DISTANCE); + + // return if less then two events have been added. + if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; + + float dt = _ga_t0->time()-_ga_t1->time(); + + if (dt<0.0f) + { + notify(WARN) << "warning dt = "<getYmin()+_ga_t0->getYmax())/2.0f; + float dy = _ga_t0->getY()-my; + _velocity = -_modelScale*0.0002f*dy; + break; + } + case(USE_MOUSE_BUTTONS_FOR_SPEED): + { + unsigned int buttonMask = _ga_t1->getButtonMask(); + if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) + { + // pan model. + + _velocity += dt*_modelScale*0.02f; + + } + else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || + buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON)) + { + + _velocity = 0.0f; + + } + else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) + { + + _velocity -= dt*_modelScale*0.02f; + + } + break; + } + } + + // rotate the camera. + osg::Vec3 center = _camera->getEyePoint(); + osg::Vec3 uv = _camera->getUpVector(); + + float mx = (_ga_t0->getXmin()+_ga_t0->getXmax())/2.0f; + + float dx = _ga_t0->getX()-mx; + + float yaw = -inDegrees(dx*0.1f*dt); + + osg::Matrix mat; + mat.makeTranslate(-center.x(),-center.y(),-center.z()); + mat *= Matrix::rotate(yaw,uv.x(),uv.y(),uv.z()); + mat *= Matrix::translate(center.x(),center.y(),center.z()); + + center = _camera->getEyePoint(); + uv = _camera->getUpVector(); + + _camera->transformLookAt(mat); + + // get the new forward (look) vector. + osg::Vec3 sv = _camera->getSideVector(); + osg::Vec3 lv = _camera->getCenterPoint()-_camera->getEyePoint(); + float lookDistance = lv.length(); + lv.normalize(); + + // movement is big enough the move the eye point along the look vector. + if (fabsf(_velocity*dt)>1e-8) + { + osg::Vec3 ep = _camera->getEyePoint(); + float distanceToMove = _velocity*dt; + + float signedBuffer; + if (distanceToMove>=0.0f) signedBuffer=_buffer; + else signedBuffer=-_buffer; + + // check to see if any obstruction in front. + osgUtil::IntersectVisitor iv; + osg::ref_ptr segForward = new osg::LineSegment; + segForward->set(ep,ep+lv*(signedBuffer+distanceToMove)); + iv.addLineSegment(segForward.get()); + + _node->accept(iv); + + if (iv.hits()) + { + osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segForward.get()); + if (!hitList.empty()) + { + // notify(INFO) << "Hit obstruction"<< std::endl; + osg::Vec3 ip = hitList.front().getWorldIntersectPoint(); + distanceToMove = (ip-ep).length()-_buffer; + _velocity = 0.0f; + } + + } + + // check to see if forward point is correct height above terrain. + osg::Vec3 fp = ep+lv*distanceToMove; + osg::Vec3 lfp = fp-uv*_height*5; + + iv.reset(); + + osg::ref_ptr segNormal = new osg::LineSegment; + segNormal->set(fp,lfp); + iv.addLineSegment(segNormal.get()); + + _node->accept(iv); + + if (iv.hits()) + { + osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segNormal.get()); + if (!hitList.empty()) + { + // notify(INFO) << "Hit terrain ok"<< std::endl; + osg::Vec3 ip = hitList.front().getWorldIntersectPoint(); + osg::Vec3 np = hitList.front().getWorldIntersectNormal(); + + if (uv*np>0.0f) uv = np; + else uv = -np; + + ep = ip+uv*_height; + lv = uv^sv; + osg::Vec3 lp = ep+lv*lookDistance; + + _camera->setLookAt(ep,lp,uv); + _camera->ensureOrthogonalUpVector(); + + return true; + + } + + } + + // no hit on the terrain found therefore resort to a fall under + // under the influence of gravity. + osg::Vec3 dp = lfp; + dp.z() -= 2*_modelScale; + + iv.reset(); + + osg::ref_ptr segFall = new osg::LineSegment; + segFall->set(lfp,dp); + iv.addLineSegment(segFall.get()); + + _node->accept(iv); + + if (iv.hits()) + { + osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segFall.get()); + if (!hitList.empty()) + { + + notify(INFO) << "Hit terrain on decent ok"<< std::endl; + osg::Vec3 ip = hitList.front().getWorldIntersectPoint(); + osg::Vec3 np = hitList.front().getWorldIntersectNormal(); + + if (uv*np>0.0f) uv = np; + else uv = -np; + + ep = ip+uv*_height; + lv = uv^sv; + osg::Vec3 lp = ep+lv*lookDistance; + + _camera->setLookAt(ep,lp,uv); + _camera->ensureOrthogonalUpVector(); + + return true; + } + } + + // no collision with terrain has been found therefore track horizontally. + + lv *= (_velocity*dt); + ep += lv; + osg::Vec3 lp = _camera->getCenterPoint()+lv; + + _camera->setLookAt(ep,lp,uv); + _camera->ensureOrthogonalUpVector(); + + } + + return true; +} diff --git a/src/osgGA/FlightManipulator.cpp b/src/osgGA/FlightManipulator.cpp new file mode 100644 index 000000000..ca34b4570 --- /dev/null +++ b/src/osgGA/FlightManipulator.cpp @@ -0,0 +1,245 @@ +#include +#include +#include + +using namespace osg; +using namespace osgGA; + +FlightManipulator::FlightManipulator() +{ + _modelScale = 0.01f; + _velocity = 0.0f; + _yawMode = YAW_AUTOMATICALLY_WHEN_BANKED; +} + + +FlightManipulator::~FlightManipulator() +{ +} + + +void FlightManipulator::setNode(osg::Node* node) +{ + _node = node; + if (_node.get()) + { + const osg::BoundingSphere& boundingSphere=_node->getBound(); + _modelScale = boundingSphere._radius; + } +} + + +const osg::Node* FlightManipulator::getNode() const +{ + return _node.get(); +} + + + +osg::Node* FlightManipulator::getNode() +{ + return _node.get(); +} + +void FlightManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + if(_node.get() && _camera.get()) + { + + const osg::BoundingSphere& boundingSphere=_node->getBound(); + + _camera->setLookAt( + boundingSphere._center+osg::Vec3( 0.0,-3.0f * boundingSphere._radius,0.0f), + boundingSphere._center, + osg::Vec3(0.0f,0.0f,1.0f)); + + _velocity = 0.0f; + + us.requestRedraw(); + + us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2); + + flushMouseEventStack(); + + } + +} + + +void FlightManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + flushMouseEventStack(); + + us.requestContinuousUpdate(false); + + _velocity = 0.0f; + + us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2); + +} + + +bool FlightManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + if(!_camera.get()) return false; + + switch(ea.getEventType()) + { + case(GUIEventAdapter::PUSH): + { + + addMouseEvent(ea); + us.requestContinuousUpdate(true); + if (calcMovement()) us.requestRedraw(); + return true; + } + + case(GUIEventAdapter::RELEASE): + { + + addMouseEvent(ea); + us.requestContinuousUpdate(true); + if (calcMovement()) us.requestRedraw(); + return true; + } + + case(GUIEventAdapter::DRAG): + { + + addMouseEvent(ea); + us.requestContinuousUpdate(true); + if (calcMovement()) us.requestRedraw(); + return true; + } + + case(GUIEventAdapter::MOVE): + { + + addMouseEvent(ea); + us.requestContinuousUpdate(true); + if (calcMovement()) us.requestRedraw(); + + return true; + } + + case(GUIEventAdapter::KEYBOARD): + if (ea.getKey()==' ') + { + flushMouseEventStack(); + home(ea,us); + us.requestRedraw(); + us.requestContinuousUpdate(false); + return true; + } + else if (ea.getKey()=='+') + { + _camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()*1.25f); + return true; + } + else if (ea.getKey()=='-') + { + _camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()/1.25f); + return true; + } + return false; + + case(GUIEventAdapter::FRAME): + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + return true; + + case(GUIEventAdapter::RESIZE): + init(ea,us); + us.requestRedraw(); + return true; + + default: + return false; + } +} + + +void FlightManipulator::flushMouseEventStack() +{ + _ga_t1 = NULL; + _ga_t0 = NULL; +} + + +void FlightManipulator::addMouseEvent(const GUIEventAdapter& ea) +{ + _ga_t1 = _ga_t0; + _ga_t0 = &ea; +} + + +bool FlightManipulator::calcMovement() +{ + _camera->setFusionDistanceMode(osg::Camera::PROPORTIONAL_TO_SCREEN_DISTANCE); + + // return if less then two events have been added. + if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; + + + float dt = _ga_t0->time()-_ga_t1->time(); + + if (dt<0.0f) + { + notify(WARN) << "warning dt = "<getButtonMask(); + if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) + { + // pan model. + + _velocity += dt*_modelScale*0.05f; + + } + else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || + buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON)) + { + + _velocity = 0.0f; + + } + else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) + { + + _velocity -= dt*_modelScale*0.05f; + + } + + float mx = (_ga_t0->getXmin()+_ga_t0->getXmax())/2.0f; + float my = (_ga_t0->getYmin()+_ga_t0->getYmax())/2.0f; + + float dx = _ga_t0->getX()-mx; + float dy = _ga_t0->getY()-my; + + osg::Vec3 center = _camera->getEyePoint(); + osg::Vec3 sv = _camera->getSideVector(); + osg::Vec3 lv = _camera->getLookVector(); + + float pitch = inDegrees(dy*0.15f*dt); + float roll = inDegrees(dx*0.1f*dt); + + osg::Matrix mat; + mat.makeTranslate(-center); + mat *= Matrix::rotate(pitch,sv.x(),sv.y(),sv.z()); + mat *= Matrix::rotate(roll,lv.x(),lv.y(),lv.z()); + if (_yawMode==YAW_AUTOMATICALLY_WHEN_BANKED) + { + float bank = asinf(sv.z()); + float yaw = inRadians(bank)*dt; + mat *= Matrix::rotate(yaw,0.0f,0.0f,1.0f); + } + + lv *= (_velocity*dt); + + mat *= Matrix::translate(center+lv); + + _camera->transformLookAt(mat); + + return true; +} diff --git a/src/osgGA/GUIEventHandler.cpp b/src/osgGA/GUIEventHandler.cpp new file mode 100644 index 000000000..3e257bce1 --- /dev/null +++ b/src/osgGA/GUIEventHandler.cpp @@ -0,0 +1,43 @@ +#include + +using osgGA::CompositeGUIEventHandler; + +bool CompositeGUIEventHandler::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa) +{ + bool result=false; + + for (ChildList::iterator itr=_children.begin(); + itr!=_children.end(); + ++itr) + { + result |= (*itr)->handle(ea,aa); + } + return result; +} + + +bool CompositeGUIEventHandler::addChild(GUIEventHandler *child) +{ + if (child && !containsNode(child)) + { + // note ref_ptr<> automatically handles incrementing child's reference count. + _children.push_back(child); + return true; + } + else return false; + +} + +bool CompositeGUIEventHandler::removeChild(GUIEventHandler *child) +{ + ChildList::iterator itr = findChild(child); + if (itr!=_children.end()) + { + // note ref_ptr<> automatically handles decrementing child's reference count. + _children.erase(itr); + + return true; + } + else return false; + +} diff --git a/src/osgGA/GUIEventHandlerVisitor.cpp b/src/osgGA/GUIEventHandlerVisitor.cpp new file mode 100644 index 000000000..49cef8683 --- /dev/null +++ b/src/osgGA/GUIEventHandlerVisitor.cpp @@ -0,0 +1,9 @@ +#include +#include + +void osgGA::GUIEventHandlerVisitor::visit(osgGA::CompositeGUIEventHandler& cgeh) +{ + for(int i=0; iaccept(*this); + } +} diff --git a/src/osgGA/KeySwitchCameraManipulator.cpp b/src/osgGA/KeySwitchCameraManipulator.cpp new file mode 100644 index 000000000..dab1f5d81 --- /dev/null +++ b/src/osgGA/KeySwitchCameraManipulator.cpp @@ -0,0 +1,45 @@ +#include +#include + +using namespace osgGA; + +void KeySwitchCameraManipulator::addCameraManipulator(int key, std::string name, CameraManipulator *cm) +{ + if(!cm) return; + + _manips[key]=std::make_pair(name,osg::ref_ptr(cm)); + if(!_current.valid()){ + _current=cm; + } +} + +bool KeySwitchCameraManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa) +{ + if(ea.getEventType()==GUIEventAdapter::KEYBOARD){ + + KeyManipMap::iterator it=_manips.find(ea.getKey()); + if(it != _manips.end()){ + osg::notify(osg::INFO)<<"Switching to manipulator: "<<(*it).second.first<second.second->setNode(_current->getNode()); + it->second.second->setCamera(_current->getCamera()); + it->second.second->init(ea,aa); + _current = it->second.second; + + //_cameraManipChangeCallbacks.notify(this); + + } + } + + return _current->handle(ea,aa); +} + +// void KeySwitchCameraManipulator::addCallback(Callback* c) +// { +// _cameraManipChangeCallbacks.addCallback(c); +// } +// +// void KeySwitchCameraManipulator::removeCallback(Callback* c) +// { +// _cameraManipChangeCallbacks.removeCallback(c); +// } diff --git a/src/osgGA/Makefile b/src/osgGA/Makefile new file mode 100644 index 000000000..18a201492 --- /dev/null +++ b/src/osgGA/Makefile @@ -0,0 +1,24 @@ +TOPDIR = ../.. +include $(TOPDIR)/Make/makedefs + + +CXXFILES = \ + CameraManipulator.cpp\ + DriveManipulator.cpp\ + FlightManipulator.cpp\ + GUIEventHandler.cpp\ + GUIEventHandlerVisitor.cpp\ + KeySwitchCameraManipulator.cpp\ + SetSceneViewVisitor.cpp\ + StateSetManipulator.cpp\ + TrackballManipulator.cpp\ + Version.cpp\ + +DEF += -DOSGGA_LIBRARY + +LIBS += -losgUtil -losg $(GL_LIBS) $(OTHER_LIBS) + +TARGET_BASENAME = osgGA +LIB = $(LIB_PREFIX)$(TARGET_BASENAME).$(LIB_EXT) + +include $(TOPDIR)/Make/makerules diff --git a/src/osgGA/SetSceneViewVisitor.cpp b/src/osgGA/SetSceneViewVisitor.cpp new file mode 100644 index 000000000..1e1b10352 --- /dev/null +++ b/src/osgGA/SetSceneViewVisitor.cpp @@ -0,0 +1,16 @@ +#include +#include +#include + +void osgGA::SetSceneViewVisitor::visit(osgGA::CameraManipulator& cm) +{ + cm.setNode(_sceneView->getSceneData()); + cm.setCamera(_sceneView->getCamera()); + cm.init(*getGUIEventAdapter(),*getGUIActionAdapter()); + cm.home(*getGUIEventAdapter(),*getGUIActionAdapter()); +} + +void osgGA::SetSceneViewVisitor::visit(osgGA::StateSetManipulator& ssm) +{ + ssm.setStateSet(_sceneView->getGlobalStateSet()); +} diff --git a/src/osgGA/StateSetManipulator.cpp b/src/osgGA/StateSetManipulator.cpp new file mode 100644 index 000000000..d745c2088 --- /dev/null +++ b/src/osgGA/StateSetManipulator.cpp @@ -0,0 +1,73 @@ +#include + +using namespace osg; +using namespace osgGA; + +StateSetManipulator::StateSetManipulator(): _drawState(NULL) +{ +} + +StateSetManipulator::~StateSetManipulator() +{ +} + +void StateSetManipulator::setStateSet(StateSet *drawState) +{ + _drawState=drawState; + if(!_drawState.valid()) return; + _backface = (_drawState->getMode(GL_CULL_FACE)==osg::StateAttribute::ON); + _lighting =(_drawState->getMode(GL_LIGHTING)==osg::StateAttribute::ON); + _texture =(_drawState->getMode(GL_TEXTURE_2D)==osg::StateAttribute::ON); +} + +StateSet *StateSetManipulator::getStateSet() +{ + return _drawState.get(); +} + +const StateSet *StateSetManipulator::getStateSet() const +{ + return _drawState.get(); +} + +bool StateSetManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa) +{ + if(!_drawState.valid()) return false; + + if(ea.getEventType()==GUIEventAdapter::KEYBOARD){ + + switch( ea.getKey() ){ + + case 'b' : + _backface = !_backface; + if( _backface ) _drawState->setMode(GL_CULL_FACE,osg::StateAttribute::ON); + else _drawState->setMode(GL_CULL_FACE,osg::StateAttribute::OVERRIDE_OFF); + aa.requestRedraw(); + return true; + break; + + case 'l' : + _lighting = !_lighting ; + if( _lighting ) _drawState->setMode(GL_LIGHTING,osg::StateAttribute::ON); + else _drawState->setMode(GL_LIGHTING,osg::StateAttribute::OVERRIDE_OFF); + aa.requestRedraw(); + return true; + break; + + case 't' : + _texture = !_texture; + if (_texture) _drawState->setMode(GL_TEXTURE_2D,osg::StateAttribute::INHERIT); + else _drawState->setMode(GL_TEXTURE_2D,osg::StateAttribute::OVERRIDE_OFF); + aa.requestRedraw(); + return true; + break; + + } + } + return false; +} + +void StateSetManipulator::accept(GUIEventHandlerVisitor& gehv) +{ + gehv.visit(*this); +} diff --git a/src/osgGA/TrackballManipulator.cpp b/src/osgGA/TrackballManipulator.cpp new file mode 100644 index 000000000..28fdaeb60 --- /dev/null +++ b/src/osgGA/TrackballManipulator.cpp @@ -0,0 +1,397 @@ +#include +#include +#include + +using namespace osg; +using namespace osgGA; + +TrackballManipulator::TrackballManipulator() +{ + _modelScale = 0.01f; + _minimumZoomScale = 0.05f; + _thrown = false; +} + + +TrackballManipulator::~TrackballManipulator() +{ +} + + +void TrackballManipulator::setNode(osg::Node* node) +{ + _node = node; + if (_node.get()) + { + const osg::BoundingSphere& boundingSphere=_node->getBound(); + _modelScale = boundingSphere._radius; + } +} + + +const osg::Node* TrackballManipulator::getNode() const +{ + return _node.get(); +} + + +osg::Node* TrackballManipulator::getNode() +{ + return _node.get(); +} + + + /*ea*/ +void TrackballManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us) +{ + if(_node.get() && _camera.get()) + { + + const osg::BoundingSphere& boundingSphere=_node->getBound(); + + _camera->setView(boundingSphere._center+osg::Vec3( 0.0,-3.0f * boundingSphere._radius,0.0f), + boundingSphere._center, + osg::Vec3(0.0f,0.0f,1.0f)); + + us.requestRedraw(); + } + +} + + +void TrackballManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& ) +{ + flushMouseEventStack(); +} + + +bool TrackballManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + if(!_camera.get()) return false; + + switch(ea.getEventType()) + { + case(GUIEventAdapter::PUSH): + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + us.requestContinuousUpdate(false); + _thrown = false; + return true; + } + + case(GUIEventAdapter::RELEASE): + { + if (ea.getButtonMask()==0) + { + + if (isMouseMoving()) + { + if (calcMovement()) + { + us.requestRedraw(); + us.requestContinuousUpdate(true); + _thrown = true; + } + } + else + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + us.requestContinuousUpdate(false); + _thrown = false; + } + + } + else + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + us.requestContinuousUpdate(false); + _thrown = false; + } + return true; + } + + case(GUIEventAdapter::DRAG): + { + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + us.requestContinuousUpdate(false); + _thrown = false; + return true; + } + + case(GUIEventAdapter::MOVE): + { + return false; + } + + case(GUIEventAdapter::KEYBOARD): + if (ea.getKey()==' ') + { + flushMouseEventStack(); + _thrown = false; + home(ea,us); + us.requestRedraw(); + us.requestContinuousUpdate(false); + return true; + } else if (ea.getKey()=='+') + { + _camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()*1.25f); + return true; + } + else if (ea.getKey()=='-') + { + _camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()/1.25f); + return true; + } + return false; + case(GUIEventAdapter::FRAME): + _camera->setFusionDistanceMode(osg::Camera::PROPORTIONAL_TO_LOOK_DISTANCE); + if (_thrown) + { + if (calcMovement()) us.requestRedraw(); + return true; + } + return false; + default: + return false; + } +} + + +bool TrackballManipulator::isMouseMoving() +{ + if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; + + static const float velocity = 100.0f; + + float dx = _ga_t0->getX()-_ga_t1->getX(); + float dy = _ga_t0->getY()-_ga_t1->getY(); + float len = sqrtf(dx*dx+dy*dy); + float dt = _ga_t0->time()-_ga_t1->time(); + + return (len>dt*velocity); +} + + +void TrackballManipulator::flushMouseEventStack() +{ + _ga_t1 = NULL; + _ga_t0 = NULL; +} + + +void TrackballManipulator::addMouseEvent(const GUIEventAdapter& ea) +{ + _ga_t1 = _ga_t0; + _ga_t0 = &ea; +} + + +bool TrackballManipulator::calcMovement() +{ + + // return if less then two events have been added. + if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; + + float dx = _ga_t0->getX()-_ga_t1->getX(); + float dy = _ga_t0->getY()-_ga_t1->getY(); + + + // return if there is no movement. + if (dx==0 && dy==0) return false; + + float focalLength = (_camera->getCenterPoint()-_camera->getEyePoint()).length(); + unsigned int buttonMask = _ga_t1->getButtonMask(); + if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) + { + + // rotate camera. + + osg::Vec3 center = _camera->getCenterPoint(); + osg::Vec3 axis; + float angle; + + float mx0 = (_ga_t0->getXmin()+_ga_t0->getXmax())/2.0f; + float rx0 = (_ga_t0->getXmax()-_ga_t0->getXmin())/2.0f; + + float my0 = (_ga_t0->getYmin()+_ga_t0->getYmax())/2.0f; + float ry0 = (_ga_t0->getYmax()-_ga_t0->getYmin())/2.0f; + + float mx1 = (_ga_t0->getXmin()+_ga_t1->getXmax())/2.0f; + float rx1 = (_ga_t0->getXmax()-_ga_t1->getXmin())/2.0f; + + float my1 = (_ga_t1->getYmin()+_ga_t1->getYmax())/2.0f; + float ry1 = (_ga_t1->getYmax()-_ga_t1->getYmin())/2.0f; + + float px0 = (_ga_t0->getX()-mx0)/rx0; + float py0 = (my0-_ga_t0->getY())/ry0; + + float px1 = (_ga_t1->getX()-mx1)/rx1; + float py1 = (my1-_ga_t1->getY())/ry1; + + trackball(axis,angle,px1,py1,px0,py0); + + osg::Matrix mat; + mat.makeTranslate(-center.x(),-center.y(),-center.z()); + mat *= Matrix::rotate(angle,axis.x(),axis.y(),axis.z()); + mat *= Matrix::translate(center.x(),center.y(),center.z()); + + _camera->transformLookAt(mat); + + return true; + + } + else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || + buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON)) + { + + // pan model. + + + float scale = 0.0015f*focalLength; + + osg::Vec3 uv = _camera->getUpVector(); + osg::Vec3 sv = _camera->getSideVector(); + osg::Vec3 dv = uv*(dy*scale)-sv*(dx*scale); + + osg::Matrix mat; + mat.makeTranslate(dv.x(),dv.y(),dv.z()); + + _camera->transformLookAt(mat); + + return true; + + } + else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) + { + + // zoom model. + + float fd = focalLength; + float scale = 1.0f-dy*0.001f; + if (fd*scale>_modelScale*_minimumZoomScale) + { + // zoom camera in. + osg::Vec3 center = _camera->getCenterPoint(); + + osg::Matrix mat; + mat.makeTranslate(-center.x(),-center.y(),-center.z()); + mat *= Matrix::scale(scale,scale,scale); + mat *= Matrix::translate(center.x(),center.y(),center.z()); + + _camera->transformLookAt(mat); + + } + else + { + + // notify(DEBUG_INFO) << "Pushing forward"<getLookVector()*(dy*scale); + + osg::Matrix mat; + mat.makeTranslate(dv.x(),dv.y(),dv.z()); + + _camera->transformLookAt(mat); + + } + + return true; + + } + + return false; +} + + +/* + * This size should really be based on the distance from the center of + * rotation to the point on the object underneath the mouse. That + * point would then track the mouse as closely as possible. This is a + * simple example, though, so that is left as an Exercise for the + * Programmer. + */ +const float TRACKBALLSIZE = 0.8f; + +/* + * Ok, simulate a track-ball. Project the points onto the virtual + * trackball, then figure out the axis of rotation, which is the cross + * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) + * Note: This is a deformed trackball-- is a trackball in the center, + * but is deformed into a hyperbolic sheet of rotation away from the + * center. This particular function was chosen after trying out + * several variations. + * + * It is assumed that the arguments to this routine are in the range + * (-1.0 ... 1.0) + */ +void TrackballManipulator::trackball(osg::Vec3& axis,float& angle, float p1x, float p1y, float p2x, float p2y) +{ + /* + * First, figure out z-coordinates for projection of P1 and P2 to + * deformed sphere + */ + + osg::Vec3 uv = _camera->getUpVector(); + osg::Vec3 sv = _camera->getSideVector(); + osg::Vec3 lv = _camera->getLookVector(); + + osg::Vec3 p1 = sv*p1x+uv*p1y-lv*tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y); + osg::Vec3 p2 = sv*p2x+uv*p2y-lv*tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y); + + /* + * Now, we want the cross product of P1 and P2 + */ + +// Robert, +// +// This was the quick 'n' dirty fix to get the trackball doing the right +// thing after fixing the Quat rotations to be right-handed. You may want +// to do something more elegant. +// axis = p1^p2; +axis = p2^p1; + axis.normalize(); + + /* + * Figure out how much to rotate around that axis. + */ + float t = (p2-p1).length() / (2.0*TRACKBALLSIZE); + + /* + * Avoid problems with out-of-control values... + */ + if (t > 1.0) t = 1.0; + if (t < -1.0) t = -1.0; + angle = inRadians(asin(t)); + +} + + +/* + * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet + * if we are away from the center of the sphere. + */ +float TrackballManipulator::tb_project_to_sphere(float r, float x, float y) +{ + float d, t, z; + + d = sqrt(x*x + y*y); + /* Inside sphere */ + if (d < r * 0.70710678118654752440) + { + z = sqrt(r*r - d*d); + } /* On hyperbola */ + else + { + t = r / 1.41421356237309504880; + z = t*t / d; + } + return z; +} diff --git a/src/osgGA/Version.cpp b/src/osgGA/Version.cpp new file mode 100644 index 000000000..691ac9747 --- /dev/null +++ b/src/osgGA/Version.cpp @@ -0,0 +1,12 @@ +#include + +const char* osgGAGetVersion() +{ + return "0.8.45"; +} + + +const char* osgGAGetLibraryName() +{ + return "Open Scene Graph Gui Adapter Library"; +} diff --git a/src/osgUtil/SceneView.cpp b/src/osgUtil/SceneView.cpp index 7823e06eb..0f9913ede 100644 --- a/src/osgUtil/SceneView.cpp +++ b/src/osgUtil/SceneView.cpp @@ -257,6 +257,12 @@ void SceneView::cull() cullStage(projectionRight.get(),modelviewRight.get(),_cullVisitorRight.get(),_rendergraphRight.get(),_renderStageRight.get()); +// if (_camera.valid()) +// { +// // clamp the camera to the near/far computed in cull traversal. +// _camera->setNearFar(_cullVisitorRight->getCalculatedNearPlane(),_cullVisitorRight->getCalculatedFarPlane()); +// } + } else { @@ -278,8 +284,15 @@ void SceneView::cull() _cullVisitor->setTraversalMask(_cullMask); cullStage(projection.get(),modelview.get(),_cullVisitor.get(),_rendergraph.get(),_renderStage.get()); + +// if (_camera.valid()) +// { +// // clamp the camera to the near/far computed in cull traversal. +// _camera->setNearFar(_cullVisitor->getCalculatedNearPlane(),_cullVisitor->getCalculatedFarPlane()); +// } } + } void SceneView::cullStage(osg::Matrix* projection,osg::Matrix* modelview,osgUtil::CullVisitor* cullVisitor, osgUtil::RenderGraph* rendergraph, osgUtil::RenderStage* renderStage)