]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/od_gauge.cxx
Include file only needed by MSVC
[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/Material>
40 #include <osg/Matrix>
41 #include <osg/PolygonMode>
42 #include <osg/ShadeModel>
43 #include <osg/StateSet>
44 #include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
45
46 #include <osgDB/FileNameUtils>
47
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     {}
91
92     ReplaceStaticTextureVisitor( SGPropertyNode* placement,
93                                  osg::Texture2D* new_texture,
94                                  osg::NodeCallback* cull_callback = 0 ):
95         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
96         _tex_name( osgDB::getSimpleFileName(
97           placement->getStringValue("texture"))
98         ),
99         _node_name( placement->getStringValue("node") ),
100         _parent_name( placement->getStringValue("parent") ),
101         _node(placement),
102         _new_texture(new_texture),
103         _cull_callback(cull_callback)
104     {
105       if(    _tex_name.empty()
106           && _node_name.empty()
107           && _parent_name.empty() )
108         SG_LOG
109         (
110           SG_GL,
111           SG_WARN,
112           "No filter criterion for replacing texture. "
113           " Every texture will be replaced!"
114         );
115     }
116
117     /**
118      * Get a list of groups which have been inserted into the scene graph to
119      * replace the given texture
120      */
121     simgear::canvas::Placements& getPlacements()
122     {
123       return _placements;
124     }
125
126     virtual void apply(osg::Geode& node)
127     {
128       simgear::EffectGeode* eg = dynamic_cast<simgear::EffectGeode*>(&node);
129       if( !eg )
130         return;
131
132       osg::StateSet* ss = eg->getEffect()->getDefaultStateSet();
133       if( !ss )
134         return;
135
136       osg::Group *parent = node.getParent(0);
137       if( !_node_name.empty() && parent->getName() != _node_name )
138         return;
139
140       if( !_parent_name.empty() )
141       {
142         // Traverse nodes upwards starting at the parent node (skip current
143         // node)
144         const osg::NodePath& np = getNodePath();
145         bool found = false;
146         for( int i = static_cast<int>(np.size()) - 2; i >= 0; --i )
147         {
148           const osg::Node* path_segment = np[i];
149           const osg::Node* path_parent = path_segment->getParent(0);
150
151           // A node without a name is always the parent of the root node of
152           // the model just containing the file name
153           if( path_parent && path_parent->getName().empty() )
154             return;
155
156           if( path_segment->getName() == _parent_name )
157           {
158             found = true;
159             break;
160           }
161         }
162
163         if( !found )
164           return;
165       }
166
167       for( size_t unit = 0; unit < ss->getNumTextureAttributeLists(); ++unit )
168       {
169         osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>
170         (
171           ss->getTextureAttribute(unit, osg::StateAttribute::TEXTURE)
172         );
173
174         if( !tex || !tex->getImage() || tex == _new_texture )
175           continue;
176
177         if( !_tex_name.empty() )
178         {
179           std::string tex_name = tex->getImage()->getFileName();
180           std::string tex_name_simple = osgDB::getSimpleFileName(tex_name);
181           if( !osgDB::equalCaseInsensitive(_tex_name, tex_name_simple) )
182             continue;
183         }
184
185         // insert a new group between the geode an it's parent which overrides
186         // the texture
187         GroupPtr group = new osg::Group;
188         group->setName("canvas texture group");
189         group->addChild(eg);
190         parent->removeChild(eg);
191         parent->addChild(group);
192
193         if( _cull_callback )
194           group->setCullCallback(_cull_callback);
195
196         osg::StateSet* stateSet = group->getOrCreateStateSet();
197         stateSet->setTextureAttribute( unit, _new_texture,
198                                              osg::StateAttribute::OVERRIDE );
199         stateSet->setTextureMode( unit, GL_TEXTURE_2D,
200                                         osg::StateAttribute::ON );
201
202         _placements.push_back( simgear::canvas::PlacementPtr(
203           new ObjectPlacement(_node, group)
204         ));
205
206         SG_LOG
207         (
208           SG_GL,
209           SG_INFO,
210              "Replaced texture '" << _tex_name << "'"
211           << " for object '" << parent->getName() << "'"
212           << (!_parent_name.empty() ? " with parent '" + _parent_name + "'"
213                                     : "")
214         );
215         return;
216       }
217     }
218
219   protected:
220
221     class ObjectPlacement:
222       public simgear::canvas::Placement
223     {
224       public:
225
226         ObjectPlacement( SGPropertyNode* node,
227                          GroupPtr group ):
228           Placement(node),
229           _group(group)
230         {
231           // TODO make more generic and extendable for more properties
232           if( node->hasValue("emission") )
233             setEmission( node->getFloatValue("emission") );
234         }
235
236         virtual bool childChanged(SGPropertyNode* node)
237         {
238           if( node->getParent() != _node )
239             return false;
240
241           if( node->getNameString() == "emission" )
242             setEmission( node->getFloatValue() );
243           else
244             return false;
245
246           return true;
247         }
248
249         void setEmission(float emit)
250         {
251           emit = SGMiscf::clip(emit, 0, 1);
252
253           if( !_material )
254           {
255             _material = new osg::Material;
256             _material->setColorMode(osg::Material::OFF);
257             _material->setDataVariance(osg::Object::DYNAMIC);
258             _group->getOrCreateStateSet()
259                   ->setAttribute(_material, ( osg::StateAttribute::ON
260                                             | osg::StateAttribute::OVERRIDE ) );
261           }
262
263           _material->setEmission(
264             osg::Material::FRONT_AND_BACK,
265             osg::Vec4(emit, emit, emit, emit)
266           );
267         }
268
269         /**
270          * Remove placement from the scene
271          */
272         virtual ~ObjectPlacement()
273         {
274           assert( _group->getNumChildren() == 1 );
275           osg::Node *child = _group->getChild(0);
276
277           if( _group->getNumParents() )
278           {
279             osg::Group *parent = _group->getParent(0);
280             parent->addChild(child);
281             parent->removeChild(_group);
282           }
283
284           _group->removeChild(child);
285         }
286
287       private:
288         GroupPtr            _group;
289         MaterialPtr         _material;
290     };
291
292     std::string _tex_name,      ///<! Name of texture to be replaced
293                 _node_name,     ///<! Only replace if node name matches
294                 _parent_name;   ///<! Only replace if any parent node matches
295                                 ///   given name (all the tree upwards)
296
297     SGPropertyNode_ptr  _node;
298     osg::Texture2D     *_new_texture;
299     osg::NodeCallback  *_cull_callback;
300
301     simgear::canvas::Placements _placements;
302 };
303
304 //------------------------------------------------------------------------------
305 simgear::canvas::Placements
306 FGODGauge::set_texture( const char* name,
307                         osg::Texture2D* new_texture )
308 {
309   osg::Group* root = globals->get_scenery()->get_aircraft_branch();
310   ReplaceStaticTextureVisitor visitor(name, new_texture);
311   root->accept(visitor);
312   return visitor.getPlacements();
313 }
314
315 //------------------------------------------------------------------------------
316 simgear::canvas::Placements
317 FGODGauge::set_texture( SGPropertyNode* placement,
318                         osg::Texture2D* new_texture,
319                         osg::NodeCallback* cull_callback )
320 {
321   osg::Group* root = globals->get_scenery()->get_aircraft_branch();
322   ReplaceStaticTextureVisitor visitor(placement, new_texture, cull_callback);
323   root->accept(visitor);
324   return visitor.getPlacements();
325 }