]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/ODGauge.cxx
Canvas: set blend function for elements and prevent autoresize
[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
47 #include <cassert>
48
49 namespace simgear
50 {
51 namespace canvas
52 {
53
54   //----------------------------------------------------------------------------
55   ODGauge::ODGauge():
56     _size_x( -1 ),
57     _size_y( -1 ),
58     _view_width( -1 ),
59     _view_height( -1 ),
60     _flags(0),
61     _coverage_samples( 0 ),
62     _color_samples( 0 )
63   {
64
65   }
66
67   //----------------------------------------------------------------------------
68   ODGauge::~ODGauge()
69   {
70     clear();
71   }
72
73   //----------------------------------------------------------------------------
74   void ODGauge::setSystemAdapter(const SystemAdapterPtr& system_adapter)
75   {
76     _system_adapter = system_adapter;
77   }
78
79   //----------------------------------------------------------------------------
80   void ODGauge::setSize(int size_x, int size_y)
81   {
82     _size_x = size_x;
83     _size_y = size_y < 0 ? size_x : size_y;
84
85     if( serviceable() )
86       reinit();
87     else if( texture )
88       texture->setTextureSize(_size_x, _size_y);
89   }
90
91   //----------------------------------------------------------------------------
92   void ODGauge::setViewSize(int width, int height)
93   {
94     _view_width = width;
95     _view_height = height < 0 ? width : height;
96
97     if( camera )
98       updateCoordinateFrame();
99   }
100
101   //----------------------------------------------------------------------------
102   osg::Vec2s ODGauge::getViewSize() const
103   {
104     return osg::Vec2s(_view_width, _view_height);
105   }
106
107   //----------------------------------------------------------------------------
108   void ODGauge::useImageCoords(bool use)
109   {
110     if( updateFlag(USE_IMAGE_COORDS, use) && texture )
111       updateCoordinateFrame();
112   }
113
114   //----------------------------------------------------------------------------
115   void ODGauge::useStencil(bool use)
116   {
117     if( updateFlag(USE_STENCIL, use) && texture )
118       updateStencil();
119   }
120
121   //----------------------------------------------------------------------------
122   void ODGauge::useAdditiveBlend(bool use)
123   {
124     if( updateFlag(USE_ADDITIVE_BLEND, use) && camera )
125       updateBlendMode();
126   }
127
128   //----------------------------------------------------------------------------
129   void ODGauge::setSampling( bool mipmapping,
130                              int coverage_samples,
131                              int color_samples )
132   {
133     if(    !updateFlag(USE_MIPMAPPING, mipmapping)
134         && _coverage_samples == coverage_samples
135         && _color_samples == color_samples )
136       return;
137
138     if( color_samples > coverage_samples )
139     {
140       SG_LOG
141       (
142         SG_GL,
143         SG_WARN,
144         "ODGauge::setSampling: color_samples > coverage_samples not allowed!"
145       );
146       color_samples = coverage_samples;
147     }
148
149     _coverage_samples = coverage_samples;
150     _color_samples = color_samples;
151
152     updateSampling();
153   }
154
155   //----------------------------------------------------------------------------
156   void ODGauge::setRender(bool render)
157   {
158     // Only the far camera should trigger this texture to be rendered.
159     camera->setNodeMask(render ? simgear::BACKGROUND_BIT : 0);
160   }
161
162   //----------------------------------------------------------------------------
163   bool ODGauge::serviceable() const
164   {
165     return _flags & AVAILABLE;
166   }
167
168   //----------------------------------------------------------------------------
169   void ODGauge::allocRT(osg::NodeCallback* camera_cull_callback)
170   {
171     camera = new osg::Camera;
172     camera->setDataVariance(osg::Object::DYNAMIC);
173     camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
174     camera->setRenderOrder(osg::Camera::PRE_RENDER);
175     camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 0.0f));
176     camera->setClearStencil(0);
177     camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT,
178                                                osg::Camera::FRAME_BUFFER );
179
180     if( camera_cull_callback )
181       camera->setCullCallback(camera_cull_callback);
182
183     setRender(true);
184     updateCoordinateFrame();
185     updateStencil();
186
187     osg::StateSet* stateSet = camera->getOrCreateStateSet();
188     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
189     stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
190     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
191     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
192     stateSet->setAttributeAndModes(
193       new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK,
194                             osg::PolygonMode::FILL ),
195       osg::StateAttribute::ON );
196     stateSet->setAttributeAndModes(
197       new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.001f),
198       osg::StateAttribute::ON );
199     stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT));
200
201     if( !texture )
202     {
203       texture = new osg::Texture2D;
204       texture->setResizeNonPowerOfTwoHint(false);
205       texture->setTextureSize(_size_x, _size_y);
206       texture->setInternalFormat(GL_RGBA);
207     }
208
209     updateSampling();
210     updateBlendMode();
211
212     if( _system_adapter )
213       _system_adapter->addCamera(camera.get());
214
215     _flags |= AVAILABLE;
216   }
217
218   //----------------------------------------------------------------------------
219   void ODGauge::reinit()
220   {
221     osg::NodeCallback* cull_callback = camera ? camera->getCullCallback() : 0;
222     clear();
223     allocRT(cull_callback);
224   }
225
226   //----------------------------------------------------------------------------
227   void ODGauge::clear()
228   {
229     if( camera.valid() && _system_adapter )
230       _system_adapter->removeCamera(camera.get());
231     camera.release();
232     texture.release();
233
234     _flags &= ~AVAILABLE;
235   }
236
237   //----------------------------------------------------------------------------
238   bool ODGauge::updateFlag(Flags flag, bool enable)
239   {
240     if( bool(_flags & flag) == enable )
241       return false;
242
243     _flags ^= flag;
244     return true;
245   }
246
247   //----------------------------------------------------------------------------
248   void ODGauge::updateCoordinateFrame()
249   {
250     assert( camera );
251
252     if( _view_width < 0 )
253       _view_width = _size_x;
254     if( _view_height < 0 )
255       _view_height = _size_y;
256
257     camera->setViewport(0, 0, _size_x, _size_y);
258
259     if( _flags & USE_IMAGE_COORDS )
260       camera->setProjectionMatrix(
261         osg::Matrix::ortho2D(0, _view_width, _view_height, 0)
262       );
263     else
264       camera->setProjectionMatrix(
265         osg::Matrix::ortho2D( -_view_width/2.,  _view_width/2.,
266                               -_view_height/2., _view_height/2. )
267       );
268   }
269
270   //----------------------------------------------------------------------------
271   void ODGauge::updateStencil()
272   {
273     assert( camera );
274
275     GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
276
277     if( _flags & USE_STENCIL )
278     {
279       camera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER,
280                        GL_DEPTH_STENCIL_EXT );
281       mask |= GL_STENCIL_BUFFER_BIT;
282     }
283     else
284     {
285       camera->detach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER);
286     }
287
288     camera->setClearMask(mask);
289   }
290
291   //----------------------------------------------------------------------------
292   void ODGauge::updateSampling()
293   {
294     assert( camera );
295     assert( texture );
296
297     texture->setFilter(
298       osg::Texture2D::MIN_FILTER,
299       (_flags & USE_MIPMAPPING) ? osg::Texture2D::LINEAR_MIPMAP_LINEAR
300                                 : osg::Texture2D::LINEAR
301     );
302     camera->attach(
303       osg::Camera::COLOR_BUFFER,
304       texture.get(),
305       0, 0,
306       _flags & USE_MIPMAPPING,
307       _coverage_samples,
308       _color_samples
309     );
310   }
311
312   //----------------------------------------------------------------------------
313   void ODGauge::updateBlendMode()
314   {
315     assert( camera );
316
317     camera->getOrCreateStateSet()
318       ->setAttributeAndModes
319       (
320         (_flags & USE_ADDITIVE_BLEND)
321           ? new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA,
322                                 osg::BlendFunc::ONE_MINUS_SRC_ALPHA,
323                                 osg::BlendFunc::ONE,
324                                 osg::BlendFunc::ONE )
325           : new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA,
326                                 osg::BlendFunc::ONE_MINUS_SRC_ALPHA )
327       );
328   }
329
330 } // namespace canvas
331 } // namespace simgear