]> git.mxchange.org Git - flightgear.git/blob - Cockpit/hud.cxx
Added the declaration of memmove needed by the stl which apparently
[flightgear.git] / Cockpit / hud.cxx
1 /**************************************************************************
2  * hud.cxx -- hud defines and prototypes
3  *
4  * Written by Michele America, started September 1997.
5  *
6  * Copyright (C) 1997  Michele F. America  - micheleamerica@geocities.com
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * $Id$
23  * (Log is kept at end of this file)
24  **************************************************************************/
25
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31 #ifdef HAVE_WINDOWS_H
32 #  include <windows.h>
33 #endif
34
35 #include <GL/glut.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #ifdef HAVE_VALUES_H
40 #  include <values.h>  // for MAXINT
41 #endif
42
43 #include <Aircraft/aircraft.h>
44 #include <Debug/fg_debug.h>
45 #include <Include/fg_constants.h>
46 #include <Math/fg_random.h>
47 #include <Math/mat3.h>
48 #include <Math/polar3d.h>
49 #include <Scenery/scenery.hxx>
50 #include <Time/fg_timer.hxx>
51 #include <Weather/weather.h>
52
53 #include "hud.hxx"
54
55
56 #ifdef __sun__
57 extern "C" {
58   extern void *memmove(void *, const void *, size_t);
59 }
60 #endif
61
62
63 // The following routines obtain information concerntin the aircraft's
64 // current state and return it to calling instrument display routines.
65 // They should eventually be member functions of the aircraft.
66 //
67
68 //using namespace std;
69
70 /*
71
72 class instr_ptr {
73   private:
74     instr_item *pHI;
75
76   public:
77     instr_ptr ( instr_item * pHudInstr = 0) : pHI( pHudInstr){}
78     ~instr_ptr() { if( pHI ) delete pHI; }
79     instr_ptr & operator = (const instr_ptr & rhs);
80     instr_ptr( const instr_ptr & image );
81 }
82
83 instr_ptr &
84 instr_ptr ::
85 operator = ( const instr_ptr & rhs )
86 {
87   if( !(this == &rhs )) {
88     pHI = new instr_item( *(rhs.pHI));
89     }
90   return *this;
91 }
92
93 instr_ptr ::
94 instr_ptr ( const instr_ptr & image ) :
95 {
96   pHI = new instr_item( *(image.pHI));
97 }
98 */
99 deque< instr_item * > HUD_deque;
100
101 class locRECT {
102   public:
103     RECT rect;
104
105     locRECT( UINT left, UINT top, UINT right, UINT bottom);
106     RECT get_rect(void) { return rect;}
107 };
108
109 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
110 {
111   rect.left   =  left;
112   rect.top    =  top;
113   rect.right  =  right;
114   rect.bottom =  bottom;
115
116 }
117 // #define DEBUG
118
119 // #define drawOneLine(x1,y1,x2,y2)  glBegin(GL_LINES);
120 //   glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
121 //
122
123 void drawOneLine( UINT x1, UINT y1, UINT x2, UINT y2)
124 {
125   glBegin(GL_LINES);
126   glVertex2f(x1, y1);
127   glVertex2f(x2, y2);
128   glEnd();
129 }
130
131 void drawOneLine( RECT &rect)
132 {
133   glBegin(GL_LINES);
134   glVertex2f(rect.left, rect.top);
135   glVertex2f(rect.right, rect.bottom);
136   glEnd();
137 }
138
139 //
140 // The following code deals with painting the "instrument" on the display
141 //
142    /* textString - Bitmap font string */
143
144 static void textString(int x, int y, char *msg, void *font)
145 {
146         glRasterPos2f(x, y);
147         while (*msg) {
148                 glutBitmapCharacter(font, *msg);
149                 msg++;
150     }
151 }
152
153 /* strokeString - Stroke font string */
154 /*
155 static void strokeString(int x, int y, char *msg, void *font)
156 {
157         glPushMatrix();
158         glTranslatef(x, y, 0);
159         glScalef(.04, .04, .04);
160         while (*msg) {
161                 glutStrokeCharacter(font, *msg);
162                 msg++;
163         }
164         glPopMatrix();
165 }
166 */
167
168
169
170 // Abstract Base Class instr_item
171 //
172 UINT instr_item :: instances;  // Initial value of zero
173
174 // constructor    ( No default provided )
175
176 instr_item  ::
177    instr_item( RECT             scr_pos,
178                DBLFNPTR         data_source,
179                ReadOriented     orientation,
180                bool             working) :
181                       handle         ( ++instances  ),
182                       scrn_pos       ( scr_pos      ),
183                       load_value_fn  ( data_source  ),
184                       oriented       ( orientation  ),
185                       is_enabled     ( working      ),
186                       broken         ( FALSE        ),
187                       brightness     ( BRT_DARK     )
188 {
189 int hitemp, widetemp;
190 int xtemp;
191
192          // Check for inverted rect coords.  We must have top/right > bottom
193          // left corners or derived classes will draw their boxes very oddly.
194          // This is the only place we can reliably validate this data. Note
195          // that the box may be entirely or partly located off the screen.
196          // This needs consideration and possibly a member function to move
197          // the box, a keen idea for supporting "editing" of the HUD.
198   if( scrn_pos.top < scrn_pos.bottom ) {
199     xtemp           = scrn_pos.bottom;
200     scrn_pos.bottom = scrn_pos.top;
201     scrn_pos.top    = xtemp;
202     }
203   if( scrn_pos.left > scrn_pos.right ) {
204     xtemp           = scrn_pos.left;
205     scrn_pos.left   = scrn_pos.right;
206     scrn_pos.right  = xtemp;
207     }
208
209          // Insure that the midpoint marker will fall exactly at the
210          // middle of the bar.
211   if( !((scr_pos.top-scr_pos.bottom) % 2)) {
212     scrn_pos.top++;
213     }
214   if( !((scr_pos.right - scr_pos.left ) % 2)) {
215     scrn_pos.right++;
216     }
217          // Set up convenience values for centroid of the box and
218          // the span values according to orientation
219
220   hitemp   = scr_pos.top - scr_pos.bottom;
221   widetemp = scr_pos.right - scr_pos.left;
222   if((orientation == ReadTOP) || (orientation == ReadBOTTOM)) {
223     scr_span = widetemp;
224     }
225   else {
226     scr_span = hitemp;
227     }
228          // Here we work out the centroid for the corrected box.
229   mid_span.x = scr_pos.left   + ((scr_pos.right - scr_pos.left) >> 1);
230   mid_span.y = scr_pos.bottom + ((scr_pos.top - scr_pos.bottom) >> 1);
231 }
232
233 // copy constructor
234 instr_item  ::
235      instr_item ( const instr_item & image ):
236                          handle       ( ++instances        ),
237                          scrn_pos     ( image.scrn_pos     ),
238                          load_value_fn( image.load_value_fn),
239                          oriented     ( image.oriented     ),
240                          is_enabled   ( image.is_enabled   ),
241                          broken       ( image.broken       ),
242                          brightness   ( image.brightness   ),
243                          scr_span     ( image.scr_span     ),
244                          mid_span     ( image.mid_span     )
245 {
246 }
247
248 // assignment operator
249
250 instr_item & instr_item :: operator = ( const instr_item & rhs )
251 {
252   if( !(this == &rhs )) { // Not an identity assignment
253     scrn_pos      = rhs.scrn_pos;
254     load_value_fn = rhs.load_value_fn;
255     oriented      = rhs.oriented;
256     is_enabled    = rhs.is_enabled;
257     broken        = rhs.broken;
258     brightness    = rhs.brightness;
259     }
260   return *this;
261 }
262
263 // destructor
264
265 instr_item :: ~instr_item ()
266 {
267   if( instances ) {
268     instances--;
269     }
270 }
271
272 void instr_item ::
273     update( void )
274 {
275 }
276
277 // break_display       This is emplaced to provide hooks for making
278 //                     instruments unreliable. The default behavior is
279 // to simply not display, but more sophisticated behavior is available
280 // by over riding the function which is virtual in this class.
281
282 void instr_item ::
283     break_display ( bool bad )
284 {
285   broken = !!bad;
286   is_enabled = FALSE;
287 }
288
289 void instr_item ::
290     SetBrightness  ( int level  )
291 {
292   brightness = level;   // This is all we will do for now. Later the
293                         // brightness levels will be sensitive both to
294                         // the control knob and the outside light levels
295                         // to emulated night vision effects.
296 }
297
298 UINT instr_item :: get_Handle( void )
299 {
300   return handle;
301 }
302
303 //======================= Top of instr_label class =========================
304 instr_label ::
305          instr_label( RECT          region,
306                       DBLFNPTR      data_source,
307                       const char   *label_format,
308                       const char   *pre_label_string,
309                       const char   *post_label_string,
310                       ReadOriented  orientation,
311                       fgLabelJust   justification,
312                       int           font_size,
313                       int           blinking,
314                       bool          working ):
315                            instr_item( region, data_source,
316                                             orientation, working ),
317                            pformat  ( label_format      ),
318                            pre_str  ( pre_label_string  ),
319                            post_str ( post_label_string ),
320                            justify  ( justification     ),
321                            fontSize ( font_size         ),
322                            blink    ( blinking          )
323 {
324 }
325
326 // I put this in to make it easy to construct a class member using the current
327 // C code.
328
329
330 instr_label :: ~instr_label()
331 {
332 }
333
334 // Copy constructor
335 instr_label :: instr_label( const instr_label & image) :
336                               instr_item((const instr_item &)image),
337                               pformat    ( image.pformat    ),
338                               pre_str  ( image.pre_str  ),
339                               post_str ( image.post_str ),
340                               blink    ( image.blink    )
341 {
342 }
343
344 instr_label & instr_label ::operator = (const instr_label & rhs )
345 {
346   if( !(this == &rhs)) {
347     instr_item::operator = (rhs);
348     pformat      = rhs.pformat;
349     fontSize   = rhs.fontSize;
350     blink      = rhs.blink;
351     justify    = rhs.justify;
352     pre_str    = rhs.pre_str;
353     post_str   = rhs.post_str;
354     }
355         return *this;
356 }
357
358
359 //
360 // draw                    Draws a label anywhere in the HUD
361 //
362 //
363 void instr_label ::
364 draw( void )       // Required method in base class
365 {
366   char format_buffer[80];
367   char label_buffer[80];
368   int posincr;
369   int lenstr;
370   RECT  scrn_rect = get_location();
371
372   if( pre_str != NULL) {
373     if( post_str != NULL ) {
374       sprintf( format_buffer, "%s%s%s", pre_str, pformat, post_str );
375       }
376     else {
377       sprintf( format_buffer, "%s%s",   pre_str, pformat );
378       }
379     }
380   else {
381     if( post_str != NULL ) {
382       sprintf( format_buffer, "%s%s",   pformat, post_str );
383       }
384     } // else do nothing if both pre and post strings are nulls. Interesting.
385
386   sprintf( label_buffer, format_buffer, get_value() );
387 #ifdef DEBUGHUD
388         fgPrintf( FG_COCKPIT, FG_DEBUG,  format_buffer );
389         fgPrintf( FG_COCKPIT, FG_DEBUG,  "\n" );
390         fgPrintf( FG_COCKPIT, FG_DEBUG, label_buffer );
391         fgPrintf( FG_COCKPIT, FG_DEBUG, "\n" );
392 #endif
393   lenstr = strlen( label_buffer );
394
395   posincr = 0;   //  default to RIGHT_JUST ... center located calc: -lenstr*8;
396
397   if( justify == CENTER_JUST ) {
398     posincr =  - (lenstr << 2); //  -lenstr*4;
399     }
400   else {
401     if( justify == LEFT_JUST ) {
402       posincr = - (lenstr << 8);  // 0;
403       }
404     }
405
406   if( fontSize == SMALL ) {
407     textString( scrn_rect.left + posincr, scrn_rect.bottom,
408                 label_buffer, GLUT_BITMAP_8_BY_13);
409     }
410   else  {
411     if( fontSize == LARGE ) {
412       textString( scrn_rect.left + posincr, scrn_rect.bottom,
413                   label_buffer, GLUT_BITMAP_9_BY_15);
414       }
415     }
416 }
417
418 //============== Top of instr_scale class memeber definitions ===============
419 //
420 // Notes:
421 // 1. instr_scales divide the specified location into half and then
422 //    the half opposite the read direction in half again. A bar is
423 //    then drawn along the second divider. Scale ticks are drawn
424 //    between the middle and quarter section lines (minor division
425 //    markers) or just over the middle line.
426 //
427 // 2.  This class was not intended to be instanciated. See moving_scale
428 //     and guage_instr classes.
429 //============================================================================
430 instr_scale ::
431 instr_scale ( RECT         the_box,
432               DBLFNPTR     load_fn,
433               ReadOriented orient,
434               int          show_range,
435               int          maxValue,
436               int          minValue,
437               UINT         major_divs,
438               UINT         minor_divs,
439               UINT         rollover,
440               bool         working ) :
441                 instr_item( the_box, load_fn, orient, working),
442                 range_shown  ( show_range ),
443                 Maximum_value( maxValue   ),
444                 Minimum_value( minValue   ),
445                 Maj_div      ( major_divs ),
446                 Min_div      ( minor_divs ),
447                 Modulo       ( rollover   )
448 {
449 int temp;
450
451   scale_factor   = (double)get_span() / range_shown;
452   if( show_range < 0 ) {
453     range_shown = -range_shown;
454     }
455   temp = (Maximum_value - Minimum_value) / 100;
456   if( range_shown < temp ) {
457     range_shown = temp;
458     }
459 }
460
461 instr_scale ::
462   instr_scale( const instr_scale & image ) :
463             instr_item( (const instr_item &) image),
464             range_shown  ( image.range_shown   ),
465             Maximum_value( image.Maximum_value ),
466             Minimum_value( image.Minimum_value ),
467             Maj_div      ( image.Maj_div       ),
468             Min_div      ( image.Min_div       ),
469             Modulo       ( image.Modulo        ),
470             scale_factor ( image.scale_factor  )
471 {
472 }
473
474 instr_scale & instr_scale :: operator = (const instr_scale & rhs )
475 {
476   if( !(this == &rhs)) {
477     instr_item::operator = (rhs);
478     Minimum_value = rhs.Minimum_value;
479     Maximum_value = rhs.Maximum_value;
480     Maj_div       = rhs.Maj_div;
481     Min_div       = rhs.Min_div;
482     Modulo        = rhs.Modulo;
483     scale_factor  = rhs.scale_factor;
484     range_shown   = rhs.range_shown;
485     }
486   return *this;
487 }
488
489 instr_scale :: ~ instr_scale () {}
490
491 //========== Top of moving_scale_instr class member definitions =============
492
493 moving_scale ::
494 moving_scale( RECT         the_box,
495               DBLFNPTR     data_source,
496               ReadOriented orientation,
497               int          max_value,
498               int          min_value,
499               UINT         major_divs,
500               UINT         minor_divs,
501               UINT         modulus,
502               double       value_span,
503               bool         working) :
504                 instr_scale( the_box,
505                              data_source, orientation,
506                              (int)value_span,
507                              max_value, min_value,
508                              major_divs, minor_divs, modulus,
509                              working),
510                 val_span   ( value_span)
511 {
512   half_width_units = range_to_show() / 2.0;
513 }
514
515 moving_scale ::
516 ~moving_scale() { }
517
518 moving_scale ::
519 moving_scale( const moving_scale & image):
520       instr_scale( (const instr_scale & ) image)
521 {
522 }
523
524 moving_scale & moving_scale ::
525 operator = (const moving_scale & rhs )
526 {
527   if( !( this == &rhs)){
528     instr_scale::operator = (rhs);
529     }
530   return *this;
531 }
532
533 void moving_scale ::
534 draw( void ) //  (HUD_scale * pscale )
535 {
536   double vmin, vmax;
537   int marker_x;
538   int marker_y;
539   register i;
540   char TextScale[80];
541   int condition;
542   int disp_val;
543   POINT mid_scr = get_centroid();
544   POINT bias_bar;                  // eliminates some orientation checks
545   double cur_value = get_value();
546   RECT   scrn_rect = get_location();
547   ReadOriented orientation = get_orientation();
548
549   vmin = cur_value - half_width_units; // width units == needle travel
550   vmax = cur_value + half_width_units; // or picture unit span.
551
552
553   if( (orientation == ReadLEFT) ||( orientation == ReadRIGHT))  // Vertical scale
554     {
555     if( orientation == ReadLEFT ) {    // Calculate x marker offset
556       marker_x = scrn_rect.left - 6;
557       bias_bar.x = ((scrn_rect.right - mid_scr.x)>>1) + mid_scr.x;
558       }
559     else {                             // We'll default this for now.
560       marker_x = mid_scr.x;            // scrn_rect.right;
561       bias_bar.x = ((mid_scr.x - scrn_rect.left)>>1) + scrn_rect.left;
562       }
563
564     // Draw the basic markings for the scale...
565
566     drawOneLine( bias_bar.x,    // Vertical scale bar
567                  scrn_rect.bottom,
568                  bias_bar.x,
569                  scrn_rect.top );
570
571
572     if( orientation == ReadLEFT )
573       {
574
575       drawOneLine( bias_bar.x,     // Bottom tick bar
576                    scrn_rect.bottom,
577                    mid_scr.x,
578                    scrn_rect.bottom );
579
580       drawOneLine( bias_bar.x,     // Top tick bar
581                    scrn_rect.top,
582                    mid_scr.x,
583                    scrn_rect.top );
584
585       drawOneLine( scrn_rect.right,       // Middle tick bar /Index
586                    mid_scr.y,
587                    bias_bar.x,
588                    mid_scr.y );
589
590       }
591     else       { // ReadRight
592       drawOneLine( bias_bar.x,
593                    scrn_rect.bottom,
594                    mid_scr.x,
595                    scrn_rect.bottom );
596
597       drawOneLine( bias_bar.x,
598                    scrn_rect.top,
599                    mid_scr.x,
600                    scrn_rect.top );
601
602       drawOneLine( scrn_rect.left,
603                    mid_scr.y,
604                    bias_bar.x,
605                    mid_scr.y );
606       }
607
608     // Work through from bottom to top of scale. Calculating where to put
609     // minor and major ticks.
610
611     for( i = (int)vmin; i <= (int)vmax; i++ )
612       {
613 //      if( sub_type == LIMIT ) {           // Don't show ticks
614         condition = (i >= min_val()); // below Minimum value.
615 //        }
616 //      else {
617 //        if( sub_type == NOLIMIT ) {
618 //          condition = 1;
619 //          }
620 //        }
621       if( condition )   // Show a tick if necessary
622         {
623         // Calculate the location of this tick
624         marker_y = scrn_rect.bottom + (int)((i - vmin) * factor());
625
626         // Block calculation artifact from drawing ticks below min coordinate.
627         // Calculation here accounts for text height.
628
629         if( marker_y < (scrn_rect.bottom + 4)) {  // Magic number!!!
630           continue;
631           }
632         if( div_min()) {
633           if( (i%div_min()) == 0) {
634 //            if( orientation == ReadLEFT )
635 //              {
636 //              drawOneLine( marker_x + 3, marker_y, marker_x + 6, marker_y );
637               drawOneLine( bias_bar.x, marker_y, mid_scr.x, marker_y );
638 //              }
639 //            else {
640 //              if( orientation == ReadRIGHT )
641 //                {
642 //                drawOneLine( marker_x, marker_y, marker_x + 3, marker_y );
643 //                drawOneLine( bias_bar.x, marker_y, mid_scr.x, marker_y );
644 //                }
645 //              }
646             }
647           }
648         if( div_max()) {
649           if( (i%div_max()) == 0 )            {
650 //            drawOneLine( marker_x,     marker_y,
651 //                         marker_x + 6, marker_y );
652             if(modulo()) {
653               disp_val = i % modulo();
654               if( disp_val < 0) {
655                 disp_val += modulo();
656                 }
657               }
658             else {
659               disp_val = i;
660               }
661             sprintf( TextScale, "%d", disp_val );
662             if( orientation == ReadLEFT )              {
663               drawOneLine( mid_scr.x - 3, marker_y, bias_bar.x, marker_y );
664
665               textString( marker_x -  8 * strlen(TextScale) - 2, marker_y - 4,
666                           TextScale, GLUT_BITMAP_8_BY_13 );
667               }
668             else  {
669               drawOneLine( mid_scr.x + 3, marker_y, bias_bar.x, marker_y );
670               textString( marker_x + 10,                         marker_y - 4,
671                           TextScale, GLUT_BITMAP_8_BY_13 );
672               } // Else read oriented right
673             } // End if modulo division by major interval is zero
674           }  // End if major interval divisor non-zero
675         } // End if condition
676       } // End for range of i from vmin to vmax
677     }  // End if VERTICAL SCALE TYPE
678   else {                                // Horizontal scale by default
679     {
680     if( orientation == ReadTOP ) {
681       bias_bar.y = ((mid_scr.y - scrn_rect.bottom)>>1 ) + scrn_rect.bottom;
682       marker_y = bias_bar.y;  // Don't use now
683       }
684     else {  // We will assume no other possibility at this time.
685       bias_bar.y = ((scrn_rect.top - mid_scr.y)>>1 ) + mid_scr.y;
686       marker_y = bias_bar.y;  // Don't use now
687       }
688
689     drawOneLine( scrn_rect.left,
690                  bias_bar.y,
691                  scrn_rect.right,
692                  bias_bar.y );
693
694     if( orientation == ReadTOP )
695       {
696       drawOneLine( scrn_rect.left,
697                    bias_bar.y,
698                    scrn_rect.left,
699                    mid_scr.y);
700
701       drawOneLine( scrn_rect.right,
702                    bias_bar.y,
703                    scrn_rect.right,
704                    mid_scr.y );
705
706       drawOneLine( mid_scr.x,
707                    scrn_rect.bottom,
708                    mid_scr.x,
709                    bias_bar.y );
710
711       }
712     else {
713       if( orientation == ReadBOTTOM )
714         {
715         drawOneLine( scrn_rect.left,
716                      bias_bar.y,
717                      scrn_rect.left,
718                      mid_scr.y );
719
720         drawOneLine( scrn_rect.right,
721                      bias_bar.y,
722                      scrn_rect.right,
723                      mid_scr.y );
724
725         drawOneLine( mid_scr.x,
726                      scrn_rect.top,
727                      mid_scr.x,
728                      bias_bar.y );
729         }
730       }
731
732     for( i = (int)vmin; i <= (int)vmax; i++ )  // increment is faster than addition
733       {
734 //      if( sub_type == LIMIT ) {
735         condition = (i >= min_val());
736 //        }
737 //      else {
738 //        if( sub_type == NOLIMIT ) {
739 //          condition = 1;
740 //          }
741 //        }
742       if( condition )        {
743         marker_x = scrn_rect.left + (int)((i - vmin) * factor());
744         if( div_min()){
745           if( (i%(int)div_min()) == 0 ) {
746 //            if( orientation == ReadTOP )
747 //              {
748 //              drawOneLine( marker_x, marker_y, marker_x, marker_y + 3 );
749               drawOneLine( marker_x, bias_bar.y, marker_x, mid_scr.y );
750 //              }
751 //            else {
752 //            drawOneLine( marker_x, marker_y + 3, marker_x, marker_y + 6 );
753 //              drawOneLine( marker_x, bias_bar.y, marker_x, mid_scr.y );
754 //              }
755             }
756            }
757         if( div_max()) {
758           if( (i%(int)div_max())==0 )
759             {
760             if(modulo()) {
761               disp_val = i % modulo();
762               if( disp_val < 0) {
763                 disp_val += modulo();
764                 }
765               }
766             else {
767               disp_val = i;
768               }
769               sprintf( TextScale, "%d", disp_val );
770             if( orientation == ReadTOP )
771               {
772 //              drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
773               drawOneLine( marker_x, mid_scr.y + 3,marker_x, bias_bar.y );
774               textString ( marker_x - 4 * strlen(TextScale), marker_y + 14,
775                            TextScale, GLUT_BITMAP_8_BY_13 );
776               }
777             else {
778 //            drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
779               drawOneLine( marker_x, mid_scr.y - 3,marker_x, bias_bar.y );
780               textString ( marker_x - 4 * strlen(TextScale), mid_scr.y - 14,
781                            TextScale, GLUT_BITMAP_8_BY_13 );
782               }
783             }
784           }  
785         }
786       }
787     }
788    }
789 }
790
791 //============== Top of guage_instr class member definitions ==============
792
793 guage_instr ::
794     guage_instr( RECT         the_box,
795                  DBLFNPTR     load_fn,
796                  ReadOriented readway,
797                  int          maxValue,
798                  int          minValue,
799                  UINT         major_divs,
800                  UINT         minor_divs,
801                  UINT         modulus,
802                  bool         working) :
803            instr_scale( the_box,
804                         load_fn, readway,
805                         maxValue, maxValue, minValue,
806                         major_divs, minor_divs,
807                         modulus,
808                         working)
809 {
810 }
811
812 guage_instr ::
813    ~guage_instr()
814 {
815 }
816
817 guage_instr ::
818     guage_instr( const guage_instr & image):
819        instr_scale( (instr_scale &) image)
820 {
821 }
822
823 guage_instr & guage_instr ::
824     operator = (const guage_instr & rhs )
825 {
826   if( !(this == &rhs)) {
827     instr_scale::operator = (rhs);
828     }
829   return *this;
830 }
831
832 // As implemented, draw only correctly draws a horizontal or vertical
833 // scale. It should contain a variation that permits clock type displays.
834 // Now is supports "tickless" displays such as control surface indicators.
835 // This routine should be worked over before using. Current value would be
836 // fetched and not used if not commented out. Clearly that is intollerable.
837
838 void guage_instr :: draw (void)
839 {
840   int marker_x;
841   int marker_y;
842   register i;
843   char TextScale[80];
844 //  int condition;
845   int disp_val;
846   double vmin              = min_val();
847   double vmax              = max_val();
848   POINT mid_scr            = get_centroid();
849 //  double cur_value         = get_value();
850   RECT   scrn_rect         = get_location();
851   ReadOriented orientation = get_orientation();
852
853   if( (orientation == ReadLEFT) ||( orientation == ReadRIGHT))  // Vertical scale
854     {
855     mid_scr = get_centroid();
856     if( orientation == ReadLEFT )     // Calculate x marker offset
857       marker_x = scrn_rect.left - 6;
858     else                              // We'll default this for now.
859       marker_x = scrn_rect.right;
860
861     // Draw the basic markings for the scale...
862
863     if( orientation == ReadLEFT )
864       {
865
866       drawOneLine( scrn_rect.right - 3,     // Bottom tick bar
867                    scrn_rect.bottom,
868                    scrn_rect.right,
869                    scrn_rect.bottom );
870
871       drawOneLine( scrn_rect.right - 3,     // Top tick bar
872                    scrn_rect.top,
873                    scrn_rect.right,
874                    scrn_rect.top );
875       }
876     else       {
877       drawOneLine( scrn_rect.right,
878                    scrn_rect.bottom,
879                    scrn_rect.right+3,
880                    scrn_rect.bottom );
881
882       drawOneLine( scrn_rect.right,
883                    scrn_rect.top,
884                    scrn_rect.right+3,
885                    scrn_rect.top );
886       }
887
888     // Work through from bottom to top of scale. Calculating where to put
889     // minor and major ticks.
890
891     for( i = (int)vmin; i <= (int)vmax; i++ )
892       {
893         // Calculate the location of this tick
894       marker_y = scrn_rect.bottom + (int)((i - vmin) * factor());
895
896       if( div_min()) {
897         if( (i%div_min()) == 0) {
898           if( orientation == ReadLEFT )
899             {
900             drawOneLine( marker_x + 3, marker_y, marker_x + 6, marker_y );
901             }
902           else {
903             drawOneLine( marker_x, marker_y, marker_x + 3, marker_y );
904             }
905           }
906         }
907       if( div_max()) {
908         if( (i%div_max()) == 0 )            {
909           drawOneLine( marker_x,     marker_y,
910                        marker_x + 6, marker_y );
911           if(modulo()) {
912             disp_val = i % modulo();
913             if( disp_val < 0) {
914               disp_val += modulo();
915               }
916             }
917           else {
918             disp_val = i;
919             }
920           sprintf( TextScale, "%d", disp_val );
921           if( orientation == ReadLEFT )              {
922             textString( marker_x -  8 * strlen(TextScale) - 2, marker_y - 4,
923                         TextScale, GLUT_BITMAP_8_BY_13 );
924             }
925           else  {
926             if( orientation == ReadRIGHT )              {
927             textString( marker_x + 10,                         marker_y - 4,
928                         TextScale, GLUT_BITMAP_8_BY_13 );
929               }
930             }
931           }
932         } // End if condition
933       } // End for range of i from vmin to vmax
934     }  // End if VERTICAL SCALE TYPE
935   else {                                // Horizontal scale by default
936     {
937     if( orientation == ReadTOP ) {
938       marker_y = scrn_rect.bottom;
939       }
940     else {
941       if( orientation == ReadBOTTOM ) {
942         marker_y = scrn_rect.bottom - 6;
943         }
944       }
945     drawOneLine( scrn_rect.left,
946                  scrn_rect.bottom,
947                  scrn_rect.right,
948                  scrn_rect.bottom );
949
950     if( orientation == ReadTOP )
951       {
952       drawOneLine( scrn_rect.left,
953                    scrn_rect.bottom,
954                    scrn_rect.left,
955                    scrn_rect.bottom + 3 );
956
957       drawOneLine( scrn_rect.right,
958                    scrn_rect.bottom,
959                    scrn_rect.right,
960                    scrn_rect.bottom + 6 );
961       }
962     else {
963       if( orientation == ReadBOTTOM )
964         {
965         drawOneLine( scrn_rect.left,
966                      scrn_rect.bottom,
967                      scrn_rect.left,
968                      scrn_rect.bottom - 6 );
969
970         drawOneLine( scrn_rect.right,
971                      scrn_rect.bottom,
972                      scrn_rect.right,
973                      scrn_rect.bottom - 6 );
974         }
975       }
976
977     for( i = (int)vmin; i <= (int)vmax; i++ )  // increment is faster than addition
978       {
979       marker_x = scrn_rect.left + (int)((i - vmin) * factor());
980       if( div_min()) {
981         if( (i%div_min()) == 0 ) {
982           if( orientation == ReadTOP )
983             {
984             drawOneLine( marker_x, marker_y, marker_x, marker_y + 3 );
985             }
986           else {
987             if( orientation == ReadBOTTOM )
988               {
989               drawOneLine( marker_x, marker_y + 3, marker_x, marker_y + 6 );
990               }
991             }
992           }  // End if minor tick called for.
993         }  // End if minor ticks are of interest
994       if( div_max()) {
995         if( (i%div_max())==0 )
996           {
997           // Modulo implies a "clock" style instrument. Needs work.
998           if(modulo()) {
999             disp_val = i % modulo();
1000             if( disp_val < 0) {
1001               disp_val += modulo();
1002               }
1003             }
1004           else {   // Scale doesn't roll around.
1005             disp_val = i;
1006             }
1007             sprintf( TextScale, "%d", disp_val );
1008           if( orientation == ReadTOP )
1009             {
1010             drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
1011             textString ( marker_x - 4 * strlen(TextScale), marker_y + 14,
1012                          TextScale, GLUT_BITMAP_8_BY_13 );
1013             }
1014           else {
1015             if( orientation == ReadBOTTOM )
1016               {
1017               drawOneLine( marker_x, marker_y, marker_x, marker_y+6 );
1018               textString ( marker_x - 4 * strlen(TextScale), marker_y - 14,
1019                            TextScale, GLUT_BITMAP_8_BY_13 );
1020               } // End if bottom
1021             } // End else if not ReadTOP
1022           } // End if major division point.
1023         } // End if major divisions of interest.
1024       }
1025     }
1026    }
1027 }
1028
1029 //============ Top of dual_instr_item class member definitions ============
1030
1031 dual_instr_item ::
1032   dual_instr_item ( RECT         the_box,
1033                     DBLFNPTR     chn1_source,
1034                     DBLFNPTR     chn2_source,
1035                     bool         working,
1036                     ReadOriented readway ):
1037                   instr_item( the_box, chn1_source, readway, working),
1038                   alt_data_source( chn2_source )
1039 {
1040 }
1041
1042 dual_instr_item ::
1043   dual_instr_item( const dual_instr_item & image) :
1044                  instr_item ((instr_item &) image ),
1045                  alt_data_source( image.alt_data_source)
1046 {
1047 }
1048
1049 dual_instr_item & dual_instr_item ::
1050   operator = (const dual_instr_item & rhs )
1051 {
1052   if( !(this == &rhs)) {
1053     instr_item::operator = (rhs);
1054     alt_data_source = rhs.alt_data_source;
1055     }
1056   return *this;
1057 }
1058
1059 //============ Top of fgTBI_instr class member definitions ==============
1060
1061 fgTBI_instr ::
1062 fgTBI_instr( RECT      the_box,
1063              DBLFNPTR  chn1_source,
1064              DBLFNPTR  chn2_source,
1065              UINT      maxBankAngle,
1066              UINT      maxSlipAngle,
1067              UINT      gap_width,
1068              bool      working ) :
1069                dual_instr_item( the_box,
1070                                 chn1_source,
1071                                 chn2_source,
1072                                 working,
1073                                 ReadTOP),
1074                BankLimit      (maxBankAngle),
1075                SlewLimit      (maxSlipAngle),
1076                scr_hole       (gap_width   )
1077 {
1078 }
1079
1080 fgTBI_instr :: ~fgTBI_instr() {}
1081
1082 fgTBI_instr :: fgTBI_instr( const fgTBI_instr & image):
1083                  dual_instr_item( (const dual_instr_item &) image),
1084                  BankLimit( image.BankLimit),
1085                  SlewLimit( image.SlewLimit),
1086                  scr_hole ( image.scr_hole )
1087 {
1088 }
1089
1090 fgTBI_instr & fgTBI_instr ::
1091 operator = (const fgTBI_instr & rhs )
1092 {
1093   if( !(this == &rhs)) {
1094     dual_instr_item::operator = (rhs);
1095     BankLimit = rhs.BankLimit;
1096     SlewLimit = rhs.SlewLimit;
1097     scr_hole  = rhs.scr_hole;
1098     }
1099    return *this;
1100 }
1101
1102 //
1103 //      Draws a Turn Bank Indicator on the screen
1104 //
1105
1106  void fgTBI_instr :: draw( void )
1107 {
1108   int x_inc1, y_inc1;
1109   int x_inc2, y_inc2;
1110   int x_t_inc1, y_t_inc1;
1111
1112   int d_bottom_x, d_bottom_y;
1113   int d_right_x, d_right_y;
1114   int d_top_x, d_top_y;
1115   int d_left_x, d_left_y;
1116
1117   int inc_b_x, inc_b_y;
1118   int inc_r_x, inc_r_y;
1119   int inc_t_x, inc_t_y;
1120   int inc_l_x, inc_l_y;
1121   RECT My_box = get_location();
1122   POINT centroid = get_centroid();
1123   int tee_height = My_box.top - My_box.bottom; // Hack, hack.
1124   
1125 //      struct fgFLIGHT *f = &current_aircraft.flight;
1126   double sin_bank, cos_bank;
1127   double bank_angle, sideslip_angle;
1128   double ss_const; // sideslip angle pixels per rad
1129
1130   bank_angle     = current_ch2();  // Roll limit +/- 30 degrees
1131   if( bank_angle < -FG_PI_2/3 ) {
1132     bank_angle = -FG_PI_2/3;
1133   }else if( bank_angle > FG_PI_2/3 ) {
1134     bank_angle = FG_PI_2/3;
1135   }
1136   sideslip_angle = current_ch1(); // Sideslip limit +/- 20 degrees
1137   if( sideslip_angle < -FG_PI/9 ) {
1138     sideslip_angle = -FG_PI/9;
1139   } else if( sideslip_angle > FG_PI/9 ) {
1140     sideslip_angle = FG_PI/9;
1141   }
1142
1143         // sin_bank = sin( FG_2PI-FG_Phi );
1144         // cos_bank = cos( FG_2PI-FG_Phi );
1145   sin_bank = sin(FG_2PI-bank_angle);
1146   cos_bank = cos(FG_2PI-bank_angle);
1147   
1148   x_inc1 = (int)(get_span() * cos_bank);
1149   y_inc1 = (int)(get_span() * sin_bank);
1150   x_inc2 = (int)(scr_hole  * cos_bank);
1151   y_inc2 = (int)(scr_hole  * sin_bank);
1152
1153   x_t_inc1 = (int)(tee_height * sin_bank);
1154   y_t_inc1 = (int)(tee_height * cos_bank);
1155   
1156   d_bottom_x = 0;
1157   d_bottom_y = (int)(-scr_hole);
1158   d_right_x  = (int)(scr_hole);
1159   d_right_y  = 0;
1160   d_top_x    = 0;
1161   d_top_y    = (int)(scr_hole);
1162   d_left_x   = (int)(-scr_hole);
1163   d_left_y   = 0;
1164
1165   ss_const = (get_span()*2)/(FG_2PI/9);  // width represents 40 degrees
1166
1167   d_bottom_x += (int)(sideslip_angle*ss_const);
1168   d_right_x  += (int)(sideslip_angle*ss_const);
1169   d_left_x   += (int)(sideslip_angle*ss_const);
1170   d_top_x    += (int)(sideslip_angle*ss_const);
1171   
1172   inc_b_x = (int)(d_bottom_x*cos_bank-d_bottom_y*sin_bank);
1173   inc_b_y = (int)(d_bottom_x*sin_bank+d_bottom_y*cos_bank);
1174   inc_r_x = (int)(d_right_x*cos_bank-d_right_y*sin_bank);
1175   inc_r_y = (int)(d_right_x*sin_bank+d_right_y*cos_bank);
1176   inc_t_x = (int)(d_top_x*cos_bank-d_top_y*sin_bank);
1177   inc_t_y = (int)(d_top_x*sin_bank+d_top_y*cos_bank);
1178   inc_l_x = (int)(d_left_x*cos_bank-d_left_y*sin_bank);
1179   inc_l_y = (int)(d_left_x*sin_bank+d_left_y*cos_bank);
1180
1181   if( scr_hole == 0 )
1182     {
1183     drawOneLine( centroid.x - x_inc1, centroid.y - y_inc1, \
1184                  centroid.x + x_inc1, centroid.y + y_inc1 );
1185     }
1186   else
1187     {
1188     drawOneLine( centroid.x - x_inc1, centroid.y - y_inc1, \
1189                  centroid.x - x_inc2, centroid.y - y_inc2 );
1190     drawOneLine( centroid.x + x_inc2, centroid.y + y_inc2, \
1191                  centroid.x + x_inc1, centroid.y + y_inc1 );
1192     }
1193
1194   // draw teemarks
1195   drawOneLine( centroid.x + x_inc2,            \
1196                  centroid.y + y_inc2,          \
1197                centroid.x + x_inc2 + x_t_inc1, \
1198                  centroid.y + y_inc2 - y_t_inc1 );
1199   drawOneLine( centroid.x - x_inc2,            \
1200                  centroid.y - y_inc2,          \
1201                centroid.x - x_inc2 + x_t_inc1, \
1202                  centroid.y - y_inc2 - y_t_inc1 );
1203                
1204   // draw sideslip diamond (it is not yet positioned correctly )
1205   drawOneLine( centroid.x + inc_b_x, \
1206                centroid.y + inc_b_y, \
1207                centroid.x + inc_r_x, \
1208                centroid.y + inc_r_y );
1209   drawOneLine( centroid.x + inc_r_x, \
1210                centroid.y + inc_r_y, \
1211                centroid.x + inc_t_x, \
1212                centroid.y + inc_t_y );
1213   drawOneLine( centroid.x + inc_t_x, \
1214                centroid.y + inc_t_y, \
1215                centroid.x + inc_l_x, \
1216                centroid.y + inc_l_y );
1217   drawOneLine( centroid.x + inc_l_x, \
1218                centroid.y + inc_l_y, \
1219                centroid.x + inc_b_x, \
1220                centroid.y + inc_b_y );
1221
1222 }
1223
1224 //====================== Top of HudLadder Class =======================
1225 HudLadder ::
1226   HudLadder(  RECT      the_box,
1227               DBLFNPTR  ptch_source,
1228               DBLFNPTR  roll_source,
1229               UINT      span_units,
1230               int       major_div,
1231               UINT      minor_div,
1232               UINT      screen_hole,
1233               UINT      lbl_pos,
1234               bool      working) :
1235                dual_instr_item( the_box,
1236                                 ptch_source,
1237                                 roll_source,
1238                                 working,
1239                                 ReadRIGHT ),
1240                width_units    ( span_units   ),
1241                div_units      ( major_div < 0? -major_div: major_div ),
1242                minor_div      ( minor_div    ),
1243                label_pos      ( lbl_pos      ),
1244                scr_hole       ( screen_hole  ),
1245                vmax           ( span_units/2 ),
1246                vmin           ( -vmax        )
1247 {
1248   if( !width_units ) {
1249     width_units = 45;
1250     }
1251   factor = (double)get_span() / (double) width_units;
1252 }
1253
1254 HudLadder ::
1255   ~HudLadder()
1256 {
1257 }
1258
1259 HudLadder ::
1260   HudLadder( const HudLadder & image ) :
1261         dual_instr_item( (dual_instr_item &) image),
1262         width_units    ( image.width_units   ),
1263         div_units      ( image.div_units     ),
1264         label_pos      ( image.label_pos     ),
1265         scr_hole       ( image.scr_hole      ),
1266         vmax           ( image.vmax ),
1267         vmin           ( image.vmin ),
1268         factor         ( image.factor        )
1269 {
1270 }
1271 HudLadder & HudLadder ::
1272   operator = ( const HudLadder & rhs )
1273 {
1274   if( !(this == &rhs)) {
1275     (dual_instr_item &)(*this) = (dual_instr_item &)rhs;
1276     width_units  = rhs.width_units;
1277     div_units    = rhs.div_units;
1278     label_pos    = rhs.label_pos;
1279     scr_hole     = rhs.scr_hole;
1280     vmax         = rhs.vmax;
1281     vmin         = rhs.vmin;
1282     factor       = rhs.factor;
1283     }
1284   return *this;
1285 }
1286
1287 //
1288 //      Draws a climb ladder in the center of the HUD
1289 //
1290
1291 void HudLadder :: draw( void )
1292 {
1293   double roll_value, pitch_value;
1294 //  int marker_x;
1295   int marker_y;
1296   int scr_min;
1297 //  int scr_max;
1298   int x_ini, x_end;
1299   int y_ini, y_end;
1300   int new_x_ini, new_x_end;
1301   int new_y_ini, new_y_end;
1302   register i;
1303   POINT centroid = get_centroid();
1304   RECT  box      = get_location();
1305   int half_span  = (box.right - box.left) >> 1;
1306   char TextLadder[80];
1307   int condition;
1308
1309   roll_value  = current_ch2();
1310   pitch_value = current_ch1() * RAD_TO_DEG;
1311
1312   vmin        = (int)(pitch_value - (double)width_units/2.0);
1313   vmax        = (int)(pitch_value + (double)width_units/2.0);
1314
1315   scr_min     = box.bottom; // centroid.y - ((box.top - box.bottom) >> 1);
1316 //  scr_max     = box.top;    // scr_min    + (box.top - box.bottom);
1317 //  marker_x    = centroid.x - half_span;
1318
1319 // Box the target.
1320   drawOneLine( centroid.x - 5, centroid.y,     centroid.x,     centroid.y + 5);
1321   drawOneLine( centroid.x,     centroid.y + 5, centroid.x + 5, centroid.y);
1322   drawOneLine( centroid.x + 5, centroid.y,     centroid.x,     centroid.y - 5);
1323   drawOneLine( centroid.x,     centroid.y - 5, centroid.x - 5, centroid.y);
1324
1325   for( i=(int)vmin; i<=(int)vmax; i+=1 )
1326     {
1327     condition = 1;
1328     if( condition )
1329       {
1330       marker_y = scr_min + (int)((i-vmin)*factor);
1331       if( div_units ) {
1332         if( i%div_units==0 )
1333           {
1334           sprintf( TextLadder, "%d", i );
1335           if( scr_hole == 0 )
1336             {
1337             if( i ) {
1338               x_ini = centroid.x - half_span;
1339               }
1340             else {
1341               x_ini = centroid.x - half_span - 10;
1342               }
1343             y_ini = marker_y;
1344             x_end = centroid.x + half_span;
1345             y_end = marker_y;
1346             new_x_ini = centroid.x + (int)(                     \
1347                        (x_ini - centroid.x) * cos(roll_value) - \
1348                        (y_ini - centroid.y) * sin(roll_value));
1349             new_y_ini = centroid.y + (int)(                     \
1350                        (x_ini - centroid.x) * sin(roll_value) + \
1351                        (y_ini - centroid.y) * cos(roll_value));
1352             new_x_end = centroid.x + (int)(                       \
1353                        (x_end - centroid.x) * cos(roll_value) - \
1354                        (y_end - centroid.y) * sin(roll_value));
1355             new_y_end = centroid.y + (int)(                            \
1356                        (x_end - centroid.x) * sin(roll_value) + \
1357                        (y_end - centroid.y) * cos(roll_value));
1358
1359             if( i >= 0 )
1360               {
1361               drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
1362               }
1363             else
1364               {
1365               glEnable(GL_LINE_STIPPLE);
1366               glLineStipple( 1, 0x00FF );
1367               drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
1368               glDisable(GL_LINE_STIPPLE);
1369               }
1370             textString( new_x_ini -  8 * strlen(TextLadder) - 8,
1371                         new_y_ini -  4,
1372                         TextLadder, GLUT_BITMAP_8_BY_13 );
1373             textString( new_x_end + 10,
1374                         new_y_end -  4,
1375                         TextLadder, GLUT_BITMAP_8_BY_13 );
1376             }
1377           else
1378             {
1379             if( i != 0 )  {
1380               x_ini = centroid.x - half_span;
1381               }
1382             else          {
1383               x_ini = centroid.x - half_span - 10;
1384               }
1385             y_ini = marker_y;
1386             x_end = centroid.x - half_span + scr_hole/2;
1387             y_end = marker_y;
1388             new_x_ini = centroid.x+ (int)(                      \
1389                         (x_ini - centroid.x) * cos(roll_value) -\
1390                         (y_ini - centroid.y) * sin(roll_value));
1391             new_y_ini = centroid.y+  (int)(                     \
1392                         (x_ini - centroid.x) * sin(roll_value) +\
1393                         (y_ini - centroid.y) * cos(roll_value));
1394             new_x_end = centroid.x+  (int)(                     \
1395                         (x_end - centroid.x) * cos(roll_value) -\
1396                         (y_end - centroid.y) * sin(roll_value));
1397             new_y_end = centroid.y+ (int)(                      \
1398                         (x_end - centroid.x) * sin(roll_value) +\
1399                         (y_end - centroid.y) * cos(roll_value));
1400
1401             if( i >= 0 )
1402               {
1403               drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
1404               }
1405             else
1406               {
1407               glEnable(GL_LINE_STIPPLE);
1408               glLineStipple( 1, 0x00FF );
1409               drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
1410               glDisable(GL_LINE_STIPPLE);
1411               }
1412             textString( new_x_ini - 8 * strlen(TextLadder) - 8,
1413                         new_y_ini - 4,
1414                         TextLadder, GLUT_BITMAP_8_BY_13 );
1415
1416             x_ini = centroid.x + half_span - scr_hole/2;
1417             y_ini = marker_y;
1418             if( i != 0 )  {
1419               x_end = centroid.x + half_span;
1420               }
1421             else          {
1422               x_end = centroid.x + half_span + 10;
1423               }
1424             y_end = marker_y;
1425             new_x_ini = centroid.x + (int)(                 \
1426                         (x_ini-centroid.x)*cos(roll_value) -\
1427                         (y_ini-centroid.y)*sin(roll_value));
1428             new_y_ini = centroid.y + (int)(                 \
1429                         (x_ini-centroid.x)*sin(roll_value) +\
1430                         (y_ini-centroid.y)*cos(roll_value));
1431             new_x_end = centroid.x + (int)(                 \
1432                         (x_end-centroid.x)*cos(roll_value) -\
1433                         (y_end-centroid.y)*sin(roll_value));
1434             new_y_end = centroid.y +  (int)(                  \
1435                         (x_end-centroid.x)*sin(roll_value) +\
1436                         (y_end-centroid.y)*cos(roll_value));
1437
1438             if( i >= 0 )
1439               {
1440               drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
1441               }
1442             else
1443               {
1444               glEnable(GL_LINE_STIPPLE);
1445               glLineStipple( 1, 0x00FF );
1446               drawOneLine( new_x_ini, new_y_ini, new_x_end, new_y_end );
1447               glDisable(GL_LINE_STIPPLE);
1448               }
1449             textString( new_x_end+10, new_y_end-4,
1450                         TextLadder, GLUT_BITMAP_8_BY_13 );
1451             }
1452           }
1453          }
1454             /* if( i%div_max()==0 )
1455             {
1456                 drawOneLine( marker_x, marker_y, marker_x+6, marker_y );
1457                 sprintf( TextScale, "%d", i );
1458                 if( orientation == LEFT )
1459                 {
1460                         textString( marker_x-8*strlen(TextScale)-2, marker_y-4,
1461                               TextScale, GLUT_BITMAP_8_BY_13 );
1462                 }
1463                 else if( orientation == RIGHT )
1464                 {
1465                         textString( marker_x+10, marker_y-4,
1466                               TextScale, GLUT_BITMAP_8_BY_13 );
1467                 }
1468             } */
1469         }
1470     }
1471
1472 }
1473
1474 //========================= End of Class Implementations===================
1475 // fgHUDInit
1476 //
1477 // Constructs a HUD object and then adds in instruments. At the present
1478 // the instruments are hard coded into the routine. Ultimately these need
1479 // to be defined by the aircraft's instrumentation records so that the
1480 // display for a Piper Cub doesn't show the speed range of a North American
1481 // mustange and the engine readouts of a B36!
1482 //
1483
1484 #define INSTRDEFS 17
1485
1486 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
1487 {
1488   instr_item *HIptr;
1489   int index;
1490   RECT loc;
1491
1492   fgPrintf( FG_COCKPIT, FG_INFO, "Initializing current aircraft HUD\n" );
1493
1494   HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());  // empty the HUD deque
1495
1496 //  hud->code = 1;
1497 //  hud->status = 0;
1498
1499   // For now lets just hardcode the hud here.
1500   // In the future, hud information has to come from the same place
1501   // aircraft information came from.
1502
1503 //  fgHUDSetTimeMode( hud, NIGHT );
1504 //  fgHUDSetBrightness( hud, BRT_LIGHT );
1505
1506   for( index = 0; index <= INSTRDEFS; index++) {
1507     switch ( index ) {
1508       case 0:     // TBI
1509       //  fgHUDAddHorizon( hud, 330, 100, 40, 5, 10, get_roll, get_sideslip );
1510         loc.left   =  330 - 40;
1511         loc.top    =  110;
1512         loc.right  =  330 + 40;
1513         loc.bottom =  100;
1514         HIptr = (instr_item *) new fgTBI_instr( loc );
1515         break;
1516
1517       case 1:     // Artificial Horizon
1518       //  fgHUDAddLadder ( hud, 330, 285, 120, 180, 70, 10,
1519       //                   NONE, 45, get_roll, get_pitch );
1520         loc.left   =  270; // 330 -  60
1521         loc.top    =  375; // 285 +  90
1522         loc.right  =  390; // 330 +  60
1523         loc.bottom =  195; // 285 -  90
1524         HIptr = (instr_item *) new HudLadder( loc );
1525         break;
1526
1527       case 2:    // KIAS
1528       //  fgHUDAddScale  ( hud, VERTICAL,     LIMIT, 200, 180, 380,  5,  10,
1529       //                      LEFT,     0,  100,   50,   0, get_speed );
1530         loc.left   =  160;
1531         loc.top    =  380;
1532         loc.right  =  200;
1533         loc.bottom =  180;
1534         HIptr = (instr_item *) new moving_scale( loc,
1535                                                  get_speed,
1536                                                  ReadLEFT,
1537                                                  200, 0,
1538                                                  10,  5,
1539                                                  0,
1540                                                  50.0,
1541                                                  TRUE);
1542         break;
1543
1544       case 3:    // Angle of Attack
1545       //  fgHUDAddScale  ( hud, HORIZONTAL, NOLIMIT, 180, 250, 410,  1,   5,
1546       //                      BOTTOM, -40,   50,   21,   0, get_aoa );
1547         loc.left   =  250;
1548         loc.top    =  190;
1549         loc.right  =  410;
1550         loc.bottom =  160;
1551         HIptr = (instr_item *) new moving_scale( loc,
1552                                                  get_aoa,
1553                                                  ReadBOTTOM,
1554                                                  50, -40,
1555                                                  5,    1,
1556                                                  0,
1557                                                  21.0,
1558                                                  TRUE);
1559         break;
1560
1561       case 4:    // GYRO COMPASS
1562       // fgHUDAddScale  ( hud, HORIZONTAL, NOLIMIT, 380, 200, 460,  5,  10,
1563       //                      TOP,      0,   50,   50, 360, get_heading );
1564         loc.left   =  200;
1565         loc.top    =  410;
1566         loc.right  =  460;
1567         loc.bottom =  380;
1568         HIptr = (instr_item *) new moving_scale( loc,
1569                                                  get_heading,
1570                                                  ReadTOP,
1571                                                  360, 0,
1572                                                  10,   5,
1573                                                  360,
1574                                                  50,
1575                                                  TRUE);
1576         break;
1577
1578       case 5:    // AMSL
1579       //  fgHUDAddScale  ( hud, VERTICAL,     LIMIT, 460, 180, 380, 25, 100,
1580       //                      RIGHT,    0, 15000, 250,   0, get_altitude);
1581         loc.left   =  460;
1582         loc.top    =  380;
1583         loc.right  =  490;
1584         loc.bottom =  180;
1585         HIptr = (instr_item *) new moving_scale( loc,
1586                                                  get_altitude,
1587                                                  ReadRIGHT,
1588                                                  15000, 0,
1589                                                  100,  25,
1590                                                  0,
1591                                                  250,
1592                                                  TRUE);
1593         break;
1594
1595       case 6:    // Digital KIAS
1596       //  fgHUDAddLabel  ( hud, 160, 150, SMALL, NOBLINK,
1597       //                 RIGHT_JUST, NULL, " Kts",      "%5.0f", get_speed );
1598         loc.left   =  160;
1599         loc.top    =  180; // Ignore
1600         loc.right  =  200; // Ignore
1601         loc.bottom =  150;
1602         HIptr = (instr_item *) new instr_label ( loc,
1603                                                  get_speed,
1604                                                  "%5.0f",
1605                                                  NULL,
1606                                                  " Kts",
1607                                                  ReadTOP,
1608                                                  RIGHT_JUST,
1609                                                  SMALL,
1610                                                  0,
1611                                                  TRUE );
1612         break;
1613
1614       case 7:    // Digital Altimeter
1615       //  fgHUDAddLabel  ( hud, 160, 135, SMALL, NOBLINK,
1616       //              RIGHT_JUST, NULL, " m",        "%5.0f", get_altitude );
1617         loc.left   =  160;
1618         loc.top    =  145; // Ignore
1619         loc.right  =  200; // Ignore
1620         loc.bottom =  135;
1621         HIptr = (instr_item *) new instr_label ( loc,
1622                                                  get_altitude,
1623                                                  "MSL  %5.0f",
1624                                                  NULL,
1625                                                  " m",
1626                                                  ReadTOP,
1627                                                  LEFT_JUST,
1628                                                  SMALL,
1629                                                  0,
1630                                                  TRUE );
1631         break;
1632
1633       case 8:    // Roll indication diagnostic
1634       // fgHUDAddLabel  ( hud, 160, 120, SMALL, NOBLINK,
1635       //                  RIGHT_JUST, NULL, " Roll",     "%5.2f", get_roll );
1636         loc.left   =  160;
1637         loc.top    =  130; // Ignore
1638         loc.right  =  200; // Ignore
1639         loc.bottom =  120;
1640         HIptr = (instr_item *) new instr_label ( loc,
1641                                                  get_roll,
1642                                                  "%5.2f",
1643                                                  " Roll",
1644                                                  " Deg",
1645                                                  ReadTOP,
1646                                                  RIGHT_JUST,
1647                                                  SMALL,
1648                                                  0,
1649                                                  TRUE );
1650         break;
1651
1652       case 9:    // Angle of attack diagnostic
1653       //  fgHUDAddLabel  ( hud, 440, 150, SMALL, NOBLINK,
1654       //                   RIGHT_JUST, NULL, " AOA",      "%5.2f", get_aoa );
1655         loc.left   =  440;
1656         loc.top    =  160; // Ignore
1657         loc.right  =  500; // Ignore
1658         loc.bottom =  150;
1659         HIptr = (instr_item *) new instr_label ( loc,
1660                                                  get_aoa,
1661                                                  "    %5.2f",
1662                                                  " AOA",
1663                                                  " Deg",
1664                                                  ReadTOP,
1665                                                  RIGHT_JUST,
1666                                                  SMALL,
1667                                                  0,
1668                                                  TRUE );
1669         break;
1670
1671       case 10:
1672       //  fgHUDAddLabel  ( hud, 440, 135, SMALL, NOBLINK,
1673       //               RIGHT_JUST, NULL, " Heading",  "%5.0f", get_heading );
1674         loc.left   =  440;
1675         loc.top    =  145; // Ignore
1676         loc.right  =  500; // Ignore
1677         loc.bottom =  135;
1678         HIptr = (instr_item *) new instr_label ( loc,
1679                                                  get_heading,
1680                                                  "%5.0f",
1681                                                  "Heading",
1682                                                  " Deg",
1683                                                  ReadTOP,
1684                                                  RIGHT_JUST,
1685                                                  SMALL,
1686                                                  0,
1687                                                  TRUE );
1688         break;
1689
1690       case 11:
1691       //  fgHUDAddLabel  ( hud, 440, 120, SMALL, NOBLINK,
1692       //              RIGHT_JUST, NULL, " Sideslip", "%5.2f", get_sideslip );
1693         loc.left   =  440;
1694         loc.top    =  130; // Ignore
1695         loc.right  =  500; // Ignore
1696         loc.bottom =  120;
1697         HIptr = (instr_item *) new instr_label ( loc,
1698                                                  get_sideslip,
1699                                                  "%5.2f",
1700                                                  "Sideslip ",
1701                                                  NULL,
1702                                                  ReadTOP,
1703                                                  RIGHT_JUST,
1704                                                  SMALL,
1705                                                  0,
1706                                                  TRUE );
1707         break;
1708
1709       case 12:
1710         loc.left   = 440;
1711         loc.top    =  90; // Ignore
1712         loc.right  = 440; // Ignore
1713         loc.bottom =  90;
1714         HIptr = (instr_item *) new instr_label( loc, get_throttleval,
1715                                                 "%.2f",
1716                                                 "Throttle ",
1717                                                 NULL,
1718                                                 ReadTOP,
1719                                                 RIGHT_JUST,
1720                                                 SMALL,
1721                                                 0,
1722                                                 TRUE );
1723         break;
1724
1725       case 13:
1726         loc.left   = 440;
1727         loc.top    =  70; // Ignore
1728         loc.right  = 500; // Ignore
1729         loc.bottom =  75;
1730         HIptr = (instr_item *) new instr_label( loc, get_elevatorval,
1731                                                 "%5.2f",
1732                                                 "Elevator",
1733                                                 NULL,
1734                                                 ReadTOP,
1735                                                 RIGHT_JUST,
1736                                                 SMALL,
1737                                                 0,
1738                                                 TRUE );
1739         break;
1740
1741       case 14:
1742         loc.left   = 440;
1743         loc.top    = 100; // Ignore
1744         loc.right  = 500; // Ignore
1745         loc.bottom =  60;
1746         HIptr = (instr_item *) new instr_label( loc, get_aileronval,
1747                                                 "%5.2f",
1748                                                 "Aileron",
1749                                                 NULL,
1750                                                 ReadTOP,
1751                                                 RIGHT_JUST,
1752                                                 SMALL,
1753                                                 0,
1754                                                 TRUE );
1755         break;
1756
1757       case 15:
1758         loc.left   = 10;
1759         loc.top    = 100; // Ignore
1760         loc.right  = 500; // Ignore
1761         loc.bottom =  10;
1762         HIptr = (instr_item *) new instr_label( loc, get_frame_rate,
1763                                                 "%.1f",
1764                                                 "Frame rate = ",
1765                                                 NULL,
1766                                                 ReadTOP,
1767                                                 RIGHT_JUST,
1768                                                 SMALL,
1769                                                 0,
1770                                                 TRUE );
1771         break;
1772
1773       case 16:
1774         loc.left   = 10;
1775         loc.top    = 100; // Ignore
1776         loc.right  = 500; // Ignore
1777         loc.bottom =  25;
1778         HIptr = (instr_item *) new instr_label( loc, get_vfc_ratio,
1779                                                 "%.2f",
1780                                                 "VFC Ratio = ",
1781                                                 NULL,
1782                                                 ReadTOP,
1783                                                 RIGHT_JUST,
1784                                                 SMALL,
1785                                                 0,
1786                                                 TRUE );
1787         break;
1788
1789       case 17:
1790         loc.left   = 10;
1791         loc.top    = 100; // Ignore
1792         loc.right  = 500; // Ignore
1793         loc.bottom =  40;
1794         HIptr = (instr_item *) new instr_label( loc, get_fov,
1795                                                 "%.1f",
1796                                                 "FOV = ",
1797                                                 NULL,
1798                                                 ReadTOP,
1799                                                 RIGHT_JUST,
1800                                                 SMALL,
1801                                                 0,
1802                                                 TRUE );
1803         break;
1804
1805       //  fgHUDAddControlSurfaces( hud, 10, 10, NULL );
1806 //        loc.left   =  250;
1807 //        loc.top    =  190;
1808 //        loc.right  =  410;
1809 //        loc.bottom =  180;
1810 //        HIptr = (instr_item *) new
1811 //        break;
1812
1813       default:;
1814       }
1815     if( HIptr ) {                   // Anything to install?
1816       HUD_deque.insert( HUD_deque.begin(), HIptr);
1817       }
1818     }
1819
1820 //  fgHUDAddControl( hud, HORIZONTAL, 50,  25, get_aileronval  ); // was 10, 10
1821 //  fgHUDAddControl( hud, VERTICAL,   150, 25, get_elevatorval ); // was 10, 10
1822 //  fgHUDAddControl( hud, HORIZONTAL, 250, 25, get_rudderval   ); // was 10, 10
1823   return 0;  // For now. Later we may use this for an error code.
1824 }
1825
1826
1827 // fgUpdateHUD
1828 //
1829 // Performs a once around the list of calls to instruments installed in
1830 // the HUD object with requests for redraw. Kinda. It will when this is
1831 // all C++.
1832 //
1833 int global_day_night_switch = DAY;
1834
1835 void fgUpdateHUD( void ) {
1836   int i;
1837   int brightness;
1838 //  int day_night_sw = current_aircraft.controls->day_night_switch;
1839   int day_night_sw = global_day_night_switch;
1840   int hud_displays = HUD_deque.size();
1841   instr_item *pHUDInstr;
1842
1843   if( !hud_displays ) {  // Trust everyone, but ALWAYS cut the cards!
1844     return;
1845     }
1846
1847   pHUDInstr = HUD_deque[0];
1848   brightness = pHUDInstr->get_brightness();
1849 //  brightness = HUD_deque.at(0)->get_brightness();
1850
1851   glMatrixMode(GL_PROJECTION);
1852   glPushMatrix();
1853
1854   glLoadIdentity();
1855   gluOrtho2D(0, 640, 0, 480);
1856   glMatrixMode(GL_MODELVIEW);
1857   glPushMatrix();
1858   glLoadIdentity();
1859
1860   glColor3f(1.0, 1.0, 1.0);
1861   glIndexi(7);
1862
1863   glDisable(GL_DEPTH_TEST);
1864   glDisable(GL_LIGHTING);
1865
1866   glLineWidth(1);
1867
1868   for( i = hud_displays; i; --i) { // Draw everything
1869 //    if( HUD_deque.at(i)->enabled()) {
1870     pHUDInstr = HUD_deque[i - 1];
1871     if( pHUDInstr->enabled()) {
1872                                    // We should to respond to a dial instead
1873                                    // or as well to the of time of day. Of
1874                                    // course, we have no dial!
1875       if( day_night_sw == DAY) {
1876         switch (brightness) {
1877           case BRT_LIGHT:
1878             glColor3f (0.1, 0.9, 0.1);
1879             break;
1880
1881           case BRT_MEDIUM:
1882             glColor3f (0.1, 0.7, 0.0);
1883             break;
1884
1885           case BRT_DARK:
1886             glColor3f (0.0, 0.5, 0.0);
1887             }
1888           }
1889         else {
1890           if( day_night_sw == NIGHT) {
1891             switch (brightness) {
1892               case BRT_LIGHT:
1893                 glColor3f (0.9, 0.1, 0.1);
1894                 break;
1895
1896               case BRT_MEDIUM:
1897                 glColor3f (0.7, 0.0, 0.1);
1898                 break;
1899
1900               case BRT_DARK:
1901               default:
1902                 glColor3f (0.5, 0.0, 0.0);
1903               }
1904             }
1905           else {     // Just in case default
1906             glColor3f (0.1, 0.9, 0.1);
1907             }
1908           }
1909     //  fgPrintf( FG_COCKPIT, FG_DEBUG, "HUD Code %d  Status %d\n",
1910     //            hud->code, hud->status );
1911       pHUDInstr->draw();
1912 //      HUD_deque.at(i)->draw(); // Responsible for broken or fixed variants.
1913                               // No broken displays honored just now.
1914       }
1915     }
1916
1917   glEnable(GL_DEPTH_TEST);
1918   glEnable(GL_LIGHTING);
1919   glMatrixMode(GL_PROJECTION);
1920   glPopMatrix();
1921   glMatrixMode(GL_MODELVIEW);
1922   glPopMatrix();
1923 }
1924
1925 /* $Log$
1926 /* Revision 1.11  1998/06/05 18:17:10  curt
1927 /* Added the declaration of memmove needed by the stl which apparently
1928 /* solaris only defines for cc compilations and not for c++ (__STDC__)
1929 /*
1930  * Revision 1.10  1998/05/17 16:58:12  curt
1931  * Added a View Frustum Culling ratio display to the hud.
1932  *
1933  * Revision 1.9  1998/05/16 13:04:14  curt
1934  * New updates from Charlie Hotchkiss.
1935  *
1936  * Revision 1.8  1998/05/13 18:27:54  curt
1937  * Added an fov to hud display.
1938  *
1939  * Revision 1.7  1998/05/11 18:13:11  curt
1940  * Complete C++ rewrite of all cockpit code by Charlie Hotchkiss.
1941  *
1942  * Revision 1.22  1998/04/18 04:14:02  curt
1943  * Moved fg_debug.c to it's own library.
1944  *
1945  * Revision 1.21  1998/04/03 21:55:28  curt
1946  * Converting to Gnu autoconf system.
1947  * Tweaks to hud.c
1948  *
1949  * Revision 1.20  1998/03/09 22:48:40  curt
1950  * Minor "formatting" tweaks.
1951  *
1952  * Revision 1.19  1998/02/23 20:18:28  curt
1953  * Incorporated Michele America's hud changes.
1954  *
1955  * Revision 1.18  1998/02/21 14:53:10  curt
1956  * Added Charlie's HUD changes.
1957  *
1958  * Revision 1.17  1998/02/20 00:16:21  curt
1959  * Thursday's tweaks.
1960  *
1961  * Revision 1.16  1998/02/19 13:05:49  curt
1962  * Incorporated some HUD tweaks from Michelle America.
1963  * Tweaked the sky's sunset/rise colors.
1964  * Other misc. tweaks.
1965  *
1966  * Revision 1.15  1998/02/16 13:38:39  curt
1967  * Integrated changes from Charlie Hotchkiss.
1968  *
1969  * Revision 1.14  1998/02/12 21:59:41  curt
1970  * Incorporated code changes contributed by Charlie Hotchkiss
1971  * <chotchkiss@namg.us.anritsu.com>
1972  *
1973  * Revision 1.12  1998/02/09 15:07:48  curt
1974  * Minor tweaks.
1975  *
1976  * Revision 1.11  1998/02/07 15:29:34  curt
1977  * Incorporated HUD changes and struct/typedef changes from Charlie Hotchkiss
1978  * <chotchkiss@namg.us.anritsu.com>
1979  *
1980  * Revision 1.10  1998/02/03 23:20:14  curt
1981  * Lots of little tweaks to fix various consistency problems discovered by
1982  * Solaris' CC.  Fixed a bug in fg_debug.c with how the fgPrintf() wrapper
1983  * passed arguments along to the real printf().  Also incorporated HUD changes
1984  * by Michele America.
1985  *
1986  * Revision 1.9  1998/01/31 00:43:04  curt
1987  * Added MetroWorks patches from Carmen Volpe.
1988  *
1989  * Revision 1.8  1998/01/27 00:47:51  curt
1990  * Incorporated Paul Bleisch's <bleisch@chromatic.com> new debug message
1991  * system and commandline/config file processing code.
1992  *
1993  * Revision 1.7  1998/01/19 18:40:20  curt
1994  * Tons of little changes to clean up the code and to remove fatal errors
1995  * when building with the c++ compiler.
1996  *
1997  * Revision 1.6  1997/12/15 23:54:34  curt
1998  * Add xgl wrappers for debugging.
1999  * Generate terrain normals on the fly.
2000  *
2001  * Revision 1.5  1997/12/10 22:37:39  curt
2002  * Prepended "fg" on the name of all global structures that didn't have it yet.
2003  * i.e. "struct WEATHER {}" became "struct fgWEATHER {}"
2004  *
2005  * Revision 1.4  1997/09/23 00:29:32  curt
2006  * Tweaks to get things to compile with gcc-win32.
2007  *
2008  * Revision 1.3  1997/09/05 14:17:26  curt
2009  * More tweaking with stars.
2010  *
2011  * Revision 1.2  1997/09/04 02:17:30  curt
2012  * Shufflin' stuff.
2013  *
2014  * Revision 1.1  1997/08/29 18:03:22  curt
2015  * Initial revision.
2016  *
2017  */