]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/ODGauge.cxx
Fix for OSG without OSG_INIT_SINGLETON_PROXY
[simgear.git] / simgear / canvas / ODGauge.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 library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Library General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
17 //
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 // Library General Public License for more details.
22 //
23 // You should have received a copy of the GNU Library General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
26
27 #ifdef HAVE_CONFIG_H
28 #  include <simgear_config.h>
29 #endif
30
31 #include "ODGauge.hxx"
32 #include "CanvasSystemAdapter.hxx"
33
34 #include <simgear/debug/logstream.hxx>
35 #include <simgear/scene/util/RenderConstants.hxx>
36
37 #include <osg/Texture2D>
38 #include <osg/AlphaFunc>
39 #include <osg/BlendFunc>
40 #include <osg/Camera>
41 #include <osg/Matrix>
42 #include <osg/PolygonMode>
43 #include <osg/ShadeModel>
44 #include <osg/StateSet>
45 #include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
46 #include <osgUtil/RenderBin>
47
48 #include <cassert>
49
50 namespace simgear
51 {
52 namespace canvas
53 {
54
55   class PreOrderBin:
56     public osgUtil::RenderBin
57   {
58     public:
59
60       PreOrderBin()
61       {}
62       PreOrderBin( const RenderBin& rhs,
63                    const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY ):
64         RenderBin(rhs, copyop)
65       {}
66
67       virtual osg::Object* cloneType() const
68       {
69         return new PreOrderBin();
70       }
71       virtual osg::Object* clone(const osg::CopyOp& copyop) const
72       {
73         return new PreOrderBin(*this,copyop);
74       }
75       virtual bool isSameKindAs(const osg::Object* obj) const
76       {
77         return dynamic_cast<const PreOrderBin*>(obj) != 0L;
78       }
79       virtual const char* className() const
80       {
81         return "PreOrderBin";
82       }
83
84       virtual void sort()
85       {
86         // Do not sort to keep traversal order...
87       }
88   };
89
90 #ifndef OSG_INIT_SINGLETON_PROXY
91   /**
92    * http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk/include/osg/Object
93    *
94    * Helper macro that creates a static proxy object to call singleton function
95    * on it's construction, ensuring that the singleton gets initialized at
96    * startup.
97    */
98 #  define OSG_INIT_SINGLETON_PROXY(ProxyName, Func)\
99           static struct ProxyName{ ProxyName() { Func; } } s_##ProxyName;
100 #endif
101
102   OSG_INIT_SINGLETON_PROXY(
103     PreOrderBinProxy,
104     (osgUtil::RenderBin::addRenderBinPrototype("PreOrderBin", new PreOrderBin))
105   );
106
107   //----------------------------------------------------------------------------
108   ODGauge::ODGauge():
109     _size_x( -1 ),
110     _size_y( -1 ),
111     _view_width( -1 ),
112     _view_height( -1 ),
113     _flags(0),
114     _coverage_samples( 0 ),
115     _color_samples( 0 )
116   {
117
118   }
119
120   //----------------------------------------------------------------------------
121   ODGauge::~ODGauge()
122   {
123     clear();
124   }
125
126   //----------------------------------------------------------------------------
127   void ODGauge::setSystemAdapter(const SystemAdapterPtr& system_adapter)
128   {
129     _system_adapter = system_adapter;
130   }
131
132   //----------------------------------------------------------------------------
133   void ODGauge::setSize(int size_x, int size_y)
134   {
135     _size_x = size_x;
136     _size_y = size_y < 0 ? size_x : size_y;
137
138     if( serviceable() )
139       reinit();
140     else if( texture )
141       texture->setTextureSize(_size_x, _size_y);
142   }
143
144   //----------------------------------------------------------------------------
145   void ODGauge::setViewSize(int width, int height)
146   {
147     _view_width = width;
148     _view_height = height < 0 ? width : height;
149
150     if( camera )
151       updateCoordinateFrame();
152   }
153
154   //----------------------------------------------------------------------------
155   osg::Vec2s ODGauge::getViewSize() const
156   {
157     return osg::Vec2s(_view_width, _view_height);
158   }
159
160   //----------------------------------------------------------------------------
161   void ODGauge::useImageCoords(bool use)
162   {
163     if( updateFlag(USE_IMAGE_COORDS, use) && texture )
164       updateCoordinateFrame();
165   }
166
167   //----------------------------------------------------------------------------
168   void ODGauge::useStencil(bool use)
169   {
170     if( updateFlag(USE_STENCIL, use) && texture )
171       updateStencil();
172   }
173
174   //----------------------------------------------------------------------------
175   void ODGauge::useAdditiveBlend(bool use)
176   {
177     if( updateFlag(USE_ADDITIVE_BLEND, use) && camera )
178       updateBlendMode();
179   }
180
181   //----------------------------------------------------------------------------
182   void ODGauge::setSampling( bool mipmapping,
183                              int coverage_samples,
184                              int color_samples )
185   {
186     if(    !updateFlag(USE_MIPMAPPING, mipmapping)
187         && _coverage_samples == coverage_samples
188         && _color_samples == color_samples )
189       return;
190
191     if( color_samples > coverage_samples )
192     {
193       SG_LOG
194       (
195         SG_GL,
196         SG_WARN,
197         "ODGauge::setSampling: color_samples > coverage_samples not allowed!"
198       );
199       color_samples = coverage_samples;
200     }
201
202     _coverage_samples = coverage_samples;
203     _color_samples = color_samples;
204
205     updateSampling();
206   }
207
208   //----------------------------------------------------------------------------
209   void ODGauge::setRender(bool render)
210   {
211     // Only the far camera should trigger this texture to be rendered.
212     camera->setNodeMask(render ? simgear::BACKGROUND_BIT : 0);
213   }
214
215   //----------------------------------------------------------------------------
216   bool ODGauge::serviceable() const
217   {
218     return _flags & AVAILABLE;
219   }
220
221   //----------------------------------------------------------------------------
222   void ODGauge::allocRT(osg::NodeCallback* camera_cull_callback)
223   {
224     camera = new osg::Camera;
225     camera->setDataVariance(osg::Object::DYNAMIC);
226     camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
227     camera->setRenderOrder(osg::Camera::PRE_RENDER);
228     camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 0.0f));
229     camera->setClearStencil(0);
230     camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT,
231                                                osg::Camera::FRAME_BUFFER );
232
233     if( camera_cull_callback )
234       camera->setCullCallback(camera_cull_callback);
235
236     setRender(true);
237     updateCoordinateFrame();
238     updateStencil();
239
240     osg::StateSet* stateSet = camera->getOrCreateStateSet();
241     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
242     stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
243     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
244     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
245     stateSet->setAttributeAndModes(
246       new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK,
247                             osg::PolygonMode::FILL ),
248       osg::StateAttribute::ON );
249     stateSet->setAttributeAndModes(
250       new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.001f),
251       osg::StateAttribute::ON );
252     stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT));
253
254     if( !texture )
255     {
256       texture = new osg::Texture2D;
257       texture->setResizeNonPowerOfTwoHint(false);
258       texture->setTextureSize(_size_x, _size_y);
259       texture->setInternalFormat(GL_RGBA);
260     }
261
262     updateSampling();
263     updateBlendMode();
264
265     if( _system_adapter )
266       _system_adapter->addCamera(camera.get());
267
268     _flags |= AVAILABLE;
269   }
270
271   //----------------------------------------------------------------------------
272   void ODGauge::reinit()
273   {
274     osg::NodeCallback* cull_callback = camera ? camera->getCullCallback() : 0;
275     clear();
276     allocRT(cull_callback);
277   }
278
279   //----------------------------------------------------------------------------
280   void ODGauge::clear()
281   {
282     if( camera.valid() && _system_adapter )
283       _system_adapter->removeCamera(camera.get());
284     camera.release();
285     texture.release();
286
287     _flags &= ~AVAILABLE;
288   }
289
290   //----------------------------------------------------------------------------
291   bool ODGauge::updateFlag(Flags flag, bool enable)
292   {
293     if( bool(_flags & flag) == enable )
294       return false;
295
296     _flags ^= flag;
297     return true;
298   }
299
300   //----------------------------------------------------------------------------
301   void ODGauge::updateCoordinateFrame()
302   {
303     assert( camera );
304
305     if( _view_width < 0 )
306       _view_width = _size_x;
307     if( _view_height < 0 )
308       _view_height = _size_y;
309
310     camera->setViewport(0, 0, _size_x, _size_y);
311
312     if( _flags & USE_IMAGE_COORDS )
313       camera->setProjectionMatrix(
314         osg::Matrix::ortho2D(0, _view_width, _view_height, 0)
315       );
316     else
317       camera->setProjectionMatrix(
318         osg::Matrix::ortho2D( -_view_width/2.,  _view_width/2.,
319                               -_view_height/2., _view_height/2. )
320       );
321   }
322
323   //----------------------------------------------------------------------------
324   void ODGauge::updateStencil()
325   {
326     assert( camera );
327
328     GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
329
330     if( _flags & USE_STENCIL )
331     {
332       camera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER,
333                        GL_DEPTH_STENCIL_EXT );
334       mask |= GL_STENCIL_BUFFER_BIT;
335     }
336     else
337     {
338       camera->detach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER);
339     }
340
341     camera->setClearMask(mask);
342   }
343
344   //----------------------------------------------------------------------------
345   void ODGauge::updateSampling()
346   {
347     assert( camera );
348     assert( texture );
349
350     texture->setFilter(
351       osg::Texture2D::MIN_FILTER,
352       (_flags & USE_MIPMAPPING) ? osg::Texture2D::LINEAR_MIPMAP_LINEAR
353                                 : osg::Texture2D::LINEAR
354     );
355     camera->attach(
356       osg::Camera::COLOR_BUFFER,
357       texture.get(),
358       0, 0,
359       _flags & USE_MIPMAPPING,
360       _coverage_samples,
361       _color_samples
362     );
363   }
364
365   //----------------------------------------------------------------------------
366   void ODGauge::updateBlendMode()
367   {
368     assert( camera );
369
370     camera->getOrCreateStateSet()
371       ->setAttributeAndModes
372       (
373         (_flags & USE_ADDITIVE_BLEND)
374           ? new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA,
375                                 osg::BlendFunc::ONE_MINUS_SRC_ALPHA,
376                                 osg::BlendFunc::ONE,
377                                 osg::BlendFunc::ONE )
378           : new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA,
379                                 osg::BlendFunc::ONE_MINUS_SRC_ALPHA )
380       );
381   }
382
383 } // namespace canvas
384 } // namespace simgear