]> git.mxchange.org Git - flightgear.git/blob - Cockpit/hud.cxx
Edited cvs log messages in source files ... bad bad bad!
[flightgear.git] / Cockpit / hud.cxx
1 /**************************************************************************
2  * hud.c -- hud defines and prototypes
3  *
4  * Written by Michele America, started September 1997.
5  *
6  * Copyright (C) 1997  Michele F. America  - micheleamerica@geocities.com
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * $Id$
23  * (Log is kept at end of this file)
24  **************************************************************************/
25  
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31 #ifdef HAVE_WINDOWS_H
32 #  include <windows.h>
33 #endif
34
35 #include <GL/glut.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #ifdef HAVE_VALUES_H
40 #  include <values.h>  // for MAXINT
41 #endif
42
43 #include <Aircraft/aircraft.h>
44 #include <Debug/fg_debug.h>
45 #include <Include/fg_constants.h>
46 #include <Math/fg_random.h>
47 #include <Math/mat3.h>
48 #include <Math/polar.h>
49 #include <Scenery/scenery.h>
50 #include <Time/fg_timer.hxx>
51 #include <Weather/weather.h>
52
53 #include "hud.hxx"
54
55 // #define DEBUG
56
57 #define drawOneLine(x1,y1,x2,y2)  glBegin(GL_LINES);  \
58         glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
59
60
61 // The following routines obtain information concerntin the aircraft's
62 // current state and return it to calling instrument display routines.
63 // They should eventually be member functions of the aircraft.
64 //
65
66 double get_throttleval( void )
67 {
68         fgCONTROLS *pcontrols;
69
70   pcontrols = current_aircraft.controls;
71   return pcontrols->throttle[0];     // Hack limiting to one engine
72 }
73
74 double get_aileronval( void )
75 {
76         fgCONTROLS *pcontrols;
77
78   pcontrols = current_aircraft.controls;
79   return pcontrols->aileron;
80 }
81
82 double get_elevatorval( void )
83 {
84         fgCONTROLS *pcontrols;
85
86   pcontrols = current_aircraft.controls;
87   return pcontrols->elevator;
88 }
89
90 double get_elev_trimval( void )
91 {
92         fgCONTROLS *pcontrols;
93
94   pcontrols = current_aircraft.controls;
95   return pcontrols->elevator_trim;
96 }
97
98 double get_rudderval( void )
99 {
100         fgCONTROLS *pcontrols;
101
102   pcontrols = current_aircraft.controls;
103   return pcontrols->rudder;
104 }
105
106 double get_speed( void )
107 {
108         fgFLIGHT *f;
109
110         f = current_aircraft.flight;
111         return( FG_V_equiv_kts );    // Make an explicit function call.
112 }
113
114 double get_aoa( void )
115 {
116         fgFLIGHT *f;
117               
118         f = current_aircraft.flight;
119         return( FG_Gamma_vert_rad * RAD_TO_DEG );
120 }
121
122 double get_roll( void )
123 {
124         fgFLIGHT *f;
125
126         f = current_aircraft.flight;
127         return( FG_Phi );
128 }
129
130 double get_pitch( void )
131 {
132         fgFLIGHT *f;
133               
134         f = current_aircraft.flight;
135         return( FG_Theta );
136 }
137
138 double get_heading( void )
139 {
140         fgFLIGHT *f;
141
142         f = current_aircraft.flight;
143         return( FG_Psi * RAD_TO_DEG );
144 }
145
146 double get_altitude( void )
147 {
148         fgFLIGHT *f;
149         // double rough_elev;
150
151         f = current_aircraft.flight;
152         // rough_elev = mesh_altitude(FG_Longitude * RAD_TO_ARCSEC,
153         //                                 FG_Latitude  * RAD_TO_ARCSEC);
154
155         return( FG_Altitude * FEET_TO_METER /* -rough_elev */ );
156 }
157
158 double get_sideslip( void )
159 {
160         fgFLIGHT *f;
161         
162         f = current_aircraft.flight;
163         
164         return( FG_Beta );
165 }
166
167 /****************************************************************************/
168 /* Convert degrees to dd mm.mmm' (DMM-Format)                               */
169 /****************************************************************************/
170 #if 0
171 char *toDM(double a)
172 {
173   short        neg = 0;
174   double       d, m;
175   static char  dm[13];
176   
177   if (a < 0.0) {
178     a = -a;
179     neg = 1;
180   }
181
182   d = (double) ( (int) a);
183   m = (a - d) * 60.0;
184   
185   if (m > 59.5) {
186     m  = 0.0;
187     d += 1.0;
188   }
189   if (neg) d = -d;
190   
191   sprintf(dm, "%.0f°%06.3f'", d, m);
192   return dm;
193 }
194 #endif // 0
195 double get_latitude( void )
196 {
197         fgFLIGHT *f;
198         f = current_aircraft.flight;
199
200 //      return( toDM(FG_Latitude * RAD_TO_DEG) );
201         return((double)((int)( FG_Latitude * RAD_TO_DEG)) );    
202 }
203 double get_lat_min( void )
204 {
205         fgFLIGHT *f;
206         double      a, d;
207
208         f = current_aircraft.flight;
209         
210         a = FG_Latitude * RAD_TO_DEG;   
211         if (a < 0.0) {
212                 a = -a;
213         }
214         d = (double) ( (int) a);
215         return( (a - d) * 60.0);
216 }
217
218
219 double get_longitude( void )
220 {
221         fgFLIGHT *f;
222         f = current_aircraft.flight;
223
224 //      return( toDM(FG_Longitude * RAD_TO_DEG) );
225         return((double)((int) (FG_Longitude * RAD_TO_DEG)) );
226 }
227 double get_long_min( void )
228 {
229         fgFLIGHT *f;
230         double  a, d;
231
232         f = current_aircraft.flight;
233         
234         a = FG_Longitude * RAD_TO_DEG;  
235         if (a < 0.0) {
236                 a = -a;
237         }
238         d = (double) ( (int) a);
239         return( (a - d) * 60.0);
240 }
241
242 //
243 // The following code deals with painting the "instrument" on the display
244 //
245    /* textString - Bitmap font string */
246
247 static void textString(int x, int y, char *msg, void *font)
248 {
249         glRasterPos2f(x, y);
250         while (*msg) {
251                 glutBitmapCharacter(font, *msg);
252                 msg++;
253     }
254 }
255
256 /* strokeString - Stroke font string */
257 /*
258 static void strokeString(int x, int y, char *msg, void *font)
259 {
260         glPushMatrix();
261         glTranslatef(x, y, 0);
262         glScalef(.04, .04, .04);
263         while (*msg) {
264                 glutStrokeCharacter(font, *msg);
265                 msg++;
266         }
267         glPopMatrix();
268 }
269 */
270
271 /*
272
273         Draws a measuring scale anywhere on the HUD
274
275
276         Needs: HUD_scale struct
277
278 */
279 static void drawscale( HUD_scale * pscale )
280 {
281   double vmin, vmax;
282   int marker_x;
283   int marker_y;
284   register i;
285   char TextScale[80];
286   int condition;
287   double cur_value = (*(pscale->load_value))();
288   int disp_val;
289
290   vmin = cur_value - pscale->half_width_units; // width units == needle travel
291   vmax = cur_value + pscale->half_width_units; // or picture unit span.
292
293
294   if( pscale->type == VERTICAL )     // Vertical scale
295     {
296       drawOneLine( pscale->scrn_pos.right,    // Vertical scale bar
297                    pscale->scrn_pos.bottom,
298                    pscale->scrn_pos.right,
299                    pscale->scrn_pos.top );
300
301     if( pscale->orientation == LEFT )     // Calculate x marker offset
302       marker_x = pscale->scrn_pos.left - 6;
303     else
304       if( pscale->orientation == RIGHT )
305         marker_x = pscale->scrn_pos.right;
306
307     // Draw the basic markings for the scale...
308
309     if( pscale->orientation == LEFT )
310       {
311
312       drawOneLine( pscale->scrn_pos.right - 3,     // Bottom tick bar
313                    pscale->scrn_pos.bottom,
314                    pscale->scrn_pos.right,
315                    pscale->scrn_pos.bottom );
316
317       drawOneLine( pscale->scrn_pos.right - 3,     // Top tick bar
318                    pscale->scrn_pos.top,
319                    pscale->scrn_pos.right,
320                    pscale->scrn_pos.top );
321
322       drawOneLine( pscale->scrn_pos.right,       // Middle tick bar /Index
323                    pscale->mid_scr,
324                    pscale->scrn_pos.right + 6,
325                    pscale->mid_scr );
326
327       }
328     else
329       if( pscale->orientation == RIGHT )
330         {
331         drawOneLine( pscale->scrn_pos.right,
332                      pscale->scrn_pos.bottom,
333                      pscale->scrn_pos.right+3,
334                      pscale->scrn_pos.bottom );
335
336         drawOneLine( pscale->scrn_pos.right,
337                      pscale->scrn_pos.top,
338                      pscale->scrn_pos.right+3,
339                      pscale->scrn_pos.top );
340
341         drawOneLine( pscale->scrn_pos.right,
342                      pscale->mid_scr,
343                      pscale->scrn_pos.right-6,
344                      pscale->mid_scr );
345         }
346
347     // Work through from bottom to top of scale. Calculating where to put
348     // minor and major ticks.
349
350     for( i = (int)(vmin); i <= (int)(vmax); i++ )
351       {
352       if( pscale->sub_type == LIMIT ) {           // Don't show ticks
353         condition = (i >= pscale->minimum_value); // below Minimum value.
354         }
355       else {
356         if( pscale->sub_type == NOLIMIT ) {
357           condition = 1;
358           }
359         }
360       if( condition )   // Show a tick if necessary
361         {
362         // Calculate the location of this tick
363         marker_y = (int)(pscale->scrn_pos.bottom + (i - vmin) * pscale->factor);
364
365         // Block calculation artifact from drawing ticks below min coordinate.
366         // Calculation here accounts for text height.
367
368         if( marker_y < (pscale->scrn_pos.bottom + 4)) {  // Magic number!!!
369           continue;
370           }
371         if( (i%pscale->div_min) == 0) {
372           if( pscale->orientation == LEFT )
373             {
374             drawOneLine( marker_x + 3, marker_y, marker_x + 6, marker_y );
375             }
376           else {
377             if( pscale->orientation == RIGHT )
378               {
379               drawOneLine( marker_x, marker_y, marker_x + 3, marker_y );
380               }
381             }
382           }
383         if( (i%pscale->div_max) == 0 )            {
384           drawOneLine( marker_x,     marker_y,
385                        marker_x + 6, marker_y );
386           if(pscale->modulo) {
387             disp_val = i % pscale->modulo;
388             if( !disp_val ) {
389               disp_val = pscale->modulo;
390               }
391             if( disp_val < 0) {
392               disp_val += pscale->modulo;
393               }
394             if( disp_val == pscale->modulo ) {
395               disp_val = 0;
396               }
397             }
398           else {
399             disp_val = i;
400             }
401           sprintf( TextScale, "%d", disp_val );
402           if( pscale->orientation == LEFT )              {
403             textString( marker_x -  8 * strlen(TextScale) - 2, marker_y - 4,
404                         TextScale, GLUT_BITMAP_8_BY_13 );
405             }
406           else  {
407             if( pscale->orientation == RIGHT )              {
408             textString( marker_x + 10,                         marker_y - 4,
409                         TextScale, GLUT_BITMAP_8_BY_13 );
410               }
411             }
412           }
413         } // End if condition
414       } // End for range of i from vmin to vmax
415     }  // End if VERTICAL SCALE TYPE
416   if( pscale->type == HORIZONTAL )     // Horizontal scale
417     {
418     if( pscale->orientation == TOP ) {
419       marker_y = pscale->scrn_pos.bottom;
420       }
421     else {
422       if( pscale->orientation == BOTTOM ) {
423         marker_y = pscale->scrn_pos.bottom - 6;
424         }
425       }
426     drawOneLine( pscale->scrn_pos.left,
427                  pscale->scrn_pos.bottom,
428                  pscale->scrn_pos.right,
429                  pscale->scrn_pos.bottom );
430
431     if( pscale->orientation == TOP )
432       {
433       drawOneLine( pscale->scrn_pos.left,
434                    pscale->scrn_pos.bottom,
435                    pscale->scrn_pos.left,
436                    pscale->scrn_pos.bottom + 3 );
437
438       drawOneLine( pscale->scrn_pos.right,
439                    pscale->scrn_pos.bottom,
440                    pscale->scrn_pos.right,
441                    pscale->scrn_pos.bottom + 6 );
442
443       drawOneLine( pscale->mid_scr,
444                    pscale->scrn_pos.bottom,
445                    pscale->mid_scr,
446                    pscale->scrn_pos.bottom - 6 );
447
448       }
449     else {
450       if( pscale->orientation == BOTTOM )
451         {
452         drawOneLine( pscale->scrn_pos.left,
453                      pscale->scrn_pos.bottom,
454                      pscale->scrn_pos.left,
455                      pscale->scrn_pos.bottom - 6 );
456
457         drawOneLine( pscale->scrn_pos.right,
458                      pscale->scrn_pos.bottom,
459                      pscale->scrn_pos.right,
460                      pscale->scrn_pos.bottom - 6 );
461
462         drawOneLine( pscale->mid_scr,
463                      pscale->scrn_pos.bottom,
464                      pscale->mid_scr,
465                      pscale->scrn_pos.bottom + 6 );
466         }
467       }
468
469     for( i = (int)(vmin); i <= (int)(vmax); i++ )  // increment is faster than addition
470       {
471       if( pscale->sub_type == LIMIT ) {
472         condition = (i >= pscale->minimum_value);
473         }
474       else {
475         if( pscale->sub_type == NOLIMIT ) {
476           condition = 1;
477           }
478         }
479       if( condition )        {
480         marker_x = (int)(pscale->scrn_pos.left + (i - vmin) * pscale->factor);
481         if( (i%pscale->div_min) == 0 ) {
482           if( pscale->orientation == TOP )
483             {
484             drawOneLine( marker_x, marker_y, marker_x, marker_y + 3 );
485             }
486           else {
487             if( pscale->orientation == BOTTOM )
488               {
489               drawOneLine( marker_x, marker_y + 3, marker_x, marker_y + 6 );
490               }
491             }
492           }
493         if( (i%pscale->div_max)==0 )
494           {
495           if(pscale->modulo) {
496             disp_val = i % pscale->modulo;
497             if( !disp_val ) {
498               disp_val = pscale->modulo;
499               }
500             if( disp_val < 0) {
501               disp_val += pscale->modulo;
502               }
503             if( disp_val == pscale->modulo ) {
504               disp_val = 0;
505               }
506             }
507           else {
508             disp_val = i;
509             }
510             sprintf( TextScale, "%d", disp_val );
511           if( pscale->orientation == TOP )
512             {
513             drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
514             textString ( marker_x - 4 * strlen(TextScale), marker_y + 14,
515                          TextScale, GLUT_BITMAP_8_BY_13 );
516             }
517           else {
518             if( pscale->orientation == BOTTOM )
519               {
520               drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
521               textString ( marker_x - 4 * strlen(TextScale), marker_y - 14,
522                            TextScale, GLUT_BITMAP_8_BY_13 );
523               }
524             }
525           }
526         }
527       }
528     }
529
530 }
531
532 //
533 //      Draws a climb ladder in the center of the HUD
534 //
535
536 static void drawladder( HUD_ladder *ladder )
537 {
538   double vmin, vmax;
539   double roll_value, pitch_value;
540   int marker_x, marker_y;
541 #ifdef DEBUGHUD
542   int mid_scr;
543 #endif
544   int scr_min, scr_max;
545   int x_ini, x_end;
546   int y_ini, y_end;
547   int new_x_ini, new_x_end;
548   int new_y_ini, new_y_end;
549   register i;
550   double factor;
551   char TextLadder[80];
552   int condition;
553
554   double cos_roll_value, sin_roll_value;
555 //  double cos_pitch_value, sin_pitch_value;
556
557   roll_value = (*ladder->load_roll)();
558   sin_roll_value = sin(roll_value);
559   cos_roll_value = cos(roll_value);
560   
561   pitch_value = (*ladder->load_pitch)()*RAD_TO_DEG;
562
563   vmin = pitch_value - ladder->width_units/2;
564   vmax = pitch_value + ladder->width_units/2;
565
566   scr_min = ladder->scrn_pos.y - (ladder->scr_height/2);
567   scr_max = scr_min       + ladder->scr_height;
568
569 #ifdef DEBUGHUD
570   mid_scr = scr_min       + (scr_max-scr_min)/2;
571 #endif
572
573   marker_x = ladder->scrn_pos.x - ladder->scr_width/2;
574
575   factor = (scr_max-scr_min)/ladder->width_units;
576
577   for( i=(int)(vmin); i<=(int)(vmax); i+=1 )
578     {
579     condition = 1;
580     if( condition )
581       {
582       marker_y = (int)(scr_min+(i-vmin)*factor);
583       if( i%ladder->div_units==0 )
584         {
585         sprintf( TextLadder, "%d", i );
586         if( ladder->scr_hole == 0 )
587           {
588           if( i ) {
589             x_ini = ladder->scrn_pos.x - ladder->scr_width/2;
590             }
591           else {
592             x_ini = ladder->scrn_pos.x - ladder->scr_width/2 - 10;
593             }
594           y_ini = marker_y;
595           x_end = ladder->scrn_pos.x + ladder->scr_width/2;
596           y_end = marker_y;
597           new_x_ini = (int)(ladder->scrn_pos.x +                             \
598                       (x_ini - ladder->scrn_pos.x) * cos_roll_value - \
599                       (y_ini - ladder->scrn_pos.y) * sin_roll_value);
600           new_y_ini = (int)(ladder->scrn_pos.y +                             \
601                       (x_ini - ladder->scrn_pos.x) * sin_roll_value + \
602                       (y_ini - ladder->scrn_pos.y) * cos_roll_value);
603           new_x_end = (int)(ladder->scrn_pos.x +                             \
604                       (x_end - ladder->scrn_pos.x) * cos_roll_value - \
605                       (y_end - ladder->scrn_pos.y) * sin_roll_value);
606           new_y_end = (int)(ladder->scrn_pos.y +                             \
607                       (x_end - ladder->scrn_pos.x) * sin_roll_value + \
608                       (y_end - ladder->scrn_pos.y) * cos_roll_value);
609
610           if( i >= 0 )
611             {
612             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
613             }
614           else
615             {
616             glEnable(GL_LINE_STIPPLE);
617             glLineStipple( 1, 0x00FF );
618             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
619             glDisable(GL_LINE_STIPPLE);
620             }
621           textString( new_x_ini -  8 * strlen(TextLadder) - 8,
622                       new_y_ini -  4,
623                       TextLadder, GLUT_BITMAP_8_BY_13 );
624           textString( new_x_end + 10,
625                       new_y_end -  4,
626                       TextLadder, GLUT_BITMAP_8_BY_13 );
627           }
628         else
629           {
630           if( i != 0 )  {
631             x_ini = ladder->scrn_pos.x - ladder->scr_width/2;
632             }
633           else          {
634             x_ini = ladder->scrn_pos.x - ladder->scr_width/2 - 10;
635             }
636           y_ini = marker_y;
637           x_end = ladder->scrn_pos.x - ladder->scr_width/2 + ladder->scr_hole/2;
638           y_end = marker_y;
639           new_x_ini = (int)(ladder->scrn_pos.x+                             \
640                       (x_ini - ladder->scrn_pos.x) * cos_roll_value -\
641                       (y_ini - ladder->scrn_pos.y) * sin_roll_value);
642           new_y_ini = (int)(ladder->scrn_pos.y+                             \
643                       (x_ini - ladder->scrn_pos.x) * sin_roll_value +\
644                       (y_ini - ladder->scrn_pos.y) * cos_roll_value);
645           new_x_end = (int)(ladder->scrn_pos.x+                             \
646                       (x_end - ladder->scrn_pos.x) * cos_roll_value -\
647                       (y_end - ladder->scrn_pos.y) * sin_roll_value);
648           new_y_end = (int)(ladder->scrn_pos.y+                             \
649                       (x_end - ladder->scrn_pos.x) * sin_roll_value +\
650                       (y_end - ladder->scrn_pos.y) * cos_roll_value);
651
652           if( i >= 0 )
653             {
654             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
655             }
656           else
657             {
658             glEnable(GL_LINE_STIPPLE);
659             glLineStipple( 1, 0x00FF );
660             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
661             glDisable(GL_LINE_STIPPLE);
662             }
663           textString( new_x_ini - 8 * strlen(TextLadder) - 8,
664                       new_y_ini - 4,
665                       TextLadder, GLUT_BITMAP_8_BY_13 );
666
667           x_ini = ladder->scrn_pos.x + ladder->scr_width/2 - ladder->scr_hole/2;
668           y_ini = marker_y;
669           if( i != 0 )  {
670             x_end = ladder->scrn_pos.x + ladder->scr_width/2;
671             }
672           else          {
673             x_end = ladder->scrn_pos.x + ladder->scr_width/2 + 10;
674             }
675           y_end = marker_y;
676           new_x_ini = (int)(ladder->scrn_pos.x +                        \
677                       (x_ini-ladder->scrn_pos.x)*cos_roll_value -\
678                       (y_ini-ladder->scrn_pos.y)*sin_roll_value);
679           new_y_ini = (int)(ladder->scrn_pos.y +                        \
680                       (x_ini-ladder->scrn_pos.x)*sin_roll_value +\
681                       (y_ini-ladder->scrn_pos.y)*cos_roll_value);
682           new_x_end = (int)(ladder->scrn_pos.x +                        \
683                       (x_end-ladder->scrn_pos.x)*cos_roll_value -\
684                       (y_end-ladder->scrn_pos.y)*sin_roll_value);
685           new_y_end = (int)(ladder->scrn_pos.y +                        \
686                       (x_end-ladder->scrn_pos.x)*sin_roll_value +\
687                       (y_end-ladder->scrn_pos.y)*cos_roll_value);
688
689           if( i >= 0 )
690             {
691             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
692             }
693           else
694             {
695             glEnable(GL_LINE_STIPPLE);
696             glLineStipple( 1, 0x00FF );
697             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
698             glDisable(GL_LINE_STIPPLE);
699             }
700           textString( new_x_end+10, new_y_end-4,
701                       TextLadder, GLUT_BITMAP_8_BY_13 );
702           }
703         }
704             /* if( i%pscale->div_max==0 )
705             {
706                 drawOneLine( marker_x, marker_y, marker_x+6, marker_y );
707                 sprintf( TextScale, "%d", i );
708                 if( pscale->orientation == LEFT )
709                 {
710                         textString( marker_x-8*strlen(TextScale)-2, marker_y-4,
711                               TextScale, GLUT_BITMAP_8_BY_13 );
712                 }
713                 else if( pscale->orientation == RIGHT )
714                 {
715                         textString( marker_x+10, marker_y-4,
716                               TextScale, GLUT_BITMAP_8_BY_13 );
717                 }
718             } */
719         }
720     }
721
722 }
723
724 //
725 //      Draws an artificial horizon line in the center of the HUD
726 //      (with or without a center hole)
727 //
728 //      Needs: x_center, y_center, length, hole
729 //
730
731 static void drawhorizon( HUD_horizon *horizon )
732 {
733   int x_inc1, y_inc1;
734   int x_inc2, y_inc2;
735   int x_t_inc1, y_t_inc1;
736   
737   int d_bottom_x, d_bottom_y;
738   int d_right_x, d_right_y;
739   int d_top_x, d_top_y;
740   int d_left_x, d_left_y;
741   
742   int inc_b_x, inc_b_y;
743   int inc_r_x, inc_r_y;
744   int inc_t_x, inc_t_y;
745   int inc_l_x, inc_l_y;
746   
747 //      struct fgFLIGHT *f = &current_aircraft.flight;
748   double sin_bank, cos_bank;
749   double bank_angle, sideslip_angle;
750   double ss_const; // sideslip angle pixels per rad
751
752   bank_angle     = (*horizon->load_roll)();     // Roll limit +/- 30 degrees
753   if( bank_angle < -FG_PI_2/3 ) {
754     bank_angle = -FG_PI_2/3;
755   }else if( bank_angle > FG_PI_2/3 ) {
756     bank_angle = FG_PI_2/3;
757   }
758   sideslip_angle = (*horizon->load_sideslip)(); // Sideslip limit +/- 5 degrees
759   if( sideslip_angle < -FG_PI/36.0 ) {
760     sideslip_angle = -FG_PI/36.0;
761   } else if( sideslip_angle > FG_PI/36.0 ) {
762     sideslip_angle = FG_PI/36.0;
763   }
764
765         // sin_bank = sin( FG_2PI-FG_Phi );
766         // cos_bank = cos( FG_2PI-FG_Phi );
767   sin_bank = sin(FG_2PI-bank_angle);
768   cos_bank = cos(FG_2PI-bank_angle);
769   
770   x_inc1 = (int)(horizon->scr_width * cos_bank);
771   y_inc1 = (int)(horizon->scr_width * sin_bank);
772   x_inc2 = (int)(horizon->scr_hole  * cos_bank);
773   y_inc2 = (int)(horizon->scr_hole  * sin_bank);
774
775   x_t_inc1 = (int)(horizon->tee_height * sin_bank);
776   y_t_inc1 = (int)(horizon->tee_height * cos_bank);
777   
778   d_bottom_x = 0;
779   d_bottom_y = (int)(-horizon->scr_hole);
780   d_right_x  = (int)(horizon->scr_hole);
781   d_right_y  = 0;
782   d_top_x    = 0;
783   d_top_y    = (int)(horizon->scr_hole);
784   d_left_x   = (int)(-horizon->scr_hole);
785   d_left_y   = 0;
786   
787   ss_const = (horizon->scr_width*2)/(FG_2PI/36.0);// width represents 10 degrees
788
789   d_bottom_x += (int)(sideslip_angle*ss_const);
790   d_right_x  += (int)(sideslip_angle*ss_const);
791   d_left_x   += (int)(sideslip_angle*ss_const);
792   d_top_x    += (int)(sideslip_angle*ss_const);
793   
794   inc_b_x = (int)(d_bottom_x*cos_bank-d_bottom_y*sin_bank);
795   inc_b_y = (int)(d_bottom_x*sin_bank+d_bottom_y*cos_bank);
796   inc_r_x = (int)(d_right_x*cos_bank-d_right_y*sin_bank);
797   inc_r_y = (int)(d_right_x*sin_bank+d_right_y*cos_bank);
798   inc_t_x = (int)(d_top_x*cos_bank-d_top_y*sin_bank);
799   inc_t_y = (int)(d_top_x*sin_bank+d_top_y*cos_bank);
800   inc_l_x = (int)(d_left_x*cos_bank-d_left_y*sin_bank);
801   inc_l_y = (int)(d_left_x*sin_bank+d_left_y*cos_bank);
802   
803   if( horizon->scr_hole == 0 )
804     {
805     drawOneLine( horizon->scrn_pos.x - x_inc1, horizon->scrn_pos.y - y_inc1, \
806                  horizon->scrn_pos.x + x_inc1, horizon->scrn_pos.y + y_inc1 );
807     }
808   else
809     {
810     drawOneLine( horizon->scrn_pos.x - x_inc1, horizon->scrn_pos.y - y_inc1, \
811                  horizon->scrn_pos.x - x_inc2, horizon->scrn_pos.y - y_inc2 );
812     drawOneLine( horizon->scrn_pos.x + x_inc2, horizon->scrn_pos.y + y_inc2, \
813                  horizon->scrn_pos.x + x_inc1, horizon->scrn_pos.y + y_inc1 );
814     }
815
816   // draw teemarks (?)
817   drawOneLine( horizon->scrn_pos.x + x_inc2, horizon->scrn_pos.y + y_inc2, \
818                horizon->scrn_pos.x + x_inc2 + x_t_inc1, horizon->scrn_pos.y + y_inc2 - y_t_inc1 );
819   drawOneLine( horizon->scrn_pos.x - x_inc2, horizon->scrn_pos.y - y_inc2, \
820                horizon->scrn_pos.x - x_inc2 + x_t_inc1, horizon->scrn_pos.y - y_inc2 - y_t_inc1 );
821                
822   // draw sideslip diamond (it is not yet positioned correctly )
823   drawOneLine( horizon->scrn_pos.x + inc_b_x, \
824                horizon->scrn_pos.y + inc_b_y, \
825                horizon->scrn_pos.x + inc_r_x, \
826                horizon->scrn_pos.y + inc_r_y )
827   drawOneLine( horizon->scrn_pos.x + inc_r_x, \
828                horizon->scrn_pos.y + inc_r_y, \
829                horizon->scrn_pos.x + inc_t_x, \
830                horizon->scrn_pos.y + inc_t_y );
831   drawOneLine( horizon->scrn_pos.x + inc_t_x, \
832                horizon->scrn_pos.y + inc_t_y, \
833                horizon->scrn_pos.x + inc_l_x, \
834                horizon->scrn_pos.y + inc_l_y );
835   drawOneLine( horizon->scrn_pos.x + inc_l_x, \
836                horizon->scrn_pos.y + inc_l_y, \
837                horizon->scrn_pos.x + inc_b_x, \
838                horizon->scrn_pos.y + inc_b_y );
839   
840   /* drawOneLine( horizon->scrn_pos.x + inc_b_x, \
841                horizon->scrn_pos.y + inc_b_y, \
842                horizon->scrn_pos.x + inc_r_x, \
843                horizon->scrn_pos.y + inc_r_y )
844   drawOneLine( horizon->scrn_pos.x + inc_r_x, \
845                horizon->scrn_pos.y + inc_r_y, \
846                horizon->scrn_pos.x + inc_t_x, \
847                horizon->scrn_pos.y + inc_t_y );
848   drawOneLine( horizon->scrn_pos.x + inc_t_x, \
849                horizon->scrn_pos.y + inc_t_y, \
850                horizon->scrn_pos.x + inc_l_x, \
851                horizon->scrn_pos.y + inc_l_y );
852   drawOneLine( horizon->scrn_pos.x + inc_l_x, \
853                horizon->scrn_pos.y + inc_l_y, \
854                horizon->scrn_pos.x + inc_b_x, \
855                horizon->scrn_pos.y + inc_b_y ); */
856 }
857
858 //  drawControlSurfaces()
859 //      Draws a representation of the control surfaces in their current state
860 //      anywhere in the HUD
861 //
862
863 static void drawControlSurfaces( HUD_control_surfaces *ctrl_surf )
864 {
865         int x_ini, y_ini;
866         int x_end, y_end;
867         /* int x_1, y_1; */
868         /* int x_2, y_2; */
869         fgCONTROLS *pCtls;
870         int tmp;
871
872         x_ini = ctrl_surf->scrn_pos.x;
873         y_ini = ctrl_surf->scrn_pos.y;
874         x_end = x_ini + 150;
875         y_end = y_ini + 60;
876
877         drawOneLine( x_ini, y_ini, x_end, y_ini );
878         drawOneLine( x_ini, y_ini, x_ini, y_end );
879         drawOneLine( x_ini, y_end, x_end, y_end );
880         drawOneLine( x_end, y_end, x_end, y_ini );
881         drawOneLine( x_ini + 30, y_ini, x_ini + 30, y_end );
882         drawOneLine( x_ini + 30, y_ini + 30, x_ini + 90, y_ini + 30 );
883         drawOneLine( x_ini + 90, y_ini, x_ini + 90, y_end );
884         drawOneLine( x_ini + 120, y_ini, x_ini + 120, y_end );
885
886         pCtls = current_aircraft.controls;
887
888         /* Draw elevator diagram */
889         textString( x_ini + 1, y_end-11, "E", GLUT_BITMAP_8_BY_13 );
890         drawOneLine( x_ini + 15, y_ini + 5, x_ini + 15, y_ini + 55 );
891         drawOneLine( x_ini + 14, y_ini + 30, x_ini + 16, y_ini + 30 );
892         tmp = y_ini + 5 + (int)(((pCtls->elevator + 1.0)/2)*50.0);
893         if( pCtls->elevator <= -0.01 || pCtls->elevator >= 0.01 )
894         {
895                 drawOneLine( x_ini + 10, tmp, x_ini + 20, tmp );
896         }
897         else
898         {
899                 drawOneLine( x_ini + 7, tmp, x_ini + 23, tmp);
900         }
901
902         /* Draw aileron diagram */
903         textString( x_ini + 30 + 1, y_end-11, "A", GLUT_BITMAP_8_BY_13 );
904         drawOneLine( x_ini + 35, y_end-15, x_ini + 85, y_end-15 );
905         drawOneLine( x_ini + 60, y_end-14, x_ini + 60, y_end-16 );
906         tmp = x_ini + 35 + (int)(((pCtls->aileron + 1.0)/2)*50.0);
907         if( pCtls->aileron <= -0.01 || pCtls->aileron >= 0.01 )
908         {
909                 drawOneLine( tmp, y_end-20, tmp, y_end-10 );
910         }
911         else
912         {
913                 drawOneLine( tmp, y_end - 25, tmp, y_end -  5 );
914         }
915
916         /* Draw rudder diagram */
917         textString ( x_ini + 30 + 1, y_ini + 21, "R", GLUT_BITMAP_8_BY_13 );
918         drawOneLine( x_ini + 35, y_ini + 15, x_ini + 85, y_ini + 15 );
919         drawOneLine( x_ini + 60, y_ini + 14, x_ini + 60, y_ini + 16 );
920
921         tmp = x_ini + 35 + (int)(((pCtls->rudder + 1.0) / 2) * 50.0);
922         if( pCtls->rudder <= -0.01 || pCtls->rudder >= 0.01 )
923         {
924                 drawOneLine( tmp, y_ini + 20, tmp, y_ini + 10 );
925         }
926         else
927         {
928                 drawOneLine( tmp, y_ini + 25, tmp, y_ini +  5 );
929         }
930
931
932         /* Draw throttle diagram */
933         textString( x_ini + 90 + 1, y_end-11, "T", GLUT_BITMAP_8_BY_13 );
934         textString( x_ini + 90 + 1, y_end-21, "r", GLUT_BITMAP_8_BY_13 );
935         drawOneLine( x_ini + 105, y_ini + 5, x_ini + 105, y_ini + 55 );
936         tmp = y_ini + 5 + (int)(pCtls->throttle[0]*50.0);
937         drawOneLine( x_ini + 100, tmp, x_ini + 110, tmp);
938
939
940         /* Draw elevator trim diagram */
941         textString( x_ini + 121, y_end-11, "T", GLUT_BITMAP_8_BY_13 );
942         textString( x_ini + 121, y_end-22, "m", GLUT_BITMAP_8_BY_13 );
943         drawOneLine( x_ini + 135, y_ini + 5, x_ini + 135, y_ini + 55 );
944         drawOneLine( x_ini + 134, y_ini + 30, x_ini + 136, y_ini + 30 );
945
946         tmp = y_ini + 5 + (int)(((pCtls->elevator_trim + 1)/2)*50.0);
947         if( pCtls->elevator_trim <= -0.01 || pCtls->elevator_trim >= 0.01 )
948         {
949                 drawOneLine( x_ini + 130, tmp, x_ini + 140, tmp);
950         }
951         else
952         {
953                 drawOneLine( x_ini + 127, tmp, x_ini + 143, tmp);
954         }
955
956 }
957
958 //
959 // Draws a label anywhere in the HUD
960 //
961 //
962
963 static void drawlabel( HUD_label *label )
964 {
965   char buffer[80];
966   char string[80];
967   int posincr;
968   int lenstr;
969
970   if( !label ) { // Eliminate the possible, but absurd case.
971     return;
972     }
973
974   if( label->pre_str != NULL) {
975     if( label->post_str != NULL ) {
976       sprintf( buffer, "%s%s%s", label->pre_str,  \
977                                  label->format,   \
978                                  label->post_str );
979       }
980     else {
981       sprintf( buffer, "%s%s",   label->pre_str, \
982                                  label->format );
983       }
984     }
985   else {
986     if( label->post_str != NULL ) {
987       sprintf( buffer, "%s%s",   label->format,  \
988                                  label->post_str );
989       }
990     } // else do nothing if both pre and post strings are nulls. Interesting.
991
992
993   sprintf( string, buffer, (*label->load_value)() );
994 #ifdef DEBUGHUD
995         fgPrintf( FG_COCKPIT, FG_DEBUG,  buffer );
996         fgPrintf( FG_COCKPIT, FG_DEBUG,  "\n" );
997         fgPrintf( FG_COCKPIT, FG_DEBUG, string );
998         fgPrintf( FG_COCKPIT, FG_DEBUG, "\n" );
999 #endif
1000   lenstr = strlen( string );
1001   if( label->justify == LEFT_JUST ) {
1002    posincr = -lenstr*8;
1003    }
1004   else {
1005     if( label->justify == CENTER_JUST ) {
1006       posincr = -lenstr*4;
1007       }
1008     else {
1009       if( label->justify == RIGHT_JUST ) {
1010         posincr = 0;
1011         }
1012       }
1013     }
1014
1015   if( label->size == SMALL ) {
1016     textString( label->scrn_pos.x + posincr, label->scrn_pos.y,
1017                 string, GLUT_BITMAP_8_BY_13);
1018     }
1019   else  {
1020     if( label->size == LARGE ) {
1021       textString( label->scrn_pos.x + posincr, label->scrn_pos.y,
1022                   string, GLUT_BITMAP_9_BY_15);
1023       }
1024     }
1025 }
1026 // The following routines concern HUD object/component object construction
1027 //
1028
1029 // fgHUDInit
1030 //
1031 // Constructs a HUD object and then adds in instruments. At the present
1032 // the instruments are hard coded into the routine. Ultimately these need
1033 // to be defined by the aircraft's instrumentation records so that the
1034 // display for a Piper Cub doesn't show the speed range of a North American
1035 // mustange and the engine readouts of a B36!
1036 //
1037 Hptr fgHUDInit( fgAIRCRAFT *current_aircraft )
1038 {
1039   Hptr hud;
1040
1041   fgPrintf( FG_COCKPIT, FG_INFO, "Initializing HUD\n" );
1042
1043   hud = (Hptr)calloc(sizeof( HUD),1);
1044   if( hud == NULL )
1045     return( NULL );
1046
1047   hud->code = 1;
1048   hud->status = 0;
1049
1050   // For now lets just hardcode the hud here.
1051   // In the future, hud information has to come from the same place
1052   // aircraft information came from.
1053
1054   fgHUDSetTimeMode( hud, NIGHT );
1055   fgHUDSetBrightness( hud, BRT_LIGHT );
1056
1057      // TBI
1058   fgHUDAddHorizon( hud, 330, 100, 40, 5, 10, get_roll, get_sideslip );
1059
1060   fgHUDAddLadder ( hud, 330, 285, 120, 180, 70, 10,
1061                    NONE, 45, get_roll, get_pitch );
1062      // KIAS
1063   fgHUDAddScale  ( hud, VERTICAL,     LIMIT, 200, 180, 380,  5,  10,
1064                       LEFT,     0,  100,   50,   0, get_speed );
1065      // Angle of Attack
1066   fgHUDAddScale  ( hud, HORIZONTAL, NOLIMIT, 180, 250, 410,  1,   5,
1067                       BOTTOM, -40,   50,   21,   0, get_aoa );
1068      // GYRO COMPASS
1069   fgHUDAddScale  ( hud, HORIZONTAL, NOLIMIT, 380, 200, 460,  5,  10,
1070                       TOP,      0,   50,   50, 360, get_heading );
1071      // AMSL
1072   fgHUDAddScale  ( hud, VERTICAL,     LIMIT, 460, 180, 380, 25, 100,
1073                       RIGHT,    0, 15000, 250,   0, get_altitude);
1074
1075   fgHUDAddLabel  ( hud, 160, 150, SMALL, NOBLINK,
1076                       RIGHT_JUST, NULL, " Kts",      "%5.0f", get_speed );
1077   fgHUDAddLabel  ( hud, 160, 135, SMALL, NOBLINK,
1078                       RIGHT_JUST, NULL, " m",        "%5.0f", get_altitude );
1079   fgHUDAddLabel  ( hud, 160, 120, SMALL, NOBLINK,
1080                       RIGHT_JUST, NULL, " Roll",     "%5.2f", get_roll );
1081   fgHUDAddLabel  ( hud, 160, 105, SMALL, NOBLINK,
1082                       RIGHT_JUST, "Lat  ", "d",     "%03.0f", get_latitude );
1083   fgHUDAddLabel  ( hud, 160, 90,  SMALL, NOBLINK,
1084                       RIGHT_JUST, NULL, " m",        "%05.2f", get_lat_min );
1085   
1086   fgHUDAddLabel  ( hud, 440, 150, SMALL, NOBLINK,
1087                       RIGHT_JUST, NULL, " AOA",      "%5.2f", get_aoa );
1088   fgHUDAddLabel  ( hud, 440, 135, SMALL, NOBLINK,
1089                       RIGHT_JUST, NULL, " Heading",  "%5.0f", get_heading );
1090   fgHUDAddLabel  ( hud, 440, 120, SMALL, NOBLINK,
1091                       RIGHT_JUST, NULL, " Sideslip", "%5.2f", get_sideslip );
1092   fgHUDAddLabel  ( hud, 440, 105, SMALL, NOBLINK,
1093                       RIGHT_JUST, "Lon  ", "d",     "%04.0f", get_longitude );
1094   fgHUDAddLabel  ( hud, 440, 90,  SMALL, NOBLINK,
1095                       RIGHT_JUST, NULL, " m",        "%05.2f", get_long_min );
1096
1097   fgHUDAddControlSurfaces( hud, 10, 10, NULL );
1098
1099 //  fgHUDAddControl( hud, HORIZONTAL, 50,  25, get_aileronval  ); // was 10, 10
1100 //  fgHUDAddControl( hud, VERTICAL,   150, 25, get_elevatorval ); // was 10, 10
1101 //  fgHUDAddControl( hud, HORIZONTAL, 250, 25, get_rudderval   ); // was 10, 10
1102
1103   return( hud );
1104 }
1105
1106
1107 // add_instrument
1108 //
1109 // This is a stand in for linked list code that will get replaced later
1110 // by some more elegant list handling code.
1111
1112 void add_instrument( Hptr hud, HIptr pinstrument )
1113 {
1114     if( !hud || !pinstrument ) {
1115         return;
1116     }
1117
1118     pinstrument->next = hud->instruments;
1119     hud->instruments = pinstrument;
1120 }
1121
1122
1123 // fgHUDAddHorizon
1124 //
1125 // Constructs a HUD_horizon "object" and installs it into the hud instrument
1126 // list.
1127
1128 Hptr fgHUDAddHorizon( Hptr hud,     \
1129                       int x_pos,    \
1130                       int y_pos,    \
1131                       int length,   \
1132                       int hole_len, \
1133                       int tee_height,\
1134                       double (*load_roll)(),
1135                       double (*load_sideslip)() )
1136 {
1137     HUD_horizon *phorizon;
1138     HUD_instr   *pinstrument;
1139
1140     if( !hud ) {
1141         return NULL;
1142     }
1143                                        // construct the parent object
1144     pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1145     if( pinstrument == NULL ) {
1146         return( NULL );
1147     }
1148     pinstrument->type    = HUDhorizon;  //  ARTIFICIAL_HORIZON;
1149
1150                                       // Construct the horizon
1151     phorizon = (HUD_horizon *) calloc( sizeof(HUD_horizon),1);
1152     if( phorizon == NULL )   {
1153         return( NULL );
1154     }
1155
1156     phorizon->scrn_pos.x    = x_pos;
1157     phorizon->scrn_pos.y    = y_pos;
1158     phorizon->scr_width     = length | 1;
1159     phorizon->scr_hole      = hole_len;
1160     phorizon->tee_height    = tee_height;
1161     phorizon->load_roll     = load_roll;
1162     phorizon->load_sideslip = load_sideslip;
1163     //  Install the horizon in the parent.
1164     pinstrument->instr   = phorizon;
1165     //  Install the instrument into hud.
1166     add_instrument( hud, pinstrument);
1167
1168     return( hud );
1169 }
1170
1171 // fgHUDAddScale
1172 //
1173 // Constructs a HUD_scale "object" and installs it into the hud instrument
1174 // list.
1175
1176 Hptr fgHUDAddScale( Hptr hud,        \
1177                     int type,        \
1178                     int sub_type,    \
1179                     int scr_pos,     \
1180                     int scr_min,     \
1181                     int scr_max,     \
1182                     int div_min,     \
1183                     int div_max,     \
1184                     int orientation, \
1185                     int min_value,   \
1186                     int max_value,   \
1187                     int width_units, \
1188                     int modulus,     \
1189                     double (*load_value)() )
1190 {
1191   HUD_scale *pscale;
1192   HUD_instr *pinstrument;
1193
1194   if( !hud ) {
1195     return NULL;
1196     }
1197
1198         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1199         if( pinstrument == NULL ) {
1200      return( NULL );
1201      }
1202
1203   pinstrument->type = HUDscale;
1204
1205   pscale = ( HUD_scale *)calloc(sizeof(HUD_scale),1);
1206   if( pscale == NULL )   {
1207      return( NULL );
1208     }
1209
1210   pscale->type             = type;
1211   pscale->sub_type         = sub_type;
1212   pscale->div_min          = div_min;
1213   pscale->div_max          = div_max;
1214   pscale->orientation      = orientation;
1215   pscale->minimum_value    = min_value;
1216   pscale->maximum_value    = max_value;
1217   pscale->modulo           = modulus;
1218   pscale->load_value       = load_value;
1219
1220   pscale->half_width_units = width_units / 2.0;
1221   pscale->scr_span = scr_max - scr_min; // Run of scan in pix coord
1222   pscale->scr_span |= 1;                // Force odd span of units.
1223              // If span is odd number of units, mid will be correct.
1224              // If not it will be high by one coordinate unit. This is
1225              // an artifact of integer division needed for screen loc's.
1226
1227   pscale->mid_scr  = (pscale->scr_span >> 1) + scr_min;
1228
1229              // Calculate the number of screen units per indicator unit
1230              // We must force floating point calculation or the factor
1231              // will be low and miss locate tics by several units.
1232
1233   pscale->factor   = (double)pscale->scr_span / (double)width_units;
1234
1235   switch( type ) {
1236     case HORIZONTAL:
1237       pscale->scrn_pos.left    = scr_min;
1238       pscale->scrn_pos.top     = scr_pos;
1239       pscale->scrn_pos.right   = scr_max;
1240       pscale->scrn_pos.bottom  = scr_pos;
1241       break;
1242
1243     case VERTICAL:
1244     default:
1245       pscale->scrn_pos.left    = scr_pos;
1246       pscale->scrn_pos.top     = scr_max;
1247       pscale->scrn_pos.right   = scr_pos;
1248       pscale->scrn_pos.bottom  = scr_min;
1249     }
1250
1251                                      // Install the scale
1252   pinstrument->instr = pscale;
1253                                       //  Install the instrument into hud.
1254   add_instrument( hud, pinstrument);
1255
1256   return( hud );
1257 }
1258
1259 // fgHUDAddLabel
1260 //
1261 // Constructs a HUD_Label object and installs it into the hud instrument
1262 // list.
1263 Hptr fgHUDAddLabel( Hptr hud,       \
1264                     int x_pos,      \
1265                     int y_pos,      \
1266                     int size,       \
1267                     int blink,      \
1268                     int justify,    \
1269                                                   char *pre_str,  \
1270                     char *post_str, \
1271                     char *format,   \
1272                     double (*load_value)() )
1273 {
1274         HUD_label *plabel;
1275         HUD_instr *pinstrument;
1276
1277   if( !hud ) {
1278     return NULL;
1279     }
1280
1281         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1282         if( pinstrument == NULL ) {
1283     return NULL;
1284     }
1285         pinstrument->type = HUDlabel;
1286
1287         plabel = (HUD_label *)calloc(sizeof(HUD_label),1);
1288         if( plabel == NULL ){
1289     return NULL;
1290     }
1291
1292   plabel->scrn_pos.x      = x_pos;
1293   plabel->scrn_pos.y      = y_pos;
1294   plabel->size       = size;
1295   plabel->blink      = blink;
1296   plabel->justify    = justify;
1297   plabel->pre_str    = pre_str;
1298   plabel->post_str   = post_str;
1299   plabel->format     = format;
1300   plabel->load_value = load_value;
1301                                       // Install the label
1302         pinstrument->instr = plabel;
1303                                       //  Install the instrument into hud.
1304   add_instrument( hud, pinstrument);
1305
1306         return( hud );
1307 }
1308
1309 // fgHUDAddLadder
1310 //
1311 // Contains code that constructs a ladder "object" and installs it as
1312 // a hud instrument in the hud instrument list.
1313 //
1314 Hptr fgHUDAddLadder( Hptr hud,        \
1315                      int x_pos,       \
1316                      int y_pos,       \
1317                      int scr_width,   \
1318                      int scr_height,  \
1319                                                    int hole_len,    \
1320                      int div_units,   \
1321                      int label_pos,   \
1322                      int width_units, \
1323                                                    double (*load_roll)(),
1324                      double (*load_pitch)() )
1325 {
1326         HUD_ladder *pladder;
1327         HUD_instr  *pinstrument;
1328
1329   if( !hud ) {
1330     return NULL;
1331     }
1332
1333         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1334         if( pinstrument == NULL )
1335                 return( NULL );
1336
1337         pinstrument->type = HUDladder;
1338
1339         pladder = (HUD_ladder *)calloc(sizeof(HUD_ladder),1);
1340         if( pladder == NULL )
1341                 return( NULL );
1342
1343   pladder->type           = 0; // Not used.
1344   pladder->scrn_pos.x          = x_pos;
1345   pladder->scrn_pos.y          = y_pos;
1346   pladder->scr_width      = scr_width;
1347   pladder->scr_height     = scr_height;
1348   pladder->scr_hole       = hole_len;
1349   pladder->div_units      = div_units;
1350   pladder->label_position = label_pos;
1351   pladder->width_units    = width_units;
1352   pladder->load_roll      = load_roll;
1353   pladder->load_pitch     = load_pitch;
1354
1355   pinstrument->instr      = pladder;
1356                                       //  Install the instrument into hud.
1357   add_instrument( hud, pinstrument);
1358         return hud;
1359 }
1360
1361 //   fgHUDAddControlSurfaces()
1362 //
1363 //   Adds the control surface indicators which make up for the lack of seat
1364 //   of the pants feel. Should be unnecessary with joystick and pedals
1365 //   enabled. But that is another improvement. Also, what of flaps? Spoilers?
1366 //   This may need to be expanded or flattened into multiple indicators,
1367 //   vertical and horizontal.
1368
1369 Hptr fgHUDAddControlSurfaces( Hptr hud,
1370                               int x_pos,
1371                               int y_pos,
1372                               double (*load_value)() )
1373 {
1374         HUD_control_surfaces *pcontrol_surfaces;
1375         HUD_instr *pinstrument;
1376
1377     if( !hud ) {
1378       return NULL;
1379     }
1380
1381     // Construct shell
1382     pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1383     if( !pinstrument ) {
1384       return NULL;
1385       }
1386     pinstrument->type = HUDcontrol_surfaces;
1387
1388     // Construct core
1389     pcontrol_surfaces = (HUD_control_surfaces *)calloc(sizeof(HUD_control),1);
1390     if( !pcontrol_surfaces ) {
1391       return( NULL );
1392       }
1393
1394     pcontrol_surfaces->scrn_pos.x = x_pos;
1395     pcontrol_surfaces->scrn_pos.y = y_pos;
1396     pcontrol_surfaces->load_value = load_value;
1397
1398     pinstrument->instr     = pcontrol_surfaces;
1399                                                    // Install
1400     add_instrument( hud, pinstrument);
1401
1402     return hud;
1403 }
1404
1405 // fgHUDAddControl
1406 //
1407 //
1408
1409 Hptr fgHUDAddControl( Hptr hud,        \
1410                       int ctrl_x,      \
1411                       int ctrl_y,      \
1412                       int ctrl_length, \
1413                       int orientation, \
1414                       int alignment,   \
1415                       int min_value,   \
1416                       int max_value,   \
1417                       int width_units, \
1418                       double (*load_value)() )
1419 {
1420     HUD_control *pcontrol;
1421     HUD_instr *pinstrument;
1422
1423     if( !hud ) {
1424       return NULL;
1425     }
1426
1427     // Construct shell
1428     pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1429     if( !pinstrument ) {
1430       return NULL;
1431       }
1432     pinstrument->type = HUDcontrol;
1433
1434     // Construct core
1435     pcontrol = (HUD_control *)calloc(sizeof(HUD_control),1);
1436     if( !(pcontrol == NULL) ) {
1437       return( NULL );
1438       }
1439     pcontrol->scrn_pos.x    = ctrl_x;
1440     pcontrol->scrn_pos.y    = ctrl_y;
1441     pcontrol->ctrl_length   = ctrl_length;
1442     pcontrol->orientation   = orientation;
1443     pcontrol->alignment     = alignment;
1444     pcontrol->min_value     = min_value;
1445     pcontrol->max_value     = max_value;
1446     pcontrol->width_units   = width_units;
1447     pcontrol->load_value    = load_value;
1448                                                    // Integrate
1449     pinstrument->instr     = pcontrol;
1450                                                    // Install
1451     add_instrument( hud, pinstrument);
1452
1453     return hud;
1454 }
1455
1456 /*
1457 Hptr fgHUDAddMovingHorizon(  Hptr hud,     \
1458                              int x_pos,    \
1459                              int y_pos,    \
1460                              int length,   \
1461                              int hole_len, \
1462                              int color )
1463 {
1464
1465 }
1466
1467 Hptr fgHUDAddCircularLadder( Hptr hud,    \
1468                              int scr_min, \
1469                              int scr_max, \
1470                              int div_min, \
1471                              int div_max, \
1472                              int max_value )
1473 {
1474
1475 }
1476
1477 Hptr fgHUDAddNumDisp( Hptr hud,           \
1478                       int x_pos,          \
1479                       int y_pos,          \
1480                       int size,           \
1481                       int color,          \
1482                       int blink,          \
1483                                                           char *pre_str,      \
1484                       char *post_str )
1485 {
1486
1487 }
1488 */
1489
1490 // fgUpdateHUD
1491 //
1492 // Performs a once around the list of calls to instruments installed in
1493 // the HUD object with requests for redraw. Kinda. It will when this is
1494 // all C++.
1495 //
1496
1497 void fgUpdateHUD( Hptr hud ) {
1498     HIptr phud_instr;
1499
1500     glMatrixMode(GL_PROJECTION);
1501     glPushMatrix();
1502
1503     glLoadIdentity();
1504     gluOrtho2D(0, 640, 0, 480);
1505     glMatrixMode(GL_MODELVIEW);
1506     glPushMatrix();
1507     glLoadIdentity();
1508
1509     glColor3f(1.0, 1.0, 1.0);
1510     glIndexi(7);
1511
1512     glDisable(GL_DEPTH_TEST);
1513     glDisable(GL_LIGHTING);
1514
1515     glLineWidth(1);
1516                                    // This is a good improvement, but needs
1517                                    // to respond to a dial instead of time
1518                                    // of day. Of course, we have no dial!
1519     if( hud->time_of_day==DAY) {
1520       switch (hud->brightness) {
1521          case BRT_LIGHT:
1522            glColor3f (0.1, 0.9, 0.1);
1523            break;
1524          case BRT_MEDIUM:
1525            glColor3f (0.1, 0.7, 0.0);
1526            break;
1527          case BRT_DARK:
1528            glColor3f (0.0, 0.5, 0.0);
1529          }
1530       }
1531     else if( hud->time_of_day==NIGHT) {
1532       switch (hud->brightness) {
1533          case BRT_LIGHT:
1534            glColor3f (0.9, 0.1, 0.1);
1535            break;
1536          case BRT_MEDIUM:
1537            glColor3f (0.7, 0.0, 0.1);
1538            break;
1539          case BRT_DARK:
1540            glColor3f (0.5, 0.0, 0.0);
1541          }
1542       }
1543     else {
1544       glColor3f (0.1, 0.9, 0.1);
1545       }
1546
1547     fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d  Status %d\n",
1548               hud->code, hud->status );
1549
1550     phud_instr = hud->instruments;
1551     while( phud_instr ) {
1552         /* printf("Drawing Instrument %d\n", phud_instr->type); */
1553
1554         switch (phud_instr->type) {
1555     case HUDhorizon:   // ARTIFICIAL HORIZON
1556             drawhorizon( (pHUDhorizon)phud_instr->instr );
1557             break;
1558
1559     case HUDscale:     // Need to simplify this call.
1560             drawscale (  (pHUDscale)  phud_instr->instr  );
1561             break;
1562
1563     case HUDlabel:
1564             drawlabel (  (pHUDlabel)  phud_instr->instr  );
1565             break;
1566
1567     case HUDladder:
1568             drawladder(  (pHUDladder) phud_instr->instr  );
1569             break;
1570
1571 //    case HUDcontrol:
1572 //      drawControl( (pHUDcontrol) phud_instr->instr );
1573 //      break;
1574
1575     case HUDcontrol_surfaces:
1576             drawControlSurfaces( (pHUDControlSurfaces) phud_instr->instr );
1577             break;
1578
1579     default:; // Ignore anything you don't know about.
1580     }
1581
1582   phud_instr = phud_instr->next;
1583   }
1584
1585   glEnable(GL_DEPTH_TEST);
1586   glEnable(GL_LIGHTING);
1587   glMatrixMode(GL_PROJECTION);
1588   glPopMatrix();
1589   glMatrixMode(GL_MODELVIEW);
1590   glPopMatrix();
1591 }
1592
1593 void fgHUDSetTimeMode( Hptr hud, int time_of_day )
1594 {
1595
1596   hud->time_of_day = time_of_day;
1597
1598 }
1599
1600 void fgHUDSetBrightness( Hptr hud, int brightness )
1601 {
1602
1603   hud->brightness = brightness;
1604
1605 }
1606
1607 /* $Log$
1608 /* Revision 1.2  1998/04/25 22:06:27  curt
1609 /* Edited cvs log messages in source files ... bad bad bad!
1610 /*
1611  * Revision 1.1  1998/04/24 00:45:57  curt
1612  * C++-ifing the code a bit.
1613  *
1614  * Revision 1.22  1998/04/18 04:14:02  curt
1615  * Moved fg_debug.c to it's own library.
1616  *
1617  * Revision 1.21  1998/04/03 21:55:28  curt
1618  * Converting to Gnu autoconf system.
1619  * Tweaks to hud.c
1620  *
1621  * Revision 1.20  1998/03/09 22:48:40  curt
1622  * Minor "formatting" tweaks.
1623  *
1624  * Revision 1.19  1998/02/23 20:18:28  curt
1625  * Incorporated Michele America's hud changes.
1626  *
1627  * Revision 1.18  1998/02/21 14:53:10  curt
1628  * Added Charlie's HUD changes.
1629  *
1630  * Revision 1.17  1998/02/20 00:16:21  curt
1631  * Thursday's tweaks.
1632  *
1633  * Revision 1.16  1998/02/19 13:05:49  curt
1634  * Incorporated some HUD tweaks from Michelle America.
1635  * Tweaked the sky's sunset/rise colors.
1636  * Other misc. tweaks.
1637  *
1638  * Revision 1.15  1998/02/16 13:38:39  curt
1639  * Integrated changes from Charlie Hotchkiss.
1640  *
1641  * Revision 1.14  1998/02/12 21:59:41  curt
1642  * Incorporated code changes contributed by Charlie Hotchkiss
1643  * <chotchkiss@namg.us.anritsu.com>
1644  *
1645  * Revision 1.12  1998/02/09 15:07:48  curt
1646  * Minor tweaks.
1647  *
1648  * Revision 1.11  1998/02/07 15:29:34  curt
1649  * Incorporated HUD changes and struct/typedef changes from Charlie Hotchkiss
1650  * <chotchkiss@namg.us.anritsu.com>
1651  *
1652  * Revision 1.10  1998/02/03 23:20:14  curt
1653  * Lots of little tweaks to fix various consistency problems discovered by
1654  * Solaris' CC.  Fixed a bug in fg_debug.c with how the fgPrintf() wrapper
1655  * passed arguments along to the real printf().  Also incorporated HUD changes
1656  * by Michele America.
1657  *
1658  * Revision 1.9  1998/01/31 00:43:04  curt
1659  * Added MetroWorks patches from Carmen Volpe.
1660  *
1661  * Revision 1.8  1998/01/27 00:47:51  curt
1662  * Incorporated Paul Bleisch's <pbleisch@acm.org> new debug message
1663  * system and commandline/config file processing code.
1664  *
1665  * Revision 1.7  1998/01/19 18:40:20  curt
1666  * Tons of little changes to clean up the code and to remove fatal errors
1667  * when building with the c++ compiler.
1668  *
1669  * Revision 1.6  1997/12/15 23:54:34  curt
1670  * Add xgl wrappers for debugging.
1671  * Generate terrain normals on the fly.
1672  *
1673  * Revision 1.5  1997/12/10 22:37:39  curt
1674  * Prepended "fg" on the name of all global structures that didn't have it yet.
1675  * i.e. "struct WEATHER {}" became "struct fgWEATHER {}"
1676  *
1677  * Revision 1.4  1997/09/23 00:29:32  curt
1678  * Tweaks to get things to compile with gcc-win32.
1679  *
1680  * Revision 1.3  1997/09/05 14:17:26  curt
1681  * More tweaking with stars.
1682  *
1683  * Revision 1.2  1997/09/04 02:17:30  curt
1684  * Shufflin' stuff.
1685  *
1686  * Revision 1.1  1997/08/29 18:03:22  curt
1687  * Initial revision.
1688  *
1689  */