]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/panel.cxx
Updates from David Megginson.
[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 <Objects/texload.h>
39 #include <Autopilot/autopilot.hxx>
40 #include <Time/fg_time.hxx>
41
42 #include "cockpit.hxx"
43 #include "panel.hxx"
44 #include "hud.hxx"
45
46 extern fgAPDataPtr APDataGlobal;
47
48 #define SIX_X 200
49 #define SIX_Y 345
50 #define SIX_W 128
51 #define SIX_SPACING (SIX_W + 5)
52 #define SMALL_W 112
53
54
55 \f
56 ////////////////////////////////////////////////////////////////////////
57 // Static functions for obtaining settings.
58 //
59 // These should be replaced with functions from a global facade,
60 // or BFI (Big Friendly Interface).
61 ////////////////////////////////////////////////////////////////////////
62
63 /**
64  * Return the indicated airspeed in knots.
65  */
66 static double
67 panelGetSpeed ()
68 {
69   return get_speed();
70 }
71
72 /**
73  * Return the roll in degrees.
74  */
75 static double
76 panelGetRoll ()
77 {
78   return get_roll() * RAD_TO_DEG;
79 }
80
81 /**
82  * Return the pitch in degrees.
83  */
84 static double
85 panelGetPitch ()
86 {
87   return get_pitch() * RAD_TO_DEG;
88 }
89
90 /**
91  * Return the altitude in feet.
92  */
93 static double
94 panelGetAltitude ()
95 {
96   return get_altitude();
97 }
98
99 /**
100  * Return the sideslip (units unknown).
101  */
102 static double
103 panelGetSideSlip ()
104 {
105   return get_sideslip();
106 }
107
108 /**
109  * Return the heading in degrees.
110  */
111 static double
112 panelGetHeading ()
113 {
114   return get_heading();
115 }
116
117 /**
118  * Return the current autopilot heading in degrees.
119  */
120 static double
121 panelGetAPHeading ()
122 {
123   return fgAPget_TargetHeading();
124 }
125
126 /**
127  * Return the climb rate in feet/minute.
128  */
129 static double
130 panelGetVerticalVelocity ()
131 {
132   return get_climb_rate();
133 }
134
135 /**
136  * Return the throttle setting (0.0 - 1.0).
137  */
138 static double
139 panelGetThrottle ()
140 {
141   return get_throttleval();
142 }
143
144 /**
145  * Return the flaps setting (0.0 - 1.0).
146  */
147 static double
148 panelGetFlaps ()
149 {
150   return controls.get_flaps();
151 }
152
153 static double
154 panelGetAileron ()
155 {
156   return controls.get_aileron();
157 }
158
159 static double
160 panelGetRudder ()
161 {
162   return controls.get_rudder();
163 }
164
165 static double
166 panelGetElevator ()
167 {
168   return controls.get_elevator();
169 }
170
171 static double
172 panelGetElevatorTrim ()
173 {
174   return controls.get_elevator_trim();
175 }
176
177 static char * panelGetTime (char * buf)
178 {
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);
182   return buf;
183 }
184
185
186 \f
187 ////////////////////////////////////////////////////////////////////////
188 // Static factory functions to create textured gauges.
189 //
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 ////////////////////////////////////////////////////////////////////////
194
195
196 /**
197  * Construct an airspeed indicator for a single-engine prop.
198  */
199 static FGPanelInstrument *
200 makeAirspeedIndicator (int x, int y)
201 {
202   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
203
204                                 // Layer 0: gauge background.
205   inst->addLayer(0, "Textures/Panel/airspeed.rgb");
206
207                                 // Layer 1: needle.
208                                 // Rotates with airspeed.
209   inst->addLayer(1, "Textures/Panel/long-needle.rgb");
210   inst->addTransformation(1, FGInstrumentLayer::ROTATION,
211                           panelGetSpeed,
212                           30.0, 220.0, 36.0 / 20.0, -54.0);
213   return inst;
214 }
215
216
217 /**
218  * Construct an artificial horizon.
219  */
220 static FGPanelInstrument *
221 makeHorizon (int x, int y)
222 {
223   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
224
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,
229                           panelGetRoll,
230                           -360.0, 360.0, -1.0, 0.0);
231
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,
236                           panelGetRoll,
237                           -360.0, 360.0, -1.0, 0.0);
238   inst->addTransformation(1, FGInstrumentLayer::YSHIFT,
239                           panelGetPitch,
240                           -20.0, 20.0, -(1.5 / 160.0) * SIX_W, 0.0);
241
242                                 // Layer 2: rim
243                                 // moves with roll only
244   inst->addLayer(2, "Textures/Panel/horizon-rim.rgb");
245   inst->addTransformation(2, FGInstrumentLayer::ROTATION,
246                           panelGetRoll,
247                           -360.0, 360.0, -1.0, 0.0);
248
249                                 // Layer 3: glass front of gauge
250                                 // fixed, with markings
251   inst->addLayer(3, "Textures/Panel/horizon-fg.rgb");
252
253   return inst;
254 }
255
256
257 /**
258  * Construct an altimeter.
259  */
260 static FGPanelInstrument *
261 makeAltimeter (int x, int y)
262 {
263   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
264
265                                 // Layer 0: gauge background
266   inst->addLayer(0, "Textures/Panel/altimeter.rgb");
267
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,
272                           panelGetAltitude,
273                           0.0, 100000.0, 360.0 / 1000.0, 0.0);
274
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,
279                           panelGetAltitude,
280                           0.0, 100000.0, 360.0 / 10000.0, 0.0);
281
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,
286                           panelGetAltitude,
287                           0.0, 100000.0, 360.0 / 100000.0, 0.0);
288
289   return inst;
290 }
291
292
293 /**
294  * Construct a turn coordinator.
295  */
296 static FGPanelInstrument *
297 makeTurnCoordinator (int x, int y)
298 {
299   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
300
301                                 // Layer 0: background
302   inst->addLayer(0, "Textures/Panel/turn-bg.rgb");
303
304                                 // Layer 1: little plane
305                                 // moves with roll
306   inst->addLayer(1, "Textures/Panel/turn.rgb");
307   inst->addTransformation(1, FGInstrumentLayer::ROTATION,
308                           panelGetRoll,
309                           -30.0, 30.0, 1.0, 0.0);
310
311                                 // Layer 2: little ball
312                                 // moves with slip/skid
313   inst->addLayer(2, "Textures/Panel/ball.rgb");
314   inst->addTransformation(2, FGInstrumentLayer::ROTATION,
315                           panelGetSideSlip,
316                           -0.1, 0.1, 450.0, 0.0);
317
318   return inst;
319 }
320
321
322 /**
323  * Construct a gyro compass.
324  */
325 static FGPanelInstrument *
326 makeGyroCompass (int x, int y)
327 {
328   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
329
330                                 // Layer 0: compass background
331                                 // rotates with heading
332   inst->addLayer(0, "Textures/Panel/gyro-bg.rgb");
333   inst->addTransformation(0, FGInstrumentLayer::ROTATION,
334                           panelGetHeading,
335                           -360.0, 360.0, -1.0, 0.0);
336
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,
341                           panelGetHeading,
342                           -360.0, 360.0, -1.0, 0.0);
343   inst->addTransformation(1, FGInstrumentLayer::ROTATION,
344                           panelGetAPHeading,
345                           -360.0, 360.0, 1.0, 0.0);
346
347                                 // Layer 2: fixed center
348   inst->addLayer(2, "Textures/Panel/gyro-fg.rgb");
349
350   return inst;
351 }
352
353
354 /**
355  * Construct a vertical velocity indicator.
356  */
357 static FGPanelInstrument *
358 makeVerticalVelocity (int x, int y)
359 {
360   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
361
362                                 // Layer 0: gauge background
363   inst->addLayer(0, "Textures/Panel/vertical.rgb");
364
365                                 // Layer 1: needle
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);
371
372   return inst;
373 }
374
375
376 /**
377  * Construct an RPM gauge.
378  */
379 static FGPanelInstrument *
380 makeRPMGauge (int x, int y)
381 {
382   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
383
384                                 // Layer 0: gauge background
385   inst->addLayer(0, "Textures/Panel/rpm.rgb");
386
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,
391                           panelGetThrottle,
392                           0.0, 100.0, 300.0, -150.0);
393
394   return inst;
395 }
396
397
398 /**
399  * Construct a flap position indicator.
400  */
401 static FGPanelInstrument *
402 makeFlapIndicator (int x, int y)
403 {
404   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
405
406                                 // Layer 0: gauge background
407   inst->addLayer(0, "Textures/Panel/flaps.rgb");
408
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,
415                           panelGetFlaps,
416                           0.0, 1.0, 120.0, 30.0);
417
418   return inst;
419 }
420
421 static FGPanelInstrument *
422 makeChronometer (int x, int y)
423 {
424   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
425
426                                 // Layer 0: gauge background
427   inst->addLayer(0, "Textures/Panel/clock.rgb");
428
429                                 // Layer 1: text
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);
439
440   return inst;
441 }
442
443
444 /**
445  * Construct control-position indicators.
446  */
447 static FGPanelInstrument *
448 makeControls (int x, int y)
449 {
450   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SMALL_W, SMALL_W);
451
452                                 // Layer 0: gauge background
453   inst->addLayer(0, "Textures/Panel/controls.rgb");
454
455                                 // Layer 1: bug
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);
460
461                                 // Layer 2: bug
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);
467
468                                 // Layer 3: bug
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);
476
477                                 // Layer 4: bug
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);
485
486   return inst;
487 }
488
489
490 /**
491  * Construct a NAV1 gauge (dummy for now).
492  */
493 static FGPanelInstrument *
494 makeNAV1 (int x, int y)
495 {
496   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
497
498                                 // Layer 0: background
499   inst->addLayer(0, "Textures/Panel/gyro-bg.rgb");
500
501   return inst;
502 }
503
504
505 /**
506  * Construct a NAV2 gauge (dummy for now).
507  */
508 static FGPanelInstrument *
509 makeNAV2 (int x, int y)
510 {
511   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
512
513                                 // Layer 0: background
514   inst->addLayer(0, "Textures/Panel/gyro-bg.rgb");
515
516   return inst;
517 }
518
519
520 /**
521  * Construct an ADF gauge (dummy for now).
522  */
523 static FGPanelInstrument *
524 makeADF (int x, int y)
525 {
526   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W, SIX_W);
527
528                                 // Layer 0: background
529   inst->addLayer(0, "Textures/Panel/gyro-bg.rgb");
530
531   return inst;
532 }
533
534
535 \f
536 ////////////////////////////////////////////////////////////////////////
537 // Implementation of FGPanel.
538 ////////////////////////////////////////////////////////////////////////
539
540 FGPanel * FGPanel::OurPanel = 0;
541
542 FGPanel::FGPanel ()
543 {
544   if (OurPanel == 0) {
545     OurPanel = this;
546   } else {
547     FG_LOG(FG_GENERAL, FG_ALERT, "Multiple panels");
548     exit(-1);
549   }
550
551   int x = SIX_X;
552   int y = SIX_Y;
553
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);
557
558                                 // Chronometer alone at side
559   x = SIX_X - SIX_SPACING - 8;
560   _instruments.push_back(makeChronometer(x, y));
561
562                                 // Top row
563   x = SIX_X;
564   _instruments.push_back(makeAirspeedIndicator(x, y));
565   x += SIX_SPACING;
566   _instruments.push_back(makeHorizon(x, y));
567   x += SIX_SPACING;
568   _instruments.push_back(makeAltimeter(x, y));
569   x += SIX_SPACING + 20;
570   _instruments.push_back(makeNAV1(x, y));
571
572                                 // Middle row
573   x = SIX_X;
574   y -= SIX_SPACING;
575   _instruments.push_back(makeTurnCoordinator(x, y));
576   x += SIX_SPACING;
577   _instruments.push_back(makeGyroCompass(x, y));
578   x += SIX_SPACING;
579   _instruments.push_back(makeVerticalVelocity(x, y));
580   x += SIX_SPACING + 20;
581   _instruments.push_back(makeNAV2(x, y));
582
583                                 // Bottom row
584   x = SIX_X;
585   y -= SIX_SPACING + 10;
586   _instruments.push_back(makeControls(x, y));
587   x += SIX_SPACING;
588   _instruments.push_back(makeFlapIndicator(x, y));
589   x += SIX_SPACING;
590   _instruments.push_back(makeRPMGauge(x, y));
591   x += SIX_SPACING + 20;
592   y += 10;
593   _instruments.push_back(makeADF(x, y));
594 }
595
596 FGPanel::~FGPanel ()
597 {
598   OurPanel = 0;
599
600   instrument_list_type::iterator current = _instruments.begin();
601   instrument_list_type::iterator last = _instruments.end();
602   
603   for ( ; current != last; ++current) {
604     delete *current;
605     *current = 0;
606   }
607 }
608
609 float
610 FGPanel::get_height () const
611 {
612   return _panel_h;
613 }
614
615 void
616 FGPanel::ReInit (int x, int y, int finx, int finy)
617 {
618   _x = x;
619   _y = y;
620   _w = finx - x;
621   _h = finy - y;
622   _panel_h = (int)((finy - y) * 0.5768 + 1);
623 }
624
625 void
626 FGPanel::Update () const
627 {
628   glMatrixMode(GL_PROJECTION);
629   glPushMatrix();
630   glLoadIdentity();
631   gluOrtho2D(_x, _x + _w, _y, _y + _h);
632
633   glMatrixMode(GL_MODELVIEW);
634   glPushMatrix();
635   glLoadIdentity();
636
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);
645   glBegin(GL_POLYGON);
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);
650   glEnd();
651
652                                 // Draw the instruments.
653   instrument_list_type::const_iterator current = _instruments.begin();
654   instrument_list_type::const_iterator end = _instruments.end();
655
656   for ( ; current != end; current++) {
657     FGPanelInstrument * instr = *current;
658     glLoadIdentity();
659     glTranslated(instr->getXPos(), instr->getYPos(), 0);
660     instr->draw();
661   }
662
663   glMatrixMode(GL_PROJECTION);
664   glPopMatrix();
665   glMatrixMode(GL_MODELVIEW);
666   glPopMatrix();
667   ssgForceBasicState();
668   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
669 }
670
671
672 \f
673 ////////////////////////////////////////////////////////////////////////
674 // Implementation of FGPanelInstrument.
675 ////////////////////////////////////////////////////////////////////////
676
677
678 FGPanelInstrument::FGPanelInstrument ()
679 {
680   setPosition(0, 0);
681   setSize(0, 0);
682 }
683
684 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
685 {
686   setPosition(x, y);
687   setSize(w, h);
688 }
689
690 FGPanelInstrument::~FGPanelInstrument ()
691 {
692 }
693
694 void
695 FGPanelInstrument::setPosition (int x, int y)
696 {
697   _x = x;
698   _y = y;
699 }
700
701 void
702 FGPanelInstrument::setSize (int w, int h)
703 {
704   _w = w;
705   _h = h;
706 }
707
708 int
709 FGPanelInstrument::getXPos () const
710 {
711   return _x;
712 }
713
714 int
715 FGPanelInstrument::getYPos () const
716 {
717   return _y;
718 }
719
720
721 \f
722 ////////////////////////////////////////////////////////////////////////
723 // Implementation of FGLayeredInstrument.
724 ////////////////////////////////////////////////////////////////////////
725
726 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
727   : FGPanelInstrument(x, y, w, h)
728 {
729 }
730
731 FGLayeredInstrument::~FGLayeredInstrument ()
732 {
733   // FIXME: free layers
734 }
735
736 void
737 FGLayeredInstrument::draw () const
738 {
739   layer_list::const_iterator it = _layers.begin();
740   layer_list::const_iterator last = _layers.end();
741   while (it != last) {
742     (*it)->draw();
743     it++;
744   }
745 }
746
747 void
748 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
749 {
750   _layers.push_back(layer);
751 }
752
753 void
754 FGLayeredInstrument::addLayer (int layer, const char *textureName)
755 {
756   addLayer(new FGTexturedInstrumentLayer(textureName, _w, _h, layer));
757 }
758
759 void
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)
765 {
766   _layers[layer]->addTransformation(type, func, min, max, factor, offset);
767 }
768
769
770 \f
771 ////////////////////////////////////////////////////////////////////////
772 // Implementation of FGInstrumentLayer.
773 ////////////////////////////////////////////////////////////////////////
774
775 FGInstrumentLayer::FGInstrumentLayer (int w, int h, int z)
776   : _w(w),
777     _h(h),
778     _z(z)
779 {
780 }
781
782 FGInstrumentLayer::~FGInstrumentLayer ()
783 {
784   transformation_list::iterator it;
785   transformation_list::iterator end;
786   while (it != end) {
787     delete *it;
788     it++;
789   }
790 }
791
792 void
793 FGInstrumentLayer::transform () const
794 {
795   glTranslatef(0.0, 0.0, (_z / 100.0) + 0.1);
796
797   transformation_list::const_iterator it = _transformations.begin();
798   transformation_list::const_iterator last = _transformations.end();
799   while (it != last) {
800     transformation *t = *it;
801     double value = (t->func == 0 ? 0.0 : (*(t->func))());
802     if (value < t->min) {
803       value = t->min;
804     } else if (value > t->max) {
805       value = t->max;
806     }
807     value = value * t->factor + t->offset;
808
809     switch (t->type) {
810     case XSHIFT:
811       glTranslatef(value, 0.0, 0.0);
812       break;
813     case YSHIFT:
814       glTranslatef(0.0, value, 0.0);
815       break;
816     case ROTATION:
817       glRotatef(-value, 0.0, 0.0, 1.0);
818       break;
819     }
820     it++;
821   }
822 }
823
824 void
825 FGInstrumentLayer::addTransformation (transform_type type,
826                                       transform_func func,
827                                       double min, double max,
828                                       double factor, double offset)
829 {
830   transformation *t = new transformation;
831   t->type = type;
832   t->func = func;
833   t->min = min;
834   t->max = max;
835   t->factor = factor;
836   t->offset = offset;
837   _transformations.push_back(t);
838 }
839
840
841 \f
842 ////////////////////////////////////////////////////////////////////////
843 // Implementation of FGTexturedInstrumentLayer.
844 ////////////////////////////////////////////////////////////////////////
845
846 FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (const char *tname,
847                                                       int w, int h, int z)
848   : FGInstrumentLayer(w, h, z)
849 {
850   setTexture(tname);
851 }
852
853 FGTexturedInstrumentLayer::FGTexturedInstrumentLayer (ssgTexture * texture,
854                                                       int w, int h, int z)
855   : FGInstrumentLayer(w, h, z)
856 {
857   setTexture(texture);
858 }
859
860 FGTexturedInstrumentLayer::~FGTexturedInstrumentLayer ()
861 {
862 }
863
864 void
865 FGTexturedInstrumentLayer::draw () const
866 {
867   int w2 = _w / 2;
868   int h2 = _h / 2;
869
870   glPushMatrix();
871   transform();
872   glBindTexture(GL_TEXTURE_2D, _texture->getHandle());
873   glBegin(GL_POLYGON);
874                                 // FIXME: is this really correct
875                                 // for layering?
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);
880   glEnd();
881   glPopMatrix();
882 }
883
884 void
885 FGTexturedInstrumentLayer::setTexture (const char *textureName)
886 {
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;
891   setTexture(texture);
892 }
893
894
895 \f
896 ////////////////////////////////////////////////////////////////////////
897 // Implementation of FGCharInstrumentLayer.
898 ////////////////////////////////////////////////////////////////////////
899
900 FGCharInstrumentLayer::FGCharInstrumentLayer (text_func func,
901                                               int w, int h, int z)
902   : FGInstrumentLayer(w, h, z),
903     _func(func)
904 {
905   _renderer.setFont(guiFntHandle);
906   _renderer.setPointSize(14);
907   _color[0] = _color[1] = _color[2] = 0.0;
908 }
909
910 FGCharInstrumentLayer::~FGCharInstrumentLayer ()
911 {
912 }
913
914 void
915 FGCharInstrumentLayer::draw () const
916 {
917   glPushMatrix();
918   glColor3fv(_color);
919   transform();
920   _renderer.begin();
921   _renderer.start3f(0, 0, 0);
922   _renderer.puts((*_func)(_buf));
923   _renderer.end();
924   glColor3f(1.0, 1.0, 1.0);     // FIXME
925   glPopMatrix();
926 }
927
928 void
929 FGCharInstrumentLayer::setColor (float r, float g, float b)
930 {
931   _color[0] = r;
932   _color[1] = g;
933   _color[2] = b;
934 }
935
936 void
937 FGCharInstrumentLayer::setPointSize (const float size)
938 {
939   _renderer.setPointSize(size);
940 }
941
942 void
943 FGCharInstrumentLayer::setFont(fntFont * font)
944 {
945   _renderer.setFont(font);
946 }
947
948
949 \f
950 // end of panel.cxx