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 <Aircraft/aircraft.hxx>
46 #include <Debug/logstream.hxx>
48 #include <Include/fg_constants.h>
49 #include <Main/options.hxx>
50 #include <Math/fg_random.h>
51 #include <Math/mat3.h>
52 #include <Math/polar3d.hxx>
54 #include <NetworkOLK/network.h>
56 #include <Scenery/scenery.hxx>
57 #include <Time/fg_timer.hxx>
59 #if defined ( __sun__ ) || defined ( __sgi )
61 extern void *memmove(void *, const void *, size_t);
69 // The following routines obtain information concerning the aircraft's
70 // current state and return it to calling instrument display routines.
71 // They should eventually be member functions of the aircraft.
74 deque< instr_item * > HUD_deque;
76 fgTextList HUD_TextList;
77 fgLineList HUD_LineList;
78 fgLineList HUD_StippleLineList;
84 locRECT( UINT left, UINT top, UINT right, UINT bottom);
85 RECT get_rect(void) { return rect;}
88 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
98 void drawOneLine( UINT x1, UINT y1, UINT x2, UINT y2)
106 void drawOneLine( RECT &rect)
109 glVertex2f(rect.left, rect.top);
110 glVertex2f(rect.right, rect.bottom);
115 // The following code deals with painting the "instrument" on the display
117 /* textString - Bitmap font string */
119 void textString( int x, int y, char *msg, void *font ){
123 // puDrawString ( NULL, msg, x, y );
127 glutBitmapCharacter(font, *msg);
134 /* strokeString - Stroke font string */
135 void strokeString(int x, int y, char *msg, void *font, float theta)
140 float sintheta,costheta;
146 glRotatef(theta * RAD_TO_DEG, 0.0, 0.0, 1.0);
147 sintheta = sin(theta);
148 costheta = cos(theta);
149 xx = (int)(x * costheta + y * sintheta);
150 yy = (int)(y * costheta - x * sintheta);
151 glTranslatef( xx, yy, 0);
152 glScalef(.1, .1, 0.0);
153 while( (c=*msg++) ) {
154 glutStrokeCharacter(font, c);
160 int getStringWidth ( char *str )
162 if ( HUDtext && str )
165 guiFntHandle->getBBox ( str, HUD_TextSize, 0, &l, &r, NULL, NULL ) ;
166 return FloatToInt( r - l );
171 //========================= End of Class Implementations===================
174 // Constructs a HUD object and then adds in instruments. At the present
175 // the instruments are hard coded into the routine. Ultimately these need
176 // to be defined by the aircraft's instrumentation records so that the
177 // display for a Piper Cub doesn't show the speed range of a North American
178 // mustange and the engine readouts of a B36!
183 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
190 int min_x = 25; //off/2;
191 int max_x = 615; //640-(off/2);
193 int max_y = 430; //480-off;
196 unsigned int text_h = 10;
197 unsigned int ladr_w2 = 60;
203 font_size = (current_options.get_xsize() > 1000) ? LARGE : SMALL;
207 FG_LOG( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD" );
209 // deque < instr_item * > :: iterator first = HUD_deque.begin();
210 // deque < instr_item * > :: iterator last = HUD_deque.end();
211 // HUD_deque.erase( first, last); // empty the HUD deque
213 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end()); // empty the HUD deque
218 // For now lets just hardcode the hud here.
219 // In the future, hud information has to come from the same place
220 // aircraft information came from.
222 // fgHUDSetTimeMode( hud, NIGHT );
223 // fgHUDSetBrightness( hud, BRT_LIGHT );
226 // int x = 290; /*cen_x-30*/
227 // int y = 45; /*off-5*/
228 // HIptr = (instr_item *) new fgTBI_instr( x, y, ladr_w2, text_h );
229 HIptr = (instr_item *) new fgTBI_instr( 290, 45, 60, 10 );
230 HUD_deque.insert( HUD_deque.begin(), HIptr);
232 // case 1: // Artificial Horizon
233 HIptr = (instr_item *) new HudLadder( cen_x-ladr_w2, cen_y-ladr_h2,
234 2*ladr_w2, 2*ladr_h2 );
235 HUD_deque.insert( HUD_deque.begin(), HIptr);
237 // case 4: // GYRO COMPASS
238 HIptr = (instr_item *) new hud_card( cen_x-(compass_w/2),
251 HUD_deque.insert( HUD_deque.begin(), HIptr);
254 HIptr = (instr_item *) new hud_card( max_x - 35 -15, // 15 to balance speed card
259 // HUDS_RIGHT | HUDS_VERT,
260 HUDS_LEFT | HUDS_VERT,
268 HUD_deque.insert( HUD_deque.begin(), HIptr);
271 HIptr = (instr_item *) new guage_instr( cen_x-50, // x
272 cen_y + ladr_h2 -20, // y
275 get_aileronval, // data source
276 HUDS_BOTTOM | HUDS_NOTEXT,
280 HUD_deque.insert( HUD_deque.begin(), HIptr);
282 // case 3: // Radio Altimeter
283 HIptr = (instr_item *) new hud_card( cen_x + ladr_w2 + gap + 13 + ladr_t,
288 HUDS_LEFT | HUDS_VERT,
296 HUD_deque.insert( HUD_deque.begin(), HIptr);
299 HIptr = (instr_item *) new guage_instr( cen_x -ladr_w2 -gap -13 -20 -ladr_t,
303 get_elevatorval, // data source
304 HUDS_RIGHT | HUDS_VERT | HUDS_NOTEXT,
305 -100.0, // Scale data
308 HUD_deque.insert( HUD_deque.begin(), HIptr);
311 HIptr = (instr_item *) new guage_instr( cen_x-50, // x
312 cen_y -gap -ladr_w2 -20, //-85 // y
315 get_rudderval, // data source
316 HUDS_TOP | HUDS_NOTEXT,
320 HUD_deque.insert( HUD_deque.begin(), HIptr);
323 HIptr = (instr_item *) new hud_card( min_x +10 +5, //min_x +18,
328 // HUDS_LEFT | HUDS_VERT,
329 HUDS_RIGHT | HUDS_VERT,
340 HUD_deque.insert( HUD_deque.begin(), HIptr);
343 // case 10: // Digital Mach number
344 HIptr = (instr_item *) new instr_label ( min_x , //same as speed tape
345 cen_y-(compass_w/2) -10, //below speed tape
358 HUD_deque.insert( HUD_deque.begin(), HIptr);
361 HIptr = (instr_item *) new guage_instr( min_x-10, // x
365 get_throttleval, // data source
366 // HUDS_VERT | HUDS_RIGHT | HUDS_NOTEXT,
367 HUDS_VERT | HUDS_LEFT | HUDS_NOTEXT, 100.0,
371 HUD_deque.insert( HUD_deque.begin(), HIptr);
372 // Remove this when below uncommented
374 HIptr = (instr_item *) new instr_label( 10,
388 HUD_deque.insert( HUD_deque.begin(), HIptr);
390 HIptr = (instr_item *) new lat_label( (cen_x - (compass_w/2))/2,
404 HUD_deque.insert( HUD_deque.begin(), HIptr);
406 HIptr = (instr_item *) new lon_label(((cen_x+compass_w/2)+(2*cen_x))/2,
419 HUD_deque.insert( HUD_deque.begin(), HIptr);
422 // case 10: // Digital KIAS
423 HIptr = (instr_item *) new instr_label ( 110,
437 HUD_deque.insert( HUD_deque.begin(), HIptr);
439 // case 11: // Digital Rate of Climb
440 HIptr = (instr_item *) new instr_label ( 110,
454 HUD_deque.insert( HUD_deque.begin(), HIptr);
456 // case 12: // Roll indication diagnostic
457 HIptr = (instr_item *) new instr_label ( 110,
471 HUD_deque.insert( HUD_deque.begin(), HIptr);
473 // case 13: // Angle of attack diagnostic
474 HIptr = (instr_item *) new instr_label ( 440,
488 HUD_deque.insert( HUD_deque.begin(), HIptr);
491 HIptr = (instr_item *) new instr_label ( 440,
505 HUD_deque.insert( HUD_deque.begin(), HIptr);
508 HIptr = (instr_item *) new instr_label ( 440,
522 HUD_deque.insert( HUD_deque.begin(), HIptr);
525 HIptr = (instr_item *) new instr_label( 440,
539 HUD_deque.insert( HUD_deque.begin(), HIptr);
542 HIptr = (instr_item *) new instr_label( 440,
556 HUD_deque.insert( HUD_deque.begin(), HIptr);
559 HIptr = (instr_item *) new instr_label( 440,
573 HUD_deque.insert( HUD_deque.begin(), HIptr);
576 HIptr = (instr_item *) new instr_label( 10,
590 HUD_deque.insert( HUD_deque.begin(), HIptr);
593 switch( current_options.get_tris_or_culled() ) {
595 HIptr = (instr_item *) new instr_label( 10,
611 HIptr = (instr_item *) new instr_label( 10,
630 HIptr = (instr_item *) new instr_label( 10,
644 HUD_deque.insert( HUD_deque.begin(), HIptr);
649 // if( HIptr ) { // Anything to install?
650 // HUD_deque.insert( HUD_deque.begin(), HIptr);
656 return 0; // For now. Later we may use this for an error code.
660 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
662 // instr_item *HIptr;
668 // int max_x = 640-off;
680 font_size = (current_options.get_xsize() > 1000) ? LARGE : SMALL;
684 FG_LOG( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD" );
686 // deque < instr_item * > :: iterator first = HUD_deque.begin();
687 // deque < instr_item * > :: iterator last = HUD_deque.end();
688 // HUD_deque.erase( first, last); // empty the HUD deque
689 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());
694 // For now lets just hardcode the hud here.
695 // In the future, hud information has to come from the same place
696 // aircraft information came from.
698 // fgHUDSetTimeMode( hud, NIGHT );
699 // fgHUDSetBrightness( hud, BRT_LIGHT );
706 p = new HudLadder( cen_x-ladr_w2, cen_y-ladr_h2, 2*ladr_w2, 2*ladr_h2, 1 );
707 HUD_deque.push_front( p );
709 // case 4: // GYRO COMPASS
710 p =new hud_card( cen_x-(compass_w/2),
723 HUD_deque.push_front( p );
725 p = new lat_label( (cen_x - compass_w/2)/2,
738 HUD_deque.push_front( p );
740 // p = new instr_label( 140, 450, 60, 10,
751 // HUD_deque.push_front( p );
753 p = new lon_label(((cen_x+compass_w/2)+(2*cen_x))/2,
766 HUD_deque.push_front( p );
770 p = new instr_label( x_pos, 25, 60, 10,
781 HUD_deque.push_front( p );
783 p = new instr_label( x_pos, 40, 120, 10,
794 HUD_deque.push_front( p );
796 p = new instr_label( x_pos, 55, 120, 10,
807 HUD_deque.push_front( p );
810 // p = new instr_label( x_pos, 70, 90, 10,
811 p = new instr_label( x_pos, 40, 90, 10,
822 HUD_deque.push_front( p );
826 p = new instr_label ( x_pos,
840 HUD_deque.push_front( p );
842 p = new instr_label( x_pos, 55, 40, 30,
853 HUD_deque.push_front( p );
855 if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET ) {
856 strcpy(units, " ft");
860 p = new instr_label( x_pos, 40, 40, 10,
871 HUD_deque.push_front( p );
873 p = new instr_label( x_pos, 25, 40, 10,
884 HUD_deque.push_front( p );
886 p = new instr_label( x_pos, 10, 60, 10,
897 HUD_deque.push_front( p );
899 p = new fgTBI_instr( 290, 55, 60, 10 ); // 270
900 HUD_deque.push_front( p );
902 p = new guage_instr( 270, //250, // x
903 390, //360, //400, //45, //420, // y
906 get_aileronval, // data source
907 HUDS_BOTTOM | HUDS_NOTEXT,
911 HUD_deque.push_front( p );
913 p = new guage_instr( 20, // x
917 get_elevatorval, // data source
918 HUDS_RIGHT | HUDS_VERT | HUDS_NOTEXT,
919 -100.0, // Scale data
922 HUD_deque.push_front( p );
924 p = new guage_instr( 270, //250, // x
928 get_rudderval, // data source
929 HUDS_TOP | HUDS_NOTEXT,
933 HUD_deque.push_front( p );
935 p = new guage_instr( 600, // x
939 get_throttleval, // data source
940 HUDS_VERT | HUDS_LEFT | HUDS_NOTEXT,
944 HUD_deque.push_front( p );
946 return 0; // For now. Later we may use this for an error code.
949 int global_day_night_switch = DAY;
951 void HUD_brightkey( bool incr_bright )
953 instr_item *pHUDInstr = HUD_deque[0];
954 int brightness = pHUDInstr->get_brightness();
956 if( current_options.get_hud_status() ) {
958 switch (brightness) {
960 current_options.set_hud_status(0);
964 brightness = BRT_LIGHT;
968 brightness = BRT_MEDIUM;
972 brightness = BRT_DARK;
976 brightness = BRT_BLACK;
980 switch (brightness) {
982 brightness = BRT_MEDIUM;
986 brightness = BRT_DARK;
990 brightness = BRT_BLACK;
995 current_options.set_hud_status(0);
1000 current_options.set_hud_status(1);
1002 if( DAY == global_day_night_switch ) {
1003 brightness = BRT_BLACK;
1006 brightness = BRT_DARK;
1007 global_day_night_switch = DAY;
1011 if( NIGHT == global_day_night_switch ) {
1012 brightness = BRT_DARK;
1015 brightness = BRT_MEDIUM;
1016 global_day_night_switch = NIGHT;
1020 pHUDInstr->SetBrightness( brightness );
1026 // Performs a once around the list of calls to instruments installed in
1027 // the HUD object with requests for redraw. Kinda. It will when this is
1030 void fgUpdateHUD( void ) {
1032 // int day_night_sw = current_aircraft.controls->day_night_switch;
1033 int day_night_sw = global_day_night_switch;
1034 int hud_displays = HUD_deque.size();
1035 instr_item *pHUDInstr;
1038 if( !hud_displays ) { // Trust everyone, but ALWAYS cut the cards!
1042 HUD_TextList.erase();
1043 HUD_LineList.erase();
1044 // HUD_StippleLineList.erase();
1046 pHUDInstr = HUD_deque[0];
1047 brightness = pHUDInstr->get_brightness();
1048 // brightness = HUD_deque.at(0)->get_brightness();
1050 glMatrixMode(GL_PROJECTION);
1054 gluOrtho2D(0, 640, 0, 480);
1055 glMatrixMode(GL_MODELVIEW);
1059 glColor3f(1.0, 1.0, 1.0);
1062 glDisable(GL_DEPTH_TEST);
1063 glDisable(GL_LIGHTING);
1065 // We can do translucency, so why not. :-)
1066 // glEnable ( GL_BLEND ) ;
1067 // glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
1069 if( day_night_sw == DAY) {
1070 switch (brightness) {
1072 // glColor4f (0.1, 0.9, 0.1, 0.75);
1073 glColor3f (0.1, 0.9, 0.1);
1077 // glColor4f (0.1, 0.7, 0.0, 0.75);
1078 glColor3f (0.1, 0.7, 0.0);
1082 // glColor4f (0.0, 0.6, 0.0, 0.75);
1083 glColor3f(0.0, 0.6, 0.0);
1087 // glColor4f( 0.0, 0.0, 0.0, 0.75);
1088 glColor3f( 0.0, 0.0, 0.0);
1095 if( day_night_sw == NIGHT) {
1096 switch (brightness) {
1098 // glColor4f (0.9, 0.1, 0.1, 0.75);
1099 glColor3f (0.9, 0.1, 0.1);
1103 // glColor4f (0.7, 0.0, 0.1, 0.75);
1104 glColor3f (0.7, 0.0, 0.1);
1109 // glColor4f (0.6, 0.0, 0.0, 0.75);
1110 glColor3f (0.6, 0.0, 0.0);
1113 else { // Just in case default
1114 // glColor4f (0.1, 0.9, 0.1, 0.75);
1115 glColor3f (0.1, 0.9, 0.1);
1119 deque < instr_item * > :: iterator current = HUD_deque.begin();
1120 deque < instr_item * > :: iterator last = HUD_deque.end();
1122 for ( ; current != last; ++current ) {
1123 pHUDInstr = *current;
1125 if( pHUDInstr->enabled()) {
1126 // fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d Status %d\n",
1127 // hud->code, hud->status );
1129 // HUD_deque.at(i)->draw(); // Responsible for broken or fixed variants.
1130 // No broken displays honored just now.
1134 char *gmt_str = get_formated_gmt_time();
1135 HUD_TextList.add( fgText( 40, 10, gmt_str) );
1137 #ifdef FG_NETWORK_OLK
1138 if ( net_hud_display ) {
1143 HUD_TextList.draw();
1145 line_width = (current_options.get_xsize() > 1000) ? 1.0 : 0.5;
1146 glLineWidth(line_width);
1147 HUD_LineList.draw();
1149 // glEnable(GL_LINE_STIPPLE);
1150 // glLineStipple( 1, 0x00FF );
1151 // HUD_StippleLineList.draw();
1152 // glDisable(GL_LINE_STIPPLE);
1154 // glDisable( GL_BLEND );
1156 glEnable(GL_DEPTH_TEST);
1157 glEnable(GL_LIGHTING);
1158 glMatrixMode(GL_PROJECTION);
1160 glMatrixMode(GL_MODELVIEW);
1168 // Performs a once around the list of calls to instruments installed in
1169 // the HUD object with requests for redraw. Kinda. It will when this is
1172 void fgUpdateHUD( void ) {
1174 // int day_night_sw = current_aircraft.controls->day_night_switch;
1175 int day_night_sw = global_day_night_switch;
1176 int hud_displays = HUD_deque.size();
1177 instr_item *pHUDInstr;
1180 if( !hud_displays ) { // Trust everyone, but ALWAYS cut the cards!
1184 HUD_TextList.erase();
1185 HUD_LineList.erase();
1186 // HUD_StippleLineList.erase();
1188 pHUDInstr = HUD_deque[0];
1189 brightness = pHUDInstr->get_brightness();
1190 // brightness = HUD_deque.at(0)->get_brightness();
1192 glMatrixMode(GL_PROJECTION);
1196 gluOrtho2D(0, 640, 0, 480);
1197 glMatrixMode(GL_MODELVIEW);
1201 glColor3f(1.0, 1.0, 1.0);
1204 glDisable(GL_DEPTH_TEST);
1205 glDisable(GL_LIGHTING);
1207 // We can do translucency, so why not. :-)
1208 // glEnable ( GL_BLEND ) ;
1209 // glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
1211 if( day_night_sw == DAY) {
1212 switch (brightness) {
1214 // glColor4f (0.1, 0.9, 0.1, 0.75);
1215 glColor3f (0.1, 0.9, 0.1);
1219 // glColor4f (0.1, 0.7, 0.0, 0.75);
1220 glColor3f (0.1, 0.7, 0.0);
1224 // glColor4f (0.0, 0.6, 0.0, 0.75);
1225 glColor3f(0.0, 0.6, 0.0);
1229 // glColor4f( 0.0, 0.0, 0.0, 0.75);
1230 glColor3f( 0.0, 0.0, 0.0);
1237 if( day_night_sw == NIGHT) {
1238 switch (brightness) {
1240 // glColor4f (0.9, 0.1, 0.1, 0.75);
1241 glColor3f (0.9, 0.1, 0.1);
1245 // glColor4f (0.7, 0.0, 0.1, 0.75);
1246 glColor3f (0.7, 0.0, 0.1);
1251 // glColor4f (0.6, 0.0, 0.0, 0.75);
1252 glColor3f (0.6, 0.0, 0.0);
1255 else { // Just in case default
1256 // glColor4f (0.1, 0.9, 0.1, 0.75);
1257 glColor3f (0.1, 0.9, 0.1);
1261 deque < instr_item * > :: iterator current = HUD_deque.begin();
1262 deque < instr_item * > :: iterator last = HUD_deque.end();
1264 for ( ; current != last; ++current ) {
1265 pHUDInstr = *current;
1267 if( pHUDInstr->enabled()) {
1268 // fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d Status %d\n",
1269 // hud->code, hud->status );
1271 // HUD_deque.at(i)->draw(); // Responsible for broken or fixed variants.
1272 // No broken displays honored just now.
1276 char *gmt_str = get_formated_gmt_time();
1277 HUD_TextList.add( fgText(40, 10, gmt_str) );
1279 #ifdef FG_NETWORK_OLK
1280 if ( net_hud_display ) {
1287 extern bool fgAPAltitudeEnabled( void );
1288 extern bool fgAPHeadingEnabled( void );
1289 extern bool fgAPWayPointEnabled( void );
1290 extern char *fgAPget_TargetDistanceStr( void );
1291 extern char *fgAPget_TargetHeadingStr( void );
1292 extern char *fgAPget_TargetAltitudeStr( void );
1293 extern char *fgAPget_TargetLatLonStr( void );
1296 // char scratch[128];
1297 // HUD_TextList.add( fgText( "AUTOPILOT", 20, apY) );
1299 if( fgAPHeadingEnabled() ) {
1300 HUD_TextList.add( fgText( 40, apY, fgAPget_TargetHeadingStr()) );
1303 if( fgAPAltitudeEnabled() ) {
1304 HUD_TextList.add( fgText( 40, apY, fgAPget_TargetAltitudeStr()) );
1307 if( fgAPWayPointEnabled() ) {
1308 HUD_TextList.add( fgText( 40, apY, fgAPget_TargetLatLonStr()) );
1310 HUD_TextList.add( fgText( 40, apY, fgAPget_TargetDistanceStr() ) );
1314 HUD_TextList.draw();
1316 line_width = (current_options.get_xsize() > 1000) ? 1.0 : 0.5;
1317 glLineWidth(line_width);
1318 HUD_LineList.draw();
1320 // glEnable(GL_LINE_STIPPLE);
1321 // glLineStipple( 1, 0x00FF );
1322 // HUD_StippleLineList.draw();
1323 // glDisable(GL_LINE_STIPPLE);
1325 // glDisable( GL_BLEND );
1327 glEnable(GL_DEPTH_TEST);
1328 glEnable(GL_LIGHTING);
1329 glMatrixMode(GL_PROJECTION);
1331 glMatrixMode(GL_MODELVIEW);