]> git.mxchange.org Git - flightgear.git/blob - src/Canvas/elements/element.cxx
Canvas: Image/Window unifying and allow using canvas inside canvas.
[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/property_helper.hxx>
21
22 #include <osg/Drawable>
23 #include <osg/Geode>
24
25 #include <cassert>
26 #include <cstring>
27
28 namespace canvas
29 {
30   const std::string NAME_TRANSFORM = "tf";
31   const std::string NAME_COLOR = "color";
32   const std::string NAME_COLOR_FILL = "color-fill";
33
34   //----------------------------------------------------------------------------
35   Element::~Element()
36   {
37
38   }
39
40   //----------------------------------------------------------------------------
41   void Element::update(double dt)
42   {
43     if( !_transform->getNodeMask() )
44       // Don't do anything if element is hidden
45       return;
46
47     if( _transform_dirty )
48     {
49       osg::Matrix m;
50       for( size_t i = 0; i < _transform_types.size(); ++i )
51       {
52         // Skip unused indizes...
53         if( _transform_types[i] == TT_NONE )
54           continue;
55
56         SGPropertyNode* tf_node = _node->getChild("tf", i, true);
57
58         // Build up the matrix representation of the current transform node
59         osg::Matrix tf;
60         switch( _transform_types[i] )
61         {
62           case TT_MATRIX:
63             tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1),
64                               tf_node->getDoubleValue("m[1]", 0), 0, 0,
65
66                               tf_node->getDoubleValue("m[2]", 0),
67                               tf_node->getDoubleValue("m[3]", 1), 0, 0,
68
69                               0,    0,    1, 0,
70                               tf_node->getDoubleValue("m[4]", 0),
71                               tf_node->getDoubleValue("m[5]", 0), 0, 1 );
72             break;
73           case TT_TRANSLATE:
74             tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0),
75                                           tf_node->getDoubleValue("t[1]", 0),
76                                           0 ) );
77             break;
78           case TT_ROTATE:
79             tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 );
80             break;
81           case TT_SCALE:
82           {
83             float sx = tf_node->getDoubleValue("s[0]", 1);
84             // sy defaults to sx...
85             tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 );
86             break;
87           }
88           default:
89             break;
90         }
91         m.postMult( tf );
92       }
93       _transform->setMatrix(m);
94       _transform_dirty = false;
95     }
96
97     if( _attributes_dirty & COLOR )
98     {
99       colorChanged( osg::Vec4( _color[0]->getFloatValue(),
100                                _color[1]->getFloatValue(),
101                                _color[2]->getFloatValue(),
102                                _color[3]->getFloatValue() ) );
103       _attributes_dirty &= ~COLOR;
104     }
105
106     if( _attributes_dirty & COLOR_FILL )
107     {
108       colorFillChanged( osg::Vec4( _color_fill[0]->getFloatValue(),
109                                    _color_fill[1]->getFloatValue(),
110                                    _color_fill[2]->getFloatValue(),
111                                    _color_fill[3]->getFloatValue() ) );
112       _attributes_dirty &= ~COLOR_FILL;
113     }
114
115     if( !_bounding_box.empty() )
116     {
117       assert( _drawable );
118
119       const osg::BoundingBox& bb = _drawable->getBound();
120       _bounding_box[0]->setFloatValue(bb._min.x());
121       _bounding_box[1]->setFloatValue(bb._min.y());
122       _bounding_box[2]->setFloatValue(bb._max.x());
123       _bounding_box[3]->setFloatValue(bb._max.y());
124     }
125   }
126
127   //----------------------------------------------------------------------------
128   osg::ref_ptr<osg::MatrixTransform> Element::getMatrixTransform()
129   {
130     return _transform;
131   }
132
133   //----------------------------------------------------------------------------
134   void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
135   {
136     if( parent == _node )
137     {
138       if( child->getNameString() == NAME_TRANSFORM )
139       {
140         if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
141           _transform_types.resize( child->getIndex() + 1 );
142
143         _transform_types[ child->getIndex() ] = TT_NONE;
144         _transform_dirty = true;
145       }
146       else
147         childAdded(child);
148     }
149     else if(    parent->getParent() == _node
150              && parent->getNameString() == NAME_TRANSFORM )
151     {
152       assert(parent->getIndex() < static_cast<int>(_transform_types.size()));
153
154       const std::string& name = child->getNameString();
155
156       TransformType& type = _transform_types[parent->getIndex()];
157
158       if(      name == "m" )
159         type = TT_MATRIX;
160       else if( name == "t" )
161         type = TT_TRANSLATE;
162       else if( name == "rot" )
163         type = TT_ROTATE;
164       else if( name == "s" )
165         type = TT_SCALE;
166
167       _transform_dirty = true;
168     }
169   }
170
171   //----------------------------------------------------------------------------
172   void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
173   {
174     if( parent != _node )
175       return;
176
177     if( child->getNameString() == NAME_TRANSFORM )
178     {
179       assert(child->getIndex() < static_cast<int>(_transform_types.size()));
180       _transform_types[ child->getIndex() ] = TT_NONE;
181
182       while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
183         _transform_types.pop_back();
184
185       _transform_dirty = true;
186     }
187     else
188       childRemoved(child);
189   }
190
191   //----------------------------------------------------------------------------
192   void Element::valueChanged(SGPropertyNode* child)
193   {
194     SGPropertyNode *parent = child->getParent();
195     if( parent->getParent() == _node )
196     {
197       if( parent->getNameString() == NAME_TRANSFORM )
198         _transform_dirty = true;
199       else if( !_color.empty() && _color[0]->getParent() == parent )
200         _attributes_dirty |= COLOR;
201       else if( !_color_fill.empty() && _color_fill[0]->getParent() == parent )
202         _attributes_dirty |= COLOR_FILL;
203     }
204     else if( parent == _node )
205     {
206       if( child->getNameString() == "update" )
207         update(0);
208       else if( child->getNameString() == "visible" )
209         // TODO check if we need another nodemask
210         _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 );
211       else
212         childChanged(child);
213     }
214   }
215
216   //----------------------------------------------------------------------------
217   Element::Element(SGPropertyNode_ptr node, uint32_t attributes_used):
218     _attributes_used( attributes_used ),
219     _attributes_dirty( attributes_used ),
220     _transform_dirty( false ),
221     _transform( new osg::MatrixTransform ),
222     _node( node ),
223     _drawable( 0 )
224   {
225     assert( _node );
226     _node->addChangeListener(this);
227
228     if( _attributes_used & COLOR )
229       linkColorNodes("color", _node, _color, osg::Vec4f(0,0,0,1));
230
231     if( _attributes_used & COLOR_FILL )
232       linkColorNodes("color-fill", _node, _color_fill, osg::Vec4f(1,1,1,1));
233
234     SG_LOG
235     (
236       SG_GL,
237       SG_DEBUG,
238       "New canvas element " << node->getPath()
239     );
240   }
241
242   //----------------------------------------------------------------------------
243   void Element::setDrawable( osg::Drawable* drawable )
244   {
245     _drawable = drawable;
246     assert( _drawable );
247
248     osg::ref_ptr<osg::Geode> geode = new osg::Geode;
249     geode->addDrawable(_drawable);
250     _transform->addChild(geode);
251
252     if( _attributes_used & BOUNDING_BOX )
253     {
254       SGPropertyNode* bb_node = _node->getChild("bounding-box", 0, true);
255       _bounding_box.resize(4);
256       _bounding_box[0] = bb_node->getChild("min-x", 0, true);
257       _bounding_box[1] = bb_node->getChild("min-y", 0, true);
258       _bounding_box[2] = bb_node->getChild("max-x", 0, true);
259       _bounding_box[3] = bb_node->getChild("max-y", 0, true);
260     }
261   }
262
263 } // namespace canvas