Add adjustable FOV (#1364)

* Add adjustable FOV

* Always use custom FOV when non-zero

* Fix pixels at edge of screen for 32:9 aspect ratio

* Remove in-game aspect ratio selection for now

* Revert "Fix pixels at edge of screen for 32:9 aspect ratio"

This reverts commit ab1df333f610f4097bca0256694b3c99f69eb9de.
This commit is contained in:
ceski 2024-01-03 23:13:36 -08:00 committed by GitHub
parent f67fb0784e
commit e3dd725b4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 115 additions and 42 deletions

View File

@ -80,6 +80,7 @@ typedef enum
#define SCREENWIDTH 320
#define SCREENHEIGHT 200
#define NONWIDEWIDTH SCREENWIDTH // [crispy] non-widescreen SCREENWIDTH
#define ACTUALHEIGHT 240
// The maximum number of players, multiplayer/networking.
#define MAXPLAYERS 4

View File

@ -44,8 +44,6 @@
#include "icon.c"
#define ACTUALHEIGHT 240
resolution_mode_t resolution_mode, default_resolution_mode;
boolean use_vsync; // killough 2/8/98: controls whether vsync is called
@ -55,6 +53,7 @@ int fpslimit; // when uncapped, limit framerate to this value
boolean fullscreen;
boolean exclusive_fullscreen;
aspect_ratio_mode_t widescreen, default_widescreen; // widescreen mode
int custom_fov;
boolean vga_porch_flash; // emulate VGA "porch" behaviour
boolean smooth_scaling;
@ -989,7 +988,7 @@ static double CurrentAspectRatio(void)
w = SCREENWIDTH;
h = unscaled_actualheight;
break;
case RATIO_MATCH_SCREEN:
case RATIO_AUTO:
w = native_width;
h = native_height;
break;
@ -1005,6 +1004,10 @@ static double CurrentAspectRatio(void)
w = 21;
h = 9;
break;
case RATIO_32_9:
w = 32;
h = 9;
break;
default:
w = 16;
h = 9;
@ -1013,14 +1016,51 @@ static double CurrentAspectRatio(void)
double aspect_ratio = (double)w / (double)h;
if (aspect_ratio > 2.4)
if (aspect_ratio > ASPECT_RATIO_MAX)
{
aspect_ratio = 2.4;
aspect_ratio = ASPECT_RATIO_MAX;
}
return aspect_ratio;
}
// Fineangles in the SCREENWIDTH wide window.
#define FIELDOFVIEW 2048
void I_UpdateFOV(void)
{
if (custom_fov)
{
const double slope = tan(custom_fov * M_PI / 360);
const double dist = (CurrentAspectRatio() * ACTUALHEIGHT / 2) / slope;
video.fov = custom_fov * ANG1;
pov_slope = slope * FRACUNIT;
pov_distance = dist * FRACUNIT;
lookdirmax = lround(dist * 100 / 160);
}
else
{
if (widescreen == RATIO_ORIG)
{
video.fov = ANG90;
pov_slope = finetangent[FINEANGLES / 4 + FIELDOFVIEW / 2];
}
else
{
const double slope = CurrentAspectRatio() * 3 / 4;
video.fov = 2 * atan(slope) / M_PI * ANG180;
pov_slope = slope * FRACUNIT;
}
pov_distance = (SCREENWIDTH / 2) << FRACBITS;
lookdirmax = 100;
}
lookdirs = 2 * lookdirmax + 1;
}
static void ResetResolution(int height)
{
double aspect_ratio = CurrentAspectRatio();
@ -1044,7 +1084,7 @@ static void ResetResolution(int height)
video.deltaw = (video.unscaledw - NONWIDEWIDTH) / 2;
video.fov = 2 * atan(video.unscaledw / (1.2 * SCREENHEIGHT) * 3 / 4) / M_PI * ANG180;
I_UpdateFOV();
Z_FreeTag(PU_VALLOC);
@ -1495,7 +1535,7 @@ static void CreateSurfaces(void)
SDL_TEXTUREACCESS_STREAMING,
w, h);
widescreen = RATIO_MATCH_SCREEN;
widescreen = RATIO_AUTO;
ResetResolution(h);
R_InitAnyRes();
@ -1503,7 +1543,7 @@ static void CreateSurfaces(void)
widescreen = default_widescreen;
if (resolution_mode != RES_DRS || widescreen != RATIO_MATCH_SCREEN)
if (resolution_mode != RES_DRS || widescreen != RATIO_AUTO)
{
ResetResolution(CurrentResolutionMode());
}

