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