]> git.mxchange.org Git - simgear.git/commitdiff
Extend SGPickCallback to allow passing more information to callbacks
authorThomas Geymayer <tomgey@gmail.com>
Thu, 9 May 2013 19:31:27 +0000 (21:31 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Thu, 9 May 2013 19:31:27 +0000 (21:31 +0200)
simgear/canvas/CMakeLists.txt
simgear/canvas/CanvasObjectPlacement.cxx [new file with mode: 0644]
simgear/canvas/CanvasObjectPlacement.hxx [new file with mode: 0644]
simgear/canvas/MouseEvent.hxx
simgear/scene/model/SGPickAnimation.cxx
simgear/scene/util/SGPickCallback.hxx

index be1a44ff18028e4b24357990a03c95b58675b593..644f62afe285f9bb7a2fecc75d516130d1d6d4f3 100644 (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
diff --git a/simgear/canvas/CanvasObjectPlacement.cxx b/simgear/canvas/CanvasObjectPlacement.cxx
new file mode 100644 (file)
index 0000000..fc0b738
--- /dev/null
@@ -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
diff --git a/simgear/canvas/CanvasObjectPlacement.hxx b/simgear/canvas/CanvasObjectPlacement.hxx
new file mode 100644 (file)
index 0000000..40c0550
--- /dev/null
@@ -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_ */
index 5bbfb99334e8412423ef94f431d83e1172d750be..c84fcd2757a76dad955eac8b095b70834a301d1b 100644 (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; }
index 9c2ff4fbcb08c2f533bd45880d5027e5ca18dcc9..dd10a9c805395241ffc3b3472cfc5ff6660bf2c4 100644 (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;
index 838d5b2e45e9ec5ed3ada84aec8d9c9bf8c2eae7..c41bce7233e8878e3510a5e64cd7c4c16601f1ea 100644 (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 )
+  { }
+
+  /**
+   * @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 void mouseMoved(const osgGA::GUIEventAdapter* event)
+  /**
+   * 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)
+  virtual bool hover( const osg::Vec2d& windowPos,
+                      const Info& info )
   {  return false; }
 
   virtual Priority getPriority() const