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 : }
|