]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/ODGauge.cxx
Move FGODGauge from FlightGear to SimGear.
[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 program is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU General Public License as
15 // published by the Free Software Foundation; either version 2 of the
16 // License, or (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful, but
19 // WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 // General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26 //
27 //
28
29 #ifdef HAVE_CONFIG_H
30 #  include <simgear_config.h>
31 #endif
32
33 #include <osg/Texture2D>
34 #include <osg/AlphaFunc>
35 #include <osg/BlendFunc>
36 #include <osg/Camera>
37 #include <osg/Matrix>
38 #include <osg/PolygonMode>
39 #include <osg/ShadeModel>
40 #include <osg/StateSet>
41 #include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
42
43 #include <simgear/debug/logstream.hxx>
44 #include <simgear/scene/util/RenderConstants.hxx>
45 #include "ODGauge.hxx"
46
47 #include <cassert>
48
49 namespace simgear
50 {
51
52 //------------------------------------------------------------------------------
53 ODGauge::ODGauge( const CameraRegistrationCallback& cb_camera_add,
54                   const CameraRegistrationCallback& cb_camera_remove ):
55   _size_x( -1 ),
56   _size_y( -1 ),
57   _view_width( -1 ),
58   _view_height( -1 ),
59   _use_image_coords( false ),
60   _use_stencil( false ),
61   _use_mipmapping( false ),
62   _coverage_samples( 0 ),
63   _color_samples( 0 ),
64   rtAvailable( false ),
65   _cb_cam_add( cb_camera_add ),
66   _cb_cam_remove( cb_camera_remove )
67 {
68
69 }
70
71 //------------------------------------------------------------------------------
72 ODGauge::~ODGauge()
73 {
74   if( camera.valid() )
75     _cb_cam_remove(camera.get());
76 }
77
78 //------------------------------------------------------------------------------
79 void ODGauge::setSize(int size_x, int size_y)
80 {
81   _size_x = size_x;
82   _size_y = size_y < 0 ? size_x : size_y;
83
84   if( texture.valid() )
85     texture->setTextureSize(_size_x, _size_x);
86 }
87
88 //----------------------------------------------------------------------------
89 void ODGauge::setViewSize(int width, int height)
90 {
91   _view_width = width;
92   _view_height = height < 0 ? width : height;
93
94   if( camera )
95     updateCoordinateFrame();
96 }
97
98 //------------------------------------------------------------------------------
99 void ODGauge::useImageCoords(bool use)
100 {
101   if( use == _use_image_coords )
102     return;
103
104   _use_image_coords = use;
105
106   if( texture )
107     updateCoordinateFrame();
108 }
109
110 //------------------------------------------------------------------------------
111 void ODGauge::useStencil(bool use)
112 {
113   if( use == _use_stencil )
114     return;
115
116   _use_stencil = use;
117
118   if( texture )
119     updateStencil();
120 }
121
122 //------------------------------------------------------------------------------
123 void ODGauge::setSampling( bool mipmapping,
124                              int coverage_samples,
125                              int color_samples )
126 {
127   if(    _use_mipmapping == mipmapping
128       && _coverage_samples == coverage_samples
129       && _color_samples == color_samples )
130     return;
131
132   _use_mipmapping = mipmapping;
133
134   if( color_samples > coverage_samples )
135   {
136     SG_LOG
137     (
138       SG_GL,
139       SG_WARN,
140       "ODGauge::setSampling: color_samples > coverage_samples not allowed!"
141     );
142     color_samples = coverage_samples;
143   }
144
145   _coverage_samples = coverage_samples;
146   _color_samples = color_samples;
147
148   updateSampling();
149 }
150
151 //------------------------------------------------------------------------------
152 void ODGauge::setRender(bool render)
153 {
154   // Only the far camera should trigger this texture to be rendered.
155   camera->setNodeMask(render ? simgear::BACKGROUND_BIT : 0);
156 }
157
158 //------------------------------------------------------------------------------
159 bool ODGauge::serviceable(void)
160 {
161   return rtAvailable;
162 }
163
164 //------------------------------------------------------------------------------
165 void ODGauge::allocRT(osg::NodeCallback* camera_cull_callback)
166 {
167   camera = new osg::Camera;
168   camera->setDataVariance(osg::Object::DYNAMIC);
169   camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
170   camera->setRenderOrder(osg::Camera::PRE_RENDER);
171   camera->setClearColor(osg::Vec4(0.0f, 0.0f, 0.0f , 0.0f));
172   camera->setClearStencil(0);
173   camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT,
174                                              osg::Camera::FRAME_BUFFER );
175
176   if( camera_cull_callback )
177     camera->setCullCallback(camera_cull_callback);
178
179   setRender(true);
180   updateCoordinateFrame();
181   updateStencil();
182
183   osg::StateSet* stateSet = camera->getOrCreateStateSet();
184   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
185   stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
186   stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
187   stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
188   stateSet->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,
189           osg::PolygonMode::FILL),
190           osg::StateAttribute::ON);
191   stateSet->setAttributeAndModes(new osg::AlphaFunc(osg::AlphaFunc::GREATER,
192           0.0f),
193           osg::StateAttribute::ON);
194   stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT));
195   stateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA,
196           osg::BlendFunc::ONE_MINUS_SRC_ALPHA),
197           osg::StateAttribute::ON);
198   if( !texture )
199   {
200     texture = new osg::Texture2D;
201     texture->setTextureSize(_size_x, _size_y);
202     texture->setInternalFormat(GL_RGBA);
203   }
204
205   updateSampling();
206
207   _cb_cam_add(camera.get());
208   rtAvailable = true;
209 }
210
211 //------------------------------------------------------------------------------
212 void ODGauge::updateCoordinateFrame()
213 {
214   assert( camera );
215
216   if( _view_width < 0 )
217     _view_width = _size_x;
218   if( _view_height < 0 )
219     _view_height = _size_y;
220
221   camera->setViewport(0, 0, _size_x, _size_y);
222
223   if( _use_image_coords )
224     camera->setProjectionMatrix(
225       osg::Matrix::ortho2D(0, _view_width, _view_height, 0)
226     );
227   else
228     camera->setProjectionMatrix(
229       osg::Matrix::ortho2D( -_view_width/2.,  _view_width/2.,
230                             -_view_height/2., _view_height/2. )
231     );
232 }
233
234 //------------------------------------------------------------------------------
235 void ODGauge::updateStencil()
236 {
237   assert( camera );
238
239   GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
240
241   if( _use_stencil)
242   {
243     camera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER,
244                      GL_DEPTH_STENCIL_EXT );
245     mask |= GL_STENCIL_BUFFER_BIT;
246   }
247   else
248   {
249     camera->detach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER);
250   }
251
252   camera->setClearMask(mask);
253 }
254
255 //------------------------------------------------------------------------------
256 void ODGauge::updateSampling()
257 {
258   assert( camera );
259   assert( texture );
260
261   texture->setFilter(
262     osg::Texture2D::MIN_FILTER,
263     _use_mipmapping ? osg::Texture2D::LINEAR_MIPMAP_LINEAR
264                     : osg::Texture2D::LINEAR
265   );
266   camera->attach(
267     osg::Camera::COLOR_BUFFER,
268     texture.get(),
269     0, 0,
270     _use_mipmapping,
271     _coverage_samples,
272     _color_samples
273   );
274 }
275
276 } // namespace simgear