1 // panel.cxx - default, 2D single-engine prop instrument panel
3 // Written by David Megginson, started January 2000.
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.
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.
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.
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/misc/fgpath.hxx>
37 #include <Main/options.hxx>
38 #include <Objects/texload.h>
39 #include <Autopilot/autopilot.hxx>
40 #include <Time/fg_time.hxx>
42 #include "cockpit.hxx"
46 extern fgAPDataPtr APDataGlobal;
51 #define SIX_SPACING (SIX_W + 5)
56 ////////////////////////////////////////////////////////////////////////
57 // Static functions for obtaining settings.
59 // These should be replaced with functions from a global facade,
60 // or BFI (Big Friendly Interface).
61 ////////////////////////////////////////////////////////////////////////
64 * Return the indicated airspeed in knots.
73 * Return the roll in degrees.
78 return get_roll() * RAD_TO_DEG;
82 * Return the pitch in degrees.
87 return get_pitch() * RAD_TO_DEG;
91 * Return the altitude in feet.
96 return get_altitude();
100 * Return the sideslip (units unknown).
105 return get_sideslip();
109 * Return the heading in degrees.
114 return get_heading();
118 * Return the current autopilot heading in degrees.
123 return fgAPget_TargetHeading();
127 * Return the climb rate in feet/minute.
130 panelGetVerticalVelocity ()
132 return get_climb_rate();
136 * Return the throttle setting (0.0 - 1.0).
141 return get_throttleval();
145 * Return the flaps setting (0.0 - 1.0).
150 return controls.get_flaps();
156 return controls.get_aileron();
162 return controls.get_rudder();
168 return controls.get_elevator();
172 panelGetElevatorTrim ()
174 return controls.get_elevator_trim();
177 static char * panelGetTime (char * buf)
179 struct tm * t = FGTime::cur_time_params->getGmt();
180 sprintf(buf, " %.2d:%.2d:%.2d",
181 t->tm_hour, t->tm_min, t->tm_sec);
187 ////////////////////////////////////////////////////////////////////////
188 // Static factory functions to create textured gauges.
190 // These will be replaced first with a giant table, and then with
191 // configuration files read from an external source, but for now
192 // they're hard-coded.
193 ////////////////////////////////////////////////////////////////////////
197 * Construct an airspeed indicator for a single-engine prop.
199 static FGPanelInstrument *
200 makeAirspeedIndicator (int x, int y)
202 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
204 // Layer 0: gauge background.
205 inst->addLayer(0, "Textures/Panel/airspeed.rgb");
208 // Rotates with airspeed.
209 inst->addLayer(1, "Textures/Panel/long-needle.rgb");
210 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
212 30.0, 220.0, 36.0 / 20.0, -54.0);
218 * Construct an artificial horizon.
220 static FGPanelInstrument *
221 makeHorizon (int x, int y)
223 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
225 // Layer 0: coloured background
226 // moves with roll only
227 inst->addLayer(0, "Textures/Panel/horizon-bg.rgb");
228 inst->addTransformation(0, FGInstrumentLayer::ROTATION,
230 -360.0, 360.0, -1.0, 0.0);
232 // Layer 1: floating horizon
233 // moves with roll and pitch
234 inst->addLayer(1, "Textures/Panel/horizon-float.rgb");
235 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
237 -360.0, 360.0, -1.0, 0.0);
238 inst->addTransformation(1, FGInstrumentLayer::YSHIFT,
240 -20.0, 20.0, -(1.5 / 160.0) * SIX_W, 0.0);
243 // moves with roll only
244 inst->addLayer(2, "Textures/Panel/horizon-rim.rgb");
245 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
247 -360.0, 360.0, -1.0, 0.0);
249 // Layer 3: glass front of gauge
250 // fixed, with markings
251 inst->addLayer(3, "Textures/Panel/horizon-fg.rgb");
258 * Construct an altimeter.
260 static FGPanelInstrument *
261 makeAltimeter (int x, int y)
263 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
265 // Layer 0: gauge background
266 inst->addLayer(0, "Textures/Panel/altimeter.rgb");
268 // Layer 1: hundreds needle (long)
269 // moves with altitude
270 inst->addLayer(1, "Textures/Panel/long-needle.rgb");
271 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
273 0.0, 100000.0, 360.0 / 1000.0, 0.0);
275 // Layer 2: thousands needle (short)
276 // moves with altitude
277 inst->addLayer(2, "Textures/Panel/short-needle.rgb");
278 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
280 0.0, 100000.0, 360.0 / 10000.0, 0.0);
282 // Layer 3: ten thousands bug (outside)
283 // moves with altitude
284 inst->addLayer(3, "Textures/Panel/bug.rgb");
285 inst->addTransformation(3, FGInstrumentLayer::ROTATION,
287 0.0, 100000.0, 360.0 / 100000.0, 0.0);
294 * Construct a turn coordinator.
296 static FGPanelInstrument *
297 makeTurnCoordinator (int x, int y)
299 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
301 // Layer 0: background
302 inst->addLayer(0, "Textures/Panel/turn-bg.rgb");
304 // Layer 1: little plane
306 inst->addLayer(1, "Textures/Panel/turn.rgb");
307 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
309 -30.0, 30.0, 1.0, 0.0);
311 // Layer 2: little ball
312 // moves with slip/skid
313 inst->addLayer(2, "Textures/Panel/ball.rgb");
314 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
316 -0.1, 0.1, 450.0, 0.0);
323 * Construct a gyro compass.
325 static FGPanelInstrument *
326 makeGyroCompass (int x, int y)
328 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
330 // Layer 0: compass background
331 // rotates with heading
332 inst->addLayer(0, "Textures/Panel/gyro-bg.rgb");
333 inst->addTransformation(0, FGInstrumentLayer::ROTATION,
335 -360.0, 360.0, -1.0, 0.0);
337 // Layer 1: heading bug
338 // rotates with heading and AP heading
339 inst->addLayer(1, "Textures/Panel/bug.rgb");
340 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
342 -360.0, 360.0, -1.0, 0.0);
343 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
345 -360.0, 360.0, 1.0, 0.0);
347 // Layer 2: fixed center
348 inst->addLayer(2, "Textures/Panel/gyro-fg.rgb");
355 * Construct a vertical velocity indicator.
357 static FGPanelInstrument *
358 makeVerticalVelocity (int x, int y)
360 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
362 // Layer 0: gauge background
363 inst->addLayer(0, "Textures/Panel/vertical.rgb");
366 // moves with vertical velocity
367 inst->addLayer(1, "Textures/Panel/long-needle.rgb");
368 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
369 panelGetVerticalVelocity,
370 -2000.0, 2000.0, 42.0/500.0, 270.0);
377 * Construct an RPM gauge.
379 static FGPanelInstrument *
380 makeRPMGauge (int x, int y)
382 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
384 // Layer 0: gauge background
385 inst->addLayer(0, "Textures/Panel/rpm.rgb");
387 // Layer 1: long needle
388 // FIXME: moves with throttle (for now)
389 inst->addLayer(1, "Textures/Panel/long-needle.rgb");
390 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
392 0.0, 100.0, 300.0, -150.0);
399 * Construct a flap position indicator.
401 static FGPanelInstrument *
402 makeFlapIndicator (int x, int y)
404 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
406 // Layer 0: gauge background
407 inst->addLayer(0, "Textures/Panel/flaps.rgb");
409 // Layer 1: long needle
410 // shifted over, rotates with flap position
411 inst->addLayer(1, "Textures/Panel/long-needle.rgb");
412 inst->addTransformation(1, FGInstrumentLayer::XSHIFT,
413 -(SMALL_W / 4) + (SMALL_W / 16));
414 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
416 0.0, 1.0, 120.0, 30.0);
421 static FGPanelInstrument *
422 makeChronometer (int x, int y)
424 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
426 // Layer 0: gauge background
427 inst->addLayer(0, "Textures/Panel/clock.rgb");
430 // displays current GMT
431 FGCharInstrumentLayer * text =
432 new FGCharInstrumentLayer(panelGetTime,
433 SMALL_W, SMALL_W, 1);
434 text->setPointSize(14);
435 text->setColor(0.2, 0.2, 0.2);
436 inst->addLayer(text);
437 inst->addTransformation(1, FGInstrumentLayer::XSHIFT, SMALL_W * -0.38);
438 inst->addTransformation(1, FGInstrumentLayer::YSHIFT, SMALL_W * -0.06);
445 * Construct control-position indicators.
447 static FGPanelInstrument *
448 makeControls (int x, int y)
450 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
452 // Layer 0: gauge background
453 inst->addLayer(0, "Textures/Panel/controls.rgb");
456 // moves left-right with aileron
457 inst->addLayer(1, "Textures/Panel/bug.rgb");
458 inst->addTransformation(1, FGInstrumentLayer::XSHIFT, panelGetAileron,
459 -1.0, 1.0, SMALL_W * .75 / 2.0, 0.0);
462 // moves left-right with rudder
463 inst->addLayer(2, "Textures/Panel/bug.rgb");
464 inst->addTransformation(2, FGInstrumentLayer::ROTATION, 180.0);
465 inst->addTransformation(2, FGInstrumentLayer::XSHIFT, panelGetRudder,
466 -1.0, 1.0, -SMALL_W * .75 / 2.0, 0.0);
469 // moves up-down with elevator trim
470 inst->addLayer(3, "Textures/Panel/bug.rgb");
471 inst->addTransformation(3, FGInstrumentLayer::ROTATION, 270.0);
472 inst->addTransformation(3, FGInstrumentLayer::YSHIFT,
473 -SMALL_W * (3.0 / 8.0));
474 inst->addTransformation(3, FGInstrumentLayer::XSHIFT, panelGetElevatorTrim,
475 -1.0, 1.0, SMALL_W * .75 / 2.0, 0.0);
478 // moves up-down with elevator
479 inst->addLayer(4, "Textures/Panel/bug.rgb");
480 inst->addTransformation(4, FGInstrumentLayer::ROTATION, 90.0);
481 inst->addTransformation(4, FGInstrumentLayer::YSHIFT,
482 -SMALL_W * (3.0 / 8.0));
483 inst->addTransformation(4, FGInstrumentLayer::XSHIFT, panelGetElevator,
484 -1.0, 1.0, -SMALL_W * .75 / 2.0, 0.0);
491 * Construct a NAV1 gauge (dummy for now).
493 static FGPanelInstrument *
494 makeNAV1 (int x, int y)
496 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
498 // Layer 0: background
499 inst->addLayer(0, "Textures/Panel/gyro-bg.rgb");
506 * Construct a NAV2 gauge (dummy for now).
508 static FGPanelInstrument *
509 makeNAV2 (int x, int y)
511 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
513 // Layer 0: background
514 inst->addLayer(0, "Textures/Panel/gyro-bg.rgb");
521 * Construct an ADF gauge (dummy for now).
523 static FGPanelInstrument *
524 makeADF (int x, int y)
526 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
528 // Layer 0: background
529 inst->addLayer(0, "Textures/Panel/gyro-bg.rgb");
536 ////////////////////////////////////////////////////////////////////////
537 // Implementation of FGPanel.
538 ////////////////////////////////////////////////////////////////////////
540 FGPanel * FGPanel::OurPanel = 0;
547 FG_LOG(FG_GENERAL, FG_ALERT, "Multiple panels");
554 FGPath tpath(current_options.get_fg_root());
555 tpath.append("Textures/Panel/panel-bg.rgb");
556 _bg = new ssgTexture((char *)tpath.c_str(), false, false);
558 // Chronometer alone at side
559 x = SIX_X - SIX_SPACING - 8;
560 _instruments.push_back(makeChronometer(x, y));
564 _instruments.push_back(makeAirspeedIndicator(x, y));
566 _instruments.push_back(makeHorizon(x, y));
568 _instruments.push_back(makeAltimeter(x, y));
569 x += SIX_SPACING + 20;
570 _instruments.push_back(makeNAV1(x, y));
575 _instruments.push_back(makeTurnCoordinator(x, y));
577 _instruments.push_back(makeGyroCompass(x, y));
579 _instruments.push_back(makeVerticalVelocity(x, y));
580 x += SIX_SPACING + 20;
581 _instruments.push_back(makeNAV2(x, y));
585 y -= SIX_SPACING + 10;
586 _instruments.push_back(makeControls(x, y));
588 _instruments.push_back(makeFlapIndicator(x, y));
590 _instruments.push_back(makeRPMGauge(x, y));
591 x += SIX_SPACING + 20;
593 _instruments.push_back(makeADF(x, y));
600 instrument_list_type::iterator current = _instruments.begin();
601 instrument_list_type::iterator last = _instruments.end();
603 for ( ; current != last; ++current) {
610 FGPanel::get_height () const
616 FGPanel::ReInit (int x, int y, int finx, int finy)
622 _panel_h = (int)((finy - y) * 0.5768 + 1);
626 FGPanel::Update () const
628 glMatrixMode(GL_PROJECTION);
631 gluOrtho2D(_x, _x + _w, _y, _y + _h);
633 glMatrixMode(GL_MODELVIEW);
637 // Draw the background
638 glEnable(GL_TEXTURE_2D);
639 glDisable(GL_LIGHTING);
640 glColor3f(1.0, 1.0, 1.0);
641 glBindTexture(GL_TEXTURE_2D, _bg->getHandle());
642 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
643 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
644 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
646 glTexCoord2f(0.0, 0.0); glVertex3f(_x, _y, 0);
647 glTexCoord2f(10.0, 0.0); glVertex3f(_x + _w, _y, 0);
648 glTexCoord2f(10.0, 5.0); glVertex3f(_x + _w, _y + _panel_h, 0);
649 glTexCoord2f(0.0, 5.0); glVertex3f(_x, _y + _panel_h, 0);
652 // Draw the instruments.
653 instrument_list_type::const_iterator current = _instruments.begin();
654 instrument_list_type::const_iterator end = _instruments.end();
656 for ( ; current != end; current++) {
657 FGPanelInstrument * instr = *current;
659 glTranslated(instr->getXPos(), instr->getYPos(), 0);
663 glMatrixMode(GL_PROJECTION);
665 glMatrixMode(GL_MODELVIEW);
667 ssgForceBasicState();
668 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
673 ////////////////////////////////////////////////////////////////////////
674 // Implementation of FGPanelInstrument.
675 ////////////////////////////////////////////////////////////////////////
678 FGPanelInstrument::FGPanelInstrument ()
684 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
690 FGPanelInstrument::~FGPanelInstrument ()
695 FGPanelInstrument::setPosition (int x, int y)
702 FGPanelInstrument::setSize (int w, int h)
709 FGPanelInstrument::getXPos () const
715 FGPanelInstrument::getYPos () const
722 ////////////////////////////////////////////////////////////////////////
723 // Implementation of FGLayeredInstrument.
724 ////////////////////////////////////////////////////////////////////////
726 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
727 : FGPanelInstrument(x, y, w, h)
731 FGLayeredInstrument::~FGLayeredInstrument ()
733 // FIXME: free layers
737 FGLayeredInstrument::draw () const
739 layer_list::const_iterator it = _layers.begin();
740 layer_list::const_iterator last = _layers.end();
748 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
750 _layers.push_back(layer);
754 FGLayeredInstrument::addLayer (int layer, const char *textureName)
756 addLayer(new FGTexturedInstrumentLayer(textureName, _w, _h, layer));
760 FGLayeredInstrument::addTransformation (int layer,
761 FGInstrumentLayer::transform_type type,
762 FGInstrumentLayer::transform_func func,
763 double min, double max,
764 double factor, double offset)
766 _layers[layer]->addTransformation(type, func, min, max, factor, offset);
771 ////////////////////////////////////////////////////////////////////////
772 // Implementation of FGInstrumentLayer.
773 ////////////////////////////////////////////////////////////////////////
775 FGInstrumentLayer::FGInstrumentLayer (int w, int h, int z)
782 FGInstrumentLayer::~FGInstrumentLayer ()
784 transformation_list::iterator it;
785 transformation_list::iterator end;
793 FGInstrumentLayer::transform () const
795 glTranslatef(0.0, 0.0, (_z / 100.0) + 0.1);
797 transformation_list::const_iterator it = _transformations.begin();
798 transformation_list::const_iterator last = _transformations.end();
800 transformation *t = *it;
801 double value = (t->func == 0 ? 0.0 : (*(t->func))());
802 if (value < t->min) {
804 } else if (value > t->max) {
807 value = value * t->factor + t->offset;
811 glTranslatef(value, 0.0, 0.0);
814 glTranslatef(0.0, value, 0.0);
817 glRotatef(-value, 0.0, 0.0, 1.0);
825 FGInstrumentLayer::addTransformation (transform_type type,
827 double min, double max,
828 double factor, double offset)
830 transformation *t = new transformation;
837 _transformations.push_back(t);
842 ////////////////////////////////////////////////////////////////////////
843 // Implementation of FGTexturedInstrumentLayer.
844 ////////////////////////////////////////////////////////////////////////
846 FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (const char *tname,
848 : FGInstrumentLayer(w, h, z)
853 FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (ssgTexture * texture,
855 : FGInstrumentLayer(w, h, z)
860 FGTexturedInstrumentLayer::~FGTexturedInstrumentLayer ()
865 FGTexturedInstrumentLayer::draw () const
872 glBindTexture(GL_TEXTURE_2D, _texture->getHandle());
874 // FIXME: is this really correct
876 glTexCoord2f(0.0, 0.0); glVertex2f(-w2, -h2);
877 glTexCoord2f(1.0, 0.0); glVertex2f(w2, -h2);
878 glTexCoord2f(1.0, 1.0); glVertex2f(w2, h2);
879 glTexCoord2f(0.0, 1.0); glVertex2f(-w2, h2);
885 FGTexturedInstrumentLayer::setTexture (const char *textureName)
887 FGPath tpath(current_options.get_fg_root());
888 tpath.append(textureName);
889 ssgTexture * texture = new ssgTexture((char *)tpath.c_str(), false, false);
890 cerr << "Loaded texture " << textureName << endl;
896 ////////////////////////////////////////////////////////////////////////
897 // Implementation of FGCharInstrumentLayer.
898 ////////////////////////////////////////////////////////////////////////
900 FGCharInstrumentLayer::FGCharInstrumentLayer (text_func func,
902 : FGInstrumentLayer(w, h, z),
905 _renderer.setFont(guiFntHandle);
906 _renderer.setPointSize(14);
907 _color[0] = _color[1] = _color[2] = 0.0;
910 FGCharInstrumentLayer::~FGCharInstrumentLayer ()
915 FGCharInstrumentLayer::draw () const
921 _renderer.start3f(0, 0, 0);
922 _renderer.puts((*_func)(_buf));
924 glColor3f(1.0, 1.0, 1.0); // FIXME
929 FGCharInstrumentLayer::setColor (float r, float g, float b)
937 FGCharInstrumentLayer::setPointSize (const float size)
939 _renderer.setPointSize(size);
943 FGCharInstrumentLayer::setFont(fntFont * font)
945 _renderer.setFont(font);