]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/hud.cxx
new FSF address
[flightgear.git] / src / Cockpit / hud.cxx
1 // hud.cxx -- hud defines and prototypes
2 //
3 // Written by Michele America, started September 1997.
4 //
5 // Copyright (C) 1997  Michele F. America  - micheleamerica@geocities.com
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23 #include <simgear/compiler.h>
24 #include <simgear/structure/exception.hxx>
25
26 #include STL_STRING
27 #include STL_FSTREAM
28
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif
32
33 #ifdef HAVE_WINDOWS_H
34 #  include <windows.h>
35 #endif
36
37 #ifdef __BORLANDC__
38 #  define exception c_exception
39 #endif
40
41 #include <math.h>
42
43 #include <stdlib.h>
44 #include <stdio.h>              // char related functions
45 #include <string.h>             // strcmp()
46
47 #include SG_GLU_H
48
49 #include <simgear/constants.h>
50 #include <simgear/debug/logstream.hxx>
51 #include <simgear/props/props.hxx>
52 #include <simgear/misc/sg_path.hxx>
53
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>
60
61 #if defined (__sun) || defined ( __sgi )
62 extern "C" {
63     extern void *memmove(void *, const void *, size_t);
64 }
65 #endif
66
67 #include "hud.hxx"
68
69 static char units[5];
70
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.
74 //
75
76 deque< instr_item * > HUD_deque;
77
78 fgTextList         HUD_TextList;
79 fgLineList         HUD_LineList;
80 fgLineList         HUD_StippleLineList;
81
82 fntRenderer *HUDtext = 0;
83 float  HUD_TextSize = 0;
84 int HUD_style = 0;
85
86 float HUD_matrix[16];
87
88
89 //$$$ begin - added, Neetha, 28 Nov 2k
90
91 static string   name;
92 static int              x;
93 static int              y;
94 static UINT    width;
95 static UINT    height;
96 static float    factor;
97 static float   span_units;
98 static float   division_units;
99 static float   minor_division = 0;
100 static UINT    screen_hole;
101 static UINT    lbl_pos;
102 static bool    working;
103 static string  loadfn;
104 static UINT     options;
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;
115 static int     justi;
116 static int              blinking;
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;
127 static bool     cap_top;
128 static bool     cap_right;
129 static bool     cap_left;
130 static float   marker_off;
131 static string  type;
132 static bool    enable_pointer;
133 static string  type_pointer;
134 static bool    frl_spot;
135 static bool     target;
136 static bool    vel_vector;
137 static bool    drift;
138 static bool    alpha;
139 static bool     energy;
140 static bool     climb_dive;
141 static bool     glide;
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
157
158
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;
163
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
171
172 static void drawHUD();
173 static void fgUpdateHUDVirtual();
174
175 class locRECT {
176 public:
177     RECT rect;
178
179     locRECT( UINT left, UINT top, UINT right, UINT bottom);
180     RECT get_rect(void) { return rect;}
181 };
182
183 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
184 {
185     rect.left   =  left;
186     rect.top    =  top;
187     rect.right  =  right;
188     rect.bottom =  bottom;
189
190 }
191 // #define DEBUG
192
193 //========================= End of Class Implementations===================
194 // fgHUDInit
195 //
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!
201 //
202
203 #define INSTRDEFS 21
204
205 //$$$ begin - added, Neetha, 28 Nov 2k
206 static instr_item * 
207 readLadder(const SGPropertyNode * node)
208 {
209
210     instr_item *p;
211
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))
241     {
242         if (HUD_style == 1)
243         {
244             factor = 1;
245             factor = (640./55.) / factor;
246         }
247     }
248
249     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
250         
251     p = (instr_item *) new HudLadder( name, x, y,
252                                       width, height, factor,
253                                       get_roll, get_pitch,
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);
259                                 
260     return p;
261                 
262 } //end readLadder
263
264 static instr_item * 
265 readCard(const SGPropertyNode * node)
266 {
267
268     instr_item *p;
269
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
302
303     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
304
305
306     if(type=="gauge") {
307         span_units = maxValue - minValue;
308     }
309
310     if (loadfn=="anzg") {
311         load_fn = get_anzg;
312     } else if (loadfn=="heading") {
313         load_fn = get_heading;
314     } else if (loadfn=="aoa") {
315         load_fn = get_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") {
321         load_fn = get_agl;
322     } else if (loadfn=="speed") {
323         load_fn = get_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;
336     }
337
338
339     if ( (type == "dial") | (type == "tape") ) {
340         p = (instr_item *) new hud_card( x,
341                                          y,  
342                                          width,
343                                          height,
344                                          load_fn,
345                                          options,
346                                          maxValue, minValue,
347                                          scaling,
348                                          major_divs, minor_divs,
349                                          modulator,
350                                          dp_showing,
351                                          span_units,
352                                          type,
353                                          tick_bottom,
354                                          tick_top,
355                                          tick_right,
356                                          tick_left,
357                                          cap_bottom,
358                                          cap_top,
359                                          cap_right,
360                                          cap_left,
361                                          marker_off,
362                                          enable_pointer,
363                                          type_pointer,
364                                          type_tick,//hud
365                                          length_tick,//hud
366                                          working,
367                                          radius, //suma
368                                          divisions, //suma
369                                          zoom  //suma
370                                          );
371     } else {
372         p = (instr_item *) new  gauge_instr( x,            // x
373                                              y,  // y
374                                              width,            // width
375                                              height,            // height
376                                              load_fn, // data source
377                                              options,
378                                              scaling,
379                                              maxValue,minValue,
380                                              major_divs, minor_divs,
381                                              dp_showing,
382                                              modulator,
383                                              working);
384     }
385
386     return p;
387 }// end readCard
388
389 static instr_item *
390 readLabel(const SGPropertyNode * node)
391 {
392     instr_item *p;
393
394     int font_size = (fgGetInt("/sim/startup/xsize") > 1000) ? HUD_FONT_LARGE : HUD_FONT_SMALL;
395
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
414
415
416     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
417
418
419     if ( justi == 0 ) {
420         justification = LEFT_JUST;
421     } else {
422         if ( justi == 1 ) {
423             justification = CENTER_JUST;
424         } else {
425             if ( justi == 2 ) {
426                 justification = RIGHT_JUST;
427             }
428         }
429     }
430
431     if ( prelabel == "NULL" ) {
432         pre_label_string = NULL;
433     } else {
434         if ( prelabel == "blank" ) {
435             pre_label_string = " ";
436         } else {
437             pre_label_string = prelabel.c_str();
438         }
439     }
440
441     if ( postlabel == "blank" ) {
442         post_label_string = " ";
443     } else {
444         if ( postlabel == "NULL" ) {
445             post_label_string = NULL;
446         } else {
447             if ( postlabel == "units" ) {
448                 post_label_string = units;
449             } else {
450                 post_label_string = postlabel.c_str();
451             }
452         }
453     }
454
455 #ifdef ENABLE_SP_FMDS
456     if ( loadfn== "aux1" ) {
457         load_fn = get_aux1;
458     } else if ( loadfn == "aux2" ) {
459         load_fn = get_aux2;
460     } else if ( loadfn == "aux3" ) {
461         load_fn = get_aux3;
462     } else if ( loadfn == "aux4" ) {
463         load_fn = get_aux4;
464     } else if ( loadfn == "aux5" ) {
465         load_fn = get_aux5;
466     } else if ( loadfn == "aux6" ) {
467         load_fn = get_aux6;
468     } else if ( loadfn == "aux7" ) {
469         load_fn = get_aux7;
470     } else if ( loadfn == "aux8" ) {
471         load_fn = get_aux8;
472     } else if ( loadfn == "aux9" ) {
473         load_fn = get_aux9;
474     } else if ( loadfn == "aux10" ) {
475         load_fn = get_aux10;
476     } else if ( loadfn == "aux11" ) {
477         load_fn = get_aux11;
478     } else if ( loadfn == "aux12" ) {
479         load_fn = get_aux12;
480     } else if ( loadfn == "aux13" ) {
481         load_fn = get_aux13;
482     } else if ( loadfn == "aux14" ) {
483         load_fn = get_aux14;
484     } else if ( loadfn == "aux15" ) {
485         load_fn = get_aux15;
486     } else if ( loadfn == "aux16" ) {
487         load_fn = get_aux16;
488     } else if ( loadfn == "aux17" ) {
489         load_fn = get_aux17;
490     } else if ( loadfn == "aux18" ) {
491         load_fn = get_aux18;
492     } else
493 #endif
494       if ( loadfn == "ax" ) {
495         load_fn = get_Ax;
496     } else if ( loadfn == "speed" ) {
497         load_fn = get_speed;
498     } else if ( loadfn == "mach" ) {
499         load_fn = get_mach;
500     } else if ( loadfn == "altitude" ) {
501         load_fn = get_altitude;
502     } else if ( loadfn == "agl" ) {
503         load_fn = get_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" ) {
509         load_fn = get_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" ) {
515         load_fn = get_aoa;
516     } else if ( loadfn == "latitude" ) {
517         load_fn  = get_latitude;
518     } else if ( loadfn == "anzg" ) {
519         load_fn = get_anzg;
520     } else if ( loadfn == "longitude" ) {
521         load_fn   = get_longitude;
522     } else if (loadfn=="throttleval") {
523         load_fn = get_throttleval;
524     }
525
526     p = (instr_item *) new instr_label ( x,
527                                          y,
528                                          width,
529                                          height,
530                                          load_fn,
531                                          label_format.c_str(),
532                                          pre_label_string,
533                                          post_label_string,
534                                          scaling,
535                                          options,
536                                          justification,
537                                          font_size,
538                                          blinking,
539                                          latitude,
540                                          longitude,
541                                          label_box, //hud
542                                          working,
543                                          digits); //suma
544
545     return p;
546 } // end readLabel
547
548 static instr_item * 
549 readTBI(const SGPropertyNode * node)
550 {
551
552     instr_item *p;
553
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
565
566     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
567
568
569     p = (instr_item *) new fgTBI_instr( x,
570                                         y,  
571                                         width,
572                                         height,
573                                         get_roll,
574                                         get_sideslip,
575                                         maxBankAngle, 
576                                         maxSlipAngle,
577                                         gap_width,
578                                         working,
579                                         tsi, //suma
580                                         rad); //suma
581
582     return p;
583 } //end readTBI
584
585 static instr_item * 
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;
606 }
607
608
609 int readInstrument(const SGPropertyNode * node)
610 {
611     static const SGPropertyNode *startup_units_node
612         = fgGetNode("/sim/startup/units");
613
614     instr_item *HIptr;
615     
616     if ( !strcmp(startup_units_node->getStringValue(), "feet") ) {
617         strcpy(units, " ft");
618     } else {
619         strcpy(units, " m");
620     }
621
622     const SGPropertyNode * ladder_group = node->getNode("ladders");
623
624     if (ladder_group != 0) {
625         int nLadders = ladder_group->nChildren();
626         for (int j = 0; j < nLadders; j++) {
627             
628             HIptr = readLadder(ladder_group->getChild(j));
629             HUD_deque.insert( HUD_deque.begin(), HIptr);
630                                         
631         }// for - ladders
632     }
633
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++) {
638             
639             HIptr = readCard(card_group->getChild(j));
640             HUD_deque.insert( HUD_deque.begin(), HIptr);
641
642         }//for - cards
643     }
644
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++) {
649
650             HIptr = readLabel(label_group->getChild(j));
651             HUD_deque.insert( HUD_deque.begin(), HIptr);
652
653         }//for - labels
654     }
655
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++) {
660
661             HIptr = readTBI(tbi_group->getChild(j));
662             HUD_deque.insert( HUD_deque.begin(), HIptr);
663
664         }//for - tbis
665     }
666     
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);
675
676         }//for - runways
677     }    
678     return 0;
679 }//end readinstrument
680
681
682 int readHud( istream &input ) 
683 {
684
685     SGPropertyNode root;
686
687     try {
688         readProperties(input, &root);
689     } catch (const sg_exception &e) {
690         guiErrorMessage("Error reading HUD: ", e);
691         return 0;
692     }
693   
694         
695     SG_LOG(SG_INPUT, SG_INFO, "Read properties for  " <<
696            root.getStringValue("name"));
697
698
699     HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());  // empty the HUD deque
700
701
702     SG_LOG(SG_INPUT, SG_INFO, "Reading Hud instruments");
703
704     const SGPropertyNode * instrument_group = root.getChild("instruments");
705     int nInstruments = instrument_group->nChildren();
706
707     for (int i = 0; i < nInstruments; i++) {
708                 
709         const SGPropertyNode * node = instrument_group->getChild(i);
710
711         SGPath path( globals->get_fg_root() );
712         path.append(node->getStringValue("path"));
713
714         SG_LOG(SG_INPUT, SG_INFO, "Reading Instrument "
715                << node->getName()
716                << " from "
717                << path.str());
718
719         SGPropertyNode root2;
720         try {
721             readProperties(path.str(), &root2);
722         } catch (const sg_exception &e) {
723             guiErrorMessage("Error reading HUD instrument: ", e);
724             continue;
725         } 
726         readInstrument(&root2);
727     }//for loop(i)
728
729     return 0;
730 }
731
732
733 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
734 {
735
736     HUD_style = 1;
737
738     SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
739
740     string hud_path =
741         fgGetString("/sim/hud/path", "Huds/Default/default.xml");
742     SGPath path(globals->get_fg_root());
743     path.append(hud_path);
744         
745     ifstream input(path.c_str());
746     if (!input.good()) {
747         SG_LOG(SG_INPUT, SG_ALERT,
748                "Cannot read Hud configuration from " << path.str());
749     } else {
750         readHud(input);
751         input.close();
752     }
753
754     fgHUDReshape();
755
756     if ( HUDtext ) {
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
760         // ourselves.
761         fntRenderer *tmp = HUDtext;
762         HUDtext = NULL;
763         delete tmp;
764     }
765
766 //    HUD_TextSize = fgGetInt("/sim/startup/xsize") / 60;
767     HUD_TextSize = 10;
768     HUDtext = new fntRenderer();
769     HUDtext -> setFont      ( guiFntHandle ) ;
770     HUDtext -> setPointSize ( HUD_TextSize ) ;
771     HUD_TextList.setFont( HUDtext );
772     
773     return 0;  // For now. Later we may use this for an error code.
774
775 }
776
777 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
778 {
779
780     HUD_style = 2;
781
782     SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
783
784     SGPath path(globals->get_fg_root());
785     path.append("Huds/Minimal/default.xml");
786
787
788     ifstream input(path.c_str());
789     if (!input.good()) {
790         SG_LOG(SG_INPUT, SG_ALERT,
791                "Cannot read Hud configuration from " << path.str());
792     } else {
793         readHud(input);
794         input.close();
795     }
796
797     return 0;  // For now. Later we may use this for an error code.
798
799 }
800 //$$$ End - added, Neetha, 28 Nov 2k  
801
802 static int global_day_night_switch = HUD_DAY;
803
804 void HUD_masterswitch( bool incr )
805 {
806     if ( fgGetBool("/sim/hud/visibility") ) {
807         if ( global_day_night_switch == HUD_DAY ) {
808             global_day_night_switch = HUD_NIGHT;
809         } else {
810             fgSetBool("/sim/hud/visibility", false);
811         }
812     } else {
813         fgSetBool("/sim/hud/visibility", true);
814         global_day_night_switch = HUD_DAY;
815     }   
816 }
817
818 void HUD_brightkey( bool incr_bright )
819 {
820     instr_item *pHUDInstr = HUD_deque[0];
821     int brightness        = pHUDInstr->get_brightness();
822
823     if( fgGetBool("/sim/hud/visibility") ) {
824         if( incr_bright ) {
825             switch (brightness)
826                 {
827                 case HUD_BRT_LIGHT:
828                     brightness = HUD_BRT_BLACK;
829                     break;
830
831                 case HUD_BRT_MEDIUM:
832                     brightness = HUD_BRT_LIGHT;
833                     break;
834
835                 case HUD_BRT_DARK:
836                     brightness = HUD_BRT_MEDIUM;
837                     break;
838
839                 case HUD_BRT_BLACK:
840                     brightness = HUD_BRT_DARK;
841                     break;
842
843                 default:
844                     brightness = HUD_BRT_BLACK;
845                 }
846         } else {
847             switch (brightness)
848                 {
849                 case HUD_BRT_LIGHT:
850                     brightness = HUD_BRT_MEDIUM;
851                     break;
852
853                 case HUD_BRT_MEDIUM:
854                     brightness = HUD_BRT_DARK;
855                     break;
856
857                 case HUD_BRT_DARK:
858                     brightness = HUD_BRT_BLACK;
859                     break;
860
861                 case HUD_BRT_BLACK:
862                     brightness = HUD_BRT_LIGHT;
863                     break;
864
865                 default:
866                     fgSetBool("/sim/hud/visibility", false);
867                 }
868         }
869     } else {
870         fgSetBool("/sim/hud/visibility", true);
871     }
872
873     pHUDInstr->SetBrightness( brightness );
874 }
875
876
877 void fgHUDReshape(void) {
878 #if 0
879     if ( HUDtext ) {
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
883         // ourselves.
884         fntRenderer *tmp = HUDtext;
885         HUDtext = NULL;
886         delete tmp;
887     }
888
889     HUD_TextSize = fgGetInt("/sim/startup/xsize") / 60;
890     HUD_TextSize = 10;
891     HUDtext = new fntRenderer();
892     HUDtext -> setFont      ( guiFntHandle ) ;
893     HUDtext -> setPointSize ( HUD_TextSize ) ;
894     HUD_TextList.setFont( HUDtext );
895 #endif
896 }
897
898
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);
902
903     if (alias->getBoolValue())
904         glColor4f(r, g, b, alpha->getFloatValue());
905     else
906         glColor3f(r, g, b);
907 }
908
909
910 // fgUpdateHUD
911 //
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
914 // all C++.
915 //
916 void fgUpdateHUD( void ) {
917         
918     static const SGPropertyNode *enable3d_node = fgGetNode("/sim/hud/enable3d");
919     if( HUD_style == 1 && enable3d_node->getBoolValue() )
920     {
921         fgUpdateHUDVirtual();
922         return;
923     }
924     
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 );
932     } else {
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 );
936     }
937 }
938
939 void fgUpdateHUDVirtual()
940 {
941     FGViewer* view = globals->get_current_view();
942
943     // Standard fgfs projection, with essentially meaningless clip
944     // planes (we'll map the whole HUD plane to z=-1)
945     glMatrixMode(GL_PROJECTION);
946     glPushMatrix();
947     glLoadIdentity();
948     gluPerspective(view->get_v_fov(), 1/view->get_aspect_ratio(), 0.1, 10);
949
950     glMatrixMode(GL_MODELVIEW);
951     glPushMatrix();
952     glLoadIdentity();
953   
954     // Standard fgfs view direction computation
955     float lookat[3];
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);
961
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
967     float m[16];
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;
972     glMultMatrixf(m);
973
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);
978
979     // Do the deed
980     drawHUD();
981
982     // Clean up our mess
983     glMatrixMode(GL_PROJECTION);
984     glPopMatrix();
985     glMatrixMode(GL_MODELVIEW);
986     glPopMatrix();
987 }
988
989 void fgUpdateHUD( GLfloat x_start, GLfloat y_start,
990                   GLfloat x_end, GLfloat y_end )
991 {
992     glMatrixMode(GL_PROJECTION);
993     glPushMatrix();
994     glLoadIdentity();
995     gluOrtho2D(x_start, x_end, y_start, y_end);
996
997     glMatrixMode(GL_MODELVIEW);
998     glPushMatrix();
999     glLoadIdentity();
1000
1001     drawHUD();
1002
1003     glMatrixMode(GL_PROJECTION);
1004     glPopMatrix();
1005     glMatrixMode(GL_MODELVIEW);
1006     glPopMatrix();
1007 }
1008
1009 void drawHUD()
1010 {
1011     if( !HUD_deque.size() ) {  // Trust everyone, but ALWAYS cut the cards!
1012         return;
1013     }
1014
1015     HUD_TextList.erase();
1016     HUD_LineList.erase();
1017     // HUD_StippleLineList.erase();
1018   
1019     glDisable(GL_DEPTH_TEST);
1020     glDisable(GL_LIGHTING);
1021
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);
1028
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];
1034
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);
1040         glLineWidth(2.0);
1041     } else {
1042         glLineWidth(1.0);
1043     }
1044
1045     if( global_day_night_switch == HUD_DAY) {
1046         switch (HUD_deque[0]->get_brightness())
1047             {
1048             case HUD_BRT_LIGHT:
1049                 set_hud_color (0.1f, 0.9f, 0.1f);
1050                 break;
1051
1052             case HUD_BRT_MEDIUM:
1053                 set_hud_color (0.1f, 0.7f, 0.0f);
1054                 break;
1055
1056             case HUD_BRT_DARK:
1057                 set_hud_color (0.0f, 0.6f, 0.0f);
1058                 break;
1059
1060             case HUD_BRT_BLACK:
1061                 set_hud_color( 0.0f, 0.0f, 0.0f);
1062                 break;
1063
1064             default:
1065                 set_hud_color (0.1f, 0.9f, 0.1f);
1066             }
1067     } else {
1068         if( global_day_night_switch == HUD_NIGHT) {
1069             switch (HUD_deque[0]->get_brightness())
1070                 {
1071                 case HUD_BRT_LIGHT:
1072                     set_hud_color (0.9f, 0.1f, 0.1f);
1073                     break;
1074
1075                 case HUD_BRT_MEDIUM:
1076                     set_hud_color (0.7f, 0.0f, 0.1f);
1077                     break;
1078
1079                 case HUD_BRT_DARK:
1080                     set_hud_color (0.6f, 0.0f, 0.0f);
1081                     break;
1082
1083                 case HUD_BRT_BLACK:
1084                     set_hud_color( 0.0f, 0.0f, 0.0f);
1085                     break;
1086
1087                 default:
1088                     set_hud_color (0.6f, 0.0f, 0.0f);
1089                 }
1090         } else {     // Just in case default
1091             set_hud_color (0.1f, 0.9f, 0.1f);
1092         }
1093     }
1094
1095     for_each(HUD_deque.begin(), HUD_deque.end(), HUDdraw());
1096
1097     HUD_TextList.add( fgText(40, 10, get_formated_gmt_time(), 0) );
1098
1099
1100     int apY = 480 - 80;
1101     
1102     
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 ) );
1107         apY -= 15;
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 ) );
1112         apY -= 15;
1113
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 ) );
1120             apY -= 15;
1121         }
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 ) );
1128             apY -= 15;
1129         }
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 ) );
1136             apY -= 15;
1137         }
1138     }
1139   
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 ) );
1144         apY -= 15;
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 ) );
1149         apY -= 15;
1150     }
1151
1152     HUD_TextList.draw();
1153
1154     HUD_LineList.draw();
1155
1156     // glEnable(GL_LINE_STIPPLE);
1157     // glLineStipple( 1, 0x00FF );
1158     // HUD_StippleLineList.draw();
1159     // glDisable(GL_LINE_STIPPLE);
1160
1161     if( antialiased_node->getBoolValue() ) {
1162         // glDisable(GL_BLEND);
1163         glDisable(GL_LINE_SMOOTH);
1164         glLineWidth(1.0);
1165     }
1166
1167     glEnable(GL_DEPTH_TEST);
1168     glEnable(GL_LIGHTING);
1169 }
1170