View File

@ -24,13 +24,18 @@
#include "doomtype.h"
#define FOVMIN 40
#define FOVMAX 140 // Up to 32:9 ultrawide.
#define ASPECT_RATIO_MAX 3.6 // Up to 32:9 ultrawide.
typedef enum
{
RATIO_ORIG,
RATIO_MATCH_SCREEN,
RATIO_AUTO,
RATIO_16_10,
RATIO_16_9,
RATIO_21_9,
RATIO_32_9,
NUM_RATIOS
} aspect_ratio_mode_t;
@ -61,6 +66,7 @@ void I_FinishUpdate(void);
void I_ReadScreen(byte* dst);
void I_UpdateFOV(void);
void I_ResetScreen(void); // killough 10/98
void I_ResetTargetRefresh(void);
void I_ToggleVsync(void); // [JN] Calls native SDL vsync toggle
@ -82,6 +88,7 @@ extern int fpslimit; // when uncapped, limit framerate to this value
extern int fps;
extern boolean vga_porch_flash; // emulate VGA "porch" behaviour
extern aspect_ratio_mode_t widescreen, default_widescreen; // widescreen mode
extern int custom_fov; // Custom FOV set by the player.
extern int video_display; // display index
extern boolean screenvisible;
extern boolean window_focused;

View File

