]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/hud.cxx
Removed FGEnvironmentMgr as a special case in globals, initialization,
[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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23 #include <simgear/compiler.h>
24 #include <simgear/misc/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 <GL/glut.h>
44 #include <stdlib.h>
45 #include <stdio.h>              // char related functions
46 #include <string.h>             // strcmp()
47
48 #include <simgear/constants.h>
49 #include <simgear/debug/logstream.hxx>
50 #include <simgear/props/props.hxx>
51 #include <simgear/misc/sg_path.hxx>
52
53 #include <Aircraft/aircraft.hxx>
54 #include <Autopilot/newauto.hxx>
55 #include <GUI/gui.h>
56 #include <Main/globals.hxx>
57 #include <Main/fg_props.hxx>
58 #ifdef FG_NETWORK_OLK
59 #include <NetworkOLK/network.h>
60 #endif
61 #include <Scenery/scenery.hxx>
62
63 #if defined ( __sun__ ) || defined ( __sgi )
64 extern "C" {
65     extern void *memmove(void *, const void *, size_t);
66 }
67 #endif
68
69 #include "hud.hxx"
70
71 static char units[5];
72
73 // The following routines obtain information concerning the aircraft's
74 // current state and return it to calling instrument display routines.
75 // They should eventually be member functions of the aircraft.
76 //
77
78 deque< instr_item * > HUD_deque;
79
80 fgTextList         HUD_TextList;
81 fgLineList         HUD_LineList;
82 fgLineList         HUD_StippleLineList;
83
84 fntRenderer *HUDtext = 0;
85 float  HUD_TextSize = 0;
86 int HUD_style = 0;
87
88 float HUD_matrix[16];
89 static float hud_trans_alpha = 0.67f;
90
91
92 //$$$ begin - added, Neetha, 28 Nov 2k
93
94 static string   name;
95 static int              x;
96 static int              y;
97 static UINT    width;
98 static UINT    height;
99 static float    factor;
100 static float   span_units;
101 static float   division_units;
102 static float   minor_division = 0;
103 static UINT    screen_hole;
104 static UINT    lbl_pos;
105 static bool    working;
106 static string  loadfn;
107 static UINT     options;
108 static float   maxValue;
109 static float   minValue;
110 static float   scaling;
111 static UINT    major_divs;
112 static UINT    minor_divs;
113 static UINT    modulator;
114 static int     dp_showing = 0;
115 static string  label_format;
116 static string  prelabel;
117 static string  postlabel;
118 static int     justi;
119 static int              blinking;
120 static float   maxBankAngle;
121 static float   maxSlipAngle;
122 static UINT    gap_width;
123 static bool     latitude;
124 static bool     longitude;
125 static bool     tick_bottom;
126 static bool     tick_top;
127 static bool     tick_right;
128 static bool     tick_left;
129 static bool     cap_bottom;
130 static bool     cap_top;
131 static bool     cap_right;
132 static bool     cap_left;
133 static float   marker_off;
134 static string  type;
135 static bool    enable_pointer;
136 static string  type_pointer;
137 static bool    frl_spot;
138 static bool     target;
139 static bool    vel_vector;
140 static bool    drift;
141 static bool    alpha;
142 static bool     energy;
143 static bool     climb_dive;
144 static bool     glide;
145 static float    glide_slope_val;
146 static bool     worm_energy;
147 static bool     waypoint;
148 static string type_tick;//hud
149 static string length_tick;//hud
150 static bool label_box;//hud
151 static int digits; //suma
152 static float radius; //suma
153 static int divisions; //suma
154 static int zoom; //suma
155 static int zenith; //suma
156 static int nadir ; //suma
157 static int hat; //suma
158 static bool tsi; //suma
159 static float rad; //suma
160
161
162 static FLTFNPTR load_fn;    
163 static fgLabelJust justification;
164 static const char *pre_label_string  = 0;
165 static const char *post_label_string = 0;
166
167 int readHud( istream &input );
168 int readInstrument ( const SGPropertyNode * node);
169 static instr_item * readLadder ( const SGPropertyNode * node);
170 static instr_item * readCard ( const SGPropertyNode * node);
171 static instr_item * readLabel( const SGPropertyNode * node);
172 static instr_item * readTBI( const SGPropertyNode * node);
173 //$$$ end   - added, Neetha, 28 Nov 2k
174
175 static void drawHUD();
176 static void fgUpdateHUDVirtual();
177
178 void fgHUDalphaInit( void );
179
180 class locRECT {
181 public:
182     RECT rect;
183
184     locRECT( UINT left, UINT top, UINT right, UINT bottom);
185     RECT get_rect(void) { return rect;}
186 };
187
188 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
189 {
190     rect.left   =  left;
191     rect.top    =  top;
192     rect.right  =  right;
193     rect.bottom =  bottom;
194
195 }
196 // #define DEBUG
197
198 //========================= End of Class Implementations===================
199 // fgHUDInit
200 //
201 // Constructs a HUD object and then adds in instruments. At the present
202 // the instruments are hard coded into the routine. Ultimately these need
203 // to be defined by the aircraft's instrumentation records so that the
204 // display for a Piper Cub doesn't show the speed range of a North American
205 // mustange and the engine readouts of a B36!
206 //
207
208 #define INSTRDEFS 21
209
210 //$$$ begin - added, Neetha, 28 Nov 2k
211 static instr_item * 
212 readLadder(const SGPropertyNode * node)
213 {
214
215     instr_item *p;
216
217     name                        = node->getStringValue("name");
218     x                           = node->getIntValue("x");
219     y                           = node->getIntValue("y");
220     width                       = node->getIntValue("width");
221     height                      = node->getIntValue("height");
222     factor                      = node->getFloatValue("compression_factor");
223     span_units          = node->getFloatValue("span_units");
224     division_units      = node->getFloatValue("division_units");
225     screen_hole         = node->getIntValue("screen_hole");
226     lbl_pos                     = node->getIntValue("lbl_pos");
227     frl_spot            = node->getBoolValue("enable_frl",false);
228     target                      = node->getBoolValue("enable_target_spot",false);
229     vel_vector          = node->getBoolValue("enable_velocity_vector",false);
230     drift                       = node->getBoolValue("enable_drift_marker",false);
231     alpha                       = node->getBoolValue("enable_alpha_bracket",false);
232     energy                      = node->getBoolValue("enable_energy_marker",false);
233     climb_dive          = node->getBoolValue("enable_climb_dive_marker",false);
234     glide                       = node->getBoolValue("enable_glide_slope_marker",false);
235     glide_slope_val     = node->getFloatValue("glide_slope",-4.0);
236     worm_energy         = node->getBoolValue("enable_energy_marker",false);
237     waypoint            = node->getBoolValue("enable_waypoint_marker",false);
238     working                     = node->getBoolValue("working");
239     zenith                      = node->getIntValue("zenith");  //suma
240     nadir                       = node->getIntValue("nadir");  //suma
241     hat                         = node->getIntValue("hat");
242     // The factor assumes a base of 55 degrees per 640 pixels.
243     // Invert to convert the "compression" factor to a
244     // pixels-per-degree number.
245     if( HUD_style == 1)
246     {
247 //        if(factor == 0)
248             factor = 1;
249         factor = (640./55.) / factor;
250     }
251
252     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
253         
254     p = (instr_item *) new HudLadder( name, x, y,
255                                       width, height, factor,
256                                       get_roll, get_pitch,
257                                       span_units, division_units, minor_division,
258                                       screen_hole, lbl_pos, frl_spot, target, vel_vector, 
259                                       drift, alpha, energy, climb_dive, 
260                                       glide, glide_slope_val, worm_energy, 
261                                       waypoint, working, zenith, nadir, hat);
262                                 
263     return p;
264                 
265 } //end readLadder
266
267 static instr_item * 
268 readCard(const SGPropertyNode * node)
269 {
270
271     instr_item *p;
272
273     name                        = node->getStringValue("name");
274     x                           = node->getIntValue("x");
275     y                           = node->getIntValue("y");
276     width                       = node->getIntValue("width");
277     height                      = node->getIntValue("height");
278     loadfn                      = node->getStringValue("loadfn");
279     options                     = node->getIntValue("options");
280     maxValue            = node->getFloatValue("maxValue");
281     minValue            = node->getFloatValue("minValue");
282     scaling                     = node->getFloatValue("disp_scaling");
283     major_divs          = node->getIntValue("major_divs");
284     minor_divs          = node->getIntValue("minor_divs");
285     modulator           = node->getIntValue("modulator");
286     span_units          = node->getFloatValue("value_span");
287     type                        = node->getStringValue("type");
288     tick_bottom     = node->getBoolValue("tick_bottom",false);
289     tick_top            = node->getBoolValue("tick_top",false);
290     tick_right          = node->getBoolValue("tick_right",false);
291     tick_left           = node->getBoolValue("tick_left",false);
292     cap_bottom          = node->getBoolValue("cap_bottom",false);
293     cap_top                     = node->getBoolValue("cap_top",false);
294     cap_right           = node->getBoolValue("cap_right",false);
295     cap_left            = node->getBoolValue("cap_left",false);
296     marker_off          = node->getFloatValue("marker_offset",0.0);
297     enable_pointer      = node->getBoolValue("enable_pointer",true);
298     type_pointer        = node->getStringValue("pointer_type");
299     type_tick           = node->getStringValue("tick_type");//hud Can be 'circle' or 'line'
300     length_tick         = node->getStringValue("tick_length");//hud For variable length
301     working                     = node->getBoolValue("working");
302     radius                      = node->getFloatValue("radius"); //suma
303     divisions           = node->getIntValue("divisions"); //suma
304     zoom                        = node->getIntValue("zoom"); //suma
305
306     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
307
308
309     if(type=="gauge") {
310         span_units = maxValue - minValue;
311     }
312
313     if (loadfn=="anzg") {
314         load_fn = get_anzg;
315     } else if (loadfn=="heading") {
316         load_fn = get_heading;
317     } else if (loadfn=="aoa") {
318         load_fn = get_aoa;
319     } else if (loadfn=="climb") {
320         load_fn = get_climb_rate;
321     } else if (loadfn=="altitude") {
322         load_fn = get_altitude;
323     } else if (loadfn=="agl") {
324         load_fn = get_agl;
325     } else if (loadfn=="speed") {
326         load_fn = get_speed;
327     } else if (loadfn=="view_direction") {
328         load_fn = get_view_direction;
329     } else if (loadfn=="aileronval") {
330         load_fn = get_aileronval;
331     } else if (loadfn=="elevatorval") {
332         load_fn = get_elevatorval;
333     } else if (loadfn=="elevatortrimval") {
334         load_fn = get_elev_trimval;
335     } else if (loadfn=="rudderval") {
336         load_fn = get_rudderval;
337     } else if (loadfn=="throttleval") {
338         load_fn = get_throttleval;
339     }
340
341
342     if ( (type == "dial") | (type == "tape") ) {
343         p = (instr_item *) new hud_card( x,
344                                          y,  
345                                          width,
346                                          height,
347                                          load_fn,
348                                          options,
349                                          maxValue, minValue,
350                                          scaling,
351                                          major_divs, minor_divs,
352                                          modulator,
353                                          dp_showing,
354                                          span_units,
355                                          type,
356                                          tick_bottom,
357                                          tick_top,
358                                          tick_right,
359                                          tick_left,
360                                          cap_bottom,
361                                          cap_top,
362                                          cap_right,
363                                          cap_left,
364                                          marker_off,
365                                          enable_pointer,
366                                          type_pointer,
367                                          type_tick,//hud
368                                          length_tick,//hud
369                                          working,
370                                          radius, //suma
371                                          divisions, //suma
372                                          zoom  //suma
373                                          );
374     } else {
375         p = (instr_item *) new  gauge_instr( x,            // x
376                                              y,  // y
377                                              width,            // width
378                                              height,            // height
379                                              load_fn, // data source
380                                              options,
381                                              scaling,
382                                              maxValue,minValue,
383                                              major_divs, minor_divs,
384                                              dp_showing,
385                                              modulator,
386                                              working);
387     }
388
389     return p;
390 }// end readCard
391
392 static instr_item *
393 readLabel(const SGPropertyNode * node)
394 {
395     instr_item *p;
396
397     int font_size = (fgGetInt("/sim/startup/xsize") > 1000) ? HUD_FONT_LARGE : HUD_FONT_SMALL;
398
399     name                = node->getStringValue("name");
400     x                   = node->getIntValue("x");
401     y                   = node->getIntValue("y");
402     width               = node->getIntValue("width");
403     height              = node->getIntValue("height");
404     loadfn              = node->getStringValue("data_source");
405     label_format        = node->getStringValue("label_format");
406     prelabel            = node->getStringValue("pre_label_string");
407     postlabel           = node->getStringValue("post_label_string");
408     scaling             = node->getFloatValue("scale_data");
409     options             = node->getIntValue("options");
410     justi               = node->getIntValue("justification");
411     blinking            = node->getIntValue("blinking");
412     latitude            = node->getBoolValue("latitude",false);
413     longitude           = node->getBoolValue("longitude",false);
414     label_box           = node->getBoolValue("label_box",false);//hud
415     working             = node->getBoolValue("working");
416     digits              = node->getIntValue("digits"); //suma
417
418
419     SG_LOG(SG_INPUT, SG_INFO, "Done reading instrument " << name);
420
421
422     if ( justi == 0 ) {
423         justification = LEFT_JUST;
424     } else {
425         if ( justi == 1 ) {
426             justification = CENTER_JUST;
427         } else {
428             if ( justi == 2 ) {
429                 justification = RIGHT_JUST;
430             }
431         }
432     }
433
434     if ( prelabel == "NULL" ) {
435         pre_label_string = NULL;
436     } else {
437         if ( prelabel == "blank" ) {
438             pre_label_string = " ";
439         } else {
440             pre_label_string = prelabel.c_str();
441         }
442     }
443
444     if ( postlabel == "blank" ) {
445         post_label_string = " ";
446     } else {
447         if ( postlabel == "NULL" ) {
448             post_label_string = NULL;
449         } else {
450             if ( postlabel == "units" ) {
451                 post_label_string = units;
452             } else {
453                 post_label_string = postlabel.c_str();
454             }
455         }
456     }
457
458     if ( loadfn== "aux1" ) {
459         load_fn = get_aux1;
460     } else if ( loadfn == "aux2" ) {
461         load_fn = get_aux2;
462     } else if ( loadfn == "aux3" ) {
463         load_fn = get_aux3;
464     } else if ( loadfn == "aux4" ) {
465         load_fn = get_aux4;
466     } else if ( loadfn == "aux5" ) {
467         load_fn = get_aux5;
468     } else if ( loadfn == "aux6" ) {
469         load_fn = get_aux6;
470     } else if ( loadfn == "aux7" ) {
471         load_fn = get_aux7;
472     } else if ( loadfn == "aux8" ) {
473         load_fn = get_aux8;
474     } else if ( loadfn == "aux9" ) {
475         load_fn = get_aux9;
476     } else if ( loadfn == "aux10" ) {
477         load_fn = get_aux10;
478     } else if ( loadfn == "aux11" ) {
479         load_fn = get_aux11;
480     } else if ( loadfn == "aux12" ) {
481         load_fn = get_aux12;
482     } else if ( loadfn == "aux13" ) {
483         load_fn = get_aux13;
484     } else if ( loadfn == "aux14" ) {
485         load_fn = get_aux14;
486     } else if ( loadfn == "aux15" ) {
487         load_fn = get_aux15;
488     } else if ( loadfn == "aux16" ) {
489         load_fn = get_aux16;
490     } else if ( loadfn == "aux17" ) {
491         load_fn = get_aux17;
492     } else if ( loadfn == "aux18" ) {
493         load_fn = get_aux18;
494     } else 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
586 int readInstrument(const SGPropertyNode * node)
587 {
588     static const SGPropertyNode *startup_units_node
589         = fgGetNode("/sim/startup/units");
590
591     instr_item *HIptr;
592     
593     if ( !strcmp(startup_units_node->getStringValue(), "feet") ) {
594         strcpy(units, " ft");
595     } else {
596         strcpy(units, " m");
597     }
598
599     const SGPropertyNode * ladder_group = node->getNode("ladders");
600
601     if (ladder_group != 0) {
602         int nLadders = ladder_group->nChildren();
603         for (int j = 0; j < nLadders; j++) {
604             
605             HIptr = readLadder(ladder_group->getChild(j));
606             HUD_deque.insert( HUD_deque.begin(), HIptr);
607                                         
608         }// for - ladders
609     }
610
611     const SGPropertyNode * card_group = node->getNode("cards");
612     if (card_group != 0) {
613         int nCards = card_group->nChildren();
614         for (int j = 0; j < nCards; j++) {
615             
616             HIptr = readCard(card_group->getChild(j));
617             HUD_deque.insert( HUD_deque.begin(), HIptr);
618
619         }//for - cards
620     }
621
622     const SGPropertyNode * label_group = node->getNode("labels");
623     if (label_group != 0) {
624         int nLabels = label_group->nChildren();
625         for (int j = 0; j < nLabels; j++) {
626
627             HIptr = readLabel(label_group->getChild(j));
628             HUD_deque.insert( HUD_deque.begin(), HIptr);
629
630         }//for - labels
631     }
632
633     const SGPropertyNode * tbi_group = node->getNode("tbis");
634     if (tbi_group != 0) {
635         int nTbis = tbi_group->nChildren();
636         for (int j = 0; j < nTbis; j++) {
637
638             HIptr = readTBI(tbi_group->getChild(j));
639             HUD_deque.insert( HUD_deque.begin(), HIptr);
640
641         }//for - tbis
642     }
643     return 0;
644 }//end readinstrument
645
646
647 int readHud( istream &input ) 
648 {
649
650     SGPropertyNode root;
651
652     try {
653         readProperties(input, &root);
654     } catch (const sg_exception &e) {
655         guiErrorMessage("Error reading HUD: ", e);
656         return 0;
657     }
658   
659         
660     SG_LOG(SG_INPUT, SG_INFO, "Read properties for  " <<
661            root.getStringValue("name"));
662
663
664     HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());  // empty the HUD deque
665
666
667     SG_LOG(SG_INPUT, SG_INFO, "Reading Hud instruments");
668
669     const SGPropertyNode * instrument_group = root.getChild("instruments");
670     int nInstruments = instrument_group->nChildren();
671
672     for (int i = 0; i < nInstruments; i++) {
673                 
674         const SGPropertyNode * node = instrument_group->getChild(i);
675
676         SGPath path( globals->get_fg_root() );
677         path.append(node->getStringValue("path"));
678
679         SG_LOG(SG_INPUT, SG_INFO, "Reading Instrument "
680                << node->getName()
681                << " from "
682                << path.str());
683
684         SGPropertyNode root2;
685         try {
686             readProperties(path.str(), &root2);
687         } catch (const sg_exception &e) {
688             guiErrorMessage("Error reading HUD instrument: ", e);
689             continue;
690         } 
691         readInstrument(&root2);
692     }//for loop(i)
693
694     return 0;
695 }
696
697
698 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
699 {
700
701     HUD_style = 1;
702
703     SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
704
705     string hud_path =
706         fgGetString("/sim/hud/path", "Huds/Default/default.xml");
707     SGPath path(globals->get_fg_root());
708     path.append(hud_path);
709         
710     ifstream input(path.c_str());
711     if (!input.good()) {
712         SG_LOG(SG_INPUT, SG_ALERT,
713                "Cannot read Hud configuration from " << path.str());
714     } else {
715         readHud(input);
716         input.close();
717     }
718
719     fgHUDalphaInit();
720     fgHUDReshape();
721
722     if ( HUDtext ) {
723         // this chunk of code is not necessarily thread safe if the
724         // compiler optimizer reorders these statements.  Note that
725         // "delete ptr" does not set "ptr = NULL".  We have to do that
726         // ourselves.
727         fntRenderer *tmp = HUDtext;
728         HUDtext = NULL;
729         delete tmp;
730     }
731
732 //    HUD_TextSize = fgGetInt("/sim/startup/xsize") / 60;
733     HUD_TextSize = 10;
734     HUDtext = new fntRenderer();
735     HUDtext -> setFont      ( guiFntHandle ) ;
736     HUDtext -> setPointSize ( HUD_TextSize ) ;
737     HUD_TextList.setFont( HUDtext );
738     
739     return 0;  // For now. Later we may use this for an error code.
740
741 }
742
743 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
744 {
745
746     HUD_style = 2;
747
748     SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
749
750     SGPath path(globals->get_fg_root());
751     path.append("Huds/Minimal/default.xml");
752
753
754     ifstream input(path.c_str());
755     if (!input.good()) {
756         SG_LOG(SG_INPUT, SG_ALERT,
757                "Cannot read Hud configuration from " << path.str());
758     } else {
759         readHud(input);
760         input.close();
761     }
762
763     return 0;  // For now. Later we may use this for an error code.
764
765 }
766 //$$$ End - added, Neetha, 28 Nov 2k  
767
768 static int global_day_night_switch = HUD_DAY;
769
770 void HUD_masterswitch( bool incr )
771 {
772     if ( fgGetBool("/sim/hud/visibility") ) {
773         if ( global_day_night_switch == HUD_DAY ) {
774             global_day_night_switch = HUD_NIGHT;
775         } else {
776             fgSetBool("/sim/hud/visibility", false);
777         }
778     } else {
779         fgSetBool("/sim/hud/visibility", true);
780         global_day_night_switch = HUD_DAY;
781     }   
782 }
783
784 void HUD_brightkey( bool incr_bright )
785 {
786     instr_item *pHUDInstr = HUD_deque[0];
787     int brightness        = pHUDInstr->get_brightness();
788
789     if( fgGetBool("/sim/hud/visibility") ) {
790         if( incr_bright ) {
791             switch (brightness)
792                 {
793                 case HUD_BRT_LIGHT:
794                     brightness = HUD_BRT_BLACK;
795                     break;
796
797                 case HUD_BRT_MEDIUM:
798                     brightness = HUD_BRT_LIGHT;
799                     break;
800
801                 case HUD_BRT_DARK:
802                     brightness = HUD_BRT_MEDIUM;
803                     break;
804
805                 case HUD_BRT_BLACK:
806                     brightness = HUD_BRT_DARK;
807                     break;
808
809                 default:
810                     brightness = HUD_BRT_BLACK;
811                 }
812         } else {
813             switch (brightness)
814                 {
815                 case HUD_BRT_LIGHT:
816                     brightness = HUD_BRT_MEDIUM;
817                     break;
818
819                 case HUD_BRT_MEDIUM:
820                     brightness = HUD_BRT_DARK;
821                     break;
822
823                 case HUD_BRT_DARK:
824                     brightness = HUD_BRT_BLACK;
825                     break;
826
827                 case HUD_BRT_BLACK:
828                     brightness = HUD_BRT_LIGHT;
829                     break;
830
831                 default:
832                     fgSetBool("/sim/hud/visibility", false);
833                 }
834         }
835     } else {
836         fgSetBool("/sim/hud/visibility", true);
837     }
838
839     pHUDInstr->SetBrightness( brightness );
840 }
841
842
843 #define fgAP_CLAMP(val,min,max) ( (val) = (val) > (max) ? (max) : (val) < (min) ? (min) : (val) )
844
845 static puDialogBox *HUDalphaDialog;
846 static puText      *HUDalphaText;
847 static puSlider    *HUDalphaHS0;
848 //static puText      *HUDtextText;
849 //static puSlider    *HUDalphaHS1;
850 static char         SliderText[2][ 8 ];
851
852 static void alpha_adj( puObject *hs ) {
853     float val ;
854
855     hs-> getValue ( &val ) ;
856     fgAP_CLAMP ( val, 0.1, 1.0 ) ;
857     // printf ( "maxroll_adj( %p ) %f %f\n", hs, val, MaxRollAdjust * val ) ;
858     hud_trans_alpha = val;
859     sprintf( SliderText[ 0 ], "%05.2f", hud_trans_alpha );
860     HUDalphaText -> setLabel ( SliderText[ 0 ] ) ;
861 }
862
863 void fgHUDalphaAdjust( puObject * ) {
864     fgSetBool("/sim/hud/antialiased", true);
865     FG_PUSH_PUI_DIALOG( HUDalphaDialog );
866 }
867
868 static void goAwayHUDalphaAdjust (puObject *)
869 {
870     FG_POP_PUI_DIALOG( HUDalphaDialog );
871 }
872
873 static void cancelHUDalphaAdjust (puObject *)
874 {
875     fgSetBool("/sim/hud/antialiased", false);
876     FG_POP_PUI_DIALOG( HUDalphaDialog );
877 }
878
879 // Done once at system initialization
880 void fgHUDalphaInit( void ) {
881
882     //  printf("fgHUDalphaInit\n");
883 #define HORIZONTAL  FALSE
884
885     int DialogX = 40;
886     int DialogY = 100;
887     int DialogWidth = 240;
888
889     char Label[] =  "HUD Adjuster";
890     char *s;
891
892     int labelX = (DialogWidth / 2) -
893         ( puGetDefaultLabelFont().getStringWidth( Label ) / 2);
894         
895     int nSliders = 1;
896     int slider_x = 10;
897     int slider_y = 55;
898     int slider_width = 220;
899     int slider_title_x = 15;
900     int slider_value_x = 160;
901     float slider_delta = 0.05f;
902
903     puFont HUDalphaLegendFont;
904     puFont HUDalphaLabelFont;
905     puGetDefaultFonts ( &HUDalphaLegendFont, &HUDalphaLabelFont );
906         
907     HUDalphaDialog = new puDialogBox ( DialogX, DialogY ); {
908         int horiz_slider_height = HUDalphaLabelFont.getStringHeight() +
909             HUDalphaLabelFont.getStringDescender() +
910             PUSTR_TGAP + PUSTR_BGAP + 5;
911
912         /* puFrame *
913            HUDalphaFrame = new puFrame ( 0, 0, DialogWidth,
914            85 + nSliders
915            * horiz_slider_height ); */
916
917         puText *
918             HUDalphaDialogMessage = new puText ( labelX,
919                                                  52 + nSliders
920                                                  * horiz_slider_height );
921         HUDalphaDialogMessage -> setDefaultValue ( Label );
922         HUDalphaDialogMessage -> getDefaultValue ( &s );
923         HUDalphaDialogMessage -> setLabel        ( s );
924
925         HUDalphaHS0 = new puSlider ( slider_x, slider_y,
926                                      slider_width, HORIZONTAL ) ;
927         HUDalphaHS0->     setDelta ( slider_delta ) ;
928         HUDalphaHS0->     setValue ( hud_trans_alpha ) ;
929         HUDalphaHS0->    setCBMode ( PUSLIDER_DELTA ) ;
930         HUDalphaHS0->  setCallback ( alpha_adj ) ;
931
932         puText *
933             HUDalphaTitle =      new puText ( slider_title_x, slider_y ) ;
934         HUDalphaTitle-> setDefaultValue ( "Alpha" ) ;
935         HUDalphaTitle-> getDefaultValue ( &s ) ;
936         HUDalphaTitle->        setLabel ( s ) ;
937                 
938         HUDalphaText = new puText ( slider_value_x, slider_y ) ;
939         sprintf( SliderText[ 0 ], "%05.2f", hud_trans_alpha );
940         HUDalphaText-> setLabel ( SliderText[ 0 ] ) ;
941
942         puOneShot *
943             HUDalphaOkButton =     new puOneShot ( 10, 10, 60, 45 );
944         HUDalphaOkButton->         setLegend ( gui_msg_OK );
945         HUDalphaOkButton-> makeReturnDefault ( TRUE );
946         HUDalphaOkButton->       setCallback ( goAwayHUDalphaAdjust );
947
948         puOneShot *
949             HUDalphaNoButton = new puOneShot ( 160, 10, 230, 45 );
950         HUDalphaNoButton->     setLegend ( gui_msg_CANCEL );
951         HUDalphaNoButton->   setCallback ( cancelHUDalphaAdjust );
952     }
953     FG_FINALIZE_PUI_DIALOG( HUDalphaDialog );
954
955 #undef HORIZONTAL
956 }
957
958
959 void fgHUDReshape(void) {
960 #if 0
961     if ( HUDtext ) {
962         // this chunk of code is not necessarily thread safe if the
963         // compiler optimizer reorders these statements.  Note that
964         // "delete ptr" does not set "ptr = NULL".  We have to do that
965         // ourselves.
966         fntRenderer *tmp = HUDtext;
967         HUDtext = NULL;
968         delete tmp;
969     }
970
971     HUD_TextSize = fgGetInt("/sim/startup/xsize") / 60;
972     HUD_TextSize = 10;
973     HUDtext = new fntRenderer();
974     HUDtext -> setFont      ( guiFntHandle ) ;
975     HUDtext -> setPointSize ( HUD_TextSize ) ;
976     HUD_TextList.setFont( HUDtext );
977 #endif
978 }
979
980
981 static void set_hud_color(float r, float g, float b) {
982     fgGetBool("/sim/hud/antialiased") ?
983         glColor4f(r,g,b,hud_trans_alpha) :
984         glColor3f(r,g,b);
985 }
986
987
988 // fgUpdateHUD
989 //
990 // Performs a once around the list of calls to instruments installed in
991 // the HUD object with requests for redraw. Kinda. It will when this is
992 // all C++.
993 //
994 void fgUpdateHUD( void ) {
995         
996     if( HUD_style == 1)
997     {
998         fgUpdateHUDVirtual();
999         return;
1000     }
1001     
1002     static const float normal_aspect = float(640) / float(480);
1003     // note: aspect_ratio is Y/X
1004     float current_aspect = 1.0f/globals->get_current_view()->get_aspect_ratio();
1005     if( current_aspect > normal_aspect ) {
1006         float aspect_adjust = current_aspect / normal_aspect;
1007         float adjust = 320.0f*aspect_adjust - 320.0f;
1008         fgUpdateHUD( -adjust, 0.0f, 640.0f+adjust, 480.0f );
1009     } else {
1010         float aspect_adjust = normal_aspect / current_aspect;
1011         float adjust = 240.0f*aspect_adjust - 240.0f;
1012         fgUpdateHUD( 0.0f, -adjust, 640.0f, 480.0f+adjust );
1013     }
1014 }
1015
1016 void fgUpdateHUDVirtual()
1017 {
1018     FGViewer* view = globals->get_current_view();
1019
1020     // Standard fgfs projection, with essentially meaningless clip
1021     // planes (we'll map the whole HUD plane to z=-1)
1022     glMatrixMode(GL_PROJECTION);
1023     glPushMatrix();
1024     glLoadIdentity();
1025     gluPerspective(view->get_v_fov(), 1/view->get_aspect_ratio(), 0.1, 10);
1026
1027     glMatrixMode(GL_MODELVIEW);
1028     glPushMatrix();
1029     glLoadIdentity();
1030   
1031     // Standard fgfs view direction computation
1032     float lookat[3];
1033     lookat[0] = -sin(SG_DEGREES_TO_RADIANS * view->getHeadingOffset_deg());
1034     lookat[1] = tan(SG_DEGREES_TO_RADIANS * view->getPitchOffset_deg());
1035     lookat[2] = -cos(SG_DEGREES_TO_RADIANS * view->getHeadingOffset_deg());
1036     if(fabs(lookat[1]) > 9999) lookat[1] = 9999; // FPU sanity
1037     gluLookAt(0, 0, 0, lookat[0], lookat[1], lookat[2], 0, 1, 0);
1038
1039     // Map the -1:1 square to a 55.0x41.25 degree wide patch at z=1.
1040     // This is the default fgfs field of view, which the HUD files are
1041     // written to assume.
1042     float dx = 0.52056705; // tan(55/2)
1043     float dy = dx * 0.75;  // assumes 4:3 aspect ratio
1044     float m[16];
1045     m[0] = dx; m[4] =  0; m[ 8] = 0; m[12] = 0;
1046     m[1] =  0; m[5] = dy; m[ 9] = 0; m[13] = 0;
1047     m[2] =  0; m[6] =  0; m[10] = 1; m[14] = 0;
1048     m[3] =  0; m[7] =  0; m[11] = 0; m[15] = 1;
1049     glMultMatrixf(m);
1050
1051     // Convert the 640x480 "HUD standard" coordinate space to a square
1052     // about the origin in the range [-1:1] at depth of -1
1053     glScalef(1./320, 1./240, 1);
1054     glTranslatef(-320, -240, -1);
1055
1056     // Do the deed
1057     drawHUD();
1058
1059     // Clean up our mess
1060     glMatrixMode(GL_PROJECTION);
1061     glPopMatrix();
1062     glMatrixMode(GL_MODELVIEW);
1063     glPopMatrix();
1064 }
1065
1066 void fgUpdateHUD( GLfloat x_start, GLfloat y_start,
1067                   GLfloat x_end, GLfloat y_end )
1068 {
1069     glMatrixMode(GL_PROJECTION);
1070     glPushMatrix();
1071     glLoadIdentity();
1072     gluOrtho2D(x_start, x_end, y_start, y_end);
1073
1074     glMatrixMode(GL_MODELVIEW);
1075     glPushMatrix();
1076     glLoadIdentity();
1077
1078     drawHUD();
1079
1080     glMatrixMode(GL_PROJECTION);
1081     glPopMatrix();
1082     glMatrixMode(GL_MODELVIEW);
1083     glPopMatrix();
1084 }
1085
1086 void drawHUD()
1087 {
1088     if( !HUD_deque.size() ) {  // Trust everyone, but ALWAYS cut the cards!
1089         return;
1090     }
1091
1092     HUD_TextList.erase();
1093     HUD_LineList.erase();
1094     // HUD_StippleLineList.erase();
1095   
1096     glDisable(GL_DEPTH_TEST);
1097     glDisable(GL_LIGHTING);
1098
1099     static const SGPropertyNode * antialiased_node
1100         = fgGetNode("/sim/hud/antialiased");
1101
1102     if( antialiased_node->getBoolValue() ) {
1103         glEnable(GL_LINE_SMOOTH);
1104         //        glEnable(GL_BLEND);
1105         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1106         glHint(GL_LINE_SMOOTH_HINT,GL_DONT_CARE);
1107         glLineWidth(2.0);
1108     } else {
1109         glLineWidth(1.0);
1110     }
1111
1112     if( global_day_night_switch == HUD_DAY) {
1113         switch (HUD_deque[0]->get_brightness())
1114             {
1115             case HUD_BRT_LIGHT:
1116                 set_hud_color (0.1f, 0.9f, 0.1f);
1117                 break;
1118
1119             case HUD_BRT_MEDIUM:
1120                 set_hud_color (0.1f, 0.7f, 0.0f);
1121                 break;
1122
1123             case HUD_BRT_DARK:
1124                 set_hud_color (0.0f, 0.6f, 0.0f);
1125                 break;
1126
1127             case HUD_BRT_BLACK:
1128                 set_hud_color( 0.0f, 0.0f, 0.0f);
1129                 break;
1130
1131             default:
1132                 set_hud_color (0.1f, 0.9f, 0.1f);
1133             }
1134     } else {
1135         if( global_day_night_switch == HUD_NIGHT) {
1136             switch (HUD_deque[0]->get_brightness())
1137                 {
1138                 case HUD_BRT_LIGHT:
1139                     set_hud_color (0.9f, 0.1f, 0.1f);
1140                     break;
1141
1142                 case HUD_BRT_MEDIUM:
1143                     set_hud_color (0.7f, 0.0f, 0.1f);
1144                     break;
1145
1146                 case HUD_BRT_DARK:
1147                     set_hud_color (0.6f, 0.0f, 0.0f);
1148                     break;
1149
1150                 case HUD_BRT_BLACK:
1151                     set_hud_color( 0.0f, 0.0f, 0.0f);
1152                     break;
1153
1154                 default:
1155                     set_hud_color (0.6f, 0.0f, 0.0f);
1156                 }
1157         } else {     // Just in case default
1158             set_hud_color (0.1f, 0.9f, 0.1f);
1159         }
1160     }
1161
1162     for_each(HUD_deque.begin(), HUD_deque.end(), HUDdraw());
1163
1164     HUD_TextList.add( fgText(40, 10, get_formated_gmt_time(), 0) );
1165
1166 #ifdef FG_NETWORK_OLK
1167     if ( net_hud_display ) {
1168         net_hud_update();
1169     }
1170 #endif
1171
1172
1173     int apY = 480 - 80;
1174     // char scratch[128];
1175     // HUD_TextList.add( fgText( "AUTOPILOT", 20, apY) );
1176     // apY -= 15;
1177     FGAutopilot *AP = globals->get_autopilot();
1178     
1179     if( AP->get_HeadingEnabled() ) {
1180         HUD_TextList.add( fgText( 40, apY, AP->get_TargetHeadingStr()) );
1181         apY -= 15;
1182     }
1183     if( AP->get_AltitudeEnabled() ) {
1184         HUD_TextList.add( fgText( 40, apY, AP->get_TargetAltitudeStr()) );
1185         apY -= 15;
1186     }
1187     if( AP->get_HeadingMode() == FGAutopilot::FG_HEADING_WAYPOINT )
1188     {
1189         if ( strlen( AP->get_TargetWP1Str() ) ) {
1190             HUD_TextList.add( fgText( 40, apY, AP->get_TargetWP1Str() ) );
1191             apY -= 15;
1192         }
1193         if ( strlen( AP->get_TargetWP2Str() ) ) {
1194             HUD_TextList.add( fgText( 40, apY, AP->get_TargetWP2Str() ) );
1195             apY -= 15;
1196         }
1197         if ( strlen( AP->get_TargetWP3Str() ) ) {
1198             HUD_TextList.add( fgText( 40, apY, AP->get_TargetWP3Str() ) );
1199                 apY -= 15;
1200         }
1201     }
1202   
1203     HUD_TextList.draw();
1204
1205     HUD_LineList.draw();
1206
1207     // glEnable(GL_LINE_STIPPLE);
1208     // glLineStipple( 1, 0x00FF );
1209     // HUD_StippleLineList.draw();
1210     // glDisable(GL_LINE_STIPPLE);
1211
1212     if( antialiased_node->getBoolValue() ) {
1213         // glDisable(GL_BLEND);
1214         glDisable(GL_LINE_SMOOTH);
1215         glLineWidth(1.0);
1216     }
1217
1218     glEnable(GL_DEPTH_TEST);
1219     glEnable(GL_LIGHTING);
1220 }
1221