]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/od_gauge.cxx
Fix for #1244 (Canvas placements with pick animation).
[flightgear.git] / src / Cockpit / od_gauge.cxx
1 // Owner Drawn Gauge helper class
2 //
3 // Written by Harald JOHNSEN, started May 2005.
4 //
5 // Copyright (C) 2005  Harald JOHNSEN
6 //
7 // Ported to OSG by Tim Moore - Jun 2007
8 //
9 // Heavily modified to be usable for the 2d Canvas by Thomas Geymayer - April 2012
10 // Supports now multisampling/mipmapping, usage of the stencil buffer and placing
11 // the texture in the scene by certain filter criteria
12 //
13 // This program is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU General Public License as
15 // published by the Free Software Foundation; either version 2 of the
16 // License, or (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful, but
19 // WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 // General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26 //
27 //
28
29 #ifdef HAVE_CONFIG_H
30 #  include "config.h"
31 #endif
32
33 #include <osg/Texture2D>
34 #include <osg/AlphaFunc>
35 #include <osg/BlendFunc>
36 #include <osg/Camera>
37 #include <osg/Geode>
38 #include <osg/NodeVisitor>
39 #include <osg/Matrix>
40 #include <osg/PolygonMode>
41 #include <osg/ShadeModel>
42 #include <osg/StateSet>
43 #include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
44
45 #include <osgDB/FileNameUtils>
46
47 #include <simgear/canvas/CanvasObjectPlacement.hxx>
48 #include <simgear/scene/material/EffectGeode.hxx>
49 #include <simgear/scene/util/RenderConstants.hxx>
50
51 #include <Canvas/FGCanvasSystemAdapter.hxx>
52 #include <Main/globals.hxx>
53 #include <Scenery/scenery.hxx>
54 #include "od_gauge.hxx"
55
56 #include <cassert>
57
58 static simgear::canvas::SystemAdapterPtr system_adapter(
59   new canvas::FGCanvasSystemAdapter
60 );
61
62 //------------------------------------------------------------------------------
63 FGODGauge::FGODGauge()
64 {
65   setSystemAdapter(system_adapter);
66 }
67
68 //------------------------------------------------------------------------------
69 FGODGauge::~FGODGauge()
70 {
71
72 }
73
74 /**
75  * Replace a texture in the airplane model with the gauge texture.
76  */
77 class ReplaceStaticTextureVisitor:
78   public osg::NodeVisitor
79 {
80   public:
81
82     typedef osg::ref_ptr<osg::Group> GroupPtr;
83     typedef osg::ref_ptr<osg::Material> MaterialPtr;
84
85     ReplaceStaticTextureVisitor( const char* name,
86                                  osg::Texture2D* new_texture ):
87         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
88         _tex_name( osgDB::getSimpleFileName(name) ),
89         _new_texture(new_texture),
90         _cull_callback(0)
91     {}
92
93     ReplaceStaticTextureVisitor( SGPropertyNode* placement,
94                                  osg::Texture2D* new_texture,
95                                  osg::NodeCallback* cull_callback = 0,
96                                  const simgear::canvas::CanvasWeakPtr& canvas =
97                                    simgear::canvas::CanvasWeakPtr() ):
98         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
99         _tex_name( osgDB::getSimpleFileName(
100           placement->getStringValue("texture"))
101         ),
102         _node_name( placement->getStringValue("node") ),
103         _parent_name( placement->getStringValue("parent") ),
104         _node(placement),
105         _new_texture(new_texture),
106         _cull_callback(cull_callback),
107         _canvas(canvas)
108     {
109       if(    _tex_name.empty()
110           && _node_name.empty()
111           && _parent_name.empty() )
112         SG_LOG
113         (
114           SG_GL,
115           SG_WARN,
116           "No filter criterion for replacing texture. "
117           " Every texture will be replaced!"
118         );
119     }
120
121     /**
122      * Get a list of groups which have been inserted into the scene graph to
123      * replace the given texture
124      */
125     simgear::canvas::Placements& getPlacements()
126     {
127       return _placements;
128     }
129
130     virtual void apply(osg::Geode& node)
131     {
132       simgear::EffectGeode* eg = dynamic_cast<simgear::EffectGeode*>(&node);
133       if( !eg )
134         return;
135
136       osg::StateSet* ss = eg->getEffect()->getDefaultStateSet();
137       if( !ss )
138         return;
139
140       osg::Group *parent = node.getParent(0);
141       if( !_node_name.empty() && getNodeName(*parent) != _node_name )
142         return;
143
144       if( !_parent_name.empty() )
145       {
146         // Traverse nodes upwards starting at the parent node (skip current
147         // node)
148         const osg::NodePath& np = getNodePath();
149         bool found = false;
150         for( int i = static_cast<int>(np.size()) - 2; i >= 0; --i )
151         {
152           const osg::Node* path_segment = np[i];
153           const osg::Node* path_parent = path_segment->getParent(0);
154
155           // A node without a name is always the parent of the root node of
156           // the model just containing the file name
157           if( path_parent && path_parent->getName().empty() )
158             return;
159
160           if( path_segment->getName() == _parent_name )
161           {
162             found = true;
163             break;
164           }
165         }
166
167         if( !found )
168           return;
169       }
170
171       for( size_t unit = 0; unit < ss->getNumTextureAttributeLists(); ++unit )
172       {
173         osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>
174         (
175           ss->getTextureAttribute(unit, osg::StateAttribute::TEXTURE)
176         );
177
178         if( !tex || !tex->getImage() || tex == _new_texture )
179           continue;
180
181         if( !_tex_name.empty() )
182         {
183           std::string tex_name = tex->getImage()->getFileName();
184           std::string tex_name_simple = osgDB::getSimpleFileName(tex_name);
185           if( !osgDB::equalCaseInsensitive(_tex_name, tex_name_simple) )
186             continue;
187         }
188
189         // insert a new group between the geode an it's parent which overrides
190         // the texture
191         GroupPtr group = new osg::Group;
192         group->setName("canvas texture group");
193         group->addChild(eg);
194         parent->removeChild(eg);
195         parent->addChild(group);
196
197         if( _cull_callback )
198           group->setCullCallback(_cull_callback);
199
200         osg::StateSet* stateSet = group->getOrCreateStateSet();
201         stateSet->setTextureAttribute( unit, _new_texture,
202                                              osg::StateAttribute::OVERRIDE );
203         stateSet->setTextureMode( unit, GL_TEXTURE_2D,
204                                         osg::StateAttribute::ON );
205
206         _placements.push_back( simgear::canvas::PlacementPtr(
207           new simgear::canvas::ObjectPlacement(_node, group, _canvas)
208         ));
209
210         SG_LOG
211         (
212           SG_GL,
213           SG_INFO,
214              "Replaced texture '" << _tex_name << "'"
215           << " for object '" << parent->getName() << "'"
216           << (!_parent_name.empty() ? " with parent '" + _parent_name + "'"
217                                     : "")
218         );
219         return;
220       }
221     }
222
223   protected:
224
225     std::string _tex_name,      ///<! Name of texture to be replaced
226                 _node_name,     ///<! Only replace if node name matches
227                 _parent_name;   ///<! Only replace if any parent node matches
228                                 ///   given name (all the tree upwards)
229
230     SGPropertyNode_ptr  _node;
231     osg::Texture2D     *_new_texture;
232     osg::NodeCallback  *_cull_callback;
233
234     simgear::canvas::CanvasWeakPtr  _canvas;
235     simgear::canvas::Placements     _placements;
236
237     const std::string& getNodeName(const osg::Node& node) const
238     {
239       if( !node.getName().empty() )
240         return node.getName();
241
242       // Special handling for pick animation which clears the name of the object
243       // and instead sets the name of a parent group with one or two groups
244       // attached (one for normal rendering and one for the picking highlight).
245       osg::Group const* parent = node.getParent(0);
246       if( parent->getName() == "pick render group" )
247         return parent->getParent(0)->getName();
248
249       return node.getName();
250     }
251 };
252
253 //------------------------------------------------------------------------------
254 simgear::canvas::Placements
255 FGODGauge::set_texture( osg::Node* branch,
256                         const char * name,
257                         osg::Texture2D* new_texture )
258 {
259   ReplaceStaticTextureVisitor visitor(name, new_texture);
260   branch->accept(visitor);
261   return visitor.getPlacements();
262 }
263
264 //------------------------------------------------------------------------------
265 simgear::canvas::Placements
266 FGODGauge::set_aircraft_texture( const char* name,
267                                  osg::Texture2D* new_texture )
268 {
269   return set_texture
270   (
271     globals->get_scenery()->get_aircraft_branch(),
272     name,
273     new_texture
274   );
275 }
276
277 //------------------------------------------------------------------------------
278 simgear::canvas::Placements
279 FGODGauge::set_texture( osg::Node* branch,
280                         SGPropertyNode* placement,
281                         osg::Texture2D* new_texture,
282                         osg::NodeCallback* cull_callback,
283                         const simgear::canvas::CanvasWeakPtr& canvas )
284 {
285   ReplaceStaticTextureVisitor visitor( placement,
286                                        new_texture,
287                                        cull_callback,
288                                        canvas );
289   branch->accept(visitor);
290   return visitor.getPlacements();
291 }
292
293 //------------------------------------------------------------------------------
294 simgear::canvas::Placements
295 FGODGauge::set_aircraft_texture( SGPropertyNode* placement,
296                                  osg::Texture2D* new_texture,
297                                  osg::NodeCallback* cull_callback,
298                                  const simgear::canvas::CanvasWeakPtr& canvas )
299 {
300   return set_texture
301   (
302     globals->get_scenery()->get_aircraft_branch(),
303     placement,
304     new_texture,
305     cull_callback,
306     canvas
307   );
308 }