]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/panel.cxx
NAV1 is now the ILS-28R on airport KMYF,
[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 <plib/fnt.h>
33 #include <GL/glut.h>
34
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>
42
43 #include "cockpit.hxx"
44 #include "panel.hxx"
45 #include "hud.hxx"
46 #include "steam.hxx"
47
48 extern fgAPDataPtr APDataGlobal;
49
50 #define SIX_X 200
51 #define SIX_Y 345
52 #define SIX_W 128
53 #define SIX_SPACING (SIX_W + 5)
54 #define SMALL_W 112
55
56
57 \f
58 ////////////////////////////////////////////////////////////////////////
59 // Static functions for obtaining settings.
60 //
61 // These should be replaced with functions from a global facade,
62 // or BFI (Big Friendly Interface).
63 ////////////////////////////////////////////////////////////////////////
64
65 static char * panelGetTime (char * buf)
66 {
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);
70   return buf;
71 }
72
73
74 \f
75 ////////////////////////////////////////////////////////////////////////
76 // Static factory functions to create textured gauges.
77 //
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 ////////////////////////////////////////////////////////////////////////
82
83 static ssgTexture *
84 createTexture (const char * relativePath)
85 {
86   return FGPanel::OurPanel->createTexture(relativePath);
87 }
88
89
90 /**
91  * Construct an airspeed indicator for a single-engine prop.
92  */
93 static FGPanelInstrument *
94 createAirspeedIndicator (int x, int y)
95 {
96   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
97
98                                 // Layer 0: gauge background.
99   inst->addLayer(0, createTexture("Textures/Panel/airspeed.rgb"));
100
101                                 // Layer 1: needle.
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);
107   return inst;
108 }
109
110
111 /**
112  * Construct an artificial horizon.
113  */
114 static FGPanelInstrument *
115 createHorizon (int x, int y)
116 {
117   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
118
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,
123                           FGBFI::getRoll,
124                           -360.0, 360.0, -1.0, 0.0);
125
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,
130                           FGBFI::getRoll,
131                           -360.0, 360.0, -1.0, 0.0);
132   inst->addTransformation(1, FGInstrumentLayer::YSHIFT,
133                           FGBFI::getPitch,
134                           -20.0, 20.0, -(1.5 / 160.0) * SIX_W, 0.0);
135
136                                 // Layer 2: rim
137                                 // moves with roll only
138   inst->addLayer(2, createTexture("Textures/Panel/horizon-rim.rgb"));
139   inst->addTransformation(2, FGInstrumentLayer::ROTATION,
140                           FGBFI::getRoll,
141                           -360.0, 360.0, -1.0, 0.0);
142
143                                 // Layer 3: glass front of gauge
144                                 // fixed, with markings
145   inst->addLayer(3, createTexture("Textures/Panel/horizon-fg.rgb"));
146
147   return inst;
148 }
149
150
151 /**
152  * Construct an altimeter.
153  */
154 static FGPanelInstrument *
155 createAltimeter (int x, int y)
156 {
157   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
158
159                                 // Layer 0: gauge background
160   inst->addLayer(0, createTexture("Textures/Panel/altimeter.rgb"));
161
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,
166                           FGSteam::get_ALT_ft,
167                           0.0, 100000.0, 360.0 / 1000.0, 0.0);
168
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,
173                           FGSteam::get_ALT_ft,
174                           0.0, 100000.0, 360.0 / 10000.0, 0.0);
175
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,
180                           FGSteam::get_ALT_ft,
181                           0.0, 100000.0, 360.0 / 100000.0, 0.0);
182
183   return inst;
184 }
185
186
187 /**
188  * Construct a turn coordinator.
189  */
190 static FGPanelInstrument *
191 createTurnCoordinator (int x, int y)
192 {
193   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
194
195                                 // Layer 0: background
196   inst->addLayer(0, createTexture("Textures/Panel/turn-bg.rgb"));
197
198                                 // Layer 1: little plane
199                                 // moves with roll
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);
204
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_rad,
210                           -0.1, 0.1, 450.0, 0.0);
211
212   return inst;
213 }
214
215
216 /**
217  * Construct a gyro compass.
218  */
219 static FGPanelInstrument *
220 createGyroCompass (int x, int y)
221 {
222   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
223
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,
228                           FGSteam::get_DG_deg,
229                           -360.0, 360.0, -1.0, 0.0);
230
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,
235                           FGSteam::get_DG_deg,
236                           -360.0, 360.0, -1.0, 0.0);
237   inst->addTransformation(1, FGInstrumentLayer::ROTATION,
238                           FGBFI::getAPHeading,
239                           -360.0, 360.0, 1.0, 0.0);
240
241                                 // Layer 2: fixed center
242   inst->addLayer(2, createTexture("Textures/Panel/gyro-fg.rgb"));
243
244   return inst;
245 }
246
247
248 /**
249  * Construct a vertical velocity indicator.
250  */
251 static FGPanelInstrument *
252 createVerticalVelocity (int x, int y)
253 {
254   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
255
256                                 // Layer 0: gauge background
257   inst->addLayer(0, createTexture("Textures/Panel/vertical.rgb"));
258
259                                 // Layer 1: needle
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);
265
266   return inst;
267 }
268
269
270 /**
271  * Construct an RPM gauge.
272  */
273 static FGPanelInstrument *
274 createRPMGauge (int x, int y)
275 {
276   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
277
278                                 // Layer 0: gauge background
279   inst->addLayer(0, createTexture("Textures/Panel/rpm.rgb"));
280
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,
285                           FGBFI::getThrottle,
286                           0.0, 100.0, 300.0, -150.0);
287
288   return inst;
289 }
290
291
292 /**
293  * Construct a flap position indicator.
294  */
295 static FGPanelInstrument *
296 createFlapIndicator (int x, int y)
297 {
298   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
299
300                                 // Layer 0: gauge background
301   inst->addLayer(0, createTexture("Textures/Panel/flaps.rgb"));
302
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,
309                           FGBFI::getFlaps,
310                           0.0, 1.0, 120.0, 30.0);
311
312   return inst;
313 }
314
315 static FGPanelInstrument *
316 createChronometer (int x, int y)
317 {
318   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
319
320                                 // Layer 0: gauge background
321   inst->addLayer(0, createTexture("Textures/Panel/clock.rgb"));
322
323                                 // Layer 1: text
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);
333
334   return inst;
335 }
336
337
338 /**
339  * Construct control-position indicators.
340  */
341 static FGPanelInstrument *
342 createControls (int x, int y)
343 {
344   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
345
346                                 // Layer 0: gauge background
347   inst->addLayer(0, createTexture("Textures/Panel/controls.rgb"));
348
349                                 // Layer 1: bug
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);
354
355                                 // Layer 2: bug
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);
361
362                                 // Layer 3: bug
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);
370
371                                 // Layer 4: bug
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);
379
380   return inst;
381 }
382
383
384 /**
385  * Construct a NAV1 gauge (hardwired).
386  */
387 static FGPanelInstrument *
388 createNAV1 (int x, int y)
389 {
390   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
391
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,
403                           -SIX_W / 4.4 );
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,
409                           -SIX_W / 4.4 );
410   inst->addTransformation(2, FGInstrumentLayer::ROTATION,
411                           90 );
412
413   return inst;
414 }
415
416
417 /**
418  * Construct a NAV2 gauge (hardwired).
419  */
420 static FGPanelInstrument *
421 createNAV2 (int x, int y)
422 {
423   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
424
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,
435                           -SIX_W / 4.4 );
436
437   return inst;
438 }
439
440
441 /**
442  * Construct an ADF gauge (hardwired).
443  */
444 static FGPanelInstrument *
445 createADF (int x, int y)
446 {
447   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
448
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);
455
456   return inst;
457 }
458
459
460 \f
461 ////////////////////////////////////////////////////////////////////////
462 // Implementation of FGPanel.
463 ////////////////////////////////////////////////////////////////////////
464
465 FGPanel * FGPanel::OurPanel = 0;
466
467 FGPanel::FGPanel ()
468 {
469   if (OurPanel == 0) {
470     OurPanel = this;
471   } else {
472     FG_LOG(FG_GENERAL, FG_ALERT, "Multiple panels");
473     exit(-1);
474   }
475
476   int x = SIX_X;
477   int y = SIX_Y;
478
479   _bg = createTexture("Textures/Panel/panel-bg.rgb");
480
481                                 // Chronometer alone at side
482   x = SIX_X - SIX_SPACING - 8;
483   _instruments.push_back(createChronometer(x, y));
484
485                                 // Top row
486   x = SIX_X;
487   _instruments.push_back(createAirspeedIndicator(x, y));
488   x += SIX_SPACING;
489   _instruments.push_back(createHorizon(x, y));
490   x += SIX_SPACING;
491   _instruments.push_back(createAltimeter(x, y));
492   x += SIX_SPACING + 20;
493   _instruments.push_back(createNAV1(x, y));
494
495                                 // Middle row
496   x = SIX_X;
497   y -= SIX_SPACING;
498   _instruments.push_back(createTurnCoordinator(x, y));
499   x += SIX_SPACING;
500   _instruments.push_back(createGyroCompass(x, y));
501   x += SIX_SPACING;
502   _instruments.push_back(createVerticalVelocity(x, y));
503   x += SIX_SPACING + 20;
504   _instruments.push_back(createNAV2(x, y));
505
506                                 // Bottom row
507   x = SIX_X;
508   y -= SIX_SPACING + 10;
509   _instruments.push_back(createControls(x, y));
510   x += SIX_SPACING;
511   _instruments.push_back(createFlapIndicator(x, y));
512   x += SIX_SPACING;
513   _instruments.push_back(createRPMGauge(x, y));
514   x += SIX_SPACING + 20;
515   y += 10;
516   _instruments.push_back(createADF(x, y));
517 }
518
519 FGPanel::~FGPanel ()
520 {
521   OurPanel = 0;
522
523   instrument_list_type::iterator current = _instruments.begin();
524   instrument_list_type::iterator last = _instruments.end();
525   
526   for ( ; current != last; ++current) {
527     delete *current;
528     *current = 0;
529   }
530 }
531
532 float
533 FGPanel::get_height () const
534 {
535   return _panel_h;
536 }
537
538 void
539 FGPanel::ReInit (int x, int y, int finx, int finy)
540 {
541   _x = x;
542   _y = y;
543   _w = finx - x;
544   _h = finy - y;
545   _panel_h = (int)((finy - y) * 0.5768 + 1);
546 }
547
548 void
549 FGPanel::Update () const
550 {
551   glMatrixMode(GL_PROJECTION);
552   glPushMatrix();
553   glLoadIdentity();
554   gluOrtho2D(_x, _x + _w, _y, _y + _h);
555
556   glMatrixMode(GL_MODELVIEW);
557   glPushMatrix();
558   glLoadIdentity();
559
560                                 // Draw the background
561   glEnable(GL_TEXTURE_2D);
562   glDisable(GL_LIGHTING);
563   glEnable(GL_BLEND);
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);
571   glBegin(GL_POLYGON);
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);
576   glEnd();
577
578                                 // Draw the instruments.
579   instrument_list_type::const_iterator current = _instruments.begin();
580   instrument_list_type::const_iterator end = _instruments.end();
581
582   for ( ; current != end; current++) {
583     FGPanelInstrument * instr = *current;
584     glLoadIdentity();
585     glTranslated(instr->getXPos(), instr->getYPos(), 0);
586     instr->draw();
587   }
588
589   glMatrixMode(GL_PROJECTION);
590   glPopMatrix();
591   glMatrixMode(GL_MODELVIEW);
592   glPopMatrix();
593   ssgForceBasicState();
594   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
595 }
596
597 ssgTexture *
598 FGPanel::createTexture (const char * relativePath)
599 {
600   ssgTexture *texture;
601
602   texture = _textureMap[relativePath];
603   if (texture == 0) {
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;
610   }
611
612   return texture;
613 }
614
615
616 \f
617 ////////////////////////////////////////////////////////////////////////
618 // Implementation of FGPanelInstrument.
619 ////////////////////////////////////////////////////////////////////////
620
621
622 FGPanelInstrument::FGPanelInstrument ()
623 {
624   setPosition(0, 0);
625   setSize(0, 0);
626 }
627
628 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
629 {
630   setPosition(x, y);
631   setSize(w, h);
632 }
633
634 FGPanelInstrument::~FGPanelInstrument ()
635 {
636 }
637
638 void
639 FGPanelInstrument::setPosition (int x, int y)
640 {
641   _x = x;
642   _y = y;
643 }
644
645 void
646 FGPanelInstrument::setSize (int w, int h)
647 {
648   _w = w;
649   _h = h;
650 }
651
652 int
653 FGPanelInstrument::getXPos () const
654 {
655   return _x;
656 }
657
658 int
659 FGPanelInstrument::getYPos () const
660 {
661   return _y;
662 }
663
664
665 \f
666 ////////////////////////////////////////////////////////////////////////
667 // Implementation of FGLayeredInstrument.
668 ////////////////////////////////////////////////////////////////////////
669
670 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
671   : FGPanelInstrument(x, y, w, h)
672 {
673 }
674
675 FGLayeredInstrument::~FGLayeredInstrument ()
676 {
677   // FIXME: free layers
678 }
679
680 void
681 FGLayeredInstrument::draw () const
682 {
683   layer_list::const_iterator it = _layers.begin();
684   layer_list::const_iterator last = _layers.end();
685   while (it != last) {
686     (*it)->draw();
687     it++;
688   }
689 }
690
691 void
692 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
693 {
694   _layers.push_back(layer);
695 }
696
697 void
698 FGLayeredInstrument::addLayer (int layer, ssgTexture * texture)
699 {
700   addLayer(new FGTexturedInstrumentLayer(texture, _w, _h, layer));
701 }
702
703 void
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)
709 {
710   _layers[layer]->addTransformation(type, func, min, max, factor, offset);
711 }
712
713
714 \f
715 ////////////////////////////////////////////////////////////////////////
716 // Implementation of FGInstrumentLayer.
717 ////////////////////////////////////////////////////////////////////////
718
719 FGInstrumentLayer::FGInstrumentLayer (int w, int h, int z)
720   : _w(w),
721     _h(h),
722     _z(z)
723 {
724 }
725
726 FGInstrumentLayer::~FGInstrumentLayer ()
727 {
728   transformation_list::iterator it = _transformations.begin();
729   transformation_list::iterator end = _transformations.end();
730   while (it != end) {
731     delete *it;
732     it++;
733   }
734 }
735
736 void
737 FGInstrumentLayer::transform () const
738 {
739   glTranslatef(0.0, 0.0, (_z / 100.0) + 0.1);
740
741   transformation_list::const_iterator it = _transformations.begin();
742   transformation_list::const_iterator last = _transformations.end();
743   while (it != last) {
744     transformation *t = *it;
745     double value = (t->func == 0 ? 0.0 : (*(t->func))());
746     if (value < t->min) {
747       value = t->min;
748     } else if (value > t->max) {
749       value = t->max;
750     }
751     value = value * t->factor + t->offset;
752
753     switch (t->type) {
754     case XSHIFT:
755       glTranslatef(value, 0.0, 0.0);
756       break;
757     case YSHIFT:
758       glTranslatef(0.0, value, 0.0);
759       break;
760     case ROTATION:
761       glRotatef(-value, 0.0, 0.0, 1.0);
762       break;
763     }
764     it++;
765   }
766 }
767
768 void
769 FGInstrumentLayer::addTransformation (transform_type type,
770                                       transform_func func,
771                                       double min, double max,
772                                       double factor, double offset)
773 {
774   transformation *t = new transformation;
775   t->type = type;
776   t->func = func;
777   t->min = min;
778   t->max = max;
779   t->factor = factor;
780   t->offset = offset;
781   _transformations.push_back(t);
782 }
783
784
785 \f
786 ////////////////////////////////////////////////////////////////////////
787 // Implementation of FGTexturedInstrumentLayer.
788 ////////////////////////////////////////////////////////////////////////
789
790 // FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (const char *tname,
791 //                                                    int w, int h, int z)
792 //   : FGInstrumentLayer(w, h, z)
793 // {
794 //   setTexture(tname);
795 // }
796
797 FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (ssgTexture * texture,
798                                                       int w, int h, int z)
799   : FGInstrumentLayer(w, h, z)
800 {
801   setTexture(texture);
802 }
803
804 FGTexturedInstrumentLayer::~FGTexturedInstrumentLayer ()
805 {
806 }
807
808 void
809 FGTexturedInstrumentLayer::draw () const
810 {
811   int w2 = _w / 2;
812   int h2 = _h / 2;
813
814   glPushMatrix();
815   transform();
816   glBindTexture(GL_TEXTURE_2D, _texture->getHandle());
817   glBegin(GL_POLYGON);
818                                 // FIXME: is this really correct
819                                 // for layering?
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);
824   glEnd();
825   glPopMatrix();
826 }
827
828 // void
829 // FGTexturedInstrumentLayer::setTexture (const char *textureName)
830 // {
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);
835 // }
836
837
838 \f
839 ////////////////////////////////////////////////////////////////////////
840 // Implementation of FGCharInstrumentLayer.
841 ////////////////////////////////////////////////////////////////////////
842
843 FGCharInstrumentLayer::FGCharInstrumentLayer (text_func func,
844                                               int w, int h, int z)
845   : FGInstrumentLayer(w, h, z),
846     _func(func)
847 {
848   _renderer.setFont(guiFntHandle);
849   _renderer.setPointSize(14);
850   _color[0] = _color[1] = _color[2] = 0.0;
851   _color[3] = 1.0;
852 }
853
854 FGCharInstrumentLayer::~FGCharInstrumentLayer ()
855 {
856 }
857
858 void
859 FGCharInstrumentLayer::draw () const
860 {
861   glPushMatrix();
862   glColor4fv(_color);
863   transform();
864   _renderer.begin();
865   _renderer.start3f(0, 0, 0);
866   _renderer.puts((*_func)(_buf));
867   _renderer.end();
868   glColor4f(1.0, 1.0, 1.0, 1.0);        // FIXME
869   glPopMatrix();
870 }
871
872 void
873 FGCharInstrumentLayer::setColor (float r, float g, float b)
874 {
875   _color[0] = r;
876   _color[1] = g;
877   _color[2] = b;
878   _color[3] = 1.0;
879 }
880
881 void
882 FGCharInstrumentLayer::setPointSize (const float size)
883 {
884   _renderer.setPointSize(size);
885 }
886
887 void
888 FGCharInstrumentLayer::setFont(fntFont * font)
889 {
890   _renderer.setFont(font);
891 }
892
893
894 \f
895 // end of panel.cxx