Files
simgear/simgear/canvas/CanvasObjectPlacement.cxx
T

248 lines
7.2 KiB
C++

///@file
/// 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 <simgear_config.h>
#include "Canvas.hxx"
#include "CanvasObjectPlacement.hxx"
#include <simgear/canvas/events/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