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