diff --git a/src/Cocoa/MyOpenGLView.h b/src/Cocoa/MyOpenGLView.h index f2befb25a..374caa8fe 100644 --- a/src/Cocoa/MyOpenGLView.h +++ b/src/Cocoa/MyOpenGLView.h @@ -35,8 +35,8 @@ MA 02110-1301, USA. #define MIN_FOV_DEG 30.0f #define MAX_FOV_DEG 80.0f -#define MIN_FOV (tan((MIN_FOV_DEG / 2) * M_PI / 180.0f)) -#define MAX_FOV (tan((MAX_FOV_DEG / 2) * M_PI / 180.0f)) +#define MIN_FOV (2 * tan((MIN_FOV_DEG / 2) * M_PI / 180.0f)) +#define MAX_FOV (2 * tan((MAX_FOV_DEG / 2) * M_PI / 180.0f)) #define NUM_KEYS 320 #define MOUSE_DOUBLE_CLICK_INTERVAL 0.40 diff --git a/src/Cocoa/MyOpenGLView.m b/src/Cocoa/MyOpenGLView.m index e0b10dcda..5bf5fb725 100644 --- a/src/Cocoa/MyOpenGLView.m +++ b/src/Cocoa/MyOpenGLView.m @@ -1236,13 +1236,13 @@ - (float) gammaValue - (void) setFov:(float)value fromFraction:(BOOL)fromFraction { - _fov = fromFraction ? value : tan((value / 2) * M_PI / 180); + _fov = fromFraction ? value : 2 * tan((value / 2) * M_PI / 180); } - (float) fov:(BOOL)inFraction { - return inFraction ? _fov : 2 * atan(_fov) * 180 / M_PI; + return inFraction ? _fov : 2 * atan(_fov / 2) * 180 / M_PI; } @end diff --git a/src/Core/Entities/PlayerEntity.h b/src/Core/Entities/PlayerEntity.h index c10e3bcc7..95f907411 100644 --- a/src/Core/Entities/PlayerEntity.h +++ b/src/Core/Entities/PlayerEntity.h @@ -721,8 +721,6 @@ typedef enum StickProfileScreen *stickProfileScreen; - double maxFieldOfView; - double fieldOfView; #if OO_FOV_INFLIGHT_CONTROL_ENABLED double fov_delta; #endif @@ -1161,6 +1159,9 @@ typedef enum */ - (GLfloat) insideAtmosphereFraction; +- (void) viewFov:(float)fovMultiplier; +- (float) viewFov; + @end diff --git a/src/Core/Entities/PlayerEntity.m b/src/Core/Entities/PlayerEntity.m index c1d32271a..f406e7943 100644 --- a/src/Core/Entities/PlayerEntity.m +++ b/src/Core/Entities/PlayerEntity.m @@ -1582,7 +1582,6 @@ - (void) deferredInit NSAssert(gOOPlayer == self, @"Expected only one PlayerEntity to exist at a time."); NSAssert([super initWithKey:PLAYER_SHIP_DESC definition:[NSDictionary dictionary]] == self, @"PlayerEntity requires -[ShipEntity initWithKey:definition:] to return unmodified self."); - maxFieldOfView = MAX_FOV; #if OO_FOV_INFLIGHT_CONTROL_ENABLED fov_delta = 2.0; // multiply by 2 each second #endif @@ -1625,7 +1624,6 @@ - (BOOL) setUpAndConfirmOK:(BOOL)stopOnError - (BOOL) setUpAndConfirmOK:(BOOL)stopOnError saveGame:(BOOL)saveGame { - fieldOfView = [[UNIVERSE gameView] fov:YES]; unsigned i; showDemoShips = NO; @@ -2838,8 +2836,6 @@ - (void) doBookkeeping:(double) delta_t [hud setScannerZoom:z1]; } - [[UNIVERSE gameView] setFov:fieldOfView fromFraction:YES]; - // scanner sanity check - lose any targets further than maximum scanner range ShipEntity *primeTarget = [self primaryTarget]; if (primeTarget && HPdistance2([primeTarget position], [self position]) > SCANNER_MAX_RANGE2 && !autopilot_engaged) @@ -8270,7 +8266,7 @@ - (void) setGuiToGameOptionsScreen #endif // field of view control - float fov = [gameView fov:NO]; + float fov = [[NSUserDefaults standardUserDefaults] floatForKey:@"fov-value"]; int fovTicks = (int)((fov - MIN_FOV_DEG) * 20 / (MAX_FOV_DEG - MIN_FOV_DEG)); NSString* fovWordDesc = DESC(@"gameoptions-fov-value"); [gui setText:[NSString stringWithFormat:@"%@%@ (%d%c) ", fovWordDesc, SliderString(fovTicks), (int)fov, 176 /*176 is the degrees symbol Unicode code point*/] forRow:GUI_ROW(GAME,FOV) align:GUI_ALIGN_CENTER]; @@ -12428,6 +12424,20 @@ - (BOOL) suppressClangStuff } #endif +- (void) viewFov:(float)fovMultiplier +{ + float gameOptionsFovInDegrees = [[NSUserDefaults standardUserDefaults] floatForKey:@"fov-value"]; + float gameOptionsFovInFraction = (2 * tan(gameOptionsFovInDegrees / 2 * M_PI / 180)); + [[UNIVERSE gameView] setFov:gameOptionsFovInFraction*fovMultiplier fromFraction:YES]; +} + +- (float) viewFov +{ + float gameOptionsFovInDegrees = [[NSUserDefaults standardUserDefaults] floatForKey:@"fov-value"]; + float gameOptionsFovInFraction = (2 * tan(gameOptionsFovInDegrees / 2 * M_PI / 180)); + return [[UNIVERSE gameView] fov:YES] / gameOptionsFovInFraction; +} + @end diff --git a/src/Core/Entities/PlayerEntityControls.m b/src/Core/Entities/PlayerEntityControls.m index 314e17df2..587f2ad85 100644 --- a/src/Core/Entities/PlayerEntityControls.m +++ b/src/Core/Entities/PlayerEntityControls.m @@ -1408,32 +1408,36 @@ - (void) pollFlightControls:(double)delta_t // Field of view controls if (![UNIVERSE displayGUI]) { - if (([gameView isDown:key_inc_field_of_view] || joyButtonState[BUTTON_INC_FIELD_OF_VIEW]) && (fieldOfView < MAX_FOV)) + float fov = [gameView fov:YES]; + if (([gameView isDown:key_inc_field_of_view] || joyButtonState[BUTTON_INC_FIELD_OF_VIEW]) && (fov < MAX_FOV)) { - fieldOfView *= pow(fov_delta, delta_t); - if (fieldOfView > MAX_FOV) fieldOfView = MAX_FOV; + fov *= pow(fov_delta, delta_t); + if (fov > MAX_FOV) fov = MAX_FOV; + [gameView setFov:(fov) fromFraction:YES]; } - if (([gameView isDown:key_dec_field_of_view] || joyButtonState[BUTTON_DEC_FIELD_OF_VIEW]) && (fieldOfView > MIN_FOV)) + if (([gameView isDown:key_dec_field_of_view] || joyButtonState[BUTTON_DEC_FIELD_OF_VIEW]) && (fov > MIN_FOV)) { - fieldOfView /= pow(fov_delta, delta_t); - if (fieldOfView < MIN_FOV) fieldOfView = MIN_FOV; + fov /= pow(fov_delta, delta_t); + if (fov < MIN_FOV) fov = MIN_FOV; + [gameView setFov:(fov) fromFraction:YES]; } NSDictionary *functionForFovAxis = [[stickHandler axisFunctions] oo_dictionaryForKey:[[NSNumber numberWithInt:AXIS_FIELD_OF_VIEW] stringValue]]; if ([stickHandler joystickCount] != 0 && functionForFovAxis != nil) { - // TODO think reqFov through double reqFov = [stickHandler getAxisState: AXIS_FIELD_OF_VIEW]; - if (fieldOfView < maxFieldOfView * reqFov) + if (fov < MAX_FOV * reqFov) { - fieldOfView *= pow(fov_delta, delta_t); - if (fieldOfView > MAX_FOV) fieldOfView = MAX_FOV; + fov *= pow(fov_delta, delta_t); + if (fov > MAX_FOV) fov = MAX_FOV; + [gameView setFov:(fov) fromFraction:YES]; } - if (fieldOfView > maxFieldOfView * reqFov) + if (fov > MAX_FOV * reqFov) { - fieldOfView /= pow(fov_delta, delta_t); - if (fieldOfView < MIN_FOV) fieldOfView = MIN_FOV; + fov /= pow(fov_delta, delta_t); + if (fov < MIN_FOV) fov = MIN_FOV; + [gameView setFov:(fov) fromFraction:YES]; } } } @@ -3146,22 +3150,21 @@ sets the actual screen resolution (controller just stores { BOOL rightKeyDown = [gameView isDown:key_gui_arrow_right]; BOOL leftKeyDown = [gameView isDown:key_gui_arrow_left]; - float fov = [gameView fov:NO]; + float fov = [[NSUserDefaults standardUserDefaults] floatForKey:@"fov-value"]; float fovStep = (MAX_FOV_DEG - MIN_FOV_DEG) / 20.0f; fov += (((rightKeyDown && (fov < MAX_FOV_DEG)) ? fovStep : 0.0f) - ((leftKeyDown && (fov > MIN_FOV_DEG)) ? fovStep : 0.0f)); if (fov > MAX_FOV_DEG) fov = MAX_FOV_DEG; if (fov < MIN_FOV_DEG) fov = MIN_FOV_DEG; [gameView setFov:fov fromFraction:NO]; - fieldOfView = [gameView fov:YES]; int fovTicks = (int)((fov - MIN_FOV_DEG) / fovStep); NSString* fovWordDesc = DESC(@"gameoptions-fov-value"); NSString* v1_string = @"|||||||||||||||||||||||||"; NSString* v0_string = @"........................."; v1_string = [v1_string substringToIndex:fovTicks]; v0_string = [v0_string substringToIndex:20 - fovTicks]; - [gui setText:[NSString stringWithFormat:@"%@%@%@ (%d%c) ", fovWordDesc, v1_string, v0_string, (int)fov, 176 /*176 is the degrees symbol ASCII code*/] forRow:GUI_ROW(GAME,FOV) align:GUI_ALIGN_CENTER]; - [[NSUserDefaults standardUserDefaults] setFloat:[gameView fov:NO] forKey:@"fov-value"]; + [gui setText:[NSString stringWithFormat:@"%@%@%@ (%d%c) ", fovWordDesc, v1_string, v0_string, (int)fov, 176 /*176 is the degrees symbol ASCII code*/] forRow:GUI_ROW(GAME,FOV) align:GUI_ALIGN_CENTER]; + [[NSUserDefaults standardUserDefaults] setFloat:fov forKey:@"fov-value"]; timeLastKeyPress = script_time; } fovControlPressed = YES; diff --git a/src/Core/HeadUpDisplay.m b/src/Core/HeadUpDisplay.m index e18b0b4a8..a60c5b0b1 100644 --- a/src/Core/HeadUpDisplay.m +++ b/src/Core/HeadUpDisplay.m @@ -3431,7 +3431,7 @@ static void hudDrawReticleOnTarget(Entity *target, PlayerEntity *player1, GLfloa p1 = HPVectorToVector(HPvector_subtract([target position], [player1 viewpointPosition])); GLfloat rdist = magnitude(p1); - GLfloat rsize = [target collisionRadius] / (2 * [[UNIVERSE gameView] fov:YES]); // FIXME integrate 2 into fov to remove magic number + GLfloat rsize = [target collisionRadius] / [[UNIVERSE gameView] fov:YES]; if (rsize < rdist * scale) rsize = rdist * scale; @@ -3670,7 +3670,7 @@ static void hudRotateViewpointForVirtualDepth(PlayerEntity * player1, Vector p1) // The field of view transformation is really a scale operation on the view window. // We must unapply it through these transformations for them to be right. // We must also take into account the window aspect ratio. - float ratio = 2 * [[UNIVERSE gameView] fov:YES]; // FIXME 2 is magic number; fov should integrate it + float ratio = [[UNIVERSE gameView] fov:YES]; if (3.0f * aspect >= 4.0f) { OOGLScaleModelView(make_vector(1/ratio, 1/ratio, 1.0f)); diff --git a/src/Core/Scripting/OOJSPlayerShip.m b/src/Core/Scripting/OOJSPlayerShip.m index 01ff90284..704c70d8a 100644 --- a/src/Core/Scripting/OOJSPlayerShip.m +++ b/src/Core/Scripting/OOJSPlayerShip.m @@ -147,6 +147,7 @@ kPlayerShip_viewPositionForward, // view position offset, vector, read-only kPlayerShip_viewPositionPort, // view position offset, vector, read-only kPlayerShip_viewPositionStarboard, // view position offset, vector, read-only + kPlayerShip_viewFov, // view fov as a multiplier of game options fov, positive float, read/write kPlayerShip_weaponsOnline, // weapons online status, boolean, read-only kPlayerShip_yaw, // yaw (overrules Ship) }; @@ -203,6 +204,7 @@ { "viewPositionForward", kPlayerShip_viewPositionForward, OOJS_PROP_READONLY_CB }, { "viewPositionPort", kPlayerShip_viewPositionPort, OOJS_PROP_READONLY_CB }, { "viewPositionStarboard", kPlayerShip_viewPositionStarboard, OOJS_PROP_READONLY_CB }, + { "viewFov", kPlayerShip_viewFov, OOJS_PROP_READWRITE_CB }, { "weaponsOnline", kPlayerShip_weaponsOnline, OOJS_PROP_READONLY_CB }, { "yaw", kPlayerShip_yaw, OOJS_PROP_READONLY_CB }, { 0 } @@ -489,6 +491,9 @@ static JSBool PlayerShipGetProperty(JSContext *context, JSObject *this, jsid pro case kPlayerShip_viewPositionStarboard: return VectorToJSValue(context, [player viewpointOffsetStarboard], value); + case kPlayerShip_viewFov: + return JS_NewNumberValue(context, [player viewFov], value); + case kPlayerShip_currentWeapon: result = [player weaponTypeForFacing:[player currentWeaponFacing] strict:NO]; break; @@ -729,7 +734,15 @@ static JSBool PlayerShipSetProperty(JSContext *context, JSObject *this, jsid pro [player adjustTradeInFactorBy:(newLevel-[player tradeInFactor])]; return YES; } - + + case kPlayerShip_viewFov: + if (JS_ValueToNumber(context, *value, &fValue)) + { + [player viewFov:fValue]; + return YES; + } + break; + case kPlayerShip_currentWeapon: { BOOL exists = NO; diff --git a/src/Core/Universe.m b/src/Core/Universe.m index 802c8d1d3..38fcd2b8b 100644 --- a/src/Core/Universe.m +++ b/src/Core/Universe.m @@ -4048,7 +4048,8 @@ - (NSDictionary *) gameSettings [result oo_setFloat:[gameView gammaValue] forKey:@"gammaValue"]; #endif - [result oo_setFloat:[gameView fov:NO] forKey:@"fovValue"]; + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + [result oo_setFloat:[prefs oo_floatForKey:@"fov-value" defaultValue:57.2f] forKey:@"fovValue"]; [result setObject:OOStringFromGraphicsDetail([self detailLevel]) forKey:@"detailLevel"]; @@ -4410,16 +4411,16 @@ - (void) drawUniverse { float nearPlane = vdist ? 1.0 : INTERMEDIATE_CLEAR_DEPTH; float farPlane = vdist ? INTERMEDIATE_CLEAR_DEPTH : MAX_CLEAR_DEPTH; - float ratio = (displayGUI ? 0.5 : [gameView fov:YES]) * nearPlane; // 0.5 is field of view ratio for GUIs + float ratio = (displayGUI ? 1.0 : [gameView fov:YES]) * nearPlane; // 1.0 is field of view ratio for GUIs OOGLResetProjection(); if ((displayGUI && 4*aspect >= 3) || (!displayGUI && 4*aspect <= 3)) { - OOGLFrustum(-ratio, ratio, -aspect*ratio, aspect*ratio, nearPlane, farPlane); + OOGLFrustum(-ratio/2, ratio/2, -aspect*ratio/2, aspect*ratio/2, nearPlane, farPlane); } else { - OOGLFrustum(-3*ratio/aspect/4, 3*ratio/aspect/4, -3*ratio/4, 3*ratio/4, nearPlane, farPlane); + OOGLFrustum(-3*ratio/aspect/8, 3*ratio/aspect/8, -3*ratio/8, 3*ratio/8, nearPlane, farPlane); } [self getActiveViewMatrix:&view_matrix forwardVector:&view_dir upVector:&view_up]; diff --git a/src/SDL/MyOpenGLView.h b/src/SDL/MyOpenGLView.h index 21b026cae..9c284df6e 100644 --- a/src/SDL/MyOpenGLView.h +++ b/src/SDL/MyOpenGLView.h @@ -32,8 +32,8 @@ MA 02110-1301, USA. #define MIN_FOV_DEG 30.0f #define MAX_FOV_DEG 80.0f -#define MIN_FOV (tan((MIN_FOV_DEG / 2) * M_PI / 180.0f)) -#define MAX_FOV (tan((MAX_FOV_DEG / 2) * M_PI / 180.0f)) +#define MIN_FOV (2 * tan((MIN_FOV_DEG / 2) * M_PI / 180.0f)) +#define MAX_FOV (2 * tan((MAX_FOV_DEG / 2) * M_PI / 180.0f)) #define MOUSEVIRTUALSTICKSENSITIVITYFACTOR 0.95f #define MOUSEX_MAXIMUM 0.6 diff --git a/src/SDL/MyOpenGLView.m b/src/SDL/MyOpenGLView.m index fb77ccfa7..ebe016e2a 100644 --- a/src/SDL/MyOpenGLView.m +++ b/src/SDL/MyOpenGLView.m @@ -2323,13 +2323,13 @@ - (float) gammaValue - (void) setFov:(float)value fromFraction:(BOOL)fromFraction { - _fov = fromFraction ? value : tan((value / 2) * M_PI / 180); + _fov = fromFraction ? value : 2 * tan((value / 2) * M_PI / 180); } - (float) fov:(BOOL)inFraction { - return inFraction ? _fov : 2 * atan(_fov) * 180 / M_PI; + return inFraction ? _fov : 2 * atan(_fov / 2) * 180 / M_PI; }