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