]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/CanvasElement.cxx
Nasal bindings: Always pass object by reference
[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   SGConstPropertyNode_ptr Element::getProps() const
113   {
114     return _node;
115   }
116
117   //----------------------------------------------------------------------------
118   SGPropertyNode_ptr Element::getProps()
119   {
120     return  _node;
121   }
122
123   //----------------------------------------------------------------------------
124   bool Element::handleMouseEvent(const MouseEvent& event)
125   {
126     // Transform event to local coordinates
127     const osg::Matrixd& m = _transform->getInverseMatrix();
128     MouseEvent local_event = event;
129     local_event.x = m(0, 0) * event.x + m(1, 0) * event.y + m(3, 0);
130     local_event.y = m(0, 1) * event.x + m(1, 1) * event.y + m(3, 1);
131
132     // Drawables have a bounding box...
133     if( _drawable )
134     {
135       if( !_drawable->getBound().contains(local_event.getPos3()) )
136         return false;
137     }
138     // ... for other elements, i.e. groups only a bounding sphere is available
139     else if( !_transform->getBound().contains(local_event.getPos3()) )
140       return false;
141
142     local_event.dx = m(0, 0) * event.dx + m(1, 0) * event.dy;
143     local_event.dy = m(0, 1) * event.dx + m(1, 1) * event.dy;
144
145     return handleLocalMouseEvent(local_event);
146   }
147
148   //----------------------------------------------------------------------------
149   osg::ref_ptr<osg::MatrixTransform> Element::getMatrixTransform()
150   {
151     return _transform;
152   }
153
154   //----------------------------------------------------------------------------
155   void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
156   {
157     if(    parent == _node
158         && child->getNameString() == NAME_TRANSFORM )
159     {
160       if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
161         _transform_types.resize( child->getIndex() + 1 );
162
163       _transform_types[ child->getIndex() ] = TT_NONE;
164       _transform_dirty = true;
165       return;
166     }
167     else if(    parent->getParent() == _node
168              && parent->getNameString() == NAME_TRANSFORM )
169     {
170       assert(parent->getIndex() < static_cast<int>(_transform_types.size()));
171
172       const std::string& name = child->getNameString();
173
174       TransformType& type = _transform_types[parent->getIndex()];
175
176       if(      name == "m" )
177         type = TT_MATRIX;
178       else if( name == "t" )
179         type = TT_TRANSLATE;
180       else if( name == "rot" )
181         type = TT_ROTATE;
182       else if( name == "s" )
183         type = TT_SCALE;
184
185       _transform_dirty = true;
186       return;
187     }
188
189     childAdded(child);
190   }
191
192   //----------------------------------------------------------------------------
193   void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
194   {
195     if( parent == _node && child->getNameString() == NAME_TRANSFORM )
196     {
197       assert(child->getIndex() < static_cast<int>(_transform_types.size()));
198       _transform_types[ child->getIndex() ] = TT_NONE;
199
200       while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
201         _transform_types.pop_back();
202
203       _transform_dirty = true;
204       return;
205     }
206
207     childRemoved(child);
208   }
209
210   //----------------------------------------------------------------------------
211   void Element::valueChanged(SGPropertyNode* child)
212   {
213     SGPropertyNode *parent = child->getParent();
214     if( parent == _node )
215     {
216       if( setStyle(child) )
217         return;
218       else if( child->getNameString() == "update" )
219         return update(0);
220       else if( child->getNameString() == "visible" )
221         // TODO check if we need another nodemask
222         return _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 );
223     }
224     else if(   parent->getParent() == _node
225             && parent->getNameString() == NAME_TRANSFORM )
226     {
227       _transform_dirty = true;
228       return;
229     }
230
231     childChanged(child);
232   }
233
234   //----------------------------------------------------------------------------
235   void Element::setBoundingBox(const osg::BoundingBox& bb)
236   {
237     if( _bounding_box.empty() )
238     {
239       SGPropertyNode* bb_node = _node->getChild("bounding-box", 0, true);
240       _bounding_box.resize(4);
241       _bounding_box[0] = bb_node->getChild("min-x", 0, true);
242       _bounding_box[1] = bb_node->getChild("min-y", 0, true);
243       _bounding_box[2] = bb_node->getChild("max-x", 0, true);
244       _bounding_box[3] = bb_node->getChild("max-y", 0, true);
245     }
246
247     _bounding_box[0]->setFloatValue(bb._min.x());
248     _bounding_box[1]->setFloatValue(bb._min.y());
249     _bounding_box[2]->setFloatValue(bb._max.x());
250     _bounding_box[3]->setFloatValue(bb._max.y());
251   }
252
253   //----------------------------------------------------------------------------
254   Element::Element( const CanvasWeakPtr& canvas,
255                     const SGPropertyNode_ptr& node,
256                     const Style& parent_style ):
257     _canvas( canvas ),
258     _transform_dirty( false ),
259     _transform( new osg::MatrixTransform ),
260     _node( node ),
261     _style( parent_style ),
262     _drawable( 0 )
263   {
264     assert( _node );
265     _node->addChangeListener(this);
266
267     SG_LOG
268     (
269       SG_GL,
270       SG_DEBUG,
271       "New canvas element " << node->getPath()
272     );
273   }
274
275   //----------------------------------------------------------------------------
276   bool Element::handleLocalMouseEvent(const MouseEvent& event)
277   {
278 //    std::cout << _node->getPath()
279 //              << " local: pos=(" << event.x << "|" << event.y << ") "
280 //              <<         "d=(" << event.dx << "|" << event.dx << ")"
281 //              << std::endl;
282     return true;
283   }
284
285   //----------------------------------------------------------------------------
286   void Element::setDrawable( osg::Drawable* drawable )
287   {
288     _drawable = drawable;
289     assert( _drawable );
290
291     osg::ref_ptr<osg::Geode> geode = new osg::Geode;
292     geode->addDrawable(_drawable);
293     _transform->addChild(geode);
294   }
295
296   //----------------------------------------------------------------------------
297   void Element::setupStyle()
298   {
299     BOOST_FOREACH( Style::value_type style, _style )
300       setStyle(style.second);
301   }
302
303   //----------------------------------------------------------------------------
304   bool Element::setStyle(const SGPropertyNode* child)
305   {
306     StyleSetters::const_iterator setter =
307       _style_setters.find(child->getNameString());
308     if( setter == _style_setters.end() )
309       return false;
310
311     setter->second(child);
312     return true;
313   }
314
315 } // namespace canvas
316 } // namespace simgear