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