Extend SGPickCallback to allow passing more information to callbacks

This commit is contained in:
Thomas Geymayer
2013-05-09 21:31:27 +02:00
parent 82f6fca06f
commit 9535aef59b
6 changed files with 388 additions and 21 deletions

View File

@@ -9,6 +9,7 @@ set(HEADERS
CanvasEventTypes.hxx
CanvasEventVisitor.hxx
CanvasMgr.hxx
CanvasObjectPlacement.hxx
CanvasPlacement.hxx
CanvasSystemAdapter.hxx
MouseEvent.hxx
@@ -23,6 +24,7 @@ set(SOURCES
CanvasEventManager.cxx
CanvasEventVisitor.cxx
CanvasMgr.cxx
CanvasObjectPlacement.cxx
CanvasPlacement.cxx
ODGauge.cxx
VGInitOperation.cxx

View File

@@ -0,0 +1,244 @@
// Canvas placement for placing a canvas texture onto osg objects.
//
// It also provides a SGPickCallback for passing mouse events to the canvas and
// manages emissive lighting of the placed canvas.
//
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "Canvas.hxx"
#include "CanvasObjectPlacement.hxx"
#include "MouseEvent.hxx"
#include <simgear/props/props.hxx>
#include <simgear/scene/util/SGPickCallback.hxx>
#include <osgGA/GUIEventAdapter>
namespace simgear
{
namespace canvas
{
/**
* Handle picking events on object with a canvas placed onto
*/
class ObjectPickCallback:
public SGPickCallback
{
public:
ObjectPickCallback(const CanvasWeakPtr& canvas):
_canvas(canvas)
{}
virtual bool needsUV() const { return true; }
virtual bool buttonPressed( int,
const osgGA::GUIEventAdapter& ea,
const Info& info )
{
MouseEventPtr event(new MouseEvent(ea));
updatePosFromUV(event, info.uv);
if( ea.getEventType() == osgGA::GUIEventAdapter::SCROLL )
{
event->type = Event::WHEEL;
event->delta.set(0,0);
switch( ea.getScrollingMotion() )
{
case osgGA::GUIEventAdapter::SCROLL_UP:
event->delta.y() = 1;
break;
case osgGA::GUIEventAdapter::SCROLL_DOWN:
event->delta.y() = -1;
break;
default:
return false;
}
}
else
{
event->type = Event::MOUSE_DOWN;
}
return handleEvent(event);
}
virtual void buttonReleased( int,
const osgGA::GUIEventAdapter& ea,
const Info* info )
{
if( ea.getEventType() != osgGA::GUIEventAdapter::RELEASE )
return;
MouseEventPtr event(new MouseEvent(ea));
event->type = Event::MOUSE_UP;
updatePosFromUV(event, info ? info->uv : SGVec2d(-1,-1));
handleEvent(event);
}
virtual void mouseMoved( const osgGA::GUIEventAdapter& ea,
const Info* info )
{
// drag (currently only with LMB)
if( ea.getEventType() != osgGA::GUIEventAdapter::DRAG )
return;
MouseEventPtr event(new MouseEvent(ea));
event->type = Event::DRAG;
updatePosFromUV(event, info ? info->uv : SGVec2d(-1,-1));
handleEvent(event);
}
virtual bool hover( const osg::Vec2d& windowPos,
const Info& info )
{
// TODO somehow get more info about event (time, modifiers, pressed
// buttons, ...)
MouseEventPtr event(new MouseEvent);
event->type = Event::MOUSE_MOVE;
event->screen_pos = windowPos;
updatePosFromUV(event, info.uv);
return handleEvent(event);
}
virtual void mouseLeave( const osg::Vec2d& windowPos )
{
MouseEventPtr event(new MouseEvent);
event->type = Event::MOUSE_LEAVE;
event->screen_pos = windowPos;
handleEvent(event);
}
protected:
CanvasWeakPtr _canvas;
osg::Vec2f _last_pos,
_last_delta;
void updatePosFromUV(const MouseEventPtr& event, const SGVec2d& uv)
{
CanvasPtr canvas = _canvas.lock();
if( !canvas )
return;
osg::Vec2d pos( uv.x() * canvas->getViewWidth(),
(1 - uv.y()) * canvas->getViewHeight() );
_last_delta = pos - _last_pos;
_last_pos = pos;
event->client_pos = pos;
event->delta = _last_delta;
}
bool handleEvent(const MouseEventPtr& event)
{
CanvasPtr canvas = _canvas.lock();
if( !canvas )
return false;
return canvas->handleMouseEvent(event);
}
};
//----------------------------------------------------------------------------
ObjectPlacement::ObjectPlacement( SGPropertyNode* node,
const GroupPtr& group,
const CanvasWeakPtr& canvas ):
Placement(node),
_group(group),
_canvas(canvas)
{
// TODO make more generic and extendable for more properties
if( node->hasValue("emission") )
setEmission( node->getFloatValue("emission") );
if( node->hasValue("capture-events") )
setCaptureEvents( node->getBoolValue("capture-events") );
}
//----------------------------------------------------------------------------
ObjectPlacement::~ObjectPlacement()
{
assert( _group->getNumChildren() == 1 );
osg::Node *child = _group->getChild(0);
if( _group->getNumParents() )
{
osg::Group *parent = _group->getParent(0);
parent->addChild(child);
parent->removeChild(_group);
}
_group->removeChild(child);
}
//----------------------------------------------------------------------------
void ObjectPlacement::setEmission(float emit)
{
emit = SGMiscf::clip(emit, 0, 1);
if( !_material )
{
_material = new osg::Material;
_material->setColorMode(osg::Material::OFF);
_material->setDataVariance(osg::Object::DYNAMIC);
_group->getOrCreateStateSet()
->setAttribute(_material, ( osg::StateAttribute::ON
| osg::StateAttribute::OVERRIDE ) );
}
_material->setEmission(
osg::Material::FRONT_AND_BACK,
osg::Vec4(emit, emit, emit, emit)
);
}
//----------------------------------------------------------------------------
void ObjectPlacement::setCaptureEvents(bool enable)
{
if( !enable && _scene_user_data )
return;
if( enable && !_pick_cb )
_pick_cb = new ObjectPickCallback(_canvas);
_scene_user_data = SGSceneUserData::getOrCreateSceneUserData(_group);
_scene_user_data->setPickCallback(enable ? _pick_cb.get() : 0);
}
//----------------------------------------------------------------------------
bool ObjectPlacement::childChanged(SGPropertyNode* node)
{
if( node->getParent() != _node )
return false;
if( node->getNameString() == "emission" )
setEmission( node->getFloatValue() );
else if( node->getNameString() == "capture-events" )
setCaptureEvents( node->getBoolValue() );
else
return false;
return true;
}
} // namespace canvas
} // namespace simgear

View File

@@ -0,0 +1,75 @@
// Canvas placement for placing a canvas texture onto osg objects.
//
// It also provides a SGPickCallback for passing mouse events to the canvas and
// manages emissive lighting of the placed canvas.
//
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef CANVAS_PICK_PLACEMENT_HXX_
#define CANVAS_OBJECT_PLACEMENT_HXX_
#include "CanvasPlacement.hxx"
#include "canvas_fwd.hxx"
#include <simgear/scene/util/SGSceneUserData.hxx>
#include <osg/Material>
namespace simgear
{
namespace canvas
{
class ObjectPlacement:
public Placement
{
public:
typedef osg::ref_ptr<osg::Group> GroupPtr;
typedef osg::ref_ptr<osg::Material> MaterialPtr;
ObjectPlacement( SGPropertyNode* node,
const GroupPtr& group,
const CanvasWeakPtr& canvas );
virtual ~ObjectPlacement();
/**
* Set emissive lighting of the object the canvas is placed on.
*/
void setEmission(float emit);
/**
* Set whether pick events should be captured.
*/
void setCaptureEvents(bool enable);
virtual bool childChanged(SGPropertyNode* child);
protected:
typedef SGSharedPtr<SGPickCallback> PickCallbackPtr;
typedef osg::ref_ptr<SGSceneUserData> SGSceneUserDataPtr;
GroupPtr _group;
MaterialPtr _material;
CanvasWeakPtr _canvas;
PickCallbackPtr _pick_cb;
SGSceneUserDataPtr _scene_user_data;
};
} // namespace canvas
} // namespace simgear
#endif /* CANVAS_PICK_PLACEMENT_HXX_ */

View File

@@ -38,6 +38,15 @@ namespace canvas
click_count(0)
{}
MouseEvent(const osgGA::GUIEventAdapter& ea):
button(ea.getButton()),
state(ea.getButtonMask()),
mod(ea.getModKeyMask()),
click_count(0)
{
time = ea.getTime();
}
osg::Vec2f getScreenPos() const { return screen_pos; }
osg::Vec2f getClientPos() const { return client_pos; }
osg::Vec2f getDelta() const { return delta; }

View File

@@ -54,17 +54,17 @@ static void readOptionalBindingList(const SGPropertyNode* aNode, SGPropertyNode*
}
osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter& ea)
{
using namespace osg;
const GraphicsContext* gc = ea->getGraphicsContext();
const GraphicsContext* gc = ea.getGraphicsContext();
const GraphicsContext::Traits* traits = gc->getTraits() ;
// Scale x, y to the dimensions of the window
double x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
double x = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
* (double)traits->width);
double y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
double y = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin()))
* (double)traits->height);
if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
if (ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
y = (double)traits->height - y;
return osg::Vec2d(x, y);
@@ -100,7 +100,9 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
_hover = readBindingList(hoverNode->getChildren("binding"), modelRoot);
}
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info&)
virtual bool buttonPressed( int button,
const osgGA::GUIEventAdapter&,
const Info& )
{
if (_buttons.find(button) == _buttons.end()) {
return false;
@@ -110,7 +112,9 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
_repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat
return true;
}
virtual void buttonReleased(int keyModState)
virtual void buttonReleased( int keyModState,
const osgGA::GUIEventAdapter&,
const Info* )
{
SG_UNUSED(keyModState);
fireBindingList(_bindingsUp);
@@ -129,7 +133,8 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
}
}
virtual bool hover(const osg::Vec2d& windowPos, const Info& info)
virtual bool hover( const osg::Vec2d& windowPos,
const Info& )
{
if (_hover.empty()) {
return false;
@@ -256,7 +261,9 @@ public:
_squaredDown = dot(_toDown, _toDown);
}
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info& info)
virtual bool buttonPressed( int button,
const osgGA::GUIEventAdapter&,
const Info& info )
{
SGVec3d loc(info.local);
SG_LOG(SG_INPUT, SG_DEBUG, "VNC pressed " << button << ": " << loc);
@@ -270,7 +277,9 @@ public:
return vv.wasSuccessful();
}
virtual void buttonReleased(int keyModState)
virtual void buttonReleased( int keyModState,
const osgGA::GUIEventAdapter&,
const Info* )
{
SG_UNUSED(keyModState);
SG_LOG(SG_INPUT, SG_DEBUG, "VNC release");
@@ -544,11 +553,13 @@ public:
}
}
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info&)
virtual bool buttonPressed( int button,
const osgGA::GUIEventAdapter& ea,
const Info& )
{
// the 'be nice to Mac / laptop' users option; alt-clicking spins the
// opposite direction. Should make this configurable
if ((button == 0) && (ea->getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_ALT)) {
if ((button == 0) && (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_ALT)) {
button = 1;
}
@@ -571,7 +582,9 @@ public:
return true;
}
virtual void buttonReleased(int keyModState)
virtual void buttonReleased( int keyModState,
const osgGA::GUIEventAdapter&,
const Info* )
{
// for *clicks*, we only fire on button release
if (!_hasDragged) {
@@ -592,7 +605,8 @@ public:
return _dragDirection;
}
virtual void mouseMoved(const osgGA::GUIEventAdapter* ea)
virtual void mouseMoved( const osgGA::GUIEventAdapter& ea,
const Info* )
{
_mousePos = eventToWindowCoords(ea);
osg::Vec2d deltaMouse = _mousePos - _lastFirePos;
@@ -618,7 +632,7 @@ public:
if (fabs(delta) >= 1.0) {
// determine direction from sign of delta
Direction dir = (delta > 0.0) ? DIRECTION_INCREASE : DIRECTION_DECREASE;
fire(ea->getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_SHIFT, dir);
fire(ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_SHIFT, dir);
_lastFirePos = _mousePos;
}
}
@@ -636,7 +650,8 @@ public:
} // of repeat iteration
}
virtual bool hover(const osg::Vec2d& windowPos, const Info& info)
virtual bool hover( const osg::Vec2d& windowPos,
const Info& )
{
if (_hover.empty()) {
return false;

View File

@@ -52,19 +52,41 @@ public:
{ }
virtual ~SGPickCallback() {}
virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* event, const Info& info)
// TODO maybe better provide a single callback to handle all events
virtual bool buttonPressed( int button,
const osgGA::GUIEventAdapter& ea,
const Info& info )
{ return false; }
virtual void update(double dt, int keyModState)
{ }
virtual void buttonReleased(int keyModState)
/**
* @param info Can be null if no info is available (eg. mouse not over 3d
* object anymore)
*/
virtual void buttonReleased( int keyModState,
const osgGA::GUIEventAdapter& ea,
const Info* info )
{ }
virtual void mouseMoved(const osgGA::GUIEventAdapter* event)
/**
* @param info Can be null if no info is available (eg. mouse not over 3d
* object anymore)
*/
virtual void mouseMoved( const osgGA::GUIEventAdapter& ea,
const Info* info )
{ }
virtual bool hover(const osg::Vec2d& windowPos, const Info& info)
/**
* The mouse is not hovering anymore over the element.
*/
virtual void mouseLeave(const osg::Vec2d& windowPos)
{ }
virtual bool hover( const osg::Vec2d& windowPos,
const Info& info )
{ return false; }
virtual Priority getPriority() const