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,
209 FGSteam::get_TC_radps,
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 (dummy for now).
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"));
400 * Construct a NAV2 gauge (dummy for now).
402 static FGPanelInstrument *
403 createNAV2 (int x, int y)
405 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
407 // Layer 0: background
408 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
415 * Construct an ADF gauge (dummy for now).
417 static FGPanelInstrument *
418 createADF (int x, int y)
420 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
422 // Layer 0: background
423 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
430 ////////////////////////////////////////////////////////////////////////
431 // Implementation of FGPanel.
432 ////////////////////////////////////////////////////////////////////////
434 FGPanel * FGPanel::OurPanel = 0;
441 FG_LOG(FG_GENERAL, FG_ALERT, "Multiple panels");
448 _bg = createTexture("Textures/Panel/panel-bg.rgb");
450 // Chronometer alone at side
451 x = SIX_X - SIX_SPACING - 8;
452 _instruments.push_back(createChronometer(x, y));
456 _instruments.push_back(createAirspeedIndicator(x, y));
458 _instruments.push_back(createHorizon(x, y));
460 _instruments.push_back(createAltimeter(x, y));
461 x += SIX_SPACING + 20;
462 _instruments.push_back(createNAV1(x, y));
467 _instruments.push_back(createTurnCoordinator(x, y));
469 _instruments.push_back(createGyroCompass(x, y));
471 _instruments.push_back(createVerticalVelocity(x, y));
472 x += SIX_SPACING + 20;
473 _instruments.push_back(createNAV2(x, y));
477 y -= SIX_SPACING + 10;
478 _instruments.push_back(createControls(x, y));
480 _instruments.push_back(createFlapIndicator(x, y));
482 _instruments.push_back(createRPMGauge(x, y));
483 x += SIX_SPACING + 20;
485 _instruments.push_back(createADF(x, y));
492 instrument_list_type::iterator current = _instruments.begin();
493 instrument_list_type::iterator last = _instruments.end();
495 for ( ; current != last; ++current) {
502 FGPanel::get_height () const
508 FGPanel::ReInit (int x, int y, int finx, int finy)
514 _panel_h = (int)((finy - y) * 0.5768 + 1);
518 FGPanel::Update () const
520 glMatrixMode(GL_PROJECTION);
523 gluOrtho2D(_x, _x + _w, _y, _y + _h);
525 glMatrixMode(GL_MODELVIEW);
529 // Draw the background
530 glEnable(GL_TEXTURE_2D);
531 glDisable(GL_LIGHTING);
533 glEnable(GL_ALPHA_TEST);
534 glEnable(GL_COLOR_MATERIAL);
535 glColor4f(1.0, 1.0, 1.0, 1.0);
536 glBindTexture(GL_TEXTURE_2D, _bg->getHandle());
537 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
538 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
539 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
541 glTexCoord2f(0.0, 0.0); glVertex3f(_x, _y, 0);
542 glTexCoord2f(10.0, 0.0); glVertex3f(_x + _w, _y, 0);
543 glTexCoord2f(10.0, 5.0); glVertex3f(_x + _w, _y + _panel_h, 0);
544 glTexCoord2f(0.0, 5.0); glVertex3f(_x, _y + _panel_h, 0);
547 // Draw the instruments.
548 instrument_list_type::const_iterator current = _instruments.begin();
549 instrument_list_type::const_iterator end = _instruments.end();
551 for ( ; current != end; current++) {
552 FGPanelInstrument * instr = *current;
554 glTranslated(instr->getXPos(), instr->getYPos(), 0);
558 glMatrixMode(GL_PROJECTION);
560 glMatrixMode(GL_MODELVIEW);
562 ssgForceBasicState();
563 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
567 FGPanel::createTexture (const char * relativePath)
571 texture = _textureMap[relativePath];
573 FGPath tpath(current_options.get_fg_root());
574 tpath.append(relativePath);
575 texture = new ssgTexture((char *)tpath.c_str(), false, false);
576 _textureMap[relativePath] = texture;
577 cerr << "Created texture " << relativePath
578 << " handle=" << texture->getHandle() << endl;
586 ////////////////////////////////////////////////////////////////////////
587 // Implementation of FGPanelInstrument.
588 ////////////////////////////////////////////////////////////////////////
591 FGPanelInstrument::FGPanelInstrument ()
597 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
603 FGPanelInstrument::~FGPanelInstrument ()
608 FGPanelInstrument::setPosition (int x, int y)
615 FGPanelInstrument::setSize (int w, int h)
622 FGPanelInstrument::getXPos () const
628 FGPanelInstrument::getYPos () const
635 ////////////////////////////////////////////////////////////////////////
636 // Implementation of FGLayeredInstrument.
637 ////////////////////////////////////////////////////////////////////////
639 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
640 : FGPanelInstrument(x, y, w, h)
644 FGLayeredInstrument::~FGLayeredInstrument ()
646 // FIXME: free layers
650 FGLayeredInstrument::draw () const
652 layer_list::const_iterator it = _layers.begin();
653 layer_list::const_iterator last = _layers.end();
661 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
663 _layers.push_back(layer);
667 FGLayeredInstrument::addLayer (int layer, ssgTexture * texture)
669 addLayer(new FGTexturedInstrumentLayer(texture, _w, _h, layer));
673 FGLayeredInstrument::addTransformation (int layer,
674 FGInstrumentLayer::transform_type type,
675 FGInstrumentLayer::transform_func func,
676 double min, double max,
677 double factor, double offset)
679 _layers[layer]->addTransformation(type, func, min, max, factor, offset);
684 ////////////////////////////////////////////////////////////////////////
685 // Implementation of FGInstrumentLayer.
686 ////////////////////////////////////////////////////////////////////////
688 FGInstrumentLayer::FGInstrumentLayer (int w, int h, int z)
695 FGInstrumentLayer::~FGInstrumentLayer ()
697 transformation_list::iterator it = _transformations.begin();
698 transformation_list::iterator end = _transformations.end();
706 FGInstrumentLayer::transform () const
708 glTranslatef(0.0, 0.0, (_z / 100.0) + 0.1);
710 transformation_list::const_iterator it = _transformations.begin();
711 transformation_list::const_iterator last = _transformations.end();
713 transformation *t = *it;
714 double value = (t->func == 0 ? 0.0 : (*(t->func))());
715 if (value < t->min) {
717 } else if (value > t->max) {
720 value = value * t->factor + t->offset;
724 glTranslatef(value, 0.0, 0.0);
727 glTranslatef(0.0, value, 0.0);
730 glRotatef(-value, 0.0, 0.0, 1.0);
738 FGInstrumentLayer::addTransformation (transform_type type,
740 double min, double max,
741 double factor, double offset)
743 transformation *t = new transformation;
750 _transformations.push_back(t);
755 ////////////////////////////////////////////////////////////////////////
756 // Implementation of FGTexturedInstrumentLayer.
757 ////////////////////////////////////////////////////////////////////////
759 // FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (const char *tname,
760 // int w, int h, int z)
761 // : FGInstrumentLayer(w, h, z)
763 // setTexture(tname);
766 FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (ssgTexture * texture,
768 : FGInstrumentLayer(w, h, z)
773 FGTexturedInstrumentLayer::~FGTexturedInstrumentLayer ()
778 FGTexturedInstrumentLayer::draw () const
785 glBindTexture(GL_TEXTURE_2D, _texture->getHandle());
787 // FIXME: is this really correct
789 glTexCoord2f(0.0, 0.0); glVertex2f(-w2, -h2);
790 glTexCoord2f(1.0, 0.0); glVertex2f(w2, -h2);
791 glTexCoord2f(1.0, 1.0); glVertex2f(w2, h2);
792 glTexCoord2f(0.0, 1.0); glVertex2f(-w2, h2);
798 // FGTexturedInstrumentLayer::setTexture (const char *textureName)
800 // FGPath tpath(current_options.get_fg_root());
801 // tpath.append(textureName);
802 // ssgTexture * texture = new ssgTexture((char *)tpath.c_str(), false, false);
803 // setTexture(texture);
808 ////////////////////////////////////////////////////////////////////////
809 // Implementation of FGCharInstrumentLayer.
810 ////////////////////////////////////////////////////////////////////////
812 FGCharInstrumentLayer::FGCharInstrumentLayer (text_func func,
814 : FGInstrumentLayer(w, h, z),
817 _renderer.setFont(guiFntHandle);
818 _renderer.setPointSize(14);
819 _color[0] = _color[1] = _color[2] = 0.0;
823 FGCharInstrumentLayer::~FGCharInstrumentLayer ()
828 FGCharInstrumentLayer::draw () const
834 _renderer.start3f(0, 0, 0);
835 _renderer.puts((*_func)(_buf));
837 glColor4f(1.0, 1.0, 1.0, 1.0); // FIXME
842 FGCharInstrumentLayer::setColor (float r, float g, float b)
851 FGCharInstrumentLayer::setPointSize (const float size)
853 _renderer.setPointSize(size);
857 FGCharInstrumentLayer::setFont(fntFont * font)
859 _renderer.setFont(font);