1 /**************************************************************************
2 * hud.c -- hud defines and prototypes
4 * Written by Michele America, started September 1997.
6 * Copyright (C) 1997 Michele F. America - nomimarketing@mail.telepac.pt
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.
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.
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.
23 * (Log is kept at end of this file)
24 **************************************************************************/
36 # include <values.h> // for MAXINT
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>
53 #define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \
54 glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
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.
62 double get_throttleval( void )
64 fgCONTROLS *pcontrols;
66 pcontrols = current_aircraft.controls;
67 return pcontrols->throttle[0]; // Hack limiting to one engine
70 double get_aileronval( void )
72 fgCONTROLS *pcontrols;
74 pcontrols = current_aircraft.controls;
75 return pcontrols->aileron;
78 double get_elevatorval( void )
80 fgCONTROLS *pcontrols;
82 pcontrols = current_aircraft.controls;
83 return pcontrols->elevator;
86 double get_elev_trimval( void )
88 fgCONTROLS *pcontrols;
90 pcontrols = current_aircraft.controls;
91 return pcontrols->elevator_trim;
94 double get_rudderval( void )
96 fgCONTROLS *pcontrols;
98 pcontrols = current_aircraft.controls;
99 return pcontrols->rudder;
102 double get_speed( void )
106 f = current_aircraft.flight;
107 return( FG_V_equiv_kts ); // Make an explicit function call.
110 double get_aoa( void )
114 f = current_aircraft.flight;
115 return( FG_Gamma_vert_rad * RAD_TO_DEG );
118 double get_roll( void )
122 f = current_aircraft.flight;
126 double get_pitch( void )
130 f = current_aircraft.flight;
134 double get_heading( void )
138 f = current_aircraft.flight;
139 return( FG_Psi*RAD_TO_DEG );
142 double get_altitude( void )
145 // double rough_elev;
147 f = current_aircraft.flight;
148 // rough_elev = mesh_altitude(FG_Longitude * RAD_TO_ARCSEC,
149 // FG_Latitude * RAD_TO_ARCSEC);
151 return( FG_Altitude * FEET_TO_METER /* -rough_elev */ );
154 double get_sideslip( void )
158 f = current_aircraft.flight;
164 // The following code deals with painting the "instrument" on the display
166 /* textString - Bitmap font string */
168 static void textString(int x, int y, char *msg, void *font)
172 glutBitmapCharacter(font, *msg);
177 /* strokeString - Stroke font string */
179 static void strokeString(int x, int y, char *msg, void *font)
182 glTranslatef(x, y, 0);
183 glScalef(.04, .04, .04);
185 glutStrokeCharacter(font, *msg);
194 Draws a measuring scale anywhere on the HUD
197 Needs: HUD_scale struct
200 static void drawscale( HUD_scale * pscale )
211 double cur_value = (*(pscale->load_value))();
213 vmin = cur_value - pscale->width_units / 2.0; // width units == needle travel
214 vmax = cur_value + pscale->width_units / 2.0; // or picture unit span.
216 scr_span = pscale->scr_max - pscale->scr_min; // Run of scan in pix coord
217 scr_span |= 1; // If span is odd number of units, mid will be correct.
218 // If not it will be high by one coordinate unit. This is
219 // an artifact of integer division needed for screen loc's.
221 mid_scr = (scr_span >> 1) + pscale->scr_min; // Middle is half that +
224 // Calculate the number of screen units per indicator unit
225 // We must force floating point calculation or the factor
226 // will be low and miss locate tics by several units.
228 factor = (double)scr_span / (double)pscale->width_units;
230 // Separate calculations for location of markings by scale
233 if( pscale->type == VERTICAL ) // Vertical scale
236 if( pscale->orientation == LEFT ) // Calculate x marker offset
237 marker_x = pscale->scr_pos-6;
239 if( pscale->orientation == RIGHT )
240 marker_x = pscale->scr_pos;
242 // Draw the basic markings for the scale...
244 drawOneLine( pscale->scr_pos, // Vertical bar
248 if( pscale->orientation == LEFT )
250 drawOneLine( pscale->scr_pos-3, // Bottom tick bar
255 drawOneLine( pscale->scr_pos-3, // Top tick bar
260 drawOneLine( pscale->scr_pos, // Middle tick bar /Index
267 if( pscale->orientation == RIGHT )
269 drawOneLine( pscale->scr_pos,
274 drawOneLine( pscale->scr_pos,
279 drawOneLine( pscale->scr_pos,
285 // Work through from bottom to top of scale. Calculating where to put
286 // minor and major ticks.
288 for( i = vmin; i <= vmax; i++ )
290 if( pscale->sub_type == LIMIT ) { // Don't show ticks
291 condition = (i >= pscale->minimum_value); // below Minimum value.
294 if( pscale->sub_type == NOLIMIT ) {
298 if( condition ) // Show a tick if necessary
300 // Calculate the location of this tick
301 marker_y = pscale->scr_min + (i - vmin) * factor;
303 // Block calculation artifact from drawing ticks below min coordinate.
304 // Calculation here accounts for text height.
306 if( marker_y < (pscale->scr_min + 4)) { // Magic number!!!
309 if( (i%pscale->div_min) == 0) {
310 if( pscale->orientation == LEFT )
312 drawOneLine( marker_x + 3, marker_y, marker_x + 6, marker_y );
315 if( pscale->orientation == RIGHT )
317 drawOneLine( marker_x, marker_y, marker_x + 3, marker_y );
321 if( (i%pscale->div_max) == 0 ) {
322 drawOneLine( marker_x, marker_y,
323 marker_x + 6, marker_y );
324 sprintf( TextScale, "%d", i );
325 if( pscale->orientation == LEFT ) {
326 textString( marker_x - 8 * strlen(TextScale) - 2, marker_y - 4,
327 TextScale, GLUT_BITMAP_8_BY_13 );
330 if( pscale->orientation == RIGHT ) {
331 textString( marker_x + 10, marker_y - 4,
332 TextScale, GLUT_BITMAP_8_BY_13 );
336 } // End if condition
337 } // End for range of i from vmin to vmax
338 } // End if VERTICAL SCALE TYPE
339 if( pscale->type == HORIZONTAL ) // Horizontal scale
341 if( pscale->orientation == TOP ) {
342 marker_y = pscale->scr_pos;
345 if( pscale->orientation == BOTTOM ) {
346 marker_y = pscale->scr_pos - 6;
349 drawOneLine( pscale->scr_min,
353 if( pscale->orientation == TOP )
355 drawOneLine( pscale->scr_min,
360 drawOneLine( pscale->scr_max,
365 drawOneLine( mid_scr,
372 if( pscale->orientation == BOTTOM )
374 drawOneLine( pscale->scr_min,
379 drawOneLine( pscale->scr_max,
384 drawOneLine( mid_scr,
391 for( i = vmin; i <= vmax; i++ ) // increment is faster than addition
393 if( pscale->sub_type == LIMIT ) {
394 condition = (i >= pscale->minimum_value);
397 if( pscale->sub_type == NOLIMIT ) {
402 marker_x = pscale->scr_min+(i-vmin)*factor;
403 if( i%pscale->div_min==0 ) {
404 if( pscale->orientation == TOP )
406 drawOneLine( marker_x, marker_y, marker_x, marker_y+3 );
409 if( pscale->orientation == BOTTOM )
411 drawOneLine( marker_x, marker_y+3, marker_x, marker_y+6 );
415 if( i%pscale->div_max==0 )
417 sprintf( TextScale, "%d", i );
418 if( pscale->orientation == TOP )
420 drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
421 textString ( marker_x-4*strlen(TextScale), marker_y+14,
422 TextScale, GLUT_BITMAP_8_BY_13 );
425 if( pscale->orientation == BOTTOM )
427 drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
428 textString ( marker_x+10, marker_y-4,
429 TextScale, GLUT_BITMAP_8_BY_13 );
440 // Draws a climb ladder in the center of the HUD
443 static void drawladder( HUD_ladder *ladder )
446 double roll_value, pitch_value;
447 int marker_x, marker_y;
451 int scr_min, scr_max;
454 int new_x_ini, new_x_end;
455 int new_y_ini, new_y_end;
461 roll_value = (*ladder->load_roll)();
462 pitch_value = (*ladder->load_pitch)()*RAD_TO_DEG;
464 vmin = pitch_value - ladder->width_units/2;
465 vmax = pitch_value + ladder->width_units/2;
467 scr_min = ladder->y_pos - (ladder->scr_height/2);
468 scr_max = scr_min + ladder->scr_height;
471 mid_scr = scr_min + (scr_max-scr_min)/2;
474 marker_x = ladder->x_pos - ladder->scr_width/2;
476 factor = (scr_max-scr_min)/ladder->width_units;
478 for( i=vmin; i<=vmax; i+=1 )
483 marker_y = scr_min+(i-vmin)*factor;
484 if( i%ladder->div_units==0 )
486 sprintf( TextLadder, "%d", i );
487 if( ladder->scr_hole == 0 )
490 x_ini = ladder->x_pos - ladder->scr_width/2;
493 x_ini = ladder->x_pos - ladder->scr_width/2 - 10;
496 x_end = ladder->x_pos + ladder->scr_width/2;
498 new_x_ini = ladder->x_pos + \
499 (x_ini - ladder->x_pos) * cos(roll_value) - \
500 (y_ini - ladder->y_pos) * sin(roll_value);
501 new_y_ini = ladder->y_pos + \
502 (x_ini - ladder->x_pos) * sin(roll_value) + \
503 (y_ini - ladder->y_pos) * cos(roll_value);
504 new_x_end = ladder->x_pos + \
505 (x_end - ladder->x_pos) * cos(roll_value) - \
506 (y_end - ladder->y_pos) * sin(roll_value);
507 new_y_end = ladder->y_pos + \
508 (x_end - ladder->x_pos) * sin(roll_value) + \
509 (y_end - ladder->y_pos) * cos(roll_value);
513 drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
517 glEnable(GL_LINE_STIPPLE);
518 glLineStipple( 1, 0x00FF );
519 drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
520 glDisable(GL_LINE_STIPPLE);
522 textString( new_x_ini - 8 * strlen(TextLadder) - 8,
524 TextLadder, GLUT_BITMAP_8_BY_13 );
525 textString( new_x_end + 10,
527 TextLadder, GLUT_BITMAP_8_BY_13 );
532 x_ini = ladder->x_pos - ladder->scr_width/2;
535 x_ini = ladder->x_pos - ladder->scr_width/2 - 10;
538 x_end = ladder->x_pos - ladder->scr_width/2 + ladder->scr_hole/2;
540 new_x_ini = ladder->x_pos+ \
541 (x_ini - ladder->x_pos) * cos(roll_value) -\
542 (y_ini - ladder->y_pos) * sin(roll_value);
543 new_y_ini = ladder->y_pos+ \
544 (x_ini - ladder->x_pos) * sin(roll_value) +\
545 (y_ini - ladder->y_pos) * cos(roll_value);
546 new_x_end = ladder->x_pos+ \
547 (x_end - ladder->x_pos) * cos(roll_value) -\
548 (y_end - ladder->y_pos) * sin(roll_value);
549 new_y_end = ladder->y_pos+ \
550 (x_end - ladder->x_pos) * sin(roll_value) +\
551 (y_end - ladder->y_pos) * cos(roll_value);
555 drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
559 glEnable(GL_LINE_STIPPLE);
560 glLineStipple( 1, 0x00FF );
561 drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
562 glDisable(GL_LINE_STIPPLE);
564 textString( new_x_ini - 8 * strlen(TextLadder) - 8,
566 TextLadder, GLUT_BITMAP_8_BY_13 );
568 x_ini = ladder->x_pos + ladder->scr_width/2 - ladder->scr_hole/2;
571 x_end = ladder->x_pos + ladder->scr_width/2;
574 x_end = ladder->x_pos + ladder->scr_width/2 + 10;
577 new_x_ini = ladder->x_pos + \
578 (x_ini-ladder->x_pos)*cos(roll_value) -\
579 (y_ini-ladder->y_pos)*sin(roll_value);
580 new_y_ini = ladder->y_pos + \
581 (x_ini-ladder->x_pos)*sin(roll_value) +\
582 (y_ini-ladder->y_pos)*cos(roll_value);
583 new_x_end = ladder->x_pos + \
584 (x_end-ladder->x_pos)*cos(roll_value) -\
585 (y_end-ladder->y_pos)*sin(roll_value);
586 new_y_end = ladder->y_pos + \
587 (x_end-ladder->x_pos)*sin(roll_value) +\
588 (y_end-ladder->y_pos)*cos(roll_value);
592 drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
596 glEnable(GL_LINE_STIPPLE);
597 glLineStipple( 1, 0x00FF );
598 drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
599 glDisable(GL_LINE_STIPPLE);
601 textString( new_x_end+10, new_y_end-4,
602 TextLadder, GLUT_BITMAP_8_BY_13 );
605 /* if( i%pscale->div_max==0 )
607 drawOneLine( marker_x, marker_y, marker_x+6, marker_y );
608 sprintf( TextScale, "%d", i );
609 if( pscale->orientation == LEFT )
611 textString( marker_x-8*strlen(TextScale)-2, marker_y-4,
612 TextScale, GLUT_BITMAP_8_BY_13 );
614 else if( pscale->orientation == RIGHT )
616 textString( marker_x+10, marker_y-4,
617 TextScale, GLUT_BITMAP_8_BY_13 );
626 // Draws an artificial horizon line in the center of the HUD
627 // (with or without a center hole)
629 // Needs: x_center, y_center, length, hole
632 static void drawhorizon( HUD_horizon *horizon )
636 int x_t_inc1, y_t_inc1;
638 int d_bottom_x, d_bottom_y;
639 int d_right_x, d_right_y;
640 int d_top_x, d_top_y;
641 int d_left_x, d_left_y;
643 // struct fgFLIGHT *f = ¤t_aircraft.flight;
644 double sin_bank, cos_bank;
645 double bank_angle, sideslip_angle;
646 double sin_sideslip, cos_sideslip;
647 double ss_const; // sideslip angle pixels per rad
649 bank_angle = (*horizon->load_roll)();
650 sideslip_angle = (*horizon->load_sideslip)();
652 // sin_bank = sin( FG_2PI-FG_Phi );
653 // cos_bank = cos( FG_2PI-FG_Phi );
654 sin_bank = sin(FG_2PI-bank_angle);
655 cos_bank = cos(FG_2PI-bank_angle);
656 sin_sideslip = sin(sideslip_angle);
657 cos_sideslip = cos(sideslip_angle);
659 x_inc1 = (int)(horizon->scr_width * cos_bank);
660 y_inc1 = (int)(horizon->scr_width * sin_bank);
661 x_inc2 = (int)(horizon->scr_hole * cos_bank);
662 y_inc2 = (int)(horizon->scr_hole * sin_bank);
664 x_t_inc1 = (int)(horizon->tee_height * sin_bank);
665 y_t_inc1 = (int)(horizon->tee_height * cos_bank);
667 d_bottom_x = horizon->x_pos;
668 d_bottom_y = horizon->y_pos-horizon->scr_hole;
669 d_right_x = horizon->x_pos+horizon->scr_hole;
670 d_right_y = horizon->y_pos;
671 d_top_x = horizon->x_pos;
672 d_top_y = horizon->y_pos+horizon->scr_hole;
673 d_left_x = horizon->x_pos-horizon->scr_hole;
674 d_left_y = horizon->y_pos;
676 ss_const = (FG_PI_2/2)/(2*horizon->scr_width-2*horizon->scr_hole);
678 d_bottom_x += sideslip_angle*ss_const; // horizon->scr_width-horizon->scr_hole;
679 d_right_x += sideslip_angle*ss_const; // horizon->scr_width-horizon->scr_hole;
680 d_left_x += sideslip_angle*ss_const; // horizon->scr_width-horizon->scr_hole;
681 d_top_x += sideslip_angle*ss_const; // horizon->scr_width-horizon->scr_hole;
683 if( horizon->scr_hole == 0 )
685 drawOneLine( horizon->x_pos - x_inc1, horizon->y_pos - y_inc1, \
686 horizon->x_pos + x_inc1, horizon->y_pos + y_inc1 );
690 drawOneLine( horizon->x_pos - x_inc1, horizon->y_pos - y_inc1, \
691 horizon->x_pos - x_inc2, horizon->y_pos - y_inc2 );
692 drawOneLine( horizon->x_pos + x_inc2, horizon->y_pos + y_inc2, \
693 horizon->x_pos + x_inc1, horizon->y_pos + y_inc1 );
697 drawOneLine( horizon->x_pos + x_inc2, horizon->y_pos + y_inc2, \
698 horizon->x_pos + x_inc2 + x_t_inc1, horizon->y_pos + y_inc2 - y_t_inc1 );
699 drawOneLine( horizon->x_pos - x_inc2, horizon->y_pos - y_inc2, \
700 horizon->x_pos - x_inc2 + x_t_inc1, horizon->y_pos - y_inc2 - y_t_inc1 );
702 // draw sideslip diamond (it is not yet positioned correctly )
703 drawOneLine( d_bottom_x, d_bottom_y, d_right_x, d_right_y )
704 drawOneLine( d_right_x, d_right_y, d_top_x, d_top_y );
705 drawOneLine( d_top_x, d_top_y, d_left_x, d_left_y );
706 drawOneLine( d_left_x, d_left_y, d_bottom_x, d_bottom_y );
709 // drawControlSurfaces()
710 // Draws a representation of the control surfaces in their current state
711 // anywhere in the HUD
714 static void drawControlSurfaces( HUD_control_surfaces *ctrl_surf )
722 x_ini = ctrl_surf->x_pos;
723 y_ini = ctrl_surf->y_pos;
727 drawOneLine( x_ini, y_ini, x_end, y_ini );
728 drawOneLine( x_ini, y_ini, x_ini, y_end );
729 drawOneLine( x_ini, y_end, x_end, y_end );
730 drawOneLine( x_end, y_end, x_end, y_ini );
731 drawOneLine( x_ini + 30, y_ini, x_ini + 30, y_end );
732 drawOneLine( x_ini + 30, y_ini + 30, x_ini + 90, y_ini + 30 );
733 drawOneLine( x_ini + 90, y_ini, x_ini + 90, y_end );
734 drawOneLine( x_ini + 120, y_ini, x_ini + 120, y_end );
736 pCtls = current_aircraft.controls;
738 /* Draw elevator diagram */
739 textString( x_ini + 1, y_end-11, "E", GLUT_BITMAP_8_BY_13 );
740 drawOneLine( x_ini + 15, y_ini + 5, x_ini + 15, y_ini + 55 );
741 drawOneLine( x_ini + 14, y_ini + 30, x_ini + 16, y_ini + 30 );
742 if( pCtls->elevator <= -0.01 || pCtls->elevator >= 0.01 )
744 drawOneLine( x_ini + 10, y_ini + 5 + (int)(((pCtls->elevator + 1.0)/2)*50.0), \
745 x_ini + 20, y_ini + 5 + (int)(((pCtls->elevator + 1.0)/2)*50.0) );
749 drawOneLine( x_ini + 7, y_ini + 5 + (int)(((pCtls->elevator + 1.0)/2)*50.0), \
750 x_ini + 23, y_ini + 5 + (int)(((pCtls->elevator + 1.0)/2)*50.0) );
753 /* Draw aileron diagram */
754 textString( x_ini + 30 + 1, y_end-11, "A", GLUT_BITMAP_8_BY_13 );
755 drawOneLine( x_ini + 35, y_end-15, x_ini + 85, y_end-15 );
756 drawOneLine( x_ini + 60, y_end-14, x_ini + 60, y_end-16 );
757 if( pCtls->aileron <= -0.01 || pCtls->aileron >= 0.01 )
759 drawOneLine( x_ini + 35 + (int)(((pCtls->aileron + 1.0)/2)*50.0), y_end-20, \
760 x_ini + 35 + (int)(((pCtls->aileron + 1.0)/2)*50.0), y_end-10 );
764 drawOneLine( x_ini + 35 + (int)(((pCtls->aileron + 1.0) / 2) * 50.0),
766 x_ini + 35 + (int)(((pCtls->aileron + 1.0) / 2) * 50.0),
770 /* Draw rudder diagram */
771 textString ( x_ini + 30 + 1, y_ini + 21, "R", GLUT_BITMAP_8_BY_13 );
772 drawOneLine( x_ini + 35, y_ini + 15, x_ini + 85, y_ini + 15 );
773 drawOneLine( x_ini + 60, y_ini + 14, x_ini + 60, y_ini + 16 );
775 if( pCtls->rudder <= -0.01 || pCtls->rudder >= 0.01 )
777 drawOneLine( x_ini + 35 + (int)(((pCtls->rudder + 1.0) / 2) * 50.0),
779 x_ini + 35 + (int)(((pCtls->rudder + 1.0) / 2) * 50.0),
784 drawOneLine( x_ini + 35 + (int)(((pCtls->rudder + 1.0) / 2) * 50.0),
786 x_ini + 35 + (int)(((pCtls->rudder + 1.0) / 2) * 50.0),
791 /* Draw throttle diagram */
792 textString( x_ini + 90 + 1, y_end-11, "T", GLUT_BITMAP_8_BY_13 );
793 textString( x_ini + 90 + 1, y_end-21, "r", GLUT_BITMAP_8_BY_13 );
794 drawOneLine( x_ini + 105, y_ini + 5, x_ini + 105, y_ini + 55 );
795 drawOneLine( x_ini + 100, y_ini + 5 + (int)(pCtls->throttle[0]*50.0), \
796 x_ini + 110, y_ini + 5 + (int)(pCtls->throttle[0]*50.0) );
799 /* Draw elevator trim diagram */
800 textString( x_ini + 121, y_end-11, "T", GLUT_BITMAP_8_BY_13 );
801 textString( x_ini + 121, y_end-22, "m", GLUT_BITMAP_8_BY_13 );
802 drawOneLine( x_ini + 135, y_ini + 5, x_ini + 135, y_ini + 55 );
803 drawOneLine( x_ini + 134, y_ini + 30, x_ini + 136, y_ini + 30 );
804 if( pCtls->elevator_trim <= -0.01 || pCtls->elevator_trim >= 0.01 )
806 drawOneLine( x_ini + 130, y_ini + 5 + (int)(((pCtls->elevator_trim + 1)/2)*50.0), \
807 x_ini + 140, y_ini + 5 + (int)(((pCtls->elevator_trim + 1.0)/2)*50.0) );
811 drawOneLine( x_ini + 127, y_ini + 5 + (int)(((pCtls->elevator_trim + 1.0)/2)*50.0), \
812 x_ini + 143, y_ini + 5 + (int)(((pCtls->elevator_trim + 1.0)/2)*50.0) );
818 // Draws a label anywhere in the HUD
822 static void drawlabel( HUD_label *label )
829 if( !label ) { // Eliminate the possible, but absurd case.
833 if( label->pre_str != NULL) {
834 if( label->post_str != NULL ) {
835 sprintf( buffer, "%s%s%s", label->pre_str, \
840 sprintf( buffer, "%s%s", label->pre_str, \
845 if( label->post_str != NULL ) {
846 sprintf( buffer, "%s%s", label->format, \
849 } // else do nothing if both pre and post strings are nulls. Interesting.
852 sprintf( string, buffer, (*label->load_value)() );
854 fgPrintf( FG_COCKPIT, FG_DEBUG, buffer );
855 fgPrintf( FG_COCKPIT, FG_DEBUG, "\n" );
856 fgPrintf( FG_COCKPIT, FG_DEBUG, string );
857 fgPrintf( FG_COCKPIT, FG_DEBUG, "\n" );
859 lenstr = strlen( string );
860 if( label->justify == LEFT_JUST ) {
864 if( label->justify == CENTER_JUST ) {
868 if( label->justify == RIGHT_JUST ) {
874 if( label->size == SMALL ) {
875 textString( label->x_pos + posincr, label->y_pos,
876 string, GLUT_BITMAP_8_BY_13);
879 if( label->size == LARGE ) {
880 textString( label->x_pos + posincr, label->y_pos,
881 string, GLUT_BITMAP_9_BY_15);
885 // The following routines concern HUD object/component object construction
890 // Constructs a HUD object and then adds in instruments. At the present
891 // the instruments are hard coded into the routine. Ultimately these need
892 // to be defined by the aircraft's instrumentation records so that the
893 // display for a Piper Cub doesn't show the speed range of a North American
894 // mustange and the engine readouts of a B36!
896 Hptr fgHUDInit( fgAIRCRAFT *current_aircraft )
900 fgPrintf( FG_COCKPIT, FG_INFO, "Initializing HUD\n" );
902 hud = (Hptr)calloc(sizeof( HUD),1);
909 // For now lets just hardcode the hud here.
910 // In the future, hud information has to come from the same place
911 // aircraft information came from.
913 fgHUDSetTimeMode( hud, NIGHT );
914 fgHUDSetBrightness( hud, BRT_LIGHT );
916 // Small, original HUD configuration
917 // fgHUDAddHorizon( hud, 590, 50, 40, 5, 10, get_roll, get_sideslip );
918 // fgHUDAddLadder ( hud, 330, 190, 90, 180, 70, 10,
919 // NONE, 45, get_roll, get_pitch );
920 // fgHUDAddScale ( hud, VERTICAL, LIMIT, 220, 100, 280, 5, 10,
921 // LEFT, 0, 100, 50, get_speed );
922 // fgHUDAddScale ( hud, VERTICAL, NOLIMIT, 440, 100, 280, 1, 5, RIGHT,
923 // -40, 50, 25, get_aoa );
924 // fgHUDAddScale ( hud, HORIZONTAL, NOLIMIT, 280, 220, 440, 5, 10,
925 // TOP, 0, 50, 50, get_heading );
926 // fgHUDAddLabel ( hud, 180, 85, SMALL, NOBLINK,
927 // RIGHT_JUST, NULL, " Kts", "%5.0f", get_speed );
928 // fgHUDAddLabel ( hud, 180, 73, SMALL, NOBLINK,
929 // RIGHT_JUST, NULL, " m", "%5.0f", get_altitude );
930 // fgHUDAddControlSurfaces( hud, 10, 10, NULL );
932 // Bigger and placed a bit higher HUD configuration
933 fgHUDAddHorizon( hud, 590, 50, 40, 5, 10, get_roll, get_sideslip );
934 fgHUDAddLadder ( hud, 330, 270, 120, 180, 70, 10,
935 NONE, 45, get_roll, get_pitch );
936 fgHUDAddScale ( hud, VERTICAL, LIMIT, 200, 180, 380, 5, 10,
937 LEFT, 0, 100, 50, get_speed );
938 fgHUDAddScale ( hud, VERTICAL, NOLIMIT, 460, 180, 380, 1, 5,
939 RIGHT, -40, 50, 25, get_aoa );
940 fgHUDAddScale ( hud, HORIZONTAL, NOLIMIT, 380, 200, 460, 5, 10,
941 TOP, 0, 50, 50, get_heading );
942 fgHUDAddLabel ( hud, 160, 165, SMALL, NOBLINK,
943 RIGHT_JUST, NULL, " Kts", "%5.0f", get_speed );
944 fgHUDAddLabel ( hud, 160, 153, SMALL, NOBLINK,
945 RIGHT_JUST, NULL, " m", "%5.0f", get_altitude );
946 fgHUDAddControlSurfaces( hud, 10, 10, NULL );
948 // fgHUDAddControl( hud, HORIZONTAL, 50, 25, get_aileronval ); // was 10, 10
949 // fgHUDAddControl( hud, VERTICAL, 150, 25, get_elevatorval ); // was 10, 10
950 // fgHUDAddControl( hud, HORIZONTAL, 250, 25, get_rudderval ); // was 10, 10
957 // This is a stand in for linked list code that will get replaced later
958 // by some more elegant list handling code.
960 void add_instrument( Hptr hud, HIptr pinstrument )
962 if( !hud || !pinstrument ) {
966 pinstrument->next = hud->instruments;
967 hud->instruments = pinstrument;
973 // Constructs a HUD_horizon "object" and installs it into the hud instrument
976 Hptr fgHUDAddHorizon( Hptr hud, \
982 double (*load_roll)(),\
983 double (*load_sideslip)() )
985 HUD_horizon *phorizon;
986 HUD_instr *pinstrument;
991 // construct the parent object
992 pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
993 if( pinstrument == NULL ) {
996 pinstrument->type = HUDhorizon; // ARTIFICIAL_HORIZON;
998 // Construct the horizon
999 phorizon = (HUD_horizon *) calloc( sizeof(HUD_horizon),1);
1000 if( phorizon == NULL ) {
1004 phorizon->x_pos = x_pos;
1005 phorizon->y_pos = y_pos;
1006 phorizon->scr_width = length;
1007 phorizon->scr_hole = hole_len;
1008 phorizon->tee_height = tee_height;
1009 phorizon->load_roll = load_roll;
1010 phorizon->load_sideslip = load_sideslip;
1011 // Install the horizon in the parent.
1012 pinstrument->instr = phorizon;
1013 // Install the instrument into hud.
1014 add_instrument( hud, pinstrument);
1021 // Constructs a HUD_scale "object" and installs it into the hud instrument
1024 Hptr fgHUDAddScale( Hptr hud, \
1036 double (*load_value)() )
1039 HUD_instr *pinstrument;
1045 pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1046 if( pinstrument == NULL ) {
1050 pinstrument->type = HUDscale;
1052 pscale = ( HUD_scale *)calloc(sizeof(HUD_scale),1);
1053 if( pscale == NULL ) {
1056 pscale->type = type;
1057 pscale->sub_type = sub_type;
1058 pscale->scr_pos = scr_pos;
1059 pscale->scr_min = scr_min;
1060 pscale->scr_max = scr_max;
1061 pscale->div_min = div_min;
1062 pscale->div_max = div_max;
1063 pscale->orientation = orientation;
1064 pscale->minimum_value = min_value;
1065 pscale->maximum_value = max_value;
1066 pscale->width_units = width_units;
1067 pscale->load_value = load_value;
1068 // Install the scale
1069 pinstrument->instr = pscale;
1070 // Install the instrument into hud.
1071 add_instrument( hud, pinstrument);
1078 // Constructs a HUD_Label object and installs it into the hud instrument
1080 Hptr fgHUDAddLabel( Hptr hud, \
1089 double (*load_value)() )
1092 HUD_instr *pinstrument;
1098 pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1099 if( pinstrument == NULL ) {
1102 pinstrument->type = HUDlabel;
1104 plabel = (HUD_label *)calloc(sizeof(HUD_label),1);
1105 if( plabel == NULL ){
1109 plabel->x_pos = x_pos;
1110 plabel->y_pos = y_pos;
1111 plabel->size = size;
1112 plabel->blink = blink;
1113 plabel->justify = justify;
1114 plabel->pre_str = pre_str;
1115 plabel->post_str = post_str;
1116 plabel->format = format;
1117 plabel->load_value = load_value;
1118 // Install the label
1119 pinstrument->instr = plabel;
1120 // Install the instrument into hud.
1121 add_instrument( hud, pinstrument);
1128 // Contains code that constructs a ladder "object" and installs it as
1129 // a hud instrument in the hud instrument list.
1131 Hptr fgHUDAddLadder( Hptr hud, \
1140 double (*load_roll)(),
1141 double (*load_pitch)() )
1143 HUD_ladder *pladder;
1144 HUD_instr *pinstrument;
1150 pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1151 if( pinstrument == NULL )
1154 pinstrument->type = HUDladder;
1156 pladder = (HUD_ladder *)calloc(sizeof(HUD_ladder),1);
1157 if( pladder == NULL )
1160 pladder->type = 0; // Not used.
1161 pladder->x_pos = x_pos;
1162 pladder->y_pos = y_pos;
1163 pladder->scr_width = scr_width;
1164 pladder->scr_height = scr_height;
1165 pladder->scr_hole = hole_len;
1166 pladder->div_units = div_units;
1167 pladder->label_position = label_pos;
1168 pladder->width_units = width_units;
1169 pladder->load_roll = load_roll;
1170 pladder->load_pitch = load_pitch;
1172 pinstrument->instr = pladder;
1173 // Install the instrument into hud.
1174 add_instrument( hud, pinstrument);
1178 // fgHUDAddControlSurfaces()
1180 // Adds the control surface indicators which make up for the lack of seat
1181 // of the pants feel. Should be unnecessary with joystick and pedals
1182 // enabled. But that is another improvement. Also, what of flaps? Spoilers?
1183 // This may need to be expanded or flattened into multiple indicators,
1184 // vertical and horizontal.
1186 Hptr fgHUDAddControlSurfaces( Hptr hud,
1189 double (*load_value)() )
1191 HUD_control_surfaces *pcontrol_surfaces;
1192 HUD_instr *pinstrument;
1199 pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1200 if( !pinstrument ) {
1203 pinstrument->type = HUDcontrol_surfaces;
1206 pcontrol_surfaces = (HUD_control_surfaces *)calloc(sizeof(HUD_control),1);
1207 if( !pcontrol_surfaces ) {
1211 pcontrol_surfaces->x_pos = x_pos;
1212 pcontrol_surfaces->y_pos = y_pos;
1213 pcontrol_surfaces->load_value = load_value;
1215 pinstrument->instr = pcontrol_surfaces;
1217 add_instrument( hud, pinstrument);
1226 Hptr fgHUDAddControl( Hptr hud, \
1235 double (*load_value)() )
1237 HUD_control *pcontrol;
1238 HUD_instr *pinstrument;
1245 pinstrument = (HIptr)calloc(sizeof(HUD_instr),1);
1246 if( !pinstrument ) {
1249 pinstrument->type = HUDcontrol;
1252 pcontrol = (HUD_control *)calloc(sizeof(HUD_control),1);
1253 if( !(pcontrol == NULL) ) {
1256 pcontrol->ctrl_x = ctrl_x;
1257 pcontrol->ctrl_y = ctrl_y;
1258 pcontrol->ctrl_length = ctrl_length;
1259 pcontrol->orientation = orientation;
1260 pcontrol->alignment = alignment;
1261 pcontrol->min_value = min_value;
1262 pcontrol->max_value = max_value;
1263 pcontrol->width_units = width_units;
1264 pcontrol->load_value = load_value;
1266 pinstrument->instr = pcontrol;
1268 add_instrument( hud, pinstrument);
1274 Hptr fgHUDAddMovingHorizon( Hptr hud, \
1284 Hptr fgHUDAddCircularLadder( Hptr hud, \
1294 Hptr fgHUDAddNumDisp( Hptr hud, \
1309 // Performs a once around the list of calls to instruments installed in
1310 // the HUD object with requests for redraw. Kinda. It will when this is
1314 void fgUpdateHUD( Hptr hud ) {
1317 glMatrixMode(GL_PROJECTION);
1321 gluOrtho2D(0, 640, 0, 480);
1322 glMatrixMode(GL_MODELVIEW);
1326 glColor3f(1.0, 1.0, 1.0);
1329 glDisable(GL_DEPTH_TEST);
1330 glDisable(GL_LIGHTING);
1334 if( hud->time_of_day==DAY) {
1335 switch (hud->brightness) {
1337 glColor3f (0.1, 0.9, 0.1);
1340 glColor3f (0.1, 0.7, 0.0);
1343 glColor3f (0.0, 0.5, 0.0);
1346 else if( hud->time_of_day==NIGHT) {
1347 switch (hud->brightness) {
1349 glColor3f (0.9, 0.1, 0.1);
1352 glColor3f (0.7, 0.0, 0.1);
1355 glColor3f (0.5, 0.0, 0.0);
1359 fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d Status %d\n",
1360 hud->code, hud->status );
1362 phud_instr = hud->instruments;
1363 while( phud_instr ) {
1364 /* printf("Drawing Instrument %d\n", phud_instr->type); */
1366 switch (phud_instr->type) {
1367 case HUDhorizon: // ARTIFICIAL HORIZON
1368 drawhorizon( (pHUDhorizon)phud_instr->instr );
1371 case HUDscale: // Need to simplify this call.
1372 drawscale ( (pHUDscale) phud_instr->instr );
1376 drawlabel ( (pHUDlabel) phud_instr->instr );
1380 drawladder( (pHUDladder) phud_instr->instr );
1384 // drawControl( (pHUDcontrol) phud_instr->instr );
1387 case HUDcontrol_surfaces:
1388 drawControlSurfaces( (pHUDControlSurfaces) phud_instr->instr );
1391 default:; // Ignore anything you don't know about.
1394 phud_instr = phud_instr->next;
1397 glEnable(GL_DEPTH_TEST);
1398 glEnable(GL_LIGHTING);
1399 glMatrixMode(GL_PROJECTION);
1401 glMatrixMode(GL_MODELVIEW);
1405 void fgHUDSetTimeMode( Hptr hud, int time_of_day )
1408 hud->time_of_day = time_of_day;
1412 void fgHUDSetBrightness( Hptr hud, int brightness )
1415 hud->brightness = brightness;
1420 /* Revision 1.17 1998/02/20 00:16:21 curt
1421 /* Thursday's tweaks.
1423 * Revision 1.16 1998/02/19 13:05:49 curt
1424 * Incorporated some HUD tweaks from Michelle America.
1425 * Tweaked the sky's sunset/rise colors.
1426 * Other misc. tweaks.
1428 * Revision 1.15 1998/02/16 13:38:39 curt
1429 * Integrated changes from Charlie Hotchkiss.
1431 * Revision 1.14 1998/02/12 21:59:41 curt
1432 * Incorporated code changes contributed by Charlie Hotchkiss
1433 * <chotchkiss@namg.us.anritsu.com>
1435 * Revision 1.12 1998/02/09 15:07:48 curt
1438 * Revision 1.11 1998/02/07 15:29:34 curt
1439 * Incorporated HUD changes and struct/typedef changes from Charlie Hotchkiss
1440 * <chotchkiss@namg.us.anritsu.com>
1442 * Revision 1.10 1998/02/03 23:20:14 curt
1443 * Lots of little tweaks to fix various consistency problems discovered by
1444 * Solaris' CC. Fixed a bug in fg_debug.c with how the fgPrintf() wrapper
1445 * passed arguments along to the real printf(). Also incorporated HUD changes
1446 * by Michele America.
1448 * Revision 1.9 1998/01/31 00:43:04 curt
1449 * Added MetroWorks patches from Carmen Volpe.
1451 * Revision 1.8 1998/01/27 00:47:51 curt
1452 * Incorporated Paul Bleisch's <bleisch@chromatic.com> new debug message
1453 * system and commandline/config file processing code.
1455 * Revision 1.7 1998/01/19 18:40:20 curt
1456 * Tons of little changes to clean up the code and to remove fatal errors
1457 * when building with the c++ compiler.
1459 * Revision 1.6 1997/12/15 23:54:34 curt
1460 * Add xgl wrappers for debugging.
1461 * Generate terrain normals on the fly.
1463 * Revision 1.5 1997/12/10 22:37:39 curt
1464 * Prepended "fg" on the name of all global structures that didn't have it yet.
1465 * i.e. "struct WEATHER {}" became "struct fgWEATHER {}"
1467 * Revision 1.4 1997/09/23 00:29:32 curt
1468 * Tweaks to get things to compile with gcc-win32.
1470 * Revision 1.3 1997/09/05 14:17:26 curt
1471 * More tweaking with stars.
1473 * Revision 1.2 1997/09/04 02:17:30 curt
1476 * Revision 1.1 1997/08/29 18:03:22 curt