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"
47 extern fgAPDataPtr APDataGlobal;
52 #define SIX_SPACING (SIX_W + 5)
57 ////////////////////////////////////////////////////////////////////////
58 // Static functions for obtaining settings.
60 // These should be replaced with functions from a global facade,
61 // or BFI (Big Friendly Interface).
62 ////////////////////////////////////////////////////////////////////////
64 static char * panelGetTime (char * buf)
66 struct tm * t = FGTime::cur_time_params->getGmt();
67 sprintf(buf, " %.2d:%.2d:%.2d",
68 t->tm_hour, t->tm_min, t->tm_sec);
74 ////////////////////////////////////////////////////////////////////////
75 // Static factory functions to create textured gauges.
77 // These will be replaced first with a giant table, and then with
78 // configuration files read from an external source, but for now
79 // they're hard-coded.
80 ////////////////////////////////////////////////////////////////////////
83 createTexture (const char * relativePath)
85 return FGPanel::OurPanel->createTexture(relativePath);
90 * Construct an airspeed indicator for a single-engine prop.
92 static FGPanelInstrument *
93 createAirspeedIndicator (int x, int y)
95 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
97 // Layer 0: gauge background.
98 inst->addLayer(0, createTexture("Textures/Panel/airspeed.rgb"));
101 // Rotates with airspeed.
102 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
103 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
105 30.0, 220.0, 36.0 / 20.0, -54.0);
111 * Construct an artificial horizon.
113 static FGPanelInstrument *
114 createHorizon (int x, int y)
116 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
118 // Layer 0: coloured background
119 // moves with roll only
120 inst->addLayer(0, createTexture("Textures/Panel/horizon-bg.rgb"));
121 inst->addTransformation(0, FGInstrumentLayer::ROTATION,
123 -360.0, 360.0, -1.0, 0.0);
125 // Layer 1: floating horizon
126 // moves with roll and pitch
127 inst->addLayer(1, createTexture("Textures/Panel/horizon-float.rgb"));
128 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
130 -360.0, 360.0, -1.0, 0.0);
131 inst->addTransformation(1, FGInstrumentLayer::YSHIFT,
133 -20.0, 20.0, -(1.5 / 160.0) * SIX_W, 0.0);
136 // moves with roll only
137 inst->addLayer(2, createTexture("Textures/Panel/horizon-rim.rgb"));
138 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
140 -360.0, 360.0, -1.0, 0.0);
142 // Layer 3: glass front of gauge
143 // fixed, with markings
144 inst->addLayer(3, createTexture("Textures/Panel/horizon-fg.rgb"));
151 * Construct an altimeter.
153 static FGPanelInstrument *
154 createAltimeter (int x, int y)
156 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
158 // Layer 0: gauge background
159 inst->addLayer(0, createTexture("Textures/Panel/altimeter.rgb"));
161 // Layer 1: hundreds needle (long)
162 // moves with altitude
163 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
164 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
166 0.0, 100000.0, 360.0 / 1000.0, 0.0);
168 // Layer 2: thousands needle (short)
169 // moves with altitude
170 inst->addLayer(2, createTexture("Textures/Panel/short-needle.rgb"));
171 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
173 0.0, 100000.0, 360.0 / 10000.0, 0.0);
175 // Layer 3: ten thousands bug (outside)
176 // moves with altitude
177 inst->addLayer(3, createTexture("Textures/Panel/bug.rgb"));
178 inst->addTransformation(3, FGInstrumentLayer::ROTATION,
180 0.0, 100000.0, 360.0 / 100000.0, 0.0);
187 * Construct a turn coordinator.
189 static FGPanelInstrument *
190 createTurnCoordinator (int x, int y)
192 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
194 // Layer 0: background
195 inst->addLayer(0, createTexture("Textures/Panel/turn-bg.rgb"));
197 // Layer 1: little plane
199 inst->addLayer(1, createTexture("Textures/Panel/turn.rgb"));
200 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
202 -30.0, 30.0, 1.0, 0.0);
204 // Layer 2: little ball
205 // moves with slip/skid
206 inst->addLayer(2, createTexture("Textures/Panel/ball.rgb"));
207 inst->addTransformation(2, FGInstrumentLayer::ROTATION,
209 -0.1, 0.1, 450.0, 0.0);
216 * Construct a gyro compass.
218 static FGPanelInstrument *
219 createGyroCompass (int x, int y)
221 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
223 // Layer 0: compass background
224 // rotates with heading
225 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
226 inst->addTransformation(0, FGInstrumentLayer::ROTATION,
228 -360.0, 360.0, -1.0, 0.0);
230 // Layer 1: heading bug
231 // rotates with heading and AP heading
232 inst->addLayer(1, createTexture("Textures/Panel/bug.rgb"));
233 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
235 -360.0, 360.0, -1.0, 0.0);
236 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
238 -360.0, 360.0, 1.0, 0.0);
240 // Layer 2: fixed center
241 inst->addLayer(2, createTexture("Textures/Panel/gyro-fg.rgb"));
248 * Construct a vertical velocity indicator.
250 static FGPanelInstrument *
251 createVerticalVelocity (int x, int y)
253 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
255 // Layer 0: gauge background
256 inst->addLayer(0, createTexture("Textures/Panel/vertical.rgb"));
259 // moves with vertical velocity
260 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
261 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
262 FGBFI::getVerticalSpeed,
263 -2000.0, 2000.0, 42.0/500.0, 270.0);
270 * Construct an RPM gauge.
272 static FGPanelInstrument *
273 createRPMGauge (int x, int y)
275 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
277 // Layer 0: gauge background
278 inst->addLayer(0, createTexture("Textures/Panel/rpm.rgb"));
280 // Layer 1: long needle
281 // FIXME: moves with throttle (for now)
282 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
283 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
285 0.0, 100.0, 300.0, -150.0);
292 * Construct a flap position indicator.
294 static FGPanelInstrument *
295 createFlapIndicator (int x, int y)
297 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
299 // Layer 0: gauge background
300 inst->addLayer(0, createTexture("Textures/Panel/flaps.rgb"));
302 // Layer 1: long needle
303 // shifted over, rotates with flap position
304 inst->addLayer(1, createTexture("Textures/Panel/long-needle.rgb"));
305 inst->addTransformation(1, FGInstrumentLayer::XSHIFT,
306 -(SMALL_W / 4) + (SMALL_W / 16));
307 inst->addTransformation(1, FGInstrumentLayer::ROTATION,
309 0.0, 1.0, 120.0, 30.0);
314 static FGPanelInstrument *
315 createChronometer (int x, int y)
317 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
319 // Layer 0: gauge background
320 inst->addLayer(0, createTexture("Textures/Panel/clock.rgb"));
323 // displays current GMT
324 FGCharInstrumentLayer * text =
325 new FGCharInstrumentLayer(panelGetTime,
326 SMALL_W, SMALL_W, 1);
327 text->setPointSize(14);
328 text->setColor(0.2, 0.2, 0.2);
329 inst->addLayer(text);
330 inst->addTransformation(1, FGInstrumentLayer::XSHIFT, SMALL_W * -0.38);
331 inst->addTransformation(1, FGInstrumentLayer::YSHIFT, SMALL_W * -0.06);
338 * Construct control-position indicators.
340 static FGPanelInstrument *
341 createControls (int x, int y)
343 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
345 // Layer 0: gauge background
346 inst->addLayer(0, createTexture("Textures/Panel/controls.rgb"));
349 // moves left-right with aileron
350 inst->addLayer(1, createTexture("Textures/Panel/bug.rgb"));
351 inst->addTransformation(1, FGInstrumentLayer::XSHIFT, FGBFI::getAileron,
352 -1.0, 1.0, SMALL_W * .75 / 2.0, 0.0);
355 // moves left-right with rudder
356 inst->addLayer(2, createTexture("Textures/Panel/bug.rgb"));
357 inst->addTransformation(2, FGInstrumentLayer::ROTATION, 180.0);
358 inst->addTransformation(2, FGInstrumentLayer::XSHIFT, FGBFI::getRudder,
359 -1.0, 1.0, -SMALL_W * .75 / 2.0, 0.0);
362 // moves up-down with elevator trim
363 inst->addLayer(3, createTexture("Textures/Panel/bug.rgb"));
364 inst->addTransformation(3, FGInstrumentLayer::ROTATION, 270.0);
365 inst->addTransformation(3, FGInstrumentLayer::YSHIFT,
366 -SMALL_W * (3.0 / 8.0));
367 inst->addTransformation(3, FGInstrumentLayer::XSHIFT, FGBFI::getElevatorTrim,
368 -1.0, 1.0, SMALL_W * .75 / 2.0, 0.0);
371 // moves up-down with elevator
372 inst->addLayer(4, createTexture("Textures/Panel/bug.rgb"));
373 inst->addTransformation(4, FGInstrumentLayer::ROTATION, 90.0);
374 inst->addTransformation(4, FGInstrumentLayer::YSHIFT,
375 -SMALL_W * (3.0 / 8.0));
376 inst->addTransformation(4, FGInstrumentLayer::XSHIFT, FGBFI::getElevator,
377 -1.0, 1.0, -SMALL_W * .75 / 2.0, 0.0);
384 * Construct a NAV1 gauge (dummy for now).
386 static FGPanelInstrument *
387 createNAV1 (int x, int y)
389 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
391 // Layer 0: background
392 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
399 * Construct a NAV2 gauge (dummy for now).
401 static FGPanelInstrument *
402 createNAV2 (int x, int y)
404 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
406 // Layer 0: background
407 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
414 * Construct an ADF gauge (dummy for now).
416 static FGPanelInstrument *
417 createADF (int x, int y)
419 FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
421 // Layer 0: background
422 inst->addLayer(0, createTexture("Textures/Panel/gyro-bg.rgb"));
429 ////////////////////////////////////////////////////////////////////////
430 // Implementation of FGPanel.
431 ////////////////////////////////////////////////////////////////////////
433 FGPanel * FGPanel::OurPanel = 0;
440 FG_LOG(FG_GENERAL, FG_ALERT, "Multiple panels");
447 _bg = createTexture("Textures/Panel/panel-bg.rgb");
449 // Chronometer alone at side
450 x = SIX_X - SIX_SPACING - 8;
451 _instruments.push_back(createChronometer(x, y));
455 _instruments.push_back(createAirspeedIndicator(x, y));
457 _instruments.push_back(createHorizon(x, y));
459 _instruments.push_back(createAltimeter(x, y));
460 x += SIX_SPACING + 20;
461 _instruments.push_back(createNAV1(x, y));
466 _instruments.push_back(createTurnCoordinator(x, y));
468 _instruments.push_back(createGyroCompass(x, y));
470 _instruments.push_back(createVerticalVelocity(x, y));
471 x += SIX_SPACING + 20;
472 _instruments.push_back(createNAV2(x, y));
476 y -= SIX_SPACING + 10;
477 _instruments.push_back(createControls(x, y));
479 _instruments.push_back(createFlapIndicator(x, y));
481 _instruments.push_back(createRPMGauge(x, y));
482 x += SIX_SPACING + 20;
484 _instruments.push_back(createADF(x, y));
491 instrument_list_type::iterator current = _instruments.begin();
492 instrument_list_type::iterator last = _instruments.end();
494 for ( ; current != last; ++current) {
501 FGPanel::get_height () const
507 FGPanel::ReInit (int x, int y, int finx, int finy)
513 _panel_h = (int)((finy - y) * 0.5768 + 1);
517 FGPanel::Update () const
519 glMatrixMode(GL_PROJECTION);
522 gluOrtho2D(_x, _x + _w, _y, _y + _h);
524 glMatrixMode(GL_MODELVIEW);
528 // Draw the background
529 glEnable(GL_TEXTURE_2D);
530 glDisable(GL_LIGHTING);
531 glColor3f(1.0, 1.0, 1.0);
532 glBindTexture(GL_TEXTURE_2D, _bg->getHandle());
533 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
534 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
535 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
537 glTexCoord2f(0.0, 0.0); glVertex3f(_x, _y, 0);
538 glTexCoord2f(10.0, 0.0); glVertex3f(_x + _w, _y, 0);
539 glTexCoord2f(10.0, 5.0); glVertex3f(_x + _w, _y + _panel_h, 0);
540 glTexCoord2f(0.0, 5.0); glVertex3f(_x, _y + _panel_h, 0);
543 // Draw the instruments.
544 instrument_list_type::const_iterator current = _instruments.begin();
545 instrument_list_type::const_iterator end = _instruments.end();
547 for ( ; current != end; current++) {
548 FGPanelInstrument * instr = *current;
550 glTranslated(instr->getXPos(), instr->getYPos(), 0);
554 glMatrixMode(GL_PROJECTION);
556 glMatrixMode(GL_MODELVIEW);
558 ssgForceBasicState();
559 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
563 FGPanel::createTexture (const char * relativePath)
567 texture = _textureMap[relativePath];
569 FGPath tpath(current_options.get_fg_root());
570 tpath.append(relativePath);
571 texture = new ssgTexture((char *)tpath.c_str(), false, false);
572 _textureMap[relativePath] = texture;
573 cerr << "Created texture " << relativePath
574 << " handle=" << texture->getHandle() << endl;
582 ////////////////////////////////////////////////////////////////////////
583 // Implementation of FGPanelInstrument.
584 ////////////////////////////////////////////////////////////////////////
587 FGPanelInstrument::FGPanelInstrument ()
593 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
599 FGPanelInstrument::~FGPanelInstrument ()
604 FGPanelInstrument::setPosition (int x, int y)
611 FGPanelInstrument::setSize (int w, int h)
618 FGPanelInstrument::getXPos () const
624 FGPanelInstrument::getYPos () const
631 ////////////////////////////////////////////////////////////////////////
632 // Implementation of FGLayeredInstrument.
633 ////////////////////////////////////////////////////////////////////////
635 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
636 : FGPanelInstrument(x, y, w, h)
640 FGLayeredInstrument::~FGLayeredInstrument ()
642 // FIXME: free layers
646 FGLayeredInstrument::draw () const
648 layer_list::const_iterator it = _layers.begin();
649 layer_list::const_iterator last = _layers.end();
657 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
659 _layers.push_back(layer);
663 FGLayeredInstrument::addLayer (int layer, ssgTexture * texture)
665 addLayer(new FGTexturedInstrumentLayer(texture, _w, _h, layer));
669 FGLayeredInstrument::addTransformation (int layer,
670 FGInstrumentLayer::transform_type type,
671 FGInstrumentLayer::transform_func func,
672 double min, double max,
673 double factor, double offset)
675 _layers[layer]->addTransformation(type, func, min, max, factor, offset);
680 ////////////////////////////////////////////////////////////////////////
681 // Implementation of FGInstrumentLayer.
682 ////////////////////////////////////////////////////////////////////////
684 FGInstrumentLayer::FGInstrumentLayer (int w, int h, int z)
691 FGInstrumentLayer::~FGInstrumentLayer ()
693 transformation_list::iterator it = _transformations.begin();
694 transformation_list::iterator end = _transformations.end();
702 FGInstrumentLayer::transform () const
704 glTranslatef(0.0, 0.0, (_z / 100.0) + 0.1);
706 transformation_list::const_iterator it = _transformations.begin();
707 transformation_list::const_iterator last = _transformations.end();
709 transformation *t = *it;
710 double value = (t->func == 0 ? 0.0 : (*(t->func))());
711 if (value < t->min) {
713 } else if (value > t->max) {
716 value = value * t->factor + t->offset;
720 glTranslatef(value, 0.0, 0.0);
723 glTranslatef(0.0, value, 0.0);
726 glRotatef(-value, 0.0, 0.0, 1.0);
734 FGInstrumentLayer::addTransformation (transform_type type,
736 double min, double max,
737 double factor, double offset)
739 transformation *t = new transformation;
746 _transformations.push_back(t);
751 ////////////////////////////////////////////////////////////////////////
752 // Implementation of FGTexturedInstrumentLayer.
753 ////////////////////////////////////////////////////////////////////////
755 // FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (const char *tname,
756 // int w, int h, int z)
757 // : FGInstrumentLayer(w, h, z)
759 // setTexture(tname);
762 FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (ssgTexture * texture,
764 : FGInstrumentLayer(w, h, z)
769 FGTexturedInstrumentLayer::~FGTexturedInstrumentLayer ()
774 FGTexturedInstrumentLayer::draw () const
781 glBindTexture(GL_TEXTURE_2D, _texture->getHandle());
783 // FIXME: is this really correct
785 glTexCoord2f(0.0, 0.0); glVertex2f(-w2, -h2);
786 glTexCoord2f(1.0, 0.0); glVertex2f(w2, -h2);
787 glTexCoord2f(1.0, 1.0); glVertex2f(w2, h2);
788 glTexCoord2f(0.0, 1.0); glVertex2f(-w2, h2);
794 // FGTexturedInstrumentLayer::setTexture (const char *textureName)
796 // FGPath tpath(current_options.get_fg_root());
797 // tpath.append(textureName);
798 // ssgTexture * texture = new ssgTexture((char *)tpath.c_str(), false, false);
799 // setTexture(texture);
804 ////////////////////////////////////////////////////////////////////////
805 // Implementation of FGCharInstrumentLayer.
806 ////////////////////////////////////////////////////////////////////////
808 FGCharInstrumentLayer::FGCharInstrumentLayer (text_func func,
810 : FGInstrumentLayer(w, h, z),
813 _renderer.setFont(guiFntHandle);
814 _renderer.setPointSize(14);
815 _color[0] = _color[1] = _color[2] = 0.0;
818 FGCharInstrumentLayer::~FGCharInstrumentLayer ()
823 FGCharInstrumentLayer::draw () const
829 _renderer.start3f(0, 0, 0);
830 _renderer.puts((*_func)(_buf));
832 glColor3f(1.0, 1.0, 1.0); // FIXME
837 FGCharInstrumentLayer::setColor (float r, float g, float b)
845 FGCharInstrumentLayer::setPointSize (const float size)
847 _renderer.setPointSize(size);
851 FGCharInstrumentLayer::setFont(fntFont * font)
853 _renderer.setFont(font);