]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/ODGauge.cxx
Refactor Canvas and add some helpers.
[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     _use_image_coords( false ),
61     _use_stencil( false ),
62     _use_mipmapping( false ),
63     _coverage_samples( 0 ),
64     _color_samples( 0 ),
65     rtAvailable( false )
66   {
67
68   }
69
70   //----------------------------------------------------------------------------
71   ODGauge::~ODGauge()
72   {
73     if( camera.valid() && _system_adapter )
74       _system_adapter->removeCamera(camera.get());
75   }
76
77   //----------------------------------------------------------------------------
78   void ODGauge::setSystemAdapter(const SystemAdapterPtr& system_adapter)
79   {
80     _system_adapter = system_adapter;
81   }
82
83   //----------------------------------------------------------------------------
84   void ODGauge::setSize(int size_x, int size_y)
85   {
86     _size_x = size_x;
87     _size_y = size_y < 0 ? size_x : size_y;
88
89     if( texture.valid() )
90       texture->setTextureSize(_size_x, _size_x);
91   }
92
93   //----------------------------------------------------------------------------
94   void ODGauge::setViewSize(int width, int height)
95   {
96     _view_width = width;
97     _view_height = height < 0 ? width : height;
98
99     if( camera )
100       updateCoordinateFrame();
101   }
102
103   //----------------------------------------------------------------------------
104   void ODGauge::useImageCoords(bool use)
105   {
106     if( use == _use_image_coords )
107       return;
108
109     _use_image_coords = use;
110
111     if( texture )
112       updateCoordinateFrame();
113   }
114
115   //----------------------------------------------------------------------------
116   void ODGauge::useStencil(bool use)
117   {
118     if( use == _use_stencil )
119       return;
120
121     _use_stencil = use;
122
123     if( texture )
124       updateStencil();
125   }
126
127   //----------------------------------------------------------------------------
128   void ODGauge::setSampling( bool mipmapping,
129                                int coverage_samples,
130                                int color_samples )
131   {
132     if(    _use_mipmapping == mipmapping
133         && _coverage_samples == coverage_samples
134         && _color_samples == color_samples )
135       return;
136
137     _use_mipmapping = mipmapping;
138
139     if( color_samples > coverage_samples )
140     {
141       SG_LOG
142       (
143         SG_GL,
144         SG_WARN,
145         "ODGauge::setSampling: color_samples > coverage_samples not allowed!"
146       );
147       color_samples = coverage_samples;
148     }
149
150     _coverage_samples = coverage_samples;
151     _color_samples = color_samples;
152
153     updateSampling();
154   }
155
156   //----------------------------------------------------------------------------
157   void ODGauge::setRender(bool render)
158   {
159     // Only the far camera should trigger this texture to be rendered.
160     camera->setNodeMask(render ? simgear::BACKGROUND_BIT : 0);
161   }
162
163   //----------------------------------------------------------------------------
164   bool ODGauge::serviceable(void)
165   {
166     return rtAvailable;
167   }
168
169   //----------------------------------------------------------------------------
170   void ODGauge::allocRT(osg::NodeCallback* camera_cull_callback)
171   {
172     camera = new osg::Camera;
173     camera->setDataVariance(osg::Object::DYNAMIC);
174     camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
175     camera->setRenderOrder(osg::Camera::PRE_RENDER);
176     camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 0.0f));
177     camera->setClearStencil(0);
178     camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT,
179                                                osg::Camera::FRAME_BUFFER );
180
181     if( camera_cull_callback )
182       camera->setCullCallback(camera_cull_callback);
183
184     setRender(true);
185     updateCoordinateFrame();
186     updateStencil();
187
188     osg::StateSet* stateSet = camera->getOrCreateStateSet();
189     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
190     stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
191     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
192     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
193     stateSet->setAttributeAndModes(
194       new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK,
195                             osg::PolygonMode::FILL ),
196       osg::StateAttribute::ON );
197     stateSet->setAttributeAndModes(
198       new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.0f),
199       osg::StateAttribute::ON );
200     stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT));
201     stateSet->setAttributeAndModes(
202       new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA,
203                           osg::BlendFunc::ONE_MINUS_SRC_ALPHA),
204       osg::StateAttribute::ON );
205     if( !texture )
206     {
207       texture = new osg::Texture2D;
208       texture->setTextureSize(_size_x, _size_y);
209       texture->setInternalFormat(GL_RGBA);
210     }
211
212     updateSampling();
213
214     if( _system_adapter )
215       _system_adapter->addCamera(camera.get());
216
217     rtAvailable = true;
218   }
219
220   //----------------------------------------------------------------------------
221   void ODGauge::updateCoordinateFrame()
222   {
223     assert( camera );
224
225     if( _view_width < 0 )
226       _view_width = _size_x;
227     if( _view_height < 0 )
228       _view_height = _size_y;
229
230     camera->setViewport(0, 0, _size_x, _size_y);
231
232     if( _use_image_coords )
233       camera->setProjectionMatrix(
234         osg::Matrix::ortho2D(0, _view_width, _view_height, 0)
235       );
236     else
237       camera->setProjectionMatrix(
238         osg::Matrix::ortho2D( -_view_width/2.,  _view_width/2.,
239                               -_view_height/2., _view_height/2. )
240       );
241   }
242
243   //----------------------------------------------------------------------------
244   void ODGauge::updateStencil()
245   {
246     assert( camera );
247
248     GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
249
250     if( _use_stencil)
251     {
252       camera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER,
253                        GL_DEPTH_STENCIL_EXT );
254       mask |= GL_STENCIL_BUFFER_BIT;
255     }
256     else
257     {
258       camera->detach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER);
259     }
260
261     camera->setClearMask(mask);
262   }
263
264   //----------------------------------------------------------------------------
265   void ODGauge::updateSampling()
266   {
267     assert( camera );
268     assert( texture );
269
270     texture->setFilter(
271       osg::Texture2D::MIN_FILTER,
272       _use_mipmapping ? osg::Texture2D::LINEAR_MIPMAP_LINEAR
273                       : osg::Texture2D::LINEAR
274     );
275     camera->attach(
276       osg::Camera::COLOR_BUFFER,
277       texture.get(),
278       0, 0,
279       _use_mipmapping,
280       _coverage_samples,
281       _color_samples
282     );
283   }
284
285 } // namespace canvas
286 } // namespace simgear