diff --git a/src/doomdef.h b/src/doomdef.h index 633879ea..88db49ff 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -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 diff --git a/src/i_video.c b/src/i_video.c index 3acc3e56..cabfaf93 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -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()); } diff --git a/src/i_video.h b/src/i_video.h index f1293977..360caf97 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -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; diff --git a/src/m_menu.c b/src/m_menu.c index 31e5988c..5c4141af 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -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, diff --git a/src/m_misc.c b/src/m_misc.c index 4bf30017..626edd65 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -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 diff --git a/src/p_mobj.h b/src/p_mobj.h index 7dd27dcb..9095b1fa 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -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); diff --git a/src/p_user.c b/src/p_user.c index 06e9c889..d28a0754 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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); } diff --git a/src/r_data.h b/src/r_data.h index 556c872b..682fb2d7 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -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. diff --git a/src/r_main.c b/src/r_main.c index bea763b5..20abada8 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -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,11 +252,10 @@ 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 // after the view angle. @@ -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 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<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]; diff --git a/src/r_main.h b/src/r_main.h index 6a127223..2c6dddf3 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -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 diff --git a/src/r_plane.c b/src/r_plane.c index c79245da..b57906af 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -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); } diff --git a/src/v_video.c b/src/v_video.c index 929311da..b6c4b5d4 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -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];