]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/hud.cxx
fix ugly aliasing effects in moving scales (caused by integer calculation
[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 #include "hud.hxx"
62
63
64 static HUD_Properties *HUD = 0;
65
66 static char units[5];
67
68 // The following routines obtain information concerning the aircraft's
69 // current state and return it to calling instrument display routines.
70 // They should eventually be member functions of the aircraft.
71 //
72
73 deque< instr_item * > HUD_deque;
74
75 fgTextList         HUD_TextList;
76 fgLineList         HUD_LineList;
77 fgLineList         HUD_StippleLineList;
78
79 fntRenderer *HUDtext = 0;
80 fntTexFont *HUD_Font = 0;
81 float HUD_TextSize = 0;
82 int HUD_style = 0;
83
84 float HUD_matrix[16];
85
86
87 //$$$ begin - added, Neetha, 28 Nov 2k
88
89 static string  name;
90 static int     x;
91 static int     y;
92 static UINT    width;
93 static UINT    height;
94 static float   factor;
95 static float   span_units;
96 static float   division_units;
97 static float   minor_division = 0;
98 static UINT    screen_hole;
99 static UINT    lbl_pos;
100 static bool    working;
101 static string  loadfn;
102 static UINT    options;
103 static float   maxValue;
104 static float   minValue;
105 static float   scaling;
106 static UINT    major_divs;
107 static UINT    minor_divs;
108 static UINT    modulator;
109 static int     dp_showing = 0;
110 static string  label_format;
111 static string  prelabel;
112 static string  postlabel;
113 static int     justi;
114 static int     blinking;
115 static float   maxBankAngle;
116 static float   maxSlipAngle;
117 static UINT    gap_width;
118 static bool    latitude;
119 static bool    longitude;
120 static bool    tick_bottom;
121 static bool    tick_top;
122 static bool    tick_right;
123 static bool    tick_left;
124 static bool    cap_bottom;
125 static bool    cap_top;
126 static bool    cap_right;
127 static bool    cap_left;
128 static float   marker_off;
129 static string  type;
130 static bool    enable_pointer;
131 static string  type_pointer;
132 static bool    frl_spot;
133 static bool    target;
134 static bool    vel_vector;
135 static bool    drift;
136 static bool    alpha;
137 static bool    energy;
138 static bool    climb_dive;
139 static bool    glide;
140 static float   glide_slope_val;
141 static bool    worm_energy;
142 static bool    waypoint;
143 static string  type_tick;//hud
144 static string  length_tick;//hud
145 static bool    label_box;//hud
146 static int     digits; //suma
147 static float   radius; //suma
148 static int     divisions; //suma
149 static int     zoom; //suma
150 static int     zenith; //suma
151 static int     nadir ; //suma
152 static int     hat; //suma
153 static bool    tsi; //suma
154 static float   rad; //suma
155
156
157 static FLTFNPTR load_fn;
158 static fgLabelJust justification;
159 static const char *pre_label_string  = 0;
160 static const char *post_label_string = 0;
161
162 int readHud( istream &input );
163 int readInstrument ( const SGPropertyNode * node);
164 static instr_item * readLadder ( const SGPropertyNode * node);
165 static instr_item * readCard ( const SGPropertyNode * node);
166 static instr_item * readLabel( const SGPropertyNode * node);
167 static instr_item * readTBI( const SGPropertyNode * node);
168 //$$$ end   - added, Neetha, 28 Nov 2k
169
170 static void drawHUD();
171 static void fgUpdateHUDVirtual();
172
173 class locRECT {
174 public:
175     RECT rect;
176
177     locRECT( UINT left, UINT top, UINT right, UINT bottom);
178     RECT get_rect(void) { return rect;}
179 };
180
181 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
182 {
183     rect.left   =  left;
184     rect.top    =  top;
185     rect.right  =  right;
186     rect.bottom =  bottom;
187
188 }
189 // #define DEBUG
190
191 //========================= End of Class Implementations===================
192 // fgHUDInit
193 //
194 // Constructs a HUD object and then adds in instruments. At the present
195 // the instruments are hard coded into the routine. Ultimately these need
196 // to be defined by the aircraft's instrumentation records so that the
197 // display for a Piper Cub doesn't show the speed range of a North American
198 // mustange and the engine readouts of a B36!
199 //
200
201 #define INSTRDEFS 21
202
203 //$$$ begin - added, Neetha, 28 Nov 2k
204 static instr_item *
205 readLadder(const SGPropertyNode * node)
206 {
207
208     instr_item *p;
209
210     name               = node->getStringValue("name");
211     x                  = node->getIntValue("x");
212     y                  = node->getIntValue("y");
213     width              = node->getIntValue("width");
214     height             = node->getIntValue("height");
215     factor             = node->getFloatValue("compression_factor");
216     span_units         = node->getFloatValue("span_units");
217     division_units     = node->getFloatValue("division_units");
218     screen_hole        = node->getIntValue("screen_hole");
219     lbl_pos            = node->getIntValue("lbl_pos");
220     frl_spot           = node->getBoolValue("enable_frl",false);
221     target             = node->getBoolValue("enable_target_spot",false);
222     vel_vector         = node->getBoolValue("enable_velocity_vector",false);
223     drift              = node->getBoolValue("enable_drift_marker",false);
224     alpha              = node->getBoolValue("enable_alpha_bracket",false);
225     energy             = node->getBoolValue("enable_energy_marker",false);
226     climb_dive         = node->getBoolValue("enable_climb_dive_marker",false);
227     glide              = node->getBoolValue("enable_glide_slope_marker",false);
228     glide_slope_val    = node->getFloatValue("glide_slope",-4.0);
229     worm_energy        = node->getBoolValue("enable_energy_marker",false);
230     waypoint           = node->getBoolValue("enable_waypoint_marker",false);
231     working            = node->getBoolValue("working");
232     zenith             = node->getIntValue("zenith");  //suma
233     nadir              = node->getIntValue("nadir");  //suma
234     hat                = node->getIntValue("hat");
235     // The factor assumes a base of 55 degrees per 640 pixels.
236     // Invert to convert the "compression" factor to a
237     // pixels-per-degree number.
238     if(fgGetBool("/sim/hud/enable3d", true))
239     {
240         if (HUD_style == 1)
241         {
242             factor = 1;
243             factor = (640./55.) / factor;
244         }
245     }
246
247     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
248
249     p = (instr_item *) new HudLadder( name, x, y,
250                                       width, height, factor,
251                                       get_roll, get_pitch,
252                                       span_units, division_units, minor_division,
253                                       screen_hole, lbl_pos, frl_spot, target, vel_vector,
254                                       drift, alpha, energy, climb_dive,
255                                       glide, glide_slope_val, worm_energy,
256                                       waypoint, working, zenith, nadir, hat);
257
258     return p;
259
260 } //end readLadder
261
262 static instr_item *
263 readCard(const SGPropertyNode * node)
264 {
265
266     instr_item *p;
267
268     name               = node->getStringValue("name");
269     x                  = node->getIntValue("x");
270     y                  = node->getIntValue("y");
271     width              = node->getIntValue("width");
272     height             = node->getIntValue("height");
273     loadfn             = node->getStringValue("loadfn");
274     options            = node->getIntValue("options");
275     maxValue           = node->getFloatValue("maxValue");
276     minValue           = node->getFloatValue("minValue");
277     scaling            = node->getFloatValue("disp_scaling");
278     major_divs         = node->getIntValue("major_divs");
279     minor_divs         = node->getIntValue("minor_divs");
280     modulator          = node->getIntValue("modulator");
281     span_units         = node->getFloatValue("value_span");
282     type               = node->getStringValue("type");
283     tick_bottom        = node->getBoolValue("tick_bottom",false);
284     tick_top           = node->getBoolValue("tick_top",false);
285     tick_right         = node->getBoolValue("tick_right",false);
286     tick_left          = node->getBoolValue("tick_left",false);
287     cap_bottom         = node->getBoolValue("cap_bottom",false);
288     cap_top            = node->getBoolValue("cap_top",false);
289     cap_right          = node->getBoolValue("cap_right",false);
290     cap_left           = node->getBoolValue("cap_left",false);
291     marker_off         = node->getFloatValue("marker_offset",0.0);
292     enable_pointer     = node->getBoolValue("enable_pointer",true);
293     type_pointer       = node->getStringValue("pointer_type");
294     type_tick          = node->getStringValue("tick_type");//hud Can be 'circle' or 'line'
295     length_tick        = node->getStringValue("tick_length");//hud For variable length
296     working            = node->getBoolValue("working");
297     radius             = node->getFloatValue("radius"); //suma
298     divisions          = node->getIntValue("divisions"); //suma
299     zoom               = node->getIntValue("zoom"); //suma
300
301     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
302
303
304     if(type=="gauge") {
305         span_units = maxValue - minValue;
306     }
307
308     if (loadfn=="anzg") {
309         load_fn = get_anzg;
310     } else if (loadfn=="heading") {
311         load_fn = get_heading;
312     } else if (loadfn=="aoa") {
313         load_fn = get_aoa;
314     } else if (loadfn=="climb") {
315         load_fn = get_climb_rate;
316     } else if (loadfn=="altitude") {
317         load_fn = get_altitude;
318     } else if (loadfn=="agl") {
319         load_fn = get_agl;
320     } else if (loadfn=="speed") {
321         load_fn = get_speed;
322     } else if (loadfn=="view_direction") {
323         load_fn = get_view_direction;
324     } else if (loadfn=="aileronval") {
325         load_fn = get_aileronval;
326     } else if (loadfn=="elevatorval") {
327         load_fn = get_elevatorval;
328     } else if (loadfn=="elevatortrimval") {
329         load_fn = get_elev_trimval;
330     } else if (loadfn=="rudderval") {
331         load_fn = get_rudderval;
332     } else if (loadfn=="throttleval") {
333         load_fn = get_throttleval;
334     }
335
336
337     if ( (type == "dial") | (type == "tape") ) {
338         p = (instr_item *) new hud_card( x,
339                                          y,
340                                          width,
341                                          height,
342                                          load_fn,
343                                          options,
344                                          maxValue, minValue,
345                                          scaling,
346                                          major_divs, minor_divs,
347                                          modulator,
348                                          dp_showing,
349                                          span_units,
350                                          type,
351                                          tick_bottom,
352                                          tick_top,
353                                          tick_right,
354                                          tick_left,
355                                          cap_bottom,
356                                          cap_top,
357                                          cap_right,
358                                          cap_left,
359                                          marker_off,
360                                          enable_pointer,
361                                          type_pointer,
362                                          type_tick,//hud
363                                          length_tick,//hud
364                                          working,
365                                          radius, //suma
366                                          divisions, //suma
367                                          zoom  //suma
368                                          );
369     } else {
370         p = (instr_item *) new  gauge_instr( x,       // x
371                                              y,       // y
372                                              width,   // width
373                                              height,  // height
374                                              load_fn, // data source
375                                              options,
376                                              scaling,
377                                              maxValue,minValue,
378                                              major_divs, minor_divs,
379                                              dp_showing,
380                                              modulator,
381                                              working);
382     }
383
384     return p;
385 }// end readCard
386
387 static instr_item *
388 readLabel(const SGPropertyNode * node)
389 {
390     instr_item *p;
391
392     int font_size = (fgGetInt("/sim/startup/xsize") > 1000) ? HUD_FONT_LARGE : HUD_FONT_SMALL;
393
394     name               = node->getStringValue("name");
395     x                  = node->getIntValue("x");
396     y                  = node->getIntValue("y");
397     width              = node->getIntValue("width");
398     height             = node->getIntValue("height");
399     loadfn             = node->getStringValue("data_source");
400     label_format       = node->getStringValue("label_format");
401     prelabel           = node->getStringValue("pre_label_string");
402     postlabel          = node->getStringValue("post_label_string");
403     scaling            = node->getFloatValue("scale_data");
404     options            = node->getIntValue("options");
405     justi              = node->getIntValue("justification");
406     blinking           = node->getIntValue("blinking");
407     latitude           = node->getBoolValue("latitude",false);
408     longitude          = node->getBoolValue("longitude",false);
409     label_box          = node->getBoolValue("label_box",false);//hud
410     working            = node->getBoolValue("working");
411     digits             = node->getIntValue("digits"); //suma
412
413
414     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
415
416
417     if ( justi == 0 ) {
418         justification = LEFT_JUST;
419     } else {
420         if ( justi == 1 ) {
421             justification = CENTER_JUST;
422         } else {
423             if ( justi == 2 ) {
424                 justification = RIGHT_JUST;
425             }
426         }
427     }
428
429     if ( prelabel == "NULL" ) {
430         pre_label_string = NULL;
431     } else {
432         if ( prelabel == "blank" ) {
433             pre_label_string = " ";
434         } else {
435             pre_label_string = prelabel.c_str();
436         }
437     }
438
439     if ( postlabel == "blank" ) {
440         post_label_string = " ";
441     } else {
442         if ( postlabel == "NULL" ) {
443             post_label_string = NULL;
444         } else {
445             if ( postlabel == "units" ) {
446                 post_label_string = units;
447             } else {
448                 post_label_string = postlabel.c_str();
449             }
450         }
451     }
452
453 #ifdef ENABLE_SP_FMDS
454     if ( loadfn== "aux1" ) {
455         load_fn = get_aux1;
456     } else if ( loadfn == "aux2" ) {
457         load_fn = get_aux2;
458     } else if ( loadfn == "aux3" ) {
459         load_fn = get_aux3;
460     } else if ( loadfn == "aux4" ) {
461         load_fn = get_aux4;
462     } else if ( loadfn == "aux5" ) {
463         load_fn = get_aux5;
464     } else if ( loadfn == "aux6" ) {
465         load_fn = get_aux6;
466     } else if ( loadfn == "aux7" ) {
467         load_fn = get_aux7;
468     } else if ( loadfn == "aux8" ) {
469         load_fn = get_aux8;
470     } else if ( loadfn == "aux9" ) {
471         load_fn = get_aux9;
472     } else if ( loadfn == "aux10" ) {
473         load_fn = get_aux10;
474     } else if ( loadfn == "aux11" ) {
475         load_fn = get_aux11;
476     } else if ( loadfn == "aux12" ) {
477         load_fn = get_aux12;
478     } else if ( loadfn == "aux13" ) {
479         load_fn = get_aux13;
480     } else if ( loadfn == "aux14" ) {
481         load_fn = get_aux14;
482     } else if ( loadfn == "aux15" ) {
483         load_fn = get_aux15;
484     } else if ( loadfn == "aux16" ) {
485         load_fn = get_aux16;
486     } else if ( loadfn == "aux17" ) {
487         load_fn = get_aux17;
488     } else if ( loadfn == "aux18" ) {
489         load_fn = get_aux18;
490     } else
491 #endif
492     if ( loadfn == "ax" ) {
493         load_fn = get_Ax;
494     } else if ( loadfn == "speed" ) {
495         load_fn = get_speed;
496     } else if ( loadfn == "mach" ) {
497         load_fn = get_mach;
498     } else if ( loadfn == "altitude" ) {
499         load_fn = get_altitude;
500     } else if ( loadfn == "agl" ) {
501         load_fn = get_agl;
502     } else if ( loadfn == "framerate" ) {
503         load_fn = get_frame_rate;
504     } else if ( loadfn == "heading" ) {
505         load_fn = get_heading;
506     } else if ( loadfn == "fov" ) {
507         load_fn = get_fov;
508     } else if ( loadfn == "vfc_tris_culled" ) {
509         load_fn = get_vfc_tris_culled;
510     } else if ( loadfn == "vfc_tris_drawn" ) {
511         load_fn = get_vfc_tris_drawn;
512     } else if ( loadfn == "aoa" ) {
513         load_fn = get_aoa;
514     } else if ( loadfn == "latitude" ) {
515         load_fn  = get_latitude;
516     } else if ( loadfn == "anzg" ) {
517         load_fn = get_anzg;
518     } else if ( loadfn == "longitude" ) {
519         load_fn   = get_longitude;
520     } else if (loadfn=="throttleval") {
521         load_fn = get_throttleval;
522     }
523
524     p = (instr_item *) new instr_label ( x,
525                                          y,
526                                          width,
527                                          height,
528                                          load_fn,
529                                          label_format.c_str(),
530                                          pre_label_string,
531                                          post_label_string,
532                                          scaling,
533                                          options,
534                                          justification,
535                                          font_size,
536                                          blinking,
537                                          latitude,
538                                          longitude,
539                                          label_box, //hud
540                                          working,
541                                          digits); //suma
542
543     return p;
544 } // end readLabel
545
546 static instr_item *
547 readTBI(const SGPropertyNode * node)
548 {
549
550     instr_item *p;
551
552     name           = node->getStringValue("name");
553     x              = node->getIntValue("x");
554     y              = node->getIntValue("y");
555     width          = node->getIntValue("width");
556     height         = node->getIntValue("height");
557     maxBankAngle   = node->getFloatValue("maxBankAngle");
558     maxSlipAngle   = node->getFloatValue("maxSlipAngle");
559     gap_width      = node->getIntValue("gap_width");
560     working        = node->getBoolValue("working");
561     tsi            = node->getBoolValue("tsi"); //suma
562     rad            = node->getFloatValue("rad"); //suma
563
564     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
565
566
567     p = (instr_item *) new fgTBI_instr( x,
568                                         y,
569                                         width,
570                                         height,
571                                         get_roll,
572                                         get_sideslip,
573                                         maxBankAngle,
574                                         maxSlipAngle,
575                                         gap_width,
576                                         working,
577                                         tsi, //suma
578                                         rad); //suma
579
580     return p;
581 } //end readTBI
582
583 static instr_item *
584 readRunway(const SGPropertyNode * node) {
585         name     = node->getStringValue("name");
586         x        = node->getIntValue("x");
587         y        = node->getIntValue("y");
588         width    = node->getIntValue("width");
589         height   = node->getIntValue("height");
590         scaling  = node->getDoubleValue("scale");
591         working  = node->getBoolValue("working",true);
592         runway_instr *ri = new runway_instr(x,y,width,height,scaling,working);
593         double scale = node->getDoubleValue("arrow_scale",1.0);
594         ri->setDrawArrow((scale>0)?true:false);
595         ri->setDrawArrowAlways((scale>0)?node->getBoolValue("arrow_always"):false);
596         ri->setStippleOutline(node->getIntValue("outer_stipple",0xFFFF));
597         ri->setStippleCenterline(node->getIntValue("center_stipple",0xFFFF));
598         ri->setArrowRotationRadius(node->getDoubleValue("arrow_radius"));
599         ri->setArrowScale(scale);
600         ri->setLineScale(node->getDoubleValue("line_scale",1.0));
601         ri->setScaleDist(node->getDoubleValue("scale_dist_nm"));
602         SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
603         return (instr_item *) ri;
604 }
605
606
607 int readInstrument(const SGPropertyNode * node)
608 {
609     static const SGPropertyNode *startup_units_node
610         = fgGetNode("/sim/startup/units");
611
612     instr_item *HIptr;
613
614     if ( !strcmp(startup_units_node->getStringValue(), "feet") ) {
615         strcpy(units, " ft");
616     } else {
617         strcpy(units, " m");
618     }
619
620     const SGPropertyNode * ladder_group = node->getNode("ladders");
621
622     if (ladder_group != 0) {
623         int nLadders = ladder_group->nChildren();
624         for (int j = 0; j < nLadders; j++) {
625
626             HIptr = readLadder(ladder_group->getChild(j));
627             HUD_deque.insert( HUD_deque.begin(), HIptr);
628
629         }// for - ladders
630     }
631
632     const SGPropertyNode * card_group = node->getNode("cards");
633     if (card_group != 0) {
634         int nCards = card_group->nChildren();
635         for (int j = 0; j < nCards; j++) {
636
637             HIptr = readCard(card_group->getChild(j));
638             HUD_deque.insert( HUD_deque.begin(), HIptr);
639
640         }//for - cards
641     }
642
643     const SGPropertyNode * label_group = node->getNode("labels");
644     if (label_group != 0) {
645         int nLabels = label_group->nChildren();
646         for (int j = 0; j < nLabels; j++) {
647
648             HIptr = readLabel(label_group->getChild(j));
649             HUD_deque.insert( HUD_deque.begin(), HIptr);
650
651         }//for - labels
652     }
653
654     const SGPropertyNode * tbi_group = node->getNode("tbis");
655     if (tbi_group != 0) {
656         int nTbis = tbi_group->nChildren();
657         for (int j = 0; j < nTbis; j++) {
658
659             HIptr = readTBI(tbi_group->getChild(j));
660             HUD_deque.insert( HUD_deque.begin(), HIptr);
661
662         }//for - tbis
663     }
664
665     const SGPropertyNode * rwy_group = node->getNode("runways");
666     if (rwy_group != 0) {
667         int nRwy = rwy_group->nChildren();
668         for (int j = 0; j < nRwy; j++) {
669             SG_LOG( SG_COCKPIT, SG_DEBUG,
670                     "**************  Reading runway properties" );
671             HIptr = readRunway(rwy_group->getChild(j));
672             HUD_deque.insert( HUD_deque.begin(), HIptr);
673
674         }//for - runways
675     }
676     return 0;
677 }//end readinstrument
678
679
680 int readHud( istream &input )
681 {
682
683     SGPropertyNode root;
684
685     try {
686         readProperties(input, &root);
687     } catch (const sg_exception &e) {
688         guiErrorMessage("Error reading HUD: ", e);
689         return 0;
690     }
691
692
693     SG_LOG(SG_INPUT, SG_INFO, "Read properties for  " <<
694            root.getStringValue("name"));
695
696
697     HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());
698
699
700     SG_LOG(SG_INPUT, SG_INFO, "Reading Hud instruments");
701
702     const SGPropertyNode * instrument_group = root.getChild("instruments");
703     int nInstruments = instrument_group->nChildren();
704
705     for (int i = 0; i < nInstruments; i++) {
706
707         const SGPropertyNode * node = instrument_group->getChild(i);
708
709         SGPath path( globals->get_fg_root() );
710         path.append(node->getStringValue("path"));
711
712         SG_LOG(SG_INPUT, SG_INFO, "Reading Instrument "
713                << node->getName()
714                << " from "
715                << path.str());
716
717         SGPropertyNode root2;
718         try {
719             readProperties(path.str(), &root2);
720         } catch (const sg_exception &e) {
721             guiErrorMessage("Error reading HUD instrument: ", e);
722             continue;
723         }
724         readInstrument(&root2);
725     }//for loop(i)
726
727     return 0;
728 }
729
730
731 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
732 {
733
734     HUD_style = 1;
735
736     SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
737
738     string hud_path =
739         fgGetString("/sim/hud/path", "Huds/Default/default.xml");
740     SGPath path(globals->get_fg_root());
741     path.append(hud_path);
742
743     ifstream input(path.c_str());
744     if (!input.good()) {
745         SG_LOG(SG_INPUT, SG_ALERT,
746                "Cannot read Hud configuration from " << path.str());
747     } else {
748         readHud(input);
749         input.close();
750     }
751
752     fgHUDReshape();
753
754     if ( HUDtext ) {
755         // this chunk of code is not necessarily thread safe if the
756         // compiler optimizer reorders these statements.  Note that
757         // "delete ptr" does not set "ptr = NULL".  We have to do that
758         // ourselves.
759         fntRenderer *tmp = HUDtext;
760         HUDtext = NULL;
761         delete tmp;
762     }
763
764     FGFontCache *fc = globals->get_fontcache();
765     HUD_Font = fc->getTexFont(fgGetString("/sim/hud/font/name", "Helvetica.txf"));
766     if (!HUD_Font)
767         throw sg_throwable(string("/sim/hud/font/name is not a texture font"));
768
769     HUD_TextSize = fgGetFloat("/sim/hud/font/size", 10);
770
771     HUDtext = new fntRenderer();
772     HUDtext->setFont(HUD_Font);
773     HUDtext->setPointSize(HUD_TextSize);
774     HUD_TextList.setFont( HUDtext );
775
776     if (!HUD)
777         HUD = new HUD_Properties;
778     return 0;  // For now. Later we may use this for an error code.
779
780 }
781
782 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
783 {
784
785     HUD_style = 2;
786
787     SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
788
789     SGPath path(globals->get_fg_root());
790     path.append("Huds/Minimal/default.xml");
791
792
793     ifstream input(path.c_str());
794     if (!input.good()) {
795         SG_LOG(SG_INPUT, SG_ALERT,
796                "Cannot read Hud configuration from " << path.str());
797     } else {
798         readHud(input);
799         input.close();
800     }
801
802     if (!HUD)
803         HUD = new HUD_Properties;
804     return 0;  // For now. Later we may use this for an error code.
805
806 }
807 //$$$ End - added, Neetha, 28 Nov 2k
808
809
810 void fgHUDReshape(void) {
811 #if 0
812     if ( HUDtext ) {
813         // this chunk of code is not necessarily thread safe if the
814         // compiler optimizer reorders these statements.  Note that
815         // "delete ptr" does not set "ptr = NULL".  We have to do that
816         // ourselves.
817         fntRenderer *tmp = HUDtext;
818         HUDtext = NULL;
819         delete tmp;
820     }
821
822     HUD_TextSize = fgGetInt("/sim/startup/xsize") / 60;
823     HUD_TextSize = 10;
824     HUDtext = new fntRenderer();
825     HUDtext -> setFont      ( guiFntHandle ) ;
826     HUDtext -> setPointSize ( HUD_TextSize ) ;
827     HUD_TextList.setFont( HUDtext );
828 #endif
829 }
830
831
832 // fgUpdateHUD
833 //
834 // Performs a once around the list of calls to instruments installed in
835 // the HUD object with requests for redraw. Kinda. It will when this is
836 // all C++.
837 //
838 void fgUpdateHUD( void ) {
839
840     static const SGPropertyNode *enable3d_node = fgGetNode("/sim/hud/enable3d");
841     if( HUD_style == 1 && enable3d_node->getBoolValue() ) {
842         fgUpdateHUDVirtual();
843         return;
844     }
845
846     static const float normal_aspect = float(640) / float(480);
847     // note: aspect_ratio is Y/X
848     float current_aspect = 1.0f/globals->get_current_view()->get_aspect_ratio();
849     if( current_aspect > normal_aspect ) {
850         float aspect_adjust = current_aspect / normal_aspect;
851         float adjust = 320.0f*aspect_adjust - 320.0f;
852         fgUpdateHUD( -adjust, 0.0f, 640.0f+adjust, 480.0f );
853     } else {
854         float aspect_adjust = normal_aspect / current_aspect;
855         float adjust = 240.0f*aspect_adjust - 240.0f;
856         fgUpdateHUD( 0.0f, -adjust, 640.0f, 480.0f+adjust );
857     }
858 }
859
860 void fgUpdateHUDVirtual()
861 {
862     FGViewer* view = globals->get_current_view();
863
864     // Standard fgfs projection, with essentially meaningless clip
865     // planes (we'll map the whole HUD plane to z=-1)
866     glMatrixMode(GL_PROJECTION);
867     glPushMatrix();
868     glLoadIdentity();
869     gluPerspective(view->get_v_fov(), 1/view->get_aspect_ratio(), 0.1, 10);
870
871     glMatrixMode(GL_MODELVIEW);
872     glPushMatrix();
873     glLoadIdentity();
874
875     // Standard fgfs view direction computation
876     float lookat[3];
877     lookat[0] = -sin(SG_DEGREES_TO_RADIANS * view->getHeadingOffset_deg());
878     lookat[1] = tan(SG_DEGREES_TO_RADIANS * view->getPitchOffset_deg());
879     lookat[2] = -cos(SG_DEGREES_TO_RADIANS * view->getHeadingOffset_deg());
880     if(fabs(lookat[1]) > 9999) lookat[1] = 9999; // FPU sanity
881     gluLookAt(0, 0, 0, lookat[0], lookat[1], lookat[2], 0, 1, 0);
882
883     // Map the -1:1 square to a 55.0x41.25 degree wide patch at z=1.
884     // This is the default fgfs field of view, which the HUD files are
885     // written to assume.
886     float dx = 0.52056705; // tan(55/2)
887     float dy = dx * 0.75;  // assumes 4:3 aspect ratio
888     float m[16];
889     m[0] = dx; m[4] =  0; m[ 8] = 0; m[12] = 0;
890     m[1] =  0; m[5] = dy; m[ 9] = 0; m[13] = 0;
891     m[2] =  0; m[6] =  0; m[10] = 1; m[14] = 0;
892     m[3] =  0; m[7] =  0; m[11] = 0; m[15] = 1;
893     glMultMatrixf(m);
894
895     // Convert the 640x480 "HUD standard" coordinate space to a square
896     // about the origin in the range [-1:1] at depth of -1
897     glScalef(1./320, 1./240, 1);
898     glTranslatef(-320, -240, -1);
899
900     // Do the deed
901     drawHUD();
902
903     // Clean up our mess
904     glMatrixMode(GL_PROJECTION);
905     glPopMatrix();
906     glMatrixMode(GL_MODELVIEW);
907     glPopMatrix();
908 }
909
910 void fgUpdateHUD( GLfloat x_start, GLfloat y_start,
911                   GLfloat x_end, GLfloat y_end )
912 {
913     glMatrixMode(GL_PROJECTION);
914     glPushMatrix();
915     glLoadIdentity();
916     gluOrtho2D(x_start, x_end, y_start, y_end);
917
918     glMatrixMode(GL_MODELVIEW);
919     glPushMatrix();
920     glLoadIdentity();
921
922     drawHUD();
923
924     glMatrixMode(GL_PROJECTION);
925     glPopMatrix();
926     glMatrixMode(GL_MODELVIEW);
927     glPopMatrix();
928 }
929
930 void drawHUD()
931 {
932     if( !HUD_deque.size() ) // Trust everyone, but ALWAYS cut the cards!
933         return;
934
935     HUD_TextList.erase();
936     HUD_LineList.erase();
937     // HUD_StippleLineList.erase();
938
939     glDisable(GL_DEPTH_TEST);
940     glDisable(GL_LIGHTING);
941
942     static const SGPropertyNode *heading_enabled
943         = fgGetNode("/autopilot/locks/heading", true);
944     static const SGPropertyNode *altitude_enabled
945         = fgGetNode("/autopilot/locks/altitude", true);
946
947     static char hud_hdg_text[256];
948     static char hud_wp0_text[256];
949     static char hud_wp1_text[256];
950     static char hud_wp2_text[256];
951     static char hud_alt_text[256];
952
953     glEnable(GL_BLEND);
954     if (HUD->isTransparent())
955         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
956     else
957         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
958
959     if (HUD->isAntialiased()) {
960         glEnable(GL_LINE_SMOOTH);
961         glAlphaFunc(GL_GREATER, HUD->alphaClamp());
962         glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
963         //glLineWidth(1.5);
964     } else {
965         //glLineWidth(1.0);
966     }
967
968     HUD->setColor();
969     for_each(HUD_deque.begin(), HUD_deque.end(), HUDdraw());
970
971     //HUD_TextList.add( fgText(40, 10, get_formated_gmt_time(), 0) );
972
973
974     int apY = 480 - 80;
975
976
977     if (strcmp( heading_enabled->getStringValue(), "dg-heading-hold") == 0 ) {
978         snprintf( hud_hdg_text, 256, "hdg = %.1f\n",
979                   fgGetDouble("/autopilot/settings/heading-bug-deg") );
980         HUD_TextList.add( fgText( 40, apY, hud_hdg_text ) );
981         apY -= 15;
982     } else if ( strcmp(heading_enabled->getStringValue(), "true-heading-hold") == 0 ) {
983         snprintf( hud_hdg_text, 256, "hdg = %.1f\n",
984                   fgGetDouble("/autopilot/settings/true-heading-deg") );
985         HUD_TextList.add( fgText( 40, apY, hud_hdg_text ) );
986         apY -= 15;
987
988         string wp0_id = fgGetString( "/autopilot/route-manager/wp[0]/id" );
989         if ( wp0_id.length() > 0 ) {
990             snprintf( hud_wp0_text, 256, "%5s %6.1fnm %s", wp0_id.c_str(),
991                       fgGetDouble( "/autopilot/route-manager/wp[0]/dist" ),
992                       fgGetString( "/autopilot/route-manager/wp[0]/eta" ) );
993             HUD_TextList.add( fgText( 40, apY, hud_wp0_text ) );
994             apY -= 15;
995         }
996         string wp1_id = fgGetString( "/autopilot/route-manager/wp[1]/id" );
997         if ( wp1_id.length() > 0 ) {
998             snprintf( hud_wp1_text, 256, "%5s %6.1fnm %s", wp1_id.c_str(),
999                       fgGetDouble( "/autopilot/route-manager/wp[1]/dist" ),
1000                       fgGetString( "/autopilot/route-manager/wp[1]/eta" ) );
1001             HUD_TextList.add( fgText( 40, apY, hud_wp1_text ) );
1002             apY -= 15;
1003         }
1004         string wp2_id = fgGetString( "/autopilot/route-manager/wp-last/id" );
1005         if ( wp2_id.length() > 0 ) {
1006             snprintf( hud_wp2_text, 256, "%5s %6.1fnm %s", wp2_id.c_str(),
1007                       fgGetDouble( "/autopilot/route-manager/wp-last/dist" ),
1008                       fgGetString( "/autopilot/route-manager/wp-last/eta" ) );
1009             HUD_TextList.add( fgText( 40, apY, hud_wp2_text ) );
1010             apY -= 15;
1011         }
1012     }
1013
1014     if ( strcmp( altitude_enabled->getStringValue(), "altitude-hold" ) == 0 ) {
1015         snprintf( hud_alt_text, 256, "alt = %.0f\n",
1016                   fgGetDouble("/autopilot/settings/target-altitude-ft") );
1017         HUD_TextList.add( fgText( 40, apY, hud_alt_text ) );
1018         apY -= 15;
1019     } else if ( strcmp( altitude_enabled->getStringValue(), "agl-hold" ) == 0 ){
1020         snprintf( hud_alt_text, 256, "agl = %.0f\n",
1021                   fgGetDouble("/autopilot/settings/target-agl-ft") );
1022         HUD_TextList.add( fgText( 40, apY, hud_alt_text ) );
1023         apY -= 15;
1024     }
1025
1026     HUD_TextList.draw();
1027     HUD_LineList.draw();
1028
1029     // glEnable(GL_LINE_STIPPLE);
1030     // glLineStipple( 1, 0x00FF );
1031     // HUD_StippleLineList.draw();
1032     // glDisable(GL_LINE_STIPPLE);
1033
1034     if (HUD->isAntialiased()) {
1035         glDisable(GL_ALPHA_TEST);
1036         glDisable(GL_LINE_SMOOTH);
1037         //glLineWidth(1.0);
1038     }
1039
1040     glEnable(GL_DEPTH_TEST);
1041     glEnable(GL_LIGHTING);
1042 }
1043
1044
1045
1046 void fgTextList::draw()
1047 {
1048     if (!Font)
1049         return;
1050
1051     vector<fgText>::iterator curString = List.begin();
1052     vector<fgText>::iterator lastString = List.end();
1053
1054     glPushAttrib(GL_COLOR_BUFFER_BIT);
1055     glEnable(GL_BLEND);
1056     if (HUD->isTransparent())
1057         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1058     else
1059         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1060
1061     if (HUD->isAntialiased()) {
1062         glEnable(GL_ALPHA_TEST);
1063         glAlphaFunc(GL_GREATER, HUD->alphaClamp());
1064     }
1065
1066     Font->begin();
1067     for (; curString != lastString; curString++)
1068         curString->Draw(Font,curString->digit);
1069     Font->end();
1070
1071     glDisable(GL_TEXTURE_2D);
1072     glPopAttrib();
1073 }
1074
1075
1076
1077 // HUD property listener class
1078 //
1079 HUD_Properties::HUD_Properties() :
1080     _current(fgGetNode("/sim/hud/current-color", true)),
1081     _visibility(fgGetNode("/sim/hud/visibility", true)),
1082     _antialiasing(fgGetNode("/sim/hud/color/antialiased", true)),
1083     _transparency(fgGetNode("/sim/hud/color/transparent", true)),
1084     _red(fgGetNode("/sim/hud/color/red", true)),
1085     _green(fgGetNode("/sim/hud/color/green", true)),
1086     _blue(fgGetNode("/sim/hud/color/blue", true)),
1087     _alpha(fgGetNode("/sim/hud/color/alpha", true)),
1088     _alpha_clamp(fgGetNode("/sim/hud/color/alpha-clamp", true)),
1089     _brightness(fgGetNode("/sim/hud/color/brightness", true)),
1090     _visible(false),
1091     _antialiased(false),
1092     _transparent(false),
1093     _a(0.67),
1094     _cl(0.01)
1095 {
1096     _visibility->addChangeListener(this);
1097     _antialiasing->addChangeListener(this);
1098     _transparency->addChangeListener(this);
1099     _red->addChangeListener(this);
1100     _green->addChangeListener(this);
1101     _blue->addChangeListener(this);
1102     _alpha->addChangeListener(this);
1103     _alpha_clamp->addChangeListener(this);
1104     _brightness->addChangeListener(this);
1105     _current->addChangeListener(this, true);
1106 }
1107
1108
1109 void HUD_Properties::valueChanged(SGPropertyNode *node)
1110 {
1111     if (!strcmp(node->getName(), "current-color")) {
1112         int i = node->getIntValue();
1113         if (i < 0)
1114             i = 0;
1115         SGPropertyNode *n = fgGetNode("/sim/hud/palette", true);
1116         if ((n = n->getChild("color", i, false))) {
1117             if (n->hasValue("red"))
1118                 _red->setFloatValue(n->getFloatValue("red", 1.0));
1119             if (n->hasValue("green"))
1120                 _green->setFloatValue(n->getFloatValue("green", 1.0));
1121             if (n->hasValue("blue"))
1122                 _blue->setFloatValue(n->getFloatValue("blue", 1.0));
1123             if (n->hasValue("alpha"))
1124                 _alpha->setFloatValue(n->getFloatValue("alpha", 0.67));
1125             if (n->hasValue("alpha-clamp"))
1126                 _alpha_clamp->setFloatValue(n->getFloatValue("alpha-clamp", 0.01));
1127             if (n->hasValue("brightness"))
1128                 _brightness->setFloatValue(n->getFloatValue("brightness", 0.75));
1129             if (n->hasValue("antialiased"))
1130                 _antialiasing->setBoolValue(n->getBoolValue("antialiased", false));
1131             if (n->hasValue("transparent"))
1132                 _transparency->setBoolValue(n->getBoolValue("transparent", false));
1133         }
1134     }
1135     _visible = _visibility->getBoolValue();
1136     _transparent = _transparency->getBoolValue();
1137     _antialiased = _antialiasing->getBoolValue();
1138     float brt = _brightness->getFloatValue();
1139     _r = clamp(brt * _red->getFloatValue());
1140     _g = clamp(brt * _green->getFloatValue());
1141     _b = clamp(brt * _blue->getFloatValue());
1142     _a = clamp(_alpha->getFloatValue());
1143     _cl = clamp(_alpha_clamp->getFloatValue());
1144 }
1145
1146
1147 void HUD_Properties::setColor() const
1148 {
1149     if (_antialiased)
1150         glColor4f(_r, _g, _b, _a);
1151     else
1152         glColor3f(_r, _g, _b);
1153 }
1154