LCOV - code coverage report
Current view: top level - Core - HeadUpDisplay.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 203 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : HeadUpDisplay.m
       4             : 
       5             : Oolite
       6             : Copyright (C) 2004-2013 Giles C Williams and contributors
       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
      10             : as published by the Free Software Foundation; either version 2
      11             : of the License, or (at your option) any later version.
      12             : 
      13             : This program is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU 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., 51 Franklin Street, Fifth Floor, Boston,
      21             : MA 02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : #import "OOCocoa.h"
      26             : #import "HeadUpDisplay.h"
      27             : #import "GameController.h"
      28             : #import "ResourceManager.h"
      29             : #import "PlayerEntity.h"
      30             : #import "OOSunEntity.h"
      31             : #import "OOPlanetEntity.h"
      32             : #import "StationEntity.h"
      33             : #import "OOVisualEffectEntity.h"
      34             : #import "OOQuiriumCascadeEntity.h"
      35             : #import "OOWaypointEntity.h"
      36             : #import "Universe.h"
      37             : #import "OOTrumble.h"
      38             : #import "OOColor.h"
      39             : #import "GuiDisplayGen.h"
      40             : #import "OOTexture.h"
      41             : #import "OOTextureSprite.h"
      42             : #import "OOPolygonSprite.h"
      43             : #import "OOCollectionExtractors.h"
      44             : #import "OOEncodingConverter.h"
      45             : #import "OOCrosshairs.h"
      46             : #import "OOConstToString.h"
      47             : #import "OOStringParsing.h"
      48             : #import "OOJoystickManager.h"
      49             : #import "OOJavaScriptEngine.h"
      50             : #import "OOStringExpander.h"
      51             : 
      52             : 
      53           0 : #define ONE_SIXTEENTH                           0.0625
      54           0 : #define ONE_SIXTYFOURTH                         0.015625
      55           0 : #define DEFAULT_OVERALL_ALPHA           0.75
      56           0 : #define GLYPH_SCALE_FACTOR                      0.13            // 0.13 is an inherited magic number
      57           0 : #define IDENTIFY_SCANNER_LOLLIPOPS      (       0       && OOLITE_DEBUG)
      58             : 
      59             : 
      60           0 : #define NOT_DEFINED                                     INFINITY
      61           0 : #define WIDGET_INFO                                     0
      62           0 : #define WIDGET_CACHE                            1
      63           0 : #define WIDGET_SELECTOR                         2
      64           0 : #define WIDGET_SELECTOR_NAME            3
      65             : 
      66             : /* Convenience macros to make set-colour-or-default quicker. 'info' must be the NSDictionary and 'alpha' must be the overall alpha or these won't work */
      67           0 : #define DO_SET_COLOR(t,d)               SetGLColourFromInfo(info,t,d,alpha)
      68           0 : #define SET_COLOR(d)                    DO_SET_COLOR(COLOR_KEY,d)
      69           0 : #define SET_COLOR_LOW(d)                DO_SET_COLOR(COLOR_KEY_LOW,d)
      70           0 : #define SET_COLOR_MEDIUM(d)             DO_SET_COLOR(COLOR_KEY_MEDIUM,d)
      71           0 : #define SET_COLOR_HIGH(d)               DO_SET_COLOR(COLOR_KEY_HIGH,d)
      72           0 : #define SET_COLOR_CRITICAL(d)   DO_SET_COLOR(COLOR_KEY_CRITICAL,d)
      73           0 : #define SET_COLOR_SURROUND(d)   DO_SET_COLOR(COLOR_KEY_SURROUND,d)
      74             : 
      75           0 : struct CachedInfo
      76             : {
      77           0 :         float x, y, x0, y0;
      78           0 :         float width, height, alpha;
      79             : };
      80             : 
      81           0 : static NSArray *sCurrentDrawItem;
      82             : 
      83           0 : OOINLINE float useDefined(float val, float validVal) 
      84             : {
      85             :         return (val == NOT_DEFINED) ? validVal : val;
      86             : }
      87             : 
      88             : 
      89           0 : static void DrawSpecialOval(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat step, GLfloat* color4v);
      90             : 
      91             : static void SetGLColourFromInfo(NSDictionary *info, NSString *key, const GLfloat defaultColor[4], GLfloat alpha);
      92             : static void GetRGBAArrayFromInfo(NSDictionary *info, GLfloat ioColor[4]);
      93             : 
      94           0 : static void hudDrawIndicatorAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount);
      95           0 : static void hudDrawMarkerAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount);
      96           0 : static void hudDrawBarAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount);
      97           0 : static void hudDrawSurroundAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz);
      98           0 : static void hudDrawStatusIconAt(int x, int y, int z, NSSize siz);
      99           0 : static void hudDrawReticleOnTarget(Entity* target, PlayerEntity* player1, GLfloat z1,
     100             :                                 GLfloat alpha, BOOL reticleTargetSensitive, NSMutableDictionary *propertiesReticleTargetSensitive,
     101             :                                 BOOL colourFromScannerColour, BOOL showText, NSDictionary *info, NSMutableArray *reticleColors);
     102           0 : static void hudDrawWaypoint(OOWaypointEntity *waypoint, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL selected, GLfloat scale);
     103           0 : static void hudRotateViewpointForVirtualDepth(PlayerEntity * player1, Vector p1);
     104           0 : static void drawScannerGrid(GLfloat x, GLfloat y, GLfloat z, NSSize siz, int v_dir, GLfloat thickness, GLfloat zoom, BOOL nonlinear, BOOL minimalistic);
     105           0 : static GLfloat nonlinearScannerFunc(GLfloat distance, GLfloat zoom, GLfloat scale);
     106           0 : static void GLDrawNonlinearCascadeWeapon( GLfloat x, GLfloat y, GLfloat z, NSSize siz, Vector centre, GLfloat radius, GLfloat zoom, GLfloat alpha );
     107             : 
     108           0 : static OOTexture                        *sFontTexture = nil;
     109           0 : static OOEncodingConverter      *sEncodingCoverter = nil;
     110             : 
     111             : 
     112           0 : enum
     113             : {
     114             :         kFontTextureOptions = kOOTextureMinFilterMipMap | kOOTextureMagFilterLinear | kOOTextureNoShrink | kOOTextureAlphaMask
     115             : };
     116             : 
     117             : 
     118             : @interface HeadUpDisplay (Private)
     119             : 
     120           0 : - (void) drawCrosshairs;
     121           0 : - (void) drawLegends;
     122           0 : - (void) drawDials;
     123           0 : - (void) drawMFDs;
     124             : 
     125           0 : - (void) drawLegend:(NSDictionary *)info;
     126           0 : - (void) drawHUDItem:(NSDictionary *)info;
     127             : 
     128           0 : - (void) drawScanner:(NSDictionary *)info;
     129           0 : - (void) drawScannerZoomIndicator:(NSDictionary *)info;
     130             : 
     131           0 : - (void) drawCompass:(NSDictionary *)info;
     132           0 : - (void) drawCompassPlanetBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
     133           0 : - (void) drawCompassStationBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
     134           0 : - (void) drawCompassSunBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
     135           0 : - (void) drawCompassTargetBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
     136           0 : - (void) drawCompassBeaconBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
     137             : 
     138           0 : - (void) drawAegis:(NSDictionary *)info;
     139           0 : - (void) drawSpeedBar:(NSDictionary *)info;
     140           0 : - (void) drawRollBar:(NSDictionary *)info;
     141           0 : - (void) drawPitchBar:(NSDictionary *)info;
     142           0 : - (void) drawYawBar:(NSDictionary *)info;
     143           0 : - (void) drawEnergyGauge:(NSDictionary *)info;
     144           0 : - (void) drawForwardShieldBar:(NSDictionary *)info;
     145           0 : - (void) drawAftShieldBar:(NSDictionary *)info;
     146           0 : - (void) drawFuelBar:(NSDictionary *)info;
     147           0 : - (void) drawWitchspaceDestination:(NSDictionary *)info;
     148           0 : - (void) drawCabinTempBar:(NSDictionary *)info;
     149           0 : - (void) drawWeaponTempBar:(NSDictionary *)info;
     150           0 : - (void) drawAltitudeBar:(NSDictionary *)info;
     151           0 : - (void) drawMissileDisplay:(NSDictionary *)info;
     152           0 : - (void) drawTargetReticle:(NSDictionary *)info;
     153           0 : - (void) drawSecondaryTargetReticle:(NSDictionary *)info;
     154           0 : - (void) drawWaypoints:(NSDictionary *)info;
     155           0 : - (void) drawStatusLight:(NSDictionary *)info;
     156           0 : - (void) drawDirectionCue:(NSDictionary *)info;
     157           0 : - (void) drawClock:(NSDictionary *)info;
     158           0 : - (void) drawPrimedEquipmentText:(NSDictionary *)info;
     159           0 : - (void) drawASCTarget:(NSDictionary *)info;
     160           0 : - (void) drawWeaponsOfflineText:(NSDictionary *)info;
     161           0 : - (void) drawMultiFunctionDisplay:(NSDictionary *)info withText:(NSString *)text asIndex:(NSUInteger)index;
     162           0 : - (void) drawFPSInfoCounter:(NSDictionary *)info;
     163           0 : - (void) drawScoopStatus:(NSDictionary *)info;
     164           0 : - (void) drawStickSensitivityIndicator:(NSDictionary *)info;
     165           0 : - (void) drawCustomBar:(NSDictionary *)info;
     166           0 : - (void) drawCustomText:(NSDictionary *)info;
     167           0 : - (void) drawCustomIndicator:(NSDictionary *)info;
     168           0 : - (void) drawCustomLight:(NSDictionary *)info;
     169           0 : - (void) drawCustomImage:(NSDictionary *)info;
     170             : 
     171           0 : - (void) drawSurroundInternal:(NSDictionary *)info color:(const GLfloat[4])color;
     172           0 : - (void) drawSurround:(NSDictionary *)info;
     173           0 : - (void) drawGreenSurround:(NSDictionary *)info;
     174           0 : - (void) drawYellowSurround:(NSDictionary *)info;
     175             : 
     176           0 : - (void) drawTrumbles:(NSDictionary *)info;
     177             : 
     178           0 : - (NSArray *) crosshairDefinitionForWeaponType:(OOWeaponType)weapon;
     179             : 
     180           0 : - (BOOL) checkPlayerInFlight;
     181           0 : - (BOOL) checkPlayerInSystemFlight;
     182             : 
     183           0 : - (void) resetGui:(GuiDisplayGen*)gui withInfo:(NSDictionary *)gui_info;
     184           0 : - (void) resetGuiPosition:(GuiDisplayGen*)gui withInfo:(NSDictionary *)gui_info;
     185             : 
     186             : 
     187             : @end
     188             : 
     189             : 
     190             : @implementation HeadUpDisplay
     191             : 
     192           0 : static const GLfloat red_color[4] =                     {1.0, 0.0, 0.0, 1.0};
     193           0 : static const GLfloat redplus_color[4] =         {1.0, 0.0, 0.5, 1.0};
     194           0 : static const GLfloat yellow_color[4] =          {1.0, 1.0, 0.0, 1.0};
     195           0 : static const GLfloat green_color[4] =           {0.0, 1.0, 0.0, 1.0};
     196           0 : static const GLfloat darkgreen_color[4] =       {0.0, 0.75, 0.0, 1.0};
     197           0 : static const GLfloat blue_color[4] =            {0.0, 0.0, 1.0, 1.0};
     198           0 : static const GLfloat black_color[4] =           {0.0, 0.0, 0.0, 1.0};
     199           0 : static const GLfloat lightgray_color[4] =       {0.25, 0.25, 0.25, 1.0};
     200             : 
     201           0 : static float    sGlyphWidths[256];
     202           0 : static float    sF6KernGovt;
     203           0 : static float    sF6KernTL;
     204           0 : static BOOL             _compassUpdated;
     205             : 
     206             : 
     207           0 : static GLfloat drawCharacterQuad(uint8_t chr, GLfloat x, GLfloat y, GLfloat z, NSSize siz);
     208             : 
     209           0 : static void InitTextEngine(void);
     210             : 
     211           0 : static void prefetchData(NSDictionary *info, struct CachedInfo *data);
     212             : 
     213             : 
     214           0 : OOINLINE void GLColorWithOverallAlpha(const GLfloat *color, GLfloat alpha)
     215             : {
     216             :         // NO OOGL(), this is called within immediate mode blocks.
     217             :         glColor4f(color[0], color[1], color[2], color[3] * alpha);
     218             : }
     219             : 
     220             : 
     221             : - (id) initWithDictionary:(NSDictionary *)hudinfo
     222             : {
     223             :         return [self initWithDictionary:hudinfo inFile:nil];
     224             : }
     225             : 
     226             : 
     227             : - (id) initWithDictionary:(NSDictionary *)hudinfo inFile:(NSString *)hudFileName
     228             : {
     229             :         unsigned                i;
     230             :         BOOL                    isCompassToBeDrawn = NO;
     231             :         BOOL                    areTrumblesToBeDrawn = NO;
     232             :         
     233             :         self = [super init];
     234             :         
     235             :         lineWidth = 1.0;
     236             :         
     237             :         if (sFontTexture == nil)  InitTextEngine();
     238             :         
     239             :         deferredHudName = nil;  // if not nil, it means that we have a deferred HUD which is to be drawn at first available opportunity
     240             :         hudName = [hudFileName copy];
     241             :         
     242             :         // init arrays
     243             :         dialArray = [[NSMutableArray alloc] initWithCapacity:16];   // alloc retains
     244             :         legendArray = [[NSMutableArray alloc] initWithCapacity:16]; // alloc retains
     245             :         mfdArray = [[NSMutableArray alloc] initWithCapacity:8]; // alloc retains
     246             :         
     247             :         _reticleColors = nil;
     248             :         
     249             :         // populate arrays
     250             :         NSArray *dials = [hudinfo oo_arrayForKey:DIALS_KEY];
     251             :         for (i = 0; i < [dials count]; i++)
     252             :         {
     253             :                 NSDictionary    *dial_info = [dials oo_dictionaryAtIndex:i];
     254             :                 if (!areTrumblesToBeDrawn && [[dial_info oo_stringForKey:SELECTOR_KEY] isEqualToString:@"drawTrumbles:"])  areTrumblesToBeDrawn = YES;
     255             :                 if (!isCompassToBeDrawn && [[dial_info oo_stringForKey:SELECTOR_KEY] isEqualToString:@"drawCompass:"])  isCompassToBeDrawn = YES;
     256             :                 if ([[dial_info oo_stringForKey:SELECTOR_KEY] isEqualToString:@"drawTargetReticle:"])
     257             :                 {
     258             :                         _reticleColors = [[NSMutableArray arrayWithObjects:[OOColor colorWithDescription:[dial_info oo_objectForKey:@"target_rgba" defaultValue:@"greenColor"]],
     259             :                                                                                                 [OOColor colorWithDescription:[dial_info oo_objectForKey:@"target_sensitive_rgba" defaultValue:@"redColor"]],
     260             :                                                                                                 [OOColor colorWithDescription:[dial_info oo_objectForKey:@"wormhole_rgba" defaultValue:@"cyanColor"]],
     261             :                                                                                                 nil] retain];
     262             :                 }
     263             :                 [self addDial:dial_info];
     264             :         }
     265             :         
     266             :         // reticle colors should be set at this point, but just be safe in case they are not
     267             :         if (!_reticleColors)
     268             :         {
     269             :                 _reticleColors = [[NSMutableArray arrayWithObjects:[OOColor greenColor], [OOColor redColor], [OOColor cyanColor], nil] retain];
     270             :         }
     271             :         
     272             :         if (!areTrumblesToBeDrawn)      // naughty - a hud with no built-in drawTrumbles: - one must be added!
     273             :         {
     274             :                 NSDictionary    *trumble_dial_info = [NSDictionary dictionaryWithObjectsAndKeys: @"drawTrumbles:", SELECTOR_KEY, nil];
     275             :                 [self addDial:trumble_dial_info];
     276             :         }
     277             :         
     278             :         _compassActive = isCompassToBeDrawn;
     279             :         
     280             :         _lastWeaponType = nil;
     281             : 
     282             :         NSArray *legends = [hudinfo oo_arrayForKey:LEGENDS_KEY];
     283             :         for (i = 0; i < [legends count]; i++)
     284             :         {
     285             :                 [self addLegend:[legends oo_dictionaryAtIndex:i]];
     286             :         }
     287             : 
     288             :         NSArray *mfds = [hudinfo oo_arrayForKey:MFDS_KEY];
     289             :         for (i = 0; i < [mfds count]; i++)
     290             :         {
     291             :                 [self addMFD:[mfds oo_dictionaryAtIndex:i]];
     292             :         }
     293             : 
     294             :         
     295             :         hudHidden = NO;
     296             :         
     297             :         _hiddenSelectors = [[NSMutableSet alloc] initWithCapacity:16];
     298             : 
     299             :         hudUpdating = NO;
     300             :         
     301             :         overallAlpha = [hudinfo oo_floatForKey:@"overall_alpha" defaultValue:DEFAULT_OVERALL_ALPHA];
     302             :         
     303             :         reticleTargetSensitive = [hudinfo oo_boolForKey:@"reticle_target_sensitive" defaultValue:NO];
     304             :         propertiesReticleTargetSensitive = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
     305             :                                                                                 [NSNumber numberWithBool:YES], @"isAccurate", 
     306             :                                                                                 [NSNumber numberWithDouble:[UNIVERSE getTime]], @"timeLastAccuracyProbabilityCalculation", 
     307             :                                                                                 nil];
     308             :         
     309             :         cloakIndicatorOnStatusLight = [hudinfo oo_boolForKey:@"cloak_indicator_on_status_light" defaultValue:YES];
     310             : 
     311             :         allowBigGui = [hudinfo oo_boolForKey:@"allow_big_gui" defaultValue:NO];
     312             :         
     313             :         last_transmitter = NO_TARGET;
     314             :         
     315             :         [crosshairDefinition release];
     316             :         
     317             :         NSString *crossfile = [[hudinfo oo_stringForKey:@"crosshair_file"] retain];
     318             :         if (crossfile == nil)
     319             :         {
     320             :                 _crosshairOverrides = [[hudinfo oo_dictionaryForKey:@"crosshairs"] retain];
     321             :                 crosshairDefinition = nil;
     322             :         }
     323             :         else
     324             :         {
     325             :                 [self setCrosshairDefinition:crossfile];
     326             :         }
     327             :         [crossfile release];
     328             :         
     329             :         id crosshairColor = [hudinfo oo_objectForKey:@"crosshair_color" defaultValue:@"greenColor"];
     330             :         _crosshairColor = [[OOColor colorWithDescription:crosshairColor] retain];
     331             :         _crosshairScale = [hudinfo oo_floatForKey:@"crosshair_scale" defaultValue:32.0f];
     332             :         _crosshairWidth = [hudinfo oo_floatForKey:@"crosshair_width" defaultValue:1.5f];
     333             :         
     334             :         minimalistic_scanner = [hudinfo oo_boolForKey:@"scanner_minimalistic" defaultValue:NO];
     335             :         
     336             :         nonlinear_scanner = [hudinfo oo_boolForKey:@"scanner_non_linear" defaultValue:NO];
     337             :         scanner_ultra_zoom = [hudinfo oo_boolForKey:@"scanner_ultra_zoom" defaultValue:NO];
     338             :         
     339             :         return self;
     340             : }
     341             : 
     342             : 
     343           0 : - (void) dealloc
     344             : {
     345             :         DESTROY(legendArray);
     346             :         DESTROY(dialArray);     
     347             :         DESTROY(mfdArray);
     348             :         DESTROY(hudName);
     349             :         DESTROY(deferredHudName);
     350             :         DESTROY(propertiesReticleTargetSensitive);
     351             :         DESTROY(_crosshairOverrides);
     352             :         DESTROY(_crosshairColor);
     353             :         DESTROY(_reticleColors);
     354             :         DESTROY(crosshairDefinition);
     355             :         DESTROY(_hiddenSelectors);
     356             : 
     357             :         [super dealloc];
     358             : }
     359             : 
     360             : //------------------------------------------------------------------------------------//
     361             : 
     362             : 
     363           0 : - (void) resetGui:(GuiDisplayGen*)gui withInfo:(NSDictionary *)gui_info
     364             : {
     365             :         [self resetGuiPosition:gui withInfo:gui_info];
     366             :         
     367             :         NSSize          siz =   [gui    size];
     368             :         int                     rht =   [gui    rowHeight];
     369             :         NSString*       title = [gui    title];
     370             :         if ([gui_info objectForKey:WIDTH_KEY])
     371             :                 siz.width = [gui_info oo_floatForKey:WIDTH_KEY];
     372             :         if ([gui_info objectForKey:HEIGHT_KEY])
     373             :                 siz.height = [gui_info oo_floatForKey:HEIGHT_KEY];
     374             :         if ([gui_info objectForKey:ROW_HEIGHT_KEY])
     375             :                 rht = [gui_info oo_floatForKey:ROW_HEIGHT_KEY];
     376             :         if ([gui_info objectForKey:TITLE_KEY])
     377             :                 title = [gui_info oo_stringForKey:TITLE_KEY];
     378             :         [gui resizeTo:siz characterHeight:rht title:title];
     379             :         if ([gui_info objectForKey:BACKGROUND_RGBA_KEY])
     380             :                 [gui setBackgroundColor:[OOColor colorFromString:[gui_info oo_stringForKey:BACKGROUND_RGBA_KEY]]];
     381             :         if ([gui_info objectForKey:ALPHA_KEY])
     382             :                 [gui setMaxAlpha: OOClamp_0_max_f([gui_info oo_floatForKey:ALPHA_KEY],1.0f)];
     383             :         else
     384             :                 [gui setMaxAlpha: 1.0f];
     385             : }
     386             : 
     387             : 
     388           0 : - (void) resetGuiPosition:(GuiDisplayGen*)gui withInfo:(NSDictionary *)gui_info
     389             : {
     390             :         Vector pos = [gui drawPosition];
     391             :         if ([gui_info objectForKey:X_KEY])
     392             :                 pos.x = [gui_info oo_floatForKey:X_KEY] +
     393             :                         [[UNIVERSE gameView] x_offset] *
     394             :                         [gui_info oo_floatForKey:X_ORIGIN_KEY defaultValue:0.0];
     395             :         if ([gui_info objectForKey:Y_KEY])
     396             :                 pos.y = [gui_info oo_floatForKey:Y_KEY] + 
     397             :                         [[UNIVERSE gameView] y_offset] *
     398             :                         [gui_info oo_floatForKey:Y_ORIGIN_KEY defaultValue:0.0];
     399             : 
     400             :         [gui setDrawPosition:pos];
     401             : }
     402             : 
     403             : 
     404             : - (void) resetGuiPositions
     405             : {
     406             :         NSDictionary *hudDict = [ResourceManager dictionaryFromFilesNamed:[self hudName] inFolder:@"Config" andMerge:YES];
     407             : 
     408             :         GuiDisplayGen*  gui = [UNIVERSE messageGUI];
     409             :         NSDictionary*   gui_info = [hudDict oo_dictionaryForKey:@"message_gui"];
     410             :         if (gui && gui_info)
     411             :         {
     412             :                 [self resetGuiPosition:gui withInfo:gui_info];
     413             :         }
     414             : 
     415             :         gui = [UNIVERSE commLogGUI];
     416             :         gui_info = [hudDict oo_dictionaryForKey:@"comm_log_gui"];
     417             :         if (gui && gui_info)
     418             :         {
     419             :                 [self resetGuiPosition:gui withInfo:gui_info];
     420             :         }
     421             : 
     422             : }
     423             : 
     424             : 
     425             : - (void) resetGuis:(NSDictionary *)info
     426             : {
     427             :         // check for entries in hud.plist for message_gui and comm_log_gui
     428             :         // then resize and reposition them accordingly.
     429             :         
     430             :         GuiDisplayGen*  gui = [UNIVERSE messageGUI];
     431             :         NSDictionary*   gui_info = [info oo_dictionaryForKey:@"message_gui"];
     432             :         if (gui && [gui_info count] > 0)
     433             :         {
     434             :                 /*
     435             :                         If switching message guis, remember the last 2 message lines.
     436             :                         Present GUI limitations make it impractical to transfer anything
     437             :                         more...
     438             :                         
     439             :                         TODO: a more usable GUI code! - Kaks 2011.11.05
     440             :                 */
     441             :                 
     442             :                 NSArray*        lastLines = [gui getLastLines]; // text, colour, fade time - text, colour, fade time
     443             :                 BOOL            line1 = ![[lastLines oo_stringAtIndex:0] isEqualToString:@""];
     444             :                 [self resetGui:gui withInfo:gui_info];
     445             : 
     446             :                 BOOL permanent = [gui_info oo_boolForKey:@"permanent" defaultValue:NO];
     447             :                 [UNIVERSE setPermanentMessageLog:permanent];
     448             :                 
     449             :                 BOOL automaticBg = [gui_info oo_boolForKey:@"background_automatic" defaultValue:YES];
     450             :                 [UNIVERSE setAutoMessageLogBg:automaticBg];
     451             :                 
     452             :                 // set message gui text colors - one for standard messages, one for incoming comms
     453             :                 // incoming comms message color must default to green for compatibility with older huds that
     454             :                 // don't have this key
     455             :                 [gui setTextColor:[OOColor colorWithDescription:[gui_info objectForKey:@"text_color"]]];
     456             :                 OOColor *textCommsColor = [OOColor colorWithDescription:[gui_info objectForKey:@"text_comms_color"]];
     457             :                 if (!textCommsColor)  textCommsColor = [OOColor greenColor];
     458             :                 [gui setTextCommsColor:textCommsColor];
     459             :                 
     460             :                 if (line1)
     461             :                 {
     462             :                         [gui printLongText:[lastLines oo_stringAtIndex:0] align:GUI_ALIGN_CENTER
     463             :                                                  color:[OOColor colorFromString:[lastLines oo_stringAtIndex:1]] 
     464             :                                           fadeTime:(permanent?0.0:[lastLines oo_floatAtIndex:2]) key:nil addToArray:nil];
     465             :                 }
     466             :                 if ([lastLines count] > 3 && (line1 || ![[lastLines oo_stringAtIndex:3] isEqualToString:@""]))
     467             :                 {
     468             :                         [gui printLongText:[lastLines oo_stringAtIndex:3] align:GUI_ALIGN_CENTER
     469             :                                                  color:[OOColor colorFromString:[lastLines oo_stringAtIndex:4]] 
     470             :                                           fadeTime:(permanent?0.0:[lastLines oo_floatAtIndex:5]) key:nil addToArray:nil];
     471             :                 }
     472             :         }
     473             :         
     474             :         if (gui_info != nil && [gui_info count] == 0)
     475             :         {
     476             :                 // exists and it's empty. complete reset.
     477             :                 [gui setCurrentRow:8];
     478             :                 [gui setDrawPosition: make_vector(0.0, -40.0, 640.0)];
     479             :                 [gui resizeTo:NSMakeSize(480, 160) characterHeight:19 title:nil];
     480             :                 [gui setCharacterSize:NSMakeSize(16,20)];       // narrow characters
     481             :                 [gui setTextColor:[OOColor yellowColor]];
     482             :                 [gui setTextCommsColor:[OOColor greenColor]];
     483             :                 [UNIVERSE setPermanentMessageLog:NO];
     484             :                 [UNIVERSE setAutoMessageLogBg:YES];
     485             :         }
     486             :         
     487             :         [gui setAlpha: 1.0f];   // message_gui is always visible.
     488             :         
     489             :         // And now set up the comms log
     490             :         
     491             :         gui = [UNIVERSE commLogGUI];
     492             :         gui_info = [info oo_dictionaryForKey:@"comm_log_gui"];
     493             :         
     494             :         if (gui && [gui_info count] > 0)
     495             :         {
     496             :                 [UNIVERSE setAutoCommLog:[gui_info oo_boolForKey:@"automatic" defaultValue:YES]];
     497             :                 [UNIVERSE setPermanentCommLog:[gui_info oo_boolForKey:@"permanent" defaultValue:NO]];
     498             :                 
     499             :                 /*
     500             :                         We need to repopulate the comms log after resetting it.
     501             :                         
     502             :                         At the moment the colour information is set on a per-line basis, rather than a per-text basis.
     503             :                         A comms message can span multiple lines, and two consecutive messages can share the same colour,
     504             :                         so trying to match the colour information from the GUI with each message won't work.
     505             :                         
     506             :                         Bottom line: colour information is lost on comms log gui reset.
     507             :                         And yes, this is yet another reason for the following
     508             :                         
     509             :                         TODO: a more usable GUI code! - Kaks 2011.11.05
     510             :                 */
     511             :                 
     512             :                 NSArray *cLog = [PLAYER commLog];
     513             :                 NSUInteger i, commCount = [cLog count];
     514             :                 
     515             :                 [self resetGui:gui withInfo:gui_info];
     516             :                 
     517             :                 for (i = 0; i < commCount; i++)
     518             :                 {
     519             :                         [gui printLongText:[cLog oo_stringAtIndex:i] align:GUI_ALIGN_LEFT color:nil
     520             :                                           fadeTime:0.0 key:nil addToArray:nil];
     521             :                 }
     522             :         }
     523             :         
     524             :         if (gui_info != nil && [gui_info count] == 0)
     525             :         {
     526             :                 // exists and it's empty. complete reset.
     527             :                 [UNIVERSE setAutoCommLog:YES];
     528             :                 [UNIVERSE setPermanentCommLog:NO];
     529             :                 [gui setCurrentRow:9];
     530             :                 [gui setDrawPosition: make_vector(0.0, 180.0, 640.0)];
     531             :                 [gui resizeTo:NSMakeSize(360, 120) characterHeight:12 title:nil];
     532             :                 [gui setBackgroundColor:[OOColor colorWithRed:0.0 green:0.05 blue:0.45 alpha:0.5]];
     533             :                 [gui setTextColor:[OOColor whiteColor]];
     534             :                 [gui printLongText:DESC(@"communications-log-string") align:GUI_ALIGN_CENTER color:[OOColor yellowColor] fadeTime:0 key:nil addToArray:nil];
     535             :         }
     536             :         
     537             :         if ([UNIVERSE permanentCommLog])
     538             :         {
     539             :                 [gui stopFadeOuts];
     540             :                 [gui setAlpha:1.0];
     541             :         }
     542             :         else
     543             :         {
     544             :                 [gui setAlpha:0.0];
     545             :         }
     546             : }
     547             : 
     548             : 
     549             : - (NSString *) hudName
     550             : {
     551             :         return hudName;
     552             : }
     553             : 
     554             : 
     555             : - (void) setHudName:(NSString *)newHudName
     556             : {
     557             :         if (newHudName != nil)
     558             :         {
     559             :                 [hudName release];
     560             :                 hudName = [newHudName copy];
     561             :         }
     562             : }
     563             : 
     564             : 
     565             : - (OOColor *) reticleColorForIndex:(NSUInteger)idx
     566             : {
     567             :         if (idx < [_reticleColors count])
     568             :         {
     569             :                 return [_reticleColors objectAtIndex:idx];
     570             :         }
     571             :         return nil;
     572             : }
     573             : 
     574             : 
     575             : - (BOOL) setReticleColorForIndex:(NSUInteger)idx toColor:(OOColor *)newColor
     576             : {
     577             :         if (newColor && idx < [_reticleColors count])
     578             :         {
     579             :                 [_reticleColors replaceObjectAtIndex:idx withObject:newColor];
     580             :                 return YES;
     581             :         }
     582             :         return NO;
     583             : }
     584             : 
     585             : 
     586             : - (GLfloat) scannerZoom
     587             : {
     588             :         return scanner_zoom;
     589             : }
     590             : 
     591             : 
     592             : - (void) setScannerZoom:(GLfloat)value
     593             : {
     594             :         scanner_zoom = value;
     595             : }
     596             : 
     597             : - (GLfloat) overallAlpha
     598             : {
     599             :         return overallAlpha;
     600             : }
     601             : 
     602             : 
     603             : - (void) setOverallAlpha:(GLfloat) newAlphaValue
     604             : {
     605             :         overallAlpha = OOClamp_0_1_f(newAlphaValue);
     606             : }
     607             : 
     608             : 
     609             : - (BOOL) reticleTargetSensitive
     610             : {
     611             :         return reticleTargetSensitive;
     612             : }
     613             : 
     614             : 
     615             : - (void) setReticleTargetSensitive:(BOOL) newReticleTargetSensitiveValue
     616             : {
     617             :         reticleTargetSensitive = !!newReticleTargetSensitiveValue; // ensure YES or NO.
     618             : }
     619             : 
     620             : 
     621             : - (NSMutableDictionary *) propertiesReticleTargetSensitive
     622             : {
     623             :         return propertiesReticleTargetSensitive;
     624             : }
     625             : 
     626             : 
     627             : - (BOOL) isHidden
     628             : {
     629             :         return hudHidden;
     630             : }
     631             : 
     632             : 
     633             : - (void) setHidden:(BOOL)newValue
     634             : {
     635             :         hudHidden = !!newValue; // ensure YES or NO
     636             : }
     637             : 
     638             : 
     639             : - (BOOL) allowBigGui
     640             : {
     641             :         return allowBigGui || hudHidden;
     642             : }
     643             : 
     644             : 
     645             : - (BOOL) hasHidden:(NSString *)selectorName
     646             : {
     647             :         if (selectorName == nil)
     648             :         {
     649             :                 return NO;
     650             :         }
     651             :         return [_hiddenSelectors containsObject:selectorName];
     652             : }
     653             : 
     654             : 
     655             : - (void) setHiddenSelector:(NSString *)selectorName hidden:(BOOL)hide
     656             : {
     657             :         if (hide)
     658             :         {
     659             :                 [_hiddenSelectors addObject:selectorName];
     660             :         }
     661             :         else
     662             :         {
     663             :                 [_hiddenSelectors removeObject:selectorName];
     664             :         }
     665             : }
     666             : 
     667             : 
     668             : - (void) clearHiddenSelectors
     669             : {
     670             :         [_hiddenSelectors removeAllObjects];
     671             : }
     672             : 
     673             : 
     674             : - (BOOL) isCompassActive
     675             : {
     676             :         return _compassActive;
     677             : }
     678             : 
     679             : 
     680             : - (void) setCompassActive:(BOOL)newValue
     681             : {
     682             :         _compassActive = !!newValue;
     683             : }
     684             : 
     685             : 
     686             : - (BOOL) isUpdating
     687             : {
     688             :         return hudUpdating;
     689             : }
     690             : 
     691             : 
     692             : - (void) setDeferredHudName:(NSString *)newDeferredHudName
     693             : {
     694             :         [deferredHudName release];
     695             :         deferredHudName = [newDeferredHudName copy];
     696             : }
     697             : 
     698             : 
     699             : - (NSString *) deferredHudName
     700             : {
     701             :         return deferredHudName;
     702             : }
     703             : 
     704             : 
     705             : - (void) addLegend:(NSDictionary *)info
     706             : {
     707             :         NSString                        *imageName = nil;
     708             :         OOTexture                       *texture = nil;
     709             :         NSSize                          imageSize;
     710             :         OOTextureSprite         *legendSprite = nil;
     711             :         NSMutableDictionary     *legendDict = nil;
     712             :         struct CachedInfo       cache;
     713             :         
     714             :         // prefetch data associated with this legend
     715             :         prefetchData(info, &cache);
     716             :         
     717             :         imageName = [info oo_stringForKey:IMAGE_KEY];
     718             :         if (imageName != nil)
     719             :         {
     720             :                 texture = [OOTexture textureWithName:imageName
     721             :                                                                         inFolder:@"Images"
     722             :                                                                          options:kOOTextureDefaultOptions | kOOTextureNoShrink
     723             :                                                                   anisotropy:kOOTextureDefaultAnisotropy
     724             :                                                                          lodBias:kOOTextureDefaultLODBias];
     725             :                 if (texture == nil)
     726             :                 {
     727             :                         OOLogERR(kOOLogFileNotFound, @"HeadUpDisplay couldn't get an image texture name for %@", imageName);
     728             :                         return;
     729             :                 }
     730             :                 
     731             :                 imageSize = [texture dimensions];
     732             :                 imageSize.width = [info oo_floatForKey:WIDTH_KEY defaultValue:imageSize.width];
     733             :                 imageSize.height = [info oo_floatForKey:HEIGHT_KEY defaultValue:imageSize.height];
     734             :                 
     735             :                 legendSprite = [[OOTextureSprite alloc] initWithTexture:texture size:imageSize];
     736             :                 
     737             :                 legendDict = [info mutableCopy];
     738             :                 [legendDict setObject:legendSprite forKey:SPRITE_KEY];
     739             :                 // add WIDGET_INFO, WIDGET_CACHE to array
     740             :                 [legendArray addObject:[NSArray arrayWithObjects:legendDict, [NSValue valueWithBytes:&cache objCType:@encode(struct CachedInfo)], nil]];                                                                                                                                    
     741             :                 [legendDict release];
     742             :                 [legendSprite release];
     743             :         }
     744             :         else if ([info oo_stringForKey:TEXT_KEY] != nil)
     745             :         {
     746             :                 // add WIDGET_INFO, WIDGET_CACHE to array
     747             :                 [legendArray addObject:[NSArray arrayWithObjects:info, [NSValue valueWithBytes:&cache objCType:@encode(struct CachedInfo)], nil]];
     748             : 
     749             :         }
     750             : }
     751             : 
     752             : 
     753             : - (void) addDial:(NSDictionary *)info
     754             : {
     755             :         static NSSet *allowedSelectors = nil;
     756             :         if (allowedSelectors == nil)
     757             :         {
     758             :                 NSDictionary *whitelist = [ResourceManager whitelistDictionary];
     759             :                 allowedSelectors = [[NSSet alloc] initWithArray:[whitelist oo_arrayForKey:@"hud_dial_methods"]];
     760             :         }
     761             :         
     762             :         NSString *selectorString = [info oo_stringForKey:SELECTOR_KEY];
     763             :         if (selectorString == nil)
     764             :         {
     765             :                 OOLogERR(@"hud.dial.noSelector", @"HUD dial in %@ is missing selector.", hudName);
     766             :                 return;
     767             :         }
     768             :         
     769             :         if (![allowedSelectors containsObject:selectorString])
     770             :         {
     771             :                 OOLogERR(@"hud.dial.invalidSelector", @"HUD dial in %@ uses selector \"%@\" which is not in whitelist, and will be ignored.", hudName, selectorString);
     772             :                 return;
     773             :         }
     774             :         
     775             :         SEL selector = NSSelectorFromString(selectorString);
     776             :         
     777             :         NSAssert2([self respondsToSelector:selector], @"HUD dial in %@ uses selector \"%@\" which is in whitelist, but not implemented.", hudName, selectorString);
     778             :         
     779             :         //  handle the case above with NS_BLOCK_ASSERTIONS too.
     780             :         if (![self respondsToSelector:selector])
     781             :         {
     782             :                 OOLogERR(@"hud.dial.invalidSelector", @"HUD dial in %@ uses selector \"%@\"  which is in whitelist, but not implemented, and will be ignored.", hudName, selectorString);
     783             :                 return;
     784             :         }
     785             :         
     786             :         // valid dial, now prefetch data
     787             :         struct CachedInfo cache;
     788             :         prefetchData(info, &cache);
     789             :         // add WIDGET_INFO, WIDGET_CACHE, WIDGET_SELECTOR, WIDGET_SELECTOR_NAME to array
     790             :         [dialArray addObject:[NSArray arrayWithObjects:info, [NSValue valueWithBytes:&cache objCType:@encode(struct CachedInfo)],
     791             :                                                  [NSValue valueWithPointer:selector], selectorString, nil]];
     792             : }
     793             : 
     794             : 
     795             : - (void) addMFD:(NSDictionary *)info
     796             : {
     797             :         struct CachedInfo cache;
     798             :         prefetchData(info, &cache);
     799             :         [mfdArray addObject:[NSArray arrayWithObjects:info, [NSValue valueWithBytes:&cache objCType:@encode(struct CachedInfo)],nil]];
     800             : }
     801             : 
     802             : 
     803             : - (NSUInteger) mfdCount
     804             : {
     805             :         return [mfdArray count];
     806             : }
     807             : 
     808             : /*
     809             :         SLOW_CODE
     810             :         As of 2012-09-13 (r5320), HUD rendering is taking 25%-30% of rendering time,
     811             :         or 15%-20% of game tick time, as tested on a couple of Macs using the
     812             :         default HUD and models. This could be worse - there used to be a note here
     813             :         saying 30%-40% of tick time - but could still improve.
     814             :         
     815             :         In a top-down perspective, of HUD rendering time, 67% is in -drawDials and
     816             :         27% is in -drawLegends.
     817             :         
     818             :         Bottom-up, one profile shows:
     819             :         21.2%   OODrawString()
     820             :                         (Caching the glyph conversion here was a win, but caching geometry
     821             :                         in vertex arrays/VBOs would be better.)
     822             :         8.9%    -[HeadUpDisplay drawHudItem:]
     823             :         5.1%    OOFloatFromObject
     824             :                         (Reifying HUD info instead of parsing plists each frame would be
     825             :                         a win.)
     826             :         4.4%    hudDrawBarAt()
     827             :                         (Using fixed geometery and a vertex shader could help here,
     828             :                         especially if bars are grouped together and drawn at once if
     829             :                         possible.)
     830             :         4.3%    -[OOCrosshairs render]
     831             :                         (Uses vertex arrays, but does more GL state manipulation than
     832             :                         strictly necessary.)
     833             :         
     834             : */
     835             : - (void) renderHUD
     836             : {
     837             :         hudUpdating = YES;
     838             :         
     839             :         OOVerifyOpenGLState();
     840             :         
     841             :         if (_crosshairWidth * lineWidth > 0)
     842             :         {
     843             :                 OOGL(GLScaledLineWidth(_crosshairWidth * lineWidth));
     844             :                 [self drawCrosshairs];
     845             :         }
     846             :         
     847             :         if (lineWidth > 0)
     848             :         {
     849             :                 OOGL(GLScaledLineWidth(lineWidth));
     850             :                 [self drawLegends];
     851             :         }
     852             :         
     853             :         [self drawDials];
     854             :         [self drawMFDs];
     855             :         OOCheckOpenGLErrors(@"After drawing HUD");
     856             :         
     857             :         OOVerifyOpenGLState();
     858             :         
     859             :         hudUpdating = NO;
     860             : }
     861             : 
     862             : 
     863           0 : - (void) drawLegends
     864             : {
     865             :         /* Since the order of legend drawing is significant, this loop must be kept
     866             :          * as an incrementing one for compatibility with previous Oolite versions.
     867             :          * CIM: 28/9/12 */
     868             :         z1 = [[UNIVERSE gameView] display_z];
     869             :         NSUInteger i, nLegends = [legendArray count];
     870             :         for (i = 0; i < nLegends; i++)
     871             :         {
     872             :                 sCurrentDrawItem = [legendArray oo_arrayAtIndex:i];
     873             :                 [self drawLegend:[sCurrentDrawItem oo_dictionaryAtIndex:WIDGET_INFO]];
     874             :         }
     875             : }
     876             : 
     877             : 
     878           0 : - (void) drawDials
     879             : {       
     880             :         z1 = [[UNIVERSE gameView] display_z];
     881             :         // reset drawScanner flag.
     882             :         _compassUpdated = NO;
     883             :         
     884             :         // tight loop, we assume dialArray doesn't change in mid-draw.
     885             :         NSUInteger i, nDials = [dialArray count];
     886             :         for (i = 0; i < nDials; i++)
     887             :         {
     888             :                 sCurrentDrawItem = [dialArray oo_arrayAtIndex:i];
     889             :                 [self drawHUDItem:[sCurrentDrawItem oo_dictionaryAtIndex:WIDGET_INFO]];
     890             :         }
     891             :         
     892             :         if (EXPECT_NOT(!_compassUpdated && _compassActive && [self checkPlayerInSystemFlight])) // compass gone / broken / disabled ?
     893             :         {
     894             :                 // trigger the targetChanged event with whom == null
     895             :                 _compassActive = NO;
     896             :                 [PLAYER doScriptEvent:OOJSID("compassTargetChanged") withArguments:[NSArray arrayWithObjects:[NSNull null], OOStringFromCompassMode([PLAYER compassMode]), nil]];
     897             :         }
     898             :         
     899             : }
     900             : 
     901             : 
     902           0 : - (void) drawMFDs
     903             : {
     904             :         NSUInteger i, nMFDs = [mfdArray count];
     905             :         NSString *text = nil;
     906             :         for (i = 0; i < nMFDs; i++)
     907             :         {
     908             :                 text = [PLAYER multiFunctionText:i];
     909             :                 if (text != nil)
     910             :                 {
     911             :                         sCurrentDrawItem = [mfdArray oo_arrayAtIndex:i];
     912             :                         [self drawMultiFunctionDisplay:[sCurrentDrawItem oo_dictionaryAtIndex:WIDGET_INFO] withText:text asIndex:i];
     913             :                 }
     914             :         }
     915             : }
     916             : 
     917             : 
     918           0 : - (void) drawCrosshairs
     919             : {
     920             :         OOViewID                                        viewID = [UNIVERSE viewDirection];
     921             :         OOWeaponType                            weapon = [PLAYER currentWeapon];
     922             :         BOOL                                            weaponsOnline = [PLAYER weaponsOnline];
     923             :         NSArray                                         *points = nil;
     924             :         
     925             :         if (viewID == VIEW_CUSTOM ||
     926             :                 overallAlpha == 0.0f ||
     927             :                 !([PLAYER status] == STATUS_IN_FLIGHT || [PLAYER status] == STATUS_WITCHSPACE_COUNTDOWN) ||
     928             :                 [UNIVERSE displayGUI]
     929             :                 )
     930             :         {
     931             :                 // Don't draw crosshairs
     932             :                 return;
     933             :         }
     934             :         
     935             :         if (weapon != _lastWeaponType || overallAlpha != _lastOverallAlpha || weaponsOnline != _lastWeaponsOnline)
     936             :         {
     937             :                 DESTROY(_crosshairs);
     938             :         }
     939             :         
     940             :         if (_crosshairs == nil)
     941             :         {
     942             :                 GLfloat useAlpha = weaponsOnline ? overallAlpha : overallAlpha * 0.5f;
     943             :                 
     944             :                 // Make new crosshairs object
     945             :                 points = [self crosshairDefinitionForWeaponType:weapon];
     946             :                 
     947             :                 _crosshairs = [[OOCrosshairs alloc] initWithPoints:points
     948             :                                                                                                          scale:_crosshairScale
     949             :                                                                                                          color:_crosshairColor
     950             :                                                                                           overallAlpha:useAlpha];
     951             :                 _lastWeaponType = weapon;
     952             :                 _lastOverallAlpha = useAlpha;
     953             :                 _lastWeaponsOnline = weaponsOnline;
     954             :         }
     955             :         
     956             :         [_crosshairs render];
     957             : }
     958             : 
     959             : 
     960             : - (NSString *) crosshairDefinition
     961             : {
     962             :         return crosshairDefinition;
     963             : }
     964             : 
     965             : 
     966             : - (BOOL) setCrosshairDefinition:(NSString *)newDefinition
     967             : {
     968             :         // force crosshair redraw
     969             :         [_crosshairs release];
     970             :         _crosshairs = nil;
     971             : 
     972             :         [_crosshairOverrides release];
     973             :         _crosshairOverrides = [[ResourceManager dictionaryFromFilesNamed:newDefinition
     974             :                                                                                                                                                                                                                                  inFolder:@"Config"
     975             :                                                                                                                                                                                                                                  andMerge:YES] retain];
     976             :         if (_crosshairOverrides == nil || [_crosshairOverrides count] == 0)
     977             :         { // invalid file
     978             :                 [_crosshairOverrides release];
     979             :                 _crosshairOverrides = [[ResourceManager dictionaryFromFilesNamed:@"crosshairs.plist"
     980             :                                                                                                                                                                                                                                          inFolder:@"Config"
     981             :                                                                                                                                                                                                                                          andMerge:YES] retain];
     982             :                 crosshairDefinition = @"crosshairs.plist";
     983             :                 return NO;
     984             :         }
     985             :         crosshairDefinition = [newDefinition copy];
     986             :         return YES;
     987             : }
     988             : 
     989             : 
     990           0 : - (NSArray *) crosshairDefinitionForWeaponType:(OOWeaponType)weapon
     991             : {
     992             :         NSString                                        *weaponName = nil;
     993             :         NSString                                        *weaponName2 = nil;
     994             :         static                                          NSDictionary *crosshairDefs = nil;
     995             :         NSArray                                         *result = nil;
     996             :         
     997             :         /*      Search order:
     998             :          (hud.plist).crosshairs.WEAPON_NAME
     999             :          (hud.plist).crosshairs.OTHER
    1000             :          (crosshairs.plist).WEAPON_NAME
    1001             :          (crosshairs.plist).OTHER
    1002             :          */
    1003             :         
    1004             :         weaponName = OOStringFromWeaponType(weapon);
    1005             :         weaponName2 = [weaponName substringFromIndex:3]; // strip "EQ_"
    1006             :         result = [_crosshairOverrides oo_arrayForKey:weaponName];
    1007             :         if (result == nil) 
    1008             :         {
    1009             :                 result = [_crosshairOverrides oo_arrayForKey:weaponName2];
    1010             :         }
    1011             :         if (result == nil)  result = [_crosshairOverrides oo_arrayForKey:@"OTHER"];
    1012             :         if (result == nil)
    1013             :         {
    1014             :                 if (crosshairDefs == nil)
    1015             :                 {
    1016             :                         crosshairDefs = [ResourceManager dictionaryFromFilesNamed:@"crosshairs.plist"
    1017             :                                                                                                                          inFolder:@"Config"
    1018             :                                                                                                                          andMerge:YES];
    1019             :                         [crosshairDefs retain];
    1020             :                 }
    1021             :                 
    1022             :                 result = [crosshairDefs oo_arrayForKey:weaponName];
    1023             :                 if (result == nil) 
    1024             :                 {
    1025             :                         result = [crosshairDefs oo_arrayForKey:weaponName2];
    1026             :                 }
    1027             :                 if (result == nil)  result = [crosshairDefs oo_arrayForKey:@"OTHER"];
    1028             :         }
    1029             :         
    1030             :         return result;
    1031             : }
    1032             : 
    1033             : 
    1034           0 : - (void) drawLegend:(NSDictionary *)info
    1035             : {
    1036             :         // check if equipment is required
    1037             :         NSString *equipmentRequired = [info oo_stringForKey:EQUIPMENT_REQUIRED_KEY];
    1038             :         if (equipmentRequired != nil && ![PLAYER hasEquipmentItemProviding:equipmentRequired])
    1039             :         {
    1040             :                 return;
    1041             :         }
    1042             : 
    1043             :         // check alert condition
    1044             :         NSUInteger alertMask = [info oo_unsignedIntForKey:ALERT_CONDITIONS_KEY defaultValue:15];
    1045             :         // 1=docked, 2=green, 4=yellow, 8=red
    1046             :         if (alertMask < 15)
    1047             :         {
    1048             :                 OOAlertCondition alertCondition = [PLAYER alertCondition];
    1049             :                 if (~alertMask & (1 << alertCondition)) {
    1050             :                         return;
    1051             :                 }
    1052             :         }
    1053             : 
    1054             :         BOOL viewOnly = [info oo_boolForKey:VIEWSCREEN_KEY defaultValue:NO];
    1055             :         // 1=docked, 2=green, 4=yellow, 8=red
    1056             :         if (viewOnly && [PLAYER guiScreen] != GUI_SCREEN_MAIN)
    1057             :         {
    1058             :                 return;
    1059             :         }
    1060             : 
    1061             :         // check association with hidden dials
    1062             :         if ([self hasHidden:[info oo_stringForKey:DIAL_REQUIRED_KEY defaultValue:nil]])
    1063             :         {
    1064             :                 return;
    1065             :         }
    1066             : 
    1067             :         OOTextureSprite                         *legendSprite = nil;
    1068             :         NSString                                        *legendText = nil;
    1069             :         float                                           x, y;
    1070             :         NSSize                                          size;
    1071             :         GLfloat                                         alpha = overallAlpha;
    1072             :         struct CachedInfo                       cached;
    1073             :         
    1074             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1075             :         
    1076             :         // if either x or y is missing, use 0 instead
    1077             :         
    1078             :         x = useDefined(cached.x, 0.0f) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1079             :         y = useDefined(cached.y, 0.0f) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1080             :         alpha *= cached.alpha;
    1081             :         
    1082             :         legendSprite = [info objectForKey:SPRITE_KEY];
    1083             :         if (legendSprite != nil)
    1084             :         {
    1085             :                 [legendSprite blitCentredToX:x Y:y Z:z1 alpha:alpha];
    1086             :         }
    1087             :         else
    1088             :         {
    1089             :                 legendText = [info oo_stringForKey:TEXT_KEY];
    1090             :                 if (legendText != nil)
    1091             :                 {
    1092             :                         // randomly chosen default width & height
    1093             :                         size.width = useDefined(cached.width, 14.0f);
    1094             :                         size.height = useDefined(cached.height, 8.0f);
    1095             :                         SET_COLOR(green_color);
    1096             :                         if ([info oo_intForKey:@"align"] == 1)
    1097             :                         {
    1098             :                                 OODrawStringAligned(legendText, x, y, z1, size, YES);
    1099             :                         }
    1100             :                         else
    1101             :                         {
    1102             :                                 OODrawStringAligned(legendText, x, y, z1, size, NO);
    1103             :                         }
    1104             :                 }
    1105             :         }
    1106             : }
    1107             : 
    1108             : 
    1109           0 : - (void) drawHUDItem:(NSDictionary *)info
    1110             : {
    1111             :         NSString        *equipment = [info oo_stringForKey:EQUIPMENT_REQUIRED_KEY];
    1112             :         
    1113             :         if (equipment != nil && ![PLAYER hasEquipmentItemProviding:equipment])
    1114             :         {
    1115             :                 return;
    1116             :         }
    1117             : 
    1118             :         // check alert condition
    1119             :         NSUInteger alertMask = [info oo_unsignedIntForKey:ALERT_CONDITIONS_KEY defaultValue:15];
    1120             :         // 1=docked, 2=green, 4=yellow, 8=red
    1121             :         if (alertMask < 15)
    1122             :         {
    1123             :                 OOAlertCondition alertCondition = [PLAYER alertCondition];
    1124             :                 if (~alertMask & (1 << alertCondition)) {
    1125             :                         return;
    1126             :                 }
    1127             :         }
    1128             : 
    1129             :         BOOL viewOnly = [info oo_boolForKey:VIEWSCREEN_KEY defaultValue:NO];
    1130             : 
    1131             :         // 1=docked, 2=green, 4=yellow, 8=red
    1132             :         if (viewOnly && [PLAYER guiScreen] != GUI_SCREEN_MAIN)
    1133             :         {
    1134             :                 return;
    1135             :         }
    1136             : 
    1137             :         if (EXPECT_NOT([self hasHidden:[sCurrentDrawItem objectAtIndex:WIDGET_SELECTOR_NAME]]))
    1138             :         {
    1139             :                 return;
    1140             :         }
    1141             : 
    1142             :         // use the selector value stored during init.
    1143             :         [self performSelector:[(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_SELECTOR] pointerValue] withObject:info];
    1144             :         OOCheckOpenGLErrors(@"HeadUpDisplay after drawHUDItem %@", info);
    1145             :         
    1146             :         OOVerifyOpenGLState();
    1147             : }
    1148             : 
    1149             : 
    1150           0 : - (BOOL) checkPlayerInFlight
    1151             : {
    1152             :         return [PLAYER isInSpace] && [PLAYER status] != STATUS_DOCKING;
    1153             : }
    1154             : 
    1155             : 
    1156           0 : - (BOOL) checkPlayerInSystemFlight
    1157             : {
    1158             :         OOSunEntity             *the_sun = [UNIVERSE sun];
    1159             :         OOPlanetEntity  *the_planet = [UNIVERSE planet];
    1160             :         
    1161             :         return [self checkPlayerInFlight]               // be in the right mode
    1162             :                 && the_sun && the_planet                // and be in a system
    1163             :                 && ![the_sun goneNova];
    1164             : }
    1165             : 
    1166             : 
    1167             : static void prefetchData(NSDictionary *info, struct CachedInfo *data)
    1168             : {
    1169             :         data->x = [info oo_floatForKey:X_KEY defaultValue:NOT_DEFINED];
    1170             :         data->x0 = [info oo_floatForKey:X_ORIGIN_KEY defaultValue:0.0];
    1171             :         data->y = [info oo_floatForKey:Y_KEY defaultValue:NOT_DEFINED];
    1172             :         data->y0 = [info oo_floatForKey:Y_ORIGIN_KEY defaultValue:0.0];
    1173             :         data->width = [info oo_floatForKey:WIDTH_KEY defaultValue:NOT_DEFINED];
    1174             :         data->height = [info oo_floatForKey:HEIGHT_KEY defaultValue:NOT_DEFINED];
    1175             :         data->alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:1.0f];  
    1176             : }
    1177             : 
    1178             : //---------------------------------------------------------------------//
    1179             : 
    1180           0 : - (void) drawScanner:(NSDictionary *)info
    1181             : {
    1182             :         int                             i, x, y;
    1183             :         NSSize                  siz;
    1184             :         GLfloat                 scanner_color[4] = { 1.0, 0.0, 0.0, 1.0 };
    1185             :         
    1186             :         BOOL                    emptyDial = ([info oo_floatForKey:ALPHA_KEY] == 0.0f);
    1187             :                 
    1188             :         BOOL                    isHostile = NO;
    1189             : 
    1190             :         BOOL                    inColorBlindMode = [UNIVERSE colorblindMode] != OO_POSTFX_NONE;
    1191             :         
    1192             :         if (emptyDial)
    1193             :         {
    1194             :                 // we can skip a lot of code.
    1195             :                 x = y = 0;
    1196             :                 scanner_color[3] = 0.0;                 // nothing to see!
    1197             :                 siz = NSMakeSize(1.0, 1.0);             // avoid divide by 0s
    1198             :         }
    1199             :         else
    1200             :         {
    1201             :                 struct CachedInfo       cached;
    1202             :         
    1203             :                 [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1204             :                 
    1205             :                 x = useDefined(cached.x, SCANNER_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1206             :                 y = useDefined(cached.y, SCANNER_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1207             :                 siz.width = useDefined(cached.width, SCANNER_WIDTH);
    1208             :                 siz.height = useDefined(cached.height, SCANNER_HEIGHT);
    1209             : 
    1210             :                 GetRGBAArrayFromInfo(info, scanner_color);
    1211             :                 
    1212             :                 scanner_color[3] *= overallAlpha;
    1213             :         }
    1214             :         
    1215             :         GLfloat                 alpha = scanner_color[3];
    1216             :         GLfloat                 col[4] = { 1.0, 1.0, 1.0, alpha };      // temporary colour variable
    1217             :         
    1218             :         GLfloat                 z_factor = siz.height / siz.width;      // approx 1/4
    1219             :         GLfloat                 y_factor = 1.0 - sqrt(z_factor);        // approx 1/2
    1220             :         
    1221             :         int                             scanner_cx = x;
    1222             :         int                             scanner_cy = y;
    1223             :         
    1224             :         int                             scannerFootprint = SCANNER_MAX_RANGE * 2.5 / siz.width;
    1225             :         
    1226             :         GLfloat                 zoom = scanner_zoom;
    1227             :         if (scanner_ultra_zoom)
    1228             :                 zoom = pow(2, zoom - 1.0);
    1229             :         GLfloat                 max_zoomed_range2 = SCANNER_SCALE * SCANNER_SCALE * 10000.0;
    1230             :         if (!nonlinear_scanner)
    1231             :         {
    1232             :                 max_zoomed_range2 /= zoom * zoom;
    1233             :         }
    1234             :         GLfloat                 max_zoomed_range = sqrt(max_zoomed_range2);
    1235             :         
    1236             :         if (PLAYER == nil)  return;
    1237             :         
    1238             :         OOMatrix                rotMatrix = [PLAYER rotationMatrix];
    1239             :         Vector                  relativePosition;
    1240             :         int                             flash = ((int)([UNIVERSE getTime] * 4))&1;
    1241             :         
    1242             :         // use a non-mutable copy so this can't be changed under us.
    1243             :         int                             ent_count               = UNIVERSE->n_entities;
    1244             :         Entity                  **uni_entities  = UNIVERSE->sortedEntities;  // grab the public sorted list
    1245             :         Entity                  *my_entities[ent_count];
    1246             :         Entity                  *scannedEntity = nil;
    1247             :         
    1248             :         for (i = 0; i < ent_count; i++)
    1249             :         {
    1250             :                 my_entities[i] = [uni_entities[i] retain];      // retained
    1251             :         }
    1252             :         
    1253             :         if (!emptyDial)
    1254             :         {
    1255             :                 OOGL(glColor4fv(scanner_color));
    1256             :                 drawScannerGrid(x, y, z1, siz, [UNIVERSE viewDirection], lineWidth, zoom, nonlinear_scanner, minimalistic_scanner);
    1257             :         }
    1258             :         
    1259             :         if ([self checkPlayerInFlight])
    1260             :         {
    1261             :                 GLfloat upscale = zoom * 1.25 / scannerFootprint;
    1262             :                 GLfloat max_blip = 0.0;
    1263             :                 int drawClass;
    1264             :                 
    1265             :                 OOVerifyOpenGLState();
    1266             :                 
    1267             :                 // Debugging code for nonlinear scanner - draws three fake cascade weapons, which looks pretty and enables me
    1268             :                 // to debug the code without the mass slaughter of innocent civillians.
    1269             :                 //if (nonlinear_scanner)
    1270             :                 //{
    1271             :                 //      Vector p = OOVectorMultiplyMatrix(make_vector(10000.0, 0.0, 0.0), rotMatrix);
    1272             :                 //      GLDrawNonlinearCascadeWeapon( scanner_cx, scanner_cy, z1, siz, p, 5000, zoom, alpha );
    1273             :                 //      p = OOVectorMultiplyMatrix(make_vector(10000.0, 4500.0, 0.0), rotMatrix);
    1274             :                 //      GLDrawNonlinearCascadeWeapon( scanner_cx, scanner_cy, z1, siz, p, 2000, zoom, alpha );
    1275             :                 //      p = OOVectorMultiplyMatrix(make_vector(0.0, 0.0, 20000.0), rotMatrix);
    1276             :                 //      GLDrawNonlinearCascadeWeapon( scanner_cx, scanner_cy, z1, siz, p, 6000, zoom, alpha );
    1277             :                 //}
    1278             :                 for (i = 0; i < ent_count; i++)  // scanner lollypops
    1279             :                 {
    1280             :                         scannedEntity = my_entities[i];
    1281             :                         
    1282             :                         drawClass = [scannedEntity scanClass];
    1283             :                         
    1284             :                         // cloaked ships - and your own one - don't show up on the scanner.
    1285             :                         if (EXPECT_NOT(drawClass == CLASS_PLAYER || ([scannedEntity isShip] && [(ShipEntity *)scannedEntity isCloaked])))
    1286             :                         {
    1287             :                                 drawClass = CLASS_NO_DRAW;
    1288             :                         }
    1289             :                         
    1290             :                         if (drawClass != CLASS_NO_DRAW)
    1291             :                         {
    1292             :                                 GLfloat x1,y1,y2;
    1293             :                                 float   ms_blip = 0.0;
    1294             :                                 
    1295             :                                 if (emptyDial)  continue;
    1296             :                                 
    1297             :                                 if (isnan(scannedEntity->zero_distance))
    1298             :                                         continue;
    1299             :                                 
    1300             :                                 // exit if it's too far away
    1301             :                                 GLfloat act_dist = sqrt(scannedEntity->zero_distance);
    1302             :                                 GLfloat lim_dist = act_dist - scannedEntity->collision_radius;
    1303             :                                 
    1304             :                                 // for efficiency, assume no scannable entity > 10km radius
    1305             :                                 if (act_dist > max_zoomed_range + 10000.0)
    1306             :                                         break;
    1307             : 
    1308             :                                 if (lim_dist > max_zoomed_range)
    1309             :                                         continue;
    1310             :                                 
    1311             :                                 // has it sent a recent message
    1312             :                                 //
    1313             :                                 if ([scannedEntity isShip]) 
    1314             :                                         ms_blip = 2.0 * [(ShipEntity *)scannedEntity messageTime];
    1315             :                                 if (ms_blip > max_blip)
    1316             :                                 {
    1317             :                                         max_blip = ms_blip;
    1318             :                                         last_transmitter = [scannedEntity universalID];
    1319             :                                 }
    1320             :                                 ms_blip -= floor(ms_blip);
    1321             :                                 
    1322             :                                 relativePosition = [PLAYER vectorTo:scannedEntity];
    1323             :                                 double fuzz = [PLAYER scannerFuzziness];
    1324             :                                 if (fuzz > 0 && ![[UNIVERSE gameController] isGamePaused])
    1325             :                                 {
    1326             :                                         relativePosition = vector_add(relativePosition,OOVectorRandomRadial(fuzz));
    1327             :                                 }
    1328             : 
    1329             :                                 Vector rp = relativePosition;
    1330             :                                 
    1331             :                                 if (act_dist > max_zoomed_range)
    1332             :                                         scale_vector(&relativePosition, max_zoomed_range / act_dist);
    1333             :                                 
    1334             :                                 // rotate the view
    1335             :                                 relativePosition = OOVectorMultiplyMatrix(relativePosition, rotMatrix);
    1336             :                                 Vector rrp = relativePosition;
    1337             :                                 // scale the view
    1338             :                                 if (nonlinear_scanner)
    1339             :                                 {
    1340             :                                         relativePosition = [HeadUpDisplay nonlinearScannerScale: relativePosition Zoom: zoom Scale: 0.5*siz.width];
    1341             :                                 }
    1342             :                                 else
    1343             :                                 {
    1344             :                                         scale_vector(&relativePosition, upscale);
    1345             :                                 }
    1346             :                                 
    1347             :                                 x1 = relativePosition.x;
    1348             :                                 y1 = z_factor * relativePosition.z;
    1349             :                                 y2 = y1 + y_factor * relativePosition.y;
    1350             :                                 
    1351             :                                 isHostile = NO;
    1352             :                                 if ([scannedEntity isShip])
    1353             :                                 {
    1354             :                                         ShipEntity *ship = (ShipEntity *)scannedEntity;
    1355             :                                         isHostile = (([ship hasHostileTarget])&&([ship primaryTarget] == PLAYER));
    1356             :                                         GLfloat *base_col = [ship scannerDisplayColorForShip:PLAYER :isHostile :flash
    1357             :                                                                                                                                                 :[ship scannerDisplayColor1] :[ship scannerDisplayColor2]
    1358             :                                                                                                                                                 :[ship scannerDisplayColorHostile1] :[ship scannerDisplayColorHostile2]
    1359             :                                                 ];
    1360             :                                         col[0] = base_col[0];   col[1] = base_col[1];   col[2] = base_col[2];   col[3] = alpha * base_col[3];
    1361             :                                 }
    1362             :                                 else if ([scannedEntity isVisualEffect])
    1363             :                                 {
    1364             :                                         OOVisualEffectEntity *vis = (OOVisualEffectEntity *)scannedEntity;
    1365             :                                         GLfloat* base_col = [vis scannerDisplayColorForShip:flash :[vis scannerDisplayColor1] :[vis scannerDisplayColor2]];
    1366             :                                         col[0] = base_col[0];   col[1] = base_col[1];   col[2] = base_col[2];   col[3] = alpha * base_col[3];
    1367             :                                 }
    1368             : 
    1369             :                                 if ([scannedEntity isWormhole])
    1370             :                                 {
    1371             :                                         col[0] = blue_color[0]; col[1] = (flash)? 1.0 : blue_color[1];  col[2] = blue_color[2]; col[3] = alpha * blue_color[3];
    1372             :                                 }
    1373             :                                 
    1374             :                                 // position the scanner
    1375             :                                 x1 += scanner_cx;   y1 += scanner_cy;   y2 += scanner_cy;
    1376             : 
    1377             :                                 if ([scannedEntity isShip])
    1378             :                                 {
    1379             :                                         ShipEntity* ship = (ShipEntity*)scannedEntity;
    1380             :                                         if ((!nonlinear_scanner && ship->collision_radius * upscale > 4.5) ||
    1381             :                                                 (nonlinear_scanner && nonlinearScannerFunc(act_dist, zoom, siz.width) - nonlinearScannerFunc(lim_dist, zoom, siz.width) > 4.5 ))
    1382             :                                         {
    1383             :                                                 Vector bounds[6];
    1384             :                                                 BoundingBox bb = ship->totalBoundingBox;
    1385             :                                                 bounds[0] = ship->v_forward; scale_vector(&bounds[0], bb.max.z);
    1386             :                                                 bounds[1] = ship->v_forward; scale_vector(&bounds[1], bb.min.z);
    1387             :                                                 bounds[2] = ship->v_right;           scale_vector(&bounds[2], bb.max.x);
    1388             :                                                 bounds[3] = ship->v_right;           scale_vector(&bounds[3], bb.min.x);
    1389             :                                                 bounds[4] = ship->v_up;                      scale_vector(&bounds[4], bb.max.y);
    1390             :                                                 bounds[5] = ship->v_up;                      scale_vector(&bounds[5], bb.min.y);
    1391             :                                                 // rotate the view
    1392             :                                                 int i;
    1393             :                                                 for (i = 0; i < 6; i++)
    1394             :                                                 {
    1395             :                                                         bounds[i] = OOVectorMultiplyMatrix(vector_add(bounds[i], rp), rotMatrix);
    1396             :                                                         if (nonlinear_scanner)
    1397             :                                                         {
    1398             :                                                                 bounds[i] = [HeadUpDisplay nonlinearScannerScale:bounds[i] Zoom: zoom Scale: 0.5*siz.width];
    1399             :                                                         }
    1400             :                                                         else
    1401             :                                                         {
    1402             :                                                                 scale_vector(&bounds[i], upscale);
    1403             :                                                         }
    1404             :                                                         bounds[i] = make_vector(bounds[i].x + scanner_cx, bounds[i].z * z_factor + bounds[i].y * y_factor + scanner_cy, z1 );
    1405             :                                                 }
    1406             :                                                 // draw the diamond
    1407             :                                                 //
    1408             :                                                 OOGLBEGIN(GL_QUADS);
    1409             :                                                         glColor4f(col[0], col[1], col[2], 0.33333 * col[3]);
    1410             :                                                         glVertex3f(bounds[0].x, bounds[0].y, bounds[0].z);      glVertex3f(bounds[4].x, bounds[4].y, bounds[4].z);
    1411             :                                                         glVertex3f(bounds[1].x, bounds[1].y, bounds[1].z);      glVertex3f(bounds[5].x, bounds[5].y, bounds[5].z);
    1412             :                                                         glVertex3f(bounds[2].x, bounds[2].y, bounds[2].z);      glVertex3f(bounds[4].x, bounds[4].y, bounds[4].z);
    1413             :                                                         glVertex3f(bounds[3].x, bounds[3].y, bounds[3].z);      glVertex3f(bounds[5].x, bounds[5].y, bounds[5].z);
    1414             :                                                         glVertex3f(bounds[2].x, bounds[2].y, bounds[2].z);      glVertex3f(bounds[0].x, bounds[0].y, bounds[0].z);
    1415             :                                                         glVertex3f(bounds[3].x, bounds[3].y, bounds[3].z);      glVertex3f(bounds[1].x, bounds[1].y, bounds[1].z);
    1416             :                                                 OOGLEND();
    1417             :                                         }
    1418             :                                 }
    1419             :                                 
    1420             :                                 if (ms_blip > 0.0)
    1421             :                                 {
    1422             :                                         DrawSpecialOval(x1 - 0.5, y2 + 1.5, z1, NSMakeSize(16.0 * (1.0 - ms_blip), 8.0 * (1.0 - ms_blip)), 30, col);
    1423             :                                 }
    1424             :                                 if ([scannedEntity isCascadeWeapon])
    1425             :                                 {
    1426             :                                         if (nonlinear_scanner)
    1427             :                                         {
    1428             :                                                 GLDrawNonlinearCascadeWeapon( scanner_cx, scanner_cy, z1, siz, rrp, scannedEntity->collision_radius, zoom, alpha );
    1429             :                                         }
    1430             :                                         else
    1431             :                                         {
    1432             :                                                 GLfloat r1 = 2.5 + scannedEntity->collision_radius * upscale;
    1433             :                                                 GLfloat l2 = r1 * r1 - relativePosition.y * relativePosition.y;
    1434             :                                                 GLfloat r0 = (l2 > 0)? sqrt(l2): 0;
    1435             :                                                 if (r0 > 0)
    1436             :                                                 {
    1437             :                                                         OOGL(glColor4f(1.0, 0.5, 1.0, alpha));
    1438             :                                                         GLDrawOval(x1  - 0.5, y1 + 1.5, z1, NSMakeSize(r0, r0 * siz.height / siz.width), 20);
    1439             :                                                 }
    1440             :                                                 OOGL(glColor4f(0.5, 0.0, 1.0, 0.33333 * alpha));
    1441             :                                                 GLDrawFilledOval(x1  - 0.5, y2 + 1.5, z1, NSMakeSize(r1, r1), 15);
    1442             :                                         }
    1443             :                                 }
    1444             :                                 else
    1445             :                                 {
    1446             : 
    1447             : #if IDENTIFY_SCANNER_LOLLIPOPS
    1448             :                                         if ([scannedEntity isShip])
    1449             :                                         {
    1450             :                                                 glColor4f(1.0, 1.0, 0.5, alpha);
    1451             :                                                 OODrawString([(ShipEntity *)scannedEntity displayName], x1 + 2, y2 + 2, z1, NSMakeSize(8, 8));
    1452             :                                         }
    1453             : #endif
    1454             :                                         glColor4fv(col);
    1455             :                                         if (inColorBlindMode && isHostile)
    1456             :                                         {
    1457             :                                                 // in colorblind mode turn hostile blips into X shapes for easier recognition
    1458             :                                                 OOGLBEGIN(GL_LINES);
    1459             :                                                 glVertex3f(x1+2, y2+3, z1);     glVertex3f(x1-3, y2, z1);       glVertex3f(x1+2, y2, z1);       glVertex3f(x1-3, y2+3, z1);
    1460             :                                                 OOGLEND();
    1461             :                                         }
    1462             :                                         else
    1463             :                                         {
    1464             :                                                 OOGLBEGIN(GL_QUADS);
    1465             :                                                 glVertex3f(x1-3, y2, z1);       glVertex3f(x1+2, y2, z1);       glVertex3f(x1+2, y2+3, z1);     glVertex3f(x1-3, y2+3, z1);     
    1466             :                                                 OOGLEND();
    1467             :                                         }
    1468             :                                         OOGLBEGIN(GL_QUADS); // lollipop tail
    1469             :                                                 col[3] *= 0.3333; // one third the alpha
    1470             :                                                 glColor4fv(col);
    1471             :                                                 glVertex3f(x1, y1, z1); glVertex3f(x1+2, y1, z1);       glVertex3f(x1+2, y2, z1);       glVertex3f(x1, y2, z1);
    1472             :                                         OOGLEND();
    1473             :                                 }
    1474             :                         }
    1475             :                 }
    1476             :                 
    1477             :         }
    1478             :         
    1479             :         for (i = 0; i < ent_count; i++)
    1480             :         {
    1481             :                 [my_entities[i] release];       //      released
    1482             :         }
    1483             :         
    1484             :         OOVerifyOpenGLState();
    1485             :         
    1486             : }
    1487             : 
    1488             : 
    1489             : - (BOOL) minimalisticScanner
    1490             : {
    1491             :         return minimalistic_scanner;
    1492             : }
    1493             : 
    1494             : 
    1495             : - (void) setMinimalisticScanner: (BOOL) newValue
    1496             : {
    1497             :         minimalistic_scanner = !!newValue;
    1498             : }
    1499             : 
    1500             : 
    1501             : + (Vector) nonlinearScannerScale: (Vector) V Zoom:(GLfloat)zoom Scale:(double) scale
    1502             : {
    1503             :         OOScalar mag = magnitude(V);
    1504             :         Vector unit = vector_normal(V);
    1505             :         return vector_multiply_scalar(unit, nonlinearScannerFunc(mag, zoom, scale));
    1506             : }
    1507             : 
    1508             : 
    1509             : - (BOOL) nonlinearScanner
    1510             : {
    1511             :         return nonlinear_scanner;
    1512             : }
    1513             : 
    1514             : 
    1515             : - (void) setNonlinearScanner: (BOOL) newValue
    1516             : {
    1517             :         nonlinear_scanner = !!newValue;
    1518             : }
    1519             : 
    1520             : 
    1521             : - (BOOL) scannerUltraZoom
    1522             : {
    1523             :         return scanner_ultra_zoom;
    1524             : }
    1525             : 
    1526             : 
    1527             : - (void) setScannerUltraZoom: (BOOL) newValue
    1528             : {
    1529             :         scanner_ultra_zoom = !!newValue;
    1530             : }
    1531             : 
    1532             : 
    1533             : - (void) refreshLastTransmitter
    1534             : {
    1535             :         Entity* lt = [UNIVERSE entityForUniversalID:last_transmitter];
    1536             :         if ((lt == nil)||(!(lt->isShip)))
    1537             :                 return;
    1538             :         ShipEntity* st = (ShipEntity*)lt;
    1539             :         if ([st messageTime] <= 0.0)
    1540             :                 [st setMessageTime:2.5];
    1541             : }
    1542             : 
    1543             : 
    1544           0 : - (void) drawScannerZoomIndicator:(NSDictionary *)info
    1545             : {
    1546             :         int                                     x, y;
    1547             :         NSSize                          siz;
    1548             :         GLfloat                         alpha;
    1549             :         GLfloat                         zoom_color[4] = { 1.0f, 0.1f, 0.0f, 1.0f };
    1550             :         struct CachedInfo       cached;
    1551             :         
    1552             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1553             :         
    1554             :         x = useDefined(cached.x, ZOOM_INDICATOR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1555             :         y = useDefined(cached.y, ZOOM_INDICATOR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1556             :         siz.width = useDefined(cached.width, ZOOM_INDICATOR_WIDTH);
    1557             :         siz.height = useDefined(cached.height, ZOOM_INDICATOR_HEIGHT);
    1558             :         
    1559             :         GetRGBAArrayFromInfo(info, zoom_color);
    1560             :         zoom_color[3] *= overallAlpha;
    1561             :         alpha = zoom_color[3];
    1562             :         
    1563             :         GLfloat cx = x - 0.3 * siz.width;
    1564             :         GLfloat cy = y - 0.75 * siz.height;
    1565             :         
    1566             :         int zl = scanner_zoom;
    1567             :         if (zl < 1) zl = 1;
    1568             :         if (zl > SCANNER_ZOOM_LEVELS) zl = SCANNER_ZOOM_LEVELS;
    1569             :         if (zl == 1) zoom_color[3] *= 0.75;
    1570             :         if (scanner_ultra_zoom)
    1571             :                 zl = pow(2, zl - 1);
    1572             :         GLColorWithOverallAlpha(zoom_color, alpha);
    1573             :         OOGL(glEnable(GL_TEXTURE_2D));
    1574             :         [sFontTexture apply];
    1575             :         
    1576             :         OOGLBEGIN(GL_QUADS);
    1577             :                 if (zl / 10 > 0)
    1578             :                         drawCharacterQuad(48 + zl / 10, cx - 0.8 * siz.width, cy, z1, siz);
    1579             :                 drawCharacterQuad(48 + zl % 10, cx - 0.4 * siz.width, cy, z1, siz);
    1580             :                 drawCharacterQuad(58, cx, cy, z1, siz);
    1581             :                 drawCharacterQuad(49, cx + 0.3 * siz.width, cy, z1, siz);
    1582             :         OOGLEND();
    1583             :         
    1584             :         [OOTexture applyNone];
    1585             :         OOGL(glDisable(GL_TEXTURE_2D));
    1586             : }
    1587             : 
    1588             : 
    1589           0 : - (void) drawCompass:(NSDictionary *)info
    1590             : {
    1591             :         int                                     x, y;
    1592             :         NSSize                          siz;
    1593             :         GLfloat                         alpha;
    1594             :         GLfloat                         compass_color[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
    1595             :         struct CachedInfo       cached;
    1596             :         
    1597             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1598             :         
    1599             :         x = useDefined(cached.x, COMPASS_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1600             :         y = useDefined(cached.y, COMPASS_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1601             :         siz.width = useDefined(cached.width, COMPASS_HALF_SIZE);
    1602             :         siz.height = useDefined(cached.height, COMPASS_HALF_SIZE);
    1603             :         
    1604             :         GetRGBAArrayFromInfo(info, compass_color);
    1605             :         compass_color[3] *= overallAlpha;
    1606             :         alpha = compass_color[3];
    1607             :         
    1608             :         // draw the compass
    1609             :         OOMatrix                rotMatrix = [PLAYER rotationMatrix];
    1610             :         
    1611             :         GLfloat h1 = siz.height * 0.125;
    1612             :         GLfloat h3 = siz.height * 0.375;
    1613             :         GLfloat w1 = siz.width * 0.125;
    1614             :         GLfloat w3 = siz.width * 0.375;
    1615             :         OOGL(GLScaledLineWidth(2.0 * lineWidth));       // thicker
    1616             :         OOGL(glColor4f(compass_color[0], compass_color[1], compass_color[2], alpha));
    1617             :         GLDrawOval(x, y, z1, siz, 12);  
    1618             :         OOGL(glColor4f(compass_color[0], compass_color[1], compass_color[2], 0.5f * alpha));
    1619             :         OOGLBEGIN(GL_LINES);
    1620             :                 glVertex3f(x - w1, y, z1);      glVertex3f(x - w3, y, z1);
    1621             :                 glVertex3f(x + w1, y, z1);      glVertex3f(x + w3, y, z1);
    1622             :                 glVertex3f(x, y - h1, z1);      glVertex3f(x, y - h3, z1);
    1623             :                 glVertex3f(x, y + h1, z1);      glVertex3f(x, y + h3, z1);
    1624             :         OOGLEND();
    1625             :         OOGL(GLScaledLineWidth(lineWidth));     // thinner
    1626             :         
    1627             :         if ([self checkPlayerInSystemFlight] && [PLAYER status] != STATUS_LAUNCHING) // normal system
    1628             :         {
    1629             :                 Entity *reference = [PLAYER compassTarget];
    1630             :                 
    1631             :                 // translate and rotate the view
    1632             : 
    1633             :                 Vector relativePosition = [PLAYER vectorTo:reference];
    1634             :                 relativePosition = OOVectorMultiplyMatrix(relativePosition, rotMatrix);
    1635             :                 relativePosition = vector_normal_or_fallback(relativePosition, kBasisZVector);
    1636             :                 
    1637             :                 relativePosition.x *= siz.width * 0.4;
    1638             :                 relativePosition.y *= siz.height * 0.4;
    1639             :                 relativePosition.x += x;
    1640             :                 relativePosition.y += y;
    1641             :                 
    1642             :                 siz.width *= 0.2;
    1643             :                 siz.height *= 0.2;
    1644             :                 OOGL(GLScaledLineWidth(2.0*lineWidth));
    1645             :                 switch ([PLAYER compassMode])
    1646             :                 {
    1647             :                         case COMPASS_MODE_INACTIVE:
    1648             :                                 break;
    1649             :                         
    1650             :                         case COMPASS_MODE_BASIC:
    1651             :                                 if ([reference isStation]) // validateCompassTarget in PlayerEntity.m changes COMPASS_BASIC_MODE target to the main station when inside the planetary aegis or in docking range of the main station
    1652             :                                         [self drawCompassStationBlipAt:relativePosition Size:siz Alpha:alpha];
    1653             :                                 else
    1654             :                                         [self drawCompassPlanetBlipAt:relativePosition Size:siz Alpha:alpha];
    1655             :                                 break;
    1656             :                                 
    1657             :                         case COMPASS_MODE_PLANET:
    1658             :                                 [self drawCompassPlanetBlipAt:relativePosition Size:siz Alpha:alpha];
    1659             :                                 break;
    1660             :                                 
    1661             :                         case COMPASS_MODE_STATION:
    1662             :                                 [self drawCompassStationBlipAt:relativePosition Size:siz Alpha:alpha];
    1663             :                                 break;
    1664             :                                 
    1665             :                         case COMPASS_MODE_SUN:
    1666             :                                 [self drawCompassSunBlipAt:relativePosition Size:siz Alpha:alpha];
    1667             :                                 break;
    1668             :                                 
    1669             :                         case COMPASS_MODE_TARGET:
    1670             :                                 [self drawCompassTargetBlipAt:relativePosition Size:siz Alpha:alpha];
    1671             :                                 break;
    1672             :                                 
    1673             :                         case COMPASS_MODE_BEACONS:
    1674             :                                 [self drawCompassBeaconBlipAt:relativePosition Size:siz Alpha:alpha];
    1675             :                                 Entity <OOBeaconEntity>           *beacon = [PLAYER nextBeacon];
    1676             :                                 [[beacon beaconDrawable] oo_drawHUDBeaconIconAt:NSMakePoint(x, y) size:siz alpha:alpha z:z1];
    1677             :                                 break;
    1678             :                 }
    1679             :                 OOGL(GLScaledLineWidth(lineWidth));     // reset
    1680             : 
    1681             :                 _compassUpdated = YES;
    1682             :                 _compassActive = YES;
    1683             :         }
    1684             : }
    1685             : 
    1686             : 
    1687           0 : OOINLINE void SetCompassBlipColor(GLfloat relativeZ, GLfloat alpha)
    1688             : {
    1689             :         if (relativeZ >= 0.0f)
    1690             :         {
    1691             :                 OOGL(glColor4f(0.0f, 1.0f, 0.0f, alpha));
    1692             :         }
    1693             :         else
    1694             :         {
    1695             :                 OOGL(glColor4f(1.0f, 0.0f, 0.0f, alpha));
    1696             :         }
    1697             : }
    1698             : 
    1699             : 
    1700           0 : - (void) drawCompassPlanetBlipAt:(Vector)relativePosition Size:(NSSize)siz Alpha:(GLfloat)alpha
    1701             : {
    1702             :         if (relativePosition.z >= 0)
    1703             :         {
    1704             :                 OOGL(glColor4f(0.0,1.0,0.0,0.75 * alpha));
    1705             :                 GLDrawFilledOval(relativePosition.x, relativePosition.y, z1, siz, 30);
    1706             :                 OOGL(glColor4f(0.0,1.0,0.0,alpha));
    1707             :                 GLDrawOval(relativePosition.x, relativePosition.y, z1, siz, 30);
    1708             :         }
    1709             :         else
    1710             :         {
    1711             :                 OOGL(glColor4f(1.0,0.0,0.0,alpha));
    1712             :                 GLDrawOval(relativePosition.x, relativePosition.y, z1, siz, 30);
    1713             :         }
    1714             : }
    1715             : 
    1716             : 
    1717           0 : - (void) drawCompassStationBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha
    1718             : {
    1719             :         SetCompassBlipColor(relativePosition.z, alpha);
    1720             :         
    1721             :         OOGLBEGIN(GL_LINE_LOOP);
    1722             :                 glVertex3f(relativePosition.x - 0.5 * siz.width, relativePosition.y - 0.5 * siz.height, z1);
    1723             :                 glVertex3f(relativePosition.x + 0.5 * siz.width, relativePosition.y - 0.5 * siz.height, z1);
    1724             :                 glVertex3f(relativePosition.x + 0.5 * siz.width, relativePosition.y + 0.5 * siz.height, z1);
    1725             :                 glVertex3f(relativePosition.x - 0.5 * siz.width, relativePosition.y + 0.5 * siz.height, z1);
    1726             :         OOGLEND();
    1727             : }
    1728             : 
    1729             : 
    1730           0 : - (void) drawCompassSunBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha
    1731             : {
    1732             :         OOGL(glColor4f(1.0, 1.0, 0.0, 0.75 * alpha));
    1733             :         GLDrawFilledOval(relativePosition.x, relativePosition.y, z1, siz, 30);
    1734             :         
    1735             :         SetCompassBlipColor(relativePosition.z, alpha);
    1736             :         
    1737             :         GLDrawOval(relativePosition.x, relativePosition.y, z1, siz, 30);
    1738             : }
    1739             : 
    1740             : 
    1741           0 : - (void) drawCompassTargetBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha
    1742             : {
    1743             :         SetCompassBlipColor(relativePosition.z, alpha);
    1744             :         
    1745             :         OOGLBEGIN(GL_LINES);
    1746             :                 glVertex3f(relativePosition.x - siz.width, relativePosition.y, z1);
    1747             :                 glVertex3f(relativePosition.x + siz.width, relativePosition.y, z1);
    1748             :                 glVertex3f(relativePosition.x, relativePosition.y - siz.height, z1);
    1749             :                 glVertex3f(relativePosition.x, relativePosition.y + siz.height, z1);
    1750             :         OOGLEND();
    1751             :         
    1752             :         GLDrawOval(relativePosition.x, relativePosition.y, z1, siz, 30);
    1753             : }
    1754             : 
    1755             : 
    1756           0 : - (void) drawCompassBeaconBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha
    1757             : {
    1758             :         SetCompassBlipColor(relativePosition.z, alpha);
    1759             :         
    1760             :         OOGLBEGIN(GL_LINES);
    1761             :         /*              glVertex3f(relativePosition.x - 0.5 * siz.width, relativePosition.y - 0.5 * siz.height, z1);
    1762             :                 glVertex3f(relativePosition.x, relativePosition.y + 0.5 * siz.height, z1);
    1763             :                 
    1764             :                 glVertex3f(relativePosition.x + 0.5 * siz.width, relativePosition.y - 0.5 * siz.height, z1);
    1765             :                 glVertex3f(relativePosition.x, relativePosition.y + 0.5 * siz.height, z1);
    1766             :                 
    1767             :                 glVertex3f(relativePosition.x - 0.5 * siz.width, relativePosition.y - 0.5 * siz.height, z1);
    1768             :                 glVertex3f(relativePosition.x + 0.5 * siz.width, relativePosition.y - 0.5 * siz.height, z1); */
    1769             :         glVertex3f(relativePosition.x + 0.6 * siz.width, relativePosition.y, z1);
    1770             :         glVertex3f(relativePosition.x, relativePosition.y + 0.6 * siz.height, z1);
    1771             : 
    1772             :         glVertex3f(relativePosition.x - 0.6 * siz.width, relativePosition.y, z1);
    1773             :         glVertex3f(relativePosition.x, relativePosition.y + 0.6 * siz.height, z1);
    1774             : 
    1775             :         glVertex3f(relativePosition.x + 0.6 * siz.width, relativePosition.y, z1);
    1776             :         glVertex3f(relativePosition.x, relativePosition.y - 0.6 * siz.height, z1);
    1777             : 
    1778             :         glVertex3f(relativePosition.x - 0.6 * siz.width, relativePosition.y, z1);
    1779             :         glVertex3f(relativePosition.x, relativePosition.y - 0.6 * siz.height, z1);
    1780             : 
    1781             :         OOGLEND();
    1782             : }
    1783             : 
    1784             : 
    1785           0 : - (void) drawAegis:(NSDictionary *)info
    1786             : {
    1787             :         if (([UNIVERSE viewDirection] == VIEW_GUI_DISPLAY)||([UNIVERSE sun] == nil)||([PLAYER checkForAegis] != AEGIS_IN_DOCKING_RANGE))
    1788             :                 return; // don't draw
    1789             :         
    1790             :         int                                     x, y;
    1791             :         NSSize                          siz;
    1792             :         GLfloat                         alpha = 0.5f * overallAlpha;
    1793             :         struct CachedInfo       cached;
    1794             :         
    1795             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1796             :         
    1797             :         x = useDefined(cached.x, AEGIS_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1798             :         y = useDefined(cached.y, AEGIS_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1799             :         siz.width = useDefined(cached.width, AEGIS_WIDTH);
    1800             :         siz.height = useDefined(cached.height, AEGIS_HEIGHT);
    1801             :         alpha *= cached.alpha;
    1802             :         
    1803             :         // draw the aegis indicator
    1804             :         //
    1805             :         GLfloat w = siz.width / 16.0;
    1806             :         GLfloat h = siz.height / 16.0;
    1807             :         
    1808             :         GLfloat strip[] = { -7,8, -6,5, 5,8, 3,5, 7,2, 4,2, 6,-1, 4,2, -4,-1, -6,2, -4,-1, -7,-1, -3,-4, -5,-7, 6,-4, 7,-7 };
    1809             :         
    1810             : #if 1
    1811             :         OOGL(glColor4f(0.0f, 1.0f, 0.0f, alpha));
    1812             :         OOGLBEGIN(GL_QUAD_STRIP);
    1813             :                 int i;
    1814             :                 for (i = 0; i < 32; i += 2)
    1815             :                 {
    1816             :                         glVertex3f(x + w * strip[i], y - h * strip[i + 1], z1);
    1817             :                 }
    1818             :         OOGLEND();
    1819             : #else
    1820             :         OOGLPushModelView();
    1821             :         OOGLTranslateModelView(make_vector(x, y, z1));
    1822             :         OOGLScaleModelView(make_vector(w, -h, 1.0f));
    1823             :         
    1824             :         OOGL(glColor4f(0.0f, 1.0f, 0.0f, alpha));
    1825             :         OOGL(glVertexPointer(2, GL_FLOAT, 0, strip));
    1826             :         OOGL(glEnableClientState(GL_VERTEX_ARRAY));
    1827             :         OOGL(glDisableClientState(GL_COLOR_ARRAY));
    1828             :         
    1829             :         OOGL(glDrawArrays(GL_QUAD_STRIP, 0, sizeof strip / sizeof *strip / 2));
    1830             :         OOGL(glDisableClientState(GL_VERTEX_ARRAY));
    1831             : 
    1832             :         OOGLPopModelView();
    1833             : #endif
    1834             : }
    1835             : 
    1836             : 
    1837           0 : - (void) drawCustomBar:(NSDictionary *)info
    1838             : {
    1839             :         int                                     x, y;
    1840             :         NSSize                          siz;
    1841             :         BOOL                            draw_surround;
    1842             :         GLfloat                         alpha = overallAlpha;
    1843             :         GLfloat                         ds = OOClamp_0_1_f([PLAYER dialCustomFloat:[info oo_stringForKey:CUSTOM_DIAL_KEY]]);
    1844             :         struct CachedInfo       cached;
    1845             :         
    1846             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1847             :         
    1848             :         x = useDefined(cached.x, 0) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1849             :         y = useDefined(cached.y, 0) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1850             :         siz.width = useDefined(cached.width, 50);
    1851             :         siz.height = useDefined(cached.height, 8);
    1852             :         alpha *= cached.alpha;
    1853             :         
    1854             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:NO];
    1855             :         
    1856             :         SET_COLOR_SURROUND(green_color);
    1857             :         if (draw_surround)
    1858             :         {
    1859             :                 // draw custom surround
    1860             :                 hudDrawSurroundAt(x, y, z1, siz);
    1861             :         }
    1862             :         // draw custom bar
    1863             :         if (ds > .75)
    1864             :         {
    1865             :                 SET_COLOR_HIGH(green_color);
    1866             :         }
    1867             :         else if (ds > .25)
    1868             :         {
    1869             :                 SET_COLOR_MEDIUM(yellow_color);
    1870             :         }
    1871             :         else
    1872             :         {
    1873             :                 SET_COLOR_LOW(red_color);
    1874             :         }
    1875             : 
    1876             :         hudDrawBarAt(x, y, z1, siz, ds);
    1877             : }
    1878             : 
    1879             : 
    1880           0 : - (void) drawCustomText:(NSDictionary *)info
    1881             : {
    1882             :         int                                     x, y;
    1883             :         NSSize                          size;
    1884             :         GLfloat                         alpha = overallAlpha;
    1885             :         NSString                        *text = [PLAYER dialCustomString:[info oo_stringForKey:CUSTOM_DIAL_KEY]];
    1886             :         struct CachedInfo       cached;
    1887             :         
    1888             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1889             :         
    1890             :         x = useDefined(cached.x, 0) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1891             :         y = useDefined(cached.y, 0) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1892             :         alpha *= cached.alpha;
    1893             :         
    1894             :         SET_COLOR(yellow_color);
    1895             : 
    1896             :         size.width = useDefined(cached.width, 10.0f);
    1897             :         size.height = useDefined(cached.height, 10.0f);
    1898             : 
    1899             :         if ([info oo_intForKey:@"align"] == 1)
    1900             :         {
    1901             :                 OODrawStringAligned(text, x, y, z1, size, YES);
    1902             :         }
    1903             :         else
    1904             :         {
    1905             :                 OODrawStringAligned(text, x, y, z1, size, NO);
    1906             :         }
    1907             : 
    1908             : }
    1909             : 
    1910             : 
    1911           0 : - (void) drawCustomIndicator:(NSDictionary *)info
    1912             : {
    1913             :         int                                     x, y;
    1914             :         NSSize                          siz;
    1915             :         BOOL                            draw_surround;
    1916             :         GLfloat                         alpha = overallAlpha;
    1917             :         GLfloat                         iv = OOClamp_n1_1_f([PLAYER dialCustomFloat:[info oo_stringForKey:CUSTOM_DIAL_KEY]]);
    1918             : 
    1919             :         struct CachedInfo       cached;
    1920             :         
    1921             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1922             :         
    1923             :         x = useDefined(cached.x, 0) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1924             :         y = useDefined(cached.y, 0) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1925             :         siz.width = useDefined(cached.width, 50);
    1926             :         siz.height = useDefined(cached.height, 8);
    1927             :         alpha *= cached.alpha;
    1928             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:NO];
    1929             :         
    1930             :         if (draw_surround)
    1931             :         {
    1932             :                 // draw custom surround
    1933             :                 SET_COLOR_SURROUND(green_color);
    1934             :                 hudDrawSurroundAt(x, y, z1, siz);
    1935             :         }
    1936             :         // draw custom indicator
    1937             :         SET_COLOR(yellow_color);
    1938             :         hudDrawIndicatorAt(x, y, z1, siz, iv);
    1939             : }
    1940             : 
    1941             : 
    1942           0 : - (void) drawCustomLight:(NSDictionary *)info
    1943             : {
    1944             :         int                                     x, y;
    1945             :         NSSize                          siz;
    1946             :         GLfloat                         alpha = overallAlpha;
    1947             : 
    1948             :         struct CachedInfo       cached;
    1949             :         
    1950             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1951             :         
    1952             :         x = useDefined(cached.x, 0) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1953             :         y = useDefined(cached.y, 0) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1954             :         siz.width = useDefined(cached.width, 8);
    1955             :         siz.height = useDefined(cached.height, 8);
    1956             :         alpha *= cached.alpha;
    1957             :         
    1958             :         GLfloat light_color[4] = { 0.25, 0.25, 0.25, 0.0};
    1959             :         
    1960             :         OOColor *color = [PLAYER dialCustomColor:[info oo_stringForKey:CUSTOM_DIAL_KEY]];
    1961             :         [color getRed:&light_color[0]
    1962             :                         green:&light_color[1]
    1963             :                          blue:&light_color[2]
    1964             :                         alpha:&light_color[3]];
    1965             : 
    1966             :         GLColorWithOverallAlpha(light_color, alpha);
    1967             :         OOGLBEGIN(GL_POLYGON);
    1968             :         hudDrawStatusIconAt(x, y, z1, siz);
    1969             :         OOGLEND();
    1970             :         OOGL(glColor4f(0.25, 0.25, 0.25, alpha));
    1971             :         OOGLBEGIN(GL_LINE_LOOP);
    1972             :                 hudDrawStatusIconAt(x, y, z1, siz);
    1973             :         OOGLEND();
    1974             : }
    1975             : 
    1976             : 
    1977           0 : - (void) drawCustomImage:(NSDictionary *)info
    1978             : {
    1979             :         int                                     x, y;
    1980             :         GLfloat                         alpha = overallAlpha;
    1981             : 
    1982             :         struct CachedInfo       cached;
    1983             :         
    1984             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    1985             :         
    1986             :         x = useDefined(cached.x, 0) + [[UNIVERSE gameView] x_offset] * cached.x0;
    1987             :         y = useDefined(cached.y, 0) + [[UNIVERSE gameView] y_offset] * cached.y0;
    1988             :         alpha *= cached.alpha;
    1989             : 
    1990             :         NSString *textureFile = [PLAYER dialCustomString:[info oo_stringForKey:CUSTOM_DIAL_KEY]];
    1991             :         if (textureFile == nil || [textureFile length] == 0) {
    1992             :                 return;
    1993             :         }
    1994             : 
    1995             :         OOTexture *texture = [OOTexture textureWithName:textureFile
    1996             :                                                                                    inFolder:@"Images"
    1997             :                                                                                         options:kOOTextureDefaultOptions | kOOTextureNoShrink
    1998             :                                                                                  anisotropy:kOOTextureDefaultAnisotropy
    1999             :                                                                                         lodBias:kOOTextureDefaultLODBias];
    2000             :         if (texture == nil)
    2001             :         {
    2002             :                 OOLogERR(kOOLogFileNotFound, @"HeadUpDisplay couldn't get an image texture name for %@", textureFile);
    2003             :                 return;
    2004             :         }
    2005             :                 
    2006             :         NSSize imageSize = [texture dimensions];
    2007             :         imageSize.width = useDefined(cached.width, imageSize.width);
    2008             :         imageSize.height = useDefined(cached.height, imageSize.height);
    2009             : 
    2010             :         /* There's possibly some optimisation which could be done by
    2011             :          * caching the sprite, but regenerating it each frame doesn't
    2012             :          * appear to take any significant amount of time compared with the
    2013             :          * time taken to actually render it and the texture will be
    2014             :          * returned from the cache anyway. - CIM */
    2015             :         OOTextureSprite *sprite = [[OOTextureSprite alloc] initWithTexture:texture size:imageSize];
    2016             : 
    2017             :         [sprite blitCentredToX:x Y:y Z:z1 alpha:alpha];
    2018             :         [sprite release];
    2019             : 
    2020             : }
    2021             : 
    2022             : 
    2023           0 : - (void) drawSpeedBar:(NSDictionary *)info
    2024             : {
    2025             :         int                                     x, y;
    2026             :         NSSize                          siz;
    2027             :         BOOL                            draw_surround;
    2028             :         GLfloat                         alpha = overallAlpha;
    2029             :         GLfloat                         ds = [PLAYER dialSpeed];
    2030             :         struct CachedInfo       cached;
    2031             :         
    2032             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2033             :         
    2034             :         x = useDefined(cached.x, SPEED_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2035             :         y = useDefined(cached.y, SPEED_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2036             :         siz.width = useDefined(cached.width, SPEED_BAR_WIDTH);
    2037             :         siz.height = useDefined(cached.height, SPEED_BAR_HEIGHT);
    2038             :         alpha *= cached.alpha;
    2039             :         
    2040             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:SPEED_BAR_DRAW_SURROUND];
    2041             :         
    2042             :         
    2043             :         SET_COLOR_SURROUND(green_color);
    2044             :         if (draw_surround)
    2045             :         {
    2046             :                 // draw speed surround
    2047             :                 hudDrawSurroundAt(x, y, z1, siz);
    2048             :         }
    2049             :         // draw speed bar
    2050             :         if (ds > .80)
    2051             :         {
    2052             :                 SET_COLOR_HIGH(red_color);
    2053             :         }
    2054             :         else if (ds > .25)
    2055             :         {
    2056             :                 SET_COLOR_MEDIUM(yellow_color);
    2057             :         }
    2058             :         else
    2059             :         {
    2060             :                 SET_COLOR_LOW(green_color);
    2061             :         }
    2062             : 
    2063             :         hudDrawBarAt(x, y, z1, siz, ds);
    2064             : }
    2065             : 
    2066             : 
    2067           0 : - (void) drawRollBar:(NSDictionary *)info
    2068             : {
    2069             :         int                                     x, y;
    2070             :         NSSize                          siz;
    2071             :         BOOL                            draw_surround;
    2072             :         GLfloat                         alpha = overallAlpha;
    2073             :         struct CachedInfo       cached;
    2074             :         
    2075             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2076             :         
    2077             :         x = useDefined(cached.x, ROLL_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2078             :         y = useDefined(cached.y, ROLL_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2079             :         siz.width = useDefined(cached.width, ROLL_BAR_WIDTH);
    2080             :         siz.height = useDefined(cached.height, ROLL_BAR_HEIGHT);
    2081             :         alpha *= cached.alpha;
    2082             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:ROLL_BAR_DRAW_SURROUND];
    2083             :         
    2084             :         if (draw_surround)
    2085             :         {
    2086             :                 // draw ROLL surround
    2087             :                 SET_COLOR_SURROUND(green_color);
    2088             :                 hudDrawSurroundAt(x, y, z1, siz);
    2089             :         }
    2090             :         // draw ROLL bar
    2091             :         SET_COLOR(yellow_color);
    2092             :         hudDrawIndicatorAt(x, y, z1, siz, [PLAYER dialRoll]);
    2093             : }
    2094             : 
    2095             : 
    2096           0 : - (void) drawPitchBar:(NSDictionary *)info
    2097             : {
    2098             :         int                                     x, y;
    2099             :         NSSize                          siz;
    2100             :         BOOL                            draw_surround;
    2101             :         GLfloat                         alpha = overallAlpha;
    2102             :         struct CachedInfo       cached;
    2103             :         
    2104             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2105             :         
    2106             :         x = useDefined(cached.x, PITCH_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2107             :         y = useDefined(cached.y, PITCH_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2108             :         siz.width = useDefined(cached.width, PITCH_BAR_WIDTH);
    2109             :         siz.height = useDefined(cached.height, PITCH_BAR_HEIGHT);
    2110             :         alpha *= cached.alpha;
    2111             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:PITCH_BAR_DRAW_SURROUND];
    2112             :         
    2113             :         if (draw_surround)
    2114             :         {
    2115             :                 // draw PITCH surround
    2116             :                 SET_COLOR_SURROUND(green_color);
    2117             :                 hudDrawSurroundAt(x, y, z1, siz);
    2118             :         }
    2119             :         // draw PITCH bar
    2120             :         SET_COLOR(yellow_color);
    2121             :         hudDrawIndicatorAt(x, y, z1, siz, [PLAYER dialPitch]);
    2122             : }
    2123             : 
    2124             : 
    2125           0 : - (void) drawYawBar:(NSDictionary *)info
    2126             : {
    2127             :         int                                     x, y;
    2128             :         NSSize                          siz;
    2129             :         BOOL                            draw_surround;
    2130             :         GLfloat                         alpha = overallAlpha;
    2131             :         struct CachedInfo       cached;
    2132             :         
    2133             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2134             :         
    2135             :         // No standard YAW definitions - using PITCH ones instead.
    2136             :         x = useDefined(cached.x, PITCH_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2137             :         y = useDefined(cached.y, PITCH_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2138             :         siz.width = useDefined(cached.width, PITCH_BAR_WIDTH);
    2139             :         siz.height = useDefined(cached.height, PITCH_BAR_HEIGHT);
    2140             :         alpha *= cached.alpha;
    2141             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:PITCH_BAR_DRAW_SURROUND];
    2142             :         
    2143             :         if (draw_surround)
    2144             :         {
    2145             :                 // draw YAW surround
    2146             :                 SET_COLOR_SURROUND(green_color);
    2147             :                 hudDrawSurroundAt(x, y, z1, siz);
    2148             :         }
    2149             :         // draw YAW bar
    2150             :         SET_COLOR(yellow_color);
    2151             :         hudDrawIndicatorAt(x, y, z1, siz, [PLAYER dialYaw]);
    2152             : }
    2153             : 
    2154             : 
    2155           0 : - (void) drawEnergyGauge:(NSDictionary *)info
    2156             : {
    2157             :         int                                     x, y;
    2158             :         unsigned                        i;
    2159             :         NSSize                          siz;
    2160             :         BOOL                            drawSurround, labelled, energyCritical = NO;
    2161             :         GLfloat                         alpha = overallAlpha;
    2162             :         GLfloat                         bankHeight, bankY;
    2163             :         PlayerEntity *player = PLAYER;
    2164             : 
    2165             :         unsigned n_bars = [player dialMaxEnergy]/64.0;
    2166             :         n_bars = [info oo_unsignedIntForKey:N_BARS_KEY defaultValue:n_bars];
    2167             :         if (n_bars < 1)
    2168             :         {
    2169             :                 n_bars = 1;
    2170             :         }
    2171             :         GLfloat                         energy = [player dialEnergy] * n_bars;
    2172             :         struct CachedInfo       cached;
    2173             :         
    2174             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2175             :         
    2176             :         x = useDefined(cached.x, ENERGY_GAUGE_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2177             :         y = useDefined(cached.y, ENERGY_GAUGE_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2178             :         siz.width = useDefined(cached.width, ENERGY_GAUGE_WIDTH);
    2179             :         siz.height = useDefined(cached.height, ENERGY_GAUGE_HEIGHT);
    2180             :         alpha *= cached.alpha;
    2181             :         drawSurround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:ENERGY_GAUGE_DRAW_SURROUND];
    2182             :         labelled = [info oo_boolForKey:LABELLED_KEY defaultValue:YES];
    2183             :         if (n_bars > 8)  labelled = NO;
    2184             :         
    2185             :         if (drawSurround)
    2186             :         {
    2187             :                 // draw energy surround
    2188             :                 SET_COLOR_SURROUND(yellow_color);
    2189             :                 hudDrawSurroundAt(x, y, z1, siz);
    2190             :         }
    2191             :         
    2192             :         bankHeight = siz.height / n_bars;
    2193             :         // draw energy banks    
    2194             :         NSSize barSize = NSMakeSize(siz.width, bankHeight - 2.0);               // leave a gap between bars
    2195             :         GLfloat midBank = bankHeight / 2.0f;
    2196             :         bankY = y - (n_bars - 1) * midBank - 1.0;
    2197             :         
    2198             :         // avoid constant colour switching...
    2199             :         if (labelled)
    2200             :         {
    2201             :                 GLColorWithOverallAlpha(green_color, alpha);
    2202             :                 GLfloat labelStartX = x + 0.5f * barSize.width + 3.0f;
    2203             :                 NSSize labelSize = NSMakeSize(9.0, (bankHeight < 18.0)? bankHeight : 18.0);
    2204             :                 for (i = 0; i < n_bars; i++)
    2205             :                 {
    2206             :                         OODrawString([NSString stringWithFormat:@"E%x", n_bars - i], labelStartX, bankY - midBank, z1, labelSize);
    2207             :                         bankY += bankHeight;
    2208             :                 }
    2209             :         }
    2210             :         
    2211             :         if (energyCritical)
    2212             :         {
    2213             :                 SET_COLOR_LOW(red_color);
    2214             :         }
    2215             :         else
    2216             :         {
    2217             :                 SET_COLOR_MEDIUM(yellow_color);
    2218             :         }
    2219             :         bankY = y - (n_bars - 1) * midBank;
    2220             :         for (i = 0; i < n_bars; i++)
    2221             :         {
    2222             :                 if (energy > 1.0)
    2223             :                 {
    2224             :                         hudDrawBarAt(x, bankY, z1, barSize, 1.0);
    2225             :                 }
    2226             :                 else if (energy > 0.0)
    2227             :                 {
    2228             :                         hudDrawBarAt(x, bankY, z1, barSize, energy);
    2229             :                 }
    2230             :                 
    2231             :                 energy -= 1.0;
    2232             :                 bankY += bankHeight;
    2233             :         }
    2234             : }
    2235             : 
    2236             : 
    2237           0 : - (void) drawForwardShieldBar:(NSDictionary *)info
    2238             : {
    2239             :         int                                     x, y;
    2240             :         NSSize                          siz;
    2241             :         BOOL                            draw_surround;
    2242             :         GLfloat                         alpha = overallAlpha;
    2243             :         GLfloat                         shield = [PLAYER dialForwardShield];
    2244             :         struct CachedInfo       cached;
    2245             :         
    2246             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2247             :         
    2248             :         x = useDefined(cached.x, FORWARD_SHIELD_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2249             :         y = useDefined(cached.y, FORWARD_SHIELD_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2250             :         siz.width = useDefined(cached.width, FORWARD_SHIELD_BAR_WIDTH);
    2251             :         siz.height = useDefined(cached.height, FORWARD_SHIELD_BAR_HEIGHT);
    2252             :         alpha *= cached.alpha;
    2253             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:FORWARD_SHIELD_BAR_DRAW_SURROUND];
    2254             :         
    2255             :         if (draw_surround)
    2256             :         {
    2257             :                 // draw forward_shield surround
    2258             :                 SET_COLOR_SURROUND(green_color);
    2259             :                 hudDrawSurroundAt(x, y, z1, siz);
    2260             :         }
    2261             :         // draw forward_shield bar
    2262             :         if (shield < .25)
    2263             :         {
    2264             :                 SET_COLOR_LOW(red_color);
    2265             :         }
    2266             :         else if (shield < .80)
    2267             :         {
    2268             :                 SET_COLOR_MEDIUM(yellow_color);
    2269             :         } 
    2270             :         else
    2271             :         {
    2272             :                 SET_COLOR_HIGH(green_color);
    2273             :         }
    2274             :         hudDrawBarAt(x, y, z1, siz, shield);
    2275             : }
    2276             : 
    2277             : 
    2278           0 : - (void) drawAftShieldBar:(NSDictionary *)info
    2279             : {
    2280             :         int                                     x, y;
    2281             :         NSSize                          siz;
    2282             :         BOOL                            draw_surround;
    2283             :         GLfloat                         alpha = overallAlpha;
    2284             :         GLfloat                         shield = [PLAYER dialAftShield];
    2285             :         struct CachedInfo       cached;
    2286             :         
    2287             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2288             :         
    2289             :         x = useDefined(cached.x, AFT_SHIELD_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2290             :         y = useDefined(cached.y, AFT_SHIELD_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2291             :         siz.width = useDefined(cached.width, AFT_SHIELD_BAR_WIDTH);
    2292             :         siz.height = useDefined(cached.height, AFT_SHIELD_BAR_HEIGHT);
    2293             :         alpha *= cached.alpha;
    2294             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:AFT_SHIELD_BAR_DRAW_SURROUND];
    2295             :         
    2296             :         if (draw_surround)
    2297             :         {
    2298             :                 // draw forward_shield surround
    2299             :                 SET_COLOR_SURROUND(green_color);
    2300             :                 hudDrawSurroundAt(x, y, z1, siz);
    2301             :         }
    2302             :         // draw forward_shield bar
    2303             :         if (shield < .25)
    2304             :         {
    2305             :                 SET_COLOR_LOW(red_color);
    2306             :         }
    2307             :         else if (shield < .80)
    2308             :         {
    2309             :                 SET_COLOR_MEDIUM(yellow_color);
    2310             :         } 
    2311             :         else
    2312             :         {
    2313             :                 SET_COLOR_HIGH(green_color);
    2314             :         }
    2315             :         hudDrawBarAt(x, y, z1, siz, shield);
    2316             : }
    2317             : 
    2318             : 
    2319           0 : - (void) drawFuelBar:(NSDictionary *)info
    2320             : {
    2321             :         int                                     x, y;
    2322             :         NSSize                          siz;
    2323             :         BOOL                            draw_surround;
    2324             :         float                           fu, hr;
    2325             :         GLfloat                         alpha = overallAlpha;
    2326             :         struct CachedInfo       cached;
    2327             :         
    2328             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2329             :         
    2330             :         x = useDefined(cached.x, FUEL_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2331             :         y = useDefined(cached.y, FUEL_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2332             :         siz.width = useDefined(cached.width, FUEL_BAR_WIDTH);
    2333             :         siz.height = useDefined(cached.height, FUEL_BAR_HEIGHT);
    2334             :         alpha *= cached.alpha;
    2335             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:NO];
    2336             :         
    2337             :         if (draw_surround)
    2338             :         {
    2339             :                 SET_COLOR_SURROUND(green_color);
    2340             :                 hudDrawSurroundAt(x, y, z1, siz);
    2341             :         }
    2342             :         
    2343             :         fu = [PLAYER dialFuel];
    2344             :         hr = [PLAYER dialHyperRange];
    2345             :         
    2346             :         // draw fuel bar
    2347             :         SET_COLOR_MEDIUM(yellow_color);
    2348             :         hudDrawBarAt(x, y, z1, siz, fu);
    2349             :         
    2350             :         // draw range indicator
    2351             :         if (hr > 0.0f && hr <= 1.0f)
    2352             :         {
    2353             :                 if ([PLAYER hasSufficientFuelForJump])
    2354             :                 {
    2355             :                         SET_COLOR_HIGH(green_color);
    2356             :                 }
    2357             :                 else
    2358             :                 {
    2359             :                         SET_COLOR_LOW(red_color);
    2360             :                 }
    2361             :                 hudDrawMarkerAt(x, y, z1, siz, hr);
    2362             :         }
    2363             : 
    2364             : }
    2365             : 
    2366             : 
    2367           0 : - (void) drawWitchspaceDestination:(NSDictionary *)info
    2368             : {
    2369             :         // A zero-distance jump counts as 0.1LY
    2370             :         if ([PLAYER dialHyperRange] == 0.0f)
    2371             :         {
    2372             :                 return;
    2373             :         }
    2374             : 
    2375             :         int                                     x, y;
    2376             :         NSSize                          siz;
    2377             :         GLfloat                         alpha = overallAlpha;
    2378             : 
    2379             :         struct CachedInfo       cached;
    2380             : 
    2381             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2382             :         
    2383             :         x = useDefined(cached.x, WITCHDEST_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2384             :         y = useDefined(cached.y, WITCHDEST_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2385             :         siz.width = useDefined(cached.width, WITCHDEST_WIDTH);
    2386             :         siz.height = useDefined(cached.height, WITCHDEST_HEIGHT);
    2387             :         alpha *= cached.alpha;
    2388             :         NSString *dest = [UNIVERSE getSystemName:[PLAYER targetSystemID]];
    2389             :         NSInteger concealment = [[[UNIVERSE systemManager] getPropertiesForSystem:[PLAYER targetSystemID] inGalaxy:[PLAYER galaxyNumber]] oo_intForKey:@"concealment" defaultValue:OO_SYSTEMCONCEALMENT_NONE];
    2390             :         if (concealment >= OO_SYSTEMCONCEALMENT_NONAME) dest = DESC(@"status-unknown-system");
    2391             : 
    2392             :         SET_COLOR(green_color);
    2393             :         
    2394             :         if ([info oo_intForKey:@"align"] == 1)
    2395             :         {
    2396             :                 OODrawStringAligned(dest, x, y, z1, siz, YES);
    2397             :         }
    2398             :         else
    2399             :         {
    2400             :                 OODrawStringAligned(dest, x, y, z1, siz, NO);
    2401             :         }
    2402             : 
    2403             : }
    2404             : 
    2405             : 
    2406           0 : - (void) drawCabinTempBar:(NSDictionary *)info
    2407             : {
    2408             :         int                                     x, y;
    2409             :         NSSize                          siz;
    2410             :         BOOL                            draw_surround;
    2411             :         GLfloat                         temp = [PLAYER hullHeatLevel];
    2412             :         GLfloat                         alpha = overallAlpha;
    2413             :         struct CachedInfo       cached;
    2414             :         
    2415             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2416             :         
    2417             :         x = useDefined(cached.x, CABIN_TEMP_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2418             :         y = useDefined(cached.y, CABIN_TEMP_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2419             :         siz.width = useDefined(cached.width, CABIN_TEMP_BAR_WIDTH);
    2420             :         siz.height = useDefined(cached.height, CABIN_TEMP_BAR_HEIGHT);
    2421             :         alpha *= cached.alpha;
    2422             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:NO];
    2423             :         
    2424             :         if (draw_surround)
    2425             :         {
    2426             :                 SET_COLOR_SURROUND(green_color);
    2427             :                 hudDrawSurroundAt(x, y, z1, siz);
    2428             :         }
    2429             :         
    2430             :         int flash = (int)([UNIVERSE getTime] * 4);
    2431             :         flash &= 1;
    2432             :         // what color are we?
    2433             :         if (temp > .80)
    2434             :         {
    2435             :                 if (temp > .90 && flash)
    2436             :                         SET_COLOR_CRITICAL(redplus_color);
    2437             :                 else
    2438             :                         SET_COLOR_HIGH(red_color);
    2439             :         }
    2440             :         else
    2441             :         {
    2442             :                 if (temp > .25)
    2443             :                         SET_COLOR_MEDIUM(yellow_color);
    2444             :                 else
    2445             :                         SET_COLOR_LOW(green_color);
    2446             :         }
    2447             : 
    2448             :         
    2449             :         hudDrawBarAt(x, y, z1, siz, temp);
    2450             : }
    2451             : 
    2452             : 
    2453           0 : - (void) drawWeaponTempBar:(NSDictionary *)info
    2454             : {
    2455             :         int                                     x, y;
    2456             :         NSSize                          siz;
    2457             :         BOOL                            draw_surround;
    2458             :         GLfloat                         temp = [PLAYER laserHeatLevel];
    2459             :         GLfloat                         alpha = overallAlpha;
    2460             :         struct CachedInfo       cached;
    2461             :         
    2462             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2463             :         
    2464             :         x = useDefined(cached.x, WEAPON_TEMP_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2465             :         y = useDefined(cached.y, WEAPON_TEMP_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2466             :         siz.width = useDefined(cached.width, WEAPON_TEMP_BAR_WIDTH);
    2467             :         siz.height = useDefined(cached.height, WEAPON_TEMP_BAR_HEIGHT);
    2468             :         alpha *= cached.alpha;
    2469             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:NO];
    2470             :         
    2471             :         if (draw_surround)
    2472             :         {
    2473             :                 SET_COLOR_SURROUND(green_color);
    2474             :                 hudDrawSurroundAt(x, y, z1, siz);
    2475             :         }
    2476             :         
    2477             :         // draw weapon_temp bar (only need to call GLColor() once!)
    2478             :         if (temp > .80)
    2479             :                 SET_COLOR_HIGH(red_color);
    2480             :         else if (temp > .25)
    2481             :                 SET_COLOR_MEDIUM(yellow_color);
    2482             :         else
    2483             :                 SET_COLOR_LOW(green_color);
    2484             :         hudDrawBarAt(x, y, z1, siz, temp);
    2485             : }
    2486             : 
    2487             : 
    2488           0 : - (void) drawAltitudeBar:(NSDictionary *)info
    2489             : {
    2490             :         int                                     x, y;
    2491             :         NSSize                          siz;
    2492             :         BOOL                            draw_surround;
    2493             :         GLfloat                         alt = [PLAYER dialAltitude];
    2494             :         GLfloat                         alpha = overallAlpha;
    2495             :         struct CachedInfo       cached;
    2496             :         
    2497             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2498             :         
    2499             :         x = useDefined(cached.x, ALTITUDE_BAR_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2500             :         y = useDefined(cached.y, ALTITUDE_BAR_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2501             :         siz.width = useDefined(cached.width, ALTITUDE_BAR_WIDTH);
    2502             :         siz.height = useDefined(cached.height, ALTITUDE_BAR_HEIGHT);
    2503             :         alpha *= cached.alpha;
    2504             :         draw_surround = [info oo_boolForKey:DRAW_SURROUND_KEY defaultValue:NO];
    2505             :         
    2506             :         if (draw_surround)
    2507             :         {
    2508             :                 SET_COLOR_SURROUND(yellow_color);
    2509             :                 hudDrawSurroundAt(x, y, z1, siz);
    2510             :         }
    2511             :         
    2512             :         int flash = (int)([UNIVERSE getTime] * 4);
    2513             :         flash &= 1;
    2514             :         
    2515             :         // draw altitude bar (evaluating the least amount of ifs per go)
    2516             :         if (alt < .25)
    2517             :         {
    2518             :                 if (alt < .10 && flash)
    2519             :                         SET_COLOR_CRITICAL(redplus_color);
    2520             :                 else
    2521             :                         SET_COLOR_HIGH(red_color);
    2522             :         }
    2523             :         else
    2524             :         {
    2525             :                 if (alt < .75)
    2526             :                         SET_COLOR_MEDIUM(yellow_color);
    2527             :                 else
    2528             :                         SET_COLOR_LOW(green_color);
    2529             :         }
    2530             :         
    2531             :         hudDrawBarAt(x, y, z1, siz, alt);
    2532             :         
    2533             : }
    2534             : 
    2535             : 
    2536           0 : static NSString * const kDefaultMissileIconKey = @"oolite-default-missile-icon";
    2537           0 : static NSString * const kDefaultMineIconKey = @"oolite-default-mine-icon";
    2538           0 : static const GLfloat kOutlineWidth = 0.5f;
    2539             : 
    2540             : 
    2541           0 : static OOPolygonSprite *IconForMissileRole(NSString *role)
    2542             : {
    2543             :         static NSMutableDictionary      *sIcons = nil;
    2544             :         OOPolygonSprite                         *result = nil;
    2545             :         
    2546             :         result = [sIcons objectForKey:role];
    2547             :         if (result == nil)
    2548             :         {
    2549             :                 NSString *key = role;
    2550             :                 NSArray *iconDef = [[UNIVERSE descriptions] oo_arrayForKey:key];
    2551             :                 if (iconDef != nil)  result = [[OOPolygonSprite alloc] initWithDataArray:iconDef outlineWidth:kOutlineWidth name:key];
    2552             :                 if (result == nil)      // No custom icon or bad data
    2553             :                 {
    2554             :                         /*      Backwards compatibility note:
    2555             :                                 The old implementation used suffixes "MISSILE" and "MINE" (without
    2556             :                                 the underscore), and didn't draw anything if neither was found. I
    2557             :                                 believe any difference in practical behavour due to the change here
    2558             :                                 will be positive.
    2559             :                                 -- Ahruman 2009-10-09
    2560             :                         */
    2561             :                         if ([role hasSuffix:@"_MISSILE"])  key = kDefaultMissileIconKey;
    2562             :                         else  key = kDefaultMineIconKey;
    2563             :                         
    2564             :                         iconDef = [[UNIVERSE descriptions] oo_arrayForKey:key];
    2565             :                         result = [[OOPolygonSprite alloc] initWithDataArray:iconDef outlineWidth:kOutlineWidth name:key];
    2566             :                 }
    2567             :                 
    2568             :                 if (result != nil)
    2569             :                 {
    2570             :                         if (sIcons == nil)  sIcons = [[NSMutableDictionary alloc] init];
    2571             :                         [sIcons setObject:result forKey:role];
    2572             :                         [result release];       // Balance alloc
    2573             :                 }
    2574             :         }
    2575             :         
    2576             :         return result;
    2577             : }
    2578             : 
    2579             : 
    2580           0 : - (void) drawIconForMissile:(ShipEntity *)missile
    2581             :                                    selected:(BOOL)selected
    2582             :                                          status:(OOMissileStatus)status
    2583             :                                                   x:(int)x y:(int)y
    2584             :                                           width:(GLfloat)width height:(GLfloat)height alpha:(GLfloat)alpha
    2585             : {
    2586             :         OOPolygonSprite *sprite = IconForMissileRole([missile primaryRole]);
    2587             :         
    2588             :         if (selected)
    2589             :         {
    2590             :                 // Draw yellow outline.
    2591             :                 OOGLPushModelView();
    2592             :                 OOGLTranslateModelView(make_vector(x - width * 2.0f, y - height * 2.0f, z1));
    2593             :                 OOGLScaleModelView(make_vector(width, height, 1.0f));
    2594             :                 GLColorWithOverallAlpha(yellow_color, alpha);
    2595             :                 [sprite drawOutline];
    2596             :                 OOGLPopModelView();
    2597             :                 
    2598             :                 // Draw black backing, so outline colour isn’t blended into missile colour.
    2599             :                 OOGLPushModelView();
    2600             :                 OOGLTranslateModelView(make_vector(x - width * 2.0f, y - height * 2.0f, z1));
    2601             :                 OOGLScaleModelView(make_vector(width, height, 1.0f));
    2602             :                 GLColorWithOverallAlpha(black_color, alpha);
    2603             :                 [sprite drawFilled];
    2604             :                 OOGLPopModelView();
    2605             :                 
    2606             :                 switch (status)
    2607             :                 {
    2608             :                         case MISSILE_STATUS_SAFE:
    2609             :                                 GLColorWithOverallAlpha(green_color, alpha);    break;
    2610             :                         case MISSILE_STATUS_ARMED:
    2611             :                                 GLColorWithOverallAlpha(yellow_color, alpha);   break;
    2612             :                         case MISSILE_STATUS_TARGET_LOCKED:
    2613             :                                 GLColorWithOverallAlpha(red_color, alpha);              break;
    2614             :                 }
    2615             :         }
    2616             :         else
    2617             :         {
    2618             :                 if ([missile primaryTarget] == nil)  GLColorWithOverallAlpha(green_color, alpha);
    2619             :                 else  GLColorWithOverallAlpha(red_color, alpha);
    2620             :         }
    2621             :         
    2622             :         OOGLPushModelView();
    2623             :         OOGLTranslateModelView(make_vector(x - width * 2.0f, y - height * 2.0f, z1));
    2624             :         OOGLScaleModelView(make_vector(width, height, 1.0f));
    2625             :         [sprite drawFilled];
    2626             :         OOGLPopModelView();
    2627             : }
    2628             : 
    2629             : 
    2630             : 
    2631           0 : - (void) drawIconForEmptyPylonAtX:(int)x y:(int)y
    2632             :                                                         width:(GLfloat)width height:(GLfloat)height alpha:(GLfloat)alpha
    2633             : {
    2634             :         OOPolygonSprite *sprite = IconForMissileRole(kDefaultMissileIconKey);
    2635             :         
    2636             :         // Draw gray outline.
    2637             :         OOGLPushModelView();
    2638             :         OOGLTranslateModelView(make_vector(x - width * 2.0f, y - height * 2.0f, z1));
    2639             :         OOGLScaleModelView(make_vector(width, height, 1.0f));
    2640             :         GLColorWithOverallAlpha(lightgray_color, alpha);
    2641             :         [sprite drawOutline];
    2642             :         OOGLPopModelView();
    2643             : }
    2644             : 
    2645             : 
    2646           0 : - (void) drawMissileDisplay:(NSDictionary *)info
    2647             : {
    2648             :         int                                     x, y, sp;
    2649             :         NSSize                          siz;
    2650             :         GLfloat                         alpha = overallAlpha;
    2651             :         struct CachedInfo       cached;
    2652             :         
    2653             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2654             :         
    2655             :         x = useDefined(cached.x, MISSILES_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2656             :         y = useDefined(cached.y, MISSILES_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2657             :         siz.width = useDefined(cached.width, MISSILE_ICON_WIDTH);
    2658             :         siz.height = useDefined(cached.height, MISSILE_ICON_HEIGHT);
    2659             :         alpha *= cached.alpha;
    2660             :         sp = [info oo_unsignedIntForKey:SPACING_KEY defaultValue:MISSILES_DISPLAY_SPACING];
    2661             :         
    2662             :         BOOL weaponsOnline = [PLAYER weaponsOnline];
    2663             :         if (!weaponsOnline)  alpha *= 0.2f;     // darken missile display if weapons are offline
    2664             :         
    2665             :         if (![PLAYER dialIdentEngaged])
    2666             :         {
    2667             :                 OOMissileStatus status = [PLAYER dialMissileStatus];
    2668             :                 NSUInteger i, n_mis = [PLAYER dialMaxMissiles];
    2669             :                 for (i = 0; i < n_mis; i++)
    2670             :                 {
    2671             :                         ShipEntity *missile = [PLAYER missileForPylon:i];
    2672             :                         if (missile)
    2673             :                         {
    2674             :                                 [self drawIconForMissile:missile
    2675             :                                                                 selected:weaponsOnline && i == [PLAYER activeMissile]
    2676             :                                                                   status:status
    2677             :                                                                            x:x + (int)i * sp + 2 y:y
    2678             :                                                                    width:siz.width * 0.25f height:siz.height * 0.25f
    2679             :                                                                    alpha:alpha];
    2680             :                         }
    2681             :                         else
    2682             :                         {
    2683             :                                 [self drawIconForEmptyPylonAtX:x + (int)i * sp + 2 y:y
    2684             :                                                                         width:siz.width * 0.25f height:siz.height * 0.25f alpha:alpha];
    2685             :                         }
    2686             :                 }
    2687             :         }
    2688             :         else
    2689             :         {
    2690             :                 x -= siz.width;
    2691             :                 y -= siz.height * 0.75;
    2692             :                 siz.width *= 0.80;
    2693             :                 sp *= 0.75;
    2694             :                 switch ([PLAYER dialMissileStatus])
    2695             :                 {
    2696             :                         case MISSILE_STATUS_SAFE:
    2697             :                                 GLColorWithOverallAlpha(green_color, alpha);    break;
    2698             :                         case MISSILE_STATUS_ARMED:
    2699             :                                 GLColorWithOverallAlpha(yellow_color, alpha);   break;
    2700             :                         case MISSILE_STATUS_TARGET_LOCKED:
    2701             :                                 GLColorWithOverallAlpha(red_color, alpha);              break;
    2702             :                 }
    2703             :                 OOGLBEGIN(GL_QUADS);
    2704             :                         glVertex3i(x , y, z1);
    2705             :                         glVertex3i(x + siz.width, y, z1);
    2706             :                         glVertex3i(x + siz.width, y + siz.height, z1);
    2707             :                         glVertex3i(x , y + siz.height, z1);
    2708             :                 OOGLEND();
    2709             :                 GLColorWithOverallAlpha(green_color, alpha);
    2710             :                 OODrawString([PLAYER dialTargetName], x + sp, y - 1, z1, NSMakeSize(siz.width, siz.height));
    2711             :         }
    2712             :         
    2713             : }
    2714             : 
    2715             : 
    2716           0 : - (void) drawTargetReticle:(NSDictionary *)info
    2717             : {
    2718             :         GLfloat alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:1.0f] * overallAlpha;
    2719             :         
    2720             :         if ([PLAYER primaryTarget] != nil)
    2721             :         {
    2722             :                 hudDrawReticleOnTarget([PLAYER primaryTarget], PLAYER, z1, alpha, reticleTargetSensitive, propertiesReticleTargetSensitive, NO, YES, info, _reticleColors);
    2723             :                 [self drawDirectionCue:info];
    2724             :         }
    2725             :         // extra feature if extra equipment installed
    2726             :         if ([PLAYER hasEquipmentItemProviding:@"EQ_INTEGRATED_TARGETING_SYSTEM"])
    2727             :         {
    2728             :                 [self drawSecondaryTargetReticle:info];
    2729             :         }
    2730             : }
    2731             : 
    2732             : 
    2733           0 : - (void) drawSecondaryTargetReticle:(NSDictionary *)info
    2734             : {
    2735             :         GLfloat alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:1.0f] * overallAlpha * 0.4;
    2736             :         
    2737             :         PlayerEntity *player = PLAYER;
    2738             :         if ([player hasEquipmentItemProviding:@"EQ_TARGET_MEMORY"])
    2739             :         {
    2740             :                 // needs target memory to be working in addition to any other equipment
    2741             :                 // this item may be bound to
    2742             :                 NSMutableArray *targetMemory = [player targetMemory];
    2743             :                 ShipEntity *primary = [player primaryTarget];
    2744             :                 for (unsigned i = 0; i < PLAYER_TARGET_MEMORY_SIZE; i++)
    2745             :                 {
    2746             :                         id sec_id = [targetMemory objectAtIndex:i];
    2747             :                         // isProxy = weakref ; not = NSNull (in this case...)
    2748             :                         // can't use isKindOfClass because that throws
    2749             :                         // NSInvalidArgumentException when called on a weakref
    2750             :                         // with a dropped object.
    2751             :                         // TODO: fix OOWeakReference so isKindOfClass works
    2752             :                         if (sec_id != nil && [sec_id isProxy])
    2753             :                         {
    2754             :                                 ShipEntity *secondary = [(OOWeakReference *)sec_id weakRefUnderlyingObject];
    2755             :                                 if (secondary != nil && secondary != primary)
    2756             :                                 {
    2757             :                                         if ([secondary zeroDistance] <= SCANNER_MAX_RANGE2 && [secondary isInSpace])
    2758             :                                         {
    2759             :                                                 hudDrawReticleOnTarget(secondary, PLAYER, z1, alpha, NO, nil, YES, NO, info, _reticleColors);   
    2760             :                                         }                       
    2761             :                                 }
    2762             :                         }
    2763             :                 }
    2764             :         }
    2765             : }
    2766             : 
    2767             : 
    2768           0 : - (void) drawWaypoints:(NSDictionary *)info
    2769             : {
    2770             :         GLfloat alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:1.0f] * overallAlpha;
    2771             :         GLfloat scale = [info oo_floatForKey:@"reticle_scale" defaultValue:ONE_SIXTYFOURTH];
    2772             : 
    2773             :         NSEnumerator *waypoints = [[UNIVERSE currentWaypoints] objectEnumerator];
    2774             :         OOWaypointEntity *waypoint = nil;
    2775             :         Entity *compass = [PLAYER compassTarget];
    2776             :         
    2777             :         while ((waypoint = [waypoints nextObject]))
    2778             :         {
    2779             :                 hudDrawWaypoint(waypoint, PLAYER, z1, alpha, waypoint==compass, scale);
    2780             :         }
    2781             : 
    2782             : }
    2783             : 
    2784             : 
    2785           0 : - (void) drawStatusLight:(NSDictionary *)info
    2786             : {
    2787             :         int                                     x, y;
    2788             :         NSSize                          siz;
    2789             :         GLfloat                         alpha = overallAlpha;
    2790             :         BOOL                            blueAlert = cloakIndicatorOnStatusLight && [PLAYER isCloaked];
    2791             :         struct CachedInfo       cached;
    2792             :         
    2793             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2794             :         
    2795             :         x = useDefined(cached.x, STATUS_LIGHT_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2796             :         y = useDefined(cached.y, STATUS_LIGHT_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2797             :         siz.width = useDefined(cached.width, STATUS_LIGHT_HEIGHT);
    2798             :         siz.height = useDefined(cached.height, STATUS_LIGHT_HEIGHT);
    2799             :         alpha *= cached.alpha;
    2800             :         
    2801             :         GLfloat status_color[4] = { 0.25, 0.25, 0.25, 1.0};
    2802             :         int alertCondition = [PLAYER alertCondition];
    2803             :         GLfloat flash_alpha = 0.333 * (2.0f + sin((GLfloat)[UNIVERSE getTime] * 2.5f * alertCondition));
    2804             :         
    2805             :         switch(alertCondition)
    2806             :         {
    2807             :                 case ALERT_CONDITION_RED:
    2808             :                         status_color[0] = red_color[0];
    2809             :                         status_color[1] = red_color[1];
    2810             :                         status_color[2] = blueAlert ? blue_color[2] : red_color[2];
    2811             :                         break;
    2812             :                         
    2813             :                 case ALERT_CONDITION_GREEN:
    2814             :                         status_color[0] = green_color[0];
    2815             :                         status_color[1] = green_color[1];
    2816             :                         status_color[2] = blueAlert ? blue_color[2] : green_color[2];
    2817             :                         break;
    2818             :                         
    2819             :                 case ALERT_CONDITION_YELLOW:
    2820             :                         status_color[0] = yellow_color[0];
    2821             :                         status_color[1] = yellow_color[1];
    2822             :                         status_color[2] = blueAlert ? blue_color[2] : yellow_color[2];
    2823             :                         break;
    2824             :                         
    2825             :                 default:
    2826             :                 case ALERT_CONDITION_DOCKED:
    2827             :                         break;
    2828             :         }
    2829             :         status_color[3] = flash_alpha;
    2830             :         GLColorWithOverallAlpha(status_color, alpha);
    2831             :         OOGLBEGIN(GL_POLYGON);
    2832             :         hudDrawStatusIconAt(x, y, z1, siz);
    2833             :         OOGLEND();
    2834             :         OOGL(glColor4f(0.25, 0.25, 0.25, alpha));
    2835             :         OOGLBEGIN(GL_LINE_LOOP);
    2836             :                 hudDrawStatusIconAt(x, y, z1, siz);
    2837             :         OOGLEND();
    2838             : }
    2839             : 
    2840             : 
    2841           0 : - (void) drawDirectionCue:(NSDictionary *)info
    2842             : {
    2843             :         GLfloat                         alpha = overallAlpha;
    2844             :         struct CachedInfo       cached;
    2845             :         
    2846             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2847             :         
    2848             :         alpha *= cached.alpha;
    2849             :         
    2850             :         if ([UNIVERSE displayGUI])  return;
    2851             :         
    2852             :         Entity          *target = [PLAYER primaryTarget];
    2853             :         if (target == nil)  return;
    2854             :         
    2855             :         // draw the direction cue
    2856             :         OOMatrix        rotMatrix;
    2857             :         
    2858             :         rotMatrix = [PLAYER rotationMatrix];
    2859             :         
    2860             :         if ([UNIVERSE viewDirection] != VIEW_GUI_DISPLAY)
    2861             :         {
    2862             :                 const GLfloat innerSize = CROSSHAIR_SIZE;
    2863             :                 const GLfloat width = CROSSHAIR_SIZE * ONE_EIGHTH;
    2864             :                 const GLfloat outerSize = CROSSHAIR_SIZE * (1.0f + ONE_EIGHTH + ONE_EIGHTH);
    2865             :                 const float visMin = 0.994521895368273f;        // cos(6 degrees)
    2866             :                 const float visMax = 0.984807753012208f;        // cos(10 degrees)
    2867             :                 
    2868             :                 // Transform the view
    2869             :                 Vector rpn = [PLAYER vectorTo:target];
    2870             :                 rpn = OOVectorMultiplyMatrix(rpn, rotMatrix);
    2871             :                 Vector drawPos = rpn;
    2872             :                 Vector forward = kZeroVector;
    2873             :                 
    2874             :                 switch ([UNIVERSE viewDirection])
    2875             :                 {
    2876             :                         case VIEW_FORWARD:
    2877             :                                 forward = kBasisZVector;
    2878             :                                 break;
    2879             :                         case VIEW_AFT:
    2880             :                                 drawPos.x = - drawPos.x;
    2881             :                                 forward = vector_flip(kBasisZVector);
    2882             :                                 break;
    2883             :                         case VIEW_PORT:
    2884             :                                 drawPos.x = drawPos.z;
    2885             :                                 forward = vector_flip(kBasisXVector);
    2886             :                                 break;
    2887             :                         case VIEW_STARBOARD:
    2888             :                                 drawPos.x = -drawPos.z;
    2889             :                                 forward = kBasisXVector;
    2890             :                                 break;
    2891             :                         case VIEW_CUSTOM:
    2892             :                                 return;
    2893             :                         
    2894             :                         default:
    2895             :                                 break;
    2896             :                 }
    2897             :                 
    2898             :                 float cosAngle = dot_product(vector_normal(rpn), forward);
    2899             :                 float visibility = 1.0f - ((visMax - cosAngle) * (1.0f / (visMax - visMin)));
    2900             :                 alpha *= OOClamp_0_1_f(visibility);
    2901             :                 
    2902             :                 if (alpha > 0.0f)
    2903             :                 {
    2904             :                         NSUInteger cueColorIndex = [target isWormhole] ? OO_RETICLE_COLOR_WORMHOLE : OO_RETICLE_COLOR_TARGET;
    2905             :                         OOColor *directionCueColor = [_reticleColors objectAtIndex:cueColorIndex];
    2906             :                         GLfloat clearColorArray[4] =    {[directionCueColor redComponent],
    2907             :                                                                                         [directionCueColor greenComponent],
    2908             :                                                                                         [directionCueColor blueComponent],
    2909             :                                                                                         0.0f};
    2910             :                         GLfloat directionCueColorArray[4] = {[directionCueColor redComponent],
    2911             :                                                                                                 [directionCueColor greenComponent],
    2912             :                                                                                                 [directionCueColor blueComponent],
    2913             :                                                                                                 [directionCueColor alphaComponent]};
    2914             :                         drawPos.z = 0.0f;       // flatten vector
    2915             :                         drawPos = vector_normal(drawPos);
    2916             :                         OOGLBEGIN(GL_LINE_STRIP);
    2917             :                                 glColor4fv(clearColorArray);
    2918             :                                 glVertex3f(drawPos.x * innerSize - drawPos.y * width, drawPos.y * innerSize + drawPos.x * width, z1);
    2919             :                                 GLColorWithOverallAlpha(directionCueColorArray, alpha);
    2920             :                                 glVertex3f(drawPos.x * outerSize, drawPos.y * outerSize, z1);
    2921             :                                 glColor4fv(clearColorArray);
    2922             :                                 glVertex3f(drawPos.x * innerSize + drawPos.y * width, drawPos.y * innerSize - drawPos.x * width, z1);
    2923             :                         OOGLEND();
    2924             :                 }
    2925             :         }
    2926             : }
    2927             : 
    2928             : 
    2929           0 : - (void) drawClock:(NSDictionary *)info
    2930             : {
    2931             :         int                                     x, y;
    2932             :         NSSize                          siz;
    2933             :         GLfloat                         itemColor[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
    2934             :         struct CachedInfo       cached;
    2935             :         
    2936             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2937             :         
    2938             :         x = useDefined(cached.x, CLOCK_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2939             :         y = useDefined(cached.y, CLOCK_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2940             :         siz.width = useDefined(cached.width, CLOCK_DISPLAY_WIDTH);
    2941             :         siz.height = useDefined(cached.height, CLOCK_DISPLAY_HEIGHT);
    2942             :         
    2943             :         GetRGBAArrayFromInfo(info, itemColor);
    2944             :         itemColor[3] *= overallAlpha;
    2945             :         
    2946             :         OOGL(glColor4f(itemColor[0], itemColor[1], itemColor[2], itemColor[3]));
    2947             :         OODrawString([PLAYER dial_clock], x, y, z1, siz);
    2948             : }
    2949             : 
    2950             : 
    2951           0 : - (void) drawPrimedEquipment:(NSDictionary *)info
    2952             : {
    2953             :         if ([PLAYER status] == STATUS_DOCKED)
    2954             :         {
    2955             :                 // Can't activate equipment while docked
    2956             :                 return;
    2957             :         }
    2958             :         
    2959             :         GLfloat                         itemColor[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
    2960             :         struct CachedInfo       cached;
    2961             :         
    2962             :         NSUInteger lines = [info oo_intForKey:@"n_bars" defaultValue:1];
    2963             :         NSInteger pec = (NSInteger)[PLAYER primedEquipmentCount];
    2964             : 
    2965             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    2966             :         
    2967             :         NSInteger x = useDefined(cached.x, PRIMED_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    2968             :         NSInteger y = useDefined(cached.y, PRIMED_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    2969             :         
    2970             :         NSSize size =
    2971             :         {
    2972             :                 .width = useDefined(cached.width, PRIMED_DISPLAY_WIDTH),
    2973             :                 .height = useDefined(cached.height, PRIMED_DISPLAY_HEIGHT)
    2974             :         };
    2975             : 
    2976             :         if (pec == 0)
    2977             :         {
    2978             :                 // Don't display if no primed equipment fitted
    2979             :                 return;
    2980             :         }
    2981             : 
    2982             :         GetRGBAArrayFromInfo(info, itemColor);
    2983             :         itemColor[3] *= overallAlpha;
    2984             : 
    2985             :         if (lines == 1)
    2986             :         {
    2987             :                 OOGL(glColor4f(itemColor[0], itemColor[1], itemColor[2], itemColor[3]));
    2988             :                 NSString *equipmentName = [PLAYER primedEquipmentName:0];
    2989             :                 OODrawString(OOExpandKey(@"equipment-primed-hud", equipmentName), x, y, z1, size);
    2990             :         }
    2991             :         else
    2992             :         {
    2993             :                 NSInteger negative = (lines - 1) / 2;
    2994             :                 NSInteger positive = lines / 2;
    2995             :                 for (NSInteger i = -negative; i <= positive; i++)
    2996             :                 {
    2997             :                         if (i >= -(pec) / 2 && i <= (pec + 1) / 2)
    2998             :                         {
    2999             :                                 // don't display loops if we have more equipment than lines
    3000             :                                 // instead compact the display towards its centre
    3001             :                                 GLfloat alphaScale = 1.0/((i<0)?(1.0-i):(1.0+i));
    3002             :                                 OOGL(glColor4f(itemColor[0], itemColor[1], itemColor[2], itemColor[3]*alphaScale));
    3003             :                                 OODrawString([PLAYER primedEquipmentName:i], x, y, z1, size);
    3004             :                         }
    3005             :                         y -= size.height;
    3006             :                 }       
    3007             :         }
    3008             : }
    3009             : 
    3010             : 
    3011           0 : - (void) drawASCTarget:(NSDictionary *)info
    3012             : {
    3013             :         if (!([self checkPlayerInSystemFlight] && [PLAYER status] != STATUS_LAUNCHING)) // normal system
    3014             :         {
    3015             :                 // Can't have compass target when docked, etc. (matches blip condition)
    3016             :                 return;
    3017             :         }
    3018             :         
    3019             :         GLfloat                         itemColor[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
    3020             :         struct CachedInfo       cached;
    3021             :         
    3022             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    3023             : 
    3024             :         NSInteger x = useDefined(cached.x, ASCTARGET_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    3025             :         NSInteger y = useDefined(cached.y, ASCTARGET_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    3026             :         
    3027             :         NSSize size =
    3028             :         {
    3029             :                 .width = useDefined(cached.width, ASCTARGET_DISPLAY_WIDTH),
    3030             :                 .height = useDefined(cached.height, ASCTARGET_DISPLAY_HEIGHT)
    3031             :         };
    3032             : 
    3033             :         GetRGBAArrayFromInfo(info, itemColor);
    3034             :         itemColor[3] *= overallAlpha;
    3035             : 
    3036             :         OOGL(glColor4f(itemColor[0], itemColor[1], itemColor[2], itemColor[3]));
    3037             :         if ([info oo_intForKey:@"align"] == 1)
    3038             :         {
    3039             :                 OODrawStringAligned([PLAYER compassTargetLabel], x, y, z1, size,YES);
    3040             :         }
    3041             :         else
    3042             :         {
    3043             :                 OODrawStringAligned([PLAYER compassTargetLabel], x, y, z1, size,NO);
    3044             :         }
    3045             :         
    3046             : }
    3047             : 
    3048             : 
    3049           0 : - (void) drawWeaponsOfflineText:(NSDictionary *)info
    3050             : {
    3051             :         OOViewID                                        viewID = [UNIVERSE viewDirection];
    3052             :         GLfloat                                         textColor[4] = {0.0f, 1.0f, 0.0f, 1.0f};
    3053             : 
    3054             :         if (viewID == VIEW_CUSTOM ||
    3055             :                 overallAlpha == 0.0f ||
    3056             :                 !([PLAYER status] == STATUS_IN_FLIGHT || [PLAYER status] == STATUS_WITCHSPACE_COUNTDOWN) ||
    3057             :                 [UNIVERSE displayGUI]
    3058             :                 )
    3059             :         {
    3060             :                 // Don't draw weapons offline text
    3061             :                 return;
    3062             :         }
    3063             : 
    3064             :         if (![PLAYER weaponsOnline])
    3065             :         {
    3066             :                 int                                     x, y;
    3067             :                 NSSize                          siz;
    3068             :                 GLfloat                         alpha = overallAlpha;
    3069             :                 struct CachedInfo       cached;
    3070             :         
    3071             :                 [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    3072             :                 
    3073             :                 x = useDefined(cached.x, WEAPONSOFFLINETEXT_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    3074             :                 y = useDefined(cached.y, WEAPONSOFFLINETEXT_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    3075             :                 siz.width = useDefined(cached.width, WEAPONSOFFLINETEXT_WIDTH);
    3076             :                 siz.height = useDefined(cached.height, WEAPONSOFFLINETEXT_HEIGHT);
    3077             :                 alpha *= cached.alpha;
    3078             :                 
    3079             :                 GetRGBAArrayFromInfo(info, textColor);
    3080             :                 textColor[3] *= overallAlpha;
    3081             :                 
    3082             :                 OOGL(glColor4f(textColor[0], textColor[1], textColor[2], textColor[3]));
    3083             :                 // TODO: some caching required...
    3084             :                 OODrawString(DESC(@"weapons-systems-offline"), x, y, z1, siz);
    3085             :         }
    3086             : }
    3087             : 
    3088             : 
    3089           0 : - (void) drawFPSInfoCounter:(NSDictionary *)info
    3090             : {
    3091             :         if (![UNIVERSE displayFPS])  return;
    3092             :         
    3093             :         int                                     x, y;
    3094             :         NSSize                          siz;
    3095             :         struct CachedInfo       cached;
    3096             :         GLfloat                         textColor[4] = {0.0, 1.0, 0.0, 1.0};
    3097             :         
    3098             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    3099             :         
    3100             :         x = useDefined(cached.x, FPSINFO_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    3101             :         y = useDefined(cached.y, FPSINFO_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    3102             :         siz.width = useDefined(cached.width, FPSINFO_DISPLAY_WIDTH);
    3103             :         siz.height = useDefined(cached.height, FPSINFO_DISPLAY_HEIGHT);
    3104             :         
    3105             :         HPVector playerPos = [PLAYER position];
    3106             :         NSString *positionInfo = [UNIVERSE expressPosition:playerPos inCoordinateSystem:@"pwm"];
    3107             :         positionInfo = [NSString stringWithFormat:@"abs %.2f %.2f %.2f / %@", playerPos.x, playerPos.y, playerPos.z, positionInfo];
    3108             :         
    3109             :         // We would normally set a variable alpha value here, but in this case we don't.
    3110             :         // We prefer the FPS counter to be always visible - Nikos 20100405
    3111             :         GetRGBAArrayFromInfo(info, textColor);
    3112             :         OOGL(glColor4f(textColor[0], textColor[1], textColor[2], 1.0f));
    3113             :         OODrawString([PLAYER dial_fpsinfo], x, y, z1, siz);
    3114             :         
    3115             : #ifndef NDEBUG
    3116             :         NSSize siz08 = NSMakeSize(0.8 * siz.width, 0.8 * siz.width);
    3117             :         NSString *collDebugInfo = [NSString stringWithFormat:@"%@ - %@", [PLAYER dial_objinfo], [UNIVERSE collisionDescription]];
    3118             :         OODrawString(collDebugInfo, x, y - siz.height, z1, siz);
    3119             :         
    3120             :         OODrawString(positionInfo, x, y - 1.8 * siz.height, z1, siz08);
    3121             :         
    3122             :         NSString *timeAccelerationFactorInfo = [NSString stringWithFormat:@"TAF: %@%.2f", DESC(@"multiplication-sign"), [UNIVERSE timeAccelerationFactor]];
    3123             :         OODrawString(timeAccelerationFactorInfo, x, y - 3.2 * siz08.height, z1, siz08);
    3124             : #endif
    3125             : }
    3126             : 
    3127             : 
    3128           0 : - (void) drawScoopStatus:(NSDictionary *)info
    3129             : {
    3130             :         int                                     i, x, y;
    3131             :         NSSize                          siz;
    3132             :         GLfloat                         alpha;
    3133             :         struct CachedInfo       cached;
    3134             :         
    3135             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    3136             :         
    3137             :         x = useDefined(cached.x, SCOOPSTATUS_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    3138             :         y = useDefined(cached.y, SCOOPSTATUS_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    3139             :         siz.width = useDefined(cached.width, SCOOPSTATUS_WIDTH);
    3140             :         siz.height = useDefined(cached.height, SCOOPSTATUS_HEIGHT);
    3141             :         // default alpha value different from all others, won't use cached.alpha
    3142             :         alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:0.75f];
    3143             :         
    3144             :         const GLfloat* s0_color = red_color;
    3145             :         GLfloat s1c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    3146             :         GLfloat s2c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    3147             :         GLfloat s3c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    3148             :         int scoop_status = [PLAYER dialFuelScoopStatus];
    3149             :         GLfloat t = [UNIVERSE getTime];
    3150             :         GLfloat a1 = alpha * 0.5f * (1.0f + sin(t * 8.0f));
    3151             :         GLfloat a2 = alpha * 0.5f * (1.0f + sin(t * 8.0f - 1.0f));
    3152             :         GLfloat a3 = alpha * 0.5f * (1.0f + sin(t * 8.0f - 2.0f));
    3153             :         
    3154             :         switch (scoop_status)
    3155             :         {
    3156             :                 case SCOOP_STATUS_NOT_INSTALLED:
    3157             :                         return; // don't draw
    3158             :                         
    3159             :                 case SCOOP_STATUS_FULL_HOLD:
    3160             :                         s0_color = darkgreen_color;
    3161             :                         alpha *= 0.75;
    3162             :                         break;
    3163             :                         
    3164             :                 case SCOOP_STATUS_ACTIVE:
    3165             :                 case SCOOP_STATUS_OKAY:
    3166             :                         s0_color = green_color;
    3167             :                         break;
    3168             :         }
    3169             :         
    3170             :         for (i = 0; i < 3; i++)
    3171             :         {
    3172             :                 s1c[i] = s0_color[i];
    3173             :                 s2c[i] = s0_color[i];
    3174             :                 s3c[i] = s0_color[i];
    3175             :         }
    3176             :         if (scoop_status == SCOOP_STATUS_FULL_HOLD)
    3177             :         {
    3178             :                 s3c[0] = red_color[0];
    3179             :                 s3c[1] = red_color[1];
    3180             :                 s3c[2] = red_color[2];
    3181             :         }
    3182             :         if (scoop_status == SCOOP_STATUS_ACTIVE)
    3183             :         {
    3184             :                 s1c[3] = alpha * a1;
    3185             :                 s2c[3] = alpha * a2;
    3186             :                 s3c[3] = alpha * a3;
    3187             :         }
    3188             :         else
    3189             :         {
    3190             :                 s1c[3] = alpha;
    3191             :                 s2c[3] = alpha;
    3192             :                 s3c[3] = alpha;
    3193             :         }
    3194             :         
    3195             :         GLfloat w1 = siz.width / 8.0;
    3196             :         GLfloat w2 = 2.0 * w1;
    3197             : //      GLfloat w3 = 3.0 * w1;
    3198             :         GLfloat w4 = 4.0 * w1;
    3199             :         GLfloat h1 = siz.height / 8.0;
    3200             :         GLfloat h2 = 2.0 * h1;
    3201             :         GLfloat h3 = 3.0 * h1;
    3202             :         GLfloat h4 = 4.0 * h1;
    3203             :         
    3204             :         OOGL(glDisable(GL_TEXTURE_2D));
    3205             :         OOGLBEGIN(GL_QUADS);
    3206             :         // section 1
    3207             :                 GLColorWithOverallAlpha(s1c, overallAlpha);
    3208             :                 glVertex3f(x, y + h1, z1);      glVertex3f(x - w2, y + h2, z1); glVertex3f(x, y + h3, z1);      glVertex3f(x + w2, y + h2, z1);
    3209             :         // section 2
    3210             :                 GLColorWithOverallAlpha(s2c, overallAlpha);
    3211             :                 glVertex3f(x, y - h1, z1);      glVertex3f(x - w4, y + h1, z1); glVertex3f(x - w4, y + h2, z1); glVertex3f(x, y, z1);
    3212             :                 glVertex3f(x, y - h1, z1);      glVertex3f(x + w4, y + h1, z1); glVertex3f(x + w4, y + h2, z1); glVertex3f(x, y, z1);
    3213             :         // section 3
    3214             :                 GLColorWithOverallAlpha(s3c, overallAlpha);
    3215             :                 glVertex3f(x, y - h4, z1);      glVertex3f(x - w2, y - h2, z1); glVertex3f(x - w2, y - h1, z1); glVertex3f(x, y - h2, z1);
    3216             :                 glVertex3f(x, y - h4, z1);      glVertex3f(x + w2, y - h2, z1); glVertex3f(x + w2, y - h1, z1); glVertex3f(x, y - h2, z1);
    3217             :         OOGLEND();
    3218             : }
    3219             : 
    3220             : 
    3221           0 : - (void) drawStickSensitivityIndicator:(NSDictionary *)info
    3222             : {
    3223             :         GLfloat                         x, y;
    3224             :         NSSize                          siz;
    3225             :         GLfloat                         alpha = overallAlpha;
    3226             :         BOOL                            mouse = [PLAYER isMouseControlOn];
    3227             :         OOJoystickManager       *stickHandler = [OOJoystickManager sharedStickHandler];
    3228             :         struct CachedInfo       cached;
    3229             :         
    3230             :         if (![stickHandler joystickCount])
    3231             :         {
    3232             :                 return; // no need to draw if no joystick fitted
    3233             :         }
    3234             : 
    3235             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    3236             :         
    3237             :         x = useDefined(cached.x, STATUS_LIGHT_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
    3238             :         y = useDefined(cached.y, STATUS_LIGHT_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
    3239             :         siz.width = useDefined(cached.width, STATUS_LIGHT_HEIGHT);
    3240             :         siz.height = useDefined(cached.height, STATUS_LIGHT_HEIGHT);
    3241             :         alpha *= cached.alpha;
    3242             :         
    3243             :         GLfloat div = [stickHandler getSensitivity];
    3244             :         
    3245             :         GLColorWithOverallAlpha(black_color, alpha / 4);
    3246             :         GLDrawFilledOval(x, y, z1, siz, 10);
    3247             :         
    3248             :         GLColorWithOverallAlpha((div < 1.0 || mouse) ? lightgray_color : green_color, alpha);
    3249             :         OOGL(GLScaledLineWidth(_crosshairWidth * lineWidth));
    3250             :         
    3251             :         if (div >= 1.0)
    3252             :         {
    3253             :                 if (!mouse)
    3254             :                 {
    3255             :                         NSSize siz8th = { siz.width / 8, siz.height / 8 };
    3256             :                         GLDrawFilledOval(x, y, z1, siz8th, 30);
    3257             :                         
    3258             :                         if (div == 1.0) // normal mode
    3259             :                                 GLColorWithOverallAlpha(lightgray_color, alpha);
    3260             :                 }
    3261             :                 
    3262             :                 siz.width -= _crosshairWidth * lineWidth / 2;
    3263             :                 siz.height -= _crosshairWidth * lineWidth / 2;
    3264             :                 GLDrawOval(x, y, z1, siz, 10);
    3265             :         }
    3266             :         else if (div < 1.0) // insensitive mode (shouldn't happen)
    3267             :                 GLDrawFilledOval(x, y, z1, siz, 10);
    3268             : 
    3269             :         OOGL(GLScaledLineWidth(lineWidth)); // reset
    3270             : }
    3271             : 
    3272             : 
    3273           0 : - (void) drawSurroundInternal:(NSDictionary *)info color:(const GLfloat[4])color
    3274             : {
    3275             :         NSInteger                       x, y;
    3276             :         NSSize                          siz;
    3277             :         GLfloat                         alpha = overallAlpha;
    3278             :         struct CachedInfo       cached;
    3279             :         
    3280             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    3281             :         
    3282             :         if (cached.x == NOT_DEFINED || cached.y == NOT_DEFINED || cached.width == NOT_DEFINED || cached.height == NOT_DEFINED)
    3283             :         {
    3284             :                 return;
    3285             :         }
    3286             :                 
    3287             :         x = cached.x + [[UNIVERSE gameView] x_offset] * cached.x0;
    3288             :         y = cached.y + [[UNIVERSE gameView] y_offset] * cached.y0;
    3289             :         siz.width = useDefined(cached.width, WEAPONSOFFLINETEXT_WIDTH);
    3290             :         siz.height = useDefined(cached.height, WEAPONSOFFLINETEXT_HEIGHT);
    3291             :         alpha *= cached.alpha;
    3292             :         
    3293             :         // draw the surround
    3294             :         GLColorWithOverallAlpha(color, alpha);
    3295             :         hudDrawSurroundAt(x, y, z1, siz);
    3296             : }
    3297             : 
    3298             : 
    3299           0 : - (void) drawSurround:(NSDictionary *)info
    3300             : {
    3301             :         GLfloat itemColor[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
    3302             :         id              colorDesc = [info objectForKey:COLOR_KEY];
    3303             :         if (colorDesc != nil)
    3304             :         {
    3305             :                 OOColor *color = [OOColor colorWithDescription:colorDesc];
    3306             :                 if (color != nil)
    3307             :                 {
    3308             :                         itemColor[0] = [color redComponent];
    3309             :                         itemColor[1] = [color greenComponent];
    3310             :                         itemColor[2] = [color blueComponent];
    3311             :                 }
    3312             :         }
    3313             : 
    3314             :         [self drawSurroundInternal:info color:itemColor];
    3315             : }
    3316             : 
    3317             : 
    3318           0 : - (void) drawGreenSurround:(NSDictionary *)info
    3319             : {
    3320             :         [self drawSurroundInternal:info color:green_color];
    3321             : }
    3322             : 
    3323             : 
    3324           0 : - (void) drawYellowSurround:(NSDictionary *)info
    3325             : {
    3326             :         [self drawSurroundInternal:info color:yellow_color];
    3327             : }
    3328             : 
    3329             : 
    3330           0 : - (void) drawTrumbles:(NSDictionary *)info
    3331             : {
    3332             :         OOTrumble** trumbles = [PLAYER trumbleArray];
    3333             :         NSUInteger i;
    3334             :         for (i = [PLAYER trumbleCount]; i > 0; i--)
    3335             :         {
    3336             :                 OOTrumble* trum = trumbles[i - 1];
    3337             :                 [trum drawTrumble: z1];
    3338             :         }
    3339             : }
    3340             : 
    3341             : 
    3342           0 : - (void) drawMultiFunctionDisplay:(NSDictionary *)info withText:(NSString *)text asIndex:(NSUInteger)index
    3343             : {
    3344             :         PlayerEntity            *player1 = PLAYER;
    3345             :         struct CachedInfo       cached;
    3346             :         NSInteger                       i, x, y;
    3347             :         NSSize                          siz, tmpsiz;
    3348             :         if ([player1 guiScreen] != GUI_SCREEN_MAIN)     // don't draw on text screens
    3349             :         {
    3350             :                 return;
    3351             :         }
    3352             :         GLfloat alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:1.0f] * overallAlpha;
    3353             :         
    3354             :         GLfloat mfd_color[4] =          {0.0, 1.0, 0.0, 0.9*alpha};
    3355             :         OOColor *mfdcol = [OOColor colorWithDescription:[info objectForKey:COLOR_KEY]];
    3356             :         if (mfdcol != nil) 
    3357             :         {
    3358             :                 [mfdcol getRed:&mfd_color[0] green:&mfd_color[1] blue:&mfd_color[2] alpha:&mfd_color[3]];
    3359             :         }
    3360             :         if (index != [player1 activeMFD])
    3361             :         {
    3362             :                 mfd_color[3] *= 0.75;
    3363             :         }
    3364             :         [self drawSurroundInternal:info color:mfd_color];
    3365             : 
    3366             :         [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
    3367             :         x = cached.x + [[UNIVERSE gameView] x_offset] * cached.x0;
    3368             :         y = cached.y + [[UNIVERSE gameView] y_offset] * cached.y0;
    3369             :         
    3370             :         siz.width = useDefined(cached.width / 15, MFD_TEXT_WIDTH);
    3371             :         siz.height = useDefined(cached.height / 10, MFD_TEXT_HEIGHT);
    3372             : 
    3373             :         GLfloat x0 = (GLfloat)(x - cached.width/2);
    3374             :         GLfloat y0 = (GLfloat)(y + cached.height/2);
    3375             :         GLfloat x1 = (GLfloat)(x + cached.width/2);
    3376             :         GLfloat y1 = (GLfloat)(y - cached.height/2);
    3377             :         GLColorWithOverallAlpha(mfd_color, alpha*0.3);
    3378             :         OOGLBEGIN(GL_QUADS);
    3379             :                 glVertex3f(x0-2,y0+2,z1);
    3380             :                 glVertex3f(x0-2,y1-2,z1);
    3381             :                 glVertex3f(x1+2,y1-2,z1);
    3382             :                 glVertex3f(x1+2,y0+2,z1);
    3383             :         OOGLEND();
    3384             : 
    3385             :         NSString *line = nil;
    3386             :         NSArray *lines = [text componentsSeparatedByString:@"\n"];
    3387             :         // text at full opacity
    3388             :         GLColorWithOverallAlpha(mfd_color, alpha);
    3389             :         for (i = 0; i < 10 ; i++)
    3390             :         {
    3391             :                 line = [lines oo_stringAtIndex:i defaultValue:nil];
    3392             :                 if (line != nil)
    3393             :                 {
    3394             :                         y0 -= siz.height;
    3395             :                         // all lines should be shorter than the size of the MFD
    3396             :                         GLfloat textwidth = OORectFromString(line, 0.0f, 0.0f, siz).size.width;
    3397             :                         if (textwidth <= cached.width)
    3398             :                         {
    3399             :                                 OODrawString(line, x0, y0, z1, siz);
    3400             :                         }
    3401             :                         else
    3402             :                         {
    3403             :                                 // compress it so it fits
    3404             :                                 tmpsiz.height = siz.height;
    3405             :                                 tmpsiz.width = siz.width * cached.width / textwidth;
    3406             :                                 OODrawString(line, x0, y0, z1, tmpsiz);
    3407             :                         }
    3408             :                 }
    3409             :                 else
    3410             :                 {
    3411             :                         break;
    3412             :                 }
    3413             :         }
    3414             : }
    3415             : 
    3416             : //---------------------------------------------------------------------//
    3417             : 
    3418           0 : static void hudDrawIndicatorAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
    3419             : {
    3420             :         if (siz.width > siz.height)
    3421             :         {
    3422             :                 GLfloat dial_oy =   y - siz.height/2;
    3423             :                 GLfloat position =  x + amount * siz.width / 2;
    3424             :                 OOGLBEGIN(GL_QUADS);
    3425             :                         glVertex3f(position, dial_oy, z);
    3426             :                         glVertex3f(position+2, y, z);
    3427             :                         glVertex3f(position, dial_oy+siz.height, z);
    3428             :                         glVertex3f(position-2, y, z);
    3429             :                 OOGLEND();
    3430             :         }
    3431             :         else
    3432             :         {
    3433             :                 GLfloat dial_ox =   x - siz.width/2;
    3434             :                 GLfloat position =  y + amount * siz.height / 2;
    3435             :                 OOGLBEGIN(GL_QUADS);
    3436             :                         glVertex3f(dial_ox, position, z);
    3437             :                         glVertex3f(x, position+2, z);
    3438             :                         glVertex3f(dial_ox + siz.width, position, z);
    3439             :                         glVertex3f(x, position-2, z);
    3440             :                 OOGLEND();
    3441             :         }
    3442             : }
    3443             : 
    3444             : 
    3445           0 : static void hudDrawMarkerAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
    3446             : {
    3447             :         if (siz.width > siz.height)
    3448             :         {
    3449             :                 GLfloat dial_oy =   y - siz.height/2;
    3450             :                 GLfloat position =  x + amount * siz.width - siz.width/2;
    3451             :                 OOGLBEGIN(GL_QUADS);
    3452             :                         glVertex3f(position+1, dial_oy+1, z);
    3453             :                         glVertex3f(position+1, dial_oy+siz.height-1, z);
    3454             :                         glVertex3f(position-1, dial_oy+siz.height-1, z);
    3455             :                         glVertex3f(position-1, dial_oy+1, z);
    3456             :                 OOGLEND();
    3457             :         }
    3458             :         else
    3459             :         {
    3460             :                 GLfloat dial_ox =   x - siz.width/2;
    3461             :                 GLfloat position =  y + amount * siz.height - siz.height/2;
    3462             :                 OOGLBEGIN(GL_QUADS);
    3463             :                         glVertex3f(dial_ox+1, position+1, z);
    3464             :                         glVertex3f(dial_ox + siz.width-1, position+1, z);
    3465             :                         glVertex3f(dial_ox + siz.width-1, position-1, z);
    3466             :                         glVertex3f(dial_ox+1, position-1, z);
    3467             :                 OOGLEND();
    3468             :         }
    3469             : }
    3470             : 
    3471             : 
    3472           0 : static void hudDrawBarAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
    3473             : {
    3474             :         GLfloat dial_ox =   x - siz.width/2;
    3475             :         GLfloat dial_oy =   y - siz.height/2;
    3476             :         if (fabs(siz.width) > fabs(siz.height))
    3477             :         {
    3478             :                 GLfloat position =  dial_ox + amount * siz.width;
    3479             :                 
    3480             :                 OOGLBEGIN(GL_QUADS);
    3481             :                         glVertex3f(dial_ox, dial_oy, z);
    3482             :                         glVertex3f(position, dial_oy, z);
    3483             :                         glVertex3f(position, dial_oy+siz.height, z);
    3484             :                         glVertex3f(dial_ox, dial_oy+siz.height, z);
    3485             :                 OOGLEND();
    3486             :         }
    3487             :         else
    3488             :         {
    3489             :                 GLfloat position =  dial_oy + amount * siz.height;
    3490             :                 
    3491             :                 OOGLBEGIN(GL_QUADS);
    3492             :                         glVertex3f(dial_ox, dial_oy, z);
    3493             :                         glVertex3f(dial_ox, position, z);
    3494             :                         glVertex3f(dial_ox+siz.width, position, z);
    3495             :                         glVertex3f(dial_ox+siz.width, dial_oy, z);
    3496             :                 OOGLEND();
    3497             :         }
    3498             : }
    3499             : 
    3500             : 
    3501           0 : static void hudDrawSurroundAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz)
    3502             : {
    3503             :         GLfloat dial_ox = x - siz.width/2;
    3504             :         GLfloat dial_oy = y - siz.height/2;
    3505             :         
    3506             :         OOGLBEGIN(GL_LINE_LOOP);
    3507             :                 glVertex3f(dial_ox-2, dial_oy-2, z);
    3508             :                 glVertex3f(dial_ox+siz.width+2, dial_oy-2, z);
    3509             :                 glVertex3f(dial_ox+siz.width+2, dial_oy+siz.height+2, z);
    3510             :                 glVertex3f(dial_ox-2, dial_oy+siz.height+2, z);
    3511             :         OOGLEND();
    3512             : }
    3513             : 
    3514             : 
    3515           0 : static void hudDrawStatusIconAt(int x, int y, int z, NSSize siz)
    3516             : {
    3517             :         int ox = x - siz.width / 2.0;
    3518             :         int oy = y - siz.height / 2.0;
    3519             :         int w = siz.width / 4.0;
    3520             :         int h = siz.height / 4.0; 
    3521             : 
    3522             :         glVertex3i(ox, oy + h, z);
    3523             :         glVertex3i(ox, oy + 3 * h, z);
    3524             :         glVertex3i(ox + w, oy + 4 * h, z);
    3525             :         glVertex3i(ox + 3 * w, oy + 4 * h, z);
    3526             :         glVertex3i(ox + 4 * w, oy + 3 * h, z);
    3527             :         glVertex3i(ox + 4 * w, oy + h, z);
    3528             :         glVertex3i(ox + 3 * w, oy, z);
    3529             :         glVertex3i(ox + w, oy, z);
    3530             : }
    3531             : 
    3532             : 
    3533           0 : static void hudDrawReticleOnTarget(Entity *target, PlayerEntity *player1, GLfloat z1, 
    3534             :                                 GLfloat alpha, BOOL reticleTargetSensitive, NSMutableDictionary *propertiesReticleTargetSensitive,
    3535             :                                 BOOL colourFromScannerColour, BOOL showText, NSDictionary *info, NSMutableArray *reticleColors)
    3536             : {
    3537             :         if (target == nil || player1 == nil)  
    3538             :         {
    3539             :                 return;
    3540             :         }
    3541             :         if ([player1 guiScreen] != GUI_SCREEN_MAIN)     // don't draw on text screens
    3542             :         {
    3543             :                 return;
    3544             :         }
    3545             : 
    3546             :         ShipEntity              *target_ship = nil;
    3547             :         NSString                *legal_desc = nil;
    3548             :         
    3549             :         GLfloat                 scale = [info oo_floatForKey:@"reticle_scale" defaultValue:ONE_SIXTYFOURTH];
    3550             :         
    3551             : 
    3552             :         if ([target isShip])
    3553             :         {
    3554             :                 target_ship = (ShipEntity *)target;
    3555             :                 legal_desc = [target_ship scanDescription];
    3556             :         }
    3557             : 
    3558             :         if ([target_ship isCloaked])  return;
    3559             :         
    3560             :         
    3561             :         Vector                  p1;
    3562             :         
    3563             :         // by definition close enough that single precision is fine
    3564             :         p1 = HPVectorToVector(HPvector_subtract([target position], [player1 viewpointPosition]));
    3565             :         
    3566             :         GLfloat                 rdist = magnitude(p1);
    3567             :         GLfloat                 rsize = [target collisionRadius] / (2 * [[UNIVERSE gameView] fov:YES]); // FIXME integrate 2 into fov to remove magic number
    3568             :         
    3569             :         if (rsize < rdist * scale)
    3570             :                 rsize = rdist * scale;
    3571             :         
    3572             :         GLfloat                 rs0 = rsize;
    3573             :         GLfloat                 rs2 = rsize * 0.50;
    3574             :         
    3575             :         OOGLPushModelView();
    3576             :         hudRotateViewpointForVirtualDepth(player1,p1);
    3577             : 
    3578             :         // draw the reticle
    3579             :         float range = sqrt(target->zero_distance) - target->collision_radius;
    3580             :         
    3581             :         int flash = (int)([UNIVERSE getTime] * 4);
    3582             :         flash &= 1;
    3583             : 
    3584             :         // Draw reticle cyan for Wormholes
    3585             :         if ([target isWormhole])
    3586             :         {
    3587             :                 OOColor *wormholeReticleColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_WORMHOLE];
    3588             :                 GLfloat wormholeReticleColorArray[4] = {[wormholeReticleColor redComponent],
    3589             :                                                                                                 [wormholeReticleColor greenComponent],
    3590             :                                                                                                 [wormholeReticleColor blueComponent],
    3591             :                                                                                                 [wormholeReticleColor alphaComponent]};
    3592             :                 GLColorWithOverallAlpha(wormholeReticleColorArray, alpha);
    3593             :         }
    3594             :         else
    3595             :         {
    3596             :                 // Reticle sensitivity accuracy calculation
    3597             :                 BOOL                    isTargeted = NO;
    3598             :                 GLfloat                 probabilityAccuracy;
    3599             :                 
    3600             :                 if (propertiesReticleTargetSensitive != nil)
    3601             :                 {
    3602             :                         // Only if target is within player's weapon range, we mind for reticle accuracy
    3603             :                         if (range < [player1 weaponRange])
    3604             :                         {
    3605             :                                 // After MAX_ACCURACY_RANGE km start decreasing high accuracy probability by ACCURACY_PROBABILITY_DECREASE_FACTOR%
    3606             :                                 if (range > MAX_ACCURACY_RANGE)   
    3607             :                                 {
    3608             :                                         // Every one second re-evaluate accuracy
    3609             :                                         if ([UNIVERSE getTime] > [propertiesReticleTargetSensitive oo_doubleForKey:@"timeLastAccuracyProbabilityCalculation"] + 1) 
    3610             :                                         {
    3611             :                                                 probabilityAccuracy = 1-(range-MAX_ACCURACY_RANGE)*ACCURACY_PROBABILITY_DECREASE_FACTOR; 
    3612             :                                                 // Make sure probability does not go below a minimum
    3613             :                                                 probabilityAccuracy = probabilityAccuracy < MIN_PROBABILITY_ACCURACY ? MIN_PROBABILITY_ACCURACY : probabilityAccuracy;
    3614             :                                                 [propertiesReticleTargetSensitive setObject:[NSNumber numberWithBool:((randf() < probabilityAccuracy) ? YES : NO)] forKey:@"isAccurate"];
    3615             :                         
    3616             :                                                 // Store the time the last accuracy probability has been performed
    3617             :                                                 [propertiesReticleTargetSensitive setObject:[NSNumber numberWithDouble:[UNIVERSE getTime]] forKey:@"timeLastAccuracyProbabilityCalculation"];
    3618             :                                         }                       
    3619             :                                         if ([propertiesReticleTargetSensitive oo_boolForKey:@"isAccurate"])
    3620             :                                         {
    3621             :                                                 // high accuracy reticle
    3622             :                                                 isTargeted = ([UNIVERSE firstEntityTargetedByPlayerPrecisely] == target);
    3623             :                                         }
    3624             :                                         else
    3625             :                                         {
    3626             :                                                 // low accuracy reticle
    3627             :                                                 isTargeted = ([UNIVERSE firstEntityTargetedByPlayer] == target);
    3628             :                                         }
    3629             :                                 }
    3630             :                                 else
    3631             :                                 {
    3632             :                                         // high accuracy reticle
    3633             :                                         isTargeted = ([UNIVERSE firstEntityTargetedByPlayerPrecisely] == target);
    3634             :                                 }
    3635             :                         }
    3636             :                 }
    3637             :                 
    3638             :                 // If reticle is target sensitive, draw target box in red 
    3639             :                 // when target passes through laser hit-point(with decreasing accuracy) 
    3640             :                 // and is within hit-range.
    3641             :                 //
    3642             :                 // NOTE: The following condition also considers (indirectly) the player's weapon range.
    3643             :                 //       'isTargeted' is initialised to FALSE. Only if target is within the player's weapon range,
    3644             :                 //       it might change value. Therefore, it is not necessary to add '&& range < [player1 weaponRange]'
    3645             :                 //       to the following condition.
    3646             :                 if (colourFromScannerColour)
    3647             :                 {
    3648             :                         if ([target isShip])
    3649             :                         {
    3650             :                                 ShipEntity *ship = (ShipEntity *)target;
    3651             :                                 BOOL isHostile = (([ship hasHostileTarget])&&([ship primaryTarget] == PLAYER));
    3652             :                                 GLColorWithOverallAlpha([ship scannerDisplayColorForShip:PLAYER :isHostile :flash :[ship scannerDisplayColor1] :[ship scannerDisplayColor2] :[ship scannerDisplayColorHostile1] :[ship scannerDisplayColorHostile2]],alpha);
    3653             :                         }
    3654             :                         else if ([target isVisualEffect])
    3655             :                         {
    3656             :                                 OOVisualEffectEntity *vis = (OOVisualEffectEntity *)target;
    3657             :                                 GLColorWithOverallAlpha([vis scannerDisplayColorForShip:flash :[vis scannerDisplayColor1] :[vis scannerDisplayColor2]],alpha);
    3658             :                         }
    3659             :                         else
    3660             :                         {
    3661             :                                 GLColorWithOverallAlpha(green_color, alpha);
    3662             :                         }
    3663             :                 }
    3664             :                 else
    3665             :                 {
    3666             :                         OOColor *reticleDisplayColor = nil;
    3667             :                         if (reticleTargetSensitive && isTargeted)
    3668             :                         {
    3669             :                                 reticleDisplayColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_TARGET_SENSITIVE];
    3670             :                                 if (!reticleDisplayColor)  reticleDisplayColor = [OOColor redColor];
    3671             :                         }
    3672             :                         else
    3673             :                         {
    3674             :                                 reticleDisplayColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_TARGET];
    3675             :                                 if (!reticleDisplayColor)  reticleDisplayColor = [OOColor greenColor];
    3676             :                         }
    3677             :                         GLfloat reticleDisplayColorArray[4] = { [reticleDisplayColor redComponent],
    3678             :                                                                                                         [reticleDisplayColor greenComponent],
    3679             :                                                                                                         [reticleDisplayColor blueComponent],
    3680             :                                                                                                         [reticleDisplayColor alphaComponent] };
    3681             :                         GLColorWithOverallAlpha(reticleDisplayColorArray, alpha);
    3682             :                 }
    3683             :         }
    3684             :         OOGLBEGIN(GL_LINES);
    3685             :                 glVertex2f(rs0,rs2);    glVertex2f(rs0,rs0);
    3686             :                 glVertex2f(rs0,rs0);    glVertex2f(rs2,rs0);
    3687             :                 
    3688             :                 glVertex2f(rs0,-rs2);   glVertex2f(rs0,-rs0);
    3689             :                 glVertex2f(rs0,-rs0);   glVertex2f(rs2,-rs0);
    3690             :                 
    3691             :                 glVertex2f(-rs0,rs2);   glVertex2f(-rs0,rs0);
    3692             :                 glVertex2f(-rs0,rs0);   glVertex2f(-rs2,rs0);
    3693             :                 
    3694             :                 glVertex2f(-rs0,-rs2);  glVertex2f(-rs0,-rs0);
    3695             :                 glVertex2f(-rs0,-rs0);  glVertex2f(-rs2,-rs0);
    3696             :         OOGLEND();
    3697             :         
    3698             :         if (showText)
    3699             :         {
    3700             :                 // add text for reticle here
    3701             :                 range *= 0.001f;
    3702             :                 if (range < 0.001f) range = 0.0f;    // avoids the occasional -0.001 km distance.
    3703             :                 NSSize textsize = NSMakeSize(rdist * scale, rdist * scale);
    3704             :                 float line_height = rdist * scale;
    3705             :                 NSString*       infoline = [NSString stringWithFormat:@"%0.3f km", range];
    3706             :                 if (legal_desc != nil) infoline = [NSString stringWithFormat:@"%@ (%@)", infoline, legal_desc];
    3707             :                 // no need to set colour here
    3708             :                 OODrawString([player1 dialTargetName], rs0, 0.5 * rs2, 0, textsize);
    3709             :                 OODrawString(infoline, rs0, 0.5 * rs2 - line_height, 0, textsize);
    3710             :         
    3711             :                 if ([target isWormhole])
    3712             :                 {
    3713             :                         // Note: No break statements in the following switch() since every case
    3714             :                         //       falls through to the next.  Cases arranged in reverse order.
    3715             :                         switch([(WormholeEntity *)target scanInfo])
    3716             :                         {
    3717             :                         case WH_SCANINFO_SHIP:
    3718             :                                 // TOOD: Render anything on the HUD for this?
    3719             :                         case WH_SCANINFO_DESTINATION:
    3720             :                                 // Rendered above in dialTargetName, so no need to do anything here
    3721             :                                 // unless we want a separate line Destination: XXX ?
    3722             :                         case WH_SCANINFO_ARRIVAL_TIME:
    3723             :                         {
    3724             :                                 NSString *wormholeETA = [NSString stringWithFormat:DESC(@"wormhole-ETA-@"), ClockToString([(WormholeEntity *)target estimatedArrivalTime], NO)];
    3725             :                                 OODrawString(wormholeETA, rs0, 0.5 * rs2 - 3 * line_height, 0, textsize);
    3726             :                         }
    3727             :                         case WH_SCANINFO_COLLAPSE_TIME:
    3728             :                         {
    3729             :                                 OOTimeDelta timeForCollapsing = [(WormholeEntity *)target expiryTime] - [player1 clockTimeAdjusted];
    3730             :                                 int minutesToCollapse = floor (timeForCollapsing / 60.0);
    3731             :                                 int secondsToCollapse = (int)timeForCollapsing % 60;
    3732             :                                 
    3733             :                                 NSString *wormholeExpiringIn = [NSString stringWithFormat:DESC(@"wormhole-collapsing-in-mm:ss"), minutesToCollapse, secondsToCollapse];
    3734             :                                 OODrawString(wormholeExpiringIn, rs0, 0.5 * rs2 - 2 * line_height, 0, textsize);
    3735             :                         }
    3736             :                         case WH_SCANINFO_SCANNED:
    3737             :                         case WH_SCANINFO_NONE:
    3738             :                                 break;
    3739             :                         }
    3740             :                 }
    3741             :         }
    3742             :         
    3743             :         OOGLPopModelView();
    3744             : }
    3745             : 
    3746             : 
    3747           0 : static void hudDrawWaypoint(OOWaypointEntity *waypoint, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL selected, GLfloat scale)
    3748             : {
    3749             :         if ([player1 guiScreen] != GUI_SCREEN_MAIN)     // don't draw on text screens
    3750             :         {
    3751             :                 return;
    3752             :         }
    3753             :         
    3754             : 
    3755             :         Vector  p1 = HPVectorToVector(HPvector_subtract([waypoint position], [player1 viewpointPosition]));
    3756             : 
    3757             :         OOGLPushModelView();
    3758             :         hudRotateViewpointForVirtualDepth(player1,p1);
    3759             :         
    3760             :         // either close enough that single precision is fine or far enough
    3761             :         // away that precision is irrelevant
    3762             :         
    3763             :         GLfloat rdist = magnitude(p1);
    3764             :         GLfloat rsize = rdist * scale;
    3765             :         
    3766             :         GLfloat rs0 = rsize;
    3767             :         GLfloat rs2 = rsize * 0.50;
    3768             : 
    3769             :         if (selected)
    3770             :         {
    3771             :                 GLColorWithOverallAlpha(blue_color, alpha);
    3772             :         }
    3773             :         else
    3774             :         {
    3775             :                 GLColorWithOverallAlpha(blue_color, alpha*0.25);
    3776             :         }
    3777             : 
    3778             :         OOGLBEGIN(GL_LINES);
    3779             :                 glVertex2f(rs0,rs2);    glVertex2f(rs2,rs2);
    3780             :                 glVertex2f(rs2,rs0);    glVertex2f(rs2,rs2);
    3781             : 
    3782             :                 glVertex2f(-rs0,rs2);   glVertex2f(-rs2,rs2);
    3783             :                 glVertex2f(-rs2,rs0);   glVertex2f(-rs2,rs2);
    3784             : 
    3785             :                 glVertex2f(-rs0,-rs2);  glVertex2f(-rs2,-rs2);
    3786             :                 glVertex2f(-rs2,-rs0);  glVertex2f(-rs2,-rs2);
    3787             : 
    3788             :                 glVertex2f(rs0,-rs2);   glVertex2f(rs2,-rs2);
    3789             :                 glVertex2f(rs2,-rs0);   glVertex2f(rs2,-rs2);
    3790             : 
    3791             : //              glVertex2f(0,-rs2);     glVertex2f(0,rs2);
    3792             : //              glVertex2f(rs2,0);      glVertex2f(-rs2,0);
    3793             :         OOGLEND();
    3794             :         
    3795             :         if (selected)
    3796             :         {
    3797             :                 GLfloat range = HPdistance([player1 position],[waypoint position]) * 0.001f;
    3798             :                 if (range < 0.001f) range = 0.0f;    // avoids the occasional -0.001 km distance.
    3799             :                 NSSize textsize = NSMakeSize(rdist * scale, rdist * scale);
    3800             :                 float line_height = rdist * scale;
    3801             :                 NSString*       infoline = [NSString stringWithFormat:@"%0.3f km", range];
    3802             :                 OODrawString(infoline, rs0 * 0.5, -rs2 - line_height, 0, textsize);
    3803             :         }
    3804             : 
    3805             :         OOGLPopModelView();
    3806             : }
    3807             : 
    3808           0 : static void hudRotateViewpointForVirtualDepth(PlayerEntity * player1, Vector p1)
    3809             : {
    3810             :         Quaternion              back_q = [player1 orientation];
    3811             :         back_q.w = -back_q.w;   // invert
    3812             :         Vector                  v1 = vector_up_from_quaternion(back_q);
    3813             :         NSSize                  viewSize = [[UNIVERSE gameView] viewSize];
    3814             :         float                   aspect = viewSize.width / viewSize.height;
    3815             : 
    3816             :         // The field of view transformation is really a scale operation on the view window.
    3817             :         // We must unapply it through these transformations for them to be right.
    3818             :         // We must also take into account the window aspect ratio.
    3819             :         float ratio = 2 * [[UNIVERSE gameView] fov:YES]; // FIXME 2 is magic number; fov should integrate it
    3820             :         if (3.0f * aspect >= 4.0f)
    3821             :         {
    3822             :                 OOGLScaleModelView(make_vector(1/ratio, 1/ratio, 1.0f));
    3823             :         }
    3824             :         else
    3825             :         {
    3826             :                 OOGLScaleModelView(make_vector((4.0f/3.0f)/(aspect*ratio), (4.0f/3.0f)/(aspect*ratio), 1.0f));
    3827             :         }
    3828             : 
    3829             :         // deal with view directions
    3830             :         Vector view_dir, view_up = kBasisYVector;
    3831             :         switch ([UNIVERSE viewDirection])
    3832             :         {
    3833             :                 default:
    3834             :                 case VIEW_FORWARD:
    3835             :                         view_dir.x = 0.0;   view_dir.y = 0.0;   view_dir.z = 1.0;
    3836             :                         break;
    3837             :                         
    3838             :                 case VIEW_AFT:
    3839             :                         view_dir.x = 0.0;   view_dir.y = 0.0;   view_dir.z = -1.0;
    3840             :                         quaternion_rotate_about_axis(&back_q, v1, M_PI);
    3841             :                         break;
    3842             :                         
    3843             :                 case VIEW_PORT:
    3844             :                         view_dir.x = -1.0;   view_dir.y = 0.0;   view_dir.z = 0.0;
    3845             :                         quaternion_rotate_about_axis(&back_q, v1, 0.5 * M_PI);
    3846             :                         break;
    3847             :                         
    3848             :                 case VIEW_STARBOARD:
    3849             :                         view_dir.x = 1.0;   view_dir.y = 0.0;   view_dir.z = 0.0;
    3850             :                         quaternion_rotate_about_axis(&back_q, v1, -0.5 * M_PI);
    3851             :                         break;
    3852             :                         
    3853             :                 case VIEW_CUSTOM:
    3854             :                         view_dir = [player1 customViewForwardVector];
    3855             :                         view_up = [player1 customViewUpVector];
    3856             :                         back_q = quaternion_multiply([player1 customViewQuaternion], back_q);
    3857             :                         break;
    3858             :         }
    3859             :         OOGLLookAt(view_dir, kZeroVector, view_up);
    3860             : 
    3861             :         // rotate the view
    3862             :         OOGLMultModelView([player1 rotationMatrix]);
    3863             :         // translate the view
    3864             :         OOGLTranslateModelView(p1);
    3865             :         // rotate to face player1
    3866             :         OOGLMultModelView(OOMatrixForQuaternionRotation(back_q));
    3867             : 
    3868             :         // We come back now to the previous scale.
    3869             :         OOGLScaleModelView(make_vector(ratio, ratio, 1.0f));
    3870             :         // draw the waypoint
    3871             : }
    3872             : 
    3873             : 
    3874           0 : static void InitTextEngine(void)
    3875             : {
    3876             :         NSDictionary                    *fontSpec = nil;
    3877             :         NSArray                                 *widths = nil;
    3878             :         NSString                                *texName = nil;
    3879             :         NSUInteger                              i, count;
    3880             :         
    3881             :         fontSpec = [ResourceManager dictionaryFromFilesNamed:@"oolite-font.plist"
    3882             :                                                                                                 inFolder:@"Config"
    3883             :                                                                                                 andMerge:NO];
    3884             :         
    3885             :         texName = [fontSpec oo_stringForKey:@"texture" defaultValue:@"oolite-font.png"];
    3886             :         sFontTexture = [OOTexture textureWithName:texName
    3887             :                                                                          inFolder:@"Textures"
    3888             :                                                                           options:kFontTextureOptions
    3889             :                                                                    anisotropy:0.0f
    3890             :                                                                           lodBias:-0.75f];
    3891             :         [sFontTexture retain];
    3892             :         
    3893             :         sF6KernGovt = [fontSpec oo_floatForKey:@"f6KernGovernment" defaultValue:1.0]; 
    3894             :         sF6KernTL = [fontSpec oo_floatForKey:@"f6KernTechLevel" defaultValue:2.0];
    3895             : 
    3896             :         sEncodingCoverter = [[OOEncodingConverter alloc] initWithFontPList:fontSpec];
    3897             :         widths = [fontSpec oo_arrayForKey:@"widths"];
    3898             :         count = [widths count];
    3899             :         if (count > 256)  count = 256;
    3900             :         for (i = 0; i != count; ++i)
    3901             :         {
    3902             :                 sGlyphWidths[i] = [widths oo_floatAtIndex:i] * GLYPH_SCALE_FACTOR;
    3903             :         }
    3904             : }
    3905             : 
    3906             : 
    3907           0 : void OOHUDResetTextEngine(void)
    3908             : {
    3909             :         DESTROY(sFontTexture);
    3910             :         DESTROY(sEncodingCoverter);
    3911             : }
    3912             : 
    3913             : 
    3914             : static GLfloat drawCharacterQuad(uint8_t chr, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
    3915             : {
    3916             :         // 31 (narrow space) and 32 (space) are non-printing characters, so
    3917             :         // don't print them, just return their width to move the pointer
    3918             :         if (chr > 32 || chr < 31) {
    3919             :                 GLfloat texture_x = ONE_SIXTEENTH * (chr & 0x0f);
    3920             :                 GLfloat texture_y = ONE_SIXTEENTH * (chr >> 4);
    3921             :                 if (chr > 32)  y += ONE_EIGHTH * siz.height; // Adjust for baseline offset change in 1.71 (needed to keep accented characters in box)
    3922             :         
    3923             :                 glTexCoord2f(texture_x, texture_y + ONE_SIXTEENTH);
    3924             :                 glVertex3f(x, y, z);
    3925             :                 glTexCoord2f(texture_x + ONE_SIXTEENTH, texture_y + ONE_SIXTEENTH);
    3926             :                 glVertex3f(x + siz.width, y, z);
    3927             :                 glTexCoord2f(texture_x + ONE_SIXTEENTH, texture_y);
    3928             :                 glVertex3f(x + siz.width, y + siz.height, z);
    3929             :                 glTexCoord2f(texture_x, texture_y);
    3930             :                 glVertex3f(x, y + siz.height, z);
    3931             :         }
    3932             :         return siz.width * sGlyphWidths[chr];
    3933             : }
    3934             : 
    3935             : 
    3936           0 : NSRect OORectFromString(NSString *text, GLfloat x, GLfloat y, NSSize siz)
    3937             : {
    3938             :         GLfloat                         w = 0;
    3939             :         NSData                          *data = nil;
    3940             :         const uint8_t           *bytes = NULL;
    3941             :         NSUInteger                      i, length;
    3942             :         
    3943             :         data = [sEncodingCoverter convertString:text];
    3944             :         bytes = [data bytes];
    3945             :         length = [data length];
    3946             :         
    3947             :         for (i = 0; i < length; i++)
    3948             :         {
    3949             :                 w += siz.width * sGlyphWidths[bytes[i]];
    3950             :         }
    3951             :         
    3952             :         return NSMakeRect(x, y, w, siz.height);
    3953             : }
    3954             : 
    3955             : 
    3956           0 : CGFloat OOStringWidthInEm(NSString *text)
    3957             : {
    3958             :         return OORectFromString(text, 0, 0, NSMakeSize(1.0 / (GLYPH_SCALE_FACTOR * 8.0), 1.0)).size.width;
    3959             : }
    3960             : 
    3961             : 
    3962           0 : void drawHighlight(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat alpha)
    3963             : {
    3964             :         // Rounded corners, fading 'shadow' version
    3965             :         OOGL(glColor4f(0.0f, 0.0f, 0.0f, alpha * 0.4f));        // dark translucent shadow
    3966             :         
    3967             :         OOGLBEGIN(GL_POLYGON);
    3968             :                 // thin 'halo' around the 'solid' highlight
    3969             :                 glVertex3f(x + 1.0f , y + siz.height + 2.5f, z);
    3970             :                 glVertex3f(x + siz.width + 3.0f, y + siz.height + 2.5f, z);
    3971             :                 glVertex3f(x + siz.width + 4.5f, y + siz.height + 1.0f, z);
    3972             :                 glVertex3f(x + siz.width + 4.5f, y + 3.0f, z);
    3973             :                 glVertex3f(x + siz.width + 3.0f, y + 1.5f, z);
    3974             :                 glVertex3f(x + 1.0f, y + 1.5f, z);
    3975             :                 glVertex3f(x - 0.5f, y + 3.0f, z);
    3976             :                 glVertex3f(x - 0.5f, y + siz.height + 1.0f, z);
    3977             :         OOGLEND();
    3978             : 
    3979             :         
    3980             :         OOGLBEGIN(GL_POLYGON);
    3981             :                 glVertex3f(x + 1.0f, y + siz.height + 2.0f, z);
    3982             :                 glVertex3f(x + siz.width + 3.0f, y + siz.height + 2.0f, z);
    3983             :                 glVertex3f(x + siz.width + 4.0f, y + siz.height + 1.0f, z);
    3984             :                 glVertex3f(x + siz.width + 4.0f, y + 3.0f, z);
    3985             :                 glVertex3f(x + siz.width + 3.0f, y + 2.0f, z);
    3986             :                 glVertex3f(x + 1.0f, y + 2.0f, z);
    3987             :                 glVertex3f(x, y + 3.0f, z);
    3988             :                 glVertex3f(x, y + siz.height + 1.0f, z);
    3989             :         OOGLEND();
    3990             : }
    3991             : 
    3992             : 
    3993           0 : void OODrawString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
    3994             : {
    3995             :         OODrawStringAligned(text,x,y,z,siz,NO);
    3996             : }
    3997             : 
    3998             : 
    3999           0 : void OODrawStringAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
    4000             : {
    4001             :         OOStartDrawingStrings();
    4002             :         OODrawStringQuadsAligned(text,x,y,z,siz,rightAlign);
    4003             :         OOStopDrawingStrings();
    4004             : }
    4005             : 
    4006           0 : void OOStartDrawingStrings() {
    4007             :         OOSetOpenGLState(OPENGL_STATE_OVERLAY);
    4008             :         
    4009             :         OOGL(glEnable(GL_TEXTURE_2D));
    4010             :         [sFontTexture apply];
    4011             :         OOGLBEGIN(GL_QUADS);
    4012             : 
    4013             : }
    4014             : 
    4015           0 : void OODrawStringQuadsAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
    4016             : {
    4017             :         GLfloat                 cx = x;
    4018             :         NSInteger               i, length;
    4019             :         NSData                  *data = nil;
    4020             :         const uint8_t   *bytes = NULL;
    4021             :         
    4022             :         data = [sEncodingCoverter convertString:text];
    4023             :         length = [data length];
    4024             :         bytes = [data bytes];
    4025             : 
    4026             :         if (EXPECT_NOT(rightAlign))
    4027             :         {
    4028             :                 cx -= OORectFromString(text, 0.0f, 0.0f, siz).size.width;
    4029             :         }
    4030             : 
    4031             :         for (i = 0; i < length; i++)
    4032             :         {
    4033             :                 cx += drawCharacterQuad(bytes[i], cx, y, z, siz);
    4034             :         }
    4035             : }
    4036             : 
    4037           0 : void OOStopDrawingStrings() {
    4038             :         OOGLEND();
    4039             :         
    4040             :         [OOTexture applyNone];
    4041             :         OOGL(glDisable(GL_TEXTURE_2D));
    4042             :         
    4043             :         OOVerifyOpenGLState();
    4044             : }
    4045             : 
    4046             : 
    4047           0 : void OODrawHilightedString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
    4048             : {
    4049             :         GLfloat color[4];
    4050             :         
    4051             :         // get the physical dimensions of the string
    4052             :         NSSize strsize = OORectFromString(text, 0.0f, 0.0f, siz).size;
    4053             :         strsize.width += 0.5f;
    4054             :         
    4055             :         OOSetOpenGLState(OPENGL_STATE_OVERLAY);
    4056             :         
    4057             :         OOGL(glPushAttrib(GL_CURRENT_BIT));     // save the text colour
    4058             :         OOGL(glGetFloatv(GL_CURRENT_COLOR, color));     // we need the original colour's alpha.
    4059             :         
    4060             :         drawHighlight(x, y, z, strsize, color[3]);
    4061             :         
    4062             :         OOGL(glPopAttrib());    //restore the colour
    4063             :         
    4064             :         OODrawString(text, x, y, z, siz);
    4065             :         
    4066             :         OOVerifyOpenGLState();
    4067             : }
    4068             : 
    4069             : 
    4070           0 : void OODrawPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
    4071             : {
    4072             :         GLfloat govcol[] = {    0.5, 0.0, 0.7,
    4073             :                                                         0.7, 0.5, 0.3,
    4074             :                                                         0.0, 1.0, 0.3,
    4075             :                                                         1.0, 0.8, 0.1,
    4076             :                                                         1.0, 0.0, 0.0,
    4077             :                                                         0.1, 0.5, 1.0,
    4078             :                                                         0.7, 0.7, 0.7,
    4079             :                                                         0.7, 1.0, 1.0};
    4080             :         
    4081             :         GLfloat cx = x;
    4082             :         int tl = tec + 1;
    4083             :         GLfloat ce1 = 1.0f - 0.125f * eco;
    4084             :         
    4085             :         OOSetOpenGLState(OPENGL_STATE_OVERLAY);
    4086             :         
    4087             :         OOGL(glEnable(GL_TEXTURE_2D));
    4088             :         [sFontTexture apply];
    4089             : 
    4090             :         OOGLBEGIN(GL_QUADS);
    4091             :         {
    4092             :                 [[UNIVERSE gui] setGLColorFromSetting:[NSString stringWithFormat:kGuiChartEconomyUColor, (unsigned long)eco]
    4093             :                                                                  defaultValue:[OOColor colorWithRed:ce1 green:1.0f blue:0.0f alpha:1.0f] 
    4094             :                                                                                 alpha:1.0];
    4095             : 
    4096             :                 // see OODrawHilightedPlanetInfo
    4097             :                 cx += drawCharacterQuad(23 - eco, cx, y, z, siz);       // characters 16..23 are economy symbols
    4098             :                 [[UNIVERSE gui] setGLColorFromSetting:[NSString stringWithFormat:kGuiChartGovernmentUColor, (unsigned long)gov]
    4099             :                                                                  defaultValue:[OOColor colorWithRed:govcol[gov*3] green:govcol[1+(gov*3)] blue:govcol[2+(gov*3)] alpha:1.0f] 
    4100             :                                                                                 alpha:1.0];
    4101             : 
    4102             :                 cx += drawCharacterQuad(gov, cx, y, z, siz) - sF6KernGovt;              // charcters 0..7 are government symbols
    4103             :                 [[UNIVERSE gui] setGLColorFromSetting:kGuiChartTechColor
    4104             :                                                                  defaultValue:[OOColor colorWithRed:0.5 green:1.0f blue:1.0f alpha:1.0f] 
    4105             :                                                                                 alpha:1.0];
    4106             : 
    4107             :                 if (tl > 9)
    4108             :                 {
    4109             :                         // display TL clamped between 1..16, this must be a '1'!
    4110             :                         cx += drawCharacterQuad(49, cx, y - 2, z, siz) - sF6KernTL;
    4111             :                 }
    4112             :                 cx += drawCharacterQuad(48 + (tl % 10), cx, y - 2.0f, z, siz);
    4113             :         }
    4114             :         OOGLEND();
    4115             :         
    4116             :         (void)cx;       // Suppress "value not used" analyzer issue.
    4117             :         
    4118             :         [OOTexture applyNone];
    4119             :         OOGL(glDisable(GL_TEXTURE_2D));
    4120             :         
    4121             :         OOVerifyOpenGLState();
    4122             : }
    4123             : 
    4124             : 
    4125           0 : void OODrawHilightedPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
    4126             : {
    4127             :         float   color[4];
    4128             :         int             tl = tec + 1;
    4129             :         
    4130             :         NSSize  hisize;
    4131             :         
    4132             :         // get the physical dimensions
    4133             :         hisize.height = siz.height;
    4134             :         hisize.width = 0.0f;
    4135             :         
    4136             :         // see OODrawPlanetInfo
    4137             :         hisize.width += siz.width * sGlyphWidths[23 - eco];
    4138             :         hisize.width += siz.width * sGlyphWidths[gov] - 1.0;
    4139             :         if (tl > 9) hisize.width += siz.width * sGlyphWidths[49] - 2.0;
    4140             :         hisize.width += siz.width * sGlyphWidths[48 + (tl % 10)];
    4141             :         
    4142             :         OOSetOpenGLState(OPENGL_STATE_OVERLAY);
    4143             :         
    4144             :         OOGL(glPushAttrib(GL_CURRENT_BIT));     // save the text colour
    4145             :         OOGL(glGetFloatv(GL_CURRENT_COLOR, color));     // we need the original colour's alpha.
    4146             :         
    4147             :         drawHighlight(x, y - 2.0f, z, hisize, color[3]);
    4148             :         
    4149             :         OOGL(glPopAttrib());    //restore the colour
    4150             :         
    4151             :         OODrawPlanetInfo(gov, eco, tec, x, y, z, siz);
    4152             :         
    4153             :         OOVerifyOpenGLState();
    4154             : }
    4155             : 
    4156           0 : static void GLDrawNonlinearCascadeWeapon( GLfloat x, GLfloat y, GLfloat z, NSSize siz, Vector centre, GLfloat radius, GLfloat zoom, GLfloat alpha )
    4157             : {
    4158             :         Vector spacepos, scannerpos;
    4159             :         GLfloat theta, phi;
    4160             :         GLfloat z_factor = siz.height / siz.width;      // approx 1/4
    4161             :         GLfloat y_factor = 1.0 - sqrt(z_factor);        // approx 1/2
    4162             :         OOGLVector *points = malloc(sizeof(OOGLVector)*25);
    4163             :         int i, j;
    4164             :         
    4165             :         if (radius*radius > centre.y*centre.y)
    4166             :         {
    4167             :                 GLfloat r0 = sqrt(radius*radius-centre.y*centre.y);
    4168             :                 OOGL(glColor4f(1.0, 0.5, 1.0, alpha));
    4169             :                 spacepos.y = 0;
    4170             :                 for (i = 0; i < 24; i++)
    4171             :                 {
    4172             :                         theta = i*2*M_PI/24;
    4173             :                         spacepos.x = centre.x + r0 * cos(theta);
    4174             :                         spacepos.z = centre.z + r0 * sin(theta);
    4175             :                         scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
    4176             :                         points[i].x = x + scannerpos.x;
    4177             :                         points[i].y = y + scannerpos.z * z_factor + scannerpos.y * y_factor;
    4178             :                         points[i].z = z;
    4179             :                 }
    4180             :                 spacepos.x = centre.x + r0;
    4181             :                 spacepos.y = 0;
    4182             :                 spacepos.z = centre.z;
    4183             :                 scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
    4184             :                 points[24].x = x + scannerpos.x;
    4185             :                 points[24].y = y + scannerpos.z * z_factor + scannerpos.y * y_factor;
    4186             :                 points[24].z = z;
    4187             :                 GLDrawPoints(points,25);
    4188             :         }
    4189             :         OOGL(glColor4f(0.5, 0.0, 1.0, 0.33333 * alpha));
    4190             :         free(points);
    4191             :         // Here, we draw a sphere distorted by the nonlinear function. We draw the sphere as a set of horizontal strips
    4192             :         // The even indices of points are the points on the upper edge of the strip, while odd indices are points
    4193             :         // on the bottom edge.
    4194             :         points = malloc(sizeof(OOGLVector)*50);
    4195             :         spacepos.x = centre.x;
    4196             :         spacepos.y = centre.y + radius;
    4197             :         spacepos.z = centre.z;
    4198             :         scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
    4199             :         for (i = 0; i <= 24; i++)
    4200             :         {
    4201             :                 points[2*i+1].x = x + scannerpos.x;
    4202             :                 points[2*i+1].y = y + scannerpos.y * y_factor + scannerpos.z * z_factor;
    4203             :                 points[2*i+1].z = z;
    4204             :         }
    4205             :         for (i = 1; i <= 24; i++)
    4206             :         {
    4207             :                 theta = i*M_PI/24;
    4208             :                 for (j = 0; j <= 24; j++)
    4209             :                 {
    4210             :                         phi = j*M_PI/12;
    4211             :                         // copy point from bottom edge of previous strip into top edge position
    4212             :                         points[2*j] = points[2*j+1];
    4213             : 
    4214             :                         spacepos.x = centre.x + radius * sin(theta) * cos(phi);
    4215             :                         spacepos.y = centre.y + radius * cos(theta);
    4216             :                         spacepos.z = centre.z + radius * sin(theta) * sin(phi);
    4217             :                         scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
    4218             :                         points[2*j+1].x = x + scannerpos.x;
    4219             :                         points[2*j+1].y = y + scannerpos.y * y_factor + scannerpos.z * z_factor;
    4220             :                         points[2*j+1].z = z;
    4221             :                 }
    4222             :                 GLDrawQuadStrip(points, 50);
    4223             :         }
    4224             :         free(points);
    4225             :         return;
    4226             : }
    4227             : 
    4228           0 : static GLfloat nonlinearScannerFunc( GLfloat distance, GLfloat zoom, GLfloat scale )
    4229             : {
    4230             :         GLfloat x = fabs(distance / SCANNER_MAX_RANGE);
    4231             :         if (x >= 1.0)
    4232             :                 return scale;
    4233             :         if (zoom <= 1.0)
    4234             :                 return scale * x;
    4235             :         GLfloat c = 1 / ( zoom - 1 );
    4236             :         GLfloat b = c * ( c + 1 );
    4237             :         GLfloat a = c + 1;
    4238             :         return scale * ( a - b / ( x + c ) );
    4239             : }
    4240             : 
    4241             : 
    4242           0 : static void drawScannerGrid(GLfloat x, GLfloat y, GLfloat z, NSSize siz, int v_dir, GLfloat thickness, GLfloat zoom, BOOL nonlinear, BOOL minimalistic)
    4243             : {
    4244             :         OOSetOpenGLState(OPENGL_STATE_OVERLAY);
    4245             : 
    4246             :         MyOpenGLView* gameView = [UNIVERSE gameView];
    4247             : 
    4248             :         GLfloat w1, h1;
    4249             :         GLfloat ww = 0.5 * siz.width;
    4250             :         GLfloat hh = 0.5 * siz.height;
    4251             :         
    4252             :         GLfloat km_scan;
    4253             :         GLfloat hdiv;
    4254             :         GLfloat wdiv;
    4255             :         BOOL drawdiv = NO, drawdiv1 = NO, drawdiv5 = NO;
    4256             :         
    4257             :         int i, ii;
    4258             :         
    4259             :         OOGL(GLScaledLineWidth(2.0 * thickness));
    4260             :         GLDrawOval(x, y, z, siz, 4);
    4261             :         OOGL(GLScaledLineWidth(thickness)); // reset (thickness = lineWidth)
    4262             :         
    4263             :         OOGLBEGIN(GL_LINES);
    4264             :                 if (!minimalistic)
    4265             :                 {
    4266             :                         glVertex3f(x, y - hh, z);       glVertex3f(x, y + hh, z);
    4267             :                         glVertex3f(x - ww, y, z);       glVertex3f(x + ww, y, z);
    4268             :         
    4269             :                         if (nonlinear)
    4270             :                         {
    4271             :                                 if (nonlinearScannerFunc(4000.0, zoom, hh)-nonlinearScannerFunc(3000.0, zoom ,hh) > 2) drawdiv1 = YES;
    4272             :                                 if (nonlinearScannerFunc(10000.0, zoom, hh)-nonlinearScannerFunc(5000.0, zoom, hh) > 2) drawdiv5 = YES;
    4273             :                                 wdiv = ww/(0.001*SCANNER_MAX_RANGE);
    4274             :                                 for (i = 1; 1000.0*i < SCANNER_MAX_RANGE; i++)
    4275             :                                 {
    4276             :                                         drawdiv = drawdiv1;
    4277             :                                         w1 = wdiv;
    4278             :                                         if (i % 10 == 0)
    4279             :                                         {
    4280             :                                                 w1 = wdiv*4;
    4281             :                                                 drawdiv = YES;
    4282             :                                                 if (nonlinearScannerFunc((i+5)*1000,zoom,hh) - nonlinearScannerFunc(i*1000.0,zoom,hh)>2)
    4283             :                                                 {
    4284             :                                                         drawdiv5 = YES;
    4285             :                                                 }
    4286             :                                                 else
    4287             :                                                 {
    4288             :                                                         drawdiv5 = NO;
    4289             :                                                 }
    4290             :                                         }
    4291             :                                         else if (i % 5 == 0)
    4292             :                                         {
    4293             :                                                 w1 = wdiv*2;
    4294             :                                                 drawdiv = drawdiv5;
    4295             :                                                 if (nonlinearScannerFunc((i+1)*1000,zoom,hh) - nonlinearScannerFunc(i*1000.0,zoom,hh)>2)
    4296             :                                                 {
    4297             :                                                         drawdiv1 = YES;
    4298             :                                                 }
    4299             :                                                 else
    4300             :                                                 {
    4301             :                                                         drawdiv1 = NO;
    4302             :                                                 }
    4303             :                                         }
    4304             :                                         if (drawdiv)
    4305             :                                         {
    4306             :                                                 h1 = nonlinearScannerFunc(i*1000.0,zoom,hh);
    4307             :                                                 glVertex3f(x - w1, y + h1, z);  glVertex3f(x + w1, y + h1, z);
    4308             :                                                 glVertex3f(x - w1, y - h1, z);  glVertex3f(x + w1, y - h1, z);
    4309             :                                         }
    4310             :                                 }
    4311             :                         }
    4312             :                         else
    4313             :                         {
    4314             :                                 km_scan = 0.001 * SCANNER_MAX_RANGE / zoom;     // calculate kilometer divisions
    4315             :                                 hdiv = 0.5 * siz.height / km_scan;
    4316             :                                 wdiv = 0.25 * siz.width / km_scan;
    4317             :                                 if (wdiv < 4.0)
    4318             :                                 {
    4319             :                                         wdiv *= 2.0;
    4320             :                                         ii = 5;
    4321             :                                 }
    4322             :                                 else
    4323             :                                 {
    4324             :                                         ii = 1;
    4325             :                                 }
    4326             :                 
    4327             :                                 for (i = ii; 2.0 * hdiv * i < siz.height; i += ii)
    4328             :                                 {
    4329             :                                         h1 = i * hdiv;
    4330             :                                         w1 = wdiv;
    4331             :                                         if (i % 5 == 0)
    4332             :                                                 w1 = w1 * 2.5;
    4333             :                                         if (i % 10 == 0)
    4334             :                                                 w1 = w1 * 2.0;
    4335             :                                         if (w1 > 3.5)        // don't draw tiny marks
    4336             :                                         {
    4337             :                                                 glVertex3f(x - w1, y + h1, z);  glVertex3f(x + w1, y + h1, z);
    4338             :                                                 glVertex3f(x - w1, y - h1, z);  glVertex3f(x + w1, y - h1, z);
    4339             :                                         }
    4340             :                                 }
    4341             :                         }
    4342             :                 }
    4343             : 
    4344             :                 double tanfov = [gameView fov:YES];
    4345             :                 GLfloat aspect = [gameView viewSize].width / [gameView viewSize].height;
    4346             :                 if (aspect < 4.0/3.0)
    4347             :                 {
    4348             :                         tanfov *= 0.75 * aspect;
    4349             :                 }
    4350             :                 double cosfov = 1.0/sqrt(1+tanfov*tanfov);
    4351             :                 double sinfov = tanfov * cosfov;
    4352             : 
    4353             :                 switch (v_dir)
    4354             :                 {
    4355             :                         case VIEW_BREAK_PATTERN:
    4356             :                         case VIEW_GUI_DISPLAY:
    4357             :                         case VIEW_FORWARD:
    4358             :                         case VIEW_NONE:
    4359             :                                 glVertex3f(x, y, z); glVertex3f(x - ww * sinfov, y + hh * cosfov, z);
    4360             :                                 glVertex3f(x, y, z); glVertex3f(x + ww * sinfov, y + hh * cosfov, z);
    4361             :                                 break;
    4362             :                                 
    4363             :                         case VIEW_AFT:
    4364             :                                 glVertex3f(x, y, z); glVertex3f(x - ww * sinfov, y - hh * cosfov, z);
    4365             :                                 glVertex3f(x, y, z); glVertex3f(x + ww * sinfov, y - hh * cosfov, z);
    4366             :                                 break;
    4367             :                                 
    4368             :                         case VIEW_PORT:
    4369             :                                 glVertex3f(x, y, z); glVertex3f(x - ww * cosfov, y + hh * sinfov, z);
    4370             :                                 glVertex3f(x, y, z); glVertex3f(x - ww * cosfov, y - hh * sinfov, z);
    4371             :                                 break;
    4372             :                                 
    4373             :                         case VIEW_STARBOARD:
    4374             :                                 glVertex3f(x, y, z); glVertex3f(x + ww * cosfov, y + hh * sinfov, z);
    4375             :                                 glVertex3f(x, y, z); glVertex3f(x + ww * cosfov, y - hh * sinfov, z);
    4376             :                                 break;
    4377             :                 }
    4378             :         OOGLEND();
    4379             :         
    4380             :         OOVerifyOpenGLState();
    4381             : }
    4382             : 
    4383             : 
    4384           0 : static void DrawSpecialOval(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat step, GLfloat *color4v)
    4385             : {
    4386             :         GLfloat                 ww = 0.5 * siz.width;
    4387             :         GLfloat                 hh = 0.5 * siz.height;
    4388             :         GLfloat                 theta;
    4389             :         GLfloat                 delta;
    4390             :         GLfloat                 s;
    4391             :         
    4392             :         delta = step * M_PI / 180.0f;
    4393             :         
    4394             :         OOGLBEGIN(GL_LINE_LOOP);
    4395             :                 for (theta = 0.0f; theta < (2.0f * M_PI); theta += delta)
    4396             :                 {
    4397             :                         s = sin(theta);
    4398             :                         glColor4f(color4v[0], color4v[1], color4v[2], fabs(s * color4v[3]));
    4399             :                         glVertex3f(x + ww * s, y + hh * cos(theta), z);
    4400             :                 }
    4401             :         OOGLEND();
    4402             : }
    4403             : 
    4404             : 
    4405             : - (void) setLineWidth:(GLfloat) value
    4406             : {
    4407             :         lineWidth = value;
    4408             : }
    4409             : 
    4410             : 
    4411             : - (GLfloat) lineWidth
    4412             : {
    4413             :         return lineWidth;
    4414             : }
    4415             : 
    4416             : @end
    4417             : 
    4418             : 
    4419             : @implementation NSString (OODisplayEncoding)
    4420             : 
    4421             : - (const char *) cStringUsingOoliteEncoding
    4422             : {
    4423             :         if (sEncodingCoverter == nil)  InitTextEngine();
    4424             :         
    4425             :         // Note: the data will be autoreleased, so the bytes behave as though they're autoreleased too.
    4426             :         return [[self dataUsingEncoding:[sEncodingCoverter encoding] allowLossyConversion:YES] bytes];
    4427             : }
    4428             : 
    4429             : 
    4430             : - (const char *) cStringUsingOoliteEncodingAndRemapping
    4431             : {
    4432             :         if (sEncodingCoverter == nil)  InitTextEngine();
    4433             :         
    4434             :         // Note: the data will be autoreleased, so the bytes behave as though they're autoreleased too.
    4435             :         return [[sEncodingCoverter convertString:self] bytes];
    4436             : }
    4437             : 
    4438             : @end
    4439             : 
    4440             : 
    4441             : @implementation OOPolygonSprite (OOHUDBeaconIcon)
    4442             : 
    4443           0 : - (void) oo_drawHUDBeaconIconAt:(NSPoint)where size:(NSSize)size alpha:(GLfloat)alpha z:(GLfloat)z
    4444             : {
    4445             :         GLfloat x = where.x - size.width;
    4446             :         GLfloat y = where.y - 1.5 * size.height;
    4447             :         
    4448             :         GLfloat ox = x - size.width * 0.5;
    4449             :         GLfloat oy = y - size.height * 0.5;
    4450             :         GLfloat width = size.width * (1.0f / 6.0f);
    4451             :         GLfloat height = size.height * (1.0f / 6.0f);
    4452             :         
    4453             :         OOGLPushModelView();
    4454             :         OOGLTranslateModelView(make_vector(ox, oy, z));
    4455             :         OOGLScaleModelView(make_vector(width, height, 1.0f));
    4456             :         [self drawFilled];
    4457             :         glColor4f(0.0, 0.0, 0.0, 0.5 * alpha);
    4458             :         [self drawOutline];
    4459             :         OOGLPopModelView();
    4460             : }
    4461             : 
    4462             : @end
    4463             : 
    4464             : 
    4465             : @implementation NSString (OOHUDBeaconIcon)
    4466             : 
    4467           0 : - (void) oo_drawHUDBeaconIconAt:(NSPoint)where size:(NSSize)size alpha:(GLfloat)alpha z:(GLfloat)z
    4468             : {
    4469             :         OODrawString(self, where.x - 2.5 * size.width, where.y - 3.0 * size.height, z, NSMakeSize(size.width * 2, size.height * 2));
    4470             : }
    4471             : 
    4472             : @end
    4473             : 
    4474             : 
    4475           0 : static void SetGLColourFromInfo(NSDictionary *info, NSString *key, const GLfloat defaultColor[4], GLfloat alpha)
    4476             : {
    4477             :         id                      colorDesc = nil;
    4478             :         OOColor         *color = nil;
    4479             :         colorDesc = [info objectForKey:key];
    4480             :         if (colorDesc != nil)
    4481             :         {
    4482             :                 color = [OOColor colorWithDescription:colorDesc];
    4483             :                 if (color != nil)
    4484             :                 {
    4485             :                         GLfloat ioColor[4];
    4486             :                         [color getRed:&ioColor[0] green:&ioColor[1] blue:&ioColor[2] alpha:&ioColor[3]];
    4487             :                         GLColorWithOverallAlpha(ioColor,alpha);
    4488             :                         return;
    4489             :                 }       
    4490             :         }       
    4491             :         GLColorWithOverallAlpha(defaultColor,alpha);
    4492             : }
    4493             : 
    4494             : 
    4495           0 : static void GetRGBAArrayFromInfo(NSDictionary *info, GLfloat ioColor[4])
    4496             : {
    4497             :         id                                              colorDesc = nil;
    4498             :         OOColor                                 *color = nil;
    4499             :         
    4500             :         // First, look for general colour specifier.
    4501             :         colorDesc = [info objectForKey:RGB_COLOR_KEY];
    4502             :         if (colorDesc != nil && ![info objectForKey:ALPHA_KEY])
    4503             :         {
    4504             :                 color = [OOColor colorWithDescription:colorDesc];
    4505             :                 if (color != nil)
    4506             :                 {
    4507             :                         [color getRed:&ioColor[0] green:&ioColor[1] blue:&ioColor[2] alpha:&ioColor[3]];
    4508             :                         return;
    4509             :                 }
    4510             :         }
    4511             :         
    4512             :         // Failing that, look for rgb_color and alpha.
    4513             :         colorDesc = [info oo_arrayForKey:RGB_COLOR_KEY];
    4514             :         if (colorDesc != nil && [colorDesc count] == 3)
    4515             :         {
    4516             :                 ioColor[0] = [colorDesc oo_nonNegativeFloatAtIndex:0];
    4517             :                 ioColor[1] = [colorDesc oo_nonNegativeFloatAtIndex:1];
    4518             :                 ioColor[2] = [colorDesc oo_nonNegativeFloatAtIndex:2];
    4519             :         }
    4520             :         ioColor[3] = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:ioColor[3]];
    4521             : }

Generated by: LCOV version 1.14