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