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 : struct CachedInfo cached;
3069 :
3070 : [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3071 :
3072 : x = useDefined(cached.x, WEAPONSOFFLINETEXT_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
3073 : y = useDefined(cached.y, WEAPONSOFFLINETEXT_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
3074 : siz.width = useDefined(cached.width, WEAPONSOFFLINETEXT_WIDTH);
3075 : siz.height = useDefined(cached.height, WEAPONSOFFLINETEXT_HEIGHT);
3076 :
3077 : GetRGBAArrayFromInfo(info, textColor);
3078 : textColor[3] *= overallAlpha;
3079 :
3080 : OOGL(glColor4f(textColor[0], textColor[1], textColor[2], textColor[3]));
3081 : // TODO: some caching required...
3082 : OODrawString(DESC(@"weapons-systems-offline"), x, y, z1, siz);
3083 : }
3084 : }
3085 :
3086 :
3087 0 : - (void) drawFPSInfoCounter:(NSDictionary *)info
3088 : {
3089 : if (![UNIVERSE displayFPS]) return;
3090 :
3091 : int x, y;
3092 : NSSize siz;
3093 : struct CachedInfo cached;
3094 : GLfloat textColor[4] = {0.0, 1.0, 0.0, 1.0};
3095 :
3096 : [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3097 :
3098 : x = useDefined(cached.x, FPSINFO_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
3099 : y = useDefined(cached.y, FPSINFO_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
3100 : siz.width = useDefined(cached.width, FPSINFO_DISPLAY_WIDTH);
3101 : siz.height = useDefined(cached.height, FPSINFO_DISPLAY_HEIGHT);
3102 :
3103 : HPVector playerPos = [PLAYER position];
3104 : NSString *positionInfo = [UNIVERSE expressPosition:playerPos inCoordinateSystem:@"pwm"];
3105 : positionInfo = [NSString stringWithFormat:@"abs %.2f %.2f %.2f / %@", playerPos.x, playerPos.y, playerPos.z, positionInfo];
3106 :
3107 : // We would normally set a variable alpha value here, but in this case we don't.
3108 : // We prefer the FPS counter to be always visible - Nikos 20100405
3109 : GetRGBAArrayFromInfo(info, textColor);
3110 : OOGL(glColor4f(textColor[0], textColor[1], textColor[2], 1.0f));
3111 : OODrawString([PLAYER dial_fpsinfo], x, y, z1, siz);
3112 :
3113 : #ifndef NDEBUG
3114 : NSSize siz08 = NSMakeSize(0.8 * siz.width, 0.8 * siz.width);
3115 : NSString *collDebugInfo = [NSString stringWithFormat:@"%@ - %@", [PLAYER dial_objinfo], [UNIVERSE collisionDescription]];
3116 : OODrawString(collDebugInfo, x, y - siz.height, z1, siz);
3117 :
3118 : OODrawString(positionInfo, x, y - 1.8 * siz.height, z1, siz08);
3119 :
3120 : NSString *timeAccelerationFactorInfo = [NSString stringWithFormat:@"TAF: %@%.2f", DESC(@"multiplication-sign"), [UNIVERSE timeAccelerationFactor]];
3121 : OODrawString(timeAccelerationFactorInfo, x, y - 3.2 * siz08.height, z1, siz08);
3122 : #endif
3123 : }
3124 :
3125 :
3126 0 : - (void) drawScoopStatus:(NSDictionary *)info
3127 : {
3128 : int i, x, y;
3129 : NSSize siz;
3130 : GLfloat alpha;
3131 : struct CachedInfo cached;
3132 :
3133 : [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3134 :
3135 : x = useDefined(cached.x, SCOOPSTATUS_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
3136 : y = useDefined(cached.y, SCOOPSTATUS_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
3137 : siz.width = useDefined(cached.width, SCOOPSTATUS_WIDTH);
3138 : siz.height = useDefined(cached.height, SCOOPSTATUS_HEIGHT);
3139 : // default alpha value different from all others, won't use cached.alpha
3140 : alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:0.75f];
3141 :
3142 : const GLfloat* s0_color = red_color;
3143 : GLfloat s1c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3144 : GLfloat s2c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3145 : GLfloat s3c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3146 : int scoop_status = [PLAYER dialFuelScoopStatus];
3147 : GLfloat t = [UNIVERSE getTime];
3148 : GLfloat a1 = alpha * 0.5f * (1.0f + sin(t * 8.0f));
3149 : GLfloat a2 = alpha * 0.5f * (1.0f + sin(t * 8.0f - 1.0f));
3150 : GLfloat a3 = alpha * 0.5f * (1.0f + sin(t * 8.0f - 2.0f));
3151 :
3152 : switch (scoop_status)
3153 : {
3154 : case SCOOP_STATUS_NOT_INSTALLED:
3155 : return; // don't draw
3156 :
3157 : case SCOOP_STATUS_FULL_HOLD:
3158 : s0_color = darkgreen_color;
3159 : alpha *= 0.75;
3160 : break;
3161 :
3162 : case SCOOP_STATUS_ACTIVE:
3163 : case SCOOP_STATUS_OKAY:
3164 : s0_color = green_color;
3165 : break;
3166 : }
3167 :
3168 : for (i = 0; i < 3; i++)
3169 : {
3170 : s1c[i] = s0_color[i];
3171 : s2c[i] = s0_color[i];
3172 : s3c[i] = s0_color[i];
3173 : }
3174 : if (scoop_status == SCOOP_STATUS_FULL_HOLD)
3175 : {
3176 : s3c[0] = red_color[0];
3177 : s3c[1] = red_color[1];
3178 : s3c[2] = red_color[2];
3179 : }
3180 : if (scoop_status == SCOOP_STATUS_ACTIVE)
3181 : {
3182 : s1c[3] = alpha * a1;
3183 : s2c[3] = alpha * a2;
3184 : s3c[3] = alpha * a3;
3185 : }
3186 : else
3187 : {
3188 : s1c[3] = alpha;
3189 : s2c[3] = alpha;
3190 : s3c[3] = alpha;
3191 : }
3192 :
3193 : GLfloat w1 = siz.width / 8.0;
3194 : GLfloat w2 = 2.0 * w1;
3195 : // GLfloat w3 = 3.0 * w1;
3196 : GLfloat w4 = 4.0 * w1;
3197 : GLfloat h1 = siz.height / 8.0;
3198 : GLfloat h2 = 2.0 * h1;
3199 : GLfloat h3 = 3.0 * h1;
3200 : GLfloat h4 = 4.0 * h1;
3201 :
3202 : OOGL(glDisable(GL_TEXTURE_2D));
3203 : OOGLBEGIN(GL_QUADS);
3204 : // section 1
3205 : GLColorWithOverallAlpha(s1c, overallAlpha);
3206 : glVertex3f(x, y + h1, z1); glVertex3f(x - w2, y + h2, z1); glVertex3f(x, y + h3, z1); glVertex3f(x + w2, y + h2, z1);
3207 : // section 2
3208 : GLColorWithOverallAlpha(s2c, overallAlpha);
3209 : glVertex3f(x, y - h1, z1); glVertex3f(x - w4, y + h1, z1); glVertex3f(x - w4, y + h2, z1); glVertex3f(x, y, z1);
3210 : glVertex3f(x, y - h1, z1); glVertex3f(x + w4, y + h1, z1); glVertex3f(x + w4, y + h2, z1); glVertex3f(x, y, z1);
3211 : // section 3
3212 : GLColorWithOverallAlpha(s3c, overallAlpha);
3213 : glVertex3f(x, y - h4, z1); glVertex3f(x - w2, y - h2, z1); glVertex3f(x - w2, y - h1, z1); glVertex3f(x, y - h2, z1);
3214 : glVertex3f(x, y - h4, z1); glVertex3f(x + w2, y - h2, z1); glVertex3f(x + w2, y - h1, z1); glVertex3f(x, y - h2, z1);
3215 : OOGLEND();
3216 : }
3217 :
3218 :
3219 0 : - (void) drawStickSensitivityIndicator:(NSDictionary *)info
3220 : {
3221 : GLfloat x, y;
3222 : NSSize siz;
3223 : GLfloat alpha = overallAlpha;
3224 : BOOL mouse = [PLAYER isMouseControlOn];
3225 : OOJoystickManager *stickHandler = [OOJoystickManager sharedStickHandler];
3226 : struct CachedInfo cached;
3227 :
3228 : if (![stickHandler joystickCount])
3229 : {
3230 : return; // no need to draw if no joystick fitted
3231 : }
3232 :
3233 : [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3234 :
3235 : x = useDefined(cached.x, STATUS_LIGHT_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
3236 : y = useDefined(cached.y, STATUS_LIGHT_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
3237 : siz.width = useDefined(cached.width, STATUS_LIGHT_HEIGHT);
3238 : siz.height = useDefined(cached.height, STATUS_LIGHT_HEIGHT);
3239 : alpha *= cached.alpha;
3240 :
3241 : GLfloat div = [stickHandler getSensitivity];
3242 :
3243 : GLColorWithOverallAlpha(black_color, alpha / 4);
3244 : GLDrawFilledOval(x, y, z1, siz, 10);
3245 :
3246 : GLColorWithOverallAlpha((div < 1.0 || mouse) ? lightgray_color : green_color, alpha);
3247 : OOGL(GLScaledLineWidth(_crosshairWidth * lineWidth));
3248 :
3249 : if (div >= 1.0)
3250 : {
3251 : if (!mouse)
3252 : {
3253 : NSSize siz8th = { siz.width / 8, siz.height / 8 };
3254 : GLDrawFilledOval(x, y, z1, siz8th, 30);
3255 :
3256 : if (div == 1.0) // normal mode
3257 : GLColorWithOverallAlpha(lightgray_color, alpha);
3258 : }
3259 :
3260 : siz.width -= _crosshairWidth * lineWidth / 2;
3261 : siz.height -= _crosshairWidth * lineWidth / 2;
3262 : GLDrawOval(x, y, z1, siz, 10);
3263 : }
3264 : else if (div < 1.0) // insensitive mode (shouldn't happen)
3265 : GLDrawFilledOval(x, y, z1, siz, 10);
3266 :
3267 : OOGL(GLScaledLineWidth(lineWidth)); // reset
3268 : }
3269 :
3270 :
3271 0 : - (void) drawSurroundInternal:(NSDictionary *)info color:(const GLfloat[4])color
3272 : {
3273 : NSInteger x, y;
3274 : NSSize siz;
3275 : GLfloat alpha = overallAlpha;
3276 : struct CachedInfo cached;
3277 :
3278 : [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3279 :
3280 : if (cached.x == NOT_DEFINED || cached.y == NOT_DEFINED || cached.width == NOT_DEFINED || cached.height == NOT_DEFINED)
3281 : {
3282 : return;
3283 : }
3284 :
3285 : x = cached.x + [[UNIVERSE gameView] x_offset] * cached.x0;
3286 : y = cached.y + [[UNIVERSE gameView] y_offset] * cached.y0;
3287 : siz.width = useDefined(cached.width, WEAPONSOFFLINETEXT_WIDTH);
3288 : siz.height = useDefined(cached.height, WEAPONSOFFLINETEXT_HEIGHT);
3289 : alpha *= cached.alpha;
3290 :
3291 : // draw the surround
3292 : GLColorWithOverallAlpha(color, alpha);
3293 : hudDrawSurroundAt(x, y, z1, siz);
3294 : }
3295 :
3296 :
3297 0 : - (void) drawSurround:(NSDictionary *)info
3298 : {
3299 : GLfloat itemColor[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
3300 : id colorDesc = [info objectForKey:COLOR_KEY];
3301 : if (colorDesc != nil)
3302 : {
3303 : OOColor *color = [OOColor colorWithDescription:colorDesc];
3304 : if (color != nil)
3305 : {
3306 : itemColor[0] = [color redComponent];
3307 : itemColor[1] = [color greenComponent];
3308 : itemColor[2] = [color blueComponent];
3309 : }
3310 : }
3311 :
3312 : [self drawSurroundInternal:info color:itemColor];
3313 : }
3314 :
3315 :
3316 0 : - (void) drawGreenSurround:(NSDictionary *)info
3317 : {
3318 : [self drawSurroundInternal:info color:green_color];
3319 : }
3320 :
3321 :
3322 0 : - (void) drawYellowSurround:(NSDictionary *)info
3323 : {
3324 : [self drawSurroundInternal:info color:yellow_color];
3325 : }
3326 :
3327 :
3328 0 : - (void) drawTrumbles:(NSDictionary *)info
3329 : {
3330 : OOTrumble** trumbles = [PLAYER trumbleArray];
3331 : NSUInteger i;
3332 : for (i = [PLAYER trumbleCount]; i > 0; i--)
3333 : {
3334 : OOTrumble* trum = trumbles[i - 1];
3335 : [trum drawTrumble: z1];
3336 : }
3337 : }
3338 :
3339 :
3340 0 : - (void) drawMultiFunctionDisplay:(NSDictionary *)info withText:(NSString *)text asIndex:(NSUInteger)index
3341 : {
3342 : PlayerEntity *player1 = PLAYER;
3343 : struct CachedInfo cached;
3344 : NSInteger i, x, y;
3345 : NSSize siz, tmpsiz;
3346 : if ([player1 guiScreen] != GUI_SCREEN_MAIN) // don't draw on text screens
3347 : {
3348 : return;
3349 : }
3350 : GLfloat alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:1.0f] * overallAlpha;
3351 :
3352 : GLfloat mfd_color[4] = {0.0, 1.0, 0.0, 0.9*alpha};
3353 : OOColor *mfdcol = [OOColor colorWithDescription:[info objectForKey:COLOR_KEY]];
3354 : if (mfdcol != nil)
3355 : {
3356 : [mfdcol getRed:&mfd_color[0] green:&mfd_color[1] blue:&mfd_color[2] alpha:&mfd_color[3]];
3357 : }
3358 : if (index != [player1 activeMFD])
3359 : {
3360 : mfd_color[3] *= 0.75;
3361 : }
3362 : [self drawSurroundInternal:info color:mfd_color];
3363 :
3364 : [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3365 : x = cached.x + [[UNIVERSE gameView] x_offset] * cached.x0;
3366 : y = cached.y + [[UNIVERSE gameView] y_offset] * cached.y0;
3367 :
3368 : siz.width = useDefined(cached.width / 15, MFD_TEXT_WIDTH);
3369 : siz.height = useDefined(cached.height / 10, MFD_TEXT_HEIGHT);
3370 :
3371 : GLfloat x0 = (GLfloat)(x - cached.width/2);
3372 : GLfloat y0 = (GLfloat)(y + cached.height/2);
3373 : GLfloat x1 = (GLfloat)(x + cached.width/2);
3374 : GLfloat y1 = (GLfloat)(y - cached.height/2);
3375 : GLColorWithOverallAlpha(mfd_color, alpha*0.3);
3376 : OOGLBEGIN(GL_QUADS);
3377 : glVertex3f(x0-2,y0+2,z1);
3378 : glVertex3f(x0-2,y1-2,z1);
3379 : glVertex3f(x1+2,y1-2,z1);
3380 : glVertex3f(x1+2,y0+2,z1);
3381 : OOGLEND();
3382 :
3383 : NSString *line = nil;
3384 : NSArray *lines = [text componentsSeparatedByString:@"\n"];
3385 : // text at full opacity
3386 : GLColorWithOverallAlpha(mfd_color, alpha);
3387 : for (i = 0; i < 10 ; i++)
3388 : {
3389 : line = [lines oo_stringAtIndex:i defaultValue:nil];
3390 : if (line != nil)
3391 : {
3392 : y0 -= siz.height;
3393 : // all lines should be shorter than the size of the MFD
3394 : GLfloat textwidth = OORectFromString(line, 0.0f, 0.0f, siz).size.width;
3395 : if (textwidth <= cached.width)
3396 : {
3397 : OODrawString(line, x0, y0, z1, siz);
3398 : }
3399 : else
3400 : {
3401 : // compress it so it fits
3402 : tmpsiz.height = siz.height;
3403 : tmpsiz.width = siz.width * cached.width / textwidth;
3404 : OODrawString(line, x0, y0, z1, tmpsiz);
3405 : }
3406 : }
3407 : else
3408 : {
3409 : break;
3410 : }
3411 : }
3412 : }
3413 :
3414 : //---------------------------------------------------------------------//
3415 :
3416 0 : static void hudDrawIndicatorAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
3417 : {
3418 : if (siz.width > siz.height)
3419 : {
3420 : GLfloat dial_oy = y - siz.height/2;
3421 : GLfloat position = x + amount * siz.width / 2;
3422 : OOGLBEGIN(GL_QUADS);
3423 : glVertex3f(position, dial_oy, z);
3424 : glVertex3f(position+2, y, z);
3425 : glVertex3f(position, dial_oy+siz.height, z);
3426 : glVertex3f(position-2, y, z);
3427 : OOGLEND();
3428 : }
3429 : else
3430 : {
3431 : GLfloat dial_ox = x - siz.width/2;
3432 : GLfloat position = y + amount * siz.height / 2;
3433 : OOGLBEGIN(GL_QUADS);
3434 : glVertex3f(dial_ox, position, z);
3435 : glVertex3f(x, position+2, z);
3436 : glVertex3f(dial_ox + siz.width, position, z);
3437 : glVertex3f(x, position-2, z);
3438 : OOGLEND();
3439 : }
3440 : }
3441 :
3442 :
3443 0 : static void hudDrawMarkerAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
3444 : {
3445 : if (siz.width > siz.height)
3446 : {
3447 : GLfloat dial_oy = y - siz.height/2;
3448 : GLfloat position = x + amount * siz.width - siz.width/2;
3449 : OOGLBEGIN(GL_QUADS);
3450 : glVertex3f(position+1, dial_oy+1, z);
3451 : glVertex3f(position+1, dial_oy+siz.height-1, z);
3452 : glVertex3f(position-1, dial_oy+siz.height-1, z);
3453 : glVertex3f(position-1, dial_oy+1, z);
3454 : OOGLEND();
3455 : }
3456 : else
3457 : {
3458 : GLfloat dial_ox = x - siz.width/2;
3459 : GLfloat position = y + amount * siz.height - siz.height/2;
3460 : OOGLBEGIN(GL_QUADS);
3461 : glVertex3f(dial_ox+1, position+1, z);
3462 : glVertex3f(dial_ox + siz.width-1, position+1, z);
3463 : glVertex3f(dial_ox + siz.width-1, position-1, z);
3464 : glVertex3f(dial_ox+1, position-1, z);
3465 : OOGLEND();
3466 : }
3467 : }
3468 :
3469 :
3470 0 : static void hudDrawBarAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
3471 : {
3472 : GLfloat dial_ox = x - siz.width/2;
3473 : GLfloat dial_oy = y - siz.height/2;
3474 : if (fabs(siz.width) > fabs(siz.height))
3475 : {
3476 : GLfloat position = dial_ox + amount * siz.width;
3477 :
3478 : OOGLBEGIN(GL_QUADS);
3479 : glVertex3f(dial_ox, dial_oy, z);
3480 : glVertex3f(position, dial_oy, z);
3481 : glVertex3f(position, dial_oy+siz.height, z);
3482 : glVertex3f(dial_ox, dial_oy+siz.height, z);
3483 : OOGLEND();
3484 : }
3485 : else
3486 : {
3487 : GLfloat position = dial_oy + amount * siz.height;
3488 :
3489 : OOGLBEGIN(GL_QUADS);
3490 : glVertex3f(dial_ox, dial_oy, z);
3491 : glVertex3f(dial_ox, position, z);
3492 : glVertex3f(dial_ox+siz.width, position, z);
3493 : glVertex3f(dial_ox+siz.width, dial_oy, z);
3494 : OOGLEND();
3495 : }
3496 : }
3497 :
3498 :
3499 0 : static void hudDrawSurroundAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz)
3500 : {
3501 : GLfloat dial_ox = x - siz.width/2;
3502 : GLfloat dial_oy = y - siz.height/2;
3503 :
3504 : OOGLBEGIN(GL_LINE_LOOP);
3505 : glVertex3f(dial_ox-2, dial_oy-2, z);
3506 : glVertex3f(dial_ox+siz.width+2, dial_oy-2, z);
3507 : glVertex3f(dial_ox+siz.width+2, dial_oy+siz.height+2, z);
3508 : glVertex3f(dial_ox-2, dial_oy+siz.height+2, z);
3509 : OOGLEND();
3510 : }
3511 :
3512 :
3513 0 : static void hudDrawStatusIconAt(int x, int y, int z, NSSize siz)
3514 : {
3515 : int ox = x - siz.width / 2.0;
3516 : int oy = y - siz.height / 2.0;
3517 : int w = siz.width / 4.0;
3518 : int h = siz.height / 4.0;
3519 :
3520 : glVertex3i(ox, oy + h, z);
3521 : glVertex3i(ox, oy + 3 * h, z);
3522 : glVertex3i(ox + w, oy + 4 * h, z);
3523 : glVertex3i(ox + 3 * w, oy + 4 * h, z);
3524 : glVertex3i(ox + 4 * w, oy + 3 * h, z);
3525 : glVertex3i(ox + 4 * w, oy + h, z);
3526 : glVertex3i(ox + 3 * w, oy, z);
3527 : glVertex3i(ox + w, oy, z);
3528 : }
3529 :
3530 :
3531 0 : static void hudDrawReticleOnTarget(Entity *target, PlayerEntity *player1, GLfloat z1,
3532 : GLfloat alpha, BOOL reticleTargetSensitive, NSMutableDictionary *propertiesReticleTargetSensitive,
3533 : BOOL colourFromScannerColour, BOOL showText, NSDictionary *info, NSMutableArray *reticleColors)
3534 : {
3535 : if (target == nil || player1 == nil)
3536 : {
3537 : return;
3538 : }
3539 : if ([player1 guiScreen] != GUI_SCREEN_MAIN) // don't draw on text screens
3540 : {
3541 : return;
3542 : }
3543 :
3544 : ShipEntity *target_ship = nil;
3545 : NSString *legal_desc = nil;
3546 :
3547 : GLfloat scale = [info oo_floatForKey:@"reticle_scale" defaultValue:ONE_SIXTYFOURTH];
3548 :
3549 :
3550 : if ([target isShip])
3551 : {
3552 : target_ship = (ShipEntity *)target;
3553 : legal_desc = [target_ship scanDescription];
3554 : }
3555 :
3556 : if ([target_ship isCloaked]) return;
3557 :
3558 :
3559 : Vector p1;
3560 :
3561 : // by definition close enough that single precision is fine
3562 : p1 = HPVectorToVector(HPvector_subtract([target position], [player1 viewpointPosition]));
3563 :
3564 : GLfloat rdist = magnitude(p1);
3565 : GLfloat rsize = [target collisionRadius] / (2 * [[UNIVERSE gameView] fov:YES]); // FIXME integrate 2 into fov to remove magic number
3566 :
3567 : if (rsize < rdist * scale)
3568 : rsize = rdist * scale;
3569 :
3570 : GLfloat rs0 = rsize;
3571 : GLfloat rs2 = rsize * 0.50;
3572 :
3573 : OOGLPushModelView();
3574 : hudRotateViewpointForVirtualDepth(player1,p1);
3575 :
3576 : // draw the reticle
3577 : float range = sqrt(target->zero_distance) - target->collision_radius;
3578 :
3579 : int flash = (int)([UNIVERSE getTime] * 4);
3580 : flash &= 1;
3581 :
3582 : // Draw reticle cyan for Wormholes
3583 : if ([target isWormhole])
3584 : {
3585 : OOColor *wormholeReticleColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_WORMHOLE];
3586 : GLfloat wormholeReticleColorArray[4] = {[wormholeReticleColor redComponent],
3587 : [wormholeReticleColor greenComponent],
3588 : [wormholeReticleColor blueComponent],
3589 : [wormholeReticleColor alphaComponent]};
3590 : GLColorWithOverallAlpha(wormholeReticleColorArray, alpha);
3591 : }
3592 : else
3593 : {
3594 : // Reticle sensitivity accuracy calculation
3595 : BOOL isTargeted = NO;
3596 : GLfloat probabilityAccuracy;
3597 :
3598 : if (propertiesReticleTargetSensitive != nil)
3599 : {
3600 : // Only if target is within player's weapon range, we mind for reticle accuracy
3601 : if (range < [player1 weaponRange])
3602 : {
3603 : // After MAX_ACCURACY_RANGE km start decreasing high accuracy probability by ACCURACY_PROBABILITY_DECREASE_FACTOR%
3604 : if (range > MAX_ACCURACY_RANGE)
3605 : {
3606 : // Every one second re-evaluate accuracy
3607 : if ([UNIVERSE getTime] > [propertiesReticleTargetSensitive oo_doubleForKey:@"timeLastAccuracyProbabilityCalculation"] + 1)
3608 : {
3609 : probabilityAccuracy = 1-(range-MAX_ACCURACY_RANGE)*ACCURACY_PROBABILITY_DECREASE_FACTOR;
3610 : // Make sure probability does not go below a minimum
3611 : probabilityAccuracy = probabilityAccuracy < MIN_PROBABILITY_ACCURACY ? MIN_PROBABILITY_ACCURACY : probabilityAccuracy;
3612 : [propertiesReticleTargetSensitive setObject:[NSNumber numberWithBool:((randf() < probabilityAccuracy) ? YES : NO)] forKey:@"isAccurate"];
3613 :
3614 : // Store the time the last accuracy probability has been performed
3615 : [propertiesReticleTargetSensitive setObject:[NSNumber numberWithDouble:[UNIVERSE getTime]] forKey:@"timeLastAccuracyProbabilityCalculation"];
3616 : }
3617 : if ([propertiesReticleTargetSensitive oo_boolForKey:@"isAccurate"])
3618 : {
3619 : // high accuracy reticle
3620 : isTargeted = ([UNIVERSE firstEntityTargetedByPlayerPrecisely] == target);
3621 : }
3622 : else
3623 : {
3624 : // low accuracy reticle
3625 : isTargeted = ([UNIVERSE firstEntityTargetedByPlayer] == target);
3626 : }
3627 : }
3628 : else
3629 : {
3630 : // high accuracy reticle
3631 : isTargeted = ([UNIVERSE firstEntityTargetedByPlayerPrecisely] == target);
3632 : }
3633 : }
3634 : }
3635 :
3636 : // If reticle is target sensitive, draw target box in red
3637 : // when target passes through laser hit-point(with decreasing accuracy)
3638 : // and is within hit-range.
3639 : //
3640 : // NOTE: The following condition also considers (indirectly) the player's weapon range.
3641 : // 'isTargeted' is initialised to FALSE. Only if target is within the player's weapon range,
3642 : // it might change value. Therefore, it is not necessary to add '&& range < [player1 weaponRange]'
3643 : // to the following condition.
3644 : if (colourFromScannerColour)
3645 : {
3646 : if ([target isShip])
3647 : {
3648 : ShipEntity *ship = (ShipEntity *)target;
3649 : BOOL isHostile = (([ship hasHostileTarget])&&([ship primaryTarget] == PLAYER));
3650 : GLColorWithOverallAlpha([ship scannerDisplayColorForShip:PLAYER :isHostile :flash :[ship scannerDisplayColor1] :[ship scannerDisplayColor2] :[ship scannerDisplayColorHostile1] :[ship scannerDisplayColorHostile2]],alpha);
3651 : }
3652 : else if ([target isVisualEffect])
3653 : {
3654 : OOVisualEffectEntity *vis = (OOVisualEffectEntity *)target;
3655 : GLColorWithOverallAlpha([vis scannerDisplayColorForShip:flash :[vis scannerDisplayColor1] :[vis scannerDisplayColor2]],alpha);
3656 : }
3657 : else
3658 : {
3659 : GLColorWithOverallAlpha(green_color, alpha);
3660 : }
3661 : }
3662 : else
3663 : {
3664 : OOColor *reticleDisplayColor = nil;
3665 : if (reticleTargetSensitive && isTargeted)
3666 : {
3667 : reticleDisplayColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_TARGET_SENSITIVE];
3668 : if (!reticleDisplayColor) reticleDisplayColor = [OOColor redColor];
3669 : }
3670 : else
3671 : {
3672 : reticleDisplayColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_TARGET];
3673 : if (!reticleDisplayColor) reticleDisplayColor = [OOColor greenColor];
3674 : }
3675 : GLfloat reticleDisplayColorArray[4] = { [reticleDisplayColor redComponent],
3676 : [reticleDisplayColor greenComponent],
3677 : [reticleDisplayColor blueComponent],
3678 : [reticleDisplayColor alphaComponent] };
3679 : GLColorWithOverallAlpha(reticleDisplayColorArray, alpha);
3680 : }
3681 : }
3682 : OOGLBEGIN(GL_LINES);
3683 : glVertex2f(rs0,rs2); glVertex2f(rs0,rs0);
3684 : glVertex2f(rs0,rs0); glVertex2f(rs2,rs0);
3685 :
3686 : glVertex2f(rs0,-rs2); glVertex2f(rs0,-rs0);
3687 : glVertex2f(rs0,-rs0); glVertex2f(rs2,-rs0);
3688 :
3689 : glVertex2f(-rs0,rs2); glVertex2f(-rs0,rs0);
3690 : glVertex2f(-rs0,rs0); glVertex2f(-rs2,rs0);
3691 :
3692 : glVertex2f(-rs0,-rs2); glVertex2f(-rs0,-rs0);
3693 : glVertex2f(-rs0,-rs0); glVertex2f(-rs2,-rs0);
3694 : OOGLEND();
3695 :
3696 : if (showText)
3697 : {
3698 : // add text for reticle here
3699 : range *= 0.001f;
3700 : if (range < 0.001f) range = 0.0f; // avoids the occasional -0.001 km distance.
3701 : NSSize textsize = NSMakeSize(rdist * scale, rdist * scale);
3702 : float line_height = rdist * scale;
3703 : NSString* infoline = [NSString stringWithFormat:@"%0.3f km", range];
3704 : if (legal_desc != nil) infoline = [NSString stringWithFormat:@"%@ (%@)", infoline, legal_desc];
3705 : // no need to set colour here
3706 : OODrawString([player1 dialTargetName], rs0, 0.5 * rs2, 0, textsize);
3707 : OODrawString(infoline, rs0, 0.5 * rs2 - line_height, 0, textsize);
3708 :
3709 : if ([target isWormhole])
3710 : {
3711 : // Note: No break statements in the following switch() since every case
3712 : // falls through to the next. Cases arranged in reverse order.
3713 : switch([(WormholeEntity *)target scanInfo])
3714 : {
3715 : case WH_SCANINFO_SHIP:
3716 : // TOOD: Render anything on the HUD for this?
3717 : case WH_SCANINFO_DESTINATION:
3718 : // Rendered above in dialTargetName, so no need to do anything here
3719 : // unless we want a separate line Destination: XXX ?
3720 : case WH_SCANINFO_ARRIVAL_TIME:
3721 : {
3722 : NSString *wormholeETA = [NSString stringWithFormat:DESC(@"wormhole-ETA-@"), ClockToString([(WormholeEntity *)target estimatedArrivalTime], NO)];
3723 : OODrawString(wormholeETA, rs0, 0.5 * rs2 - 3 * line_height, 0, textsize);
3724 : }
3725 : case WH_SCANINFO_COLLAPSE_TIME:
3726 : {
3727 : OOTimeDelta timeForCollapsing = [(WormholeEntity *)target expiryTime] - [player1 clockTimeAdjusted];
3728 : int minutesToCollapse = floor (timeForCollapsing / 60.0);
3729 : int secondsToCollapse = (int)timeForCollapsing % 60;
3730 :
3731 : NSString *wormholeExpiringIn = [NSString stringWithFormat:DESC(@"wormhole-collapsing-in-mm:ss"), minutesToCollapse, secondsToCollapse];
3732 : OODrawString(wormholeExpiringIn, rs0, 0.5 * rs2 - 2 * line_height, 0, textsize);
3733 : }
3734 : case WH_SCANINFO_SCANNED:
3735 : case WH_SCANINFO_NONE:
3736 : break;
3737 : }
3738 : }
3739 : }
3740 :
3741 : OOGLPopModelView();
3742 : }
3743 :
3744 :
3745 0 : static void hudDrawWaypoint(OOWaypointEntity *waypoint, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL selected, GLfloat scale)
3746 : {
3747 : if ([player1 guiScreen] != GUI_SCREEN_MAIN) // don't draw on text screens
3748 : {
3749 : return;
3750 : }
3751 :
3752 :
3753 : Vector p1 = HPVectorToVector(HPvector_subtract([waypoint position], [player1 viewpointPosition]));
3754 :
3755 : OOGLPushModelView();
3756 : hudRotateViewpointForVirtualDepth(player1,p1);
3757 :
3758 : // either close enough that single precision is fine or far enough
3759 : // away that precision is irrelevant
3760 :
3761 : GLfloat rdist = magnitude(p1);
3762 : GLfloat rsize = rdist * scale;
3763 :
3764 : GLfloat rs0 = rsize;
3765 : GLfloat rs2 = rsize * 0.50;
3766 :
3767 : if (selected)
3768 : {
3769 : GLColorWithOverallAlpha(blue_color, alpha);
3770 : }
3771 : else
3772 : {
3773 : GLColorWithOverallAlpha(blue_color, alpha*0.25);
3774 : }
3775 :
3776 : OOGLBEGIN(GL_LINES);
3777 : glVertex2f(rs0,rs2); glVertex2f(rs2,rs2);
3778 : glVertex2f(rs2,rs0); glVertex2f(rs2,rs2);
3779 :
3780 : glVertex2f(-rs0,rs2); glVertex2f(-rs2,rs2);
3781 : glVertex2f(-rs2,rs0); glVertex2f(-rs2,rs2);
3782 :
3783 : glVertex2f(-rs0,-rs2); glVertex2f(-rs2,-rs2);
3784 : glVertex2f(-rs2,-rs0); glVertex2f(-rs2,-rs2);
3785 :
3786 : glVertex2f(rs0,-rs2); glVertex2f(rs2,-rs2);
3787 : glVertex2f(rs2,-rs0); glVertex2f(rs2,-rs2);
3788 :
3789 : // glVertex2f(0,-rs2); glVertex2f(0,rs2);
3790 : // glVertex2f(rs2,0); glVertex2f(-rs2,0);
3791 : OOGLEND();
3792 :
3793 : if (selected)
3794 : {
3795 : GLfloat range = HPdistance([player1 position],[waypoint position]) * 0.001f;
3796 : if (range < 0.001f) range = 0.0f; // avoids the occasional -0.001 km distance.
3797 : NSSize textsize = NSMakeSize(rdist * scale, rdist * scale);
3798 : float line_height = rdist * scale;
3799 : NSString* infoline = [NSString stringWithFormat:@"%0.3f km", range];
3800 : OODrawString(infoline, rs0 * 0.5, -rs2 - line_height, 0, textsize);
3801 : }
3802 :
3803 : OOGLPopModelView();
3804 : }
3805 :
3806 0 : static void hudRotateViewpointForVirtualDepth(PlayerEntity * player1, Vector p1)
3807 : {
3808 : Quaternion back_q = [player1 orientation];
3809 : back_q.w = -back_q.w; // invert
3810 : Vector v1 = vector_up_from_quaternion(back_q);
3811 : NSSize viewSize = [[UNIVERSE gameView] viewSize];
3812 : float aspect = viewSize.width / viewSize.height;
3813 :
3814 : // The field of view transformation is really a scale operation on the view window.
3815 : // We must unapply it through these transformations for them to be right.
3816 : // We must also take into account the window aspect ratio.
3817 : float ratio = 2 * [[UNIVERSE gameView] fov:YES]; // FIXME 2 is magic number; fov should integrate it
3818 : if (3.0f * aspect >= 4.0f)
3819 : {
3820 : OOGLScaleModelView(make_vector(1/ratio, 1/ratio, 1.0f));
3821 : }
3822 : else
3823 : {
3824 : OOGLScaleModelView(make_vector((4.0f/3.0f)/(aspect*ratio), (4.0f/3.0f)/(aspect*ratio), 1.0f));
3825 : }
3826 :
3827 : // deal with view directions
3828 : Vector view_dir, view_up = kBasisYVector;
3829 : switch ([UNIVERSE viewDirection])
3830 : {
3831 : default:
3832 : case VIEW_FORWARD:
3833 : view_dir.x = 0.0; view_dir.y = 0.0; view_dir.z = 1.0;
3834 : break;
3835 :
3836 : case VIEW_AFT:
3837 : view_dir.x = 0.0; view_dir.y = 0.0; view_dir.z = -1.0;
3838 : quaternion_rotate_about_axis(&back_q, v1, M_PI);
3839 : break;
3840 :
3841 : case VIEW_PORT:
3842 : view_dir.x = -1.0; view_dir.y = 0.0; view_dir.z = 0.0;
3843 : quaternion_rotate_about_axis(&back_q, v1, 0.5 * M_PI);
3844 : break;
3845 :
3846 : case VIEW_STARBOARD:
3847 : view_dir.x = 1.0; view_dir.y = 0.0; view_dir.z = 0.0;
3848 : quaternion_rotate_about_axis(&back_q, v1, -0.5 * M_PI);
3849 : break;
3850 :
3851 : case VIEW_CUSTOM:
3852 : view_dir = [player1 customViewForwardVector];
3853 : view_up = [player1 customViewUpVector];
3854 : back_q = quaternion_multiply([player1 customViewQuaternion], back_q);
3855 : break;
3856 : }
3857 : OOGLLookAt(view_dir, kZeroVector, view_up);
3858 :
3859 : // rotate the view
3860 : OOGLMultModelView([player1 rotationMatrix]);
3861 : // translate the view
3862 : OOGLTranslateModelView(p1);
3863 : // rotate to face player1
3864 : OOGLMultModelView(OOMatrixForQuaternionRotation(back_q));
3865 :
3866 : // We come back now to the previous scale.
3867 : OOGLScaleModelView(make_vector(ratio, ratio, 1.0f));
3868 : // draw the waypoint
3869 : }
3870 :
3871 :
3872 0 : static void InitTextEngine(void)
3873 : {
3874 : NSDictionary *fontSpec = nil;
3875 : NSArray *widths = nil;
3876 : NSString *texName = nil;
3877 : NSUInteger i, count;
3878 :
3879 : fontSpec = [ResourceManager dictionaryFromFilesNamed:@"oolite-font.plist"
3880 : inFolder:@"Config"
3881 : andMerge:NO];
3882 :
3883 : texName = [fontSpec oo_stringForKey:@"texture" defaultValue:@"oolite-font.png"];
3884 : sFontTexture = [OOTexture textureWithName:texName
3885 : inFolder:@"Textures"
3886 : options:kFontTextureOptions
3887 : anisotropy:0.0f
3888 : lodBias:-0.75f];
3889 : [sFontTexture retain];
3890 :
3891 : sF6KernGovt = [fontSpec oo_floatForKey:@"f6KernGovernment" defaultValue:1.0];
3892 : sF6KernTL = [fontSpec oo_floatForKey:@"f6KernTechLevel" defaultValue:2.0];
3893 :
3894 : sEncodingCoverter = [[OOEncodingConverter alloc] initWithFontPList:fontSpec];
3895 : widths = [fontSpec oo_arrayForKey:@"widths"];
3896 : count = [widths count];
3897 : if (count > 256) count = 256;
3898 : for (i = 0; i != count; ++i)
3899 : {
3900 : sGlyphWidths[i] = [widths oo_floatAtIndex:i] * GLYPH_SCALE_FACTOR;
3901 : }
3902 : }
3903 :
3904 :
3905 0 : void OOHUDResetTextEngine(void)
3906 : {
3907 : DESTROY(sFontTexture);
3908 : DESTROY(sEncodingCoverter);
3909 : }
3910 :
3911 :
3912 : static GLfloat drawCharacterQuad(uint8_t chr, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
3913 : {
3914 : // 31 (narrow space) and 32 (space) are non-printing characters, so
3915 : // don't print them, just return their width to move the pointer
3916 : if (chr > 32 || chr < 31) {
3917 : GLfloat texture_x = ONE_SIXTEENTH * (chr & 0x0f);
3918 : GLfloat texture_y = ONE_SIXTEENTH * (chr >> 4);
3919 : if (chr > 32) y += ONE_EIGHTH * siz.height; // Adjust for baseline offset change in 1.71 (needed to keep accented characters in box)
3920 :
3921 : glTexCoord2f(texture_x, texture_y + ONE_SIXTEENTH);
3922 : glVertex3f(x, y, z);
3923 : glTexCoord2f(texture_x + ONE_SIXTEENTH, texture_y + ONE_SIXTEENTH);
3924 : glVertex3f(x + siz.width, y, z);
3925 : glTexCoord2f(texture_x + ONE_SIXTEENTH, texture_y);
3926 : glVertex3f(x + siz.width, y + siz.height, z);
3927 : glTexCoord2f(texture_x, texture_y);
3928 : glVertex3f(x, y + siz.height, z);
3929 : }
3930 : return siz.width * sGlyphWidths[chr];
3931 : }
3932 :
3933 :
3934 0 : NSRect OORectFromString(NSString *text, GLfloat x, GLfloat y, NSSize siz)
3935 : {
3936 : GLfloat w = 0;
3937 : NSData *data = nil;
3938 : const uint8_t *bytes = NULL;
3939 : NSUInteger i, length;
3940 :
3941 : data = [sEncodingCoverter convertString:text];
3942 : bytes = [data bytes];
3943 : length = [data length];
3944 :
3945 : for (i = 0; i < length; i++)
3946 : {
3947 : w += siz.width * sGlyphWidths[bytes[i]];
3948 : }
3949 :
3950 : return NSMakeRect(x, y, w, siz.height);
3951 : }
3952 :
3953 :
3954 0 : CGFloat OOStringWidthInEm(NSString *text)
3955 : {
3956 : return OORectFromString(text, 0, 0, NSMakeSize(1.0 / (GLYPH_SCALE_FACTOR * 8.0), 1.0)).size.width;
3957 : }
3958 :
3959 :
3960 0 : void drawHighlight(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat alpha)
3961 : {
3962 : // Rounded corners, fading 'shadow' version
3963 : OOGL(glColor4f(0.0f, 0.0f, 0.0f, alpha * 0.4f)); // dark translucent shadow
3964 :
3965 : OOGLBEGIN(GL_POLYGON);
3966 : // thin 'halo' around the 'solid' highlight
3967 : glVertex3f(x + 1.0f , y + siz.height + 2.5f, z);
3968 : glVertex3f(x + siz.width + 3.0f, y + siz.height + 2.5f, z);
3969 : glVertex3f(x + siz.width + 4.5f, y + siz.height + 1.0f, z);
3970 : glVertex3f(x + siz.width + 4.5f, y + 3.0f, z);
3971 : glVertex3f(x + siz.width + 3.0f, y + 1.5f, z);
3972 : glVertex3f(x + 1.0f, y + 1.5f, z);
3973 : glVertex3f(x - 0.5f, y + 3.0f, z);
3974 : glVertex3f(x - 0.5f, y + siz.height + 1.0f, z);
3975 : OOGLEND();
3976 :
3977 :
3978 : OOGLBEGIN(GL_POLYGON);
3979 : glVertex3f(x + 1.0f, y + siz.height + 2.0f, z);
3980 : glVertex3f(x + siz.width + 3.0f, y + siz.height + 2.0f, z);
3981 : glVertex3f(x + siz.width + 4.0f, y + siz.height + 1.0f, z);
3982 : glVertex3f(x + siz.width + 4.0f, y + 3.0f, z);
3983 : glVertex3f(x + siz.width + 3.0f, y + 2.0f, z);
3984 : glVertex3f(x + 1.0f, y + 2.0f, z);
3985 : glVertex3f(x, y + 3.0f, z);
3986 : glVertex3f(x, y + siz.height + 1.0f, z);
3987 : OOGLEND();
3988 : }
3989 :
3990 :
3991 0 : void OODrawString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
3992 : {
3993 : OODrawStringAligned(text,x,y,z,siz,NO);
3994 : }
3995 :
3996 :
3997 0 : void OODrawStringAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
3998 : {
3999 : OOStartDrawingStrings();
4000 : OODrawStringQuadsAligned(text,x,y,z,siz,rightAlign);
4001 : OOStopDrawingStrings();
4002 : }
4003 :
4004 0 : void OOStartDrawingStrings() {
4005 : OOSetOpenGLState(OPENGL_STATE_OVERLAY);
4006 :
4007 : OOGL(glEnable(GL_TEXTURE_2D));
4008 : [sFontTexture apply];
4009 : OOGLBEGIN(GL_QUADS);
4010 :
4011 : }
4012 :
4013 0 : void OODrawStringQuadsAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
4014 : {
4015 : GLfloat cx = x;
4016 : NSInteger i, length;
4017 : NSData *data = nil;
4018 : const uint8_t *bytes = NULL;
4019 :
4020 : data = [sEncodingCoverter convertString:text];
4021 : length = [data length];
4022 : bytes = [data bytes];
4023 :
4024 : if (EXPECT_NOT(rightAlign))
4025 : {
4026 : cx -= OORectFromString(text, 0.0f, 0.0f, siz).size.width;
4027 : }
4028 :
4029 : for (i = 0; i < length; i++)
4030 : {
4031 : cx += drawCharacterQuad(bytes[i], cx, y, z, siz);
4032 : }
4033 : }
4034 :
4035 0 : void OOStopDrawingStrings() {
4036 : OOGLEND();
4037 :
4038 : [OOTexture applyNone];
4039 : OOGL(glDisable(GL_TEXTURE_2D));
4040 :
4041 : OOVerifyOpenGLState();
4042 : }
4043 :
4044 :
4045 0 : void OODrawHilightedString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
4046 : {
4047 : GLfloat color[4];
4048 :
4049 : // get the physical dimensions of the string
4050 : NSSize strsize = OORectFromString(text, 0.0f, 0.0f, siz).size;
4051 : strsize.width += 0.5f;
4052 :
4053 : OOSetOpenGLState(OPENGL_STATE_OVERLAY);
4054 :
4055 : OOGL(glPushAttrib(GL_CURRENT_BIT)); // save the text colour
4056 : OOGL(glGetFloatv(GL_CURRENT_COLOR, color)); // we need the original colour's alpha.
4057 :
4058 : drawHighlight(x, y, z, strsize, color[3]);
4059 :
4060 : OOGL(glPopAttrib()); //restore the colour
4061 :
4062 : OODrawString(text, x, y, z, siz);
4063 :
4064 : OOVerifyOpenGLState();
4065 : }
4066 :
4067 :
4068 0 : void OODrawPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
4069 : {
4070 : GLfloat govcol[] = { 0.5, 0.0, 0.7,
4071 : 0.7, 0.5, 0.3,
4072 : 0.0, 1.0, 0.3,
4073 : 1.0, 0.8, 0.1,
4074 : 1.0, 0.0, 0.0,
4075 : 0.1, 0.5, 1.0,
4076 : 0.7, 0.7, 0.7,
4077 : 0.7, 1.0, 1.0};
4078 :
4079 : GLfloat cx = x;
4080 : int tl = tec + 1;
4081 : GLfloat ce1 = 1.0f - 0.125f * eco;
4082 :
4083 : OOSetOpenGLState(OPENGL_STATE_OVERLAY);
4084 :
4085 : OOGL(glEnable(GL_TEXTURE_2D));
4086 : [sFontTexture apply];
4087 :
4088 : OOGLBEGIN(GL_QUADS);
4089 : {
4090 : [[UNIVERSE gui] setGLColorFromSetting:[NSString stringWithFormat:kGuiChartEconomyUColor, (unsigned long)eco]
4091 : defaultValue:[OOColor colorWithRed:ce1 green:1.0f blue:0.0f alpha:1.0f]
4092 : alpha:1.0];
4093 :
4094 : // see OODrawHilightedPlanetInfo
4095 : cx += drawCharacterQuad(23 - eco, cx, y, z, siz); // characters 16..23 are economy symbols
4096 : [[UNIVERSE gui] setGLColorFromSetting:[NSString stringWithFormat:kGuiChartGovernmentUColor, (unsigned long)gov]
4097 : defaultValue:[OOColor colorWithRed:govcol[gov*3] green:govcol[1+(gov*3)] blue:govcol[2+(gov*3)] alpha:1.0f]
4098 : alpha:1.0];
4099 :
4100 : cx += drawCharacterQuad(gov, cx, y, z, siz) - sF6KernGovt; // charcters 0..7 are government symbols
4101 : [[UNIVERSE gui] setGLColorFromSetting:kGuiChartTechColor
4102 : defaultValue:[OOColor colorWithRed:0.5 green:1.0f blue:1.0f alpha:1.0f]
4103 : alpha:1.0];
4104 :
4105 : if (tl > 9)
4106 : {
4107 : // display TL clamped between 1..16, this must be a '1'!
4108 : cx += drawCharacterQuad(49, cx, y - 2, z, siz) - sF6KernTL;
4109 : }
4110 : cx += drawCharacterQuad(48 + (tl % 10), cx, y - 2.0f, z, siz);
4111 : }
4112 : OOGLEND();
4113 :
4114 : (void)cx; // Suppress "value not used" analyzer issue.
4115 :
4116 : [OOTexture applyNone];
4117 : OOGL(glDisable(GL_TEXTURE_2D));
4118 :
4119 : OOVerifyOpenGLState();
4120 : }
4121 :
4122 :
4123 0 : void OODrawHilightedPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
4124 : {
4125 : float color[4];
4126 : int tl = tec + 1;
4127 :
4128 : NSSize hisize;
4129 :
4130 : // get the physical dimensions
4131 : hisize.height = siz.height;
4132 : hisize.width = 0.0f;
4133 :
4134 : // see OODrawPlanetInfo
4135 : hisize.width += siz.width * sGlyphWidths[23 - eco];
4136 : hisize.width += siz.width * sGlyphWidths[gov] - 1.0;
4137 : if (tl > 9) hisize.width += siz.width * sGlyphWidths[49] - 2.0;
4138 : hisize.width += siz.width * sGlyphWidths[48 + (tl % 10)];
4139 :
4140 : OOSetOpenGLState(OPENGL_STATE_OVERLAY);
4141 :
4142 : OOGL(glPushAttrib(GL_CURRENT_BIT)); // save the text colour
4143 : OOGL(glGetFloatv(GL_CURRENT_COLOR, color)); // we need the original colour's alpha.
4144 :
4145 : drawHighlight(x, y - 2.0f, z, hisize, color[3]);
4146 :
4147 : OOGL(glPopAttrib()); //restore the colour
4148 :
4149 : OODrawPlanetInfo(gov, eco, tec, x, y, z, siz);
4150 :
4151 : OOVerifyOpenGLState();
4152 : }
4153 :
4154 0 : static void GLDrawNonlinearCascadeWeapon( GLfloat x, GLfloat y, GLfloat z, NSSize siz, Vector centre, GLfloat radius, GLfloat zoom, GLfloat alpha )
4155 : {
4156 : Vector spacepos, scannerpos;
4157 : GLfloat theta, phi;
4158 : GLfloat z_factor = siz.height / siz.width; // approx 1/4
4159 : GLfloat y_factor = 1.0 - sqrt(z_factor); // approx 1/2
4160 : OOGLVector *points = malloc(sizeof(OOGLVector)*25);
4161 : int i, j;
4162 :
4163 : if (radius*radius > centre.y*centre.y)
4164 : {
4165 : GLfloat r0 = sqrt(radius*radius-centre.y*centre.y);
4166 : OOGL(glColor4f(1.0, 0.5, 1.0, alpha));
4167 : spacepos.y = 0;
4168 : for (i = 0; i < 24; i++)
4169 : {
4170 : theta = i*2*M_PI/24;
4171 : spacepos.x = centre.x + r0 * cos(theta);
4172 : spacepos.z = centre.z + r0 * sin(theta);
4173 : scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
4174 : points[i].x = x + scannerpos.x;
4175 : points[i].y = y + scannerpos.z * z_factor + scannerpos.y * y_factor;
4176 : points[i].z = z;
4177 : }
4178 : spacepos.x = centre.x + r0;
4179 : spacepos.y = 0;
4180 : spacepos.z = centre.z;
4181 : scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
4182 : points[24].x = x + scannerpos.x;
4183 : points[24].y = y + scannerpos.z * z_factor + scannerpos.y * y_factor;
4184 : points[24].z = z;
4185 : GLDrawPoints(points,25);
4186 : }
4187 : OOGL(glColor4f(0.5, 0.0, 1.0, 0.33333 * alpha));
4188 : free(points);
4189 : // Here, we draw a sphere distorted by the nonlinear function. We draw the sphere as a set of horizontal strips
4190 : // The even indices of points are the points on the upper edge of the strip, while odd indices are points
4191 : // on the bottom edge.
4192 : points = malloc(sizeof(OOGLVector)*50);
4193 : spacepos.x = centre.x;
4194 : spacepos.y = centre.y + radius;
4195 : spacepos.z = centre.z;
4196 : scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
4197 : for (i = 0; i <= 24; i++)
4198 : {
4199 : points[2*i+1].x = x + scannerpos.x;
4200 : points[2*i+1].y = y + scannerpos.y * y_factor + scannerpos.z * z_factor;
4201 : points[2*i+1].z = z;
4202 : }
4203 : for (i = 1; i <= 24; i++)
4204 : {
4205 : theta = i*M_PI/24;
4206 : for (j = 0; j <= 24; j++)
4207 : {
4208 : phi = j*M_PI/12;
4209 : // copy point from bottom edge of previous strip into top edge position
4210 : points[2*j] = points[2*j+1];
4211 :
4212 : spacepos.x = centre.x + radius * sin(theta) * cos(phi);
4213 : spacepos.y = centre.y + radius * cos(theta);
4214 : spacepos.z = centre.z + radius * sin(theta) * sin(phi);
4215 : scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
4216 : points[2*j+1].x = x + scannerpos.x;
4217 : points[2*j+1].y = y + scannerpos.y * y_factor + scannerpos.z * z_factor;
4218 : points[2*j+1].z = z;
4219 : }
4220 : GLDrawQuadStrip(points, 50);
4221 : }
4222 : free(points);
4223 : return;
4224 : }
4225 :
4226 0 : static GLfloat nonlinearScannerFunc( GLfloat distance, GLfloat zoom, GLfloat scale )
4227 : {
4228 : GLfloat x = fabs(distance / SCANNER_MAX_RANGE);
4229 : if (x >= 1.0)
4230 : return scale;
4231 : if (zoom <= 1.0)
4232 : return scale * x;
4233 : GLfloat c = 1 / ( zoom - 1 );
4234 : GLfloat b = c * ( c + 1 );
4235 : GLfloat a = c + 1;
4236 : return scale * ( a - b / ( x + c ) );
4237 : }
4238 :
4239 :
4240 0 : static void drawScannerGrid(GLfloat x, GLfloat y, GLfloat z, NSSize siz, int v_dir, GLfloat thickness, GLfloat zoom, BOOL nonlinear, BOOL minimalistic)
4241 : {
4242 : OOSetOpenGLState(OPENGL_STATE_OVERLAY);
4243 :
4244 : MyOpenGLView* gameView = [UNIVERSE gameView];
4245 :
4246 : GLfloat w1, h1;
4247 : GLfloat ww = 0.5 * siz.width;
4248 : GLfloat hh = 0.5 * siz.height;
4249 :
4250 : GLfloat km_scan;
4251 : GLfloat hdiv;
4252 : GLfloat wdiv;
4253 : BOOL drawdiv = NO, drawdiv1 = NO, drawdiv5 = NO;
4254 :
4255 : int i, ii;
4256 :
4257 : OOGL(GLScaledLineWidth(2.0 * thickness));
4258 : GLDrawOval(x, y, z, siz, 4);
4259 : OOGL(GLScaledLineWidth(thickness)); // reset (thickness = lineWidth)
4260 :
4261 : OOGLBEGIN(GL_LINES);
4262 : if (!minimalistic)
4263 : {
4264 : glVertex3f(x, y - hh, z); glVertex3f(x, y + hh, z);
4265 : glVertex3f(x - ww, y, z); glVertex3f(x + ww, y, z);
4266 :
4267 : if (nonlinear)
4268 : {
4269 : if (nonlinearScannerFunc(4000.0, zoom, hh)-nonlinearScannerFunc(3000.0, zoom ,hh) > 2) drawdiv1 = YES;
4270 : if (nonlinearScannerFunc(10000.0, zoom, hh)-nonlinearScannerFunc(5000.0, zoom, hh) > 2) drawdiv5 = YES;
4271 : wdiv = ww/(0.001*SCANNER_MAX_RANGE);
4272 : for (i = 1; 1000.0*i < SCANNER_MAX_RANGE; i++)
4273 : {
4274 : drawdiv = drawdiv1;
4275 : w1 = wdiv;
4276 : if (i % 10 == 0)
4277 : {
4278 : w1 = wdiv*4;
4279 : drawdiv = YES;
4280 : if (nonlinearScannerFunc((i+5)*1000,zoom,hh) - nonlinearScannerFunc(i*1000.0,zoom,hh)>2)
4281 : {
4282 : drawdiv5 = YES;
4283 : }
4284 : else
4285 : {
4286 : drawdiv5 = NO;
4287 : }
4288 : }
4289 : else if (i % 5 == 0)
4290 : {
4291 : w1 = wdiv*2;
4292 : drawdiv = drawdiv5;
4293 : if (nonlinearScannerFunc((i+1)*1000,zoom,hh) - nonlinearScannerFunc(i*1000.0,zoom,hh)>2)
4294 : {
4295 : drawdiv1 = YES;
4296 : }
4297 : else
4298 : {
4299 : drawdiv1 = NO;
4300 : }
4301 : }
4302 : if (drawdiv)
4303 : {
4304 : h1 = nonlinearScannerFunc(i*1000.0,zoom,hh);
4305 : glVertex3f(x - w1, y + h1, z); glVertex3f(x + w1, y + h1, z);
4306 : glVertex3f(x - w1, y - h1, z); glVertex3f(x + w1, y - h1, z);
4307 : }
4308 : }
4309 : }
4310 : else
4311 : {
4312 : km_scan = 0.001 * SCANNER_MAX_RANGE / zoom; // calculate kilometer divisions
4313 : hdiv = 0.5 * siz.height / km_scan;
4314 : wdiv = 0.25 * siz.width / km_scan;
4315 : if (wdiv < 4.0)
4316 : {
4317 : wdiv *= 2.0;
4318 : ii = 5;
4319 : }
4320 : else
4321 : {
4322 : ii = 1;
4323 : }
4324 :
4325 : for (i = ii; 2.0 * hdiv * i < siz.height; i += ii)
4326 : {
4327 : h1 = i * hdiv;
4328 : w1 = wdiv;
4329 : if (i % 5 == 0)
4330 : w1 = w1 * 2.5;
4331 : if (i % 10 == 0)
4332 : w1 = w1 * 2.0;
4333 : if (w1 > 3.5) // don't draw tiny marks
4334 : {
4335 : glVertex3f(x - w1, y + h1, z); glVertex3f(x + w1, y + h1, z);
4336 : glVertex3f(x - w1, y - h1, z); glVertex3f(x + w1, y - h1, z);
4337 : }
4338 : }
4339 : }
4340 : }
4341 :
4342 : double tanfov = [gameView fov:YES];
4343 : GLfloat aspect = [gameView viewSize].width / [gameView viewSize].height;
4344 : if (aspect < 4.0/3.0)
4345 : {
4346 : tanfov *= 0.75 * aspect;
4347 : }
4348 : double cosfov = 1.0/sqrt(1+tanfov*tanfov);
4349 : double sinfov = tanfov * cosfov;
4350 :
4351 : switch (v_dir)
4352 : {
4353 : case VIEW_BREAK_PATTERN:
4354 : case VIEW_GUI_DISPLAY:
4355 : case VIEW_FORWARD:
4356 : case VIEW_NONE:
4357 : glVertex3f(x, y, z); glVertex3f(x - ww * sinfov, y + hh * cosfov, z);
4358 : glVertex3f(x, y, z); glVertex3f(x + ww * sinfov, y + hh * cosfov, z);
4359 : break;
4360 :
4361 : case VIEW_AFT:
4362 : glVertex3f(x, y, z); glVertex3f(x - ww * sinfov, y - hh * cosfov, z);
4363 : glVertex3f(x, y, z); glVertex3f(x + ww * sinfov, y - hh * cosfov, z);
4364 : break;
4365 :
4366 : case VIEW_PORT:
4367 : glVertex3f(x, y, z); glVertex3f(x - ww * cosfov, y + hh * sinfov, z);
4368 : glVertex3f(x, y, z); glVertex3f(x - ww * cosfov, y - hh * sinfov, z);
4369 : break;
4370 :
4371 : case VIEW_STARBOARD:
4372 : glVertex3f(x, y, z); glVertex3f(x + ww * cosfov, y + hh * sinfov, z);
4373 : glVertex3f(x, y, z); glVertex3f(x + ww * cosfov, y - hh * sinfov, z);
4374 : break;
4375 : }
4376 : OOGLEND();
4377 :
4378 : OOVerifyOpenGLState();
4379 : }
4380 :
4381 :
4382 0 : static void DrawSpecialOval(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat step, GLfloat *color4v)
4383 : {
4384 : GLfloat ww = 0.5 * siz.width;
4385 : GLfloat hh = 0.5 * siz.height;
4386 : GLfloat theta;
4387 : GLfloat delta;
4388 : GLfloat s;
4389 :
4390 : delta = step * M_PI / 180.0f;
4391 :
4392 : OOGLBEGIN(GL_LINE_LOOP);
4393 : for (theta = 0.0f; theta < (2.0f * M_PI); theta += delta)
4394 : {
4395 : s = sin(theta);
4396 : glColor4f(color4v[0], color4v[1], color4v[2], fabs(s * color4v[3]));
4397 : glVertex3f(x + ww * s, y + hh * cos(theta), z);
4398 : }
4399 : OOGLEND();
4400 : }
4401 :
4402 :
4403 : - (void) setLineWidth:(GLfloat) value
4404 : {
4405 : lineWidth = value;
4406 : }
4407 :
4408 :
4409 : - (GLfloat) lineWidth
4410 : {
4411 : return lineWidth;
4412 : }
4413 :
4414 : @end
4415 :
4416 :
4417 : @implementation NSString (OODisplayEncoding)
4418 :
4419 : - (const char *) cStringUsingOoliteEncoding
4420 : {
4421 : if (sEncodingCoverter == nil) InitTextEngine();
4422 :
4423 : // Note: the data will be autoreleased, so the bytes behave as though they're autoreleased too.
4424 : return [[self dataUsingEncoding:[sEncodingCoverter encoding] allowLossyConversion:YES] bytes];
4425 : }
4426 :
4427 :
4428 : - (const char *) cStringUsingOoliteEncodingAndRemapping
4429 : {
4430 : if (sEncodingCoverter == nil) InitTextEngine();
4431 :
4432 : // Note: the data will be autoreleased, so the bytes behave as though they're autoreleased too.
4433 : return [[sEncodingCoverter convertString:self] bytes];
4434 : }
4435 :
4436 : @end
4437 :
4438 :
4439 : @implementation OOPolygonSprite (OOHUDBeaconIcon)
4440 :
4441 0 : - (void) oo_drawHUDBeaconIconAt:(NSPoint)where size:(NSSize)size alpha:(GLfloat)alpha z:(GLfloat)z
4442 : {
4443 : GLfloat x = where.x - size.width;
4444 : GLfloat y = where.y - 1.5 * size.height;
4445 :
4446 : GLfloat ox = x - size.width * 0.5;
4447 : GLfloat oy = y - size.height * 0.5;
4448 : GLfloat width = size.width * (1.0f / 6.0f);
4449 : GLfloat height = size.height * (1.0f / 6.0f);
4450 :
4451 : OOGLPushModelView();
4452 : OOGLTranslateModelView(make_vector(ox, oy, z));
4453 : OOGLScaleModelView(make_vector(width, height, 1.0f));
4454 : [self drawFilled];
4455 : glColor4f(0.0, 0.0, 0.0, 0.5 * alpha);
4456 : [self drawOutline];
4457 : OOGLPopModelView();
4458 : }
4459 :
4460 : @end
4461 :
4462 :
4463 : @implementation NSString (OOHUDBeaconIcon)
4464 :
4465 0 : - (void) oo_drawHUDBeaconIconAt:(NSPoint)where size:(NSSize)size alpha:(GLfloat)alpha z:(GLfloat)z
4466 : {
4467 : OODrawString(self, where.x - 2.5 * size.width, where.y - 3.0 * size.height, z, NSMakeSize(size.width * 2, size.height * 2));
4468 : }
4469 :
4470 : @end
4471 :
4472 :
4473 0 : static void SetGLColourFromInfo(NSDictionary *info, NSString *key, const GLfloat defaultColor[4], GLfloat alpha)
4474 : {
4475 : id colorDesc = nil;
4476 : OOColor *color = nil;
4477 : colorDesc = [info objectForKey:key];
4478 : if (colorDesc != nil)
4479 : {
4480 : color = [OOColor colorWithDescription:colorDesc];
4481 : if (color != nil)
4482 : {
4483 : GLfloat ioColor[4];
4484 : [color getRed:&ioColor[0] green:&ioColor[1] blue:&ioColor[2] alpha:&ioColor[3]];
4485 : GLColorWithOverallAlpha(ioColor,alpha);
4486 : return;
4487 : }
4488 : }
4489 : GLColorWithOverallAlpha(defaultColor,alpha);
4490 : }
4491 :
4492 :
4493 0 : static void GetRGBAArrayFromInfo(NSDictionary *info, GLfloat ioColor[4])
4494 : {
4495 : id colorDesc = nil;
4496 : OOColor *color = nil;
4497 :
4498 : // First, look for general colour specifier.
4499 : colorDesc = [info objectForKey:RGB_COLOR_KEY];
4500 : if (colorDesc != nil && ![info objectForKey:ALPHA_KEY])
4501 : {
4502 : color = [OOColor colorWithDescription:colorDesc];
4503 : if (color != nil)
4504 : {
4505 : [color getRed:&ioColor[0] green:&ioColor[1] blue:&ioColor[2] alpha:&ioColor[3]];
4506 : return;
4507 : }
4508 : }
4509 :
4510 : // Failing that, look for rgb_color and alpha.
4511 : colorDesc = [info oo_arrayForKey:RGB_COLOR_KEY];
4512 : if (colorDesc != nil && [colorDesc count] == 3)
4513 : {
4514 : ioColor[0] = [colorDesc oo_nonNegativeFloatAtIndex:0];
4515 : ioColor[1] = [colorDesc oo_nonNegativeFloatAtIndex:1];
4516 : ioColor[2] = [colorDesc oo_nonNegativeFloatAtIndex:2];
4517 : }
4518 : ioColor[3] = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:ioColor[3]];
4519 : }
|