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