@ -3638,6 +3638,7 @@ enum {
gen1_title1,
gen1_hires,
gen1_widescreen,
gen1_fov,
gen1_gap1,
gen1_fullscreen,
@ -3777,6 +3778,17 @@ static void M_CoerceFPSLimit(void)
I_ResetTargetRefresh();
}
static void M_UpdateFOV(void)
{
if (custom_fov < FOVMIN)
{
custom_fov = 0;
}
I_UpdateFOV();
R_ExecuteSetViewSize();
}
static void M_ResetScreen(void)
{
need_reset = true;
@ -3792,6 +3804,9 @@ setup_menu_t gen_settings1[] = { // General Settings screen1
{"Widescreen Rendering", S_YESNO, m_null, M_X, M_Y+ gen1_widescreen*M_SPC,
{"widescreen"}, 0, M_ResetScreen},
{"FOV", S_NUM, m_null, M_X, M_Y + gen1_fov*M_SPC,
{"fov"}, 0, M_UpdateFOV},
{"", S_SKIP, m_null, M_X, M_Y + gen1_gap1*M_SPC},
{"Fullscreen Mode", S_YESNO, m_null, M_X, M_Y+ gen1_fullscreen*M_SPC,

View File

@ -205,8 +205,15 @@ default_t defaults[] = {
{
"widescreen",
(config_t *) &default_widescreen, NULL,
{RATIO_MATCH_SCREEN}, {RATIO_ORIG, NUM_RATIOS-1}, number, ss_none, wad_no,
"widescreen mode (0 = disable, 1 = match screen, 2 = 16:10, 3 = 16:9, 4 = 21:9)"
{RATIO_AUTO}, {RATIO_ORIG, NUM_RATIOS-1}, number, ss_none, wad_no,
"Widescreen (0 = Off, 1 = Auto, 2 = 16:10, 3 = 16:9, 4 = 21:9, 5 = 32:9)"
},
{
"fov",
(config_t *) &custom_fov, NULL,
{0}, {0, FOVMAX}, number, ss_none, wad_no,
"Field of view in degrees (0 = Auto, 40 to 140 = Custom)"
},
// display index

View File

@ -425,7 +425,7 @@ extern boolean colored_blood;
// Heretic/Hexen used value `173` presumably because Raven assumed an
// equilateral triangle (i.e. 60°) for the vertical FOV which spans
// 200 px, so the height of that triangle would be 100*sqrt(3) = 173.
#define PLAYER_SLOPE(a) ((((a)->lookdir / MLOOKUNIT) << FRACBITS) / 160)
#define PLAYER_SLOPE(a) (FixedDiv(((a)->lookdir << FRACBITS) / MLOOKUNIT, pov_distance))
extern boolean direct_vertical_aiming, default_direct_vertical_aiming;
void P_UpdateDirectVerticalAiming(void);

View File

@ -238,8 +238,8 @@ void P_MovePlayer (player_t* player)
if (!menuactive && !demoplayback)
{
player->lookdir = BETWEEN(-LOOKDIRMAX * MLOOKUNIT,
LOOKDIRMAX * MLOOKUNIT,
player->lookdir = BETWEEN(-lookdirmax * MLOOKUNIT,
lookdirmax * MLOOKUNIT,
player->lookdir + cmd->lookdir);
player->slope = PLAYER_SLOPE(player);
}

View File

@ -24,8 +24,9 @@
#include "r_defs.h"
#include "r_state.h"
#define LOOKDIRMAX 100
#define LOOKDIRS (2*LOOKDIRMAX+1) // [crispy] lookdir range: -100..100
// Largest range at FOV 40, AR 3.6 (742 = (3.6*240/2)/tan(40*M_PI/360)*100/160).
#define LOOKDIRSMAX (2 * 742 + 1)
#define MLOOKUNIT 8
// Retrieve column data for span blitting.

View File

@ -32,9 +32,6 @@
#include "am_map.h"
#include "st_stuff.h"
// Fineangles in the SCREENWIDTH wide window.
#define FIELDOFVIEW 2048
// killough: viewangleoffset is a legacy from the pre-v1.2 days, when Doom
// had Left/Mid/Right viewing. +/-ANG90 offsets were placed here on each
// node, by d_net.c, to set up a L/M/R session.
@ -53,6 +50,10 @@ fixed_t viewcos, viewsin;
player_t *viewplayer;
extern lighttable_t **walllights;
fixed_t viewheightfrac; // [FG] sprite clipping optimizations
fixed_t pov_slope;
fixed_t pov_distance;
int lookdirmax;
int lookdirs;
//
// precalculated math tables
@ -251,10 +252,9 @@ static fixed_t centerxfrac_nonwide;
//
// killough 5/2/98: reformatted
static void R_InitTextureMapping (void)
static void R_InitTextureMapping(fixed_t focallength)
{
register int i,x;
fixed_t focallength;
// Use tangent table to generate viewangletox:
// viewangletox will give the next greatest x
@ -263,15 +263,13 @@ static void R_InitTextureMapping (void)
// Calc focallength
// so FIELDOFVIEW angles covers SCREENWIDTH.
focallength = FixedDiv(centerxfrac_nonwide, finetangent[FINEANGLES/4+FIELDOFVIEW/2]);
for (i=0 ; i<FINEANGLES/2 ; i++)
{
int t;
if (finetangent[i] > FRACUNIT*2)
if (finetangent[i] > pov_slope)
t = -1;
else
if (finetangent[i] < -FRACUNIT*2)
if (finetangent[i] < -pov_slope)
t = viewwidth+1;
else
{
@ -502,12 +500,12 @@ void R_ExecuteSetViewSize (void)
centerxfrac = centerx<<FRACBITS;
centeryfrac = centery<<FRACBITS;
centerxfrac_nonwide = (viewwidth_nonwide/2)<<FRACBITS;
projection = centerxfrac_nonwide;
projection = FixedDiv(centerxfrac, pov_slope);
viewheightfrac = viewheight<<(FRACBITS+1); // [FG] sprite clipping optimizations
R_InitBuffer(); // killough 11/98
R_InitTextureMapping();
R_InitTextureMapping(projection);
// psprite scales
pspritescale = FixedDiv(viewwidth_nonwide, SCREENWIDTH); // killough 11/98
@ -520,14 +518,14 @@ void R_ExecuteSetViewSize (void)
// planes
for (i=0 ; i<viewheight ; i++)
{ // killough 5/2/98: reformatted
for (j = 0; j < LOOKDIRS; j++)
for (j = 0; j < lookdirs; j++)
{
// [crispy] re-generate lookup-table for yslope[] whenever "viewheight" or "hires" change
fixed_t dy = abs(((i-viewheight/2-(j-LOOKDIRMAX)*viewblocks/10)<<FRACBITS)+FRACUNIT/2);
yslopes[j][i] = FixedDiv(viewwidth_nonwide*(FRACUNIT/2), dy);
fixed_t dy = abs(((i-viewheight/2-(j-lookdirmax)*viewblocks/10)<<FRACBITS)+FRACUNIT/2);
yslopes[j][i] = FixedDiv(projection, dy);
}
}
yslope = yslopes[LOOKDIRMAX];
yslope = yslopes[lookdirmax];
for (i=0 ; i<viewwidth ; i++)
{
@ -699,10 +697,10 @@ void R_SetupFrame (player_t *player)
extralight = player->extralight;
extralight += STRICTMODE(LIGHTBRIGHT * extra_level_brightness);
if (pitch > LOOKDIRMAX)
pitch = LOOKDIRMAX;
else if (pitch < -LOOKDIRMAX)
pitch = -LOOKDIRMAX;
if (pitch > lookdirmax)
pitch = lookdirmax;
else if (pitch < -lookdirmax)
pitch = -lookdirmax;
// apply new yslope[] whenever "lookdir", "viewheight" or "hires" change
tempCentery = viewheight/2 + pitch * viewblocks / 10;
@ -710,7 +708,7 @@ void R_SetupFrame (player_t *player)
{
centery = tempCentery;
centeryfrac = centery << FRACBITS;
yslope = yslopes[LOOKDIRMAX + pitch];
yslope = yslopes[lookdirmax + pitch];
}
viewsin = finesine[viewangle>>ANGLETOFINESHIFT];

View File

@ -40,6 +40,10 @@ extern int validcount;
extern int linecount;
extern int loopcount;
extern fixed_t viewheightfrac; // [FG] sprite clipping optimizations
extern fixed_t pov_slope; // For calculating projection.
extern fixed_t pov_distance; // Distance from POV to projection plane.
extern int lookdirmax;
extern int lookdirs;
//
// Rendering stats

View File

@ -119,7 +119,7 @@ void R_InitPlanesRes(void)
if (yslopes)
{
for (i = 0; i < LOOKDIRS; ++i)
for (i = 0; i < LOOKDIRSMAX; ++i)
{
Z_Free(yslopes[i]);
}
@ -136,8 +136,8 @@ void R_InitPlanesRes(void)
cachedxstep = Z_Calloc(1, video.height * sizeof(*cachedxstep), PU_STATIC, NULL);
cachedystep = Z_Calloc(1, video.height * sizeof(*cachedystep), PU_STATIC, NULL);
yslopes = Z_Malloc(LOOKDIRS * sizeof(*yslopes), PU_STATIC, NULL);
for (i = 0; i < LOOKDIRS; ++i)
yslopes = Z_Malloc(LOOKDIRSMAX * sizeof(*yslopes), PU_STATIC, NULL);
for (i = 0; i < LOOKDIRSMAX; ++i)
{
yslopes[i] = Z_Calloc(1, video.height * sizeof(**yslopes), PU_STATIC, NULL);
}

View File

@ -284,7 +284,7 @@ void WriteGeneratedLumpWad(const char *filename)
video_t video;
#define WIDE_SCREENWIDTH 576 // corresponds to 2.4 aspect ratio
#define WIDE_SCREENWIDTH 864 // corresponds to 3.6 aspect ratio
static int x1lookup[WIDE_SCREENWIDTH + 1];
static int y1lookup[SCREENHEIGHT + 1];