1 // Wx Radar background texture
3 // Written by Harald JOHNSEN, started May 2005.
5 // Copyright (C) 2005 Harald JOHNSEN
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include <Main/fg_props.hxx>
29 #include <Main/globals.hxx>
30 #include <Cockpit/panel.hxx>
31 #include <Cockpit/hud.hxx>
33 #include <simgear/constants.h>
34 #include <simgear/misc/sg_path.hxx>
35 #include <simgear/environment/visual_enviro.hxx>
36 #include "instrument_mgr.hxx"
37 #include "od_gauge.hxx"
38 #include "wxradar.hxx"
40 // texture name to use in 2D and 3D instruments
41 static const char *odgauge_name = "Aircraft/Instruments/Textures/od_wxradar.rgb";
43 wxRadarBg::wxRadarBg ( SGPropertyNode *node) :
48 last_switchKnob( "off" ),
49 sim_init_done ( false ),
53 for ( i = 0; i < node->nChildren(); ++i ) {
54 SGPropertyNode *child = node->getChild(i);
55 string cname = child->getName();
56 string cval = child->getStringValue();
57 if ( cname == "name" ) {
59 } else if ( cname == "number" ) {
60 num = child->getIntValue();
62 SG_LOG( SG_INSTR, SG_WARN, "Error in wxRadar config logic" );
63 if ( name.length() ) {
64 SG_LOG( SG_INSTR, SG_WARN, "Section = " << name );
70 wxRadarBg::wxRadarBg ()
74 wxRadarBg::~wxRadarBg ()
82 branch = "/instrumentation/" + name;
84 _Instrument = fgGetNode(branch.c_str(), num, true );
85 _serviceable_node = _Instrument->getChild("serviceable", 0, true);
86 resultTexture = FGTextureManager::createTexture( odgauge_name );
87 SGPath tpath(globals->get_fg_root());
88 tpath.append("Aircraft/Instruments/Textures/wxecho.rgb");
89 // no mipmap or else alpha will mix with pixels on the border of shapes, ruining the effect
92 // wxEcho = new ssgTexture( tpath.c_str(), false, false, false);
93 wxEcho = new osg::Texture2D;
95 _Instrument->setFloatValue("trk", 0.0);
96 _Instrument->setFloatValue("tilt", 0.0);
97 _Instrument->setStringValue("status","");
98 // those properties are used by a radar instrument of a MFD
99 // input switch = OFF | TST | STBY | ON
100 // input mode = WX | WXA | MAP
101 // ouput status = STBY | TEST | WX | WXA | MAP | blank
102 // input lightning = true | false
103 // input TRK = +/- n degrees
104 // input TILT = +/- n degree
105 // input autotilt = true | false
106 // input range = n nm (20/40/80)
107 // input display-mode = arc | rose | map | plan
109 FGInstrumentMgr *imgr = (FGInstrumentMgr *) globals->get_subsystem("instrumentation");
110 odg = (FGODGauge *) imgr->get_subsystem("od_gauge");
114 wxRadarBg::update (double delta_time_sec)
118 if ( ! sim_init_done ) {
119 if ( ! fgGetBool("sim/sceneryloaded", false) )
121 sim_init_done = true;
123 if ( !odg || ! _serviceable_node->getBoolValue() ) {
124 _Instrument->setStringValue("status","");
127 string switchKnob = _Instrument->getStringValue("switch", "on");
128 string modeButton = _Instrument->getStringValue("mode", "wx");
129 bool drawLightning = _Instrument->getBoolValue("lightning", true);
130 float range_nm = _Instrument->getFloatValue("range", 40.0);
131 float range_m = range_nm * SG_NM_TO_METER;
133 if ( last_switchKnob != switchKnob ) {
134 // since 3D models don't share textures with the rest of the world
135 // we must locate them and replace their handle by hand
136 // only do that when the instrument is turned on
137 if ( last_switchKnob == "off" )
138 odg->set_texture( odgauge_name, resultTexture.get());
139 last_switchKnob = switchKnob;
141 FGViewer *current__view = globals->get_current_view();
142 if ( current__view->getInternal() &&
143 (current__view->getHeadingOffset_deg() <= 15.0 || current__view->getHeadingOffset_deg() >= 345.0) &&
144 (current__view->getPitchOffset_deg() <= 15.0 || current__view->getPitchOffset_deg() >= 350.0) ) {
146 // we don't update the radar echo if the pilot looks around
148 radarEchoBuffer = *sgEnviro.get_radar_echo();
150 odg->beginCapture(256);
153 glMatrixMode(GL_MODELVIEW);
156 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
157 glBindTexture(GL_TEXTURE_2D, 0);
159 if ( switchKnob == "off" ) {
160 _Instrument->setStringValue("status","");
161 } else if ( switchKnob == "stby" ) {
162 _Instrument->setStringValue("status","STBY");
163 } else if ( switchKnob == "tst" ) {
164 _Instrument->setStringValue("status","TST");
165 // find something interesting to do...
167 string display_mode = _Instrument->getStringValue("display-mode", "arc");
169 // pretend we have a scan angle bigger then the FOV
170 // TODO:check real fov, enlarge if < nn, and do clipping if > mm
171 const float fovFactor = 1.45f;
172 float view_heading = get_heading() * SG_DEGREES_TO_RADIANS;
173 float range = 200.0f / range_nm;
174 _Instrument->setStringValue("status", modeButton.c_str());
175 if ( display_mode == "arc" ) {
176 glTranslatef(0.0f, -180.0f, 0.0f);
177 range = 2*180.0f / range_nm;
178 } else if ( display_mode == "map" ) {
179 // float view_heading = get_track() * SG_DEGREES_TO_RADIANS;
180 } else if ( display_mode == "plan" ) {
181 // no sense I presume
186 range /= SG_NM_TO_METER;
187 // we will rotate the echo quads, this gives a better rendering
188 const float rot_x = cos ( view_heading );
189 const float rot_y = sin ( view_heading );
191 list_of_SGWxRadarEcho *radarEcho = &radarEchoBuffer;
192 list_of_SGWxRadarEcho::iterator iradarEcho;
193 const float LWClevel[] = { 0.1f, 0.5f, 2.1f };
194 const float symbolSize = 1.0f / 8.0f ;
195 // draw the radar echo, we do that in 3 passes, one for each color level
196 // this is to 'merge' same colors together
198 // glBindTexture(GL_TEXTURE_2D, wxEcho->getHandle() );
199 glColor3f(1.0f, 1.0f, 1.0f);
202 for (int level = 0; level <= 2 ; level++ ) {
203 float col = level * symbolSize;
204 for (iradarEcho = radarEcho->begin() ; iradarEcho != radarEcho->end() ; iradarEcho++ ) {
205 int cloudId = (iradarEcho->cloudId) ;
206 bool upgrade = ((cloudId >> 5) & 1);
207 float lwc = iradarEcho->LWC + (upgrade ? 1.0f : 0.0f);
209 if ( iradarEcho->LWC >= 0.5 && iradarEcho->LWC <= 0.6)
211 if ( (! iradarEcho->lightning) && ( lwc >= LWClevel[level]) ) {
212 float dist = sgSqrt( iradarEcho->dist );
213 float size = iradarEcho->radius * 2.0;
214 if ( dist - size > range_m )
218 // compute the relative angle from the view direction
219 float angle = ( view_heading + iradarEcho->heading );
222 if ( angle < - SG_PI )
224 // and apply a fov factor to simulate a greater scan angle
225 angle = angle * fovFactor + SG_PI / 2.0;
226 float x = cos( angle ) * dist;
227 float y = sin( angle ) * dist;
228 // use different shapes so the display is less boring
229 float row = symbolSize * (float) (4 + (cloudId & 3) );
230 float size_x = rot_x * size;
231 float size_y = rot_y * size;
232 glTexCoord2f( col, row);
233 glVertex2f( x - size_x, y - size_y);
234 glTexCoord2f( col+symbolSize, row);
235 glVertex2f( x + size_y, y - size_x);
236 glTexCoord2f( col+symbolSize, row+symbolSize);
237 glVertex2f( x + size_x, y + size_y);
238 glTexCoord2f( col, row+symbolSize);
239 glVertex2f( x - size_y, y + size_x);
245 // draw lightning echos
246 if ( drawLightning ) {
247 float col = 3 * symbolSize;
248 float row = 4 * symbolSize;
249 for (iradarEcho = radarEcho->begin() ; iradarEcho != radarEcho->end() ; iradarEcho++ ) {
250 if ( iradarEcho->lightning ) {
251 float dist = iradarEcho->dist;
253 float angle = (view_heading - iradarEcho->heading);
256 if ( angle < - SG_PI )
258 angle = angle * fovFactor - SG_PI / 2.0;
259 float x = cos( angle ) * dist;
260 float y = sin( angle ) * dist;
261 glColor3f(1.0f, 1.0f, 1.0f);
262 float size = symbolSize * 0.5f;
264 glTexCoord2f( col, row);
265 glVertex2f( x - size, y - size);
266 glTexCoord2f( col+symbolSize, row);
267 glVertex2f( x + size, y - size);
268 glTexCoord2f( col+symbolSize, row+symbolSize);
269 glVertex2f( x + size, y + size);
270 glTexCoord2f( col, row+symbolSize);
271 glVertex2f( x - size, y + size);
276 // erase what is out of sight of antenna
286 float yOffset = 180.0f, xOffset = 256.0f;
288 if ( display_mode != "arc" ) {
293 if ( display_mode != "plan" ) {
295 glColor4f(1.0f, 0.0f, 0.0f, 0.01f);
297 glTexCoord2f( 0.5f, 0.25f);
298 glVertex2f(-xOffset, 0.0 + yOffset);
299 glTexCoord2f( 1.0f, 0.25f);
300 glVertex2f(xOffset, 0.0 + yOffset);
301 glTexCoord2f( 1.0f, 0.5f);
302 glVertex2f(xOffset, 256.0 + yOffset);
303 glTexCoord2f( 0.5f, 0.5f);
304 glVertex2f(-xOffset, 256.0 + yOffset);
307 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
308 // glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
309 glDisable(GL_ALPHA_TEST);
310 glBindTexture(GL_TEXTURE_2D, 0);
312 glBegin( GL_TRIANGLES );
313 glVertex2f(0.0, 0.0);
314 glVertex2f(-256.0, 0.0);
315 glVertex2f(-256.0, 256.0 * tan(30*SG_DEGREES_TO_RADIANS));
317 glVertex2f(0.0, 0.0);
318 glVertex2f(256.0, 0.0);
319 glVertex2f(256.0, 256.0 * tan(30*SG_DEGREES_TO_RADIANS));
321 glVertex2f(-256, 0.0);
322 glVertex2f(256.0, 0.0);
323 glVertex2f(-256.0, -256.0);
325 glVertex2f(256, 0.0);
326 glVertex2f(256.0, -256.0);
327 glVertex2f(-256.0, -256.0);
332 /* glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
334 glVertex2f(0.0, 0.0);
335 glVertex2f(-256.0, 256.0);
336 glVertex2f(0.0, 0.0);
337 glVertex2f(256.0, 256.0);
341 glEnable(GL_ALPHA_TEST);
344 odg->endCapture( resultTexture.get() );