diff --git a/include/osg/BlendFunc b/include/osg/BlendFunc index 611cfb241..79ffc8cd5 100644 --- a/include/osg/BlendFunc +++ b/include/osg/BlendFunc @@ -35,7 +35,34 @@ namespace osg { -/** Encapsulates OpenGL blend/transparency state. */ +/** Encapsulates OpenGL blend/transparency state. + * + * Blending combines incoming fragment with a fragment + * already present in the target buffer. + * + * OpenGL 1.1 supports following source and destination blending factors: + * GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + * GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, + * GL_ZERO, GL_ONE. + * + * Moreover, there are three source-only blending factors: + * GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA_SATURATE + * and two destination-only blending factors: + * GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR. + * OpenGL 1.4 allowed to use these five blending factors + * as both - source and destination blending factors. + * + * Following four source and destination blending factors + * were added by Imaging subset of OpenGL 1.2 + * and made mandatory by OpenGL 1.4: + * GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, + * GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA + * + * OpenGL 1.4 further provides glBlendFuncSeparate + * (promoted from GL_EXT_blend_func_separate). + * It makes possible to set blending functions for RGB and Alpha separately. + * Before, it was possible to set just one blending function for RGBA. + */ class OSG_EXPORT BlendFunc : public StateAttribute { public : diff --git a/include/osg/Vec3d b/include/osg/Vec3d index 7ec50a7ca..4d313f074 100644 --- a/include/osg/Vec3d +++ b/include/osg/Vec3d @@ -188,6 +188,7 @@ class Vec3d /** Normalize the vector so that it has length unity. * Returns the previous length of the vector. + * If the vector is zero length, it is left unchanged and zero is returned. */ inline value_type normalize() { diff --git a/include/osgGA/OrbitManipulator b/include/osgGA/OrbitManipulator index 5584f50bb..b6a31699b 100644 --- a/include/osgGA/OrbitManipulator +++ b/include/osgGA/OrbitManipulator @@ -50,6 +50,11 @@ class OSGGA_EXPORT OrbitManipulator : public StandardManipulator virtual void getTransformation( osg::Vec3d& eye, osg::Quat& rotation ) const; virtual void getTransformation( osg::Vec3d& center, osg::Vec3d& eye, osg::Vec3d& up ) const; + void setHeading( double azimuth ); + double getHeading() const; + void setElevation( double elevation ); + double getElevation() const; + virtual void setCenter( const osg::Vec3d& center ); const osg::Vec3d& getCenter() const; virtual void setRotation( const osg::Quat& rotation ); diff --git a/include/osgGA/StandardManipulator b/include/osgGA/StandardManipulator index 4b7709c9a..5a17eeac0 100644 --- a/include/osgGA/StandardManipulator +++ b/include/osgGA/StandardManipulator @@ -39,7 +39,7 @@ class OSGGA_EXPORT StandardManipulator : public CameraManipulator UPDATE_MODEL_SIZE = 0x01, COMPUTE_HOME_USING_BBOX = 0x02, PROCESS_MOUSE_WHEEL = 0x04, - SET_CENTER_ON_WHEEL_UP = 0x08, + SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT = 0x08, DEFAULT_SETTINGS = UPDATE_MODEL_SIZE | COMPUTE_HOME_USING_BBOX | PROCESS_MOUSE_WHEEL }; @@ -62,6 +62,8 @@ class OSGGA_EXPORT StandardManipulator : public CameraManipulator virtual void setVerticalAxisFixed( bool value ); inline bool getVerticalAxisFixed() const; + inline bool getAllowThrow() const; + virtual void setAllowThrow( bool allowThrow ); virtual void setAnimationTime( const double t ); double getAnimationTime() const; @@ -113,6 +115,7 @@ class OSGGA_EXPORT StandardManipulator : public CameraManipulator // mouse state bool _thrown; + bool _allowThrow; float _mouseCenterX, _mouseCenterY; // internal event stack comprising last two mouse events. @@ -181,6 +184,12 @@ inline bool StandardManipulator::getVerticalAxisFixed() const return _verticalAxisFixed; } +/// Returns true if the camera can be thrown, false otherwise. It defaults to true. +inline bool StandardManipulator::getAllowThrow() const +{ + return _allowThrow; +} + } diff --git a/src/osgGA/FirstPersonManipulator.cpp b/src/osgGA/FirstPersonManipulator.cpp index 8602ac34d..86483f03d 100644 --- a/src/osgGA/FirstPersonManipulator.cpp +++ b/src/osgGA/FirstPersonManipulator.cpp @@ -37,7 +37,7 @@ FirstPersonManipulator::FirstPersonManipulator( int flags ) setAcceleration( 0.25, true ); setMaxVelocity( 0.25, true ); setWheelMovement( 0.05, true ); - if( _flags & SET_CENTER_ON_WHEEL_UP ) + if( _flags & SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT ) setAnimationTime( 0.2 ); } @@ -233,50 +233,62 @@ void FirstPersonManipulator::init( const GUIEventAdapter& ea, GUIActionAdapter& // doc in parent bool FirstPersonManipulator::handleMouseWheel( const GUIEventAdapter& ea, GUIActionAdapter& us ) { - switch( ea.getScrollingMotion() ) { + osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion(); - // mouse scroll up event - case GUIEventAdapter::SCROLL_UP: { + // handle centering + if( _flags & SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT ) + { - if( _flags & SET_CENTER_ON_WHEEL_UP ) { + if( sm == GUIEventAdapter::SCROLL_DOWN && _wheelMovement > 0. || + sm == GUIEventAdapter::SCROLL_UP && _wheelMovement < 0. ) + { // stop thrown animation _thrown = false; if( getAnimationTime() <= 0. ) - // center by mouse intersection (no animation) - setCenterByMousePointerIntersection( ea, us ); + // center by mouse intersection (no animation) + setCenterByMousePointerIntersection( ea, us ); else { - // start new animation only if there is no animation in progress - if( !isAnimating() ) - startAnimationByMousePointerIntersection( ea, us ); + // start new animation only if there is no animation in progress + if( !isAnimating() ) + startAnimationByMousePointerIntersection( ea, us ); } - } + } + } - // move forward - moveForward( isAnimating() ? dynamic_cast< FirstPersonAnimationData* >( _animationData.get() )->_targetRot : _rotation, - _wheelMovement * (getRelativeFlag( _wheelMovementFlagIndex ) ? _modelSize : 1. )); - us.requestRedraw(); - us.requestContinuousUpdate( isAnimating() || _thrown ); - return true; - } + switch( sm ) { - // mouse scroll down event - case GUIEventAdapter::SCROLL_DOWN: - moveForward( -_wheelMovement * (getRelativeFlag( _wheelMovementFlagIndex ) ? _modelSize : 1. )); - _thrown = false; - us.requestRedraw(); - us.requestContinuousUpdate( isAnimating() || _thrown ); - return true; + // mouse scroll up event + case GUIEventAdapter::SCROLL_UP: + { + // move forward + moveForward( isAnimating() ? dynamic_cast< FirstPersonAnimationData* >( _animationData.get() )->_targetRot : _rotation, + -_wheelMovement * (getRelativeFlag( _wheelMovementFlagIndex ) ? _modelSize : 1. )); + us.requestRedraw(); + us.requestContinuousUpdate( isAnimating() || _thrown ); + return true; + } - // unhandled mouse scrolling motion - default: - return false; - } + // mouse scroll down event + case GUIEventAdapter::SCROLL_DOWN: + { + // move backward + moveForward( _wheelMovement * (getRelativeFlag( _wheelMovementFlagIndex ) ? _modelSize : 1. )); + _thrown = false; + us.requestRedraw(); + us.requestContinuousUpdate( isAnimating() || _thrown ); + return true; + } + + // unhandled mouse scrolling motion + default: + return false; + } } diff --git a/src/osgGA/FlightManipulator.cpp b/src/osgGA/FlightManipulator.cpp index ffaf3ed8d..7509a24c9 100644 --- a/src/osgGA/FlightManipulator.cpp +++ b/src/osgGA/FlightManipulator.cpp @@ -114,6 +114,7 @@ bool FlightManipulator::handleKeyDown( const GUIEventAdapter& ea, GUIActionAdapt } +/// General flight-style event handler bool FlightManipulator::flightHandleEvent( const GUIEventAdapter& ea, GUIActionAdapter& us ) { addMouseEvent( ea ); diff --git a/src/osgGA/OrbitManipulator.cpp b/src/osgGA/OrbitManipulator.cpp index 0624f1b90..8af5ad610 100644 --- a/src/osgGA/OrbitManipulator.cpp +++ b/src/osgGA/OrbitManipulator.cpp @@ -36,7 +36,7 @@ OrbitManipulator::OrbitManipulator( int flags ) { setMinimumDistance( 0.05, true ); setWheelZoomFactor( 0.1 ); - if( _flags & SET_CENTER_ON_WHEEL_UP ) + if( _flags & SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT ) setAnimationTime( 0.2 ); } @@ -148,34 +148,108 @@ void OrbitManipulator::getTransformation( osg::Vec3d& center, osg::Vec3d& eye, o } +/** Sets the transformation by heading. Heading is given as an angle in radians giving a azimuth in xy plane. + Its meaning is similar to longitude used in cartography and navigation. + Positive number is going to the east direction.*/ +void OrbitManipulator::setHeading( double azimuth ) +{ + CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); + Vec3d localUp = getUpVector( coordinateFrame ); + Vec3d localRight = getSideVector( coordinateFrame ); + + Vec3d dir = Quat( getElevation(), localRight ) * Quat( azimuth, localUp ) * Vec3d( 0., -_distance, 0. ); + + setTransformation( _center, _center + dir, localUp ); +} + + +/// Returns the heading in radians. \sa setHeading +double OrbitManipulator::getHeading() const +{ + CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); + Vec3d localFront = getFrontVector( coordinateFrame ); + Vec3d localRight = getSideVector( coordinateFrame ); + + Vec3d center, eye, tmp; + getTransformation( center, eye, tmp ); + + Plane frontPlane( localFront, center ); + double frontDist = frontPlane.distance( eye ); + Plane rightPlane( localRight, center ); + double rightDist = rightPlane.distance( eye ); + + return atan2( rightDist, -frontDist ); +} + + +/** Sets the transformation by elevation. Elevation is given as an angle in radians from xy plane. + Its meaning is similar to latitude used in cartography and navigation. + Positive number is going to the north direction, negative to the south.*/ +void OrbitManipulator::setElevation( double elevation ) +{ + CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); + Vec3d localUp = getUpVector( coordinateFrame ); + Vec3d localRight = getSideVector( coordinateFrame ); + + Vec3d dir = Quat( -elevation, localRight ) * Quat( getHeading(), localUp ) * Vec3d( 0., -_distance, 0. ); + + setTransformation( _center, _center + dir, localUp ); +} + + +/// Returns the elevation in radians. \sa setElevation +double OrbitManipulator::getElevation() const +{ + CoordinateFrame coordinateFrame = getCoordinateFrame( _center ); + Vec3d localUp = getUpVector( coordinateFrame ); + localUp.normalize(); + + Vec3d center, eye, tmp; + getTransformation( center, eye, tmp ); + + Plane plane( localUp, center ); + double dist = plane.distance( eye ); + + return asin( -dist / (eye-center).length() ); +} + + // doc in parent bool OrbitManipulator::handleMouseWheel( const GUIEventAdapter& ea, GUIActionAdapter& us ) { - switch( ea.getScrollingMotion() ) + osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion(); + + // handle centering + if( _flags & SET_CENTER_ON_WHEEL_FORWARD_MOVEMENT ) + { + + if( sm == GUIEventAdapter::SCROLL_DOWN && _wheelZoomFactor > 0. || + sm == GUIEventAdapter::SCROLL_UP && _wheelZoomFactor < 0. ) + { + + if( getAnimationTime() <= 0. ) + { + // center by mouse intersection (no animation) + setCenterByMousePointerIntersection( ea, us ); + } + else + { + // start new animation only if there is no animation in progress + if( !isAnimating() ) + startAnimationByMousePointerIntersection( ea, us ); + + } + + } + } + + switch( sm ) { // mouse scroll up event case GUIEventAdapter::SCROLL_UP: { - - if( _flags & SET_CENTER_ON_WHEEL_UP ) - { - - if( getAnimationTime() <= 0. ) - { - // center by mouse intersection (no animation) - setCenterByMousePointerIntersection( ea, us ); - } - else - { - // start new animation only if there is no animation in progress - if( !isAnimating() ) - startAnimationByMousePointerIntersection( ea, us ); - - } - } - // perform zoom - zoomModel( -_wheelZoomFactor, true ); + zoomModel( _wheelZoomFactor, true ); us.requestRedraw(); us.requestContinuousUpdate( isAnimating() || _thrown ); return true; @@ -183,10 +257,13 @@ bool OrbitManipulator::handleMouseWheel( const GUIEventAdapter& ea, GUIActionAda // mouse scroll down event case GUIEventAdapter::SCROLL_DOWN: - zoomModel( _wheelZoomFactor, true ); + { + // perform zoom + zoomModel( -_wheelZoomFactor, true ); us.requestRedraw(); us.requestContinuousUpdate( false ); return true; + } // unhandled mouse scrolling motion default: @@ -530,7 +607,8 @@ void OrbitManipulator::setTrackballSize( const double& size ) /** Set the mouse wheel zoom factor. The amount of camera movement on each mouse wheel event is computed as the current distance to the center multiplied by this factor. - For example, value of 0.1 will short distance to center by 10% on each wheel up event.*/ + For example, value of 0.1 will short distance to center by 10% on each wheel up event. + Use negative value for reverse mouse wheel direction.*/ void OrbitManipulator::setWheelZoomFactor( double wheelZoomFactor ) { _wheelZoomFactor = wheelZoomFactor; diff --git a/src/osgGA/StandardManipulator.cpp b/src/osgGA/StandardManipulator.cpp index 742bc9901..ad1d8370c 100644 --- a/src/osgGA/StandardManipulator.cpp +++ b/src/osgGA/StandardManipulator.cpp @@ -25,16 +25,16 @@ using namespace osgUtil; -/** \fn void StandardManipulator::setTransformation( const osg::Vec3d& eye, const osg::Quat& rotation ); +/** \fn void StandardManipulator::setTransformation( const osg::Vec3d& eye, const osg::Quat& rotation ) Sets manipulator by eye position and eye orientation.*/ -/** \fn void StandardManipulator::setTransformation( const osg::Vec3d& center, const osg::Vec3d& eye, const osg::Vec3d& up ); +/** \fn void StandardManipulator::setTransformation( const osg::Vec3d& center, const osg::Vec3d& eye, const osg::Vec3d& up ) Sets manipulator by focal center, eye position, and up vector.*/ -/** \fn void StandardManipulator::getTransformation( osg::Vec3d& eye, osg::Quat& rotation ); +/** \fn void StandardManipulator::getTransformation( osg::Vec3d& eye, osg::Quat& rotation ) Gets manipulator's eye position and eye orientation.*/ -/** \fn void StandardManipulator::getTransformation( osg::Vec3d& center, osg::Vec3d& eye, osg::Vec3d& up ); +/** \fn void StandardManipulator::getTransformation( osg::Vec3d& center, osg::Vec3d& eye, osg::Vec3d& up ) Gets manipulator's focal center, eye position, and up vector.*/ @@ -51,6 +51,7 @@ int StandardManipulator::allocateRelativeFlag() StandardManipulator::StandardManipulator( int flags ) : inherited(), _thrown( false ), + _allowThrow( true ), _mouseCenterX(0.0f), _mouseCenterY(0.0f), _delta_frame_time(0.01), _last_frame_time(0.0), _modelSize( 0. ), @@ -65,6 +66,7 @@ StandardManipulator::StandardManipulator( int flags ) StandardManipulator::StandardManipulator( const StandardManipulator& uim, const CopyOp& copyOp ) : inherited( uim, copyOp ), _thrown( uim._thrown ), + _allowThrow( uim._allowThrow ), _mouseCenterX(0.0f), _mouseCenterY(0.0f), _ga_t1( dynamic_cast< GUIEventAdapter* >( copyOp( uim._ga_t1.get() ) ) ), _ga_t0( dynamic_cast< GUIEventAdapter* >( copyOp( uim._ga_t0.get() ) ) ), @@ -364,7 +366,7 @@ bool StandardManipulator::handleMouseRelease( const GUIEventAdapter& ea, GUIActi if( isMouseMoving() ) { - if( performMovement() ) + if( performMovement() && _allowThrow ) { us.requestRedraw(); us.requestContinuousUpdate( true ); @@ -583,6 +585,15 @@ bool StandardManipulator::isMouseMoving() const } +/** Set the 'allow throw' flag. If it is set to true (default), releasing the mouse button + while moving the mouse results in a throw. If manipulator was thrown, it continues spinning + although no mouse button is down at the moment.*/ +void StandardManipulator::setAllowThrow( bool allowThrow ) +{ + _allowThrow = allowThrow; +} + + /** Returns the scale that should be applied on animation of "thrown" manipulator state to avoid its dependency on varying frame rate. diff --git a/src/osgGA/TerrainManipulator.cpp b/src/osgGA/TerrainManipulator.cpp index 53730632d..37a9c8348 100644 --- a/src/osgGA/TerrainManipulator.cpp +++ b/src/osgGA/TerrainManipulator.cpp @@ -35,12 +35,16 @@ TerrainManipulator::TerrainManipulator( const TerrainManipulator& tm, const Copy } +/** Sets the manipulator rotation mode. RotationMode is now deprecated by + osgGA::StandardManipulator::setVerticalAxisFixed() functionality, + that is used across StandardManipulator derived classes.*/ void TerrainManipulator::setRotationMode( TerrainManipulator::RotationMode mode ) { setVerticalAxisFixed( mode == ELEVATION_AZIM ); } +/** Returns the manipulator rotation mode.*/ TerrainManipulator::RotationMode TerrainManipulator::getRotationMode() const { return getVerticalAxisFixed() ? ELEVATION_AZIM : ELEVATION_AZIM_ROLL;