1 // Owner Drawn Gauge helper class
3 // Written by Harald JOHNSEN, started May 2005.
5 // Copyright (C) 2005 Harald JOHNSEN
7 // Ported to OSG by Tim Moore - Jun 2007
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
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.
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.
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.
33 #include <osg/Texture2D>
34 #include <osg/AlphaFunc>
35 #include <osg/BlendFunc>
38 #include <osg/NodeVisitor>
39 #include <osg/Material>
41 #include <osg/PolygonMode>
42 #include <osg/ShadeModel>
43 #include <osg/StateSet>
44 #include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
46 #include <osgDB/FileNameUtils>
48 #include <simgear/scene/material/EffectGeode.hxx>
49 #include <simgear/scene/util/RenderConstants.hxx>
51 #include <Canvas/FGCanvasSystemAdapter.hxx>
52 #include <Main/globals.hxx>
53 #include <Scenery/scenery.hxx>
54 #include "od_gauge.hxx"
58 static simgear::canvas::SystemAdapterPtr system_adapter(
59 new canvas::FGCanvasSystemAdapter
62 //------------------------------------------------------------------------------
63 FGODGauge::FGODGauge()
65 setSystemAdapter(system_adapter);
68 //------------------------------------------------------------------------------
69 FGODGauge::~FGODGauge()
75 * Replace a texture in the airplane model with the gauge texture.
77 class ReplaceStaticTextureVisitor:
78 public osg::NodeVisitor
82 typedef osg::ref_ptr<osg::Group> GroupPtr;
83 typedef osg::ref_ptr<osg::Material> MaterialPtr;
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)
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"))
99 _node_name( placement->getStringValue("node") ),
100 _parent_name( placement->getStringValue("parent") ),
102 _new_texture(new_texture),
103 _cull_callback(cull_callback)
105 if( _tex_name.empty()
106 && _node_name.empty()
107 && _parent_name.empty() )
112 "No filter criterion for replacing texture. "
113 " Every texture will be replaced!"
118 * Get a list of groups which have been inserted into the scene graph to
119 * replace the given texture
121 simgear::canvas::Placements& getPlacements()
126 virtual void apply(osg::Geode& node)
128 simgear::EffectGeode* eg = dynamic_cast<simgear::EffectGeode*>(&node);
132 osg::StateSet* ss = eg->getEffect()->getDefaultStateSet();
136 osg::Group *parent = node.getParent(0);
137 if( !_node_name.empty() && parent->getName() != _node_name )
140 if( !_parent_name.empty() )
142 // Traverse nodes upwards starting at the parent node (skip current
144 const osg::NodePath& np = getNodePath();
146 for( int i = static_cast<int>(np.size()) - 2; i >= 0; --i )
148 const osg::Node* path_segment = np[i];
149 const osg::Node* path_parent = path_segment->getParent(0);
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() )
156 if( path_segment->getName() == _parent_name )
167 for( size_t unit = 0; unit < ss->getNumTextureAttributeLists(); ++unit )
169 osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>
171 ss->getTextureAttribute(unit, osg::StateAttribute::TEXTURE)
174 if( !tex || !tex->getImage() || tex == _new_texture )
177 if( !_tex_name.empty() )
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) )
185 // insert a new group between the geode an it's parent which overrides
187 GroupPtr group = new osg::Group;
188 group->setName("canvas texture group");
190 parent->removeChild(eg);
191 parent->addChild(group);
194 group->setCullCallback(_cull_callback);
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 );
202 _placements.push_back( simgear::canvas::PlacementPtr(
203 new ObjectPlacement(_node, group)
210 "Replaced texture '" << _tex_name << "'"
211 << " for object '" << parent->getName() << "'"
212 << (!_parent_name.empty() ? " with parent '" + _parent_name + "'"
221 class ObjectPlacement:
222 public simgear::canvas::Placement
226 ObjectPlacement( SGPropertyNode* node,
231 // TODO make more generic and extendable for more properties
232 if( node->hasValue("emission") )
233 setEmission( node->getFloatValue("emission") );
236 virtual bool childChanged(SGPropertyNode* node)
238 if( node->getParent() != _node )
241 if( node->getNameString() == "emission" )
242 setEmission( node->getFloatValue() );
249 void setEmission(float emit)
251 emit = SGMiscf::clip(emit, 0, 1);
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 ) );
263 _material->setEmission(
264 osg::Material::FRONT_AND_BACK,
265 osg::Vec4(emit, emit, emit, emit)
270 * Remove placement from the scene
272 virtual ~ObjectPlacement()
274 assert( _group->getNumChildren() == 1 );
275 osg::Node *child = _group->getChild(0);
277 if( _group->getNumParents() )
279 osg::Group *parent = _group->getParent(0);
280 parent->addChild(child);
281 parent->removeChild(_group);
284 _group->removeChild(child);
289 MaterialPtr _material;
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)
297 SGPropertyNode_ptr _node;
298 osg::Texture2D *_new_texture;
299 osg::NodeCallback *_cull_callback;
301 simgear::canvas::Placements _placements;
304 //------------------------------------------------------------------------------
305 simgear::canvas::Placements
306 FGODGauge::set_texture( const char* name,
307 osg::Texture2D* new_texture )
309 osg::Group* root = globals->get_scenery()->get_aircraft_branch();
310 ReplaceStaticTextureVisitor visitor(name, new_texture);
311 root->accept(visitor);
312 return visitor.getPlacements();
315 //------------------------------------------------------------------------------
316 simgear::canvas::Placements
317 FGODGauge::set_texture( SGPropertyNode* placement,
318 osg::Texture2D* new_texture,
319 osg::NodeCallback* cull_callback )
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();