]> git.mxchange.org Git - flightgear.git/blob - Cockpit/hud.c
f0dc7e7f13d5a5204ec2d6fc14573d9d98ff7ba8
[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->width_units / 2;
165   vmax = cur_value + pscale->width_units / 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->width_units;
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->width_units;
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   fgPrintf( FG_COCKPIT, FG_INFO, "Initializing HUD\n" );
762
763   hud = (Hptr)calloc(sizeof( HUD),1);
764   if( hud == NULL )
765     return( NULL );
766
767   hud->code = 1;
768   hud->status = 0;
769
770   // For now lets just hardcode the hud here .
771   // In the future, hud information has to come from the same place
772   // aircraft information came from.
773
774   fgHUDAddHorizon( hud, 590, 50, 40, 20, get_roll );
775   fgHUDAddScale  ( hud, VERTICAL, LIMIT, 220, 100, 280, 5, 10,
776                    LEFT, LEFT, 0, 100, 50, get_speed );
777   fgHUDAddScale  ( hud, VERTICAL, NOLIMIT, 440, 100, 280, 1, 5,
778                    RIGHT, RIGHT, -400, 50, 25, get_aoa );
779   fgHUDAddScale  ( hud, HORIZONTAL, NOLIMIT, 280, 220, 440, 5, 10,
780                    TOP, TOP, 0, 50, 50, get_heading );
781   fgHUDAddLabel  ( hud, 180, 85, SMALL, NOBLINK,
782                    RIGHT_JUST, NULL, " Kts", "%5.0f", get_speed );
783   fgHUDAddLabel  ( hud, 180, 73, SMALL, NOBLINK,
784                    RIGHT_JUST, NULL, " m", "%5.0f", get_altitude );
785   fgHUDAddLadder ( hud, 330, 190, 90, 180, 70, 10,
786                    NONE, 45, get_roll, get_pitch );
787   // fgHUDAddControlSurfaces( hud, 10, 10, get_heading );
788
789   return( hud );
790 }
791
792
793 // add_instrument
794 //
795 // This is a stand in for linked list code that will get replaced later
796 // by some more elegant list handling code.
797
798 void add_instrument( Hptr hud, HIptr pinstrument )
799 {
800     if( !hud || !pinstrument ) {
801         return;
802     }
803
804     pinstrument->next = hud->instruments;
805     hud->instruments = pinstrument;
806 }
807
808
809 // fgHUDAddHorizon
810 //
811 // Constructs a HUD_horizon "object" and installs it into the hud instrument
812 // list.
813
814 Hptr fgHUDAddHorizon( Hptr hud,     \
815                       int x_pos,    \
816                       int y_pos,    \
817                       int length,   \
818                       int hole_len, \
819                       double (*load_value)() )
820 {
821     HUD_horizon *phorizon;
822     HUD_instr   *pinstrument;
823
824     if( !hud ) {
825         return NULL;
826     }
827                                        // construct the parent object
828     pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
829     if( pinstrument == NULL ) {
830         return( NULL );
831     }
832     pinstrument->type    = HUDhorizon;  //  ARTIFICIAL_HORIZON;
833
834                                       // Construct the horizon
835     phorizon = (HUD_horizon *) calloc( sizeof(HUD_horizon),1);
836     if( phorizon == NULL )   {
837         return( NULL );
838     }
839
840     phorizon->x_pos      = x_pos;
841     phorizon->y_pos      = y_pos;
842     phorizon->scr_width  = length;
843     phorizon->scr_hole   = hole_len;
844     phorizon->load_value = load_value;
845     //  Install the horizon in the parent.
846     pinstrument->instr   = phorizon;
847     //  Install the instrument into hud.
848     add_instrument( hud, pinstrument);
849
850     return( hud );
851 }
852
853 // fgHUDAddScale
854 //
855 // Constructs a HUD_scale "object" and installs it into the hud instrument
856 // list.
857
858 Hptr fgHUDAddScale( Hptr hud,        \
859                     int type,        \
860                     int sub_type,    \
861                     int scr_pos,     \
862                     int scr_min,     \
863                     int scr_max,     \
864                     int div_min,     \
865                     int div_max,     \
866                     int orientation, \
867                     int with_min,    \
868                     int min_value,   \
869                     int max_value,   \
870                     int width_units, \
871                     double (*load_value)() )
872 {
873   HUD_scale *pscale;
874   HUD_instr *pinstrument;
875
876   if( !hud ) {
877     return NULL;
878     }
879
880         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
881         if( pinstrument == NULL ) {
882      return( NULL );
883      }
884
885   pinstrument->type = HUDscale;
886
887   pscale = ( HUD_scale *)calloc(sizeof(HUD_scale),1);
888   if( pscale == NULL )   {
889      return( NULL );
890     }
891   pscale->type          = type;
892   pscale->sub_type      = sub_type;
893   pscale->scr_pos       = scr_pos;
894   pscale->scr_min       = scr_min;
895   pscale->scr_max       = scr_max;
896   pscale->div_min       = div_min;
897   pscale->div_max       = div_max;
898   pscale->orientation   = orientation;
899   pscale->with_minimum  = with_min;
900   pscale->minimum_value = min_value;
901   pscale->maximum_value = max_value;
902   pscale->width_units   = width_units;
903   pscale->load_value    = load_value;
904                                      // Install the scale
905   pinstrument->instr = pscale;
906                                       //  Install the instrument into hud.
907   add_instrument( hud, pinstrument);
908
909   return( hud );
910 }
911
912 // fgHUDAddLabel
913 //
914 // Constructs a HUD_Label object and installs it into the hud instrument
915 // list.
916 Hptr fgHUDAddLabel( Hptr hud,       \
917                     int x_pos,      \
918                     int y_pos,      \
919                     int size,       \
920                     int blink,      \
921                     int justify,    \
922                                                   char *pre_str,  \
923                     char *post_str, \
924                     char *format,   \
925                     double (*load_value)() )
926 {
927         HUD_label *plabel;
928         HUD_instr *pinstrument;
929
930   if( !hud ) {
931     return NULL;
932     }
933
934         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
935         if( pinstrument == NULL ) {
936     return NULL;
937     }
938         pinstrument->type = HUDlabel;
939
940         plabel = (HUD_label *)calloc(sizeof(HUD_label),1);
941         if( plabel == NULL ){
942     return NULL;
943     }
944
945   plabel->x_pos      = x_pos;
946   plabel->y_pos      = y_pos;
947   plabel->size       = size;
948   plabel->blink      = blink;
949   plabel->justify    = justify;
950   plabel->pre_str    = pre_str;
951   plabel->post_str   = post_str;
952   plabel->format     = format;
953   plabel->load_value = load_value;
954                                       // Install the label
955         pinstrument->instr = plabel;
956                                       //  Install the instrument into hud.
957   add_instrument( hud, pinstrument);
958
959         return( hud );
960 }
961
962 // fgHUDAddLadder
963 //
964 // Contains code that constructs a ladder "object" and installs it as
965 // a hud instrument in the hud instrument list.
966 //
967 Hptr fgHUDAddLadder( Hptr hud,        \
968                      int x_pos,       \
969                      int y_pos,       \
970                      int scr_width,   \
971                      int scr_height,  \
972                                                    int hole_len,    \
973                      int div_units,   \
974                      int label_pos,   \
975                      int width_units, \
976                                                    double (*load_roll)(),
977                      double (*load_pitch)() )
978 {
979         HUD_ladder *pladder;
980         HUD_instr  *pinstrument;
981
982   if( !hud ) {
983     return NULL;
984     }
985
986         pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
987         if( pinstrument == NULL )
988                 return( NULL );
989
990         pinstrument->type = HUDladder;
991
992         pladder = (HUD_ladder *)calloc(sizeof(HUD_ladder),1);
993         if( pladder == NULL )
994                 return( NULL );
995
996   pladder->type           = 0; // Not used.
997   pladder->x_pos          = x_pos;
998   pladder->y_pos          = y_pos;
999   pladder->scr_width      = scr_width;
1000   pladder->scr_height     = scr_height;
1001   pladder->scr_hole       = hole_len;
1002   pladder->div_units      = div_units;
1003   pladder->label_position = label_pos;
1004   pladder->width_units    = width_units;
1005   pladder->load_roll      = load_roll;
1006   pladder->load_pitch     = load_pitch;
1007
1008   pinstrument->instr      = pladder;
1009                                       //  Install the instrument into hud.
1010   add_instrument( hud, pinstrument);
1011         return hud;
1012 }
1013
1014 /*
1015 Hptr fgHUDAddMovingHorizon(  Hptr hud,     \
1016                              int x_pos,    \
1017                              int y_pos,    \
1018                              int length,   \
1019                              int hole_len, \
1020                              int color )
1021 {
1022
1023 }
1024
1025 Hptr fgHUDAddCircularLadder( Hptr hud,    \
1026                              int scr_min, \
1027                              int scr_max, \
1028                              int div_min, \
1029                              int div_max, \
1030                              int max_value )
1031 {
1032
1033 }
1034
1035 Hptr fgHUDAddNumDisp( Hptr hud,           \
1036                       int x_pos,          \
1037                       int y_pos,          \
1038                       int size,           \
1039                       int color,          \
1040                       int blink,          \
1041                                                           char *pre_str,      \
1042                       char *post_str )
1043 {
1044
1045 }
1046 */
1047
1048 // fgUpdateHUD
1049 //
1050 // Performs a once around the list of calls to instruments installed in
1051 // the HUD object with requests for redraw. Kinda. It will when this is
1052 // all C++.
1053 //
1054
1055 void fgUpdateHUD( Hptr hud ) {
1056     HIptr phud_instr;
1057
1058     glMatrixMode(GL_PROJECTION);
1059     glPushMatrix();
1060
1061     glLoadIdentity();
1062     gluOrtho2D(0, 640, 0, 480);
1063     glMatrixMode(GL_MODELVIEW);
1064     glPushMatrix();
1065     glLoadIdentity();
1066
1067     glColor3f(1.0, 1.0, 1.0);
1068     glIndexi(7);
1069
1070     glDisable(GL_DEPTH_TEST);
1071     glDisable(GL_LIGHTING);
1072
1073     glLineWidth(1);
1074     glColor3f (0.1, 0.9, 0.1);
1075
1076     fgPrintf( FG_COCKPIT, FG_DEBUG,
1077               "HUD Code %d  Status %d\n",
1078               hud->code, hud->status );
1079
1080     phud_instr = hud->instruments;
1081     while( phud_instr ) {
1082         /* printf("Drawing Instrument %d\n", phud_instr->type); */
1083
1084         switch (phud_instr->type) {
1085         case HUDhorizon:   // ARTIFICIAL HORIZON
1086             drawhorizon( (pHUDhorizon)phud_instr->instr );
1087             break;
1088             
1089         case HUDscale:     // Need to simplify this call.
1090             drawscale (  (pHUDscale)  phud_instr->instr  );
1091             break;
1092
1093         case HUDlabel:
1094             drawlabel (  (pHUDlabel)  phud_instr->instr  );
1095             break;
1096
1097         case HUDladder:
1098             drawladder(  (pHUDladder) phud_instr->instr  );
1099             break;
1100
1101         case HUDcontrols:
1102             drawControlSurfaces( (pHUDControlSurface) phud_instr->instr );
1103             
1104         default:; // Ignore anything you don't know about.
1105         }
1106
1107         phud_instr = phud_instr->next;
1108     }
1109
1110     glEnable(GL_DEPTH_TEST);
1111     glEnable(GL_LIGHTING);
1112     glMatrixMode(GL_PROJECTION);
1113     glPopMatrix();
1114     glMatrixMode(GL_MODELVIEW);
1115     glPopMatrix();
1116 }
1117
1118
1119 /* $Log$
1120 /* Revision 1.13  1998/02/11 02:50:19  curt
1121 /* Added changes submitted by Michele America.
1122 /*
1123  * Revision 1.12  1998/02/09 15:07:48  curt
1124  * Minor tweaks.
1125  *
1126  * Revision 1.11  1998/02/07 15:29:34  curt
1127  * Incorporated HUD changes and struct/typedef changes from Charlie Hotchkiss
1128  * <chotchkiss@namg.us.anritsu.com>
1129  *
1130  * Revision 1.10  1998/02/03 23:20:14  curt
1131  * Lots of little tweaks to fix various consistency problems discovered by
1132  * Solaris' CC.  Fixed a bug in fg_debug.c with how the fgPrintf() wrapper
1133  * passed arguments along to the real printf().  Also incorporated HUD changes
1134  * by Michele America.
1135  *
1136  * Revision 1.9  1998/01/31 00:43:04  curt
1137  * Added MetroWorks patches from Carmen Volpe.
1138  *
1139  * Revision 1.8  1998/01/27 00:47:51  curt
1140  * Incorporated Paul Bleisch's <bleisch@chromatic.com> new debug message
1141  * system and commandline/config file processing code.
1142  *
1143  * Revision 1.7  1998/01/19 18:40:20  curt
1144  * Tons of little changes to clean up the code and to remove fatal errors
1145  * when building with the c++ compiler.
1146  *
1147  * Revision 1.6  1997/12/15 23:54:34  curt
1148  * Add xgl wrappers for debugging.
1149  * Generate terrain normals on the fly.
1150  *
1151  * Revision 1.5  1997/12/10 22:37:39  curt
1152  * Prepended "fg" on the name of all global structures that didn't have it yet.
1153  * i.e. "struct WEATHER {}" became "struct fgWEATHER {}"
1154  *
1155  * Revision 1.4  1997/09/23 00:29:32  curt
1156  * Tweaks to get things to compile with gcc-win32.
1157  *
1158  * Revision 1.3  1997/09/05 14:17:26  curt
1159  * More tweaking with stars.
1160  *
1161  * Revision 1.2  1997/09/04 02:17:30  curt
1162  * Shufflin' stuff.
1163  *
1164  * Revision 1.1  1997/08/29 18:03:22  curt
1165  * Initial revision.
1166  *
1167  */