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;
85 locRECT( UINT left, UINT top, UINT right, UINT bottom);
86 RECT get_rect(void) { return rect;}
89 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
99 void drawOneLine( UINT x1, UINT y1, UINT x2, UINT y2)
107 void drawOneLine( RECT &rect)
110 glVertex2f(rect.left, rect.top);
111 glVertex2f(rect.right, rect.bottom);
116 // The following code deals with painting the "instrument" on the display
118 /* textString - Bitmap font string */
120 void textString( int x, int y, char *msg, void *font ){
124 // puDrawString ( NULL, msg, x, y );
128 glutBitmapCharacter(font, *msg);
135 /* strokeString - Stroke font string */
136 void strokeString(int x, int y, char *msg, void *font, float theta)
141 float sintheta,costheta;
147 glRotatef(theta * RAD_TO_DEG, 0.0, 0.0, 1.0);
148 sintheta = sin(theta);
149 costheta = cos(theta);
150 xx = (int)(x * costheta + y * sintheta);
151 yy = (int)(y * costheta - x * sintheta);
152 glTranslatef( xx, yy, 0);
153 glScalef(.1, .1, 0.0);
154 while( (c=*msg++) ) {
155 glutStrokeCharacter(font, c);
161 int getStringWidth ( char *str )
163 if ( HUDtext && str )
166 guiFntHandle->getBBox ( str, HUD_TextSize, 0, &l, &r, NULL, NULL ) ;
167 return FloatToInt( r - l );
172 //========================= End of Class Implementations===================
175 // Constructs a HUD object and then adds in instruments. At the present
176 // the instruments are hard coded into the routine. Ultimately these need
177 // to be defined by the aircraft's instrumentation records so that the
178 // display for a Piper Cub doesn't show the speed range of a North American
179 // mustange and the engine readouts of a B36!
184 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
191 int min_x = 25; //off/2;
192 int max_x = 615; //640-(off/2);
194 int max_y = 430; //480-off;
197 unsigned int text_h = 10;
198 unsigned int ladr_w2 = 60;
204 font_size = (current_options.get_xsize() > 1000) ? LARGE : SMALL;
208 FG_LOG( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD" );
210 // deque < instr_item * > :: iterator first = HUD_deque.begin();
211 // deque < instr_item * > :: iterator last = HUD_deque.end();
212 // HUD_deque.erase( first, last); // empty the HUD deque
214 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end()); // empty the HUD deque
219 // For now lets just hardcode the hud here.
220 // In the future, hud information has to come from the same place
221 // aircraft information came from.
223 // fgHUDSetTimeMode( hud, NIGHT );
224 // fgHUDSetBrightness( hud, BRT_LIGHT );
227 // int x = 290; /*cen_x-30*/
228 // int y = 45; /*off-5*/
229 // HIptr = (instr_item *) new fgTBI_instr( x, y, ladr_w2, text_h );
230 HIptr = (instr_item *) new fgTBI_instr( 290, 45, 60, 10 );
231 HUD_deque.insert( HUD_deque.begin(), HIptr);
233 // case 1: // Artificial Horizon
234 HIptr = (instr_item *) new HudLadder( cen_x-ladr_w2, cen_y-ladr_h2,
235 2*ladr_w2, 2*ladr_h2 );
236 HUD_deque.insert( HUD_deque.begin(), HIptr);
238 // case 4: // GYRO COMPASS
239 HIptr = (instr_item *) new hud_card( cen_x-(compass_w/2),
252 HUD_deque.insert( HUD_deque.begin(), HIptr);
255 HIptr = (instr_item *) new hud_card( max_x - 35 -15, // 15 to balance speed card
260 // HUDS_RIGHT | HUDS_VERT,
261 HUDS_LEFT | HUDS_VERT,
269 HUD_deque.insert( HUD_deque.begin(), HIptr);
272 HIptr = (instr_item *) new guage_instr( cen_x-50, // x
273 cen_y + ladr_h2 -20, // y
276 get_aileronval, // data source
277 HUDS_BOTTOM | HUDS_NOTEXT,
281 HUD_deque.insert( HUD_deque.begin(), HIptr);
283 // case 3: // Radio Altimeter
284 HIptr = (instr_item *) new hud_card( cen_x + ladr_w2 + gap + 13 + ladr_t,
289 HUDS_LEFT | HUDS_VERT,
297 HUD_deque.insert( HUD_deque.begin(), HIptr);
300 HIptr = (instr_item *) new guage_instr( cen_x -ladr_w2 -gap -13 -20 -ladr_t,
304 get_elevatorval, // data source
305 HUDS_RIGHT | HUDS_VERT | HUDS_NOTEXT,
306 -100.0, // Scale data
309 HUD_deque.insert( HUD_deque.begin(), HIptr);
312 HIptr = (instr_item *) new guage_instr( cen_x-50, // x
313 cen_y -gap -ladr_w2 -20, //-85 // y
316 get_rudderval, // data source
317 HUDS_TOP | HUDS_NOTEXT,
321 HUD_deque.insert( HUD_deque.begin(), HIptr);
324 HIptr = (instr_item *) new hud_card( min_x +10 +5, //min_x +18,
329 // HUDS_LEFT | HUDS_VERT,
330 HUDS_RIGHT | HUDS_VERT,
341 HUD_deque.insert( HUD_deque.begin(), HIptr);
344 // case 10: // Digital Mach number
345 HIptr = (instr_item *) new instr_label ( min_x , //same as speed tape
346 cen_y-(compass_w/2) -10, //below speed tape
359 HUD_deque.insert( HUD_deque.begin(), HIptr);
362 HIptr = (instr_item *) new guage_instr( min_x-10, // x
366 get_throttleval, // data source
367 // HUDS_VERT | HUDS_RIGHT | HUDS_NOTEXT,
368 HUDS_VERT | HUDS_LEFT | HUDS_NOTEXT, 100.0,
372 HUD_deque.insert( HUD_deque.begin(), HIptr);
373 // Remove this when below uncommented
375 HIptr = (instr_item *) new instr_label( 10,
389 HUD_deque.insert( HUD_deque.begin(), HIptr);
391 HIptr = (instr_item *) new lat_label( (cen_x - (compass_w/2))/2,
405 HUD_deque.insert( HUD_deque.begin(), HIptr);
407 HIptr = (instr_item *) new lon_label(((cen_x+compass_w/2)+(2*cen_x))/2,
420 HUD_deque.insert( HUD_deque.begin(), HIptr);
423 // case 10: // Digital KIAS
424 HIptr = (instr_item *) new instr_label ( 110,
438 HUD_deque.insert( HUD_deque.begin(), HIptr);
440 // case 11: // Digital Rate of Climb
441 HIptr = (instr_item *) new instr_label ( 110,
455 HUD_deque.insert( HUD_deque.begin(), HIptr);
457 // case 12: // Roll indication diagnostic
458 HIptr = (instr_item *) new instr_label ( 110,
472 HUD_deque.insert( HUD_deque.begin(), HIptr);
474 // case 13: // Angle of attack diagnostic
475 HIptr = (instr_item *) new instr_label ( 440,
489 HUD_deque.insert( HUD_deque.begin(), HIptr);
492 HIptr = (instr_item *) new instr_label ( 440,
506 HUD_deque.insert( HUD_deque.begin(), HIptr);
509 HIptr = (instr_item *) new instr_label ( 440,
523 HUD_deque.insert( HUD_deque.begin(), HIptr);
526 HIptr = (instr_item *) new instr_label( 440,
540 HUD_deque.insert( HUD_deque.begin(), HIptr);
543 HIptr = (instr_item *) new instr_label( 440,
557 HUD_deque.insert( HUD_deque.begin(), HIptr);
560 HIptr = (instr_item *) new instr_label( 440,
574 HUD_deque.insert( HUD_deque.begin(), HIptr);
577 HIptr = (instr_item *) new instr_label( 10,
591 HUD_deque.insert( HUD_deque.begin(), HIptr);
594 switch( current_options.get_tris_or_culled() ) {
596 HIptr = (instr_item *) new instr_label( 10,
612 HIptr = (instr_item *) new instr_label( 10,
631 HIptr = (instr_item *) new instr_label( 10,
645 HUD_deque.insert( HUD_deque.begin(), HIptr);
650 // if( HIptr ) { // Anything to install?
651 // HUD_deque.insert( HUD_deque.begin(), HIptr);
657 return 0; // For now. Later we may use this for an error code.
661 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
663 // instr_item *HIptr;
669 // int max_x = 640-off;
681 font_size = (current_options.get_xsize() > 1000) ? LARGE : SMALL;
685 FG_LOG( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD" );
687 // deque < instr_item * > :: iterator first = HUD_deque.begin();
688 // deque < instr_item * > :: iterator last = HUD_deque.end();
689 // HUD_deque.erase( first, last); // empty the HUD deque
690 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());
695 // For now lets just hardcode the hud here.
696 // In the future, hud information has to come from the same place
697 // aircraft information came from.
699 // fgHUDSetTimeMode( hud, NIGHT );
700 // fgHUDSetBrightness( hud, BRT_LIGHT );
707 p = new HudLadder( cen_x-ladr_w2, cen_y-ladr_h2, 2*ladr_w2, 2*ladr_h2, 1 );
708 HUD_deque.push_front( p );
710 // case 4: // GYRO COMPASS
711 p =new hud_card( cen_x-(compass_w/2),
724 HUD_deque.push_front( p );
726 p = new lat_label( (cen_x - compass_w/2)/2,
739 HUD_deque.push_front( p );
741 // p = new instr_label( 140, 450, 60, 10,
752 // HUD_deque.push_front( p );
754 p = new lon_label(((cen_x+compass_w/2)+(2*cen_x))/2,
767 HUD_deque.push_front( p );
771 p = new instr_label( x_pos, 25, 60, 10,
782 HUD_deque.push_front( p );
784 p = new instr_label( x_pos, 40, 120, 10,
795 HUD_deque.push_front( p );
797 p = new instr_label( x_pos, 55, 120, 10,
808 HUD_deque.push_front( p );
811 // p = new instr_label( x_pos, 70, 90, 10,
812 p = new instr_label( x_pos, 40, 90, 10,
823 HUD_deque.push_front( p );
827 p = new instr_label ( x_pos,
841 HUD_deque.push_front( p );
843 p = new instr_label( x_pos, 55, 40, 30,
854 HUD_deque.push_front( p );
856 if ( current_options.get_units() == fgOPTIONS::FG_UNITS_FEET ) {
857 strcpy(units, " ft");
861 p = new instr_label( x_pos, 40, 40, 10,
872 HUD_deque.push_front( p );
874 p = new instr_label( x_pos, 25, 40, 10,
885 HUD_deque.push_front( p );
887 p = new instr_label( x_pos, 10, 60, 10,
898 HUD_deque.push_front( p );
900 p = new fgTBI_instr( 290, 55, 60, 10 ); // 270
901 HUD_deque.push_front( p );
903 p = new guage_instr( 270, //250, // x
904 390, //360, //400, //45, //420, // y
907 get_aileronval, // data source
908 HUDS_BOTTOM | HUDS_NOTEXT,
912 HUD_deque.push_front( p );
914 p = new guage_instr( 20, // x
918 get_elevatorval, // data source
919 HUDS_RIGHT | HUDS_VERT | HUDS_NOTEXT,
920 -100.0, // Scale data
923 HUD_deque.push_front( p );
925 p = new guage_instr( 270, //250, // x
929 get_rudderval, // data source
930 HUDS_TOP | HUDS_NOTEXT,
934 HUD_deque.push_front( p );
936 p = new guage_instr( 600, // x
940 get_throttleval, // data source
941 HUDS_VERT | HUDS_LEFT | HUDS_NOTEXT,
945 HUD_deque.push_front( p );
947 return 0; // For now. Later we may use this for an error code.
950 int global_day_night_switch = DAY;
952 void HUD_brightkey( bool incr_bright )
954 instr_item *pHUDInstr = HUD_deque[0];
955 int brightness = pHUDInstr->get_brightness();
957 if( current_options.get_hud_status() ) {
959 switch (brightness) {
961 current_options.set_hud_status(0);
965 brightness = BRT_LIGHT;
969 brightness = BRT_MEDIUM;
973 brightness = BRT_DARK;
977 brightness = BRT_BLACK;
981 switch (brightness) {
983 brightness = BRT_MEDIUM;
987 brightness = BRT_DARK;
991 brightness = BRT_BLACK;
996 current_options.set_hud_status(0);
1001 current_options.set_hud_status(1);
1003 if( DAY == global_day_night_switch ) {
1004 brightness = BRT_BLACK;
1007 brightness = BRT_DARK;
1008 global_day_night_switch = DAY;
1012 if( NIGHT == global_day_night_switch ) {
1013 brightness = BRT_DARK;
1016 brightness = BRT_MEDIUM;
1017 global_day_night_switch = NIGHT;
1021 pHUDInstr->SetBrightness( brightness );
1027 // Performs a once around the list of calls to instruments installed in
1028 // the HUD object with requests for redraw. Kinda. It will when this is
1031 void fgUpdateHUD( void ) {
1033 // int day_night_sw = current_aircraft.controls->day_night_switch;
1034 int day_night_sw = global_day_night_switch;
1035 int hud_displays = HUD_deque.size();
1036 instr_item *pHUDInstr;
1039 if( !hud_displays ) { // Trust everyone, but ALWAYS cut the cards!
1043 HUD_TextList.erase();
1044 HUD_LineList.erase();
1045 // HUD_StippleLineList.erase();
1047 pHUDInstr = HUD_deque[0];
1048 brightness = pHUDInstr->get_brightness();
1049 // brightness = HUD_deque.at(0)->get_brightness();
1051 glMatrixMode(GL_PROJECTION);
1055 gluOrtho2D(0, 640, 0, 480);
1056 glMatrixMode(GL_MODELVIEW);
1060 glColor3f(1.0, 1.0, 1.0);
1063 glDisable(GL_DEPTH_TEST);
1064 glDisable(GL_LIGHTING);
1066 // We can do translucency, so why not. :-)
1067 // glEnable ( GL_BLEND ) ;
1068 // glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
1070 if( day_night_sw == DAY) {
1071 switch (brightness) {
1073 // glColor4f (0.1, 0.9, 0.1, 0.75);
1074 glColor3f (0.1, 0.9, 0.1);
1078 // glColor4f (0.1, 0.7, 0.0, 0.75);
1079 glColor3f (0.1, 0.7, 0.0);
1083 // glColor4f (0.0, 0.6, 0.0, 0.75);
1084 glColor3f(0.0, 0.6, 0.0);
1088 // glColor4f( 0.0, 0.0, 0.0, 0.75);
1089 glColor3f( 0.0, 0.0, 0.0);
1096 if( day_night_sw == NIGHT) {
1097 switch (brightness) {
1099 // glColor4f (0.9, 0.1, 0.1, 0.75);
1100 glColor3f (0.9, 0.1, 0.1);
1104 // glColor4f (0.7, 0.0, 0.1, 0.75);
1105 glColor3f (0.7, 0.0, 0.1);
1110 // glColor4f (0.6, 0.0, 0.0, 0.75);
1111 glColor3f (0.6, 0.0, 0.0);
1114 else { // Just in case default
1115 // glColor4f (0.1, 0.9, 0.1, 0.75);
1116 glColor3f (0.1, 0.9, 0.1);
1120 deque < instr_item * > :: iterator current = HUD_deque.begin();
1121 deque < instr_item * > :: iterator last = HUD_deque.end();
1123 for ( ; current != last; ++current ) {
1124 pHUDInstr = *current;
1126 if( pHUDInstr->enabled()) {
1127 // fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d Status %d\n",
1128 // hud->code, hud->status );
1130 // HUD_deque.at(i)->draw(); // Responsible for broken or fixed variants.
1131 // No broken displays honored just now.
1135 char *gmt_str = get_formated_gmt_time();
1136 HUD_TextList.add( fgText( 40, 10, gmt_str) );
1138 #ifdef FG_NETWORK_OLK
1139 if ( net_hud_display ) {
1144 HUD_TextList.draw();
1146 line_width = (current_options.get_xsize() > 1000) ? 1.0 : 0.5;
1147 glLineWidth(line_width);
1148 HUD_LineList.draw();
1150 // glEnable(GL_LINE_STIPPLE);
1151 // glLineStipple( 1, 0x00FF );
1152 // HUD_StippleLineList.draw();
1153 // glDisable(GL_LINE_STIPPLE);
1155 // glDisable( GL_BLEND );
1157 glEnable(GL_DEPTH_TEST);
1158 glEnable(GL_LIGHTING);
1159 glMatrixMode(GL_PROJECTION);
1161 glMatrixMode(GL_MODELVIEW);
1169 // Performs a once around the list of calls to instruments installed in
1170 // the HUD object with requests for redraw. Kinda. It will when this is
1173 void fgUpdateHUD( void ) {
1175 // int day_night_sw = current_aircraft.controls->day_night_switch;
1176 int day_night_sw = global_day_night_switch;
1177 int hud_displays = HUD_deque.size();
1178 instr_item *pHUDInstr;
1181 if( !hud_displays ) { // Trust everyone, but ALWAYS cut the cards!
1185 HUD_TextList.erase();
1186 HUD_LineList.erase();
1187 // HUD_StippleLineList.erase();
1189 pHUDInstr = HUD_deque[0];
1190 brightness = pHUDInstr->get_brightness();
1191 // brightness = HUD_deque.at(0)->get_brightness();
1193 glMatrixMode(GL_PROJECTION);
1197 gluOrtho2D(0, 640, 0, 480);
1198 glMatrixMode(GL_MODELVIEW);
1202 glColor3f(1.0, 1.0, 1.0);
1205 glDisable(GL_DEPTH_TEST);
1206 glDisable(GL_LIGHTING);
1208 // We can do translucency, so why not. :-)
1209 // glEnable ( GL_BLEND ) ;
1210 // glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
1212 if( day_night_sw == DAY) {
1213 switch (brightness) {
1215 // glColor4f (0.1, 0.9, 0.1, 0.75);
1216 glColor3f (0.1, 0.9, 0.1);
1220 // glColor4f (0.1, 0.7, 0.0, 0.75);
1221 glColor3f (0.1, 0.7, 0.0);
1225 // glColor4f (0.0, 0.6, 0.0, 0.75);
1226 glColor3f(0.0, 0.6, 0.0);
1230 // glColor4f( 0.0, 0.0, 0.0, 0.75);
1231 glColor3f( 0.0, 0.0, 0.0);
1238 if( day_night_sw == NIGHT) {
1239 switch (brightness) {
1241 // glColor4f (0.9, 0.1, 0.1, 0.75);
1242 glColor3f (0.9, 0.1, 0.1);
1246 // glColor4f (0.7, 0.0, 0.1, 0.75);
1247 glColor3f (0.7, 0.0, 0.1);
1252 // glColor4f (0.6, 0.0, 0.0, 0.75);
1253 glColor3f (0.6, 0.0, 0.0);
1256 else { // Just in case default
1257 // glColor4f (0.1, 0.9, 0.1, 0.75);
1258 glColor3f (0.1, 0.9, 0.1);
1262 deque < instr_item * > :: iterator current = HUD_deque.begin();
1263 deque < instr_item * > :: iterator last = HUD_deque.end();
1265 for ( ; current != last; ++current ) {
1266 pHUDInstr = *current;
1268 if( pHUDInstr->enabled()) {
1269 // fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d Status %d\n",
1270 // hud->code, hud->status );
1272 // HUD_deque.at(i)->draw(); // Responsible for broken or fixed variants.
1273 // No broken displays honored just now.
1277 char *gmt_str = get_formated_gmt_time();
1278 HUD_TextList.add( fgText(40, 10, gmt_str) );
1280 #ifdef FG_NETWORK_OLK
1281 if ( net_hud_display ) {
1288 // extern bool fgAPAltitudeEnabled( void );
1289 // extern bool fgAPHeadingEnabled( void );
1290 // extern bool fgAPWayPointEnabled( void );
1291 // extern char *fgAPget_TargetDistanceStr( void );
1292 // extern char *fgAPget_TargetHeadingStr( void );
1293 // extern char *fgAPget_TargetAltitudeStr( void );
1294 // extern char *fgAPget_TargetLatLonStr( void );
1297 // char scratch[128];
1298 // HUD_TextList.add( fgText( "AUTOPILOT", 20, apY) );
1300 if( current_autopilot->get_HeadingEnabled() ) {
1301 HUD_TextList.add( fgText( 40, apY,
1302 current_autopilot->get_TargetHeadingStr()) );
1305 if( current_autopilot->get_AltitudeEnabled() ) {
1306 HUD_TextList.add( fgText( 40, apY,
1307 current_autopilot->get_TargetAltitudeStr()) );
1310 if( current_autopilot->get_HeadingMode() ==
1311 FGAutopilot::FG_HEADING_WAYPOINT ) {
1312 HUD_TextList.add( fgText( 40, apY,
1313 current_autopilot->get_TargetLatLonStr()) );
1315 HUD_TextList.add( fgText( 40, apY,
1316 current_autopilot->get_TargetDistanceStr() ) );
1320 HUD_TextList.draw();
1322 line_width = (current_options.get_xsize() > 1000) ? 1.0 : 0.5;
1323 glLineWidth(line_width);
1324 HUD_LineList.draw();
1326 // glEnable(GL_LINE_STIPPLE);
1327 // glLineStipple( 1, 0x00FF );
1328 // HUD_StippleLineList.draw();
1329 // glDisable(GL_LINE_STIPPLE);
1331 // glDisable( GL_BLEND );
1333 glEnable(GL_DEPTH_TEST);
1334 glEnable(GL_LIGHTING);
1335 glMatrixMode(GL_PROJECTION);
1337 glMatrixMode(GL_MODELVIEW);