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 <Main/bfi.hxx>
39 #include <Objects/texload.h>
40 #include <Autopilot/autopilot.hxx>
41 #include <Time/fg_time.hxx>
43 #include "cockpit.hxx"
48 extern fgAPDataPtr APDataGlobal;
53 #define SIX_SPACING (SIX_W + 5)
58 ////////////////////////////////////////////////////////////////////////
59 // Static functions for obtaining settings.
61 // These should be replaced with functions from a global facade,
62 // or BFI (Big Friendly Interface).
63 ////////////////////////////////////////////////////////////////////////
65 static char * panelGetTime (char * buf)
67 struct tm * t = FGTime::cur_time_params->getGmt();
68 sprintf(buf, " %.2d:%.2d:%.2d",
69 t->tm_hour, t->tm_min, t->tm_sec);
75 ////////////////////////////////////////////////////////////////////////
76 // Static factory functions to create textured gauges.
78 // These will be replaced first with a giant table, and then with
79 // configuration files read from an external source, but for now
80 // they're hard-coded.
81 ////////////////////////////////////////////////////////////////////////
84 createTexture (const char * relativePath)
86 return FGPanel::OurPanel->createTexture(relativePath);
91 * Construct an airspeed indicator for a single-engine prop.
93 static FGPanelInstrument *
94 createAirspeedIndicator (int x, int y)
96 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
98 // Layer 0: gauge background.
99 inst->addLayer(0, createTexture("Textures/Panel/airspeed.rgb"));
102 // Rotates with airspeed.
103 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
104 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
105 FGSteam::get_ASI_kias,
106 30.0, 220.0, 36.0 / 20.0, -54.0);
112 * Construct an artificial horizon.
114 static FGPanelInstrument *
115 createHorizon (int x, int y)
117 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
119 // Layer 0: coloured background
120 // moves with roll only
121 inst->addLayer(0, createTexture("Textures/Panel/horizon-bg.rgb"));
122 inst->addTransformation(0, FGInstrumentLayer::ROTATION,
124 -360.0, 360.0, -1.0, 0.0);
126 // Layer 1: floating horizon
127 // moves with roll and pitch
128 inst->addLayer(1, createTexture("Textures/Panel/horizon-float.rgb"));
129 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
131 -360.0, 360.0, -1.0, 0.0);
132 inst->addTransformation(1, FGInstrumentLayer::YSHIFT,
134 -20.0, 20.0, -(1.5 / 160.0) * SIX_W, 0.0);
137 // moves with roll only
138 inst->addLayer(2, createTexture("Textures/Panel/horizon-rim.rgb"));
139 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
141 -360.0, 360.0, -1.0, 0.0);
143 // Layer 3: glass front of gauge
144 // fixed, with markings
145 inst->addLayer(3, createTexture("Textures/Panel/horizon-fg.rgb"));
152 * Construct an altimeter.
154 static FGPanelInstrument *
155 createAltimeter (int x, int y)
157 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
159 // Layer 0: gauge background
160 inst->addLayer(0, createTexture("Textures/Panel/altimeter.rgb"));
162 // Layer 1: hundreds needle (long)
163 // moves with altitude
164 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
165 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
167 0.0, 100000.0, 360.0 / 1000.0, 0.0);
169 // Layer 2: thousands needle (short)
170 // moves with altitude
171 inst->addLayer(2, createTexture("Textures/Panel/short-needle.rgb"));
172 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
174 0.0, 100000.0, 360.0 / 10000.0, 0.0);
176 // Layer 3: ten thousands bug (outside)
177 // moves with altitude
178 inst->addLayer(3, createTexture("Textures/Panel/bug.rgb"));
179 inst->addTransformation(3, FGInstrumentLayer::ROTATION,
181 0.0, 100000.0, 360.0 / 100000.0, 0.0);
188 * Construct a turn coordinator.
190 static FGPanelInstrument *
191 createTurnCoordinator (int x, int y)
193 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
195 // Layer 0: background
196 inst->addLayer(0, createTexture("Textures/Panel/turn-bg.rgb"));
198 // Layer 1: little plane
200 inst->addLayer(1, createTexture("Textures/Panel/turn.rgb"));
201 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
202 FGSteam::get_TC_radps,
203 -30.0, 30.0, 1.0, 0.0);
205 // Layer 2: little ball
206 // moves with slip/skid
207 inst->addLayer(2, createTexture("Textures/Panel/ball.rgb"));
208 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
210 -0.1, 0.1, 450.0, 0.0);
217 * Construct a gyro compass.
219 static FGPanelInstrument *
220 createGyroCompass (int x, int y)
222 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
224 // Layer 0: compass background
225 // rotates with heading
226 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
227 inst->addTransformation(0, FGInstrumentLayer::ROTATION,
229 -360.0, 360.0, -1.0, 0.0);
231 // Layer 1: heading bug
232 // rotates with heading and AP heading
233 inst->addLayer(1, createTexture("Textures/Panel/bug.rgb"));
234 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
236 -360.0, 360.0, -1.0, 0.0);
237 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
239 -360.0, 360.0, 1.0, 0.0);
241 // Layer 2: fixed center
242 inst->addLayer(2, createTexture("Textures/Panel/gyro-fg.rgb"));
249 * Construct a vertical velocity indicator.
251 static FGPanelInstrument *
252 createVerticalVelocity (int x, int y)
254 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
256 // Layer 0: gauge background
257 inst->addLayer(0, createTexture("Textures/Panel/vertical.rgb"));
260 // moves with vertical velocity
261 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
262 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
263 FGSteam::get_VSI_fps,
264 -2000.0, 2000.0, 42.0/500.0, 270.0);
271 * Construct an RPM gauge.
273 static FGPanelInstrument *
274 createRPMGauge (int x, int y)
276 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
278 // Layer 0: gauge background
279 inst->addLayer(0, createTexture("Textures/Panel/rpm.rgb"));
281 // Layer 1: long needle
282 // FIXME: moves with throttle (for now)
283 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
284 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
286 0.0, 100.0, 300.0, -150.0);
293 * Construct a flap position indicator.
295 static FGPanelInstrument *
296 createFlapIndicator (int x, int y)
298 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
300 // Layer 0: gauge background
301 inst->addLayer(0, createTexture("Textures/Panel/flaps.rgb"));
303 // Layer 1: long needle
304 // shifted over, rotates with flap position
305 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
306 inst->addTransformation(1, FGInstrumentLayer::XSHIFT,
307 -(SMALL_W / 4) + (SMALL_W / 16));
308 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
310 0.0, 1.0, 120.0, 30.0);
315 static FGPanelInstrument *
316 createChronometer (int x, int y)
318 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
320 // Layer 0: gauge background
321 inst->addLayer(0, createTexture("Textures/Panel/clock.rgb"));
324 // displays current GMT
325 FGCharInstrumentLayer * text =
326 new FGCharInstrumentLayer(panelGetTime,
327 SMALL_W, SMALL_W, 1);
328 text->setPointSize(14);
329 text->setColor(0.2, 0.2, 0.2);
330 inst->addLayer(text);
331 inst->addTransformation(1, FGInstrumentLayer::XSHIFT, SMALL_W * -0.38);
332 inst->addTransformation(1, FGInstrumentLayer::YSHIFT, SMALL_W * -0.06);
339 * Construct control-position indicators.
341 static FGPanelInstrument *
342 createControls (int x, int y)
344 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
346 // Layer 0: gauge background
347 inst->addLayer(0, createTexture("Textures/Panel/controls.rgb"));
350 // moves left-right with aileron
351 inst->addLayer(1, createTexture("Textures/Panel/bug.rgb"));
352 inst->addTransformation(1, FGInstrumentLayer::XSHIFT, FGBFI::getAileron,
353 -1.0, 1.0, SMALL_W * .75 / 2.0, 0.0);
356 // moves left-right with rudder
357 inst->addLayer(2, createTexture("Textures/Panel/bug.rgb"));
358 inst->addTransformation(2, FGInstrumentLayer::ROTATION, 180.0);
359 inst->addTransformation(2, FGInstrumentLayer::XSHIFT, FGBFI::getRudder,
360 -1.0, 1.0, -SMALL_W * .75 / 2.0, 0.0);
363 // moves up-down with elevator trim
364 inst->addLayer(3, createTexture("Textures/Panel/bug.rgb"));
365 inst->addTransformation(3, FGInstrumentLayer::ROTATION, 270.0);
366 inst->addTransformation(3, FGInstrumentLayer::YSHIFT,
367 -SMALL_W * (3.0 / 8.0));
368 inst->addTransformation(3, FGInstrumentLayer::XSHIFT, FGBFI::getElevatorTrim,
369 -1.0, 1.0, SMALL_W * .75 / 2.0, 0.0);
372 // moves up-down with elevator
373 inst->addLayer(4, createTexture("Textures/Panel/bug.rgb"));
374 inst->addTransformation(4, FGInstrumentLayer::ROTATION, 90.0);
375 inst->addTransformation(4, FGInstrumentLayer::YSHIFT,
376 -SMALL_W * (3.0 / 8.0));
377 inst->addTransformation(4, FGInstrumentLayer::XSHIFT, FGBFI::getElevator,
378 -1.0, 1.0, -SMALL_W * .75 / 2.0, 0.0);
385 * Construct a NAV1 gauge (hardwired).
387 static FGPanelInstrument *
388 createNAV1 (int x, int y)
390 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
392 // Layer 0: background
393 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
394 inst->addTransformation(0, FGInstrumentLayer::ROTATION,
395 FGSteam::get_HackOBS1_deg,
396 -360.0, 360.0, -1.0, 0.0);
397 // Layer 1: long needle
398 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
399 inst->addTransformation(1, FGInstrumentLayer::XSHIFT,
400 FGSteam::get_HackVOR1_deg,
401 -10.0, 10.0, SIX_W / 40.0, 0.0);
402 inst->addTransformation(1, FGInstrumentLayer::YSHIFT,
404 inst->addLayer(2, createTexture("Textures/Panel/long-needle.rgb"));
405 inst->addTransformation(2, FGInstrumentLayer::YSHIFT,
406 FGSteam::get_HackGS_deg,
407 -1.0, 1.0, SIX_W / 5.0, 0.0);
408 inst->addTransformation(2, FGInstrumentLayer::XSHIFT,
410 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
418 * Construct a NAV2 gauge (hardwired).
420 static FGPanelInstrument *
421 createNAV2 (int x, int y)
423 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
425 // Layer 0: background
426 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
427 inst->addTransformation(0, FGInstrumentLayer::ROTATION,
428 FGSteam::get_HackOBS2_deg,
429 -360.0, 360.0, -1.0, 0.0);
430 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
431 inst->addTransformation(1, FGInstrumentLayer::XSHIFT,
432 FGSteam::get_HackVOR2_deg,
433 -10.0, 10.0, SIX_W / 40.0, 0.0);
434 inst->addTransformation(1, FGInstrumentLayer::YSHIFT,
442 * Construct an ADF gauge (hardwired).
444 static FGPanelInstrument *
445 createADF (int x, int y)
447 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
449 // Layer 0: background
450 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
451 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
452 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
453 FGSteam::get_HackADF_deg,
454 -720.0, 720.0, 1.0, 0.0);
461 ////////////////////////////////////////////////////////////////////////
462 // Implementation of FGPanel.
463 ////////////////////////////////////////////////////////////////////////
465 FGPanel * FGPanel::OurPanel = 0;
472 FG_LOG(FG_GENERAL, FG_ALERT, "Multiple panels");
479 _bg = createTexture("Textures/Panel/panel-bg.rgb");
481 // Chronometer alone at side
482 x = SIX_X - SIX_SPACING - 8;
483 _instruments.push_back(createChronometer(x, y));
487 _instruments.push_back(createAirspeedIndicator(x, y));
489 _instruments.push_back(createHorizon(x, y));
491 _instruments.push_back(createAltimeter(x, y));
492 x += SIX_SPACING + 20;
493 _instruments.push_back(createNAV1(x, y));
498 _instruments.push_back(createTurnCoordinator(x, y));
500 _instruments.push_back(createGyroCompass(x, y));
502 _instruments.push_back(createVerticalVelocity(x, y));
503 x += SIX_SPACING + 20;
504 _instruments.push_back(createNAV2(x, y));
508 y -= SIX_SPACING + 10;
509 _instruments.push_back(createControls(x, y));
511 _instruments.push_back(createFlapIndicator(x, y));
513 _instruments.push_back(createRPMGauge(x, y));
514 x += SIX_SPACING + 20;
516 _instruments.push_back(createADF(x, y));
523 instrument_list_type::iterator current = _instruments.begin();
524 instrument_list_type::iterator last = _instruments.end();
526 for ( ; current != last; ++current) {
533 FGPanel::get_height () const
539 FGPanel::ReInit (int x, int y, int finx, int finy)
545 _panel_h = (int)((finy - y) * 0.5768 + 1);
549 FGPanel::Update () const
551 glMatrixMode(GL_PROJECTION);
554 gluOrtho2D(_x, _x + _w, _y, _y + _h);
556 glMatrixMode(GL_MODELVIEW);
560 // Draw the background
561 glEnable(GL_TEXTURE_2D);
562 glDisable(GL_LIGHTING);
564 glEnable(GL_ALPHA_TEST);
565 glEnable(GL_COLOR_MATERIAL);
566 glColor4f(1.0, 1.0, 1.0, 1.0);
567 glBindTexture(GL_TEXTURE_2D, _bg->getHandle());
568 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
569 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
570 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
572 glTexCoord2f(0.0, 0.0); glVertex3f(_x, _y, 0);
573 glTexCoord2f(10.0, 0.0); glVertex3f(_x + _w, _y, 0);
574 glTexCoord2f(10.0, 5.0); glVertex3f(_x + _w, _y + _panel_h, 0);
575 glTexCoord2f(0.0, 5.0); glVertex3f(_x, _y + _panel_h, 0);
578 // Draw the instruments.
579 instrument_list_type::const_iterator current = _instruments.begin();
580 instrument_list_type::const_iterator end = _instruments.end();
582 for ( ; current != end; current++) {
583 FGPanelInstrument * instr = *current;
585 glTranslated(instr->getXPos(), instr->getYPos(), 0);
589 glMatrixMode(GL_PROJECTION);
591 glMatrixMode(GL_MODELVIEW);
593 ssgForceBasicState();
594 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
598 FGPanel::createTexture (const char * relativePath)
602 texture = _textureMap[relativePath];
604 FGPath tpath(current_options.get_fg_root());
605 tpath.append(relativePath);
606 texture = new ssgTexture((char *)tpath.c_str(), false, false);
607 _textureMap[relativePath] = texture;
608 cerr << "Created texture " << relativePath
609 << " handle=" << texture->getHandle() << endl;
617 ////////////////////////////////////////////////////////////////////////
618 // Implementation of FGPanelInstrument.
619 ////////////////////////////////////////////////////////////////////////
622 FGPanelInstrument::FGPanelInstrument ()
628 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
634 FGPanelInstrument::~FGPanelInstrument ()
639 FGPanelInstrument::setPosition (int x, int y)
646 FGPanelInstrument::setSize (int w, int h)
653 FGPanelInstrument::getXPos () const
659 FGPanelInstrument::getYPos () const
666 ////////////////////////////////////////////////////////////////////////
667 // Implementation of FGLayeredInstrument.
668 ////////////////////////////////////////////////////////////////////////
670 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
671 : FGPanelInstrument(x, y, w, h)
675 FGLayeredInstrument::~FGLayeredInstrument ()
677 // FIXME: free layers
681 FGLayeredInstrument::draw () const
683 layer_list::const_iterator it = _layers.begin();
684 layer_list::const_iterator last = _layers.end();
692 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
694 _layers.push_back(layer);
698 FGLayeredInstrument::addLayer (int layer, ssgTexture * texture)
700 addLayer(new FGTexturedInstrumentLayer(texture, _w, _h, layer));
704 FGLayeredInstrument::addTransformation (int layer,
705 FGInstrumentLayer::transform_type type,
706 FGInstrumentLayer::transform_func func,
707 double min, double max,
708 double factor, double offset)
710 _layers[layer]->addTransformation(type, func, min, max, factor, offset);
715 ////////////////////////////////////////////////////////////////////////
716 // Implementation of FGInstrumentLayer.
717 ////////////////////////////////////////////////////////////////////////
719 FGInstrumentLayer::FGInstrumentLayer (int w, int h, int z)
726 FGInstrumentLayer::~FGInstrumentLayer ()
728 transformation_list::iterator it = _transformations.begin();
729 transformation_list::iterator end = _transformations.end();
737 FGInstrumentLayer::transform () const
739 glTranslatef(0.0, 0.0, (_z / 100.0) + 0.1);
741 transformation_list::const_iterator it = _transformations.begin();
742 transformation_list::const_iterator last = _transformations.end();
744 transformation *t = *it;
745 double value = (t->func == 0 ? 0.0 : (*(t->func))());
746 if (value < t->min) {
748 } else if (value > t->max) {
751 value = value * t->factor + t->offset;
755 glTranslatef(value, 0.0, 0.0);
758 glTranslatef(0.0, value, 0.0);
761 glRotatef(-value, 0.0, 0.0, 1.0);
769 FGInstrumentLayer::addTransformation (transform_type type,
771 double min, double max,
772 double factor, double offset)
774 transformation *t = new transformation;
781 _transformations.push_back(t);
786 ////////////////////////////////////////////////////////////////////////
787 // Implementation of FGTexturedInstrumentLayer.
788 ////////////////////////////////////////////////////////////////////////
790 // FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (const char *tname,
791 // int w, int h, int z)
792 // : FGInstrumentLayer(w, h, z)
794 // setTexture(tname);
797 FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (ssgTexture * texture,
799 : FGInstrumentLayer(w, h, z)
804 FGTexturedInstrumentLayer::~FGTexturedInstrumentLayer ()
809 FGTexturedInstrumentLayer::draw () const
816 glBindTexture(GL_TEXTURE_2D, _texture->getHandle());
818 // FIXME: is this really correct
820 glTexCoord2f(0.0, 0.0); glVertex2f(-w2, -h2);
821 glTexCoord2f(1.0, 0.0); glVertex2f(w2, -h2);
822 glTexCoord2f(1.0, 1.0); glVertex2f(w2, h2);
823 glTexCoord2f(0.0, 1.0); glVertex2f(-w2, h2);
829 // FGTexturedInstrumentLayer::setTexture (const char *textureName)
831 // FGPath tpath(current_options.get_fg_root());
832 // tpath.append(textureName);
833 // ssgTexture * texture = new ssgTexture((char *)tpath.c_str(), false, false);
834 // setTexture(texture);
839 ////////////////////////////////////////////////////////////////////////
840 // Implementation of FGCharInstrumentLayer.
841 ////////////////////////////////////////////////////////////////////////
843 FGCharInstrumentLayer::FGCharInstrumentLayer (text_func func,
845 : FGInstrumentLayer(w, h, z),
848 _renderer.setFont(guiFntHandle);
849 _renderer.setPointSize(14);
850 _color[0] = _color[1] = _color[2] = 0.0;
854 FGCharInstrumentLayer::~FGCharInstrumentLayer ()
859 FGCharInstrumentLayer::draw () const
865 _renderer.start3f(0, 0, 0);
866 _renderer.puts((*_func)(_buf));
868 glColor4f(1.0, 1.0, 1.0, 1.0); // FIXME
873 FGCharInstrumentLayer::setColor (float r, float g, float b)
882 FGCharInstrumentLayer::setPointSize (const float size)
884 _renderer.setPointSize(size);
888 FGCharInstrumentLayer::setFont(fntFont * font)
890 _renderer.setFont(font);