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>
53 #include <Network/network.h>
54 #include <Scenery/scenery.hxx>
55 #include <Time/fg_timer.hxx>
57 #if defined ( __sun__ ) || defined ( __sgi )
59 extern void *memmove(void *, const void *, size_t);
67 // The following routines obtain information concerning the aircraft's
68 // current state and return it to calling instrument display routines.
69 // They should eventually be member functions of the aircraft.
72 deque< instr_item * > HUD_deque;
74 fgTextList HUD_TextList;
75 fgLineList HUD_LineList;
76 fgLineList HUD_StippleLineList;
82 locRECT( UINT left, UINT top, UINT right, UINT bottom);
83 RECT get_rect(void) { return rect;}
86 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
96 void drawOneLine( UINT x1, UINT y1, UINT x2, UINT y2)
104 void drawOneLine( RECT &rect)
107 glVertex2f(rect.left, rect.top);
108 glVertex2f(rect.right, rect.bottom);
113 // The following code deals with painting the "instrument" on the display
115 /* textString - Bitmap font string */
117 void textString( int x, int y, char *msg, void *font ){
121 // puDrawString ( NULL, msg, x, y );
125 glutBitmapCharacter(font, *msg);
132 /* strokeString - Stroke font string */
133 void strokeString(int x, int y, char *msg, void *font, float theta)
138 float sintheta,costheta;
144 glRotatef(theta * RAD_TO_DEG, 0.0, 0.0, 1.0);
145 sintheta = sin(theta);
146 costheta = cos(theta);
147 xx = (int)(x * costheta + y * sintheta);
148 yy = (int)(y * costheta - x * sintheta);
149 glTranslatef( xx, yy, 0);
150 glScalef(.1, .1, 0.0);
151 while( (c=*msg++) ) {
152 glutStrokeCharacter(font, c);
158 int getStringWidth ( char *str )
160 if ( HUDtext && str )
163 guiFntHandle->getBBox ( str, HUD_TextSize, 0, &l, &r, NULL, NULL ) ;
164 return FloatToInt( r - l );
169 //========================= End of Class Implementations===================
172 // Constructs a HUD object and then adds in instruments. At the present
173 // the instruments are hard coded into the routine. Ultimately these need
174 // to be defined by the aircraft's instrumentation records so that the
175 // display for a Piper Cub doesn't show the speed range of a North American
176 // mustange and the engine readouts of a B36!
181 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
188 int min_x = 25; //off/2;
189 int max_x = 615; //640-(off/2);
191 int max_y = 430; //480-off;
194 unsigned int text_h = 10;
195 unsigned int ladr_w2 = 60;
201 font_size = (current_options.get_xsize() > 1000) ? LARGE : SMALL;
205 FG_LOG( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD" );
207 // deque < instr_item * > :: iterator first = HUD_deque.begin();
208 // deque < instr_item * > :: iterator last = HUD_deque.end();
209 // HUD_deque.erase( first, last); // empty the HUD deque
211 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end()); // empty the HUD deque
216 // For now lets just hardcode the hud here.
217 // In the future, hud information has to come from the same place
218 // aircraft information came from.
220 // fgHUDSetTimeMode( hud, NIGHT );
221 // fgHUDSetBrightness( hud, BRT_LIGHT );
224 // int x = 290; /*cen_x-30*/
225 // int y = 45; /*off-5*/
226 // HIptr = (instr_item *) new fgTBI_instr( x, y, ladr_w2, text_h );
227 HIptr = (instr_item *) new fgTBI_instr( 290, 45, 60, 10 );
228 HUD_deque.insert( HUD_deque.begin(), HIptr);
230 // case 1: // Artificial Horizon
231 HIptr = (instr_item *) new HudLadder( cen_x-ladr_w2, cen_y-ladr_h2,
232 2*ladr_w2, 2*ladr_h2 );
233 HUD_deque.insert( HUD_deque.begin(), HIptr);
235 // case 4: // GYRO COMPASS
236 HIptr = (instr_item *) new hud_card( cen_x-(compass_w/2),
249 HUD_deque.insert( HUD_deque.begin(), HIptr);
252 HIptr = (instr_item *) new hud_card( max_x - 35 -15, // 15 to balance speed card
257 // HUDS_RIGHT | HUDS_VERT,
258 HUDS_LEFT | HUDS_VERT,
266 HUD_deque.insert( HUD_deque.begin(), HIptr);
269 HIptr = (instr_item *) new guage_instr( cen_x-50, // x
270 cen_y + ladr_h2 -20, // y
273 get_aileronval, // data source
274 HUDS_BOTTOM | HUDS_NOTEXT,
278 HUD_deque.insert( HUD_deque.begin(), HIptr);
280 // case 3: // Radio Altimeter
281 HIptr = (instr_item *) new hud_card( cen_x + ladr_w2 + gap + 13 + ladr_t,
286 HUDS_LEFT | HUDS_VERT,
294 HUD_deque.insert( HUD_deque.begin(), HIptr);
297 HIptr = (instr_item *) new guage_instr( cen_x -ladr_w2 -gap -13 -20 -ladr_t,
301 get_elevatorval, // data source
302 HUDS_RIGHT | HUDS_VERT | HUDS_NOTEXT,
303 -100.0, // Scale data
306 HUD_deque.insert( HUD_deque.begin(), HIptr);
309 HIptr = (instr_item *) new guage_instr( cen_x-50, // x
310 cen_y -gap -ladr_w2 -20, //-85 // y
313 get_rudderval, // data source
314 HUDS_TOP | HUDS_NOTEXT,
318 HUD_deque.insert( HUD_deque.begin(), HIptr);
321 HIptr = (instr_item *) new hud_card( min_x +10 +5, //min_x +18,
326 // HUDS_LEFT | HUDS_VERT,
327 HUDS_RIGHT | HUDS_VERT,
338 HUD_deque.insert( HUD_deque.begin(), HIptr);
341 // case 10: // Digital Mach number
342 HIptr = (instr_item *) new instr_label ( min_x , //same as speed tape
343 cen_y-(compass_w/2) -10, //below speed tape
356 HUD_deque.insert( HUD_deque.begin(), HIptr);
359 HIptr = (instr_item *) new guage_instr( min_x-10, // x
363 get_throttleval, // data source
364 // HUDS_VERT | HUDS_RIGHT | HUDS_NOTEXT,
365 HUDS_VERT | HUDS_LEFT | HUDS_NOTEXT, 100.0,
369 HUD_deque.insert( HUD_deque.begin(), HIptr);
370 // Remove this when below uncommented
372 HIptr = (instr_item *) new instr_label( 10,
386 HUD_deque.insert( HUD_deque.begin(), HIptr);
388 HIptr = (instr_item *) new lat_label( (cen_x - (compass_w/2))/2,
402 HUD_deque.insert( HUD_deque.begin(), HIptr);
404 HIptr = (instr_item *) new lon_label(((cen_x+compass_w/2)+(2*cen_x))/2,
417 HUD_deque.insert( HUD_deque.begin(), HIptr);
420 // case 10: // Digital KIAS
421 HIptr = (instr_item *) new instr_label ( 110,
435 HUD_deque.insert( HUD_deque.begin(), HIptr);
437 // case 11: // Digital Rate of Climb
438 HIptr = (instr_item *) new instr_label ( 110,
452 HUD_deque.insert( HUD_deque.begin(), HIptr);
454 // case 12: // Roll indication diagnostic
455 HIptr = (instr_item *) new instr_label ( 110,
469 HUD_deque.insert( HUD_deque.begin(), HIptr);
471 // case 13: // Angle of attack diagnostic
472 HIptr = (instr_item *) new instr_label ( 440,
486 HUD_deque.insert( HUD_deque.begin(), HIptr);
489 HIptr = (instr_item *) new instr_label ( 440,
503 HUD_deque.insert( HUD_deque.begin(), HIptr);
506 HIptr = (instr_item *) new instr_label ( 440,
520 HUD_deque.insert( HUD_deque.begin(), HIptr);
523 HIptr = (instr_item *) new instr_label( 440,
537 HUD_deque.insert( HUD_deque.begin(), HIptr);
540 HIptr = (instr_item *) new instr_label( 440,
554 HUD_deque.insert( HUD_deque.begin(), HIptr);
557 HIptr = (instr_item *) new instr_label( 440,
571 HUD_deque.insert( HUD_deque.begin(), HIptr);
574 HIptr = (instr_item *) new instr_label( 10,
588 HUD_deque.insert( HUD_deque.begin(), HIptr);
591 switch( current_options.get_tris_or_culled() ) {
593 HIptr = (instr_item *) new instr_label( 10,
609 HIptr = (instr_item *) new instr_label( 10,
628 HIptr = (instr_item *) new instr_label( 10,
642 HUD_deque.insert( HUD_deque.begin(), HIptr);
647 // if( HIptr ) { // Anything to install?
648 // HUD_deque.insert( HUD_deque.begin(), HIptr);
654 return 0; // For now. Later we may use this for an error code.
658 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
660 // instr_item *HIptr;
666 // int max_x = 640-off;
678 font_size = (current_options.get_xsize() > 1000) ? LARGE : SMALL;
682 FG_LOG( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD" );
684 // deque < instr_item * > :: iterator first = HUD_deque.begin();
685 // deque < instr_item * > :: iterator last = HUD_deque.end();
686 // HUD_deque.erase( first, last); // empty the HUD deque
687 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());
692 // For now lets just hardcode the hud here.
693 // In the future, hud information has to come from the same place
694 // aircraft information came from.
696 // fgHUDSetTimeMode( hud, NIGHT );
697 // fgHUDSetBrightness( hud, BRT_LIGHT );
704 p = new HudLadder( cen_x-ladr_w2, cen_y-ladr_h2, 2*ladr_w2, 2*ladr_h2, 1 );
705 HUD_deque.push_front( p );
707 // case 4: // GYRO COMPASS
708 p =new hud_card( cen_x-(compass_w/2),
721 HUD_deque.push_front( p );
723 p = new lat_label( (cen_x - compass_w/2)/2,
736 HUD_deque.push_front( p );
738 // p = new instr_label( 140, 450, 60, 10,
749 // HUD_deque.push_front( p );
751 p = new lon_label(((cen_x+compass_w/2)+(2*cen_x))/2,
764 HUD_deque.push_front( p );
768 p = new instr_label( x_pos, 25, 60, 10,
779 HUD_deque.push_front( p );
781 p = new instr_label( x_pos, 40, 120, 10,
792 HUD_deque.push_front( p );
794 p = new instr_label( x_pos, 55, 120, 10,
805 HUD_deque.push_front( p );
808 // p = new instr_label( x_pos, 70, 90, 10,
809 p = new instr_label( x_pos, 40, 90, 10,
820 HUD_deque.push_front( p );
824 p = new instr_label ( x_pos,
838 HUD_deque.push_front( p );
840 p = new instr_label( x_pos, 55, 40, 30,
851 HUD_deque.push_front( p );
853 if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET ) {
854 strcpy(units, " ft");
858 p = new instr_label( x_pos, 40, 40, 10,
869 HUD_deque.push_front( p );
871 p = new instr_label( x_pos, 25, 40, 10,
882 HUD_deque.push_front( p );
884 p = new instr_label( x_pos, 10, 60, 10,
895 HUD_deque.push_front( p );
897 p = new fgTBI_instr( 290, 55, 60, 10 ); // 270
898 HUD_deque.push_front( p );
900 p = new guage_instr( 270, //250, // x
901 390, //360, //400, //45, //420, // y
904 get_aileronval, // data source
905 HUDS_BOTTOM | HUDS_NOTEXT,
909 HUD_deque.push_front( p );
911 p = new guage_instr( 20, // x
915 get_elevatorval, // data source
916 HUDS_RIGHT | HUDS_VERT | HUDS_NOTEXT,
917 -100.0, // Scale data
920 HUD_deque.push_front( p );
922 p = new guage_instr( 270, //250, // x
926 get_rudderval, // data source
927 HUDS_TOP | HUDS_NOTEXT,
931 HUD_deque.push_front( p );
933 p = new guage_instr( 600, // x
937 get_throttleval, // data source
938 HUDS_VERT | HUDS_LEFT | HUDS_NOTEXT,
942 HUD_deque.push_front( p );
944 return 0; // For now. Later we may use this for an error code.
947 int global_day_night_switch = DAY;
949 void HUD_brightkey( bool incr_bright )
951 instr_item *pHUDInstr = HUD_deque[0];
952 int brightness = pHUDInstr->get_brightness();
954 if( current_options.get_hud_status() ) {
956 switch (brightness) {
958 current_options.set_hud_status(0);
962 brightness = BRT_LIGHT;
966 brightness = BRT_MEDIUM;
970 brightness = BRT_DARK;
974 brightness = BRT_BLACK;
978 switch (brightness) {
980 brightness = BRT_MEDIUM;
984 brightness = BRT_DARK;
988 brightness = BRT_BLACK;
993 current_options.set_hud_status(0);
998 current_options.set_hud_status(1);
1000 if( DAY == global_day_night_switch ) {
1001 brightness = BRT_BLACK;
1004 brightness = BRT_DARK;
1005 global_day_night_switch = DAY;
1009 if( NIGHT == global_day_night_switch ) {
1010 brightness = BRT_DARK;
1013 brightness = BRT_MEDIUM;
1014 global_day_night_switch = NIGHT;
1018 pHUDInstr->SetBrightness( brightness );
1024 // Performs a once around the list of calls to instruments installed in
1025 // the HUD object with requests for redraw. Kinda. It will when this is
1028 void fgUpdateHUD( void ) {
1030 // int day_night_sw = current_aircraft.controls->day_night_switch;
1031 int day_night_sw = global_day_night_switch;
1032 int hud_displays = HUD_deque.size();
1033 instr_item *pHUDInstr;
1036 if( !hud_displays ) { // Trust everyone, but ALWAYS cut the cards!
1040 HUD_TextList.erase();
1041 HUD_LineList.erase();
1042 // HUD_StippleLineList.erase();
1044 pHUDInstr = HUD_deque[0];
1045 brightness = pHUDInstr->get_brightness();
1046 // brightness = HUD_deque.at(0)->get_brightness();
1048 glMatrixMode(GL_PROJECTION);
1052 gluOrtho2D(0, 640, 0, 480);
1053 glMatrixMode(GL_MODELVIEW);
1057 glColor3f(1.0, 1.0, 1.0);
1060 glDisable(GL_DEPTH_TEST);
1061 glDisable(GL_LIGHTING);
1063 // We can do translucency, so why not. :-)
1064 // glEnable ( GL_BLEND ) ;
1065 // glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
1067 if( day_night_sw == DAY) {
1068 switch (brightness) {
1070 // glColor4f (0.1, 0.9, 0.1, 0.75);
1071 glColor3f (0.1, 0.9, 0.1);
1075 // glColor4f (0.1, 0.7, 0.0, 0.75);
1076 glColor3f (0.1, 0.7, 0.0);
1080 // glColor4f (0.0, 0.6, 0.0, 0.75);
1081 glColor3f(0.0, 0.6, 0.0);
1085 // glColor4f( 0.0, 0.0, 0.0, 0.75);
1086 glColor3f( 0.0, 0.0, 0.0);
1093 if( day_night_sw == NIGHT) {
1094 switch (brightness) {
1096 // glColor4f (0.9, 0.1, 0.1, 0.75);
1097 glColor3f (0.9, 0.1, 0.1);
1101 // glColor4f (0.7, 0.0, 0.1, 0.75);
1102 glColor3f (0.7, 0.0, 0.1);
1107 // glColor4f (0.6, 0.0, 0.0, 0.75);
1108 glColor3f (0.6, 0.0, 0.0);
1111 else { // Just in case default
1112 // glColor4f (0.1, 0.9, 0.1, 0.75);
1113 glColor3f (0.1, 0.9, 0.1);
1117 deque < instr_item * > :: iterator current = HUD_deque.begin();
1118 deque < instr_item * > :: iterator last = HUD_deque.end();
1120 for ( ; current != last; ++current ) {
1121 pHUDInstr = *current;
1123 if( pHUDInstr->enabled()) {
1124 // fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d Status %d\n",
1125 // hud->code, hud->status );
1127 // HUD_deque.at(i)->draw(); // Responsible for broken or fixed variants.
1128 // No broken displays honored just now.
1132 char *gmt_str = get_formated_gmt_time();
1133 HUD_TextList.add( fgText( 40, 10, gmt_str) );
1135 #ifdef FG_NETWORK_OLK
1136 if ( net_hud_display ) {
1141 HUD_TextList.draw();
1143 line_width = (current_options.get_xsize() > 1000) ? 1.0 : 0.5;
1144 glLineWidth(line_width);
1145 HUD_LineList.draw();
1147 // glEnable(GL_LINE_STIPPLE);
1148 // glLineStipple( 1, 0x00FF );
1149 // HUD_StippleLineList.draw();
1150 // glDisable(GL_LINE_STIPPLE);
1152 // glDisable( GL_BLEND );
1154 glEnable(GL_DEPTH_TEST);
1155 glEnable(GL_LIGHTING);
1156 glMatrixMode(GL_PROJECTION);
1158 glMatrixMode(GL_MODELVIEW);
1166 // Performs a once around the list of calls to instruments installed in
1167 // the HUD object with requests for redraw. Kinda. It will when this is
1170 void fgUpdateHUD( void ) {
1172 // int day_night_sw = current_aircraft.controls->day_night_switch;
1173 int day_night_sw = global_day_night_switch;
1174 int hud_displays = HUD_deque.size();
1175 instr_item *pHUDInstr;
1178 if( !hud_displays ) { // Trust everyone, but ALWAYS cut the cards!
1182 HUD_TextList.erase();
1183 HUD_LineList.erase();
1184 // HUD_StippleLineList.erase();
1186 pHUDInstr = HUD_deque[0];
1187 brightness = pHUDInstr->get_brightness();
1188 // brightness = HUD_deque.at(0)->get_brightness();
1190 glMatrixMode(GL_PROJECTION);
1194 gluOrtho2D(0, 640, 0, 480);
1195 glMatrixMode(GL_MODELVIEW);
1199 glColor3f(1.0, 1.0, 1.0);
1202 glDisable(GL_DEPTH_TEST);
1203 glDisable(GL_LIGHTING);
1205 // We can do translucency, so why not. :-)
1206 // glEnable ( GL_BLEND ) ;
1207 // glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
1209 if( day_night_sw == DAY) {
1210 switch (brightness) {
1212 // glColor4f (0.1, 0.9, 0.1, 0.75);
1213 glColor3f (0.1, 0.9, 0.1);
1217 // glColor4f (0.1, 0.7, 0.0, 0.75);
1218 glColor3f (0.1, 0.7, 0.0);
1222 // glColor4f (0.0, 0.6, 0.0, 0.75);
1223 glColor3f(0.0, 0.6, 0.0);
1227 // glColor4f( 0.0, 0.0, 0.0, 0.75);
1228 glColor3f( 0.0, 0.0, 0.0);
1235 if( day_night_sw == NIGHT) {
1236 switch (brightness) {
1238 // glColor4f (0.9, 0.1, 0.1, 0.75);
1239 glColor3f (0.9, 0.1, 0.1);
1243 // glColor4f (0.7, 0.0, 0.1, 0.75);
1244 glColor3f (0.7, 0.0, 0.1);
1249 // glColor4f (0.6, 0.0, 0.0, 0.75);
1250 glColor3f (0.6, 0.0, 0.0);
1253 else { // Just in case default
1254 // glColor4f (0.1, 0.9, 0.1, 0.75);
1255 glColor3f (0.1, 0.9, 0.1);
1259 deque < instr_item * > :: iterator current = HUD_deque.begin();
1260 deque < instr_item * > :: iterator last = HUD_deque.end();
1262 for ( ; current != last; ++current ) {
1263 pHUDInstr = *current;
1265 if( pHUDInstr->enabled()) {
1266 // fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d Status %d\n",
1267 // hud->code, hud->status );
1269 // HUD_deque.at(i)->draw(); // Responsible for broken or fixed variants.
1270 // No broken displays honored just now.
1274 char *gmt_str = get_formated_gmt_time();
1275 HUD_TextList.add( fgText(40, 10, gmt_str) );
1278 extern bool fgAPAltitudeEnabled( void );
1279 extern bool fgAPHeadingEnabled( void );
1280 extern bool fgAPWayPointEnabled( void );
1281 extern char *fgAPget_TargetDistanceStr( void );
1282 extern char *fgAPget_TargetHeadingStr( void );
1283 extern char *fgAPget_TargetAltitudeStr( void );
1284 extern char *fgAPget_TargetLatLonStr( void );
1287 // char scratch[128];
1288 // HUD_TextList.add( fgText( "AUTOPILOT", 20, apY) );
1290 if( fgAPHeadingEnabled() ) {
1291 HUD_TextList.add( fgText( 40, apY, fgAPget_TargetHeadingStr()) );
1294 if( fgAPAltitudeEnabled() ) {
1295 HUD_TextList.add( fgText( 40, apY, fgAPget_TargetAltitudeStr()) );
1298 if( fgAPWayPointEnabled() ) {
1299 HUD_TextList.add( fgText( 40, apY, fgAPget_TargetLatLonStr()) );
1301 HUD_TextList.add( fgText( 40, apY, fgAPget_TargetDistanceStr() ) );
1305 HUD_TextList.draw();
1307 line_width = (current_options.get_xsize() > 1000) ? 1.0 : 0.5;
1308 glLineWidth(line_width);
1309 HUD_LineList.draw();
1311 // glEnable(GL_LINE_STIPPLE);
1312 // glLineStipple( 1, 0x00FF );
1313 // HUD_StippleLineList.draw();
1314 // glDisable(GL_LINE_STIPPLE);
1316 // glDisable( GL_BLEND );
1318 glEnable(GL_DEPTH_TEST);
1319 glEnable(GL_LIGHTING);
1320 glMatrixMode(GL_PROJECTION);
1322 glMatrixMode(GL_MODELVIEW);