]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/CanvasObjectPlacement.cxx
Update for OpenSceneGraph 3.3.2 API changes.
[simgear.git] / simgear / canvas / CanvasObjectPlacement.cxx
1 // Canvas placement for placing a canvas texture onto osg objects.
2 //
3 // It also provides a SGPickCallback for passing mouse events to the canvas and
4 // manages emissive lighting of the placed canvas.
5 //
6 // Copyright (C) 2013  Thomas Geymayer <tomgey@gmail.com>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
21
22 #include "Canvas.hxx"
23 #include "CanvasObjectPlacement.hxx"
24 #include <simgear/canvas/events/MouseEvent.hxx>
25
26 #include <simgear/props/props.hxx>
27 #include <simgear/scene/util/SGPickCallback.hxx>
28
29 #include <osgGA/GUIEventAdapter>
30
31 namespace simgear
32 {
33 namespace canvas
34 {
35
36   /**
37    * Handle picking events on object with a canvas placed onto
38    */
39   class ObjectPickCallback:
40     public SGPickCallback
41   {
42     public:
43
44       ObjectPickCallback(const CanvasWeakPtr& canvas):
45         _canvas(canvas)
46       {}
47
48       virtual bool needsUV() const { return true; }
49
50       virtual bool buttonPressed( int,
51                                   const osgGA::GUIEventAdapter& ea,
52                                   const Info& info )
53       {
54         MouseEventPtr event(new MouseEvent(ea));
55         updatePosFromUV(event, info.uv);
56
57         if( ea.getEventType() == osgGA::GUIEventAdapter::SCROLL )
58         {
59           event->type = Event::WHEEL;
60           event->delta.set(0,0);
61           switch( ea.getScrollingMotion() )
62           {
63             case osgGA::GUIEventAdapter::SCROLL_UP:
64               event->delta.y() = 1;
65               break;
66             case osgGA::GUIEventAdapter::SCROLL_DOWN:
67               event->delta.y() = -1;
68               break;
69             default:
70               return false;
71           }
72         }
73         else
74         {
75           event->type = Event::MOUSE_DOWN;
76         }
77
78         return handleEvent(event);
79       }
80
81       virtual void buttonReleased( int,
82                                    const osgGA::GUIEventAdapter& ea,
83                                    const Info* info )
84       {
85         if( ea.getEventType() != osgGA::GUIEventAdapter::RELEASE )
86           return;
87
88         MouseEventPtr event(new MouseEvent(ea));
89         event->type = Event::MOUSE_UP;
90         updatePosFromUV(event, info ? info->uv : SGVec2d(-1,-1));
91
92         handleEvent(event);
93       }
94
95       virtual void mouseMoved( const osgGA::GUIEventAdapter& ea,
96                                const Info* info )
97       {
98         // drag (currently only with LMB)
99         if( ea.getEventType() != osgGA::GUIEventAdapter::DRAG )
100           return;
101
102         MouseEventPtr event(new MouseEvent(ea));
103         event->type = Event::DRAG;
104         updatePosFromUV(event, info ? info->uv : SGVec2d(-1,-1));
105
106         handleEvent(event);
107       }
108
109       virtual bool hover( const osg::Vec2d& windowPos,
110                           const Info& info )
111       {
112         // TODO somehow get more info about event (time, modifiers, pressed
113         // buttons, ...)
114         MouseEventPtr event(new MouseEvent);
115         event->type = Event::MOUSE_MOVE;
116         event->screen_pos = windowPos;
117         updatePosFromUV(event, info.uv);
118
119         return handleEvent(event);
120       }
121
122       virtual void mouseLeave( const osg::Vec2d& windowPos )
123       {
124         MouseEventPtr event(new MouseEvent);
125         event->type = Event::MOUSE_LEAVE;
126         event->screen_pos = windowPos;
127
128         handleEvent(event);
129       }
130
131     protected:
132       CanvasWeakPtr _canvas;
133       osg::Vec2f    _last_pos,
134                     _last_delta;
135
136       void updatePosFromUV(const MouseEventPtr& event, const SGVec2d& uv)
137       {
138         CanvasPtr canvas = _canvas.lock();
139         if( !canvas )
140           return;
141
142         osg::Vec2d pos( uv.x() * canvas->getViewWidth(),
143                         (1 - uv.y()) * canvas->getViewHeight() );
144
145         _last_delta = pos - _last_pos;
146         _last_pos = pos;
147
148         event->client_pos = pos;
149         event->delta = _last_delta;
150       }
151
152       bool handleEvent(const MouseEventPtr& event)
153       {
154         CanvasPtr canvas = _canvas.lock();
155         if( !canvas )
156           return false;
157
158         return canvas->handleMouseEvent(event);
159       }
160   };
161
162   //----------------------------------------------------------------------------
163   ObjectPlacement::ObjectPlacement( SGPropertyNode* node,
164                                     const GroupPtr& group,
165                                     const CanvasWeakPtr& canvas ):
166     Placement(node),
167     _group(group),
168     _canvas(canvas)
169   {
170     // TODO make more generic and extendable for more properties
171     if( node->hasValue("emission") )
172       setEmission( node->getFloatValue("emission") );
173     if( node->hasValue("capture-events") )
174       setCaptureEvents( node->getBoolValue("capture-events") );
175   }
176
177   //----------------------------------------------------------------------------
178   ObjectPlacement::~ObjectPlacement()
179   {
180     assert( _group->getNumChildren() == 1 );
181     osg::Node *child = _group->getChild(0);
182
183     if( _group->getNumParents() )
184     {
185       osg::Group *parent = _group->getParent(0);
186       parent->addChild(child);
187       parent->removeChild(_group);
188     }
189
190     _group->removeChild(child);
191   }
192
193   //----------------------------------------------------------------------------
194   void ObjectPlacement::setEmission(float emit)
195   {
196     emit = SGMiscf::clip(emit, 0, 1);
197
198     if( !_material )
199     {
200       _material = new osg::Material;
201       _material->setColorMode(osg::Material::OFF);
202       _material->setDataVariance(osg::Object::DYNAMIC);
203       _group->getOrCreateStateSet()
204             ->setAttribute(_material, ( osg::StateAttribute::ON
205                                       | osg::StateAttribute::OVERRIDE ) );
206     }
207
208     _material->setEmission(
209       osg::Material::FRONT_AND_BACK,
210       osg::Vec4(emit, emit, emit, emit)
211     );
212   }
213
214   //----------------------------------------------------------------------------
215   void ObjectPlacement::setCaptureEvents(bool enable)
216   {
217     if( !enable && _scene_user_data )
218       return;
219
220     if( enable && !_pick_cb )
221       _pick_cb = new ObjectPickCallback(_canvas);
222
223     _scene_user_data = SGSceneUserData::getOrCreateSceneUserData(_group);
224     _scene_user_data->setPickCallback(enable ? _pick_cb.get() : 0);
225   }
226
227   //----------------------------------------------------------------------------
228   bool ObjectPlacement::childChanged(SGPropertyNode* node)
229   {
230     if( node->getParent() != _node )
231       return false;
232
233     if( node->getNameString() == "emission" )
234       setEmission( node->getFloatValue() );
235     else if( node->getNameString() == "capture-events" )
236       setCaptureEvents( node->getBoolValue() );
237     else
238       return false;
239
240     return true;
241   }
242
243 } // namespace canvas
244 } // namespace simgear