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