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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <simgear/compiler.h>
24 #include <simgear/structure/exception.hxx>
38 # define exception c_exception
44 #include <stdio.h> // char related functions
45 #include <string.h> // strcmp()
49 #include <simgear/constants.h>
50 #include <simgear/debug/logstream.hxx>
51 #include <simgear/props/props.hxx>
52 #include <simgear/misc/sg_path.hxx>
54 #include <Aircraft/aircraft.hxx>
55 #include <Autopilot/xmlauto.hxx>
56 #include <GUI/new_gui.hxx>
57 #include <Main/globals.hxx>
58 #include <Main/fg_props.hxx>
59 #include <Scenery/scenery.hxx>
61 #if defined (__sun) || defined ( __sgi )
63 extern void *memmove(void *, const void *, size_t);
71 // The following routines obtain information concerning the aircraft's
72 // current state and return it to calling instrument display routines.
73 // They should eventually be member functions of the aircraft.
76 deque< instr_item * > HUD_deque;
78 fgTextList HUD_TextList;
79 fgLineList HUD_LineList;
80 fgLineList HUD_StippleLineList;
82 fntRenderer *HUDtext = 0;
83 float HUD_TextSize = 0;
89 //$$$ begin - added, Neetha, 28 Nov 2k
97 static float span_units;
98 static float division_units;
99 static float minor_division = 0;
100 static UINT screen_hole;
103 static string loadfn;
105 static float maxValue;
106 static float minValue;
107 static float scaling;
108 static UINT major_divs;
109 static UINT minor_divs;
110 static UINT modulator;
111 static int dp_showing = 0;
112 static string label_format;
113 static string prelabel;
114 static string postlabel;
117 static float maxBankAngle;
118 static float maxSlipAngle;
119 static UINT gap_width;
120 static bool latitude;
121 static bool longitude;
122 static bool tick_bottom;
123 static bool tick_top;
124 static bool tick_right;
125 static bool tick_left;
126 static bool cap_bottom;
128 static bool cap_right;
129 static bool cap_left;
130 static float marker_off;
132 static bool enable_pointer;
133 static string type_pointer;
134 static bool frl_spot;
136 static bool vel_vector;
140 static bool climb_dive;
142 static float glide_slope_val;
143 static bool worm_energy;
144 static bool waypoint;
145 static string type_tick;//hud
146 static string length_tick;//hud
147 static bool label_box;//hud
148 static int digits; //suma
149 static float radius; //suma
150 static int divisions; //suma
151 static int zoom; //suma
152 static int zenith; //suma
153 static int nadir ; //suma
154 static int hat; //suma
155 static bool tsi; //suma
156 static float rad; //suma
159 static FLTFNPTR load_fn;
160 static fgLabelJust justification;
161 static const char *pre_label_string = 0;
162 static const char *post_label_string = 0;
164 int readHud( istream &input );
165 int readInstrument ( const SGPropertyNode * node);
166 static instr_item * readLadder ( const SGPropertyNode * node);
167 static instr_item * readCard ( const SGPropertyNode * node);
168 static instr_item * readLabel( const SGPropertyNode * node);
169 static instr_item * readTBI( const SGPropertyNode * node);
170 //$$$ end - added, Neetha, 28 Nov 2k
172 static void drawHUD();
173 static void fgUpdateHUDVirtual();
179 locRECT( UINT left, UINT top, UINT right, UINT bottom);
180 RECT get_rect(void) { return rect;}
183 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
188 rect.bottom = bottom;
193 //========================= End of Class Implementations===================
196 // Constructs a HUD object and then adds in instruments. At the present
197 // the instruments are hard coded into the routine. Ultimately these need
198 // to be defined by the aircraft's instrumentation records so that the
199 // display for a Piper Cub doesn't show the speed range of a North American
200 // mustange and the engine readouts of a B36!
205 //$$$ begin - added, Neetha, 28 Nov 2k
207 readLadder(const SGPropertyNode * node)
212 name = node->getStringValue("name");
213 x = node->getIntValue("x");
214 y = node->getIntValue("y");
215 width = node->getIntValue("width");
216 height = node->getIntValue("height");
217 factor = node->getFloatValue("compression_factor");
218 span_units = node->getFloatValue("span_units");
219 division_units = node->getFloatValue("division_units");
220 screen_hole = node->getIntValue("screen_hole");
221 lbl_pos = node->getIntValue("lbl_pos");
222 frl_spot = node->getBoolValue("enable_frl",false);
223 target = node->getBoolValue("enable_target_spot",false);
224 vel_vector = node->getBoolValue("enable_velocity_vector",false);
225 drift = node->getBoolValue("enable_drift_marker",false);
226 alpha = node->getBoolValue("enable_alpha_bracket",false);
227 energy = node->getBoolValue("enable_energy_marker",false);
228 climb_dive = node->getBoolValue("enable_climb_dive_marker",false);
229 glide = node->getBoolValue("enable_glide_slope_marker",false);
230 glide_slope_val = node->getFloatValue("glide_slope",-4.0);
231 worm_energy = node->getBoolValue("enable_energy_marker",false);
232 waypoint = node->getBoolValue("enable_waypoint_marker",false);
233 working = node->getBoolValue("working");
234 zenith = node->getIntValue("zenith"); //suma
235 nadir = node->getIntValue("nadir"); //suma
236 hat = node->getIntValue("hat");
237 // The factor assumes a base of 55 degrees per 640 pixels.
238 // Invert to convert the "compression" factor to a
239 // pixels-per-degree number.
240 if(fgGetBool("/sim/hud/enable3d", true))
245 factor = (640./55.) / factor;
249 SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
251 p = (instr_item *) new HudLadder( name, x, y,
252 width, height, factor,
254 span_units, division_units, minor_division,
255 screen_hole, lbl_pos, frl_spot, target, vel_vector,
256 drift, alpha, energy, climb_dive,
257 glide, glide_slope_val, worm_energy,
258 waypoint, working, zenith, nadir, hat);
265 readCard(const SGPropertyNode * node)
270 name = node->getStringValue("name");
271 x = node->getIntValue("x");
272 y = node->getIntValue("y");
273 width = node->getIntValue("width");
274 height = node->getIntValue("height");
275 loadfn = node->getStringValue("loadfn");
276 options = node->getIntValue("options");
277 maxValue = node->getFloatValue("maxValue");
278 minValue = node->getFloatValue("minValue");
279 scaling = node->getFloatValue("disp_scaling");
280 major_divs = node->getIntValue("major_divs");
281 minor_divs = node->getIntValue("minor_divs");
282 modulator = node->getIntValue("modulator");
283 span_units = node->getFloatValue("value_span");
284 type = node->getStringValue("type");
285 tick_bottom = node->getBoolValue("tick_bottom",false);
286 tick_top = node->getBoolValue("tick_top",false);
287 tick_right = node->getBoolValue("tick_right",false);
288 tick_left = node->getBoolValue("tick_left",false);
289 cap_bottom = node->getBoolValue("cap_bottom",false);
290 cap_top = node->getBoolValue("cap_top",false);
291 cap_right = node->getBoolValue("cap_right",false);
292 cap_left = node->getBoolValue("cap_left",false);
293 marker_off = node->getFloatValue("marker_offset",0.0);
294 enable_pointer = node->getBoolValue("enable_pointer",true);
295 type_pointer = node->getStringValue("pointer_type");
296 type_tick = node->getStringValue("tick_type");//hud Can be 'circle' or 'line'
297 length_tick = node->getStringValue("tick_length");//hud For variable length
298 working = node->getBoolValue("working");
299 radius = node->getFloatValue("radius"); //suma
300 divisions = node->getIntValue("divisions"); //suma
301 zoom = node->getIntValue("zoom"); //suma
303 SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
307 span_units = maxValue - minValue;
310 if (loadfn=="anzg") {
312 } else if (loadfn=="heading") {
313 load_fn = get_heading;
314 } else if (loadfn=="aoa") {
316 } else if (loadfn=="climb") {
317 load_fn = get_climb_rate;
318 } else if (loadfn=="altitude") {
319 load_fn = get_altitude;
320 } else if (loadfn=="agl") {
322 } else if (loadfn=="speed") {
324 } else if (loadfn=="view_direction") {
325 load_fn = get_view_direction;
326 } else if (loadfn=="aileronval") {
327 load_fn = get_aileronval;
328 } else if (loadfn=="elevatorval") {
329 load_fn = get_elevatorval;
330 } else if (loadfn=="elevatortrimval") {
331 load_fn = get_elev_trimval;
332 } else if (loadfn=="rudderval") {
333 load_fn = get_rudderval;
334 } else if (loadfn=="throttleval") {
335 load_fn = get_throttleval;
339 if ( (type == "dial") | (type == "tape") ) {
340 p = (instr_item *) new hud_card( x,
348 major_divs, minor_divs,
372 p = (instr_item *) new gauge_instr( x, // x
376 load_fn, // data source
380 major_divs, minor_divs,
390 readLabel(const SGPropertyNode * node)
394 int font_size = (fgGetInt("/sim/startup/xsize") > 1000) ? HUD_FONT_LARGE : HUD_FONT_SMALL;
396 name = node->getStringValue("name");
397 x = node->getIntValue("x");
398 y = node->getIntValue("y");
399 width = node->getIntValue("width");
400 height = node->getIntValue("height");
401 loadfn = node->getStringValue("data_source");
402 label_format = node->getStringValue("label_format");
403 prelabel = node->getStringValue("pre_label_string");
404 postlabel = node->getStringValue("post_label_string");
405 scaling = node->getFloatValue("scale_data");
406 options = node->getIntValue("options");
407 justi = node->getIntValue("justification");
408 blinking = node->getIntValue("blinking");
409 latitude = node->getBoolValue("latitude",false);
410 longitude = node->getBoolValue("longitude",false);
411 label_box = node->getBoolValue("label_box",false);//hud
412 working = node->getBoolValue("working");
413 digits = node->getIntValue("digits"); //suma
416 SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
420 justification = LEFT_JUST;
423 justification = CENTER_JUST;
426 justification = RIGHT_JUST;
431 if ( prelabel == "NULL" ) {
432 pre_label_string = NULL;
434 if ( prelabel == "blank" ) {
435 pre_label_string = " ";
437 pre_label_string = prelabel.c_str();
441 if ( postlabel == "blank" ) {
442 post_label_string = " ";
444 if ( postlabel == "NULL" ) {
445 post_label_string = NULL;
447 if ( postlabel == "units" ) {
448 post_label_string = units;
450 post_label_string = postlabel.c_str();
455 #ifdef ENABLE_SP_FMDS
456 if ( loadfn== "aux1" ) {
458 } else if ( loadfn == "aux2" ) {
460 } else if ( loadfn == "aux3" ) {
462 } else if ( loadfn == "aux4" ) {
464 } else if ( loadfn == "aux5" ) {
466 } else if ( loadfn == "aux6" ) {
468 } else if ( loadfn == "aux7" ) {
470 } else if ( loadfn == "aux8" ) {
472 } else if ( loadfn == "aux9" ) {
474 } else if ( loadfn == "aux10" ) {
476 } else if ( loadfn == "aux11" ) {
478 } else if ( loadfn == "aux12" ) {
480 } else if ( loadfn == "aux13" ) {
482 } else if ( loadfn == "aux14" ) {
484 } else if ( loadfn == "aux15" ) {
486 } else if ( loadfn == "aux16" ) {
488 } else if ( loadfn == "aux17" ) {
490 } else if ( loadfn == "aux18" ) {
494 if ( loadfn == "ax" ) {
496 } else if ( loadfn == "speed" ) {
498 } else if ( loadfn == "mach" ) {
500 } else if ( loadfn == "altitude" ) {
501 load_fn = get_altitude;
502 } else if ( loadfn == "agl" ) {
504 } else if ( loadfn == "framerate" ) {
505 load_fn = get_frame_rate;
506 } else if ( loadfn == "heading" ) {
507 load_fn = get_heading;
508 } else if ( loadfn == "fov" ) {
510 } else if ( loadfn == "vfc_tris_culled" ) {
511 load_fn = get_vfc_tris_culled;
512 } else if ( loadfn == "vfc_tris_drawn" ) {
513 load_fn = get_vfc_tris_drawn;
514 } else if ( loadfn == "aoa" ) {
516 } else if ( loadfn == "latitude" ) {
517 load_fn = get_latitude;
518 } else if ( loadfn == "anzg" ) {
520 } else if ( loadfn == "longitude" ) {
521 load_fn = get_longitude;
522 } else if (loadfn=="throttleval") {
523 load_fn = get_throttleval;
526 p = (instr_item *) new instr_label ( x,
531 label_format.c_str(),
549 readTBI(const SGPropertyNode * node)
554 name = node->getStringValue("name");
555 x = node->getIntValue("x");
556 y = node->getIntValue("y");
557 width = node->getIntValue("width");
558 height = node->getIntValue("height");
559 maxBankAngle = node->getFloatValue("maxBankAngle");
560 maxSlipAngle = node->getFloatValue("maxSlipAngle");
561 gap_width = node->getIntValue("gap_width");
562 working = node->getBoolValue("working");
563 tsi = node->getBoolValue("tsi"); //suma
564 rad = node->getFloatValue("rad"); //suma
566 SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
569 p = (instr_item *) new fgTBI_instr( x,
586 readRunway(const SGPropertyNode * node) {
587 name = node->getStringValue("name");
588 x = node->getIntValue("x");
589 y = node->getIntValue("y");
590 width = node->getIntValue("width");
591 height = node->getIntValue("height");
592 scaling = node->getDoubleValue("scale");
593 working = node->getBoolValue("working",true);
594 runway_instr *ri = new runway_instr(x,y,width,height,scaling,working);
595 double scale = node->getDoubleValue("arrow_scale",1.0);
596 ri->setDrawArrow((scale>0)?true:false);
597 ri->setDrawArrowAlways((scale>0)?node->getBoolValue("arrow_always"):false);
598 ri->setStippleOutline(node->getIntValue("outer_stipple",0xFFFF));
599 ri->setStippleCenterline(node->getIntValue("center_stipple",0xFFFF));
600 ri->setArrowRotationRadius(node->getDoubleValue("arrow_radius"));
601 ri->setArrowScale(scale);
602 ri->setLineScale(node->getDoubleValue("line_scale",1.0));
603 ri->setScaleDist(node->getDoubleValue("scale_dist_nm"));
604 SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
605 return (instr_item *) ri;
609 int readInstrument(const SGPropertyNode * node)
611 static const SGPropertyNode *startup_units_node
612 = fgGetNode("/sim/startup/units");
616 if ( !strcmp(startup_units_node->getStringValue(), "feet") ) {
617 strcpy(units, " ft");
622 const SGPropertyNode * ladder_group = node->getNode("ladders");
624 if (ladder_group != 0) {
625 int nLadders = ladder_group->nChildren();
626 for (int j = 0; j < nLadders; j++) {
628 HIptr = readLadder(ladder_group->getChild(j));
629 HUD_deque.insert( HUD_deque.begin(), HIptr);
634 const SGPropertyNode * card_group = node->getNode("cards");
635 if (card_group != 0) {
636 int nCards = card_group->nChildren();
637 for (int j = 0; j < nCards; j++) {
639 HIptr = readCard(card_group->getChild(j));
640 HUD_deque.insert( HUD_deque.begin(), HIptr);
645 const SGPropertyNode * label_group = node->getNode("labels");
646 if (label_group != 0) {
647 int nLabels = label_group->nChildren();
648 for (int j = 0; j < nLabels; j++) {
650 HIptr = readLabel(label_group->getChild(j));
651 HUD_deque.insert( HUD_deque.begin(), HIptr);
656 const SGPropertyNode * tbi_group = node->getNode("tbis");
657 if (tbi_group != 0) {
658 int nTbis = tbi_group->nChildren();
659 for (int j = 0; j < nTbis; j++) {
661 HIptr = readTBI(tbi_group->getChild(j));
662 HUD_deque.insert( HUD_deque.begin(), HIptr);
667 const SGPropertyNode * rwy_group = node->getNode("runways");
668 if (rwy_group != 0) {
669 int nRwy = rwy_group->nChildren();
670 for (int j = 0; j < nRwy; j++) {
671 SG_LOG( SG_COCKPIT, SG_DEBUG,
672 "************** Reading runway properties" );
673 HIptr = readRunway(rwy_group->getChild(j));
674 HUD_deque.insert( HUD_deque.begin(), HIptr);
679 }//end readinstrument
682 int readHud( istream &input )
688 readProperties(input, &root);
689 } catch (const sg_exception &e) {
690 guiErrorMessage("Error reading HUD: ", e);
695 SG_LOG(SG_INPUT, SG_INFO, "Read properties for " <<
696 root.getStringValue("name"));
699 HUD_deque.erase( HUD_deque.begin(), HUD_deque.end()); // empty the HUD deque
702 SG_LOG(SG_INPUT, SG_INFO, "Reading Hud instruments");
704 const SGPropertyNode * instrument_group = root.getChild("instruments");
705 int nInstruments = instrument_group->nChildren();
707 for (int i = 0; i < nInstruments; i++) {
709 const SGPropertyNode * node = instrument_group->getChild(i);
711 SGPath path( globals->get_fg_root() );
712 path.append(node->getStringValue("path"));
714 SG_LOG(SG_INPUT, SG_INFO, "Reading Instrument "
719 SGPropertyNode root2;
721 readProperties(path.str(), &root2);
722 } catch (const sg_exception &e) {
723 guiErrorMessage("Error reading HUD instrument: ", e);
726 readInstrument(&root2);
733 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
738 SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
741 fgGetString("/sim/hud/path", "Huds/Default/default.xml");
742 SGPath path(globals->get_fg_root());
743 path.append(hud_path);
745 ifstream input(path.c_str());
747 SG_LOG(SG_INPUT, SG_ALERT,
748 "Cannot read Hud configuration from " << path.str());
757 // this chunk of code is not necessarily thread safe if the
758 // compiler optimizer reorders these statements. Note that
759 // "delete ptr" does not set "ptr = NULL". We have to do that
761 fntRenderer *tmp = HUDtext;
766 // HUD_TextSize = fgGetInt("/sim/startup/xsize") / 60;
768 HUDtext = new fntRenderer();
769 HUDtext -> setFont ( guiFntHandle ) ;
770 HUDtext -> setPointSize ( HUD_TextSize ) ;
771 HUD_TextList.setFont( HUDtext );
773 return 0; // For now. Later we may use this for an error code.
777 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
782 SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
784 SGPath path(globals->get_fg_root());
785 path.append("Huds/Minimal/default.xml");
788 ifstream input(path.c_str());
790 SG_LOG(SG_INPUT, SG_ALERT,
791 "Cannot read Hud configuration from " << path.str());
797 return 0; // For now. Later we may use this for an error code.
800 //$$$ End - added, Neetha, 28 Nov 2k
802 static int global_day_night_switch = HUD_DAY;
804 void HUD_masterswitch( bool incr )
806 if ( fgGetBool("/sim/hud/visibility") ) {
807 if ( global_day_night_switch == HUD_DAY ) {
808 global_day_night_switch = HUD_NIGHT;
810 fgSetBool("/sim/hud/visibility", false);
813 fgSetBool("/sim/hud/visibility", true);
814 global_day_night_switch = HUD_DAY;
818 void HUD_brightkey( bool incr_bright )
820 instr_item *pHUDInstr = HUD_deque[0];
821 int brightness = pHUDInstr->get_brightness();
823 if( fgGetBool("/sim/hud/visibility") ) {
828 brightness = HUD_BRT_BLACK;
832 brightness = HUD_BRT_LIGHT;
836 brightness = HUD_BRT_MEDIUM;
840 brightness = HUD_BRT_DARK;
844 brightness = HUD_BRT_BLACK;
850 brightness = HUD_BRT_MEDIUM;
854 brightness = HUD_BRT_DARK;
858 brightness = HUD_BRT_BLACK;
862 brightness = HUD_BRT_LIGHT;
866 fgSetBool("/sim/hud/visibility", false);
870 fgSetBool("/sim/hud/visibility", true);
873 pHUDInstr->SetBrightness( brightness );
877 void fgHUDReshape(void) {
880 // this chunk of code is not necessarily thread safe if the
881 // compiler optimizer reorders these statements. Note that
882 // "delete ptr" does not set "ptr = NULL". We have to do that
884 fntRenderer *tmp = HUDtext;
889 HUD_TextSize = fgGetInt("/sim/startup/xsize") / 60;
891 HUDtext = new fntRenderer();
892 HUDtext -> setFont ( guiFntHandle ) ;
893 HUDtext -> setPointSize ( HUD_TextSize ) ;
894 HUD_TextList.setFont( HUDtext );
899 static void set_hud_color(float r, float g, float b) {
900 static SGPropertyNode_ptr alias = fgGetNode("/sim/hud/antialiased", true);
901 static SGPropertyNode_ptr alpha = fgGetNode("/sim/hud/alpha", true);
903 if (alias->getBoolValue())
904 glColor4f(r, g, b, alpha->getFloatValue());
912 // Performs a once around the list of calls to instruments installed in
913 // the HUD object with requests for redraw. Kinda. It will when this is
916 void fgUpdateHUD( void ) {
918 static const SGPropertyNode *enable3d_node = fgGetNode("/sim/hud/enable3d");
919 if( HUD_style == 1 && enable3d_node->getBoolValue() )
921 fgUpdateHUDVirtual();
925 static const float normal_aspect = float(640) / float(480);
926 // note: aspect_ratio is Y/X
927 float current_aspect = 1.0f/globals->get_current_view()->get_aspect_ratio();
928 if( current_aspect > normal_aspect ) {
929 float aspect_adjust = current_aspect / normal_aspect;
930 float adjust = 320.0f*aspect_adjust - 320.0f;
931 fgUpdateHUD( -adjust, 0.0f, 640.0f+adjust, 480.0f );
933 float aspect_adjust = normal_aspect / current_aspect;
934 float adjust = 240.0f*aspect_adjust - 240.0f;
935 fgUpdateHUD( 0.0f, -adjust, 640.0f, 480.0f+adjust );
939 void fgUpdateHUDVirtual()
941 FGViewer* view = globals->get_current_view();
943 // Standard fgfs projection, with essentially meaningless clip
944 // planes (we'll map the whole HUD plane to z=-1)
945 glMatrixMode(GL_PROJECTION);
948 gluPerspective(view->get_v_fov(), 1/view->get_aspect_ratio(), 0.1, 10);
950 glMatrixMode(GL_MODELVIEW);
954 // Standard fgfs view direction computation
956 lookat[0] = -sin(SG_DEGREES_TO_RADIANS * view->getHeadingOffset_deg());
957 lookat[1] = tan(SG_DEGREES_TO_RADIANS * view->getPitchOffset_deg());
958 lookat[2] = -cos(SG_DEGREES_TO_RADIANS * view->getHeadingOffset_deg());
959 if(fabs(lookat[1]) > 9999) lookat[1] = 9999; // FPU sanity
960 gluLookAt(0, 0, 0, lookat[0], lookat[1], lookat[2], 0, 1, 0);
962 // Map the -1:1 square to a 55.0x41.25 degree wide patch at z=1.
963 // This is the default fgfs field of view, which the HUD files are
964 // written to assume.
965 float dx = 0.52056705; // tan(55/2)
966 float dy = dx * 0.75; // assumes 4:3 aspect ratio
968 m[0] = dx; m[4] = 0; m[ 8] = 0; m[12] = 0;
969 m[1] = 0; m[5] = dy; m[ 9] = 0; m[13] = 0;
970 m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0;
971 m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1;
974 // Convert the 640x480 "HUD standard" coordinate space to a square
975 // about the origin in the range [-1:1] at depth of -1
976 glScalef(1./320, 1./240, 1);
977 glTranslatef(-320, -240, -1);
983 glMatrixMode(GL_PROJECTION);
985 glMatrixMode(GL_MODELVIEW);
989 void fgUpdateHUD( GLfloat x_start, GLfloat y_start,
990 GLfloat x_end, GLfloat y_end )
992 glMatrixMode(GL_PROJECTION);
995 gluOrtho2D(x_start, x_end, y_start, y_end);
997 glMatrixMode(GL_MODELVIEW);
1003 glMatrixMode(GL_PROJECTION);
1005 glMatrixMode(GL_MODELVIEW);
1011 if( !HUD_deque.size() ) { // Trust everyone, but ALWAYS cut the cards!
1015 HUD_TextList.erase();
1016 HUD_LineList.erase();
1017 // HUD_StippleLineList.erase();
1019 glDisable(GL_DEPTH_TEST);
1020 glDisable(GL_LIGHTING);
1022 static const SGPropertyNode *antialiased_node
1023 = fgGetNode("/sim/hud/antialiased", true);
1024 static const SGPropertyNode *heading_enabled
1025 = fgGetNode("/autopilot/locks/heading", true);
1026 static const SGPropertyNode *altitude_enabled
1027 = fgGetNode("/autopilot/locks/altitude", true);
1029 static char hud_hdg_text[256];
1030 static char hud_wp0_text[256];
1031 static char hud_wp1_text[256];
1032 static char hud_wp2_text[256];
1033 static char hud_alt_text[256];
1035 if( antialiased_node->getBoolValue() ) {
1036 glEnable(GL_LINE_SMOOTH);
1037 // glEnable(GL_BLEND);
1038 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1039 glHint(GL_LINE_SMOOTH_HINT,GL_DONT_CARE);
1045 if( global_day_night_switch == HUD_DAY) {
1046 switch (HUD_deque[0]->get_brightness())
1049 set_hud_color (0.1f, 0.9f, 0.1f);
1052 case HUD_BRT_MEDIUM:
1053 set_hud_color (0.1f, 0.7f, 0.0f);
1057 set_hud_color (0.0f, 0.6f, 0.0f);
1061 set_hud_color( 0.0f, 0.0f, 0.0f);
1065 set_hud_color (0.1f, 0.9f, 0.1f);
1068 if( global_day_night_switch == HUD_NIGHT) {
1069 switch (HUD_deque[0]->get_brightness())
1072 set_hud_color (0.9f, 0.1f, 0.1f);
1075 case HUD_BRT_MEDIUM:
1076 set_hud_color (0.7f, 0.0f, 0.1f);
1080 set_hud_color (0.6f, 0.0f, 0.0f);
1084 set_hud_color( 0.0f, 0.0f, 0.0f);
1088 set_hud_color (0.6f, 0.0f, 0.0f);
1090 } else { // Just in case default
1091 set_hud_color (0.1f, 0.9f, 0.1f);
1095 for_each(HUD_deque.begin(), HUD_deque.end(), HUDdraw());
1097 HUD_TextList.add( fgText(40, 10, get_formated_gmt_time(), 0) );
1103 if (strcmp( heading_enabled->getStringValue(), "dg-heading-hold") == 0 ) {
1104 snprintf( hud_hdg_text, 256, "hdg = %.1f\n",
1105 fgGetDouble("/autopilot/settings/heading-bug-deg") );
1106 HUD_TextList.add( fgText( 40, apY, hud_hdg_text ) );
1108 } else if ( strcmp(heading_enabled->getStringValue(), "true-heading-hold") == 0 ) {
1109 snprintf( hud_hdg_text, 256, "hdg = %.1f\n",
1110 fgGetDouble("/autopilot/settings/true-heading-deg") );
1111 HUD_TextList.add( fgText( 40, apY, hud_hdg_text ) );
1114 string wp0_id = fgGetString( "/autopilot/route-manager/wp[0]/id" );
1115 if ( wp0_id.length() > 0 ) {
1116 snprintf( hud_wp0_text, 256, "%5s %6.1fnm %s", wp0_id.c_str(),
1117 fgGetDouble( "/autopilot/route-manager/wp[0]/dist" ),
1118 fgGetString( "/autopilot/route-manager/wp[0]/eta" ) );
1119 HUD_TextList.add( fgText( 40, apY, hud_wp0_text ) );
1122 string wp1_id = fgGetString( "/autopilot/route-manager/wp[1]/id" );
1123 if ( wp1_id.length() > 0 ) {
1124 snprintf( hud_wp1_text, 256, "%5s %6.1fnm %s", wp1_id.c_str(),
1125 fgGetDouble( "/autopilot/route-manager/wp[1]/dist" ),
1126 fgGetString( "/autopilot/route-manager/wp[1]/eta" ) );
1127 HUD_TextList.add( fgText( 40, apY, hud_wp1_text ) );
1130 string wp2_id = fgGetString( "/autopilot/route-manager/wp-last/id" );
1131 if ( wp2_id.length() > 0 ) {
1132 snprintf( hud_wp2_text, 256, "%5s %6.1fnm %s", wp2_id.c_str(),
1133 fgGetDouble( "/autopilot/route-manager/wp-last/dist" ),
1134 fgGetString( "/autopilot/route-manager/wp-last/eta" ) );
1135 HUD_TextList.add( fgText( 40, apY, hud_wp2_text ) );
1140 if ( strcmp( altitude_enabled->getStringValue(), "altitude-hold" ) == 0 ) {
1141 snprintf( hud_alt_text, 256, "alt = %.0f\n",
1142 fgGetDouble("/autopilot/settings/target-altitude-ft") );
1143 HUD_TextList.add( fgText( 40, apY, hud_alt_text ) );
1145 } else if ( strcmp( altitude_enabled->getStringValue(), "agl-hold" ) == 0 ){
1146 snprintf( hud_alt_text, 256, "agl = %.0f\n",
1147 fgGetDouble("/autopilot/settings/target-agl-ft") );
1148 HUD_TextList.add( fgText( 40, apY, hud_alt_text ) );
1152 HUD_TextList.draw();
1154 HUD_LineList.draw();
1156 // glEnable(GL_LINE_STIPPLE);
1157 // glLineStipple( 1, 0x00FF );
1158 // HUD_StippleLineList.draw();
1159 // glDisable(GL_LINE_STIPPLE);
1161 if( antialiased_node->getBoolValue() ) {
1162 // glDisable(GL_BLEND);
1163 glDisable(GL_LINE_SMOOTH);
1167 glEnable(GL_DEPTH_TEST);
1168 glEnable(GL_LIGHTING);