Oolite 1.91.0.7646-241128-10e222e
Loading...
Searching...
No Matches
HeadUpDisplay.m
Go to the documentation of this file.
1/*
2
3HeadUpDisplay.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 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"
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"
45#import "OOCrosshairs.h"
46#import "OOConstToString.h"
47#import "OOStringParsing.h"
48#import "OOJoystickManager.h"
50#import "OOStringExpander.h"
51
52
53#define ONE_SIXTEENTH 0.0625
54#define ONE_SIXTYFOURTH 0.015625
55#define DEFAULT_OVERALL_ALPHA 0.75
56#define GLYPH_SCALE_FACTOR 0.13 // 0.13 is an inherited magic number
57#define IDENTIFY_SCANNER_LOLLIPOPS ( 0 && OOLITE_DEBUG)
58
59
60#define NOT_DEFINED INFINITY
61#define WIDGET_INFO 0
62#define WIDGET_CACHE 1
63#define WIDGET_SELECTOR 2
64#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#define DO_SET_COLOR(t,d) SetGLColourFromInfo(info,t,d,alpha)
68#define SET_COLOR(d) DO_SET_COLOR(COLOR_KEY,d)
69#define SET_COLOR_LOW(d) DO_SET_COLOR(COLOR_KEY_LOW,d)
70#define SET_COLOR_MEDIUM(d) DO_SET_COLOR(COLOR_KEY_MEDIUM,d)
71#define SET_COLOR_HIGH(d) DO_SET_COLOR(COLOR_KEY_HIGH,d)
72#define SET_COLOR_CRITICAL(d) DO_SET_COLOR(COLOR_KEY_CRITICAL,d)
73#define SET_COLOR_SURROUND(d) DO_SET_COLOR(COLOR_KEY_SURROUND,d)
74
76{
77 float x, y, x0, y0;
79};
80
81static NSArray *sCurrentDrawItem;
82
83OOINLINE float useDefined(float val, float validVal)
84{
85 return (val == NOT_DEFINED) ? validVal : val;
86}
87
88
89static void DrawSpecialOval(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat step, GLfloat* color4v);
90
91static void SetGLColourFromInfo(NSDictionary *info, NSString *key, const GLfloat defaultColor[4], GLfloat alpha);
92static void GetRGBAArrayFromInfo(NSDictionary *info, GLfloat ioColor[4]);
93
94static void hudDrawIndicatorAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount);
95static void hudDrawMarkerAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount);
96static void hudDrawBarAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount);
97static void hudDrawSurroundAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz);
98static void hudDrawStatusIconAt(int x, int y, int z, NSSize siz);
99static void hudDrawReticleOnTarget(Entity* target, PlayerEntity* player1, GLfloat z1,
100 GLfloat alpha, BOOL reticleTargetSensitive, NSMutableDictionary *propertiesReticleTargetSensitive,
101 BOOL colourFromScannerColour, BOOL showText, NSDictionary *info, NSMutableArray *reticleColors);
102static void hudDrawWaypoint(OOWaypointEntity *waypoint, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL selected, GLfloat scale);
103static void hudRotateViewpointForVirtualDepth(PlayerEntity * player1, Vector p1);
104static void drawScannerGrid(GLfloat x, GLfloat y, GLfloat z, NSSize siz, int v_dir, GLfloat thickness, GLfloat zoom, BOOL nonlinear, BOOL minimalistic);
105static GLfloat nonlinearScannerFunc(GLfloat distance, GLfloat zoom, GLfloat scale);
106static void GLDrawNonlinearCascadeWeapon( GLfloat x, GLfloat y, GLfloat z, NSSize siz, Vector centre, GLfloat radius, GLfloat zoom, GLfloat alpha );
107
110
111
112enum
113{
116
117
118@interface HeadUpDisplay (Private)
119
120- (void) drawCrosshairs;
121- (void) drawLegends;
122- (void) drawDials;
123- (void) drawMFDs;
124
125- (void) drawLegend:(NSDictionary *)info;
126- (void) drawHUDItem:(NSDictionary *)info;
127
128- (void) drawScanner:(NSDictionary *)info;
129- (void) drawScannerZoomIndicator:(NSDictionary *)info;
130
131- (void) drawCompass:(NSDictionary *)info;
132- (void) drawCompassPlanetBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
133- (void) drawCompassStationBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
134- (void) drawCompassSunBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
135- (void) drawCompassTargetBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
136- (void) drawCompassBeaconBlipAt:(Vector) relativePosition Size:(NSSize) siz Alpha:(GLfloat) alpha;
137
138- (void) drawAegis:(NSDictionary *)info;
139- (void) drawSpeedBar:(NSDictionary *)info;
140- (void) drawRollBar:(NSDictionary *)info;
141- (void) drawPitchBar:(NSDictionary *)info;
142- (void) drawYawBar:(NSDictionary *)info;
143- (void) drawEnergyGauge:(NSDictionary *)info;
144- (void) drawForwardShieldBar:(NSDictionary *)info;
145- (void) drawAftShieldBar:(NSDictionary *)info;
146- (void) drawFuelBar:(NSDictionary *)info;
147- (void) drawWitchspaceDestination:(NSDictionary *)info;
148- (void) drawCabinTempBar:(NSDictionary *)info;
149- (void) drawWeaponTempBar:(NSDictionary *)info;
150- (void) drawAltitudeBar:(NSDictionary *)info;
151- (void) drawMissileDisplay:(NSDictionary *)info;
152- (void) drawTargetReticle:(NSDictionary *)info;
153- (void) drawSecondaryTargetReticle:(NSDictionary *)info;
154- (void) drawWaypoints:(NSDictionary *)info;
155- (void) drawStatusLight:(NSDictionary *)info;
156- (void) drawDirectionCue:(NSDictionary *)info;
157- (void) drawClock:(NSDictionary *)info;
158- (void) drawPrimedEquipmentText:(NSDictionary *)info;
159- (void) drawASCTarget:(NSDictionary *)info;
160- (void) drawWeaponsOfflineText:(NSDictionary *)info;
161- (void) drawMultiFunctionDisplay:(NSDictionary *)info withText:(NSString *)text asIndex:(NSUInteger)index;
162- (void) drawFPSInfoCounter:(NSDictionary *)info;
163- (void) drawScoopStatus:(NSDictionary *)info;
164- (void) drawStickSensitivityIndicator:(NSDictionary *)info;
165- (void) drawCustomBar:(NSDictionary *)info;
166- (void) drawCustomText:(NSDictionary *)info;
167- (void) drawCustomIndicator:(NSDictionary *)info;
168- (void) drawCustomLight:(NSDictionary *)info;
169- (void) drawCustomImage:(NSDictionary *)info;
170
171- (void) drawSurroundInternal:(NSDictionary *)info color:(const GLfloat[4])color;
172- (void) drawSurround:(NSDictionary *)info;
173- (void) drawGreenSurround:(NSDictionary *)info;
174- (void) drawYellowSurround:(NSDictionary *)info;
175
176- (void) drawTrumbles:(NSDictionary *)info;
177
178- (NSArray *) crosshairDefinitionForWeaponType:(OOWeaponType)weapon;
179
180- (BOOL) checkPlayerInFlight;
182
183- (void) resetGui:(GuiDisplayGen*)gui withInfo:(NSDictionary *)gui_info;
184- (void) resetGuiPosition:(GuiDisplayGen*)gui withInfo:(NSDictionary *)gui_info;
185
186
187@end
188
189
190@implementation HeadUpDisplay
191
192static const GLfloat red_color[4] = {1.0, 0.0, 0.0, 1.0};
193static const GLfloat redplus_color[4] = {1.0, 0.0, 0.5, 1.0};
194static const GLfloat yellow_color[4] = {1.0, 1.0, 0.0, 1.0};
195static const GLfloat green_color[4] = {0.0, 1.0, 0.0, 1.0};
196static const GLfloat darkgreen_color[4] = {0.0, 0.75, 0.0, 1.0};
197static const GLfloat blue_color[4] = {0.0, 0.0, 1.0, 1.0};
198static const GLfloat black_color[4] = {0.0, 0.0, 0.0, 1.0};
199static const GLfloat lightgray_color[4] = {0.25, 0.25, 0.25, 1.0};
200
201static float sGlyphWidths[256];
202static float sF6KernGovt;
203static float sF6KernTL;
204static BOOL _compassUpdated;
205
206
207static GLfloat drawCharacterQuad(uint8_t chr, GLfloat x, GLfloat y, GLfloat z, NSSize siz);
208
209static void InitTextEngine(void);
210
211static void prefetchData(NSDictionary *info, struct CachedInfo *data);
212
213
214OOINLINE 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- (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- (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- (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
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]];
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
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
858
859 hudUpdating = NO;
860}
861
862
863- (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- (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- (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- (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- (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- (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);
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- (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
1147}
1148
1149
1150- (BOOL) checkPlayerInFlight
1151{
1152 return [PLAYER isInSpace] && [PLAYER status] != STATUS_DOCKING;
1153}
1154
1155
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
1167static 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- (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
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
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
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- (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;
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;
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
1585 OOGL(glDisable(GL_TEXTURE_2D));
1586}
1587
1588
1589- (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
1687OOINLINE 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- (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- (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- (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- (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- (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- (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
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
1833#endif
1834}
1835
1836
1837- (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
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 {
1866 }
1867 else if (ds > .25)
1868 {
1870 }
1871 else
1872 {
1874 }
1875
1876 hudDrawBarAt(x, y, z1, siz, ds);
1877}
1878
1879
1880- (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
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- (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
1934 hudDrawSurroundAt(x, y, z1, siz);
1935 }
1936 // draw custom indicator
1938 hudDrawIndicatorAt(x, y, z1, siz, iv);
1939}
1940
1941
1942- (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- (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- (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
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 {
2053 }
2054 else if (ds > .25)
2055 {
2057 }
2058 else
2059 {
2061 }
2062
2063 hudDrawBarAt(x, y, z1, siz, ds);
2064}
2065
2066
2067- (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
2088 hudDrawSurroundAt(x, y, z1, siz);
2089 }
2090 // draw ROLL bar
2092 hudDrawIndicatorAt(x, y, z1, siz, [PLAYER dialRoll]);
2093}
2094
2095
2096- (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
2117 hudDrawSurroundAt(x, y, z1, siz);
2118 }
2119 // draw PITCH bar
2121 hudDrawIndicatorAt(x, y, z1, siz, [PLAYER dialPitch]);
2122}
2123
2124
2125- (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
2147 hudDrawSurroundAt(x, y, z1, siz);
2148 }
2149 // draw YAW bar
2151 hudDrawIndicatorAt(x, y, z1, siz, [PLAYER dialYaw]);
2152}
2153
2154
2155- (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;
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
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 {
2214 }
2215 else
2216 {
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- (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;
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
2259 hudDrawSurroundAt(x, y, z1, siz);
2260 }
2261 // draw forward_shield bar
2262 if (shield < .25)
2263 {
2265 }
2266 else if (shield < .80)
2267 {
2269 }
2270 else
2271 {
2273 }
2274 hudDrawBarAt(x, y, z1, siz, shield);
2275}
2276
2277
2278- (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;
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
2300 hudDrawSurroundAt(x, y, z1, siz);
2301 }
2302 // draw forward_shield bar
2303 if (shield < .25)
2304 {
2306 }
2307 else if (shield < .80)
2308 {
2310 }
2311 else
2312 {
2314 }
2315 hudDrawBarAt(x, y, z1, siz, shield);
2316}
2317
2318
2319- (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 {
2340 hudDrawSurroundAt(x, y, z1, siz);
2341 }
2342
2343 fu = [PLAYER dialFuel];
2344 hr = [PLAYER dialHyperRange];
2345
2346 // draw fuel bar
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 {
2356 }
2357 else
2358 {
2360 }
2361 hudDrawMarkerAt(x, y, z1, siz, hr);
2362 }
2363
2364}
2365
2366
2367- (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
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- (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;
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 {
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)
2437 else
2439 }
2440 else
2441 {
2442 if (temp > .25)
2444 else
2446 }
2447
2448
2449 hudDrawBarAt(x, y, z1, siz, temp);
2450}
2451
2452
2453- (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;
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 {
2474 hudDrawSurroundAt(x, y, z1, siz);
2475 }
2476
2477 // draw weapon_temp bar (only need to call GLColor() once!)
2478 if (temp > .80)
2480 else if (temp > .25)
2482 else
2484 hudDrawBarAt(x, y, z1, siz, temp);
2485}
2486
2487
2488- (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;
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 {
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)
2520 else
2522 }
2523 else
2524 {
2525 if (alt < .75)
2527 else
2529 }
2530
2531 hudDrawBarAt(x, y, z1, siz, alt);
2532
2533}
2534
2535
2536static NSString * const kDefaultMissileIconKey = @"oolite-default-missile-icon";
2537static NSString * const kDefaultMineIconKey = @"oolite-default-mine-icon";
2538static const GLfloat kOutlineWidth = 0.5f;
2539
2540
2541static 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- (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.
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];
2597
2598 // Draw black backing, so outline colour isn’t blended into missile colour.
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];
2605
2606 switch (status)
2607 {
2609 GLColorWithOverallAlpha(green_color, alpha); break;
2611 GLColorWithOverallAlpha(yellow_color, alpha); break;
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
2623 OOGLTranslateModelView(make_vector(x - width * 2.0f, y - height * 2.0f, z1));
2624 OOGLScaleModelView(make_vector(width, height, 1.0f));
2625 [sprite drawFilled];
2627}
2628
2629
2630
2631- (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.
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];
2643}
2644
2645
2646- (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;
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 {
2697 GLColorWithOverallAlpha(green_color, alpha); break;
2699 GLColorWithOverallAlpha(yellow_color, alpha); break;
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- (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- (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- (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- (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;
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 {
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
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
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:
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- (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- (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;
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- (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- (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- (void) drawWeaponsOfflineText:(NSDictionary *)info
3050{
3051 OOViewID viewID = [UNIVERSE viewDirection];
3052 GLfloat textColor[4] = {0.0f, 1.0f, 0.0f, 1.0f};
3053
3054 if (viewID == VIEW_CUSTOM ||
3055 overallAlpha == 0.0f ||
3056 !([PLAYER status] == STATUS_IN_FLIGHT || [PLAYER status] == STATUS_WITCHSPACE_COUNTDOWN) ||
3057 [UNIVERSE displayGUI]
3058 )
3059 {
3060 // Don't draw weapons offline text
3061 return;
3062 }
3063
3064 if (![PLAYER weaponsOnline])
3065 {
3066 int x, y;
3067 NSSize siz;
3068 GLfloat alpha = overallAlpha;
3069 struct CachedInfo cached;
3070
3071 [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3072
3073 x = useDefined(cached.x, WEAPONSOFFLINETEXT_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
3074 y = useDefined(cached.y, WEAPONSOFFLINETEXT_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
3076 siz.height = useDefined(cached.height, WEAPONSOFFLINETEXT_HEIGHT);
3077 alpha *= cached.alpha;
3078
3079 GetRGBAArrayFromInfo(info, textColor);
3080 textColor[3] *= overallAlpha;
3081
3082 OOGL(glColor4f(textColor[0], textColor[1], textColor[2], textColor[3]));
3083 // TODO: some caching required...
3084 OODrawString(DESC(@"weapons-systems-offline"), x, y, z1, siz);
3085 }
3086}
3087
3088
3089- (void) drawFPSInfoCounter:(NSDictionary *)info
3090{
3091 if (![UNIVERSE displayFPS]) return;
3092
3093 int x, y;
3094 NSSize siz;
3095 struct CachedInfo cached;
3096 GLfloat textColor[4] = {0.0, 1.0, 0.0, 1.0};
3097
3098 [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3099
3100 x = useDefined(cached.x, FPSINFO_DISPLAY_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
3101 y = useDefined(cached.y, FPSINFO_DISPLAY_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
3103 siz.height = useDefined(cached.height, FPSINFO_DISPLAY_HEIGHT);
3104
3105 HPVector playerPos = [PLAYER position];
3106 NSString *positionInfo = [UNIVERSE expressPosition:playerPos inCoordinateSystem:@"pwm"];
3107 positionInfo = [NSString stringWithFormat:@"abs %.2f %.2f %.2f / %@", playerPos.x, playerPos.y, playerPos.z, positionInfo];
3108
3109 // We would normally set a variable alpha value here, but in this case we don't.
3110 // We prefer the FPS counter to be always visible - Nikos 20100405
3111 GetRGBAArrayFromInfo(info, textColor);
3112 OOGL(glColor4f(textColor[0], textColor[1], textColor[2], 1.0f));
3113 OODrawString([PLAYER dial_fpsinfo], x, y, z1, siz);
3114
3115#ifndef NDEBUG
3116 NSSize siz08 = NSMakeSize(0.8 * siz.width, 0.8 * siz.width);
3117 NSString *collDebugInfo = [NSString stringWithFormat:@"%@ - %@", [PLAYER dial_objinfo], [UNIVERSE collisionDescription]];
3118 OODrawString(collDebugInfo, x, y - siz.height, z1, siz);
3119
3120 OODrawString(positionInfo, x, y - 1.8 * siz.height, z1, siz08);
3121
3122 NSString *timeAccelerationFactorInfo = [NSString stringWithFormat:@"TAF: %@%.2f", DESC(@"multiplication-sign"), [UNIVERSE timeAccelerationFactor]];
3123 OODrawString(timeAccelerationFactorInfo, x, y - 3.2 * siz08.height, z1, siz08);
3124#endif
3125}
3126
3127
3128- (void) drawScoopStatus:(NSDictionary *)info
3129{
3130 int i, x, y;
3131 NSSize siz;
3132 GLfloat alpha;
3133 struct CachedInfo cached;
3134
3135 [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3136
3137 x = useDefined(cached.x, SCOOPSTATUS_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
3138 y = useDefined(cached.y, SCOOPSTATUS_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
3139 siz.width = useDefined(cached.width, SCOOPSTATUS_WIDTH);
3140 siz.height = useDefined(cached.height, SCOOPSTATUS_HEIGHT);
3141 // default alpha value different from all others, won't use cached.alpha
3142 alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:0.75f];
3143
3144 const GLfloat* s0_color = red_color;
3145 GLfloat s1c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3146 GLfloat s2c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3147 GLfloat s3c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3148 int scoop_status = [PLAYER dialFuelScoopStatus];
3149 GLfloat t = [UNIVERSE getTime];
3150 GLfloat a1 = alpha * 0.5f * (1.0f + sin(t * 8.0f));
3151 GLfloat a2 = alpha * 0.5f * (1.0f + sin(t * 8.0f - 1.0f));
3152 GLfloat a3 = alpha * 0.5f * (1.0f + sin(t * 8.0f - 2.0f));
3153
3154 switch (scoop_status)
3155 {
3157 return; // don't draw
3158
3160 s0_color = darkgreen_color;
3161 alpha *= 0.75;
3162 break;
3163
3165 case SCOOP_STATUS_OKAY:
3166 s0_color = green_color;
3167 break;
3168 }
3169
3170 for (i = 0; i < 3; i++)
3171 {
3172 s1c[i] = s0_color[i];
3173 s2c[i] = s0_color[i];
3174 s3c[i] = s0_color[i];
3175 }
3176 if (scoop_status == SCOOP_STATUS_FULL_HOLD)
3177 {
3178 s3c[0] = red_color[0];
3179 s3c[1] = red_color[1];
3180 s3c[2] = red_color[2];
3181 }
3182 if (scoop_status == SCOOP_STATUS_ACTIVE)
3183 {
3184 s1c[3] = alpha * a1;
3185 s2c[3] = alpha * a2;
3186 s3c[3] = alpha * a3;
3187 }
3188 else
3189 {
3190 s1c[3] = alpha;
3191 s2c[3] = alpha;
3192 s3c[3] = alpha;
3193 }
3194
3195 GLfloat w1 = siz.width / 8.0;
3196 GLfloat w2 = 2.0 * w1;
3197// GLfloat w3 = 3.0 * w1;
3198 GLfloat w4 = 4.0 * w1;
3199 GLfloat h1 = siz.height / 8.0;
3200 GLfloat h2 = 2.0 * h1;
3201 GLfloat h3 = 3.0 * h1;
3202 GLfloat h4 = 4.0 * h1;
3203
3204 OOGL(glDisable(GL_TEXTURE_2D));
3205 OOGLBEGIN(GL_QUADS);
3206 // section 1
3207 GLColorWithOverallAlpha(s1c, overallAlpha);
3208 glVertex3f(x, y + h1, z1); glVertex3f(x - w2, y + h2, z1); glVertex3f(x, y + h3, z1); glVertex3f(x + w2, y + h2, z1);
3209 // section 2
3210 GLColorWithOverallAlpha(s2c, overallAlpha);
3211 glVertex3f(x, y - h1, z1); glVertex3f(x - w4, y + h1, z1); glVertex3f(x - w4, y + h2, z1); glVertex3f(x, y, z1);
3212 glVertex3f(x, y - h1, z1); glVertex3f(x + w4, y + h1, z1); glVertex3f(x + w4, y + h2, z1); glVertex3f(x, y, z1);
3213 // section 3
3214 GLColorWithOverallAlpha(s3c, overallAlpha);
3215 glVertex3f(x, y - h4, z1); glVertex3f(x - w2, y - h2, z1); glVertex3f(x - w2, y - h1, z1); glVertex3f(x, y - h2, z1);
3216 glVertex3f(x, y - h4, z1); glVertex3f(x + w2, y - h2, z1); glVertex3f(x + w2, y - h1, z1); glVertex3f(x, y - h2, z1);
3217 OOGLEND();
3218}
3219
3220
3221- (void) drawStickSensitivityIndicator:(NSDictionary *)info
3222{
3223 GLfloat x, y;
3224 NSSize siz;
3225 GLfloat alpha = overallAlpha;
3226 BOOL mouse = [PLAYER isMouseControlOn];
3228 struct CachedInfo cached;
3229
3230 if (![stickHandler joystickCount])
3231 {
3232 return; // no need to draw if no joystick fitted
3233 }
3234
3235 [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3236
3237 x = useDefined(cached.x, STATUS_LIGHT_CENTRE_X) + [[UNIVERSE gameView] x_offset] * cached.x0;
3238 y = useDefined(cached.y, STATUS_LIGHT_CENTRE_Y) + [[UNIVERSE gameView] y_offset] * cached.y0;
3240 siz.height = useDefined(cached.height, STATUS_LIGHT_HEIGHT);
3241 alpha *= cached.alpha;
3242
3243 GLfloat div = [stickHandler getSensitivity];
3244
3245 GLColorWithOverallAlpha(black_color, alpha / 4);
3246 GLDrawFilledOval(x, y, z1, siz, 10);
3247
3248 GLColorWithOverallAlpha((div < 1.0 || mouse) ? lightgray_color : green_color, alpha);
3249 OOGL(GLScaledLineWidth(_crosshairWidth * lineWidth));
3250
3251 if (div >= 1.0)
3252 {
3253 if (!mouse)
3254 {
3255 NSSize siz8th = { siz.width / 8, siz.height / 8 };
3256 GLDrawFilledOval(x, y, z1, siz8th, 30);
3257
3258 if (div == 1.0) // normal mode
3259 GLColorWithOverallAlpha(lightgray_color, alpha);
3260 }
3261
3262 siz.width -= _crosshairWidth * lineWidth / 2;
3263 siz.height -= _crosshairWidth * lineWidth / 2;
3264 GLDrawOval(x, y, z1, siz, 10);
3265 }
3266 else if (div < 1.0) // insensitive mode (shouldn't happen)
3267 GLDrawFilledOval(x, y, z1, siz, 10);
3268
3269 OOGL(GLScaledLineWidth(lineWidth)); // reset
3270}
3271
3272
3273- (void) drawSurroundInternal:(NSDictionary *)info color:(const GLfloat[4])color
3274{
3275 NSInteger x, y;
3276 NSSize siz;
3277 GLfloat alpha = overallAlpha;
3278 struct CachedInfo cached;
3279
3280 [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3281
3282 if (cached.x == NOT_DEFINED || cached.y == NOT_DEFINED || cached.width == NOT_DEFINED || cached.height == NOT_DEFINED)
3283 {
3284 return;
3285 }
3286
3287 x = cached.x + [[UNIVERSE gameView] x_offset] * cached.x0;
3288 y = cached.y + [[UNIVERSE gameView] y_offset] * cached.y0;
3289 siz.width = useDefined(cached.width, WEAPONSOFFLINETEXT_WIDTH);
3290 siz.height = useDefined(cached.height, WEAPONSOFFLINETEXT_HEIGHT);
3291 alpha *= cached.alpha;
3292
3293 // draw the surround
3294 GLColorWithOverallAlpha(color, alpha);
3295 hudDrawSurroundAt(x, y, z1, siz);
3296}
3297
3298
3299- (void) drawSurround:(NSDictionary *)info
3300{
3301 GLfloat itemColor[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
3302 id colorDesc = [info objectForKey:COLOR_KEY];
3303 if (colorDesc != nil)
3304 {
3305 OOColor *color = [OOColor colorWithDescription:colorDesc];
3306 if (color != nil)
3307 {
3308 itemColor[0] = [color redComponent];
3309 itemColor[1] = [color greenComponent];
3310 itemColor[2] = [color blueComponent];
3311 }
3312 }
3313
3314 [self drawSurroundInternal:info color:itemColor];
3315}
3316
3317
3318- (void) drawGreenSurround:(NSDictionary *)info
3319{
3320 [self drawSurroundInternal:info color:green_color];
3321}
3322
3323
3324- (void) drawYellowSurround:(NSDictionary *)info
3325{
3326 [self drawSurroundInternal:info color:yellow_color];
3327}
3328
3329
3330- (void) drawTrumbles:(NSDictionary *)info
3331{
3332 OOTrumble** trumbles = [PLAYER trumbleArray];
3333 NSUInteger i;
3334 for (i = [PLAYER trumbleCount]; i > 0; i--)
3335 {
3336 OOTrumble* trum = trumbles[i - 1];
3337 [trum drawTrumble: z1];
3338 }
3339}
3340
3341
3342- (void) drawMultiFunctionDisplay:(NSDictionary *)info withText:(NSString *)text asIndex:(NSUInteger)index
3343{
3344 PlayerEntity *player1 = PLAYER;
3345 struct CachedInfo cached;
3346 NSInteger i, x, y;
3347 NSSize siz, tmpsiz;
3348 if ([player1 guiScreen] != GUI_SCREEN_MAIN) // don't draw on text screens
3349 {
3350 return;
3351 }
3352 GLfloat alpha = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:1.0f] * overallAlpha;
3353
3354 GLfloat mfd_color[4] = {0.0, 1.0, 0.0, 0.9*alpha};
3355 OOColor *mfdcol = [OOColor colorWithDescription:[info objectForKey:COLOR_KEY]];
3356 if (mfdcol != nil)
3357 {
3358 [mfdcol getRed:&mfd_color[0] green:&mfd_color[1] blue:&mfd_color[2] alpha:&mfd_color[3]];
3359 }
3360 if (index != [player1 activeMFD])
3361 {
3362 mfd_color[3] *= 0.75;
3363 }
3364 [self drawSurroundInternal:info color:mfd_color];
3365
3366 [(NSValue *)[sCurrentDrawItem objectAtIndex:WIDGET_CACHE] getValue:&cached];
3367 x = cached.x + [[UNIVERSE gameView] x_offset] * cached.x0;
3368 y = cached.y + [[UNIVERSE gameView] y_offset] * cached.y0;
3369
3370 siz.width = useDefined(cached.width / 15, MFD_TEXT_WIDTH);
3371 siz.height = useDefined(cached.height / 10, MFD_TEXT_HEIGHT);
3372
3373 GLfloat x0 = (GLfloat)(x - cached.width/2);
3374 GLfloat y0 = (GLfloat)(y + cached.height/2);
3375 GLfloat x1 = (GLfloat)(x + cached.width/2);
3376 GLfloat y1 = (GLfloat)(y - cached.height/2);
3377 GLColorWithOverallAlpha(mfd_color, alpha*0.3);
3378 OOGLBEGIN(GL_QUADS);
3379 glVertex3f(x0-2,y0+2,z1);
3380 glVertex3f(x0-2,y1-2,z1);
3381 glVertex3f(x1+2,y1-2,z1);
3382 glVertex3f(x1+2,y0+2,z1);
3383 OOGLEND();
3384
3385 NSString *line = nil;
3386 NSArray *lines = [text componentsSeparatedByString:@"\n"];
3387 // text at full opacity
3388 GLColorWithOverallAlpha(mfd_color, alpha);
3389 for (i = 0; i < 10 ; i++)
3390 {
3391 line = [lines oo_stringAtIndex:i defaultValue:nil];
3392 if (line != nil)
3393 {
3394 y0 -= siz.height;
3395 // all lines should be shorter than the size of the MFD
3396 GLfloat textwidth = OORectFromString(line, 0.0f, 0.0f, siz).size.width;
3397 if (textwidth <= cached.width)
3398 {
3399 OODrawString(line, x0, y0, z1, siz);
3400 }
3401 else
3402 {
3403 // compress it so it fits
3404 tmpsiz.height = siz.height;
3405 tmpsiz.width = siz.width * cached.width / textwidth;
3406 OODrawString(line, x0, y0, z1, tmpsiz);
3407 }
3408 }
3409 else
3410 {
3411 break;
3412 }
3413 }
3414}
3415
3416//---------------------------------------------------------------------//
3417
3418static void hudDrawIndicatorAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
3419{
3420 if (siz.width > siz.height)
3421 {
3422 GLfloat dial_oy = y - siz.height/2;
3423 GLfloat position = x + amount * siz.width / 2;
3424 OOGLBEGIN(GL_QUADS);
3425 glVertex3f(position, dial_oy, z);
3426 glVertex3f(position+2, y, z);
3427 glVertex3f(position, dial_oy+siz.height, z);
3428 glVertex3f(position-2, y, z);
3429 OOGLEND();
3430 }
3431 else
3432 {
3433 GLfloat dial_ox = x - siz.width/2;
3434 GLfloat position = y + amount * siz.height / 2;
3435 OOGLBEGIN(GL_QUADS);
3436 glVertex3f(dial_ox, position, z);
3437 glVertex3f(x, position+2, z);
3438 glVertex3f(dial_ox + siz.width, position, z);
3439 glVertex3f(x, position-2, z);
3440 OOGLEND();
3441 }
3442}
3443
3444
3445static void hudDrawMarkerAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
3446{
3447 if (siz.width > siz.height)
3448 {
3449 GLfloat dial_oy = y - siz.height/2;
3450 GLfloat position = x + amount * siz.width - siz.width/2;
3451 OOGLBEGIN(GL_QUADS);
3452 glVertex3f(position+1, dial_oy+1, z);
3453 glVertex3f(position+1, dial_oy+siz.height-1, z);
3454 glVertex3f(position-1, dial_oy+siz.height-1, z);
3455 glVertex3f(position-1, dial_oy+1, z);
3456 OOGLEND();
3457 }
3458 else
3459 {
3460 GLfloat dial_ox = x - siz.width/2;
3461 GLfloat position = y + amount * siz.height - siz.height/2;
3462 OOGLBEGIN(GL_QUADS);
3463 glVertex3f(dial_ox+1, position+1, z);
3464 glVertex3f(dial_ox + siz.width-1, position+1, z);
3465 glVertex3f(dial_ox + siz.width-1, position-1, z);
3466 glVertex3f(dial_ox+1, position-1, z);
3467 OOGLEND();
3468 }
3469}
3470
3471
3472static void hudDrawBarAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
3473{
3474 GLfloat dial_ox = x - siz.width/2;
3475 GLfloat dial_oy = y - siz.height/2;
3476 if (fabs(siz.width) > fabs(siz.height))
3477 {
3478 GLfloat position = dial_ox + amount * siz.width;
3479
3480 OOGLBEGIN(GL_QUADS);
3481 glVertex3f(dial_ox, dial_oy, z);
3482 glVertex3f(position, dial_oy, z);
3483 glVertex3f(position, dial_oy+siz.height, z);
3484 glVertex3f(dial_ox, dial_oy+siz.height, z);
3485 OOGLEND();
3486 }
3487 else
3488 {
3489 GLfloat position = dial_oy + amount * siz.height;
3490
3491 OOGLBEGIN(GL_QUADS);
3492 glVertex3f(dial_ox, dial_oy, z);
3493 glVertex3f(dial_ox, position, z);
3494 glVertex3f(dial_ox+siz.width, position, z);
3495 glVertex3f(dial_ox+siz.width, dial_oy, z);
3496 OOGLEND();
3497 }
3498}
3499
3500
3501static void hudDrawSurroundAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz)
3502{
3503 GLfloat dial_ox = x - siz.width/2;
3504 GLfloat dial_oy = y - siz.height/2;
3505
3506 OOGLBEGIN(GL_LINE_LOOP);
3507 glVertex3f(dial_ox-2, dial_oy-2, z);
3508 glVertex3f(dial_ox+siz.width+2, dial_oy-2, z);
3509 glVertex3f(dial_ox+siz.width+2, dial_oy+siz.height+2, z);
3510 glVertex3f(dial_ox-2, dial_oy+siz.height+2, z);
3511 OOGLEND();
3512}
3513
3514
3515static void hudDrawStatusIconAt(int x, int y, int z, NSSize siz)
3516{
3517 int ox = x - siz.width / 2.0;
3518 int oy = y - siz.height / 2.0;
3519 int w = siz.width / 4.0;
3520 int h = siz.height / 4.0;
3521
3522 glVertex3i(ox, oy + h, z);
3523 glVertex3i(ox, oy + 3 * h, z);
3524 glVertex3i(ox + w, oy + 4 * h, z);
3525 glVertex3i(ox + 3 * w, oy + 4 * h, z);
3526 glVertex3i(ox + 4 * w, oy + 3 * h, z);
3527 glVertex3i(ox + 4 * w, oy + h, z);
3528 glVertex3i(ox + 3 * w, oy, z);
3529 glVertex3i(ox + w, oy, z);
3530}
3531
3532
3533static void hudDrawReticleOnTarget(Entity *target, PlayerEntity *player1, GLfloat z1,
3534 GLfloat alpha, BOOL reticleTargetSensitive, NSMutableDictionary *propertiesReticleTargetSensitive,
3535 BOOL colourFromScannerColour, BOOL showText, NSDictionary *info, NSMutableArray *reticleColors)
3536{
3537 if (target == nil || player1 == nil)
3538 {
3539 return;
3540 }
3541 if ([player1 guiScreen] != GUI_SCREEN_MAIN) // don't draw on text screens
3542 {
3543 return;
3544 }
3545
3546 ShipEntity *target_ship = nil;
3547 NSString *legal_desc = nil;
3548
3549 GLfloat scale = [info oo_floatForKey:@"reticle_scale" defaultValue:ONE_SIXTYFOURTH];
3550
3551
3552 if ([target isShip])
3553 {
3554 target_ship = (ShipEntity *)target;
3555 legal_desc = [target_ship scanDescription];
3556 }
3557
3558 if ([target_ship isCloaked]) return;
3559
3560
3561 Vector p1;
3562
3563 // by definition close enough that single precision is fine
3564 p1 = HPVectorToVector(HPvector_subtract([target position], [player1 viewpointPosition]));
3565
3566 GLfloat rdist = magnitude(p1);
3567 GLfloat rsize = [target collisionRadius] / (2 * [[UNIVERSE gameView] fov:YES]); // FIXME integrate 2 into fov to remove magic number
3568
3569 if (rsize < rdist * scale)
3570 rsize = rdist * scale;
3571
3572 GLfloat rs0 = rsize;
3573 GLfloat rs2 = rsize * 0.50;
3574
3577
3578 // draw the reticle
3579 float range = sqrt(target->zero_distance) - target->collision_radius;
3580
3581 int flash = (int)([UNIVERSE getTime] * 4);
3582 flash &= 1;
3583
3584 // Draw reticle cyan for Wormholes
3585 if ([target isWormhole])
3586 {
3587 OOColor *wormholeReticleColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_WORMHOLE];
3588 GLfloat wormholeReticleColorArray[4] = {[wormholeReticleColor redComponent],
3589 [wormholeReticleColor greenComponent],
3590 [wormholeReticleColor blueComponent],
3591 [wormholeReticleColor alphaComponent]};
3592 GLColorWithOverallAlpha(wormholeReticleColorArray, alpha);
3593 }
3594 else
3595 {
3596 // Reticle sensitivity accuracy calculation
3597 BOOL isTargeted = NO;
3598 GLfloat probabilityAccuracy;
3599
3600 if (propertiesReticleTargetSensitive != nil)
3601 {
3602 // Only if target is within player's weapon range, we mind for reticle accuracy
3603 if (range < [player1 weaponRange])
3604 {
3605 // After MAX_ACCURACY_RANGE km start decreasing high accuracy probability by ACCURACY_PROBABILITY_DECREASE_FACTOR%
3606 if (range > MAX_ACCURACY_RANGE)
3607 {
3608 // Every one second re-evaluate accuracy
3609 if ([UNIVERSE getTime] > [propertiesReticleTargetSensitive oo_doubleForKey:@"timeLastAccuracyProbabilityCalculation"] + 1)
3610 {
3611 probabilityAccuracy = 1-(range-MAX_ACCURACY_RANGE)*ACCURACY_PROBABILITY_DECREASE_FACTOR;
3612 // Make sure probability does not go below a minimum
3613 probabilityAccuracy = probabilityAccuracy < MIN_PROBABILITY_ACCURACY ? MIN_PROBABILITY_ACCURACY : probabilityAccuracy;
3614 [propertiesReticleTargetSensitive setObject:[NSNumber numberWithBool:((randf() < probabilityAccuracy) ? YES : NO)] forKey:@"isAccurate"];
3615
3616 // Store the time the last accuracy probability has been performed
3617 [propertiesReticleTargetSensitive setObject:[NSNumber numberWithDouble:[UNIVERSE getTime]] forKey:@"timeLastAccuracyProbabilityCalculation"];
3618 }
3619 if ([propertiesReticleTargetSensitive oo_boolForKey:@"isAccurate"])
3620 {
3621 // high accuracy reticle
3622 isTargeted = ([UNIVERSE firstEntityTargetedByPlayerPrecisely] == target);
3623 }
3624 else
3625 {
3626 // low accuracy reticle
3627 isTargeted = ([UNIVERSE firstEntityTargetedByPlayer] == target);
3628 }
3629 }
3630 else
3631 {
3632 // high accuracy reticle
3633 isTargeted = ([UNIVERSE firstEntityTargetedByPlayerPrecisely] == target);
3634 }
3635 }
3636 }
3637
3638 // If reticle is target sensitive, draw target box in red
3639 // when target passes through laser hit-point(with decreasing accuracy)
3640 // and is within hit-range.
3641 //
3642 // NOTE: The following condition also considers (indirectly) the player's weapon range.
3643 // 'isTargeted' is initialised to FALSE. Only if target is within the player's weapon range,
3644 // it might change value. Therefore, it is not necessary to add '&& range < [player1 weaponRange]'
3645 // to the following condition.
3646 if (colourFromScannerColour)
3647 {
3648 if ([target isShip])
3649 {
3650 ShipEntity *ship = (ShipEntity *)target;
3651 BOOL isHostile = (([ship hasHostileTarget])&&([ship primaryTarget] == PLAYER));
3652 GLColorWithOverallAlpha([ship scannerDisplayColorForShip:PLAYER :isHostile :flash :[ship scannerDisplayColor1] :[ship scannerDisplayColor2] :[ship scannerDisplayColorHostile1] :[ship scannerDisplayColorHostile2]],alpha);
3653 }
3654 else if ([target isVisualEffect])
3655 {
3657 GLColorWithOverallAlpha([vis scannerDisplayColorForShip:flash :[vis scannerDisplayColor1] :[vis scannerDisplayColor2]],alpha);
3658 }
3659 else
3660 {
3661 GLColorWithOverallAlpha(green_color, alpha);
3662 }
3663 }
3664 else
3665 {
3666 OOColor *reticleDisplayColor = nil;
3667 if (reticleTargetSensitive && isTargeted)
3668 {
3669 reticleDisplayColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_TARGET_SENSITIVE];
3670 if (!reticleDisplayColor) reticleDisplayColor = [OOColor redColor];
3671 }
3672 else
3673 {
3674 reticleDisplayColor = [reticleColors objectAtIndex:OO_RETICLE_COLOR_TARGET];
3675 if (!reticleDisplayColor) reticleDisplayColor = [OOColor greenColor];
3676 }
3677 GLfloat reticleDisplayColorArray[4] = { [reticleDisplayColor redComponent],
3678 [reticleDisplayColor greenComponent],
3679 [reticleDisplayColor blueComponent],
3680 [reticleDisplayColor alphaComponent] };
3681 GLColorWithOverallAlpha(reticleDisplayColorArray, alpha);
3682 }
3683 }
3684 OOGLBEGIN(GL_LINES);
3685 glVertex2f(rs0,rs2); glVertex2f(rs0,rs0);
3686 glVertex2f(rs0,rs0); glVertex2f(rs2,rs0);
3687
3688 glVertex2f(rs0,-rs2); glVertex2f(rs0,-rs0);
3689 glVertex2f(rs0,-rs0); glVertex2f(rs2,-rs0);
3690
3691 glVertex2f(-rs0,rs2); glVertex2f(-rs0,rs0);
3692 glVertex2f(-rs0,rs0); glVertex2f(-rs2,rs0);
3693
3694 glVertex2f(-rs0,-rs2); glVertex2f(-rs0,-rs0);
3695 glVertex2f(-rs0,-rs0); glVertex2f(-rs2,-rs0);
3696 OOGLEND();
3697
3698 if (showText)
3699 {
3700 // add text for reticle here
3701 range *= 0.001f;
3702 if (range < 0.001f) range = 0.0f; // avoids the occasional -0.001 km distance.
3703 NSSize textsize = NSMakeSize(rdist * scale, rdist * scale);
3704 float line_height = rdist * scale;
3705 NSString* infoline = [NSString stringWithFormat:@"%0.3f km", range];
3706 if (legal_desc != nil) infoline = [NSString stringWithFormat:@"%@ (%@)", infoline, legal_desc];
3707 // no need to set colour here
3708 OODrawString([player1 dialTargetName], rs0, 0.5 * rs2, 0, textsize);
3709 OODrawString(infoline, rs0, 0.5 * rs2 - line_height, 0, textsize);
3710
3711 if ([target isWormhole])
3712 {
3713 // Note: No break statements in the following switch() since every case
3714 // falls through to the next. Cases arranged in reverse order.
3715 switch([(WormholeEntity *)target scanInfo])
3716 {
3717 case WH_SCANINFO_SHIP:
3718 // TOOD: Render anything on the HUD for this?
3720 // Rendered above in dialTargetName, so no need to do anything here
3721 // unless we want a separate line Destination: XXX ?
3723 {
3724 NSString *wormholeETA = [NSString stringWithFormat:DESC(@"wormhole-ETA-@"), ClockToString([(WormholeEntity *)target estimatedArrivalTime], NO)];
3725 OODrawString(wormholeETA, rs0, 0.5 * rs2 - 3 * line_height, 0, textsize);
3726 }
3728 {
3729 OOTimeDelta timeForCollapsing = [(WormholeEntity *)target expiryTime] - [player1 clockTimeAdjusted];
3730 int minutesToCollapse = floor (timeForCollapsing / 60.0);
3731 int secondsToCollapse = (int)timeForCollapsing % 60;
3732
3733 NSString *wormholeExpiringIn = [NSString stringWithFormat:DESC(@"wormhole-collapsing-in-mm:ss"), minutesToCollapse, secondsToCollapse];
3734 OODrawString(wormholeExpiringIn, rs0, 0.5 * rs2 - 2 * line_height, 0, textsize);
3735 }
3737 case WH_SCANINFO_NONE:
3738 break;
3739 }
3740 }
3741 }
3742
3744}
3745
3746
3747static void hudDrawWaypoint(OOWaypointEntity *waypoint, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL selected, GLfloat scale)
3748{
3749 if ([player1 guiScreen] != GUI_SCREEN_MAIN) // don't draw on text screens
3750 {
3751 return;
3752 }
3753
3754
3755 Vector p1 = HPVectorToVector(HPvector_subtract([waypoint position], [player1 viewpointPosition]));
3756
3759
3760 // either close enough that single precision is fine or far enough
3761 // away that precision is irrelevant
3762
3763 GLfloat rdist = magnitude(p1);
3764 GLfloat rsize = rdist * scale;
3765
3766 GLfloat rs0 = rsize;
3767 GLfloat rs2 = rsize * 0.50;
3768
3769 if (selected)
3770 {
3771 GLColorWithOverallAlpha(blue_color, alpha);
3772 }
3773 else
3774 {
3775 GLColorWithOverallAlpha(blue_color, alpha*0.25);
3776 }
3777
3778 OOGLBEGIN(GL_LINES);
3779 glVertex2f(rs0,rs2); glVertex2f(rs2,rs2);
3780 glVertex2f(rs2,rs0); glVertex2f(rs2,rs2);
3781
3782 glVertex2f(-rs0,rs2); glVertex2f(-rs2,rs2);
3783 glVertex2f(-rs2,rs0); glVertex2f(-rs2,rs2);
3784
3785 glVertex2f(-rs0,-rs2); glVertex2f(-rs2,-rs2);
3786 glVertex2f(-rs2,-rs0); glVertex2f(-rs2,-rs2);
3787
3788 glVertex2f(rs0,-rs2); glVertex2f(rs2,-rs2);
3789 glVertex2f(rs2,-rs0); glVertex2f(rs2,-rs2);
3790
3791// glVertex2f(0,-rs2); glVertex2f(0,rs2);
3792// glVertex2f(rs2,0); glVertex2f(-rs2,0);
3793 OOGLEND();
3794
3795 if (selected)
3796 {
3797 GLfloat range = HPdistance([player1 position],[waypoint position]) * 0.001f;
3798 if (range < 0.001f) range = 0.0f; // avoids the occasional -0.001 km distance.
3799 NSSize textsize = NSMakeSize(rdist * scale, rdist * scale);
3800 float line_height = rdist * scale;
3801 NSString* infoline = [NSString stringWithFormat:@"%0.3f km", range];
3802 OODrawString(infoline, rs0 * 0.5, -rs2 - line_height, 0, textsize);
3803 }
3804
3806}
3807
3808static void hudRotateViewpointForVirtualDepth(PlayerEntity * player1, Vector p1)
3809{
3810 Quaternion back_q = [player1 orientation];
3811 back_q.w = -back_q.w; // invert
3812 Vector v1 = vector_up_from_quaternion(back_q);
3813 NSSize viewSize = [[UNIVERSE gameView] viewSize];
3814 float aspect = viewSize.width / viewSize.height;
3815
3816 // The field of view transformation is really a scale operation on the view window.
3817 // We must unapply it through these transformations for them to be right.
3818 // We must also take into account the window aspect ratio.
3819 float ratio = 2 * [[UNIVERSE gameView] fov:YES]; // FIXME 2 is magic number; fov should integrate it
3820 if (3.0f * aspect >= 4.0f)
3821 {
3822 OOGLScaleModelView(make_vector(1/ratio, 1/ratio, 1.0f));
3823 }
3824 else
3825 {
3826 OOGLScaleModelView(make_vector((4.0f/3.0f)/(aspect*ratio), (4.0f/3.0f)/(aspect*ratio), 1.0f));
3827 }
3828
3829 // deal with view directions
3830 Vector view_dir, view_up = kBasisYVector;
3831 switch ([UNIVERSE viewDirection])
3832 {
3833 default:
3834 case VIEW_FORWARD:
3835 view_dir.x = 0.0; view_dir.y = 0.0; view_dir.z = 1.0;
3836 break;
3837
3838 case VIEW_AFT:
3839 view_dir.x = 0.0; view_dir.y = 0.0; view_dir.z = -1.0;
3840 quaternion_rotate_about_axis(&back_q, v1, M_PI);
3841 break;
3842
3843 case VIEW_PORT:
3844 view_dir.x = -1.0; view_dir.y = 0.0; view_dir.z = 0.0;
3845 quaternion_rotate_about_axis(&back_q, v1, 0.5 * M_PI);
3846 break;
3847
3848 case VIEW_STARBOARD:
3849 view_dir.x = 1.0; view_dir.y = 0.0; view_dir.z = 0.0;
3850 quaternion_rotate_about_axis(&back_q, v1, -0.5 * M_PI);
3851 break;
3852
3853 case VIEW_CUSTOM:
3854 view_dir = [player1 customViewForwardVector];
3855 view_up = [player1 customViewUpVector];
3856 back_q = quaternion_multiply([player1 customViewQuaternion], back_q);
3857 break;
3858 }
3859 OOGLLookAt(view_dir, kZeroVector, view_up);
3860
3861 // rotate the view
3862 OOGLMultModelView([player1 rotationMatrix]);
3863 // translate the view
3865 // rotate to face player1
3867
3868 // We come back now to the previous scale.
3869 OOGLScaleModelView(make_vector(ratio, ratio, 1.0f));
3870 // draw the waypoint
3871}
3872
3873
3874static void InitTextEngine(void)
3875{
3876 NSDictionary *fontSpec = nil;
3877 NSArray *widths = nil;
3878 NSString *texName = nil;
3879 NSUInteger i, count;
3880
3881 fontSpec = [ResourceManager dictionaryFromFilesNamed:@"oolite-font.plist"
3882 inFolder:@"Config"
3883 andMerge:NO];
3884
3885 texName = [fontSpec oo_stringForKey:@"texture" defaultValue:@"oolite-font.png"];
3887 inFolder:@"Textures"
3888 options:kFontTextureOptions
3889 anisotropy:0.0f
3890 lodBias:-0.75f];
3891 [sFontTexture retain];
3892
3893 sF6KernGovt = [fontSpec oo_floatForKey:@"f6KernGovernment" defaultValue:1.0];
3894 sF6KernTL = [fontSpec oo_floatForKey:@"f6KernTechLevel" defaultValue:2.0];
3895
3896 sEncodingCoverter = [[OOEncodingConverter alloc] initWithFontPList:fontSpec];
3897 widths = [fontSpec oo_arrayForKey:@"widths"];
3898 count = [widths count];
3899 if (count > 256) count = 256;
3900 for (i = 0; i != count; ++i)
3901 {
3902 sGlyphWidths[i] = [widths oo_floatAtIndex:i] * GLYPH_SCALE_FACTOR;
3903 }
3904}
3905
3906
3912
3913
3914static GLfloat drawCharacterQuad(uint8_t chr, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
3915{
3916 // 31 (narrow space) and 32 (space) are non-printing characters, so
3917 // don't print them, just return their width to move the pointer
3918 if (chr > 32 || chr < 31) {
3919 GLfloat texture_x = ONE_SIXTEENTH * (chr & 0x0f);
3920 GLfloat texture_y = ONE_SIXTEENTH * (chr >> 4);
3921 if (chr > 32) y += ONE_EIGHTH * siz.height; // Adjust for baseline offset change in 1.71 (needed to keep accented characters in box)
3922
3923 glTexCoord2f(texture_x, texture_y + ONE_SIXTEENTH);
3924 glVertex3f(x, y, z);
3925 glTexCoord2f(texture_x + ONE_SIXTEENTH, texture_y + ONE_SIXTEENTH);
3926 glVertex3f(x + siz.width, y, z);
3927 glTexCoord2f(texture_x + ONE_SIXTEENTH, texture_y);
3928 glVertex3f(x + siz.width, y + siz.height, z);
3929 glTexCoord2f(texture_x, texture_y);
3930 glVertex3f(x, y + siz.height, z);
3931 }
3932 return siz.width * sGlyphWidths[chr];
3933}
3934
3935
3936NSRect OORectFromString(NSString *text, GLfloat x, GLfloat y, NSSize siz)
3937{
3938 GLfloat w = 0;
3939 NSData *data = nil;
3940 const uint8_t *bytes = NULL;
3941 NSUInteger i, length;
3942
3943 data = [sEncodingCoverter convertString:text];
3944 bytes = [data bytes];
3945 length = [data length];
3946
3947 for (i = 0; i < length; i++)
3948 {
3949 w += siz.width * sGlyphWidths[bytes[i]];
3950 }
3951
3952 return NSMakeRect(x, y, w, siz.height);
3953}
3954
3955
3956CGFloat OOStringWidthInEm(NSString *text)
3957{
3958 return OORectFromString(text, 0, 0, NSMakeSize(1.0 / (GLYPH_SCALE_FACTOR * 8.0), 1.0)).size.width;
3959}
3960
3961
3962void drawHighlight(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat alpha)
3963{
3964 // Rounded corners, fading 'shadow' version
3965 OOGL(glColor4f(0.0f, 0.0f, 0.0f, alpha * 0.4f)); // dark translucent shadow
3966
3967 OOGLBEGIN(GL_POLYGON);
3968 // thin 'halo' around the 'solid' highlight
3969 glVertex3f(x + 1.0f , y + siz.height + 2.5f, z);
3970 glVertex3f(x + siz.width + 3.0f, y + siz.height + 2.5f, z);
3971 glVertex3f(x + siz.width + 4.5f, y + siz.height + 1.0f, z);
3972 glVertex3f(x + siz.width + 4.5f, y + 3.0f, z);
3973 glVertex3f(x + siz.width + 3.0f, y + 1.5f, z);
3974 glVertex3f(x + 1.0f, y + 1.5f, z);
3975 glVertex3f(x - 0.5f, y + 3.0f, z);
3976 glVertex3f(x - 0.5f, y + siz.height + 1.0f, z);
3977 OOGLEND();
3978
3979
3980 OOGLBEGIN(GL_POLYGON);
3981 glVertex3f(x + 1.0f, y + siz.height + 2.0f, z);
3982 glVertex3f(x + siz.width + 3.0f, y + siz.height + 2.0f, z);
3983 glVertex3f(x + siz.width + 4.0f, y + siz.height + 1.0f, z);
3984 glVertex3f(x + siz.width + 4.0f, y + 3.0f, z);
3985 glVertex3f(x + siz.width + 3.0f, y + 2.0f, z);
3986 glVertex3f(x + 1.0f, y + 2.0f, z);
3987 glVertex3f(x, y + 3.0f, z);
3988 glVertex3f(x, y + siz.height + 1.0f, z);
3989 OOGLEND();
3990}
3991
3992
3993void OODrawString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
3994{
3995 OODrawStringAligned(text,x,y,z,siz,NO);
3996}
3997
3998
3999void OODrawStringAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
4000{
4002 OODrawStringQuadsAligned(text,x,y,z,siz,rightAlign);
4004}
4005
4008
4009 OOGL(glEnable(GL_TEXTURE_2D));
4010 [sFontTexture apply];
4011 OOGLBEGIN(GL_QUADS);
4012
4013}
4014
4015void OODrawStringQuadsAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
4016{
4017 GLfloat cx = x;
4018 NSInteger i, length;
4019 NSData *data = nil;
4020 const uint8_t *bytes = NULL;
4021
4022 data = [sEncodingCoverter convertString:text];
4023 length = [data length];
4024 bytes = [data bytes];
4025
4026 if (EXPECT_NOT(rightAlign))
4027 {
4028 cx -= OORectFromString(text, 0.0f, 0.0f, siz).size.width;
4029 }
4030
4031 for (i = 0; i < length; i++)
4032 {
4033 cx += drawCharacterQuad(bytes[i], cx, y, z, siz);
4034 }
4035}
4036
4038 OOGLEND();
4039
4041 OOGL(glDisable(GL_TEXTURE_2D));
4042
4044}
4045
4046
4047void OODrawHilightedString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
4048{
4049 GLfloat color[4];
4050
4051 // get the physical dimensions of the string
4052 NSSize strsize = OORectFromString(text, 0.0f, 0.0f, siz).size;
4053 strsize.width += 0.5f;
4054
4056
4057 OOGL(glPushAttrib(GL_CURRENT_BIT)); // save the text colour
4058 OOGL(glGetFloatv(GL_CURRENT_COLOR, color)); // we need the original colour's alpha.
4059
4060 drawHighlight(x, y, z, strsize, color[3]);
4061
4062 OOGL(glPopAttrib()); //restore the colour
4063
4064 OODrawString(text, x, y, z, siz);
4065
4067}
4068
4069
4070void OODrawPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
4071{
4072 GLfloat govcol[] = { 0.5, 0.0, 0.7,
4073 0.7, 0.5, 0.3,
4074 0.0, 1.0, 0.3,
4075 1.0, 0.8, 0.1,
4076 1.0, 0.0, 0.0,
4077 0.1, 0.5, 1.0,
4078 0.7, 0.7, 0.7,
4079 0.7, 1.0, 1.0};
4080
4081 GLfloat cx = x;
4082 int tl = tec + 1;
4083 GLfloat ce1 = 1.0f - 0.125f * eco;
4084
4086
4087 OOGL(glEnable(GL_TEXTURE_2D));
4088 [sFontTexture apply];
4089
4090 OOGLBEGIN(GL_QUADS);
4091 {
4092 [[UNIVERSE gui] setGLColorFromSetting:[NSString stringWithFormat:kGuiChartEconomyUColor, (unsigned long)eco]
4093 defaultValue:[OOColor colorWithRed:ce1 green:1.0f blue:0.0f alpha:1.0f]
4094 alpha:1.0];
4095
4096 // see OODrawHilightedPlanetInfo
4097 cx += drawCharacterQuad(23 - eco, cx, y, z, siz); // characters 16..23 are economy symbols
4098 [[UNIVERSE gui] setGLColorFromSetting:[NSString stringWithFormat:kGuiChartGovernmentUColor, (unsigned long)gov]
4099 defaultValue:[OOColor colorWithRed:govcol[gov*3] green:govcol[1+(gov*3)] blue:govcol[2+(gov*3)] alpha:1.0f]
4100 alpha:1.0];
4101
4102 cx += drawCharacterQuad(gov, cx, y, z, siz) - sF6KernGovt; // charcters 0..7 are government symbols
4103 [[UNIVERSE gui] setGLColorFromSetting:kGuiChartTechColor
4104 defaultValue:[OOColor colorWithRed:0.5 green:1.0f blue:1.0f alpha:1.0f]
4105 alpha:1.0];
4106
4107 if (tl > 9)
4108 {
4109 // display TL clamped between 1..16, this must be a '1'!
4110 cx += drawCharacterQuad(49, cx, y - 2, z, siz) - sF6KernTL;
4111 }
4112 cx += drawCharacterQuad(48 + (tl % 10), cx, y - 2.0f, z, siz);
4113 }
4114 OOGLEND();
4115
4116 (void)cx; // Suppress "value not used" analyzer issue.
4117
4119 OOGL(glDisable(GL_TEXTURE_2D));
4120
4122}
4123
4124
4125void OODrawHilightedPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
4126{
4127 float color[4];
4128 int tl = tec + 1;
4129
4130 NSSize hisize;
4131
4132 // get the physical dimensions
4133 hisize.height = siz.height;
4134 hisize.width = 0.0f;
4135
4136 // see OODrawPlanetInfo
4137 hisize.width += siz.width * sGlyphWidths[23 - eco];
4138 hisize.width += siz.width * sGlyphWidths[gov] - 1.0;
4139 if (tl > 9) hisize.width += siz.width * sGlyphWidths[49] - 2.0;
4140 hisize.width += siz.width * sGlyphWidths[48 + (tl % 10)];
4141
4143
4144 OOGL(glPushAttrib(GL_CURRENT_BIT)); // save the text colour
4145 OOGL(glGetFloatv(GL_CURRENT_COLOR, color)); // we need the original colour's alpha.
4146
4147 drawHighlight(x, y - 2.0f, z, hisize, color[3]);
4148
4149 OOGL(glPopAttrib()); //restore the colour
4150
4151 OODrawPlanetInfo(gov, eco, tec, x, y, z, siz);
4152
4154}
4155
4156static void GLDrawNonlinearCascadeWeapon( GLfloat x, GLfloat y, GLfloat z, NSSize siz, Vector centre, GLfloat radius, GLfloat zoom, GLfloat alpha )
4157{
4158 Vector spacepos, scannerpos;
4159 GLfloat theta, phi;
4160 GLfloat z_factor = siz.height / siz.width; // approx 1/4
4161 GLfloat y_factor = 1.0 - sqrt(z_factor); // approx 1/2
4162 OOGLVector *points = malloc(sizeof(OOGLVector)*25);
4163 int i, j;
4164
4165 if (radius*radius > centre.y*centre.y)
4166 {
4167 GLfloat r0 = sqrt(radius*radius-centre.y*centre.y);
4168 OOGL(glColor4f(1.0, 0.5, 1.0, alpha));
4169 spacepos.y = 0;
4170 for (i = 0; i < 24; i++)
4171 {
4172 theta = i*2*M_PI/24;
4173 spacepos.x = centre.x + r0 * cos(theta);
4174 spacepos.z = centre.z + r0 * sin(theta);
4175 scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
4176 points[i].x = x + scannerpos.x;
4177 points[i].y = y + scannerpos.z * z_factor + scannerpos.y * y_factor;
4178 points[i].z = z;
4179 }
4180 spacepos.x = centre.x + r0;
4181 spacepos.y = 0;
4182 spacepos.z = centre.z;
4183 scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
4184 points[24].x = x + scannerpos.x;
4185 points[24].y = y + scannerpos.z * z_factor + scannerpos.y * y_factor;
4186 points[24].z = z;
4187 GLDrawPoints(points,25);
4188 }
4189 OOGL(glColor4f(0.5, 0.0, 1.0, 0.33333 * alpha));
4190 free(points);
4191 // Here, we draw a sphere distorted by the nonlinear function. We draw the sphere as a set of horizontal strips
4192 // The even indices of points are the points on the upper edge of the strip, while odd indices are points
4193 // on the bottom edge.
4194 points = malloc(sizeof(OOGLVector)*50);
4195 spacepos.x = centre.x;
4196 spacepos.y = centre.y + radius;
4197 spacepos.z = centre.z;
4198 scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
4199 for (i = 0; i <= 24; i++)
4200 {
4201 points[2*i+1].x = x + scannerpos.x;
4202 points[2*i+1].y = y + scannerpos.y * y_factor + scannerpos.z * z_factor;
4203 points[2*i+1].z = z;
4204 }
4205 for (i = 1; i <= 24; i++)
4206 {
4207 theta = i*M_PI/24;
4208 for (j = 0; j <= 24; j++)
4209 {
4210 phi = j*M_PI/12;
4211 // copy point from bottom edge of previous strip into top edge position
4212 points[2*j] = points[2*j+1];
4213
4214 spacepos.x = centre.x + radius * sin(theta) * cos(phi);
4215 spacepos.y = centre.y + radius * cos(theta);
4216 spacepos.z = centre.z + radius * sin(theta) * sin(phi);
4217 scannerpos = [HeadUpDisplay nonlinearScannerScale: spacepos Zoom: zoom Scale: 0.5*siz.width];
4218 points[2*j+1].x = x + scannerpos.x;
4219 points[2*j+1].y = y + scannerpos.y * y_factor + scannerpos.z * z_factor;
4220 points[2*j+1].z = z;
4221 }
4222 GLDrawQuadStrip(points, 50);
4223 }
4224 free(points);
4225 return;
4226}
4227
4228static GLfloat nonlinearScannerFunc( GLfloat distance, GLfloat zoom, GLfloat scale )
4229{
4230 GLfloat x = fabs(distance / SCANNER_MAX_RANGE);
4231 if (x >= 1.0)
4232 return scale;
4233 if (zoom <= 1.0)
4234 return scale * x;
4235 GLfloat c = 1 / ( zoom - 1 );
4236 GLfloat b = c * ( c + 1 );
4237 GLfloat a = c + 1;
4238 return scale * ( a - b / ( x + c ) );
4239}
4240
4241
4242static void drawScannerGrid(GLfloat x, GLfloat y, GLfloat z, NSSize siz, int v_dir, GLfloat thickness, GLfloat zoom, BOOL nonlinear, BOOL minimalistic)
4243{
4245
4246 MyOpenGLView* gameView = [UNIVERSE gameView];
4247
4248 GLfloat w1, h1;
4249 GLfloat ww = 0.5 * siz.width;
4250 GLfloat hh = 0.5 * siz.height;
4251
4252 GLfloat km_scan;
4253 GLfloat hdiv;
4254 GLfloat wdiv;
4255 BOOL drawdiv = NO, drawdiv1 = NO, drawdiv5 = NO;
4256
4257 int i, ii;
4258
4259 OOGL(GLScaledLineWidth(2.0 * thickness));
4260 GLDrawOval(x, y, z, siz, 4);
4261 OOGL(GLScaledLineWidth(thickness)); // reset (thickness = lineWidth)
4262
4263 OOGLBEGIN(GL_LINES);
4264 if (!minimalistic)
4265 {
4266 glVertex3f(x, y - hh, z); glVertex3f(x, y + hh, z);
4267 glVertex3f(x - ww, y, z); glVertex3f(x + ww, y, z);
4268
4269 if (nonlinear)
4270 {
4271 if (nonlinearScannerFunc(4000.0, zoom, hh)-nonlinearScannerFunc(3000.0, zoom ,hh) > 2) drawdiv1 = YES;
4272 if (nonlinearScannerFunc(10000.0, zoom, hh)-nonlinearScannerFunc(5000.0, zoom, hh) > 2) drawdiv5 = YES;
4273 wdiv = ww/(0.001*SCANNER_MAX_RANGE);
4274 for (i = 1; 1000.0*i < SCANNER_MAX_RANGE; i++)
4275 {
4276 drawdiv = drawdiv1;
4277 w1 = wdiv;
4278 if (i % 10 == 0)
4279 {
4280 w1 = wdiv*4;
4281 drawdiv = YES;
4282 if (nonlinearScannerFunc((i+5)*1000,zoom,hh) - nonlinearScannerFunc(i*1000.0,zoom,hh)>2)
4283 {
4284 drawdiv5 = YES;
4285 }
4286 else
4287 {
4288 drawdiv5 = NO;
4289 }
4290 }
4291 else if (i % 5 == 0)
4292 {
4293 w1 = wdiv*2;
4294 drawdiv = drawdiv5;
4295 if (nonlinearScannerFunc((i+1)*1000,zoom,hh) - nonlinearScannerFunc(i*1000.0,zoom,hh)>2)
4296 {
4297 drawdiv1 = YES;
4298 }
4299 else
4300 {
4301 drawdiv1 = NO;
4302 }
4303 }
4304 if (drawdiv)
4305 {
4306 h1 = nonlinearScannerFunc(i*1000.0,zoom,hh);
4307 glVertex3f(x - w1, y + h1, z); glVertex3f(x + w1, y + h1, z);
4308 glVertex3f(x - w1, y - h1, z); glVertex3f(x + w1, y - h1, z);
4309 }
4310 }
4311 }
4312 else
4313 {
4314 km_scan = 0.001 * SCANNER_MAX_RANGE / zoom; // calculate kilometer divisions
4315 hdiv = 0.5 * siz.height / km_scan;
4316 wdiv = 0.25 * siz.width / km_scan;
4317 if (wdiv < 4.0)
4318 {
4319 wdiv *= 2.0;
4320 ii = 5;
4321 }
4322 else
4323 {
4324 ii = 1;
4325 }
4326
4327 for (i = ii; 2.0 * hdiv * i < siz.height; i += ii)
4328 {
4329 h1 = i * hdiv;
4330 w1 = wdiv;
4331 if (i % 5 == 0)
4332 w1 = w1 * 2.5;
4333 if (i % 10 == 0)
4334 w1 = w1 * 2.0;
4335 if (w1 > 3.5) // don't draw tiny marks
4336 {
4337 glVertex3f(x - w1, y + h1, z); glVertex3f(x + w1, y + h1, z);
4338 glVertex3f(x - w1, y - h1, z); glVertex3f(x + w1, y - h1, z);
4339 }
4340 }
4341 }
4342 }
4343
4344 double tanfov = [gameView fov:YES];
4345 GLfloat aspect = [gameView viewSize].width / [gameView viewSize].height;
4346 if (aspect < 4.0/3.0)
4347 {
4348 tanfov *= 0.75 * aspect;
4349 }
4350 double cosfov = 1.0/sqrt(1+tanfov*tanfov);
4351 double sinfov = tanfov * cosfov;
4352
4353 switch (v_dir)
4354 {
4355 case VIEW_BREAK_PATTERN:
4356 case VIEW_GUI_DISPLAY:
4357 case VIEW_FORWARD:
4358 case VIEW_NONE:
4359 glVertex3f(x, y, z); glVertex3f(x - ww * sinfov, y + hh * cosfov, z);
4360 glVertex3f(x, y, z); glVertex3f(x + ww * sinfov, y + hh * cosfov, z);
4361 break;
4362
4363 case VIEW_AFT:
4364 glVertex3f(x, y, z); glVertex3f(x - ww * sinfov, y - hh * cosfov, z);
4365 glVertex3f(x, y, z); glVertex3f(x + ww * sinfov, y - hh * cosfov, z);
4366 break;
4367
4368 case VIEW_PORT:
4369 glVertex3f(x, y, z); glVertex3f(x - ww * cosfov, y + hh * sinfov, z);
4370 glVertex3f(x, y, z); glVertex3f(x - ww * cosfov, y - hh * sinfov, z);
4371 break;
4372
4373 case VIEW_STARBOARD:
4374 glVertex3f(x, y, z); glVertex3f(x + ww * cosfov, y + hh * sinfov, z);
4375 glVertex3f(x, y, z); glVertex3f(x + ww * cosfov, y - hh * sinfov, z);
4376 break;
4377 }
4378 OOGLEND();
4379
4381}
4382
4383
4384static void DrawSpecialOval(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat step, GLfloat *color4v)
4385{
4386 GLfloat ww = 0.5 * siz.width;
4387 GLfloat hh = 0.5 * siz.height;
4388 GLfloat theta;
4389 GLfloat delta;
4390 GLfloat s;
4391
4392 delta = step * M_PI / 180.0f;
4393
4394 OOGLBEGIN(GL_LINE_LOOP);
4395 for (theta = 0.0f; theta < (2.0f * M_PI); theta += delta)
4396 {
4397 s = sin(theta);
4398 glColor4f(color4v[0], color4v[1], color4v[2], fabs(s * color4v[3]));
4399 glVertex3f(x + ww * s, y + hh * cos(theta), z);
4400 }
4401 OOGLEND();
4402}
4403
4404
4405- (void) setLineWidth:(GLfloat) value
4406{
4407 lineWidth = value;
4408}
4409
4410
4411- (GLfloat) lineWidth
4412{
4413 return lineWidth;
4414}
4415
4416@end
4417
4418
4419@implementation NSString (OODisplayEncoding)
4420
4421- (const char *) cStringUsingOoliteEncoding
4422{
4423 if (sEncodingCoverter == nil) InitTextEngine();
4424
4425 // Note: the data will be autoreleased, so the bytes behave as though they're autoreleased too.
4426 return [[self dataUsingEncoding:[sEncodingCoverter encoding] allowLossyConversion:YES] bytes];
4427}
4428
4429
4430- (const char *) cStringUsingOoliteEncodingAndRemapping
4431{
4432 if (sEncodingCoverter == nil) InitTextEngine();
4433
4434 // Note: the data will be autoreleased, so the bytes behave as though they're autoreleased too.
4435 return [[sEncodingCoverter convertString:self] bytes];
4436}
4437
4438@end
4439
4440
4441@implementation OOPolygonSprite (OOHUDBeaconIcon)
4442
4443- (void) oo_drawHUDBeaconIconAt:(NSPoint)where size:(NSSize)size alpha:(GLfloat)alpha z:(GLfloat)z
4444{
4445 GLfloat x = where.x - size.width;
4446 GLfloat y = where.y - 1.5 * size.height;
4447
4448 GLfloat ox = x - size.width * 0.5;
4449 GLfloat oy = y - size.height * 0.5;
4450 GLfloat width = size.width * (1.0f / 6.0f);
4451 GLfloat height = size.height * (1.0f / 6.0f);
4452
4454 OOGLTranslateModelView(make_vector(ox, oy, z));
4455 OOGLScaleModelView(make_vector(width, height, 1.0f));
4456 [self drawFilled];
4457 glColor4f(0.0, 0.0, 0.0, 0.5 * alpha);
4458 [self drawOutline];
4460}
4461
4462@end
4463
4464
4465@implementation NSString (OOHUDBeaconIcon)
4466
4467- (void) oo_drawHUDBeaconIconAt:(NSPoint)where size:(NSSize)size alpha:(GLfloat)alpha z:(GLfloat)z
4468{
4469 OODrawString(self, where.x - 2.5 * size.width, where.y - 3.0 * size.height, z, NSMakeSize(size.width * 2, size.height * 2));
4470}
4471
4472@end
4473
4474
4475static void SetGLColourFromInfo(NSDictionary *info, NSString *key, const GLfloat defaultColor[4], GLfloat alpha)
4476{
4477 id colorDesc = nil;
4478 OOColor *color = nil;
4479 colorDesc = [info objectForKey:key];
4480 if (colorDesc != nil)
4481 {
4482 color = [OOColor colorWithDescription:colorDesc];
4483 if (color != nil)
4484 {
4485 GLfloat ioColor[4];
4486 [color getRed:&ioColor[0] green:&ioColor[1] blue:&ioColor[2] alpha:&ioColor[3]];
4487 GLColorWithOverallAlpha(ioColor,alpha);
4488 return;
4489 }
4490 }
4491 GLColorWithOverallAlpha(defaultColor,alpha);
4492}
4493
4494
4495static void GetRGBAArrayFromInfo(NSDictionary *info, GLfloat ioColor[4])
4496{
4497 id colorDesc = nil;
4498 OOColor *color = nil;
4499
4500 // First, look for general colour specifier.
4501 colorDesc = [info objectForKey:RGB_COLOR_KEY];
4502 if (colorDesc != nil && ![info objectForKey:ALPHA_KEY])
4503 {
4504 color = [OOColor colorWithDescription:colorDesc];
4505 if (color != nil)
4506 {
4507 [color getRed:&ioColor[0] green:&ioColor[1] blue:&ioColor[2] alpha:&ioColor[3]];
4508 return;
4509 }
4510 }
4511
4512 // Failing that, look for rgb_color and alpha.
4513 colorDesc = [info oo_arrayForKey:RGB_COLOR_KEY];
4514 if (colorDesc != nil && [colorDesc count] == 3)
4515 {
4516 ioColor[0] = [colorDesc oo_nonNegativeFloatAtIndex:0];
4517 ioColor[1] = [colorDesc oo_nonNegativeFloatAtIndex:1];
4518 ioColor[2] = [colorDesc oo_nonNegativeFloatAtIndex:2];
4519 }
4520 ioColor[3] = [info oo_nonNegativeFloatForKey:ALPHA_KEY defaultValue:ioColor[3]];
4521}
#define SCANNER_MAX_RANGE
Definition Entity.h:51
#define SCANNER_MAX_RANGE2
Definition Entity.h:52
#define ZOOM_INDICATOR_HEIGHT
#define SELECTOR_KEY
#define ROW_HEIGHT_KEY
#define CABIN_TEMP_BAR_HEIGHT
#define AFT_SHIELD_BAR_HEIGHT
#define HEIGHT_KEY
#define FPSINFO_DISPLAY_Y
#define SCOOPSTATUS_HEIGHT
#define CABIN_TEMP_BAR_CENTRE_Y
#define FPSINFO_DISPLAY_WIDTH
#define SCANNER_WIDTH
#define MISSILE_ICON_WIDTH
#define ASCTARGET_DISPLAY_WIDTH
#define STATUS_LIGHT_CENTRE_X
#define ALTITUDE_BAR_CENTRE_X
#define MFD_TEXT_WIDTH
#define SPEED_BAR_CENTRE_Y
#define SCANNER_CENTRE_Y
void OODrawStringAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
#define WIDTH_KEY
#define ZOOM_INDICATOR_WIDTH
#define PITCH_BAR_CENTRE_Y
#define SCOOPSTATUS_CENTRE_X
#define ASCTARGET_DISPLAY_HEIGHT
#define ROLL_BAR_CENTRE_Y
#define WEAPON_TEMP_BAR_HEIGHT
#define AEGIS_CENTRE_Y
#define X_KEY
#define SCOOPSTATUS_WIDTH
#define ALTITUDE_BAR_WIDTH
#define SCANNER_ZOOM_LEVELS
#define CABIN_TEMP_BAR_WIDTH
#define CLOCK_DISPLAY_WIDTH
#define WEAPONSOFFLINETEXT_WIDTH
#define FORWARD_SHIELD_BAR_HEIGHT
#define WEAPON_TEMP_BAR_WIDTH
#define WITCHDEST_WIDTH
void OOHUDResetTextEngine(void)
#define WITCHDEST_HEIGHT
#define SPEED_BAR_WIDTH
#define FORWARD_SHIELD_BAR_WIDTH
void OODrawStringQuadsAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
#define AFT_SHIELD_BAR_CENTRE_Y
#define FORWARD_SHIELD_BAR_CENTRE_Y
#define ROLL_BAR_WIDTH
#define CLOCK_DISPLAY_Y
#define PRIMED_DISPLAY_WIDTH
#define WEAPONSOFFLINETEXT_DISPLAY_X
#define WEAPONSOFFLINETEXT_HEIGHT
void OOStartDrawingStrings(void)
#define FPSINFO_DISPLAY_HEIGHT
#define TITLE_KEY
#define CABIN_TEMP_BAR_CENTRE_X
#define CUSTOM_DIAL_KEY
#define ROLL_BAR_HEIGHT
#define TEXT_KEY
#define MISSILES_DISPLAY_Y
#define FUEL_BAR_CENTRE_Y
#define AEGIS_CENTRE_X
#define FUEL_BAR_CENTRE_X
#define WEAPON_TEMP_BAR_CENTRE_X
#define ONE_EIGHTH
#define PRIMED_DISPLAY_X
NSRect OORectFromString(NSString *text, GLfloat x, GLfloat y, NSSize siz)
#define AEGIS_WIDTH
#define ZOOM_INDICATOR_CENTRE_X
#define AFT_SHIELD_BAR_WIDTH
#define CLOCK_DISPLAY_X
#define PITCH_BAR_CENTRE_X
#define ALTITUDE_BAR_HEIGHT
#define ACCURACY_PROBABILITY_DECREASE_FACTOR
#define COMPASS_CENTRE_Y
#define ASCTARGET_DISPLAY_X
#define ENERGY_GAUGE_CENTRE_X
#define FUEL_BAR_HEIGHT
#define SPEED_BAR_HEIGHT
#define MISSILES_DISPLAY_X
#define MIN_PROBABILITY_ACCURACY
#define WEAPONSOFFLINETEXT_DISPLAY_Y
#define FORWARD_SHIELD_BAR_CENTRE_X
#define ROLL_BAR_CENTRE_X
#define DIAL_REQUIRED_KEY
void OODrawString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
#define WEAPON_TEMP_BAR_CENTRE_Y
#define AFT_SHIELD_BAR_CENTRE_X
void OODrawPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
#define CLOCK_DISPLAY_HEIGHT
#define PRIMED_DISPLAY_HEIGHT
#define FPSINFO_DISPLAY_X
#define ENERGY_GAUGE_HEIGHT
#define BACKGROUND_RGBA_KEY
#define WITCHDEST_CENTRE_X
#define COMPASS_CENTRE_X
#define SCANNER_CENTRE_X
#define ENERGY_GAUGE_WIDTH
void OOStopDrawingStrings(void)
#define PRIMED_DISPLAY_Y
#define MAX_ACCURACY_RANGE
#define ALTITUDE_BAR_CENTRE_Y
#define SCANNER_SCALE
#define COMPASS_HALF_SIZE
#define WITCHDEST_CENTRE_Y
#define ASCTARGET_DISPLAY_Y
#define MISSILE_ICON_HEIGHT
#define AEGIS_HEIGHT
#define SCANNER_HEIGHT
#define PITCH_BAR_HEIGHT
#define STATUS_LIGHT_CENTRE_Y
#define ALPHA_KEY
#define STATUS_LIGHT_HEIGHT
#define SCOOPSTATUS_CENTRE_Y
#define Y_KEY
#define ENERGY_GAUGE_CENTRE_Y
#define FUEL_BAR_WIDTH
#define PITCH_BAR_WIDTH
@ OO_RETICLE_COLOR_TARGET
@ OO_RETICLE_COLOR_WORMHOLE
#define ZOOM_INDICATOR_CENTRE_Y
#define MFD_TEXT_HEIGHT
#define SPEED_BAR_CENTRE_X
static void hudRotateViewpointForVirtualDepth(PlayerEntity *player1, Vector p1)
static void hudDrawStatusIconAt(int x, int y, int z, NSSize siz)
#define SET_COLOR_CRITICAL(d)
static float sF6KernGovt
static void hudDrawWaypoint(OOWaypointEntity *waypoint, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL selected, GLfloat scale)
static const GLfloat redplus_color[4]
#define ONE_SIXTEENTH
#define SET_COLOR_LOW(d)
#define SET_COLOR_MEDIUM(d)
static NSString *const kDefaultMissileIconKey
static NSString *const kDefaultMineIconKey
static float sGlyphWidths[256]
static OOEncodingConverter * sEncodingCoverter
#define NOT_DEFINED
#define WIDGET_SELECTOR_NAME
static OOTexture * sFontTexture
static void SetGLColourFromInfo(NSDictionary *info, NSString *key, const GLfloat defaultColor[4], GLfloat alpha)
static void DrawSpecialOval(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat step, GLfloat *color4v)
static const GLfloat green_color[4]
static GLfloat nonlinearScannerFunc(GLfloat distance, GLfloat zoom, GLfloat scale)
static const GLfloat darkgreen_color[4]
static void hudDrawSurroundAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz)
static void GLDrawNonlinearCascadeWeapon(GLfloat x, GLfloat y, GLfloat z, NSSize siz, Vector centre, GLfloat radius, GLfloat zoom, GLfloat alpha)
static void hudDrawReticleOnTarget(Entity *target, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL reticleTargetSensitive, NSMutableDictionary *propertiesReticleTargetSensitive, BOOL colourFromScannerColour, BOOL showText, NSDictionary *info, NSMutableArray *reticleColors)
static NSArray * sCurrentDrawItem
static float sF6KernTL
static const GLfloat lightgray_color[4]
static BOOL _compassUpdated
static const GLfloat black_color[4]
#define SET_COLOR_HIGH(d)
static void hudDrawIndicatorAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
static const GLfloat blue_color[4]
static const GLfloat yellow_color[4]
#define SET_COLOR_SURROUND(d)
static void hudDrawMarkerAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
#define GLYPH_SCALE_FACTOR
#define SET_COLOR(d)
@ kFontTextureOptions
static const GLfloat red_color[4]
static void GetRGBAArrayFromInfo(NSDictionary *info, GLfloat ioColor[4])
static void drawScannerGrid(GLfloat x, GLfloat y, GLfloat z, NSSize siz, int v_dir, GLfloat thickness, GLfloat zoom, BOOL nonlinear, BOOL minimalistic)
OOINLINE float useDefined(float val, float validVal)
static void hudDrawBarAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
static const GLfloat kOutlineWidth
#define DESTROY(x)
Definition OOCocoa.h:77
#define EXPECT_NOT(x)
#define OOINLINE
#define OOLogERR(class, format,...)
Definition OOLogging.h:112
NSString *const kOOLogFileNotFound
Definition OOLogging.m:652
GLfloat OOScalar
Definition OOMaths.h:64
#define M_PI
Definition OOMaths.h:73
Vector OOVectorMultiplyMatrix(Vector v, OOMatrix m)
Definition OOMatrix.m:129
OOMatrix OOMatrixForQuaternionRotation(Quaternion orientation)
Definition OOMatrix.m:65
void OOGLLookAt(Vector eye, Vector center, Vector up)
void OOGLScaleModelView(Vector scale)
void OOGLPushModelView(void)
void OOGLTranslateModelView(Vector vector)
void OOGLMultModelView(OOMatrix matrix)
OOMatrix OOGLPopModelView(void)
#define OOGLBEGIN
Definition OOOpenGL.h:253
void GLDrawFilledOval(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat step)
Definition OOOpenGL.m:165
@ OPENGL_STATE_OVERLAY
Definition OOOpenGL.h:126
void GLDrawPoints(OOGLVector *points, int n)
Definition OOOpenGL.m:174
void GLDrawQuadStrip(OOGLVector *points, int n)
Definition OOOpenGL.m:203
#define OOVerifyOpenGLState()
Definition OOOpenGL.h:136
BOOL OOCheckOpenGLErrors(NSString *format,...)
Definition OOOpenGL.m:39
void GLScaledLineWidth(GLfloat width)
Definition OOOpenGL.m:218
void GLDrawOval(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat step)
Definition OOOpenGL.m:155
#define OOSetOpenGLState(STATE)
Definition OOOpenGL.h:135
#define OOGL(statement)
Definition OOOpenGL.h:251
#define OOGLEND
Definition OOOpenGL.h:254
unsigned count
return nil
Vector vector_up_from_quaternion(Quaternion quat)
void quaternion_rotate_about_axis(Quaternion *quat, Vector axis, OOScalar angle)
Quaternion quaternion_multiply(Quaternion q1, Quaternion q2)
float y
float x
#define OOExpandKey(key,...)
@ OO_SYSTEMCONCEALMENT_NONAME
@ kOOTextureNoShrink
Definition OOTexture.h:53
@ kOOTextureMinFilterMipMap
Definition OOTexture.h:48
@ kOOTextureAlphaMask
Definition OOTexture.h:60
@ kOOTextureMagFilterLinear
Definition OOTexture.h:51
@ AEGIS_IN_DOCKING_RANGE
Definition OOTypes.h:64
OOViewID
Definition OOTypes.h:43
double OOTimeDelta
Definition OOTypes.h:224
@ NO_TARGET
Definition OOTypes.h:194
const Vector kZeroVector
Definition OOVector.m:28
const Vector kBasisYVector
Definition OOVector.m:30
const Vector kBasisZVector
Definition OOVector.m:31
const Vector kBasisXVector
Definition OOVector.m:29
Vector OOVectorRandomRadial(OOScalar maxLength)
Definition OOVector.m:115
@ SCOOP_STATUS_FULL_HOLD
@ SCOOP_STATUS_NOT_INSTALLED
@ SCOOP_STATUS_ACTIVE
@ SCOOP_STATUS_OKAY
#define PLAYER
OOMissileStatus
@ MISSILE_STATUS_TARGET_LOCKED
@ MISSILE_STATUS_ARMED
@ MISSILE_STATUS_SAFE
#define PLAYER_TARGET_MEMORY_SIZE
OOAlertCondition
Definition ShipEntity.h:172
@ ALERT_CONDITION_GREEN
Definition ShipEntity.h:176
@ ALERT_CONDITION_RED
Definition ShipEntity.h:178
@ ALERT_CONDITION_YELLOW
Definition ShipEntity.h:177
@ ALERT_CONDITION_DOCKED
Definition ShipEntity.h:175
NSString * OOStringFromWeaponType(OOWeaponType weapon) CONST_FUNC
#define UNIVERSE
Definition Universe.h:840
#define DESC(key)
Definition Universe.h:846
@ OO_POSTFX_NONE
Definition Universe.h:90
#define CROSSHAIR_SIZE
Definition Universe.h:60
@ WH_SCANINFO_NONE
@ WH_SCANINFO_SCANNED
@ WH_SCANINFO_SHIP
@ WH_SCANINFO_ARRIVAL_TIME
@ WH_SCANINFO_DESTINATION
@ WH_SCANINFO_COLLAPSE_TIME
GLfloat collision_radius
Definition Entity.h:111
OOUniversalID universalID
Definition Entity.h:89
Quaternion orientation
Definition Entity.h:114
GLfloat zero_distance
Definition Entity.h:108
unsigned isShip
Definition Entity.h:91
GLfloat collisionRadius()
Definition Entity.m:905
OOScanClass scanClass
Definition Entity.h:106
unsigned isWormhole
Definition Entity.h:94
void setTextColor:(OOColor *color)
void resizeTo:characterHeight:title:(NSSize gui_size,[characterHeight] int csize,[title] NSString *gui_title)
void setMaxAlpha:(GLfloat an_alpha)
void setDrawPosition:(Vector vector)
void setCharacterSize:(NSSize character_size)
NSArray * getLastLines()
NSString * title
void setBackgroundColor:(OOColor *color)
void printLongText:align:color:fadeTime:key:addToArray:(NSString *str,[align] OOGUIAlignment alignment,[color] OOColor *text_color,[fadeTime] float text_fade,[key] NSString *text_key,[addToArray] NSMutableArray *text_array)
void setTextCommsColor:(OOColor *color)
void setAlpha:(GLfloat an_alpha)
void setCurrentRow:(OOGUIRow value)
unsigned rowHeight()
Vector nonlinearScannerScale:Zoom:Scale:(Vector V,[Zoom] GLfloat zoom,[Scale] double scale)
static void hudDrawIndicatorAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
static void hudDrawStatusIconAt(int x, int y, int z, NSSize siz)
void OOStopDrawingStrings()
void OODrawHilightedPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
static void hudRotateViewpointForVirtualDepth(PlayerEntity *player1, Vector p1)
void OODrawStringQuadsAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
static GLfloat nonlinearScannerFunc(GLfloat distance, GLfloat zoom, GLfloat scale)
static void hudDrawBarAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
static void hudDrawSurroundAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz)
NSRect OORectFromString(NSString *text, GLfloat x, GLfloat y, NSSize siz)
static void drawScannerGrid(GLfloat x, GLfloat y, GLfloat z, NSSize siz, int v_dir, GLfloat thickness, GLfloat zoom, BOOL nonlinear, BOOL minimalistic)
void OODrawStringAligned(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz, BOOL rightAlign)
void OOStartDrawingStrings()
static void GLDrawNonlinearCascadeWeapon(GLfloat x, GLfloat y, GLfloat z, NSSize siz, Vector centre, GLfloat radius, GLfloat zoom, GLfloat alpha)
void OODrawHilightedString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
void drawHighlight(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat alpha)
static void hudDrawMarkerAt(GLfloat x, GLfloat y, GLfloat z, NSSize siz, GLfloat amount)
CGFloat OOStringWidthInEm(NSString *text)
static void hudDrawReticleOnTarget(Entity *target, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL reticleTargetSensitive, NSMutableDictionary *propertiesReticleTargetSensitive, BOOL colourFromScannerColour, BOOL showText, NSDictionary *info, NSMutableArray *reticleColors)
void OODrawString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
static void hudDrawWaypoint(OOWaypointEntity *waypoint, PlayerEntity *player1, GLfloat z1, GLfloat alpha, BOOL selected, GLfloat scale)
void OODrawPlanetInfo(int gov, int eco, int tec, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
float fov:(BOOL inFraction)
OOColor * cyanColor()
Definition OOColor.m:286
OOColor * colorWithRed:green:blue:alpha:(float red,[green] float green,[blue] float blue,[alpha] float alpha)
Definition OOColor.m:95
float alphaComponent()
Definition OOColor.m:486
OOColor * colorFromString:(NSString *colorFloatString)
Definition OOColor.m:214
float blueComponent()
Definition OOColor.m:362
OOColor * colorWithDescription:(id description)
Definition OOColor.m:127
OOColor * redColor()
Definition OOColor.m:268
OOColor * greenColor()
Definition OOColor.m:274
void getRed:green:blue:alpha:(float *red,[green] float *green,[blue] float *blue,[alpha] float *alpha)
Definition OOColor.m:368
OOColor * whiteColor()
Definition OOColor.m:256
float redComponent()
Definition OOColor.m:350
OOColor * yellowColor()
Definition OOColor.m:292
float greenComponent()
Definition OOColor.m:356
NSStringEncoding encoding()
NSData * convertString:(NSString *string)
void blitCentredToX:Y:Z:alpha:(float x,[Y] float y,[Z] float z,[alpha] float a)
void apply()
Definition OOTexture.m:269
NSSize dimensions()
Definition OOTexture.m:306
void applyNone()
Definition OOTexture.m:275
id textureWithName:inFolder:options:anisotropy:lodBias:(NSString *name,[inFolder] NSString *directory,[options] OOTextureFlags options,[anisotropy] GLfloat anisotropy,[lodBias] GLfloat lodBias)
Definition OOTexture.m:134
void drawTrumble:(double z)
Definition OOTrumble.m:371
NSMutableArray * targetMemory()
GLfloat dialMaxEnergy()
Vector customViewUpVector
Vector customViewForwardVector
double clockTimeAdjusted()
NSDictionary * whitelistDictionary()
NSDictionary * dictionaryFromFilesNamed:inFolder:andMerge:(NSString *fileName,[inFolder] NSString *folderName,[andMerge] BOOL mergeFiles)
Vector v_forward
Definition ShipEntity.h:200
OOColor * scannerDisplayColor2()
BoundingBox totalBoundingBox
Definition ShipEntity.h:213
Vector v_up
Definition ShipEntity.h:200
NSString * scanDescription()
OOColor * scannerDisplayColorHostile2()
OOColor * scannerDisplayColorHostile1()
BOOL hasHostileTarget()
void setMessageTime:(double value)
OOColor * scannerDisplayColor1()
Vector v_right
Definition ShipEntity.h:200
voidpf void uLong size
Definition ioapi.h:134
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
GLfloat y
Definition OOOpenGL.h:205
GLfloat x
Definition OOOpenGL.h:204
GLfloat z
Definition OOOpenGL.h:206