]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/wxradar.cxx
1a879ed5f019b3aa93f1bf46021326f8c5920112
[flightgear.git] / src / Instrumentation / wxradar.cxx
1 // Wx Radar background texture
2 //
3 // Written by Harald JOHNSEN, started May 2005.
4 //
5 // Copyright (C) 2005  Harald JOHNSEN
6 //
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.
11 //
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.
16 //
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.
20 //
21 //
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 #include <plib/sg.h>
28 #include <Main/fg_props.hxx>
29 #include <Main/globals.hxx>
30 #include <Cockpit/panel.hxx>
31 #include <Cockpit/hud.hxx>
32
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"
39
40 // texture name to use in 2D and 3D instruments
41 static const char *odgauge_name = "Aircraft/Instruments/Textures/od_wxradar.rgb";
42
43 wxRadarBg::wxRadarBg ( SGPropertyNode *node) :
44     name("wxRadar"),
45     num(0),
46     resultTexture( 0 ),
47     wxEcho( 0 ),
48     last_switchKnob( "off" ),
49     sim_init_done ( false ),
50     odg( 0 )
51 {
52     int i;
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" ) {
58             name = cval;
59         } else if ( cname == "number" ) {
60             num = child->getIntValue();
61         } else {
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 );
65             }
66         }
67     }
68 }
69
70 wxRadarBg::wxRadarBg ()
71 {
72 }
73
74 wxRadarBg::~wxRadarBg ()
75 {
76 }
77
78 void
79 wxRadarBg::init ()
80 {
81     string branch;
82     branch = "/instrumentation/" + name;
83
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
90
91     // OSGFIXME
92 //     wxEcho = new ssgTexture( tpath.c_str(), false, false, false);
93     wxEcho = new osg::Texture2D;
94
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
108
109     FGInstrumentMgr *imgr = (FGInstrumentMgr *) globals->get_subsystem("instrumentation");
110     odg = (FGODGauge *) imgr->get_subsystem("od_gauge");
111 }
112
113 void
114 wxRadarBg::update (double delta_time_sec)
115 {
116   //OSGFIXME
117 #if 0
118     if ( ! sim_init_done ) {
119         if ( ! fgGetBool("sim/sceneryloaded", false) )
120             return;
121         sim_init_done = true;
122     }
123     if ( !odg || ! _serviceable_node->getBoolValue() ) {
124         _Instrument->setStringValue("status","");
125         return;
126     }
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;
132
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;
140     }
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) ) {
145
146         // we don't update the radar echo if the pilot looks around
147         // this is a copy
148         radarEchoBuffer = *sgEnviro.get_radar_echo();
149     }
150     odg->beginCapture(256);
151     odg->Clear();
152
153     glMatrixMode(GL_MODELVIEW);
154     glLoadIdentity();
155     glPushMatrix();
156     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
157     glBindTexture(GL_TEXTURE_2D, 0);
158
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...
166     } else {
167         string display_mode = _Instrument->getStringValue("display-mode", "arc");
168
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
182             view_heading = 0;
183         } else {
184             // rose
185         }
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 );
190
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
197         // OSGFIXME
198 //         glBindTexture(GL_TEXTURE_2D, wxEcho->getHandle() );
199         glColor3f(1.0f, 1.0f, 1.0f);
200         glBegin( GL_QUADS );
201
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);
208                 // skip ns
209                 if ( iradarEcho->LWC >= 0.5 && iradarEcho->LWC <= 0.6)
210                     continue;
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 )
215                         continue;
216                     dist = dist * range;
217                     size = size * range;
218                     // compute the relative angle from the view direction
219                     float angle = ( view_heading + iradarEcho->heading );
220                     if ( angle > SG_PI )
221                         angle -= 2.0*SG_PI;
222                     if ( angle < - SG_PI )
223                         angle += 2.0*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);
240                 }
241             }
242         }
243         glEnd(); // GL_QUADS
244
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;
252                     dist = dist * range;
253                     float angle = (view_heading - iradarEcho->heading);
254                     if ( angle > SG_PI )
255                         angle -= 2.0*SG_PI;
256                     if ( angle < - SG_PI )
257                         angle += 2.0*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;
263                     glBegin( GL_QUADS );
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);
272                     glEnd();
273                 }
274             }
275         }
276         // erase what is out of sight of antenna
277         /*
278             |\     /|
279             | \   / |
280             |  \ /  |
281             ---------
282             |       |
283             |       |
284             ---------
285         */
286         float yOffset = 180.0f, xOffset = 256.0f;
287
288         if ( display_mode != "arc" ) {
289             yOffset = 40.0f;
290             xOffset = 240.0f;
291         }
292
293         if ( display_mode != "plan" ) {
294             glDisable(GL_BLEND);
295             glColor4f(1.0f, 0.0f, 0.0f, 0.01f);
296             glBegin( GL_QUADS );
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);
305             glEnd();
306
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);
311
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));
316
317             glVertex2f(0.0, 0.0);
318             glVertex2f(256.0, 0.0);
319             glVertex2f(256.0, 256.0 * tan(30*SG_DEGREES_TO_RADIANS));
320
321             glVertex2f(-256, 0.0);
322             glVertex2f(256.0, 0.0);
323             glVertex2f(-256.0, -256.0);
324
325             glVertex2f(256, 0.0);
326             glVertex2f(256.0, -256.0);
327             glVertex2f(-256.0, -256.0);
328             glEnd();
329         }
330
331         // DEBUG only
332 /*      glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
333         glBegin( GL_LINES );
334         glVertex2f(0.0, 0.0);
335         glVertex2f(-256.0, 256.0);
336         glVertex2f(0.0, 0.0);
337         glVertex2f(256.0, 256.0);
338         glEnd();*/
339
340         glEnable(GL_BLEND);
341         glEnable(GL_ALPHA_TEST);
342     }
343     glPopMatrix();
344     odg->endCapture( resultTexture.get() );
345 #endif
346 }