]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/wxradar.cxx
a6dea2399ffaf992e27d5b50834d4ef7484f7aad
[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 - hjohnsen@evc.net
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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20 //
21 //
22
23 #include <plib/sg.h>
24 #include <plib/ssg.h>
25 #include <Main/fg_props.hxx>
26 #include <Main/globals.hxx>
27 #include <Cockpit/panel.hxx>
28 #include <Cockpit/hud.hxx>
29
30 #include <simgear/constants.h>
31 #include <simgear/misc/sg_path.hxx>
32 #include <simgear/environment/visual_enviro.hxx>
33 #include "instrument_mgr.hxx"
34 #include "od_gauge.hxx"
35 #include "wxradar.hxx"
36
37 // texture name to use in 2D and 3D instruments
38 static const char *odgauge_name = "Aircraft/Instruments/Textures/od_wxradar.rgb";
39
40 wxRadarBg::wxRadarBg ( SGPropertyNode *node) :
41     name("wxRadar"),
42     num(0),
43     resultTexture( 0 ),
44     wxEcho( 0 ),
45     last_switchKnob( "off" ),
46     sim_init_done ( false ),
47     odg( 0 )
48 {
49     int i;
50     for ( i = 0; i < node->nChildren(); ++i ) {
51         SGPropertyNode *child = node->getChild(i);
52         string cname = child->getName();
53         string cval = child->getStringValue();
54         if ( cname == "name" ) {
55             name = cval;
56         } else if ( cname == "number" ) {
57             num = child->getIntValue();
58         } else {
59             SG_LOG( SG_INSTR, SG_WARN, "Error in wxRadar config logic" );
60             if ( name.length() ) {
61                 SG_LOG( SG_INSTR, SG_WARN, "Section = " << name );
62             }
63         }
64     }
65 }
66
67 wxRadarBg::wxRadarBg ()
68 {
69 }
70
71 wxRadarBg::~wxRadarBg ()
72 {
73     ssgDeRefDelete(resultTexture);
74     ssgDeRefDelete(wxEcho);
75 }
76
77 void
78 wxRadarBg::init ()
79 {
80     string branch;
81     branch = "/instrumentation/" + name;
82
83     _Instrument = fgGetNode(branch.c_str(), num, true );
84     _serviceable_node = _Instrument->getChild("serviceable", 0, true);
85     resultTexture = FGTextureManager::createTexture( odgauge_name );
86     resultTexture->ref();
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     wxEcho = new ssgTexture( tpath.c_str(), false, false, false);
91     wxEcho->ref();
92
93     _Instrument->setFloatValue("trk", 0.0);
94     _Instrument->setFloatValue("tilt", 0.0);
95     _Instrument->setStringValue("status","");
96     // those properties are used by a radar instrument of a MFD
97     // input switch = OFF | TST | STBY | ON
98     // input mode = WX | WXA | MAP
99     // ouput status = STBY | TEST | WX | WXA | MAP | blank
100     // input lightning = true | false
101     // input TRK = +/- n degrees
102     // input TILT = +/- n degree
103     // input autotilt = true | false
104     // input range = n nm (20/40/80)
105     // input display-mode = arc | rose | map | plan
106
107     FGInstrumentMgr *imgr = (FGInstrumentMgr *) globals->get_subsystem("instrumentation");
108     odg = (FGODGauge *) imgr->get_subsystem("od_gauge");
109 }
110
111 void
112 wxRadarBg::update (double delta_time_sec)
113 {
114     if( ! sim_init_done ) {
115         if( ! fgGetBool("sim/sceneryloaded", false) )
116             return;
117         sim_init_done = true;
118     }
119     if ( !odg || ! _serviceable_node->getBoolValue() ) {
120         _Instrument->setStringValue("status","");
121         return;
122     }
123     string switchKnob = _Instrument->getStringValue("switch", "on");
124     string modeButton = _Instrument->getStringValue("mode", "wx");
125     bool drawLightning = _Instrument->getBoolValue("lightning", true);
126     float range_nm = _Instrument->getFloatValue("range", 40.0);
127     float range_m = range_nm * SG_NM_TO_METER;
128
129     if( last_switchKnob != switchKnob ) {
130         // since 3D models don't share textures with the rest of the world
131         // we must locate them and replace their handle by hand
132         // only do that when the instrument is turned on
133         if( last_switchKnob == "off" )
134             odg->set_texture( odgauge_name, resultTexture->getHandle());
135         last_switchKnob = switchKnob;
136     }
137     odg->beginCapture(256);
138     odg->Clear();
139     glMatrixMode(GL_MODELVIEW);
140     glLoadIdentity();
141     glPushMatrix();
142         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
143         glBindTexture(GL_TEXTURE_2D, 0);
144         if( switchKnob == "off" ) {
145             _Instrument->setStringValue("status","");
146         } else if( switchKnob == "stby" ) {
147             _Instrument->setStringValue("status","STBY");
148         } else if( switchKnob == "tst" ) {
149             _Instrument->setStringValue("status","TST");
150             // find something interesting to do...
151         } else {
152             string display_mode = _Instrument->getStringValue("display-mode", "arc");
153             // pretend we have a scan angle bigger then the FOV
154             // TODO:check real fov, enlarge if < nn, and do clipping if > mm
155             const float fovFactor = 1.45f;
156             float view_heading = get_heading() * SG_DEGREES_TO_RADIANS;
157             float range = 200.0f / range_nm;
158             _Instrument->setStringValue("status", modeButton.c_str());
159             if( display_mode == "arc" ) {
160                 glTranslatef(0.0f, -180.0f, 0.0f);
161                 range = 2*180.0f / range_nm;
162             } else if( display_mode == "map" ) {
163 //                float view_heading = get_track() * SG_DEGREES_TO_RADIANS;
164             } else if( display_mode == "plan" ) {
165                 // no sense I presume
166                 float view_heading = 0.0;
167             } else {
168                 // rose
169             }
170             range /= SG_NM_TO_METER;
171             // we will rotate the echo quads, this gives a better rendering
172             const float rot_x = cos ( view_heading );
173             const float rot_y = sin ( view_heading );
174
175             list_of_SGWxRadarEcho *radarEcho = sgEnviro.get_radar_echo();
176             list_of_SGWxRadarEcho::iterator iradarEcho;
177             const float LWClevel[] = { 0.1f, 0.5f, 2.1f };
178             const float symbolSize = 1.0f / 8.0f ;
179             // draw the radar echo, we do that in 3 passes, one for each color level
180             // this is to 'merge' same colors together
181             glBindTexture(GL_TEXTURE_2D, wxEcho->getHandle() );
182             glColor3f(1.0f, 1.0f, 1.0f);
183             glBegin( GL_QUADS );
184
185             for(int level = 0; level <= 2 ; level++ ) {
186                 float col = level * symbolSize;
187                 for(iradarEcho = radarEcho->begin() ; iradarEcho != radarEcho->end() ; iradarEcho++ ) {
188                     int cloudId = (iradarEcho->cloudId) ;
189                     bool upgrade = ((cloudId >> 5) & 1);
190                     float lwc = iradarEcho->LWC + (upgrade ? 1.0f : 0.0f);
191                     // skip ns
192                     if( iradarEcho->LWC >= 0.5 && iradarEcho->LWC <= 0.6)
193                         continue;
194                     if( (! iradarEcho->lightning) && ( lwc >= LWClevel[level]) ) {
195                         float dist = sgSqrt( iradarEcho->dist );
196                         float size = iradarEcho->radius * 2.0;
197                         if( dist - size > range_m )
198                             continue;
199                         dist = dist * range;
200                         size = size * range;
201                         // compute the relative angle from the view direction
202                         float angle = ( view_heading + iradarEcho->heading );
203                         if( angle > SG_PI )
204                             angle -= 2.0*SG_PI;
205                         if( angle < - SG_PI )
206                             angle += 2.0*SG_PI;
207                         // and apply a fov factor to simulate a greater scan angle
208                         angle =  angle * fovFactor + SG_PI / 2.0;
209                         float x = cos( angle ) * dist;
210                         float y = sin( angle ) * dist;
211                         // use different shapes so the display is less boring
212                         float row = symbolSize * (float) (4 + (cloudId & 3) );
213                         float size_x = rot_x * size;
214                         float size_y = rot_y * size;
215                         glTexCoord2f( col, row);
216                         glVertex2f( x - size_x, y - size_y);
217                         glTexCoord2f( col+symbolSize, row);
218                         glVertex2f( x + size_y, y - size_x);
219                         glTexCoord2f( col+symbolSize, row+symbolSize);
220                         glVertex2f( x + size_x, y + size_y);
221                         glTexCoord2f( col, row+symbolSize);
222                         glVertex2f( x - size_y, y + size_x);
223                     }
224                 }
225             }
226             glEnd(); // GL_QUADS
227
228             // draw lightning echos
229             if( drawLightning ) {
230                 float col = 3 * symbolSize;
231                 float row = 4 * symbolSize;
232                 for(iradarEcho = radarEcho->begin() ; iradarEcho != radarEcho->end() ; iradarEcho++ ) {
233                     if( iradarEcho->lightning ) {
234                         float dist = iradarEcho->dist;
235                         dist = dist * range;
236                         float angle = (view_heading - iradarEcho->heading);
237                         if( angle > SG_PI )
238                             angle -= 2.0*SG_PI;
239                         if( angle < - SG_PI )
240                             angle += 2.0*SG_PI;
241                         angle =  angle * fovFactor - SG_PI / 2.0;
242                         float x = cos( angle ) * dist;
243                         float y = sin( angle ) * dist;
244                         glColor3f(1.0f, 1.0f, 1.0f);
245                         float size = symbolSize * 0.5f;
246                         glBegin( GL_QUADS );
247                             glTexCoord2f( col, row);
248                             glVertex2f( x - size, y - size);
249                             glTexCoord2f( col+symbolSize, row);
250                             glVertex2f( x + size, y - size);
251                             glTexCoord2f( col+symbolSize, row+symbolSize);
252                             glVertex2f( x + size, y + size);
253                             glTexCoord2f( col, row+symbolSize);
254                             glVertex2f( x - size, y + size);
255                         glEnd();
256                     }
257                 }
258             }
259             // erase what is out of sight of antenna
260             /*
261                 |\     /|
262                 | \   / |
263                 |  \ /  |
264                 ---------
265                 |       |
266                 |       |
267                 ---------
268             */
269             float yOffset = 180.0f, xOffset = 256.0f;
270             if( display_mode != "arc" ) {
271                 yOffset = 40.0f;
272                 xOffset = 240.0f;
273             }
274              glDisable(GL_BLEND);
275                glColor4f(1.0f, 0.0f, 0.0f, 0.01f);
276             glBegin( GL_QUADS );
277                 glTexCoord2f( 0.5f, 0.25f);
278                 glVertex2f(-xOffset, 0.0 + yOffset);
279                 glTexCoord2f( 1.0f, 0.25f);
280                 glVertex2f(xOffset, 0.0 + yOffset);
281                 glTexCoord2f( 1.0f, 0.5f);
282                 glVertex2f(xOffset, 256.0 + yOffset);
283                 glTexCoord2f( 0.5f, 0.5f);
284                 glVertex2f(-xOffset, 256.0 + yOffset);
285             glEnd();
286
287             glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
288 //            glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
289             glDisable(GL_ALPHA_TEST);
290             glBindTexture(GL_TEXTURE_2D, 0);
291
292             glBegin( GL_TRIANGLES );
293                 glVertex2f(0.0, 0.0);
294                 glVertex2f(-256.0, 0.0);
295                 glVertex2f(-256.0, 256.0);
296
297                 glVertex2f(0.0, 0.0);
298                 glVertex2f(256.0, 0.0);
299                 glVertex2f(256.0, 256.0);
300
301                 glVertex2f(-256, 0.0);
302                 glVertex2f(256.0, 0.0);
303                 glVertex2f(-256.0, -256.0);
304
305                 glVertex2f(256, 0.0);
306                 glVertex2f(256.0, -256.0);
307                 glVertex2f(-256.0, -256.0);
308             glEnd();
309
310             // DEBUG only
311 /*            glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
312             glBegin( GL_LINES );
313                 glVertex2f(0.0, 0.0);
314                 glVertex2f(-256.0, 256.0);
315                 glVertex2f(0.0, 0.0);
316                 glVertex2f(256.0, 256.0);
317             glEnd();*/
318
319             glEnable(GL_BLEND);
320             glEnable(GL_ALPHA_TEST);
321         }
322     glPopMatrix();
323     odg->endCapture( resultTexture->getHandle() );
324 }