1 // hud.cxx -- hud defines and prototypes
3 // Written by Michele America, started September 1997.
5 // Copyright (C) 1997 Michele F. America - micheleamerica@geocities.com
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 # define exception c_exception
42 # include <values.h> // for MAXINT
45 #include <simgear/constants.h>
46 #include <simgear/debug/logstream.hxx>
47 #include <simgear/math/fg_random.h>
48 #include <simgear/math/polar3d.hxx>
50 #include <Aircraft/aircraft.hxx>
51 #include <Autopilot/newauto.hxx>
53 #include <Main/options.hxx>
55 #include <NetworkOLK/network.h>
57 #include <Scenery/scenery.hxx>
58 #include <Time/fg_timer.hxx>
60 #if defined ( __sun__ ) || defined ( __sgi )
62 extern void *memmove(void *, const void *, size_t);
70 // The following routines obtain information concerning the aircraft's
71 // current state and return it to calling instrument display routines.
72 // They should eventually be member functions of the aircraft.
75 deque< instr_item * > HUD_deque;
77 fgTextList HUD_TextList;
78 fgLineList HUD_LineList;
79 fgLineList HUD_StippleLineList;
81 float hud_trans_alpha = 0.5f;
82 void fgHUDalphaInit( void );
88 locRECT( UINT left, UINT top, UINT right, UINT bottom);
89 RECT get_rect(void) { return rect;}
92 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
102 void drawOneLine( UINT x1, UINT y1, UINT x2, UINT y2)
110 void drawOneLine( RECT &rect)
113 glVertex2f(rect.left, rect.top);
114 glVertex2f(rect.right, rect.bottom);
119 // The following code deals with painting the "instrument" on the display
121 /* textString - Bitmap font string */
123 void textString( int x, int y, char *msg, void *font ){
127 // puDrawString ( NULL, msg, x, y );
131 glutBitmapCharacter(font, *msg);
138 /* strokeString - Stroke font string */
139 void strokeString(int x, int y, char *msg, void *font, float theta)
144 float sintheta,costheta;
150 glRotatef(theta * RAD_TO_DEG, 0.0, 0.0, 1.0);
151 sintheta = sin(theta);
152 costheta = cos(theta);
153 xx = (int)(x * costheta + y * sintheta);
154 yy = (int)(y * costheta - x * sintheta);
155 glTranslatef( xx, yy, 0);
156 glScalef(.1, .1, 0.0);
157 while( (c=*msg++) ) {
158 glutStrokeCharacter(font, c);
164 int getStringWidth ( char *str )
166 if ( HUDtext && str )
169 guiFntHandle->getBBox ( str, HUD_TextSize, 0, &l, &r, NULL, NULL ) ;
170 return FloatToInt( r - l );
175 //========================= End of Class Implementations===================
178 // Constructs a HUD object and then adds in instruments. At the present
179 // the instruments are hard coded into the routine. Ultimately these need
180 // to be defined by the aircraft's instrumentation records so that the
181 // display for a Piper Cub doesn't show the speed range of a North American
182 // mustange and the engine readouts of a B36!
187 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
194 int min_x = 25; //off/2;
195 int max_x = 615; //640-(off/2);
197 int max_y = 430; //480-off;
200 unsigned int text_h = 10;
201 unsigned int ladr_w2 = 60;
207 font_size = (current_options.get_xsize() > 1000) ? LARGE : SMALL;
211 FG_LOG( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD" );
213 // deque < instr_item * > :: iterator first = HUD_deque.begin();
214 // deque < instr_item * > :: iterator last = HUD_deque.end();
215 // HUD_deque.erase( first, last); // empty the HUD deque
217 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end()); // empty the HUD deque
222 // For now lets just hardcode the hud here.
223 // In the future, hud information has to come from the same place
224 // aircraft information came from.
226 // fgHUDSetTimeMode( hud, NIGHT );
227 // fgHUDSetBrightness( hud, BRT_LIGHT );
230 // int x = 290; /*cen_x-30*/
231 // int y = 45; /*off-5*/
232 // HIptr = (instr_item *) new fgTBI_instr( x, y, ladr_w2, text_h );
233 HIptr = (instr_item *) new fgTBI_instr( 290, 45, 60, 10 );
234 HUD_deque.insert( HUD_deque.begin(), HIptr);
236 // case 1: // Artificial Horizon
237 HIptr = (instr_item *) new HudLadder( cen_x-ladr_w2, cen_y-ladr_h2,
238 2*ladr_w2, 2*ladr_h2 );
239 HUD_deque.insert( HUD_deque.begin(), HIptr);
241 // case 4: // GYRO COMPASS
242 HIptr = (instr_item *) new hud_card( cen_x-(compass_w/2),
255 HUD_deque.insert( HUD_deque.begin(), HIptr);
258 HIptr = (instr_item *) new hud_card( max_x - 35 -15, // 15 to balance speed card
263 // HUDS_RIGHT | HUDS_VERT,
264 HUDS_LEFT | HUDS_VERT,
272 HUD_deque.insert( HUD_deque.begin(), HIptr);
275 HIptr = (instr_item *) new guage_instr( cen_x-50, // x
276 cen_y + ladr_h2 -20, // y
279 get_aileronval, // data source
280 HUDS_BOTTOM | HUDS_NOTEXT,
284 HUD_deque.insert( HUD_deque.begin(), HIptr);
286 // case 3: // Radio Altimeter
287 HIptr = (instr_item *) new hud_card( cen_x + ladr_w2 + gap + 13 + ladr_t,
292 HUDS_LEFT | HUDS_VERT,
300 HUD_deque.insert( HUD_deque.begin(), HIptr);
303 HIptr = (instr_item *) new guage_instr( cen_x -ladr_w2 -gap -13 -20 -ladr_t,
307 get_elevatorval, // data source
308 HUDS_RIGHT | HUDS_VERT | HUDS_NOTEXT,
309 -100.0, // Scale data
312 HUD_deque.insert( HUD_deque.begin(), HIptr);
315 HIptr = (instr_item *) new guage_instr( cen_x-50, // x
316 cen_y -gap -ladr_w2 -20, //-85 // y
319 get_rudderval, // data source
320 HUDS_TOP | HUDS_NOTEXT,
324 HUD_deque.insert( HUD_deque.begin(), HIptr);
327 HIptr = (instr_item *) new hud_card( min_x +10 +5, //min_x +18,
332 // HUDS_LEFT | HUDS_VERT,
333 HUDS_RIGHT | HUDS_VERT,
344 HUD_deque.insert( HUD_deque.begin(), HIptr);
347 // case 10: // Digital Mach number
348 HIptr = (instr_item *) new instr_label ( min_x , //same as speed tape
349 cen_y-(compass_w/2) -10, //below speed tape
362 HUD_deque.insert( HUD_deque.begin(), HIptr);
365 HIptr = (instr_item *) new guage_instr( min_x-10, // x
369 get_throttleval, // data source
370 // HUDS_VERT | HUDS_RIGHT | HUDS_NOTEXT,
371 HUDS_VERT | HUDS_LEFT | HUDS_NOTEXT, 100.0,
375 HUD_deque.insert( HUD_deque.begin(), HIptr);
376 // Remove this when below uncommented
378 HIptr = (instr_item *) new instr_label( 10,
392 HUD_deque.insert( HUD_deque.begin(), HIptr);
394 HIptr = (instr_item *) new lat_label( (cen_x - (compass_w/2))/2,
408 HUD_deque.insert( HUD_deque.begin(), HIptr);
410 HIptr = (instr_item *) new lon_label(((cen_x+compass_w/2)+(2*cen_x))/2,
423 HUD_deque.insert( HUD_deque.begin(), HIptr);
426 // case 10: // Digital KIAS
427 HIptr = (instr_item *) new instr_label ( 110,
441 HUD_deque.insert( HUD_deque.begin(), HIptr);
443 // case 11: // Digital Rate of Climb
444 HIptr = (instr_item *) new instr_label ( 110,
458 HUD_deque.insert( HUD_deque.begin(), HIptr);
460 // case 12: // Roll indication diagnostic
461 HIptr = (instr_item *) new instr_label ( 110,
475 HUD_deque.insert( HUD_deque.begin(), HIptr);
477 // case 13: // Angle of attack diagnostic
478 HIptr = (instr_item *) new instr_label ( 440,
492 HUD_deque.insert( HUD_deque.begin(), HIptr);
495 HIptr = (instr_item *) new instr_label ( 440,
509 HUD_deque.insert( HUD_deque.begin(), HIptr);
512 HIptr = (instr_item *) new instr_label ( 440,
526 HUD_deque.insert( HUD_deque.begin(), HIptr);
529 HIptr = (instr_item *) new instr_label( 440,
543 HUD_deque.insert( HUD_deque.begin(), HIptr);
546 HIptr = (instr_item *) new instr_label( 440,
560 HUD_deque.insert( HUD_deque.begin(), HIptr);
563 HIptr = (instr_item *) new instr_label( 440,
577 HUD_deque.insert( HUD_deque.begin(), HIptr);
580 HIptr = (instr_item *) new instr_label( 10,
594 HUD_deque.insert( HUD_deque.begin(), HIptr);
597 switch( current_options.get_tris_or_culled() ) {
599 HIptr = (instr_item *) new instr_label( 10,
615 HIptr = (instr_item *) new instr_label( 10,
634 HIptr = (instr_item *) new instr_label( 10,
648 HUD_deque.insert( HUD_deque.begin(), HIptr);
653 // if( HIptr ) { // Anything to install?
654 // HUD_deque.insert( HUD_deque.begin(), HIptr);
661 return 0; // For now. Later we may use this for an error code.
665 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
667 // instr_item *HIptr;
673 // int max_x = 640-off;
685 font_size = (current_options.get_xsize() > 1000) ? LARGE : SMALL;
689 FG_LOG( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD" );
691 // deque < instr_item * > :: iterator first = HUD_deque.begin();
692 // deque < instr_item * > :: iterator last = HUD_deque.end();
693 // HUD_deque.erase( first, last); // empty the HUD deque
694 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());
699 // For now lets just hardcode the hud here.
700 // In the future, hud information has to come from the same place
701 // aircraft information came from.
703 // fgHUDSetTimeMode( hud, NIGHT );
704 // fgHUDSetBrightness( hud, BRT_LIGHT );
711 p = new HudLadder( cen_x-ladr_w2, cen_y-ladr_h2, 2*ladr_w2, 2*ladr_h2, 1 );
712 HUD_deque.push_front( p );
714 // case 4: // GYRO COMPASS
715 p =new hud_card( cen_x-(compass_w/2),
728 HUD_deque.push_front( p );
730 p = new lat_label( (cen_x - compass_w/2)/2,
743 HUD_deque.push_front( p );
745 // p = new instr_label( 140, 450, 60, 10,
756 // HUD_deque.push_front( p );
758 p = new lon_label(((cen_x+compass_w/2)+(2*cen_x))/2,
771 HUD_deque.push_front( p );
775 p = new instr_label( x_pos, 25, 60, 10,
786 HUD_deque.push_front( p );
788 p = new instr_label( x_pos, 40, 120, 10,
799 HUD_deque.push_front( p );
801 p = new instr_label( x_pos, 55, 120, 10,
812 HUD_deque.push_front( p );
815 // p = new instr_label( x_pos, 70, 90, 10,
816 p = new instr_label( x_pos, 40, 90, 10,
827 HUD_deque.push_front( p );
831 p = new instr_label ( x_pos,
845 HUD_deque.push_front( p );
847 p = new instr_label( x_pos, 55, 40, 30,
858 HUD_deque.push_front( p );
860 if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET ) {
861 strcpy(units, " ft");
865 p = new instr_label( x_pos, 40, 40, 10,
876 HUD_deque.push_front( p );
878 p = new instr_label( x_pos, 25, 40, 10,
889 HUD_deque.push_front( p );
891 p = new instr_label( x_pos, 10, 60, 10,
902 HUD_deque.push_front( p );
904 p = new fgTBI_instr( 290, 55, 60, 10 ); // 270
905 HUD_deque.push_front( p );
907 p = new guage_instr( 270, //250, // x
908 390, //360, //400, //45, //420, // y
911 get_aileronval, // data source
912 HUDS_BOTTOM | HUDS_NOTEXT,
916 HUD_deque.push_front( p );
918 p = new guage_instr( 20, // x
922 get_elevatorval, // data source
923 HUDS_RIGHT | HUDS_VERT | HUDS_NOTEXT,
924 -100.0, // Scale data
927 HUD_deque.push_front( p );
929 p = new guage_instr( 270, //250, // x
933 get_rudderval, // data source
934 HUDS_TOP | HUDS_NOTEXT,
938 HUD_deque.push_front( p );
940 p = new guage_instr( 600, // x
944 get_throttleval, // data source
945 HUDS_VERT | HUDS_LEFT | HUDS_NOTEXT,
949 HUD_deque.push_front( p );
951 return 0; // For now. Later we may use this for an error code.
954 int global_day_night_switch = DAY;
956 void HUD_brightkey( bool incr_bright )
958 instr_item *pHUDInstr = HUD_deque[0];
959 int brightness = pHUDInstr->get_brightness();
961 if( current_options.get_hud_status() ) {
963 switch (brightness) {
965 current_options.set_hud_status(0);
969 brightness = BRT_LIGHT;
973 brightness = BRT_MEDIUM;
977 brightness = BRT_DARK;
981 brightness = BRT_BLACK;
985 switch (brightness) {
987 brightness = BRT_MEDIUM;
991 brightness = BRT_DARK;
995 brightness = BRT_BLACK;
1000 current_options.set_hud_status(0);
1005 current_options.set_hud_status(1);
1007 if( DAY == global_day_night_switch ) {
1008 brightness = BRT_BLACK;
1011 brightness = BRT_DARK;
1012 global_day_night_switch = DAY;
1016 if( NIGHT == global_day_night_switch ) {
1017 brightness = BRT_DARK;
1020 brightness = BRT_MEDIUM;
1021 global_day_night_switch = NIGHT;
1025 pHUDInstr->SetBrightness( brightness );
1029 #define fgAP_CLAMP(val,min,max) ( (val) = (val) > (max) ? (max) : (val) < (min) ? (min) : (val) )
1031 static puDialogBox *HUDalphaDialog;
1032 static puFrame *HUDalphaFrame;
1033 static puText *HUDalphaDialogMessage;
1034 static puText *HUDalphaTitle;
1035 static puText *HUDalphaText;
1036 static puOneShot *HUDalphaOkButton;
1037 static puSlider *HUDalphaHS0;
1038 static puFont HUDalphaLegendFont;
1039 static puFont HUDalphaLabelFont;
1040 static char SliderText[1][ 8 ];
1042 static void alpha_adj( puObject *hs ) {
1045 hs-> getValue ( &val ) ;
1046 fgAP_CLAMP ( val, 0.1, 1.0 ) ;
1047 // printf ( "maxroll_adj( %p ) %f %f\n", hs, val, MaxRollAdjust * val ) ;
1048 hud_trans_alpha = val;
1049 sprintf( SliderText[ 0 ], "%05.2f", hud_trans_alpha );
1050 HUDalphaText -> setLabel ( SliderText[ 0 ] ) ;
1053 void fgHUDalphaAdjust( puObject * ) {
1054 FG_PUSH_PUI_DIALOG( HUDalphaDialog );
1057 static void goAwayHUDalphaAdjust (puObject *)
1059 FG_POP_PUI_DIALOG( HUDalphaDialog );
1062 // Done once at system initialization
1063 void fgHUDalphaInit( void ) {
1065 // printf("fgAPAdjustInit\n");
1066 #define HORIZONTAL FALSE
1070 int DialogWidth = 230;
1072 char Label[] = "HUD Alpha Adjust";
1075 int labelX = (DialogWidth / 2) -
1076 (puGetStringWidth( puGetDefaultLabelFont(), Label ) / 2);
1077 labelX -= 30; // KLUDGEY
1082 int slider_width = 210;
1083 int slider_title_x = 15;
1084 int slider_value_x = 160;
1085 float slider_delta = 0.05f;
1087 puGetDefaultFonts ( &HUDalphaLegendFont, &HUDalphaLabelFont );
1088 HUDalphaDialog = new puDialogBox ( DialogX, DialogY ); {
1089 int horiz_slider_height = puGetStringHeight (HUDalphaLabelFont) +
1090 puGetStringDescender (HUDalphaLabelFont) +
1091 PUSTR_TGAP + PUSTR_BGAP + 5;
1093 HUDalphaFrame = new puFrame ( 0, 0,
1095 85 + nSliders * horiz_slider_height );
1097 HUDalphaDialogMessage = new puText ( labelX,
1099 * horiz_slider_height );
1100 HUDalphaDialogMessage -> setDefaultValue ( Label );
1101 HUDalphaDialogMessage -> getDefaultValue ( &s );
1102 HUDalphaDialogMessage -> setLabel ( s );
1104 HUDalphaHS0 = new puSlider ( slider_x, slider_y,
1105 slider_width, HORIZONTAL ) ;
1106 HUDalphaHS0-> setDelta ( slider_delta ) ;
1107 HUDalphaHS0-> setValue ( hud_trans_alpha ) ;
1108 HUDalphaHS0-> setCBMode ( PUSLIDER_DELTA ) ;
1109 HUDalphaHS0-> setCallback ( alpha_adj ) ;
1111 sprintf( SliderText[ 0 ], "%05.2f", hud_trans_alpha );
1112 HUDalphaTitle = new puText ( slider_title_x, slider_y ) ;
1113 HUDalphaTitle-> setDefaultValue ( "MaxAlpha" ) ;
1114 HUDalphaTitle-> getDefaultValue ( &s ) ;
1115 HUDalphaTitle-> setLabel ( s ) ;
1116 HUDalphaText = new puText ( slider_value_x, slider_y ) ;
1117 HUDalphaText-> setLabel ( SliderText[ 0 ] ) ;
1120 HUDalphaOkButton = new puOneShot ( 10, 10, 60, 50 );
1121 HUDalphaOkButton-> setLegend ( gui_msg_OK );
1122 HUDalphaOkButton-> makeReturnDefault ( TRUE );
1123 HUDalphaOkButton-> setCallback ( goAwayHUDalphaAdjust );
1125 FG_FINALIZE_PUI_DIALOG( HUDalphaDialog );
1132 // Performs a once around the list of calls to instruments installed in
1133 // the HUD object with requests for redraw. Kinda. It will when this is
1136 void fgUpdateHUD( void ) {
1138 // int day_night_sw = current_aircraft.controls->day_night_switch;
1139 int day_night_sw = global_day_night_switch;
1140 int hud_displays = HUD_deque.size();
1141 instr_item *pHUDInstr;
1144 if( !hud_displays ) { // Trust everyone, but ALWAYS cut the cards!
1148 HUD_TextList.erase();
1149 HUD_LineList.erase();
1150 // HUD_StippleLineList.erase();
1152 pHUDInstr = HUD_deque[0];
1153 brightness = pHUDInstr->get_brightness();
1154 // brightness = HUD_deque.at(0)->get_brightness();
1156 glMatrixMode(GL_PROJECTION);
1160 gluOrtho2D(0, 640, 0, 480);
1161 glMatrixMode(GL_MODELVIEW);
1165 glColor3f(1.0, 1.0, 1.0);
1168 glDisable(GL_DEPTH_TEST);
1169 glDisable(GL_LIGHTING);
1171 // #define ANTI_ALIAS_HUD
1172 #ifdef ANTI_ALIAS_HUD
1173 #define HUD_COLOR(r,g,b) glColor4f(r,g,b,hud_trans_alpha)
1174 glEnable(GL_LINE_SMOOTH);
1176 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1177 glHint(GL_LINE_SMOOTH_HINT,GL_DONT_CARE);
1180 #define HUD_COLOR(r,g,b) glColor3f(r,g,b)
1184 if( day_night_sw == DAY) {
1185 switch (brightness) {
1187 HUD_COLOR (0.1f, 0.9f, 0.1f);
1191 HUD_COLOR (0.1f, 0.7f, 0.0f);
1195 HUD_COLOR (0.0f, 0.6f, 0.0f);
1199 HUD_COLOR( 0.0f, 0.0f, 0.0f);
1203 HUD_COLOR (0.1f, 0.9f, 0.1f);
1207 if( day_night_sw == NIGHT) {
1208 switch (brightness) {
1210 HUD_COLOR (0.9f, 0.1f, 0.1f);
1214 HUD_COLOR (0.7f, 0.0f, 0.1f);
1219 HUD_COLOR (0.6f, 0.0f, 0.0f);
1222 else { // Just in case default
1223 HUD_COLOR (0.1f, 0.9f, 0.1f);
1227 deque < instr_item * > :: iterator current = HUD_deque.begin();
1228 deque < instr_item * > :: iterator last = HUD_deque.end();
1230 for ( ; current != last; ++current ) {
1231 pHUDInstr = *current;
1233 if( pHUDInstr->enabled()) {
1234 // fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d Status %d\n",
1235 // hud->code, hud->status );
1237 // HUD_deque.at(i)->draw(); // Responsible for broken or fixed variants.
1238 // No broken displays honored just now.
1242 char *gmt_str = get_formated_gmt_time();
1243 HUD_TextList.add( fgText(40, 10, gmt_str) );
1245 #ifdef FG_NETWORK_OLK
1246 if ( net_hud_display ) {
1253 // extern bool fgAPAltitudeEnabled( void );
1254 // extern bool fgAPHeadingEnabled( void );
1255 // extern bool fgAPWayPointEnabled( void );
1256 // extern char *fgAPget_TargetDistanceStr( void );
1257 // extern char *fgAPget_TargetHeadingStr( void );
1258 // extern char *fgAPget_TargetAltitudeStr( void );
1259 // extern char *fgAPget_TargetLatLonStr( void );
1262 // char scratch[128];
1263 // HUD_TextList.add( fgText( "AUTOPILOT", 20, apY) );
1265 if( current_autopilot->get_HeadingEnabled() ) {
1266 HUD_TextList.add( fgText( 40, apY,
1267 current_autopilot->get_TargetHeadingStr()) );
1270 if( current_autopilot->get_AltitudeEnabled() ) {
1271 HUD_TextList.add( fgText( 40, apY,
1272 current_autopilot->get_TargetAltitudeStr()) );
1275 if( current_autopilot->get_HeadingMode() ==
1276 FGAutopilot::FG_HEADING_WAYPOINT ) {
1277 HUD_TextList.add( fgText( 40, apY,
1278 current_autopilot->get_TargetLatLonStr()) );
1280 HUD_TextList.add( fgText( 40, apY,
1281 current_autopilot->get_TargetDistanceStr() ) );
1285 HUD_TextList.draw();
1287 HUD_LineList.draw();
1289 // glEnable(GL_LINE_STIPPLE);
1290 // glLineStipple( 1, 0x00FF );
1291 // HUD_StippleLineList.draw();
1292 // glDisable(GL_LINE_STIPPLE);
1295 #ifdef ANTI_ALIAS_HUD
1296 glDisable(GL_BLEND);
1297 glDisable(GL_LINE_SMOOTH);
1301 glEnable(GL_DEPTH_TEST);
1302 glEnable(GL_LIGHTING);
1303 glMatrixMode(GL_PROJECTION);
1305 glMatrixMode(GL_MODELVIEW);