]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/panel.cxx
One more pass at a reorg.
[flightgear.git] / src / Cockpit / panel.cxx
1 //  panel.cxx - default, 2D single-engine prop instrument panel
2 //
3 //  Written by David Megginson, started January 2000.
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License as
7 //  published by the Free Software Foundation; either version 2 of the
8 //  License, or (at your option) any later version.
9 // 
10 //  This program is distributed in the hope that it will be useful, but
11 //  WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //  General Public License for more details.
14 // 
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //
19 //  $Id$
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #ifdef HAVE_WINDOWS_H          
26 #  include <windows.h>
27 #endif
28
29 #include <string.h>
30
31 #include <plib/ssg.h>
32 #include <GL/glut.h>
33 #include <simgear/xgl/xgl.h>
34
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/misc/fgpath.hxx>
37
38 #include <Main/options.hxx>
39 #include <Objects/texload.h>
40 #include <Autopilot/autopilot.hxx>
41
42 #include "cockpit.hxx"
43 #include "panel.hxx"
44
45 #define SIX_X 200
46 #define SIX_Y 345
47 #define SIX_W 128
48 #define SIX_SPACING (SIX_W + 5)
49 #define SMALL_W 112
50
51
52 \f
53 ////////////////////////////////////////////////////////////////////////
54 // Implementation of FGPanel.
55 ////////////////////////////////////////////////////////////////////////
56
57 FGPanel * FGPanel::OurPanel = 0;
58
59 FGPanel::FGPanel ()
60 {
61   if (OurPanel == 0) {
62     OurPanel = this;
63   } else {
64     FG_LOG(FG_GENERAL, FG_ALERT, "Multiple panels");
65     exit(-1);
66   }
67
68   int x = SIX_X;
69   int y = SIX_Y;
70
71   FGPath tpath(current_options.get_fg_root());
72   tpath.append("Textures/Panel/panel-bg.rgb");
73   _bg = new ssgTexture((char *)tpath.c_str(), false, false);
74
75   _airspeed = new FGAirspeedIndicator(x, y);
76   x += SIX_SPACING;
77   _horizon = new FGHorizon(x, y);
78   x += SIX_SPACING;
79   _altimeter = new FGAltimeter(x, y);
80   x = SIX_X;
81   y -= SIX_SPACING;
82   _coordinator = new FGTurnCoordinator(x, y);
83   x += SIX_SPACING;
84   _gyro = new FGGyroCompass(x, y);
85   x += SIX_SPACING;
86   _vertical = new FGVerticalVelocity(x, y);
87
88   y -= SIX_SPACING;
89   _rpm = new FGRPMGauge(x, y);
90
91   x -= SIX_SPACING;
92   _flaps = new FGFlapIndicator(x, y);
93 }
94
95 FGPanel::~FGPanel ()
96 {
97   OurPanel = 0;
98   delete _airspeed;
99   delete _horizon;
100   delete _altimeter;
101   delete _coordinator;
102   delete _gyro;
103   delete _vertical;
104   delete _rpm;
105   delete _flaps;
106 }
107
108 float
109 FGPanel::get_height () const
110 {
111   return _panel_h;
112 }
113
114 void
115 FGPanel::ReInit (int x, int y, int finx, int finy)
116 {
117   _x = x;
118   _y = y;
119   _w = finx - x;
120   _h = finy - y;
121   _panel_h = (int)((finy - y) * 0.5768 + 1);
122 }
123
124 void
125 FGPanel::Update () const
126 {
127   // glPushAttrib(GL_ALL_ATTRIB_BITS);
128
129   glMatrixMode(GL_PROJECTION);
130   glPushMatrix();
131   glLoadIdentity();
132   gluOrtho2D(_x, _x + _w, _y, _y + _h);
133
134   glMatrixMode(GL_MODELVIEW);
135   glPushMatrix();
136   glLoadIdentity();
137
138                                 // Draw the background
139   glDisable(GL_LIGHTING);
140   glEnable(GL_TEXTURE_2D);
141   if ( _bg->getHandle() >= 0 ) {
142       glBindTexture(GL_TEXTURE_2D, _bg->getHandle());
143   } else {
144       cout << "invalid texture handle in FGPanel::Update()" << endl;
145   }
146   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
147   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
148   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
149   glBegin(GL_POLYGON);
150   glTexCoord2f(0.0, 0.0); glVertex3f(_x, _y, 0);
151   glTexCoord2f(10.0, 0.0); glVertex3f(_x + _w, _y, 0);
152   glTexCoord2f(10.0, 5.0); glVertex3f(_x + _w, _y + _panel_h, 0);
153   glTexCoord2f(0.0, 5.0); glVertex3f(_x, _y + _panel_h, 0);
154   glEnd();
155
156                                 // Draw the instruments.
157   glLoadIdentity();
158   glTranslated(_airspeed->getXPos(), _airspeed->getYPos(), 0);
159   _airspeed->draw();
160
161   glLoadIdentity();
162   glTranslated(_horizon->getXPos(), _horizon->getYPos(), 0);
163   _horizon->draw();
164
165   glLoadIdentity();
166   glTranslated(_altimeter->getXPos(), _altimeter->getYPos(), 0);
167   _altimeter->draw();
168
169   glLoadIdentity();
170   glTranslated(_coordinator->getXPos(), _coordinator->getYPos(), 0);
171   _coordinator->draw();
172
173   glLoadIdentity();
174   glTranslated(_gyro->getXPos(), _gyro->getYPos(), 0);
175   _gyro->draw();
176
177   glLoadIdentity();
178   glTranslated(_vertical->getXPos(), _vertical->getYPos(), 0);
179   _vertical->draw();
180
181   glLoadIdentity();
182   glTranslated(_rpm->getXPos(), _rpm->getYPos(), 0);
183   _rpm->draw();
184
185   glLoadIdentity();
186   glTranslated(_flaps->getXPos(), _flaps->getYPos(), 0);
187   _flaps->draw();
188
189   glMatrixMode(GL_PROJECTION);
190   glPopMatrix();
191   glMatrixMode(GL_MODELVIEW);
192   glPopMatrix();
193
194   // glPopAttrib();
195
196 //   ssgForceBasicState();
197 }
198
199
200 \f
201 ////////////////////////////////////////////////////////////////////////
202 // Implementation of FGPanelInstrument.
203 ////////////////////////////////////////////////////////////////////////
204
205
206 FGPanelInstrument::FGPanelInstrument ()
207 {
208   setPosition(0, 0);
209   setSize(0, 0);
210 }
211
212 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
213 {
214   setPosition(x, y);
215   setSize(w, h);
216 }
217
218 FGPanelInstrument::~FGPanelInstrument ()
219 {
220 }
221
222 void
223 FGPanelInstrument::setPosition (int x, int y)
224 {
225   _x = x;
226   _y = y;
227 }
228
229 void
230 FGPanelInstrument::setSize (int w, int h)
231 {
232   _w = w;
233   _h = h;
234 }
235
236 int
237 FGPanelInstrument::getXPos () const
238 {
239   return _x;
240 }
241
242 int
243 FGPanelInstrument::getYPos () const
244 {
245   return _y;
246 }
247
248
249 \f
250 ////////////////////////////////////////////////////////////////////////
251 // Implementation of FGTexturedInstrument.
252 ////////////////////////////////////////////////////////////////////////
253
254 FGTexturedInstrument::FGTexturedInstrument (int x, int y, int w, int h)
255   : FGPanelInstrument(x, y, w, h)
256 {
257   for (int i = 0; i < MAX_LAYERS; i++) {
258     _layers[i] = false;
259   }
260 }
261
262 FGTexturedInstrument::~FGTexturedInstrument ()
263 {
264   // FIXME: maybe free textures
265 }
266
267 void
268 FGTexturedInstrument::addLayer (int layer, const char * textureName)
269 {
270   FGPath tpath(current_options.get_fg_root());
271   tpath.append(textureName);
272   ssgTexture * texture = new ssgTexture((char *)tpath.c_str(), false, false);
273   cerr << "Loaded texture " << textureName << endl;
274   addLayer(layer, texture);
275 }
276
277 void
278 FGTexturedInstrument::addLayer (int layer, ssgTexture * texture)
279 {
280   _layers[layer] = true;
281   _textures[layer] = texture;
282   _rotation[layer] = 0.0;
283   _xoffset[layer] = _yoffset[layer] = 0;
284   _xcenter[layer] = _ycenter[layer] = 0;
285 }
286
287 void
288 FGTexturedInstrument::setLayerCenter (int layer, int x, int y)
289 {
290   _xcenter[layer] = x;
291   _ycenter[layer] = y;
292 }
293
294 void
295 FGTexturedInstrument::setLayerRot (int layer, double rotation) const
296 {
297   _rotation[layer] = rotation;
298 }
299
300 void
301 FGTexturedInstrument::setLayerOffset (int layer, int xoff, int yoff) const
302 {
303   _xoffset[layer] = xoff;
304   _yoffset[layer] = yoff;
305 }
306
307 bool
308 FGTexturedInstrument::hasLayer (int layer) const
309 {
310   return _layers[layer];
311 }
312
313 void
314 FGTexturedInstrument::draw () const
315 {
316   glEnable(GL_TEXTURE_2D);
317
318   int i;
319   int w2 = _w / 2;
320   int h2 = _h / 2;
321
322   glMatrixMode(GL_MODELVIEW);
323   for (i = 0; i < MAX_LAYERS; i++) {
324     if (hasLayer(i)) {
325       glPushMatrix();
326       glTranslated(_xcenter[i], _ycenter[i], 0);
327       glRotatef(0.0 - _rotation[i], 0.0, 0.0, 1.0);
328       glTranslated(_xoffset[i], _yoffset[i], 0);
329       if ( _textures[i]->getHandle() >= 0 ) {
330           glBindTexture(GL_TEXTURE_2D, _textures[i]->getHandle());
331       } else {
332           cout << "invalid texture handle in FGTexturedInstrument::draw()" 
333                << endl;
334       }
335       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
336       glBegin(GL_POLYGON);
337                                 // FIXME: is this really correct
338                                 // for layering?
339       glTexCoord2f(0.0, 0.0); glVertex3f(-w2, -h2, i / 100.0 + 0.1);
340       glTexCoord2f(1.0, 0.0); glVertex3f(w2, -h2, i / 100.0 + 0.1);
341       glTexCoord2f(1.0, 1.0); glVertex3f(w2, h2, i / 100.0 + 0.1);
342       glTexCoord2f(0.0, 1.0); glVertex3f(-w2, h2, i / 100.0 + 0.1);
343       glEnd();
344       glPopMatrix();
345     }
346   }
347
348   glDisable(GL_TEXTURE_2D);
349 }
350
351
352 \f
353 ////////////////////////////////////////////////////////////////////////
354 // Implementation of FGAirspeedIndicator.
355 ////////////////////////////////////////////////////////////////////////
356
357 FGAirspeedIndicator::FGAirspeedIndicator (int x, int y)
358   : FGTexturedInstrument(x, y, SIX_W, SIX_W)
359 {
360   addLayer(0, "Textures/Panel/airspeed.rgb");
361   addLayer(1, "Textures/Panel/long-needle.rgb");
362 }
363
364 FGAirspeedIndicator::~FGAirspeedIndicator ()
365 {
366 }
367
368 void
369 FGAirspeedIndicator::draw () const
370 {
371   double speed = get_speed();
372   if (speed < 30.0) {
373     speed = 30.0;
374   } else if (speed > 220.0) {
375     speed = 220.0;
376   }
377   double angle = speed / 20.0 * 36.0 - 54.0;
378   setLayerRot(1, angle);
379   FGTexturedInstrument::draw();
380 }
381
382
383 \f
384 ////////////////////////////////////////////////////////////////////////
385 // Implementation of FGHorizon.
386 ////////////////////////////////////////////////////////////////////////
387
388 FGHorizon::FGHorizon (int x, int y)
389   : FGTexturedInstrument(x, y, SIX_W, SIX_W)
390 {
391   addLayer(0, "Textures/Panel/horizon-bg.rgb");
392   addLayer(1, "Textures/Panel/horizon-float.rgb");
393   addLayer(2, "Textures/Panel/horizon-rim.rgb");
394   addLayer(3, "Textures/Panel/horizon-fg.rgb");
395 }
396
397 FGHorizon::~FGHorizon ()
398 {
399 }
400
401 void
402 FGHorizon::draw () const
403 {
404   double rot = get_roll() * RAD_TO_DEG;
405   double pitch = get_pitch() * RAD_TO_DEG;
406   if (pitch > 20)
407     pitch = 20;
408   else if (pitch < -20)
409     pitch = -20;
410   int yoffset = 0 - (pitch * ((1.5 / 160.0) * _h));
411   setLayerRot(0, 0 - rot);
412   setLayerRot(1, 0 - rot);
413   setLayerOffset(1, 0, yoffset);
414   setLayerRot(2, 0 - rot);
415   FGTexturedInstrument::draw();
416 }
417
418
419 \f
420 ////////////////////////////////////////////////////////////////////////
421 // Implementation of FGAltimeter.
422 ////////////////////////////////////////////////////////////////////////
423
424 // TODO: add 10,000 bug
425
426 FGAltimeter::FGAltimeter (int x, int y)
427   : FGTexturedInstrument(x, y, SIX_W, SIX_W)
428 {
429   addLayer(0, "Textures/Panel/altimeter.rgb");
430   addLayer(1, "Textures/Panel/long-needle.rgb");
431   addLayer(2, "Textures/Panel/short-needle.rgb");
432   addLayer(3, "Textures/Panel/bug.rgb");
433 }
434
435 FGAltimeter::~FGAltimeter ()
436 {
437 }
438
439 void
440 FGAltimeter::draw () const
441 {
442   long altitude = get_altitude();
443   setLayerRot(1, (altitude % 1000) / 1000.0 * 360.0);
444   setLayerRot(2, (altitude % 10000) / 10000.0 * 360.0);
445   setLayerRot(3, (altitude % 100000) / 100000.0 * 360.0);
446   FGTexturedInstrument::draw();
447 }
448
449
450 \f
451 ////////////////////////////////////////////////////////////////////////
452 // Implementation of FGTurnCoordinator.
453 ////////////////////////////////////////////////////////////////////////
454
455 // TODO: add slip/skid ball
456
457 FGTurnCoordinator::FGTurnCoordinator (int x, int y)
458   : FGTexturedInstrument(x, y, SIX_W, SIX_W)
459 {
460   addLayer(0, "Textures/Panel/turn-bg.rgb");
461   addLayer(1, "Textures/Panel/turn.rgb");
462   addLayer(2, "Textures/Panel/ball.rgb");
463 }
464
465 FGTurnCoordinator::~FGTurnCoordinator ()
466 {
467 }
468
469 void
470 FGTurnCoordinator::draw () const
471 {
472                                 // Set little plane
473                                 // FIXME: this should be turn, maybe
474   double rot = get_roll() * RAD_TO_DEG;
475   if (rot > 30.0)
476     rot = 30.0;
477   else if (rot < -30.0)
478     rot = -30.0;
479   setLayerRot(1, rot);
480
481                                 // Set ball
482                                 // FIXME: totally bogus values
483   double slip = get_sideslip() * 450;
484   if (slip > 45) {
485     slip = 45;
486   } else if (slip < -45) {
487     slip = -45;
488   }
489   setLayerRot(2, 0 - slip);
490
491   FGTexturedInstrument::draw();
492 }
493
494
495 \f
496 ////////////////////////////////////////////////////////////////////////
497 // Implementation of FGGyroCompass.
498 ////////////////////////////////////////////////////////////////////////
499
500 // TODO: add heading bug
501
502 FGGyroCompass::FGGyroCompass (int x, int y)
503   : FGTexturedInstrument(x, y, SIX_W, SIX_W)
504 {
505   addLayer(0, "Textures/Panel/gyro-bg.rgb");
506   addLayer(1, "Textures/Panel/bug.rgb");
507   addLayer(2, "Textures/Panel/gyro-fg.rgb");
508 }
509
510 FGGyroCompass::~FGGyroCompass ()
511 {
512 }
513
514 void
515 FGGyroCompass::draw () const
516 {
517   setLayerRot(0, 0.0 - get_heading());
518   setLayerRot(1, 0.0 - get_heading() + fgAPget_TargetHeading());
519   FGTexturedInstrument::draw();
520 }
521
522
523 \f
524 ////////////////////////////////////////////////////////////////////////
525 // Implementation of FGVerticalVelocity.
526 ////////////////////////////////////////////////////////////////////////
527
528 FGVerticalVelocity::FGVerticalVelocity (int x, int y)
529   : FGTexturedInstrument(x, y, SIX_W, SIX_W)
530 {
531   addLayer(0, "Textures/Panel/vertical.rgb");
532   addLayer(1, "Textures/Panel/long-needle.rgb");
533 }
534
535 FGVerticalVelocity::~FGVerticalVelocity ()
536 {
537 }
538
539 void
540 FGVerticalVelocity::draw () const
541 {
542   double climb = get_climb_rate() / 500.0;
543   if (climb < -4.0) {
544     climb = -4.0;
545   } else if (climb > 4.0) {
546     climb = 4.0;
547   }
548   double rot = (climb * 42.0) + 270.0;
549                                 // FIXME: why inverted?
550   setLayerRot(1, rot);
551   FGTexturedInstrument::draw();
552 }
553
554
555 \f
556 ////////////////////////////////////////////////////////////////////////
557 // Implementation of FGRPMGauge.
558 ////////////////////////////////////////////////////////////////////////
559
560 FGRPMGauge::FGRPMGauge (int x, int y)
561   : FGTexturedInstrument(x, y, SMALL_W, SMALL_W)
562 {
563   addLayer(0, "Textures/Panel/rpm.rgb");
564   addLayer(1, "Textures/Panel/long-needle.rgb");
565 }
566
567 FGRPMGauge::~FGRPMGauge ()
568 {
569 }
570
571 void
572 FGRPMGauge::draw () const
573 {
574   double rot = get_throttleval() * 300 - 150;
575   setLayerRot(1, rot);
576   FGTexturedInstrument::draw();
577 }
578
579
580 \f
581 ////////////////////////////////////////////////////////////////////////
582 // Implementation of FGFlapIndicator.
583 ////////////////////////////////////////////////////////////////////////
584
585 FGFlapIndicator::FGFlapIndicator (int x, int y)
586   : FGTexturedInstrument(x, y, SMALL_W, SMALL_W)
587 {
588   addLayer(0, "Textures/Panel/flaps.rgb");
589   addLayer(1, "Textures/Panel/long-needle.rgb");
590   setLayerCenter(1, 0 - (SMALL_W / 4) + (SMALL_W / 16), 0);
591 }
592
593 FGFlapIndicator::~FGFlapIndicator ()
594 {
595 }
596
597 void
598 FGFlapIndicator::draw () const
599 {
600   double rot = controls.get_flaps() * 120 + 30;
601   setLayerRot(1, rot);
602   FGTexturedInstrument::draw();
603 }
604
605
606 \f
607 // end of panel.cxx