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