]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/od_gauge.cxx
Code cleanups, code updates and fix at least on (possible) devide-by-zero
[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 <Main/globals.hxx>
52 #include <Scenery/scenery.hxx>
53 #include "od_gauge.hxx"
54
55 #include <cassert>
56
57 //------------------------------------------------------------------------------
58 FGODGauge::FGODGauge()
59 {
60
61 }
62
63 //------------------------------------------------------------------------------
64 FGODGauge::~FGODGauge()
65 {
66
67 }
68
69 /**
70  * Replace a texture in the airplane model with the gauge texture.
71  */
72 class ReplaceStaticTextureVisitor:
73   public osg::NodeVisitor
74 {
75   public:
76
77     typedef osg::ref_ptr<osg::Group> GroupPtr;
78     typedef osg::ref_ptr<osg::Material> MaterialPtr;
79
80     ReplaceStaticTextureVisitor( const char* name,
81                                  osg::Texture2D* new_texture ):
82         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
83         _tex_name( osgDB::getSimpleFileName(name) ),
84         _new_texture(new_texture),
85         _cull_callback(0)
86     {}
87
88     ReplaceStaticTextureVisitor( SGPropertyNode* placement,
89                                  osg::Texture2D* new_texture,
90                                  osg::NodeCallback* cull_callback = 0,
91                                  const simgear::canvas::CanvasWeakPtr& canvas =
92                                    simgear::canvas::CanvasWeakPtr() ):
93         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
94         _tex_name( osgDB::getSimpleFileName(
95           placement->getStringValue("texture"))
96         ),
97         _node_name( placement->getStringValue("node") ),
98         _parent_name( placement->getStringValue("parent") ),
99         _node(placement),
100         _new_texture(new_texture),
101         _cull_callback(cull_callback),
102         _canvas(canvas)
103     {
104       if(    _tex_name.empty()
105           && _node_name.empty()
106           && _parent_name.empty() )
107         SG_LOG
108         (
109           SG_GL,
110           SG_WARN,
111           "No filter criterion for replacing texture. "
112           " Every texture will be replaced!"
113         );
114     }
115
116     /**
117      * Get a list of groups which have been inserted into the scene graph to
118      * replace the given texture
119      */
120     simgear::canvas::Placements& getPlacements()
121     {
122       return _placements;
123     }
124
125     virtual void apply(osg::Geode& node)
126     {
127       simgear::EffectGeode* eg = dynamic_cast<simgear::EffectGeode*>(&node);
128       if( !eg )
129         return;
130       simgear::Effect* eff = eg->getEffect();
131       if (!eff)
132           return;
133       osg::StateSet* ss = eff->getDefaultStateSet();
134       if( !ss )
135         return;
136
137       osg::Group *parent = node.getParent(0);
138       if( !_node_name.empty() && getNodeName(*parent) != _node_name )
139         return;
140
141       if( !_parent_name.empty() )
142       {
143         // Traverse nodes upwards starting at the parent node (skip current
144         // node)
145         const osg::NodePath& np = getNodePath();
146         bool found = false;
147         for( int i = static_cast<int>(np.size()) - 2; i >= 0; --i )
148         {
149           const osg::Node* path_segment = np[i];
150           const osg::Node* path_parent = path_segment->getParent(0);
151
152           // A node without a name is always the parent of the root node of
153           // the model just containing the file name
154           if( path_parent && path_parent->getName().empty() )
155             return;
156
157           if( path_segment->getName() == _parent_name )
158           {
159             found = true;
160             break;
161           }
162         }
163
164         if( !found )
165           return;
166       }
167
168       for( size_t unit = 0; unit < ss->getNumTextureAttributeLists(); ++unit )
169       {
170         osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>
171         (
172           ss->getTextureAttribute(unit, osg::StateAttribute::TEXTURE)
173         );
174
175         if( !tex || !tex->getImage() || tex == _new_texture )
176           continue;
177
178         if( !_tex_name.empty() )
179         {
180           std::string tex_name = tex->getImage()->getFileName();
181           std::string tex_name_simple = osgDB::getSimpleFileName(tex_name);
182           if( !osgDB::equalCaseInsensitive(_tex_name, tex_name_simple) )
183             continue;
184         }
185
186         // insert a new group between the geode an it's parent which overrides
187         // the texture
188         GroupPtr group = new osg::Group;
189         group->setName("canvas texture group");
190         group->addChild(eg);
191         parent->removeChild(eg);
192         parent->addChild(group);
193
194         if( _cull_callback )
195           group->setCullCallback(_cull_callback);
196
197         osg::StateSet* stateSet = group->getOrCreateStateSet();
198         stateSet->setTextureAttribute( unit, _new_texture,
199                                              osg::StateAttribute::OVERRIDE );
200         stateSet->setTextureMode( unit, GL_TEXTURE_2D,
201                                         osg::StateAttribute::ON );
202
203         _placements.push_back( simgear::canvas::PlacementPtr(
204           new simgear::canvas::ObjectPlacement(_node, group, _canvas)
205         ));
206
207         SG_LOG
208         (
209           SG_GL,
210           SG_INFO,
211              "Replaced texture '" << _tex_name << "'"
212           << " for object '" << parent->getName() << "'"
213           << (!_parent_name.empty() ? " with parent '" + _parent_name + "'"
214                                     : "")
215         );
216         return;
217       }
218     }
219
220   protected:
221
222     std::string _tex_name,      ///<! Name of texture to be replaced
223                 _node_name,     ///<! Only replace if node name matches
224                 _parent_name;   ///<! Only replace if any parent node matches
225                                 ///   given name (all the tree upwards)
226
227     SGPropertyNode_ptr  _node;
228     osg::Texture2D     *_new_texture;
229     osg::NodeCallback  *_cull_callback;
230
231     simgear::canvas::CanvasWeakPtr  _canvas;
232     simgear::canvas::Placements     _placements;
233
234     const std::string& getNodeName(const osg::Node& node) const
235     {
236       if( !node.getName().empty() )
237         return node.getName();
238
239       // Special handling for pick animation which clears the name of the object
240       // and instead sets the name of a parent group with one or two groups
241       // attached (one for normal rendering and one for the picking highlight).
242       osg::Group const* parent = node.getParent(0);
243       if( parent->getName() == "pick render group" )
244         return parent->getParent(0)->getName();
245
246       return node.getName();
247     }
248 };
249
250 //------------------------------------------------------------------------------
251 simgear::canvas::Placements
252 FGODGauge::set_texture( osg::Node* branch,
253                         const char * name,
254                         osg::Texture2D* new_texture )
255 {
256   ReplaceStaticTextureVisitor visitor(name, new_texture);
257   branch->accept(visitor);
258   return visitor.getPlacements();
259 }
260
261 //------------------------------------------------------------------------------
262 simgear::canvas::Placements
263 FGODGauge::set_aircraft_texture( const char* name,
264                                  osg::Texture2D* new_texture )
265 {
266   return set_texture
267   (
268     globals->get_scenery()->get_aircraft_branch(),
269     name,
270     new_texture
271   );
272 }
273
274 //------------------------------------------------------------------------------
275 simgear::canvas::Placements
276 FGODGauge::set_texture( osg::Node* branch,
277                         SGPropertyNode* placement,
278                         osg::Texture2D* new_texture,
279                         osg::NodeCallback* cull_callback,
280                         const simgear::canvas::CanvasWeakPtr& canvas )
281 {
282   ReplaceStaticTextureVisitor visitor( placement,
283                                        new_texture,
284                                        cull_callback,
285                                        canvas );
286   branch->accept(visitor);
287   return visitor.getPlacements();
288 }
289
290 //------------------------------------------------------------------------------
291 simgear::canvas::Placements
292 FGODGauge::set_aircraft_texture( SGPropertyNode* placement,
293                                  osg::Texture2D* new_texture,
294                                  osg::NodeCallback* cull_callback,
295                                  const simgear::canvas::CanvasWeakPtr& canvas )
296 {
297   return set_texture
298   (
299     globals->get_scenery()->get_aircraft_branch(),
300     placement,
301     new_texture,
302     cull_callback,
303     canvas
304   );
305 }