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