]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/wxradar.cxx
Roy Vegard Ovesen:
[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(node->getStringValue("name", "wxRadar")),
45     _num(node->getIntValue("number", 0)),
46     resultTexture( 0 ),
47     wxEcho( 0 ),
48     last_switchKnob( "off" ),
49     sim_init_done ( false ),
50     odg( 0 )
51 {
52 }
53
54 wxRadarBg::~wxRadarBg ()
55 {
56 }
57
58 void
59 wxRadarBg::init ()
60 {
61     string branch;
62     branch = "/instrumentation/" + _name;
63
64     _Instrument = fgGetNode(branch.c_str(), _num, true );
65     _serviceable_node = _Instrument->getChild("serviceable", 0, true);
66     resultTexture = FGTextureManager::createTexture( odgauge_name );
67     SGPath tpath(globals->get_fg_root());
68     tpath.append("Aircraft/Instruments/Textures/wxecho.rgb");
69     // no mipmap or else alpha will mix with pixels on the border of shapes, ruining the effect
70
71     // OSGFIXME
72 //     wxEcho = new ssgTexture( tpath.c_str(), false, false, false);
73     wxEcho = new osg::Texture2D;
74
75     _Instrument->setFloatValue("trk", 0.0);
76     _Instrument->setFloatValue("tilt", 0.0);
77     _Instrument->setStringValue("status","");
78     // those properties are used by a radar instrument of a MFD
79     // input switch = OFF | TST | STBY | ON
80     // input mode = WX | WXA | MAP
81     // ouput status = STBY | TEST | WX | WXA | MAP | blank
82     // input lightning = true | false
83     // input TRK = +/- n degrees
84     // input TILT = +/- n degree
85     // input autotilt = true | false
86     // input range = n nm (20/40/80)
87     // input display-mode = arc | rose | map | plan
88
89     FGInstrumentMgr *imgr = (FGInstrumentMgr *) globals->get_subsystem("instrumentation");
90     odg = (FGODGauge *) imgr->get_subsystem("od_gauge");
91 }
92
93 void
94 wxRadarBg::update (double delta_time_sec)
95 {
96   //OSGFIXME
97 #if 0
98     if ( ! sim_init_done ) {
99         if ( ! fgGetBool("sim/sceneryloaded", false) )
100             return;
101         sim_init_done = true;
102     }
103     if ( !odg || ! _serviceable_node->getBoolValue() ) {
104         _Instrument->setStringValue("status","");
105         return;
106     }
107     string switchKnob = _Instrument->getStringValue("switch", "on");
108     string modeButton = _Instrument->getStringValue("mode", "wx");
109     bool drawLightning = _Instrument->getBoolValue("lightning", true);
110     float range_nm = _Instrument->getFloatValue("range", 40.0);
111     float range_m = range_nm * SG_NM_TO_METER;
112
113     if ( last_switchKnob != switchKnob ) {
114         // since 3D models don't share textures with the rest of the world
115         // we must locate them and replace their handle by hand
116         // only do that when the instrument is turned on
117         if ( last_switchKnob == "off" )
118             odg->set_texture( odgauge_name, resultTexture.get());
119         last_switchKnob = switchKnob;
120     }
121     FGViewer *current__view = globals->get_current_view();
122     if ( current__view->getInternal() &&
123         (current__view->getHeadingOffset_deg() <= 15.0 || current__view->getHeadingOffset_deg() >= 345.0) &&
124         (current__view->getPitchOffset_deg() <= 15.0 || current__view->getPitchOffset_deg() >= 350.0) ) {
125
126         // we don't update the radar echo if the pilot looks around
127         // this is a copy
128         radarEchoBuffer = *sgEnviro.get_radar_echo();
129     }
130     odg->beginCapture(256);
131     odg->Clear();
132
133     glMatrixMode(GL_MODELVIEW);
134     glLoadIdentity();
135     glPushMatrix();
136     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
137     glBindTexture(GL_TEXTURE_2D, 0);
138
139     if ( switchKnob == "off" ) {
140         _Instrument->setStringValue("status","");
141     } else if ( switchKnob == "stby" ) {
142         _Instrument->setStringValue("status","STBY");
143     } else if ( switchKnob == "tst" ) {
144         _Instrument->setStringValue("status","TST");
145         // find something interesting to do...
146     } else {
147         string display_mode = _Instrument->getStringValue("display-mode", "arc");
148
149         // pretend we have a scan angle bigger then the FOV
150         // TODO:check real fov, enlarge if < nn, and do clipping if > mm
151         const float fovFactor = 1.45f;
152         float view_heading = get_heading() * SG_DEGREES_TO_RADIANS;
153         float range = 200.0f / range_nm;
154         _Instrument->setStringValue("status", modeButton.c_str());
155         if ( display_mode == "arc" ) {
156             glTranslatef(0.0f, -180.0f, 0.0f);
157             range = 2*180.0f / range_nm;
158         } else if ( display_mode == "map" ) {
159 //            float view_heading = get_track() * SG_DEGREES_TO_RADIANS;
160         } else if ( display_mode == "plan" ) {
161             // no sense I presume
162             view_heading = 0;
163         } else {
164             // rose
165         }
166         range /= SG_NM_TO_METER;
167         // we will rotate the echo quads, this gives a better rendering
168         const float rot_x = cos ( view_heading );
169         const float rot_y = sin ( view_heading );
170
171         list_of_SGWxRadarEcho *radarEcho = &radarEchoBuffer;
172         list_of_SGWxRadarEcho::iterator iradarEcho;
173         const float LWClevel[] = { 0.1f, 0.5f, 2.1f };
174         const float symbolSize = 1.0f / 8.0f ;
175         // draw the radar echo, we do that in 3 passes, one for each color level
176         // this is to 'merge' same colors together
177         // OSGFIXME
178 //         glBindTexture(GL_TEXTURE_2D, wxEcho->getHandle() );
179         glColor3f(1.0f, 1.0f, 1.0f);
180         glBegin( GL_QUADS );
181
182         for (int level = 0; level <= 2 ; level++ ) {
183             float col = level * symbolSize;
184             for (iradarEcho = radarEcho->begin() ; iradarEcho != radarEcho->end() ; iradarEcho++ ) {
185                 int cloudId = (iradarEcho->cloudId) ;
186                 bool upgrade = ((cloudId >> 5) & 1);
187                 float lwc = iradarEcho->LWC + (upgrade ? 1.0f : 0.0f);
188                 // skip ns
189                 if ( iradarEcho->LWC >= 0.5 && iradarEcho->LWC <= 0.6)
190                     continue;
191                 if ( (! iradarEcho->lightning) && ( lwc >= LWClevel[level]) ) {
192                     float dist = sgSqrt( iradarEcho->dist );
193                     float size = iradarEcho->radius * 2.0;
194                     if ( dist - size > range_m )
195                         continue;
196                     dist = dist * range;
197                     size = size * range;
198                     // compute the relative angle from the view direction
199                     float angle = ( view_heading + iradarEcho->heading );
200                     if ( angle > SG_PI )
201                         angle -= 2.0*SG_PI;
202                     if ( angle < - SG_PI )
203                         angle += 2.0*SG_PI;
204                     // and apply a fov factor to simulate a greater scan angle
205                     angle =  angle * fovFactor + SG_PI / 2.0;
206                     float x = cos( angle ) * dist;
207                     float y = sin( angle ) * dist;
208                     // use different shapes so the display is less boring
209                     float row = symbolSize * (float) (4 + (cloudId & 3) );
210                     float size_x = rot_x * size;
211                     float size_y = rot_y * size;
212                     glTexCoord2f( col, row);
213                     glVertex2f( x - size_x, y - size_y);
214                     glTexCoord2f( col+symbolSize, row);
215                     glVertex2f( x + size_y, y - size_x);
216                     glTexCoord2f( col+symbolSize, row+symbolSize);
217                     glVertex2f( x + size_x, y + size_y);
218                     glTexCoord2f( col, row+symbolSize);
219                     glVertex2f( x - size_y, y + size_x);
220                 }
221             }
222         }
223         glEnd(); // GL_QUADS
224
225         // draw lightning echos
226         if ( drawLightning ) {
227             float col = 3 * symbolSize;
228             float row = 4 * symbolSize;
229             for (iradarEcho = radarEcho->begin() ; iradarEcho != radarEcho->end() ; iradarEcho++ ) {
230                 if ( iradarEcho->lightning ) {
231                     float dist = iradarEcho->dist;
232                     dist = dist * range;
233                     float angle = (view_heading - iradarEcho->heading);
234                     if ( angle > SG_PI )
235                         angle -= 2.0*SG_PI;
236                     if ( angle < - SG_PI )
237                         angle += 2.0*SG_PI;
238                     angle =  angle * fovFactor - SG_PI / 2.0;
239                     float x = cos( angle ) * dist;
240                     float y = sin( angle ) * dist;
241                     glColor3f(1.0f, 1.0f, 1.0f);
242                     float size = symbolSize * 0.5f;
243                     glBegin( GL_QUADS );
244                         glTexCoord2f( col, row);
245                         glVertex2f( x - size, y - size);
246                         glTexCoord2f( col+symbolSize, row);
247                         glVertex2f( x + size, y - size);
248                         glTexCoord2f( col+symbolSize, row+symbolSize);
249                         glVertex2f( x + size, y + size);
250                         glTexCoord2f( col, row+symbolSize);
251                         glVertex2f( x - size, y + size);
252                     glEnd();
253                 }
254             }
255         }
256         // erase what is out of sight of antenna
257         /*
258             |\     /|
259             | \   / |
260             |  \ /  |
261             ---------
262             |       |
263             |       |
264             ---------
265         */
266         float yOffset = 180.0f, xOffset = 256.0f;
267
268         if ( display_mode != "arc" ) {
269             yOffset = 40.0f;
270             xOffset = 240.0f;
271         }
272
273         if ( display_mode != "plan" ) {
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 * tan(30*SG_DEGREES_TO_RADIANS));
296
297             glVertex2f(0.0, 0.0);
298             glVertex2f(256.0, 0.0);
299             glVertex2f(256.0, 256.0 * tan(30*SG_DEGREES_TO_RADIANS));
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
311         // DEBUG only
312 /*      glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
313         glBegin( GL_LINES );
314         glVertex2f(0.0, 0.0);
315         glVertex2f(-256.0, 256.0);
316         glVertex2f(0.0, 0.0);
317         glVertex2f(256.0, 256.0);
318         glEnd();*/
319
320         glEnable(GL_BLEND);
321         glEnable(GL_ALPHA_TEST);
322     }
323     glPopMatrix();
324     odg->endCapture( resultTexture.get() );
325 #endif
326 }