]> git.mxchange.org Git - flightgear.git/blob - Cockpit/hud.c
Incorporated HUD changes and struct/typedef changes from Charlie Hotchkiss
[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  - nomimarketing@mail.telepac.pt
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 /* not WIN32 */
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 <Scenery/mesh.h>   /* not used any more :-) */
49 #include <Time/fg_timer.h>
50 #include <Weather/weather.h>
51
52 // #define DEBUG
53
54 #define drawOneLine(x1,y1,x2,y2)  glBegin(GL_LINES);  \
55    glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
56    
57
58 // The following routines obtain information concerntin the aircraft's
59 // current state and return it to calling instrument display routines.
60 // They should eventually be member functions of the aircraft.
61 //
62
63 double get_speed( void )
64 {
65         fgFLIGHT *f;
66
67         f = current_aircraft.flight;
68         return( FG_V_equiv_kts );    // Make an explicit function call.
69 }
70
71 double get_aoa( void )
72 {
73         fgFLIGHT *f;
74               
75         f = current_aircraft.flight;
76         return( FG_Gamma_vert_rad * RAD_TO_DEG );
77 }
78
79 double get_roll( void )
80 {
81         fgFLIGHT *f;
82               
83         f = current_aircraft.flight;
84         return( FG_Phi );
85 }
86
87 double get_pitch( void )
88 {
89         fgFLIGHT *f;
90               
91         f = current_aircraft.flight;
92         return( FG_Theta );
93 }
94
95 double get_heading( void )
96 {
97         fgFLIGHT *f;
98
99         f = current_aircraft.flight;
100         return( FG_Psi*RAD_TO_DEG );
101 }
102
103 double get_altitude( void )
104 {
105         fgFLIGHT *f;
106         // double rough_elev;
107
108         f = current_aircraft.flight;
109         // rough_elev = mesh_altitude(FG_Longitude * RAD_TO_ARCSEC,
110         //                                 FG_Latitude  * RAD_TO_ARCSEC);
111
112         return( FG_Altitude * FEET_TO_METER /* -rough_elev */ );
113 }
114
115 //
116 // The following code deals with painting the "instrument" on the display
117 //
118    /* textString - Bitmap font string */
119
120 static void textString(int x, int y, char *msg, void *font)
121 {
122         glRasterPos2f(x, y);
123         while (*msg) {
124                 glutBitmapCharacter(font, *msg);
125                 msg++;
126     }
127 }
128
129 /* strokeString - Stroke font string */
130 /*
131 static void strokeString(int x, int y, char *msg, void *font)
132 {
133         glPushMatrix();
134         glTranslatef(x, y, 0);
135         glScalef(.04, .04, .04);
136         while (*msg) {
137                 glutStrokeCharacter(font, *msg);
138                 msg++;
139         }
140         glPopMatrix();
141 }
142 */
143
144 /*
145
146         Draws a measuring scale anywhere on the HUD
147
148
149         Needs: HUD_scale struct
150
151 */
152 static void drawscale( HUD_scale * pscale )
153 {
154   double vmin, vmax;
155   int marker_x;
156   int marker_y;
157   int mid_scr;
158   register i;
159   double factor;
160   char TextScale[80];
161   int condition;
162   double cur_value = (*(pscale->load_value))();
163
164   vmin = cur_value - pscale->maximum_value / 2;
165   vmax = cur_value + pscale->maximum_value / 2;
166
167   mid_scr = pscale->scr_min+(pscale->scr_max-pscale->scr_min)/2;
168
169   if( pscale->type == VERTICAL )     // Vertical scale
170     {
171     if( pscale->orientation == LEFT )
172       marker_x = pscale->scr_pos-6;
173     else
174       if( pscale->orientation == RIGHT )
175         marker_x = pscale->scr_pos;
176     drawOneLine( pscale->scr_pos,
177                  pscale->scr_min,
178                  pscale->scr_pos,
179                  pscale->scr_max );
180     if( pscale->orientation == LEFT )
181       {
182       drawOneLine( pscale->scr_pos-3,
183                    pscale->scr_min,
184                    pscale->scr_pos,
185                    pscale->scr_min );
186
187       drawOneLine( pscale->scr_pos-3,
188                    pscale->scr_max,
189                    pscale->scr_pos,
190                    pscale->scr_max );
191
192       drawOneLine( pscale->scr_pos,
193                    mid_scr,
194                    pscale->scr_pos+6,
195                    mid_scr );
196
197       }
198     else
199       if( pscale->orientation == RIGHT )
200         {
201         drawOneLine( pscale->scr_pos,
202                      pscale->scr_min,
203                      pscale->scr_pos+3,
204                      pscale->scr_min );
205
206         drawOneLine( pscale->scr_pos,
207                      pscale->scr_max,
208                      pscale->scr_pos+3,
209                      pscale->scr_max );
210
211         drawOneLine( pscale->scr_pos,
212                      mid_scr,
213                      pscale->scr_pos-6,
214                      mid_scr );
215         }
216
217     factor = (pscale->scr_max - pscale->scr_min)/pscale->maximum_value;
218
219     for( i=vmin; i<=vmax; i+=1 )
220       {
221       if( pscale->sub_type == LIMIT )
222         condition = i>= pscale->minimum_value;
223       else
224         if( pscale->sub_type == NOLIMIT )
225           condition = 1;
226
227       if( condition )
228         {
229         marker_y = pscale->scr_min+(i-vmin)*factor;
230         if( i%pscale->div_min==0 )
231           if( pscale->orientation == LEFT )
232             {
233             drawOneLine( marker_x+3, marker_y, marker_x+6, marker_y );
234             }
235           else
236             if( pscale->orientation == RIGHT )
237               {
238               drawOneLine( marker_x, marker_y, marker_x+3, marker_y );
239               }
240             if( i%pscale->div_max==0 )
241               {
242               drawOneLine( marker_x, marker_y, marker_x+6, marker_y );
243               sprintf( TextScale, "%d", i );
244               if( pscale->orientation == LEFT )
245                 {
246                 textString( marker_x-8*strlen(TextScale)-2, marker_y-4,
247                             TextScale, GLUT_BITMAP_8_BY_13 );
248                 }
249               else
250                 if( pscale->orientation == RIGHT )
251                   {
252                   textString( marker_x+10, marker_y-4,
253                               TextScale, GLUT_BITMAP_8_BY_13 );
254                   }
255               }
256          }
257       } // End for range of i from vmin to vmax
258     }
259   if( pscale->type == HORIZONTAL )     // Horizontal scale
260     {
261     if( pscale->orientation == TOP )
262       marker_y = pscale->scr_pos;
263     else
264       if( pscale->orientation == BOTTOM )
265         marker_y = pscale->scr_pos-6;
266     drawOneLine( pscale->scr_min,
267                  pscale->scr_pos,
268                  pscale->scr_max,
269                  pscale->scr_pos );
270     if( pscale->orientation == TOP )
271       {
272       drawOneLine( pscale->scr_min,
273                    pscale->scr_pos,
274                    pscale->scr_min,
275                    pscale->scr_pos-3 );
276
277       drawOneLine( pscale->scr_max,
278                    pscale->scr_pos,
279                    pscale->scr_max,
280                    pscale->scr_pos-3 );
281
282       drawOneLine( mid_scr,
283                    pscale->scr_pos,
284                    mid_scr,
285                    pscale->scr_pos-6 );
286
287       }
288     else
289       if( pscale->orientation == BOTTOM )
290         {
291         drawOneLine( pscale->scr_min,
292                      pscale->scr_pos,
293                      pscale->scr_min,
294                      pscale->scr_pos+3 );
295
296         drawOneLine( pscale->scr_max,
297                      pscale->scr_pos,
298                      pscale->scr_max,
299                      pscale->scr_pos+3 );
300
301         drawOneLine( mid_scr,
302                      pscale->scr_pos,
303                      mid_scr,
304                      pscale->scr_pos+6 );
305         }
306
307     factor = (pscale->scr_max - pscale->scr_min)/pscale->maximum_value;
308
309     for( i=vmin; i<=vmax; i+=1 )
310       {
311       if( pscale->sub_type == LIMIT )
312         condition = i>= pscale->minimum_value;
313       else
314         if( pscale->sub_type == NOLIMIT )
315           condition = 1;
316
317       if( condition )
318         {
319         marker_x = pscale->scr_min+(i-vmin)*factor;
320         if( i%pscale->div_min==0 )
321           if( pscale->orientation == TOP )
322             {
323             drawOneLine( marker_x, marker_y, marker_x, marker_y+3 );
324             }
325           else
326             if( pscale->orientation == BOTTOM )
327               {
328               drawOneLine( marker_x, marker_y+3, marker_x, marker_y+6 );
329               }
330           if( i%pscale->div_max==0 )
331             {
332             sprintf( TextScale, "%d", i );
333             if( pscale->orientation == TOP )
334               {
335               drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
336               textString ( marker_x-4*strlen(TextScale), marker_y+14,
337                            TextScale, GLUT_BITMAP_8_BY_13 );
338               }
339             else
340               if( pscale->orientation == BOTTOM )
341                 {
342                 drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
343                 textString ( marker_x+10, marker_y-4,
344                              TextScale, GLUT_BITMAP_8_BY_13 );
345                 }
346             }
347         }
348       }
349     }
350
351 }
352
353 /*
354
355         Draws a climb ladder in the center of the HUD
356
357 */
358
359 static void drawladder( HUD_ladder *ladder )
360 {
361   double vmin, vmax;
362   double roll_value, pitch_value;
363   int marker_x, marker_y;
364 #ifdef DEBUGHUD
365   int mid_scr;
366 #endif
367   int scr_min, scr_max;
368   int x_ini, x_end;
369   int y_ini, y_end;
370   int new_x_ini, new_x_end;
371   int new_y_ini, new_y_end;
372   register i;
373   double factor;
374   char TextLadder[80];
375   int condition;
376
377   roll_value = (*ladder->load_roll)();
378   pitch_value = (*ladder->load_pitch)()*RAD_TO_DEG;
379
380   vmin = pitch_value - ladder->width_units/2;
381   vmax = pitch_value + ladder->width_units/2;
382     
383   scr_min = ladder->y_pos - (ladder->scr_height/2);
384   scr_max = scr_min       + ladder->scr_height;
385
386 #ifdef DEBUGHUD
387   mid_scr = scr_min       + (scr_max-scr_min)/2;
388 #endif
389
390   marker_x = ladder->x_pos - ladder->scr_width/2;
391
392   factor = (scr_max-scr_min)/ladder->width_units;
393
394   for( i=vmin; i<=vmax; i+=1 )
395     {
396     condition = 1;
397     if( condition )
398       {
399       marker_y = scr_min+(i-vmin)*factor;
400       if( i%ladder->div_units==0 )
401         {
402         sprintf( TextLadder, "%d", i );
403         if( ladder->scr_hole == 0 )
404           {
405           if( i )
406             x_ini = ladder->x_pos - ladder->scr_width/2;
407           else
408             x_ini = ladder->x_pos - ladder->scr_width/2 - 10;
409           y_ini = marker_y;
410           x_end = ladder->x_pos + ladder->scr_width/2;
411           y_end = marker_y;
412           new_x_ini = ladder->x_pos +                             \
413                       (x_ini - ladder->x_pos) * cos(roll_value) - \
414                       (y_ini - ladder->y_pos) * sin(roll_value);
415           new_y_ini = ladder->y_pos +                             \
416                       (x_ini - ladder->x_pos) * sin(roll_value) + \
417                       (y_ini - ladder->y_pos) * cos(roll_value);
418           new_x_end = ladder->x_pos +                             \
419                       (x_end - ladder->x_pos) * cos(roll_value) - \
420                       (y_end - ladder->y_pos) * sin(roll_value);
421           new_y_end = ladder->y_pos +                             \
422                       (x_end - ladder->x_pos) * sin(roll_value) + \
423                       (y_end - ladder->y_pos) * cos(roll_value);
424
425           if( i >= 0 )
426             {
427             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
428             }
429           else
430             {
431             glEnable(GL_LINE_STIPPLE);
432             glLineStipple( 1, 0x00FF );
433             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
434             glDisable(GL_LINE_STIPPLE);
435             }
436           textString( new_x_ini -  8 * strlen(TextLadder) - 8,
437                       new_y_ini -  4,
438                       TextLadder, GLUT_BITMAP_8_BY_13 );
439           textString( new_x_end + 10,
440                       new_y_end -  4,
441                       TextLadder, GLUT_BITMAP_8_BY_13 );
442           }
443         else
444           {
445           if( i != 0 )
446             x_ini = ladder->x_pos - ladder->scr_width/2;
447           else
448             x_ini = ladder->x_pos - ladder->scr_width/2 - 10;
449           y_ini = marker_y;
450           x_end = ladder->x_pos - ladder->scr_width/2 + ladder->scr_hole/2;
451           y_end = marker_y;
452           new_x_ini = ladder->x_pos+                             \
453                       (x_ini - ladder->x_pos) * cos(roll_value) -\
454                       (y_ini - ladder->y_pos) * sin(roll_value);
455           new_y_ini = ladder->y_pos+                             \
456                       (x_ini - ladder->x_pos) * sin(roll_value) +\
457                       (y_ini - ladder->y_pos) * cos(roll_value);
458           new_x_end = ladder->x_pos+                             \
459                       (x_end - ladder->x_pos) * cos(roll_value) -\
460                       (y_end - ladder->y_pos) * sin(roll_value);
461           new_y_end = ladder->y_pos+                             \
462                       (x_end - ladder->x_pos) * sin(roll_value) +\
463                       (y_end - ladder->y_pos) * cos(roll_value);
464
465           if( i >= 0 )
466             {
467             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
468             }
469           else
470             {
471             glEnable(GL_LINE_STIPPLE);
472             glLineStipple( 1, 0x00FF );
473             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
474             glDisable(GL_LINE_STIPPLE);
475             }
476           textString( new_x_ini - 8 * strlen(TextLadder) - 8,
477                       new_y_ini - 4,
478                       TextLadder, GLUT_BITMAP_8_BY_13 );
479
480           x_ini = ladder->x_pos + ladder->scr_width/2 - ladder->scr_hole/2;
481           y_ini = marker_y;
482           if( i != 0 )
483             x_end = ladder->x_pos + ladder->scr_width/2;
484           else
485             x_end = ladder->x_pos + ladder->scr_width/2 + 10;
486           y_end = marker_y;
487           new_x_ini = ladder->x_pos +                        \
488                       (x_ini-ladder->x_pos)*cos(roll_value) -\
489                       (y_ini-ladder->y_pos)*sin(roll_value);
490           new_y_ini = ladder->y_pos +                        \
491                       (x_ini-ladder->x_pos)*sin(roll_value) +\
492                       (y_ini-ladder->y_pos)*cos(roll_value);
493           new_x_end = ladder->x_pos +                        \
494                       (x_end-ladder->x_pos)*cos(roll_value) -\
495                                          (y_end-ladder->y_pos)*sin(roll_value);
496           new_y_end = ladder->y_pos +                        \
497                       (x_end-ladder->x_pos)*sin(roll_value) +\
498                       (y_end-ladder->y_pos)*cos(roll_value);
499
500           if( i >= 0 )
501             {
502             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
503             }
504           else
505             {
506             glEnable(GL_LINE_STIPPLE);
507             glLineStipple( 1, 0x00FF );
508             drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
509             glDisable(GL_LINE_STIPPLE);
510             }
511           textString( new_x_end+10, new_y_end-4,
512                       TextLadder, GLUT_BITMAP_8_BY_13 );
513           }
514         }
515             /* if( i%pscale->div_max==0 )
516             {
517                 drawOneLine( marker_x, marker_y, marker_x+6, marker_y );
518                 sprintf( TextScale, "%d", i );
519                 if( pscale->orientation == LEFT )
520                 {
521                         textString( marker_x-8*strlen(TextScale)-2, marker_y-4,
522                               TextScale, GLUT_BITMAP_8_BY_13 );
523                 }
524                 else if( pscale->orientation == RIGHT )
525                 {
526                         textString( marker_x+10, marker_y-4,
527                               TextScale, GLUT_BITMAP_8_BY_13 );
528                 }
529             } */
530         }
531     }
532
533 }
534
535 //
536 //      Draws an artificial horizon line in the center of the HUD
537 //      (with or without a center hole)
538 //
539 //      Needs: x_center, y_center, length, hole
540 //
541
542 static void drawhorizon( HUD_horizon *horizon )
543 {
544   int x_inc1, y_inc1;
545   int x_inc2, y_inc2;
546 //      struct fgFLIGHT *f = &current_aircraft.flight;
547   double sin_bank, cos_bank;
548   double bank_angle;
549
550   bank_angle = (*horizon->load_value)();
551
552         // sin_bank = sin( FG_2PI-FG_Phi );
553         // cos_bank = cos( FG_2PI-FG_Phi );
554   sin_bank = sin(FG_2PI-bank_angle);
555   cos_bank = cos(FG_2PI-bank_angle);
556   x_inc1 = (int)(horizon->scr_width * cos_bank);
557   y_inc1 = (int)(horizon->scr_width * sin_bank);
558   x_inc2 = (int)(horizon->scr_hole  * cos_bank);
559   y_inc2 = (int)(horizon->scr_hole  * sin_bank);
560
561   if( horizon->scr_hole == 0 )
562     {
563     drawOneLine( horizon->x_pos - x_inc1, horizon->y_pos - y_inc1, \
564                  horizon->x_pos + x_inc1, horizon->y_pos + y_inc1 );
565     }
566   else
567     {
568     drawOneLine( horizon->x_pos - x_inc1, horizon->y_pos - y_inc1, \
569                  horizon->x_pos - x_inc2, horizon->y_pos - y_inc2 );
570     drawOneLine( horizon->x_pos + x_inc2, horizon->y_pos + y_inc2, \
571                  horizon->x_pos + x_inc1, horizon->y_pos + y_inc1 );
572     }
573 }
574 /*
575
576         Draws a representation of the control surfaces in their current state
577                 anywhere in the HUD
578         
579         Needs: struct HUD_control_surfaces
580
581 */
582 static void drawControlSurfaces( HUD_control_surfaces *ctrl_surf )
583 {
584         int x_ini, y_ini;
585         int x_end, y_end;
586         /* int x_1, y_1; */
587         /* int x_2, y_2; */
588         fgCONTROLS *c;
589
590         x_ini = ctrl_surf->x_pos;
591         y_ini = ctrl_surf->y_pos;
592         x_end = x_ini + 150;
593         y_end = y_ini + 60;
594
595         drawOneLine( x_ini, y_ini, x_end, y_ini );
596         drawOneLine( x_ini, y_ini, x_ini, y_end );
597         drawOneLine( x_ini, y_end, x_end, y_end );
598         drawOneLine( x_end, y_end, x_end, y_ini );
599         drawOneLine( x_ini + 30, y_ini, x_ini + 30, y_end );
600         drawOneLine( x_ini + 30, y_ini + 30, x_ini + 90, y_ini + 30 );
601         drawOneLine( x_ini + 90, y_ini, x_ini + 90, y_end );
602         drawOneLine( x_ini + 120, y_ini, x_ini + 120, y_end );
603
604         c = current_aircraft.controls;
605
606         /* Draw elevator diagram */
607         textString( x_ini + 1, y_end-11, "E", GLUT_BITMAP_8_BY_13 );
608         drawOneLine( x_ini + 15, y_ini + 5, x_ini + 15, y_ini + 55 );
609         drawOneLine( x_ini + 14, y_ini + 30, x_ini + 16, y_ini + 30 );
610         if( FG_Elevator <= -0.01 || FG_Elevator >= 0.01 )
611         {
612                 drawOneLine( x_ini + 10, y_ini + 5 + (int)(((FG_Elevator + 1.0)/2)*50.0), \
613                                 x_ini + 20, y_ini + 5 + (int)(((FG_Elevator + 1.0)/2)*50.0) );
614         }
615         else
616         {
617                 drawOneLine( x_ini + 7, y_ini + 5 + (int)(((FG_Elevator + 1.0)/2)*50.0), \
618                                 x_ini + 23, y_ini + 5 + (int)(((FG_Elevator + 1.0)/2)*50.0) );
619         }
620
621         /* Draw aileron diagram */
622         textString( x_ini + 30 + 1, y_end-11, "A", GLUT_BITMAP_8_BY_13 );
623         drawOneLine( x_ini + 35, y_end-15, x_ini + 85, y_end-15 );
624         drawOneLine( x_ini + 60, y_end-14, x_ini + 60, y_end-16 );
625         if( FG_Aileron <= -0.01 || FG_Aileron >= 0.01 )
626         {
627                 drawOneLine( x_ini + 35 + (int)(((FG_Aileron + 1.0)/2)*50.0), y_end-20, \
628                                 x_ini + 35 + (int)(((FG_Aileron + 1.0)/2)*50.0), y_end-10 );
629         }
630         else
631         {
632                 drawOneLine( x_ini + 35 + (int)(((FG_Aileron + 1.0)/2)*50.0), y_end-25, \
633                                 x_ini + 35 + (int)(((FG_Aileron + 1.0)/2)*50.0), y_end-5 );
634         }
635
636         /* Draw rudder diagram */
637         textString( x_ini + 30 + 1, y_ini + 21, "R", GLUT_BITMAP_8_BY_13 );
638         drawOneLine( x_ini + 35, y_ini + 15, x_ini + 85, y_ini + 15 );
639         drawOneLine( x_ini + 60, y_ini + 14, x_ini + 60, y_ini + 16 );
640         if( FG_Rudder <= -0.01 || FG_Rudder >= 0.01 )
641         {
642                 drawOneLine( x_ini + 35 + (int)(((FG_Rudder + 1.0)/2)*50.0), y_ini + 20, \
643                                 x_ini + 35 + (int)(((FG_Rudder + 1.0)/2)*50.0), y_ini + 10 );
644         }
645         else
646         {
647                 drawOneLine( x_ini + 35 + (int)(((FG_Rudder + 1.0)/2)*50.0), y_ini + 25, \
648                                 x_ini + 35 + (int)(((FG_Rudder + 1.0)/2)*50.0), y_ini + 5 );
649         }
650         
651         
652         /* Draw throttle diagram */
653         textString( x_ini + 90 + 1, y_end-11, "T", GLUT_BITMAP_8_BY_13 );       
654         textString( x_ini + 90 + 1, y_end-21, "r", GLUT_BITMAP_8_BY_13 );       
655         drawOneLine( x_ini + 105, y_ini + 5, x_ini + 105, y_ini + 55 );
656         drawOneLine( x_ini + 100, y_ini + 5 + (int)(FG_Throttle[0]*50.0), \
657                         x_ini + 110, y_ini + 5 + (int)(FG_Throttle[0]*50.0) );
658         
659         
660         /* Draw elevator trim diagram */
661         textString( x_ini + 121, y_end-11, "T", GLUT_BITMAP_8_BY_13 );  
662         textString( x_ini + 121, y_end-22, "m", GLUT_BITMAP_8_BY_13 );  
663         drawOneLine( x_ini + 135, y_ini + 5, x_ini + 135, y_ini + 55 );
664         drawOneLine( x_ini + 134, y_ini + 30, x_ini + 136, y_ini + 30 );
665         if( FG_Elev_Trim <= -0.01 || FG_Elev_Trim >= 0.01 )
666         {
667                 drawOneLine( x_ini + 130, y_ini + 5 + (int)(((FG_Elev_Trim + 1)/2)*50.0), \
668                                 x_ini + 140, y_ini + 5 + (int)(((FG_Elev_Trim + 1.0)/2)*50.0) );
669         }
670         else
671         {
672                 drawOneLine( x_ini + 127, y_ini + 5 + (int)(((FG_Elev_Trim + 1.0)/2)*50.0), \
673                                 x_ini + 143, y_ini + 5 + (int)(((FG_Elev_Trim + 1.0)/2)*50.0) );
674         }
675         
676 }
677
678 //
679 // Draws a label anywhere in the HUD
680 //
681 //
682
683 static void drawlabel( HUD_label *label )
684 {
685   char buffer[80];
686   char string[80];
687   int posincr;
688   int lenstr;
689
690   if( !label ) { // Eliminate the possible, but absurd case.
691     return;
692     }
693
694   if( label->pre_str != NULL) {
695     if( label->post_str != NULL ) {
696       sprintf( buffer, "%s%s%s", label->pre_str,  \
697                                  label->format,   \
698                                  label->post_str );
699       }
700     else {
701       sprintf( buffer, "%s%s",   label->pre_str, \
702                                  label->format );
703       }
704     }
705   else {
706     if( label->post_str != NULL ) {
707       sprintf( buffer, "%s%s",   label->format,  \
708                                  label->post_str );
709       }
710     } // else do nothing if both pre and post strings are nulls. Interesting.
711
712
713   sprintf( string, buffer, (*label->load_value)() );
714
715         fgPrintf( FG_COCKPIT, FG_DEBUG,  buffer );
716         fgPrintf( FG_COCKPIT, FG_DEBUG,  "\n" );
717         fgPrintf( FG_COCKPIT, FG_DEBUG, string );
718         fgPrintf( FG_COCKPIT, FG_DEBUG, "\n" );
719
720   lenstr = strlen( string );
721   if( label->justify == LEFT_JUST ) {
722    posincr = -lenstr*8;
723    }
724   else {
725     if( label->justify == CENTER_JUST ) {
726       posincr = -lenstr*4;
727       }
728     else {
729       if( label->justify == RIGHT_JUST ) {
730         posincr = 0;
731         }
732       }
733     }
734
735   if( label->size == SMALL ) {
736     textString( label->x_pos + posincr, label->y_pos,
737                 string, GLUT_BITMAP_8_BY_13);
738     }
739   else  {
740     if( label->size == LARGE ) {
741       textString( label->x_pos + posincr, label->y_pos,
742                   string, GLUT_BITMAP_9_BY_15);
743       }
744     }
745 }
746 // The following routines concern HUD object/component object construction
747 //
748
749 // fgHUDInit
750 //
751 // Constructs a HUD object and then adds in instruments. At the present
752 // the instruments are hard coded into the routine. Ultimately these need
753 // to be defined by the aircraft's instrumentation records so that the
754 // display for a Piper Cub doesn't show the speed range of a North American
755 // mustange and the engine readouts of a B36!
756 //
757 Hptr fgHUDInit( fgAIRCRAFT *current_aircraft )
758 {
759   Hptr hud;
760
761   hud = (Hptr)calloc(sizeof( HUD),1);
762   if( hud == NULL )
763     return( NULL );
764
765   hud->code = 1;
766   hud->status = 0;
767
768   // For now lets just hardcode the hud here .
769   // In the future, hud information has to come from the same place
770   // aircraft information came from.
771
772   fgHUDAddHorizon( hud, 590, 50, 40, 20, get_roll );
773   fgHUDAddScale  ( hud, VERTICAL, NOLIMIT, 220, 100, 280, 5, 10,
774                    LEFT, LEFT, 0, 100, get_speed );
775   fgHUDAddScale  ( hud, VERTICAL, NOLIMIT, 440, 100, 280, 1, 5,
776                    RIGHT, RIGHT, -400, 25, get_aoa );
777   fgHUDAddScale  ( hud, HORIZONTAL, NOLIMIT, 280, 220, 440, 5, 10,
778                    TOP, TOP, 0, 50, get_heading );
779   fgHUDAddLabel  ( hud, 180, 85, SMALL, NOBLINK,
780                    RIGHT_JUST, NULL, " Kts", "%5.0f", get_speed );
781   fgHUDAddLabel  ( hud, 180, 73, SMALL, NOBLINK,
782                    RIGHT_JUST, NULL, " m", "%5.0f", get_altitude );
783   fgHUDAddLadder ( hud, 330, 190, 90, 180, 70, 10,
784                    NONE, 45, get_roll, get_pitch );
785   // fgHUDAddControlSurfaces( hud, 10, 10, get_heading );
786
787   return( hud );
788 }
789
790 // add_instrument
791 //
792 // This is a stand in for linked list code that will get replaced later
793 // by some more elegant list handling code.
794
795 void add_instrument( Hptr hud, HIptr pinstrument )
796 {
797   if( !hud || !pinstrument ) {
798     return;
799     }
800   pinstrument->next = hud->instruments;
801   hud->instruments = pinstrument;
802 }
803
804 // fgHUDAddHorizon
805 //
806 // Constructs a HUD_horizon "object" and installs it into the hud instrument
807 // list.
808
809 Hptr fgHUDAddHorizon( Hptr hud,     \
810                       int x_pos,    \
811                       int y_pos,    \
812                       int length,   \
813                       int hole_len, \
814                       double (*load_value)() )
815 {
816   HUD_horizon *phorizon;
817   HUD_instr   *pinstrument;
818
819   if( !hud ) {
820     return NULL;
821     }
822                                        // construct the parent object
823         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
824         if( pinstrument == NULL ) {
825                 return( NULL );
826     }
827         pinstrument->type    = HUDhorizon;  //  ARTIFICIAL_HORIZON;
828
829                                       // Construct the horizon
830         phorizon = (HUD_horizon *) calloc( sizeof(HUD_horizon),1);
831         if( phorizon == NULL )   {
832                 return( NULL );
833     }
834
835   phorizon->x_pos      = x_pos;
836   phorizon->y_pos      = y_pos;
837   phorizon->scr_width  = length;
838   phorizon->scr_hole   = hole_len;
839   phorizon->load_value = load_value;
840                                       //  Install the horizon in the parent.
841   pinstrument->instr   = phorizon;
842                                       //  Install the instrument into hud.
843   add_instrument( hud, pinstrument);
844
845   return( hud );
846 }
847
848 // fgHUDAddScale
849 //
850 // Constructs a HUD_scale "object" and installs it into the hud instrument
851 // list.
852
853 Hptr fgHUDAddScale( Hptr hud,        \
854                     int type,        \
855                     int sub_type,    \
856                     int scr_pos,     \
857                     int scr_min,     \
858                     int scr_max,     \
859                     int div_min,     \
860                     int div_max,     \
861                     int orientation, \
862                     int with_min,    \
863                     int min_value,   \
864                     int width_units, \
865                     double (*load_value)() )
866 {
867   HUD_scale *pscale;
868   HUD_instr *pinstrument;
869
870   if( !hud ) {
871     return NULL;
872     }
873
874         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
875         if( pinstrument == NULL ) {
876      return( NULL );
877      }
878
879   pinstrument->type = SCALE;
880
881   pscale = ( HUD_scale *)calloc(sizeof(HUD_scale),1);
882   if( pscale == NULL )   {
883      return( NULL );
884     }
885   pscale->type          = type;
886   pscale->type          = sub_type;
887   pscale->scr_pos       = scr_pos;
888   pscale->scr_min       = scr_min;
889   pscale->scr_max       = scr_max;
890   pscale->div_min       = div_min;
891   pscale->div_max       = div_max;
892   pscale->orientation   = orientation;
893   pscale->with_minimum  = with_min;
894   pscale->minimum_value = min_value;
895   pscale->width_units   = width_units;
896   pscale->load_value    = load_value;
897                                      // Install the scale
898   pinstrument->instr = pscale;
899                                       //  Install the instrument into hud.
900   add_instrument( hud, pinstrument);
901
902   return( hud );
903 }
904
905 // fgHUDAddLabel
906 //
907 // Constructs a HUD_Label object and installs it into the hud instrument
908 // list.
909 Hptr fgHUDAddLabel( Hptr hud,       \
910                     int x_pos,      \
911                     int y_pos,      \
912                     int size,       \
913                     int blink,      \
914                     int justify,    \
915                                                   char *pre_str,  \
916                     char *post_str, \
917                     char *format,   \
918                     double (*load_value)() )
919 {
920         HUD_label *plabel;
921         HUD_instr *pinstrument;
922
923   if( !hud ) {
924     return NULL;
925     }
926
927         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
928         if( pinstrument == NULL ) {
929     return NULL;
930     }
931         pinstrument->type = LABEL;
932
933         plabel = (HUD_label *)calloc(sizeof(HUD_label),1);
934         if( plabel == NULL ){
935     return NULL;
936     }
937
938   plabel->x_pos      = x_pos;
939   plabel->y_pos      = y_pos;
940   plabel->size       = size;
941   plabel->blink      = blink;
942   plabel->justify    = justify;
943   plabel->pre_str    = pre_str;
944   plabel->post_str   = post_str;
945   plabel->format     = format;
946   plabel->load_value = load_value;
947                                       // Install the label
948         pinstrument->instr = plabel;
949                                       //  Install the instrument into hud.
950   add_instrument( hud, pinstrument);
951
952         return( hud );
953 }
954
955 // fgHUDAddLadder
956 //
957 // Contains code that constructs a ladder "object" and installs it as
958 // a hud instrument in the hud instrument list.
959 //
960 Hptr fgHUDAddLadder( Hptr hud,        \
961                      int x_pos,       \
962                      int y_pos,       \
963                      int scr_width,   \
964                      int scr_height,  \
965                                                    int hole_len,    \
966                      int div_units,   \
967                      int label_pos,   \
968                      int width_units, \
969                                                    double (*load_roll)(),
970                      double (*load_pitch)() )
971 {
972         HUD_ladder *pladder;
973         HUD_instr  *pinstrument;
974
975   if( !hud ) {
976     return NULL;
977     }
978
979         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
980         if( pinstrument == NULL )
981                 return( NULL );
982
983         pinstrument->type = LADDER;
984
985         pladder = (HUD_ladder *)calloc(sizeof(HUD_ladder),1);
986         if( pladder == NULL )
987                 return( NULL );
988
989   pladder->type           = 0; // Not used.
990   pladder->x_pos          = x_pos;
991   pladder->y_pos          = y_pos;
992   pladder->scr_width      = scr_width;
993   pladder->scr_height     = scr_height;
994   pladder->scr_hole       = hole_len;
995   pladder->div_units      = div_units;
996   pladder->label_position = label_pos;
997   pladder->width_units    = width_units;
998   pladder->load_roll      = load_roll;
999   pladder->load_pitch     = load_pitch;
1000
1001   pinstrument->instr      = pladder;
1002                                       //  Install the instrument into hud.
1003   add_instrument( hud, pinstrument);
1004         return hud;
1005 }
1006
1007 /*
1008 Hptr fgHUDAddMovingHorizon(  Hptr hud,     \
1009                              int x_pos,    \
1010                              int y_pos,    \
1011                              int length,   \
1012                              int hole_len, \
1013                              int color )
1014 {
1015
1016 }
1017
1018 Hptr fgHUDAddCircularLadder( Hptr hud,    \
1019                              int scr_min, \
1020                              int scr_max, \
1021                              int div_min, \
1022                              int div_max, \
1023                              int max_value )
1024 {
1025
1026 }
1027
1028 Hptr fgHUDAddNumDisp( Hptr hud,           \
1029                       int x_pos,          \
1030                       int y_pos,          \
1031                       int size,           \
1032                       int color,          \
1033                       int blink,          \
1034                                                           char *pre_str,      \
1035                       char *post_str )
1036 {
1037
1038 }
1039 */
1040
1041 // fgUpdateHUD
1042 //
1043 // Performs a once around the list of calls to instruments installed in
1044 // the HUD object with requests for redraw. Kinda. It will when this is
1045 // all C++.
1046 //
1047
1048 void fgUpdateHUD( Hptr hud )
1049 {
1050         HIptr phud_instr;
1051
1052         glMatrixMode(GL_PROJECTION);
1053         glPushMatrix();
1054
1055         glLoadIdentity();
1056         gluOrtho2D(0, 640, 0, 480);
1057         glMatrixMode(GL_MODELVIEW);
1058         glPushMatrix();
1059         glLoadIdentity();
1060
1061         glColor3f(1.0, 1.0, 1.0);
1062         glIndexi(7);
1063
1064         glDisable(GL_DEPTH_TEST);
1065         glDisable(GL_LIGHTING);
1066
1067         glLineWidth(1);
1068         glColor3f (0.1, 0.9, 0.1);
1069
1070   fgPrintf( FG_COCKPIT, FG_DEBUG,
1071             "HUD Code %d  Status %d\n",
1072             hud->code, hud->status );
1073
1074   phud_instr = hud->instruments;
1075   while( phud_instr )   {
1076     switch (phud_instr->type){
1077                   case HUDhorizon:                  // ARTIFICIAL HORIZON
1078         drawhorizon( (pHUDhorizon)phud_instr );
1079           break;
1080
1081         case HUDscale:                  // Need to simplify this call.
1082         drawscale (  (pHUDscale)  phud_instr  );
1083         break;
1084
1085       case HUDlabel:
1086         drawlabel (  (pHUDlabel)  phud_instr  );
1087         break;
1088
1089         case HUDladder:
1090                 drawladder(  (pHUDladder) phud_instr  );
1091         break;
1092
1093       case HUDcontrols:
1094         drawControlSurfaces( (pHUDControlSurface) phud_instr );
1095       default:; // Ignore anything you don't know about.
1096       }
1097         phud_instr = phud_instr->next;
1098     }
1099
1100         glEnable(GL_DEPTH_TEST);
1101         glEnable(GL_LIGHTING);
1102         glMatrixMode(GL_PROJECTION);
1103         glPopMatrix();
1104         glMatrixMode(GL_MODELVIEW);
1105         glPopMatrix();
1106
1107 }
1108
1109
1110 /* $Log$
1111 /* Revision 1.11  1998/02/07 15:29:34  curt
1112 /* Incorporated HUD changes and struct/typedef changes from Charlie Hotchkiss
1113 /* <chotchkiss@namg.us.anritsu.com>
1114 /*
1115  * Revision 1.10  1998/02/03 23:20:14  curt
1116  * Lots of little tweaks to fix various consistency problems discovered by
1117  * Solaris' CC.  Fixed a bug in fg_debug.c with how the fgPrintf() wrapper
1118  * passed arguments along to the real printf().  Also incorporated HUD changes
1119  * by Michele America.
1120  *
1121  * Revision 1.9  1998/01/31 00:43:04  curt
1122  * Added MetroWorks patches from Carmen Volpe.
1123  *
1124  * Revision 1.8  1998/01/27 00:47:51  curt
1125  * Incorporated Paul Bleisch's <bleisch@chromatic.com> new debug message
1126  * system and commandline/config file processing code.
1127  *
1128  * Revision 1.7  1998/01/19 18:40:20  curt
1129  * Tons of little changes to clean up the code and to remove fatal errors
1130  * when building with the c++ compiler.
1131  *
1132  * Revision 1.6  1997/12/15 23:54:34  curt
1133  * Add xgl wrappers for debugging.
1134  * Generate terrain normals on the fly.
1135  *
1136  * Revision 1.5  1997/12/10 22:37:39  curt
1137  * Prepended "fg" on the name of all global structures that didn't have it yet.
1138  * i.e. "struct WEATHER {}" became "struct fgWEATHER {}"
1139  *
1140  * Revision 1.4  1997/09/23 00:29:32  curt
1141  * Tweaks to get things to compile with gcc-win32.
1142  *
1143  * Revision 1.3  1997/09/05 14:17:26  curt
1144  * More tweaking with stars.
1145  *
1146  * Revision 1.2  1997/09/04 02:17:30  curt
1147  * Shufflin' stuff.
1148  *
1149  * Revision 1.1  1997/08/29 18:03:22  curt
1150  * Initial revision.
1151  *
1152  */