]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/CanvasElement.cxx
Jenkins has some problems with bind and lambdas. Let's try it with ordinary function...
[simgear.git] / simgear / canvas / elements / CanvasElement.cxx
1 // Interface for 2D Canvas element
2 //
3 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Library General Public License for more details.
14 //
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
18
19 #include "CanvasElement.hxx"
20 #include <simgear/canvas/MouseEvent.hxx>
21
22 #include <osg/Drawable>
23 #include <osg/Geode>
24
25 #include <boost/foreach.hpp>
26
27 #include <cassert>
28 #include <cstring>
29
30 namespace simgear
31 {
32 namespace canvas
33 {
34   const std::string NAME_TRANSFORM = "tf";
35
36   //----------------------------------------------------------------------------
37   void Element::removeListener()
38   {
39     _node->removeChangeListener(this);
40   }
41
42   //----------------------------------------------------------------------------
43   Element::~Element()
44   {
45     removeListener();
46
47     BOOST_FOREACH(osg::Group* parent, _transform->getParents())
48     {
49       parent->removeChild(_transform);
50     }
51   }
52
53   //----------------------------------------------------------------------------
54   void Element::update(double dt)
55   {
56     if( !_transform->getNodeMask() )
57       // Don't do anything if element is hidden
58       return;
59
60     if( _transform_dirty )
61     {
62       osg::Matrix m;
63       for( size_t i = 0; i < _transform_types.size(); ++i )
64       {
65         // Skip unused indizes...
66         if( _transform_types[i] == TT_NONE )
67           continue;
68
69         SGPropertyNode* tf_node = _node->getChild("tf", i, true);
70
71         // Build up the matrix representation of the current transform node
72         osg::Matrix tf;
73         switch( _transform_types[i] )
74         {
75           case TT_MATRIX:
76             tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1),
77                               tf_node->getDoubleValue("m[1]", 0), 0, 0,
78
79                               tf_node->getDoubleValue("m[2]", 0),
80                               tf_node->getDoubleValue("m[3]", 1), 0, 0,
81
82                               0,    0,    1, 0,
83                               tf_node->getDoubleValue("m[4]", 0),
84                               tf_node->getDoubleValue("m[5]", 0), 0, 1 );
85             break;
86           case TT_TRANSLATE:
87             tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0),
88                                           tf_node->getDoubleValue("t[1]", 0),
89                                           0 ) );
90             break;
91           case TT_ROTATE:
92             tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 );
93             break;
94           case TT_SCALE:
95           {
96             float sx = tf_node->getDoubleValue("s[0]", 1);
97             // sy defaults to sx...
98             tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 );
99             break;
100           }
101           default:
102             break;
103         }
104         m.postMult( tf );
105       }
106       _transform->setMatrix(m);
107       _transform_dirty = false;
108     }
109   }
110
111   //----------------------------------------------------------------------------
112   bool Element::handleMouseEvent(const MouseEvent& event)
113   {
114     // Transform event to local coordinates
115     const osg::Matrixd& m = _transform->getInverseMatrix();
116     MouseEvent local_event = event;
117     local_event.x = m(0, 0) * event.x + m(1, 0) * event.y + m(3, 0);
118     local_event.y = m(0, 1) * event.x + m(1, 1) * event.y + m(3, 1);
119
120     // Drawables have a bounding box...
121     if( _drawable )
122     {
123       if( !_drawable->getBound().contains(local_event.getPos3()) )
124         return false;
125     }
126     // ... for other elements, i.e. groups only a bounding sphere is available
127     else if( !_transform->getBound().contains(local_event.getPos3()) )
128       return false;
129
130     local_event.dx = m(0, 0) * event.dx + m(1, 0) * event.dy;
131     local_event.dy = m(0, 1) * event.dx + m(1, 1) * event.dy;
132
133     return handleLocalMouseEvent(local_event);
134   }
135
136   //----------------------------------------------------------------------------
137   osg::ref_ptr<osg::MatrixTransform> Element::getMatrixTransform()
138   {
139     return _transform;
140   }
141
142   //----------------------------------------------------------------------------
143   void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
144   {
145     if(    parent == _node
146         && child->getNameString() == NAME_TRANSFORM )
147     {
148       if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
149         _transform_types.resize( child->getIndex() + 1 );
150
151       _transform_types[ child->getIndex() ] = TT_NONE;
152       _transform_dirty = true;
153       return;
154     }
155     else if(    parent->getParent() == _node
156              && parent->getNameString() == NAME_TRANSFORM )
157     {
158       assert(parent->getIndex() < static_cast<int>(_transform_types.size()));
159
160       const std::string& name = child->getNameString();
161
162       TransformType& type = _transform_types[parent->getIndex()];
163
164       if(      name == "m" )
165         type = TT_MATRIX;
166       else if( name == "t" )
167         type = TT_TRANSLATE;
168       else if( name == "rot" )
169         type = TT_ROTATE;
170       else if( name == "s" )
171         type = TT_SCALE;
172
173       _transform_dirty = true;
174       return;
175     }
176
177     childAdded(child);
178   }
179
180   //----------------------------------------------------------------------------
181   void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
182   {
183     if( parent == _node && child->getNameString() == NAME_TRANSFORM )
184     {
185       assert(child->getIndex() < static_cast<int>(_transform_types.size()));
186       _transform_types[ child->getIndex() ] = TT_NONE;
187
188       while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
189         _transform_types.pop_back();
190
191       _transform_dirty = true;
192       return;
193     }
194
195     childRemoved(child);
196   }
197
198   //----------------------------------------------------------------------------
199   void Element::valueChanged(SGPropertyNode* child)
200   {
201     SGPropertyNode *parent = child->getParent();
202     if( parent == _node )
203     {
204       if( setStyle(child) )
205         return;
206       else if( child->getNameString() == "update" )
207         return update(0);
208       else if( child->getNameString() == "visible" )
209         // TODO check if we need another nodemask
210         return _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 );
211     }
212     else if(   parent->getParent() == _node
213             && parent->getNameString() == NAME_TRANSFORM )
214     {
215       _transform_dirty = true;
216       return;
217     }
218
219     childChanged(child);
220   }
221
222   //----------------------------------------------------------------------------
223   void Element::setBoundingBox(const osg::BoundingBox& bb)
224   {
225     if( _bounding_box.empty() )
226     {
227       SGPropertyNode* bb_node = _node->getChild("bounding-box", 0, true);
228       _bounding_box.resize(4);
229       _bounding_box[0] = bb_node->getChild("min-x", 0, true);
230       _bounding_box[1] = bb_node->getChild("min-y", 0, true);
231       _bounding_box[2] = bb_node->getChild("max-x", 0, true);
232       _bounding_box[3] = bb_node->getChild("max-y", 0, true);
233     }
234
235     _bounding_box[0]->setFloatValue(bb._min.x());
236     _bounding_box[1]->setFloatValue(bb._min.y());
237     _bounding_box[2]->setFloatValue(bb._max.x());
238     _bounding_box[3]->setFloatValue(bb._max.y());
239   }
240
241   //----------------------------------------------------------------------------
242   Element::Element( const CanvasWeakPtr& canvas,
243                     const SGPropertyNode_ptr& node,
244                     const Style& parent_style ):
245     _canvas( canvas ),
246     _transform_dirty( false ),
247     _transform( new osg::MatrixTransform ),
248     _node( node ),
249     _style( parent_style ),
250     _drawable( 0 )
251   {
252     assert( _node );
253     _node->addChangeListener(this);
254
255     SG_LOG
256     (
257       SG_GL,
258       SG_DEBUG,
259       "New canvas element " << node->getPath()
260     );
261   }
262
263   //----------------------------------------------------------------------------
264   bool Element::handleLocalMouseEvent(const MouseEvent& event)
265   {
266 //    std::cout << _node->getPath()
267 //              << " local: pos=(" << event.x << "|" << event.y << ") "
268 //              <<         "d=(" << event.dx << "|" << event.dx << ")"
269 //              << std::endl;
270     return true;
271   }
272
273   //----------------------------------------------------------------------------
274   void Element::setDrawable( osg::Drawable* drawable )
275   {
276     _drawable = drawable;
277     assert( _drawable );
278
279     osg::ref_ptr<osg::Geode> geode = new osg::Geode;
280     geode->addDrawable(_drawable);
281     _transform->addChild(geode);
282   }
283
284   //----------------------------------------------------------------------------
285   void Element::setupStyle()
286   {
287     BOOST_FOREACH( Style::value_type style, _style )
288       setStyle(style.second);
289   }
290
291   //----------------------------------------------------------------------------
292   bool Element::setStyle(const SGPropertyNode* child)
293   {
294     StyleSetters::const_iterator setter =
295       _style_setters.find(child->getNameString());
296     if( setter == _style_setters.end() )
297       return false;
298
299     setter->second(child);
300     return true;
301   }
302
303 } // namespace canvas
304 } // namespace simgear