]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/hud.cxx
Merge branch 'ehofman/particle'
[flightgear.git] / src / Cockpit / hud.cxx
1 // hud.cxx -- hud defines and prototypes
2 //
3 // Written by Michele America, started September 1997.
4 //
5 // Copyright (C) 1997  Michele F. America  - micheleamerica@geocities.com
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #include <simgear/compiler.h>
24 #include <simgear/structure/exception.hxx>
25
26 #include <string>
27 #include <fstream>
28
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif
32
33 #include <math.h>
34 #include <stdlib.h>
35 #include <stdio.h>              // char related functions
36 #include <string.h>             // strcmp()
37
38 #include <simgear/constants.h>
39 #include <simgear/debug/logstream.hxx>
40 #include <simgear/misc/sg_path.hxx>
41 #include <simgear/props/props_io.hxx>
42
43 #include <osg/GLU>
44
45 #include <Aircraft/aircraft.hxx>
46 //#include <Autopilot/xmlauto.hxx>
47 #include <GUI/new_gui.hxx>           // FGFontCache
48 #include <Main/globals.hxx>
49 #include <Scenery/scenery.hxx>
50 #include <Airports/runways.hxx>
51 #include <Main/viewer.hxx>
52
53 #include "hud.hxx"
54
55
56 static HUD_Properties *HUDprop = 0;
57
58 static char units[5];
59
60 deque<SGSharedPtr<instr_item> > HUD_deque;
61
62 fgTextList HUD_TextList;
63 fgLineList HUD_LineList;
64 fgLineList HUD_StippleLineList;
65
66 fntRenderer *HUDtext = 0;
67 fntTexFont *HUD_Font = 0;
68 float HUD_TextSize = 0;
69 int HUD_style = 0;
70
71 float HUD_matrix[16];
72
73 int readHud( istream &input );
74 int readInstrument ( const SGPropertyNode * node);
75
76 static void drawHUD(osg::State*);
77 static void fgUpdateHUDVirtual(osg::State*);
78
79
80 class locRECT {
81 public:
82     RECT rect;
83
84     locRECT( UINT left, UINT top, UINT right, UINT bottom);
85     RECT get_rect(void) { return rect; }
86 };
87
88 locRECT :: locRECT( UINT left, UINT top, UINT right, UINT bottom)
89 {
90     rect.left   =  left;
91     rect.top    =  top;
92     rect.right  =  right;
93     rect.bottom =  bottom;
94
95 }
96 // #define DEBUG
97
98
99
100
101 int readInstrument(const SGPropertyNode * node)
102 {
103     static const SGPropertyNode *startup_units_node
104         = fgGetNode("/sim/startup/units");
105
106     instr_item *HIptr;
107
108     if ( !strcmp(startup_units_node->getStringValue(), "feet") ) {
109         strcpy(units, " ft");
110     } else {
111         strcpy(units, " m");
112     }
113
114     const SGPropertyNode * ladder_group = node->getNode("ladders");
115
116     if (ladder_group != 0) {
117         int nLadders = ladder_group->nChildren();
118         for (int j = 0; j < nLadders; j++) {
119             HIptr = static_cast<instr_item *>(new HudLadder(ladder_group->getChild(j)));
120             HUD_deque.insert(HUD_deque.begin(), HIptr);
121         }
122     }
123
124     const SGPropertyNode * card_group = node->getNode("cards");
125     if (card_group != 0) {
126         int nCards = card_group->nChildren();
127         for (int j = 0; j < nCards; j++) {
128             const char *type = card_group->getChild(j)->getStringValue("type", "gauge");
129
130             if (!strcmp(type, "gauge"))
131                 HIptr = static_cast<instr_item *>(new gauge_instr(card_group->getChild(j)));
132             else if (!strcmp(type, "dial") || !strcmp(type, "tape"))
133                 HIptr = static_cast<instr_item *>(new hud_card(card_group->getChild(j)));
134             else {
135                 SG_LOG(SG_INPUT, SG_WARN, "HUD: unknown 'card' type: " << type);
136                 continue;
137             }
138             HUD_deque.insert(HUD_deque.begin(), HIptr);
139         }
140     }
141
142     const SGPropertyNode * label_group = node->getNode("labels");
143     if (label_group != 0) {
144         int nLabels = label_group->nChildren();
145         for (int j = 0; j < nLabels; j++) {
146             HIptr = static_cast<instr_item *>(new instr_label(label_group->getChild(j)));
147             HUD_deque.insert(HUD_deque.begin(), HIptr);
148         }
149     }
150
151     const SGPropertyNode * tbi_group = node->getNode("tbis");
152     if (tbi_group != 0) {
153         int nTbis = tbi_group->nChildren();
154         for (int j = 0; j < nTbis; j++) {
155             HIptr = static_cast<instr_item *>(new fgTBI_instr(tbi_group->getChild(j)));
156             HUD_deque.insert(HUD_deque.begin(), HIptr);
157         }
158     }
159
160     const SGPropertyNode * rwy_group = node->getNode("runways");
161     if (rwy_group != 0) {
162         int nRwy = rwy_group->nChildren();
163         for (int j = 0; j < nRwy; j++) {
164             HIptr = static_cast<instr_item *>(new runway_instr(rwy_group->getChild(j)));
165             HUD_deque.insert(HUD_deque.begin(), HIptr);
166         }
167     }
168     return 0;
169 } //end readinstrument
170
171
172 int readHud( istream &input )
173 {
174
175     SGPropertyNode root;
176
177     try {
178         readProperties(input, &root);
179     } catch (const sg_exception &e) {
180         guiErrorMessage("Error reading HUD: ", e);
181         return 0;
182     }
183
184
185     SG_LOG(SG_INPUT, SG_DEBUG, "Read properties for  " <<
186            root.getStringValue("name"));
187
188     if (!root.getNode("depreciated"))
189         SG_LOG(SG_INPUT, SG_ALERT, "WARNING: use of depreciated old HUD");
190
191     HUD_deque.erase( HUD_deque.begin(), HUD_deque.end());
192
193
194     SG_LOG(SG_INPUT, SG_DEBUG, "Reading Hud instruments");
195
196     const SGPropertyNode * instrument_group = root.getChild("instruments");
197     int nInstruments = instrument_group->nChildren();
198
199     for (int i = 0; i < nInstruments; i++) {
200
201         const SGPropertyNode * node = instrument_group->getChild(i);
202
203         SGPath path( globals->get_fg_root() );
204         path.append(node->getStringValue("path"));
205
206         SG_LOG(SG_INPUT, SG_DEBUG, "Reading Instrument "
207                << node->getName()
208                << " from "
209                << path.str());
210
211         SGPropertyNode root2;
212         try {
213             readProperties(path.str(), &root2);
214         } catch (const sg_exception &e) {
215             guiErrorMessage("Error reading HUD instrument: ", e);
216             continue;
217         }
218         readInstrument(&root2);
219     }//for loop(i)
220
221     return 0;
222 }
223
224
225 // fgHUDInit
226 //
227 // Constructs a HUD object and then adds in instruments. At the present
228 // the instruments are hard coded into the routine. Ultimately these need
229 // to be defined by the aircraft's instrumentation records so that the
230 // display for a Piper Cub doesn't show the speed range of a North American
231 // mustange and the engine readouts of a B36!
232 //
233 int fgHUDInit( fgAIRCRAFT * /* current_aircraft */ )
234 {
235
236     HUD_style = 1;
237
238     SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
239
240     string hud_path =
241         fgGetString("/sim/hud/path", "Huds/Default/default.xml");
242     SGPath path(globals->get_fg_root());
243     path.append(hud_path);
244
245     ifstream input(path.c_str());
246     if (!input.good()) {
247         SG_LOG(SG_INPUT, SG_ALERT,
248                "Cannot read Hud configuration from " << path.str());
249     } else {
250         readHud(input);
251         input.close();
252     }
253
254     if ( HUDtext ) {
255         // this chunk of code is not necessarily thread safe if the
256         // compiler optimizer reorders these statements.  Note that
257         // "delete ptr" does not set "ptr = NULL".  We have to do that
258         // ourselves.
259         fntRenderer *tmp = HUDtext;
260         HUDtext = NULL;
261         delete tmp;
262     }
263
264     FGFontCache *fc = globals->get_fontcache();
265     const char* fileName = fgGetString("/sim/hud/font/name", "Helvetica.txf");
266     HUD_Font = fc->getTexFont(fileName);
267     if (!HUD_Font)
268         throw sg_io_exception("/sim/hud/font/name is not a texture font",
269                               sg_location(fileName));
270
271     HUD_TextSize = fgGetFloat("/sim/hud/font/size", 10);
272
273     HUDtext = new fntRenderer();
274     HUDtext->setFont(HUD_Font);
275     HUDtext->setPointSize(HUD_TextSize);
276     HUD_TextList.setFont( HUDtext );
277
278     if (!HUDprop)
279         HUDprop = new HUD_Properties;
280     return 0;  // For now. Later we may use this for an error code.
281
282 }
283
284
285 int fgHUDInit2( fgAIRCRAFT * /* current_aircraft */ )
286 {
287
288     HUD_style = 2;
289
290     SG_LOG( SG_COCKPIT, SG_INFO, "Initializing current aircraft HUD" );
291
292     SGPath path(globals->get_fg_root());
293     path.append("Huds/Minimal/default.xml");
294
295
296     ifstream input(path.c_str());
297     if (!input.good()) {
298         SG_LOG(SG_INPUT, SG_ALERT,
299                "Cannot read Hud configuration from " << path.str());
300     } else {
301         readHud(input);
302         input.close();
303     }
304
305     if (!HUDprop)
306         HUDprop = new HUD_Properties;
307     return 0;  // For now. Later we may use this for an error code.
308
309 }
310 //$$$ End - added, Neetha, 28 Nov 2k
311
312
313 // fgUpdateHUD
314 //
315 // Performs a once around the list of calls to instruments installed in
316 // the HUD object with requests for redraw. Kinda. It will when this is
317 // all C++.
318 //
319 void fgUpdateHUD( osg::State* state ) {
320
321     static const SGPropertyNode *enable3d_node = fgGetNode("/sim/hud/enable3d");
322     if ( HUD_style == 1 && enable3d_node->getBoolValue() ) {
323         fgUpdateHUDVirtual(state);
324         return;
325     }
326
327     static const float normal_aspect = float(640) / float(480);
328     // note: aspect_ratio is Y/X
329     float current_aspect = 1.0f/globals->get_current_view()->get_aspect_ratio();
330     if ( current_aspect > normal_aspect ) {
331         float aspect_adjust = current_aspect / normal_aspect;
332         float adjust = 320.0f*aspect_adjust - 320.0f;
333         fgUpdateHUD( state, -adjust, 0.0f, 640.0f+adjust, 480.0f );
334     } else {
335         float aspect_adjust = normal_aspect / current_aspect;
336         float adjust = 240.0f*aspect_adjust - 240.0f;
337         fgUpdateHUD( state, 0.0f, -adjust, 640.0f, 480.0f+adjust );
338     }
339 }
340
341 void fgUpdateHUDVirtual(osg::State* state)
342 {
343     FGViewer* view = globals->get_current_view();
344
345     // Standard fgfs projection, with essentially meaningless clip
346     // planes (we'll map the whole HUD plane to z=-1)
347     glMatrixMode(GL_PROJECTION);
348     glPushMatrix();
349     glLoadIdentity();
350     gluPerspective(view->get_v_fov(), 1/view->get_aspect_ratio(), 0.1, 10);
351
352     glMatrixMode(GL_MODELVIEW);
353     glPushMatrix();
354     glLoadIdentity();
355
356     // Standard fgfs view direction computation
357     float lookat[3];
358     lookat[0] = -sin(SG_DEGREES_TO_RADIANS * view->getHeadingOffset_deg());
359     lookat[1] = tan(SG_DEGREES_TO_RADIANS * view->getPitchOffset_deg());
360     lookat[2] = -cos(SG_DEGREES_TO_RADIANS * view->getHeadingOffset_deg());
361     if (fabs(lookat[1]) > 9999)
362         lookat[1] = 9999; // FPU sanity
363     gluLookAt(0, 0, 0, lookat[0], lookat[1], lookat[2], 0, 1, 0);
364
365     // Map the -1:1 square to a 55.0x41.25 degree wide patch at z=1.
366     // This is the default fgfs field of view, which the HUD files are
367     // written to assume.
368     float dx = 0.52056705; // tan(55/2)
369     float dy = dx * 0.75;  // assumes 4:3 aspect ratio
370     float m[16];
371     m[0] = dx; m[4] =  0; m[ 8] = 0; m[12] = 0;
372     m[1] =  0; m[5] = dy; m[ 9] = 0; m[13] = 0;
373     m[2] =  0; m[6] =  0; m[10] = 1; m[14] = 0;
374     m[3] =  0; m[7] =  0; m[11] = 0; m[15] = 1;
375     glMultMatrixf(m);
376
377     // Convert the 640x480 "HUD standard" coordinate space to a square
378     // about the origin in the range [-1:1] at depth of -1
379     glScalef(1./320, 1./240, 1);
380     glTranslatef(-320, -240, -1);
381
382     // Do the deed
383     drawHUD(state);
384
385     // Clean up our mess
386     glMatrixMode(GL_PROJECTION);
387     glPopMatrix();
388     glMatrixMode(GL_MODELVIEW);
389     glPopMatrix();
390 }
391
392
393 void fgUpdateHUD( osg::State* state, GLfloat x_start, GLfloat y_start,
394                   GLfloat x_end, GLfloat y_end )
395 {
396     glMatrixMode(GL_PROJECTION);
397     glPushMatrix();
398     glLoadIdentity();
399     gluOrtho2D(x_start, x_end, y_start, y_end);
400
401     glMatrixMode(GL_MODELVIEW);
402     glPushMatrix();
403     glLoadIdentity();
404
405     drawHUD(state);
406
407     glMatrixMode(GL_PROJECTION);
408     glPopMatrix();
409     glMatrixMode(GL_MODELVIEW);
410     glPopMatrix();
411 }
412
413
414 void drawHUD(osg::State* state)
415 {
416     if ( !HUD_deque.size() ) // Trust everyone, but ALWAYS cut the cards!
417         return;
418
419     HUD_TextList.erase();
420     HUD_LineList.erase();
421     // HUD_StippleLineList.erase();
422
423     glDisable(GL_DEPTH_TEST);
424     glDisable(GL_LIGHTING);
425
426     static const SGPropertyNode *heading_enabled
427         = fgGetNode("/autopilot/locks/heading", true);
428     static const SGPropertyNode *altitude_enabled
429         = fgGetNode("/autopilot/locks/altitude", true);
430
431     static char hud_hdg_text[256];
432     static char hud_gps_text0[256];
433     static char hud_gps_text1[256];
434     static char hud_gps_text2[256];
435     static char hud_alt_text[256];
436
437     glEnable(GL_BLEND);
438     if (HUDprop->isTransparent())
439         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
440     else
441         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
442
443     if (HUDprop->isAntialiased()) {
444         glEnable(GL_LINE_SMOOTH);
445         glAlphaFunc(GL_GREATER, HUDprop->alphaClamp());
446         glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
447         //glLineWidth(1.5);
448     } else {
449         //glLineWidth(1.0);
450     }
451
452     HUDprop->setColor();
453     for_each(HUD_deque.begin(), HUD_deque.end(), HUDdraw());
454
455     //HUD_TextList.add( fgText(40, 10, get_formated_gmt_time(), 0) );
456
457
458     int apY = 480 - 80;
459
460
461     if (strcmp( heading_enabled->getStringValue(), "dg-heading-hold") == 0 ) {
462         snprintf( hud_hdg_text, 256, "hdg = %.1f\n",
463                   fgGetDouble("/autopilot/settings/heading-bug-deg") );
464         HUD_TextList.add( fgText( 40, apY, hud_hdg_text ) );
465         apY -= 15;
466     } else if ( strcmp(heading_enabled->getStringValue(), "true-heading-hold") == 0 ) {
467         snprintf( hud_hdg_text, 256, "hdg = %.1f\n",
468                   fgGetDouble("/autopilot/settings/true-heading-deg") );
469         HUD_TextList.add( fgText( 40, apY, hud_hdg_text ) );
470         apY -= 15;
471     }
472   
473   // GPS current waypoint information
474     SGPropertyNode_ptr gps = fgGetNode("/instrumentation/gps", true);
475     SGPropertyNode_ptr curWp = gps->getChild("wp")->getChild("wp",1);
476     
477     if ((gps->getDoubleValue("raim") > 0.5) && curWp) {
478       // GPS is receiving a valid signal
479       snprintf(hud_gps_text0, 256, "WPT:%5s BRG:%03.0f %5.1fnm",
480         curWp->getStringValue("ID"),
481         curWp->getDoubleValue("bearing-mag-deg"),
482         curWp->getDoubleValue("distance-nm"));
483       HUD_TextList.add( fgText( 40, apY, hud_gps_text0 ) );
484       apY -= 15;
485        
486        // curWp->getStringValue("TTW")
487       snprintf(hud_gps_text2, 256, "ETA %s", curWp->getStringValue("TTW"));
488       HUD_TextList.add( fgText( 40, apY, hud_gps_text2 ) );
489       apY -= 15;
490       
491       double courseError = curWp->getDoubleValue("course-error-nm");
492       if (fabs(courseError) >= 0.01) {
493         // generate an arrow indicatinng if the pilot should turn left or right
494         char dir = (courseError < 0.0) ? '<' : '>';
495         snprintf(hud_gps_text1, 256, "GPS TRK:%03.0f XTRK:%c%4.2fnm",
496           gps->getDoubleValue("indicated-track-magnetic-deg"), dir, fabs(courseError));
497       } else { // on course, don't bother showing the XTRK error
498         snprintf(hud_gps_text1, 256, "GPS TRK:%03.0f",
499           gps->getDoubleValue("indicated-track-magnetic-deg"));
500       }
501       
502       HUD_TextList.add( fgText( 40, apY, hud_gps_text1) );
503       apY -= 15;
504     } // of valid GPS output
505     
506   ////////////////////
507
508     if ( strcmp( altitude_enabled->getStringValue(), "altitude-hold" ) == 0 ) {
509         snprintf( hud_alt_text, 256, "alt = %.0f\n",
510                   fgGetDouble("/autopilot/settings/target-altitude-ft") );
511         HUD_TextList.add( fgText( 40, apY, hud_alt_text ) );
512         apY -= 15;
513     } else if ( strcmp( altitude_enabled->getStringValue(), "agl-hold" ) == 0 ){
514         snprintf( hud_alt_text, 256, "agl = %.0f\n",
515                   fgGetDouble("/autopilot/settings/target-agl-ft") );
516         HUD_TextList.add( fgText( 40, apY, hud_alt_text ) );
517         apY -= 15;
518     }
519
520     HUD_TextList.draw();
521     HUD_LineList.draw();
522
523     // glEnable(GL_LINE_STIPPLE);
524     // glLineStipple( 1, 0x00FF );
525     // HUD_StippleLineList.draw();
526     // glDisable(GL_LINE_STIPPLE);
527
528     if (HUDprop->isAntialiased()) {
529         glDisable(GL_ALPHA_TEST);
530         glDisable(GL_LINE_SMOOTH);
531         //glLineWidth(1.0);
532     }
533
534     if (HUDprop->isTransparent())
535         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
536
537     glEnable(GL_DEPTH_TEST);
538     glEnable(GL_LIGHTING);
539 }
540
541
542 void fgTextList::draw()
543 {
544     if (!Font)
545         return;
546
547     vector<fgText>::iterator curString = List.begin();
548     vector<fgText>::iterator lastString = List.end();
549
550     glPushAttrib(GL_COLOR_BUFFER_BIT);
551     glEnable(GL_TEXTURE_2D);
552     glEnable(GL_BLEND);
553     if (HUDprop->isTransparent())
554         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
555     else
556         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
557
558     if (HUDprop->isAntialiased()) {
559         glEnable(GL_ALPHA_TEST);
560         glAlphaFunc(GL_GREATER, HUDprop->alphaClamp());
561     }
562
563     Font->begin();
564     for (; curString != lastString; curString++)
565         curString->Draw(Font);
566     Font->end();
567
568     glDisable(GL_TEXTURE_2D);
569     glPopAttrib();
570 }
571
572
573 // HUD property listener class
574 //
575 HUD_Properties::HUD_Properties() :
576     _current(fgGetNode("/sim/hud/current-color", true)),
577     _visibility(fgGetNode("/sim/hud/visibility", true)),
578     _antialiasing(fgGetNode("/sim/hud/color/antialiased", true)),
579     _transparency(fgGetNode("/sim/hud/color/transparent", true)),
580     _red(fgGetNode("/sim/hud/color/red", true)),
581     _green(fgGetNode("/sim/hud/color/green", true)),
582     _blue(fgGetNode("/sim/hud/color/blue", true)),
583     _alpha(fgGetNode("/sim/hud/color/alpha", true)),
584     _alpha_clamp(fgGetNode("/sim/hud/color/alpha-clamp", true)),
585     _brightness(fgGetNode("/sim/hud/color/brightness", true)),
586     _visible(false),
587     _antialiased(false),
588     _transparent(false),
589     _a(0.67),
590     _cl(0.01)
591 {
592     _visibility->addChangeListener(this);
593     _antialiasing->addChangeListener(this);
594     _transparency->addChangeListener(this);
595     _red->addChangeListener(this);
596     _green->addChangeListener(this);
597     _blue->addChangeListener(this);
598     _alpha->addChangeListener(this);
599     _alpha_clamp->addChangeListener(this);
600     _brightness->addChangeListener(this);
601     _current->addChangeListener(this, true);
602 }
603
604
605 void HUD_Properties::valueChanged(SGPropertyNode *node)
606 {
607     if (!strcmp(node->getName(), "current-color")) {
608         int i = node->getIntValue();
609         if (i < 0)
610             i = 0;
611         SGPropertyNode *n = fgGetNode("/sim/hud/palette", true);
612         if ((n = n->getChild("color", i, false))) {
613             if (n->hasValue("red"))
614                 _red->setFloatValue(n->getFloatValue("red", 1.0));
615             if (n->hasValue("green"))
616                 _green->setFloatValue(n->getFloatValue("green", 1.0));
617             if (n->hasValue("blue"))
618                 _blue->setFloatValue(n->getFloatValue("blue", 1.0));
619             if (n->hasValue("alpha"))
620                 _alpha->setFloatValue(n->getFloatValue("alpha", 0.67));
621             if (n->hasValue("alpha-clamp"))
622                 _alpha_clamp->setFloatValue(n->getFloatValue("alpha-clamp", 0.01));
623             if (n->hasValue("brightness"))
624                 _brightness->setFloatValue(n->getFloatValue("brightness", 0.75));
625             if (n->hasValue("antialiased"))
626                 _antialiasing->setBoolValue(n->getBoolValue("antialiased", false));
627             if (n->hasValue("transparent"))
628                 _transparency->setBoolValue(n->getBoolValue("transparent", false));
629         }
630     }
631     _visible = _visibility->getBoolValue();
632     _transparent = _transparency->getBoolValue();
633     _antialiased = _antialiasing->getBoolValue();
634     float brt = _brightness->getFloatValue();
635     _r = clamp(brt * _red->getFloatValue());
636     _g = clamp(brt * _green->getFloatValue());
637     _b = clamp(brt * _blue->getFloatValue());
638     _a = clamp(_alpha->getFloatValue());
639     _cl = clamp(_alpha_clamp->getFloatValue());
640 }
641
642
643 void HUD_Properties::setColor() const
644 {
645     if (_antialiased)
646         glColor4f(_r, _g, _b, _a);
647     else
648         glColor3f(_r, _g, _b);
649 }
650
651