Skip to content

Commit

Permalink
output: fix clipping sprites
Browse files Browse the repository at this point in the history
Resolves #1870. Reworks the viewport module to ensure all window sizing
game variables stay in sync.
  • Loading branch information
rr- committed Nov 11, 2024
1 parent 47e66d8 commit d8f2a09
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 86 deletions.
24 changes: 12 additions & 12 deletions src/tr2/game/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,10 @@ void __cdecl Output_Init(

void __cdecl Output_InsertPolygons(const int16_t *obj_ptr, const int32_t clip)
{
g_FltWinLeft = g_PhdWinMinX + g_PhdWinLeft;
g_FltWinTop = g_PhdWinMinY + g_PhdWinTop;
g_FltWinRight = g_PhdWinRight + g_PhdWinMinX + 1;
g_FltWinBottom = g_PhdWinBottom + g_PhdWinMinY + 1;
g_FltWinLeft = g_PhdWinMinX;
g_FltWinTop = g_PhdWinMinY;
g_FltWinRight = g_PhdWinMinX + g_PhdWinMaxX + 1;
g_FltWinBottom = g_PhdWinMinY + g_PhdWinMaxY + 1;
g_FltWinCenterX = g_PhdWinMinX + g_PhdWinCenterX;
g_FltWinCenterY = g_PhdWinMinY + g_PhdWinCenterY;

Expand All @@ -433,8 +433,8 @@ void __cdecl Output_InsertRoom(const int16_t *obj_ptr, int32_t is_outside)
{
g_FltWinLeft = g_PhdWinMinX + g_PhdWinLeft;
g_FltWinTop = g_PhdWinMinY + g_PhdWinTop;
g_FltWinRight = g_PhdWinRight + g_PhdWinMinX + 1;
g_FltWinBottom = g_PhdWinBottom + g_PhdWinMinY + 1;
g_FltWinRight = g_PhdWinMinX + g_PhdWinRight + 1;
g_FltWinBottom = g_PhdWinMinY + g_PhdWinBottom + 1;
g_FltWinCenterX = g_PhdWinMinX + g_PhdWinCenterX;
g_FltWinCenterY = g_PhdWinMinY + g_PhdWinCenterY;

Expand Down Expand Up @@ -465,8 +465,8 @@ void __cdecl Output_InsertSkybox(const int16_t *obj_ptr)
{
g_FltWinLeft = g_PhdWinMinX + g_PhdWinLeft;
g_FltWinTop = g_PhdWinMinY + g_PhdWinTop;
g_FltWinRight = g_PhdWinRight + g_PhdWinMinX + 1;
g_FltWinBottom = g_PhdWinBottom + g_PhdWinMinY + 1;
g_FltWinRight = g_PhdWinMinX + g_PhdWinRight + 1;
g_FltWinBottom = g_PhdWinMinY + g_PhdWinBottom + 1;
g_FltWinCenterX = g_PhdWinMinX + g_PhdWinCenterX;
g_FltWinCenterY = g_PhdWinMinY + g_PhdWinCenterY;

Expand Down Expand Up @@ -3228,7 +3228,7 @@ void __cdecl Output_InsertFlatRect_ZBuffered(

CLAMPL(x1, g_PhdWinMinX);
CLAMPL(y1, g_PhdWinMinY);
CLAMPG(x2, g_PhdWinWidth + g_PhdWinMinX);
CLAMPG(x2, g_PhdWinMinX + g_PhdWinWidth);
CLAMPG(y2, g_PhdWinMinY + g_PhdWinHeight);
CLAMP(z, g_PhdNearZ, g_PhdFarZ);

Expand Down Expand Up @@ -3832,7 +3832,7 @@ void __cdecl Output_InsertFlatRect_Sorted(

CLAMPL(x1, g_PhdWinMinX);
CLAMPL(y1, g_PhdWinMinY);
CLAMPG(x2, g_PhdWinWidth + g_PhdWinMinX);
CLAMPG(x2, g_PhdWinMinX + g_PhdWinWidth);
CLAMPG(y2, g_PhdWinMinY + g_PhdWinHeight);

g_Sort3DPtr->_0 = (int32_t)g_Info3DPtr;
Expand Down Expand Up @@ -3952,8 +3952,8 @@ void __cdecl Output_InsertSprite_Sorted(
}

if (x0 < g_PhdWinMinX || y0 < g_PhdWinMinY
|| x1 > g_PhdWinWidth + g_PhdWinMinX
|| y1 > g_PhdWinHeight + g_PhdWinMinY) {
|| x1 > g_PhdWinMinX + g_PhdWinWidth
|| y1 > g_PhdWinMinY + g_PhdWinHeight) {
g_FltWinLeft = (float)g_PhdWinMinX;
g_FltWinTop = (float)g_PhdWinMinY;
g_FltWinRight = (float)(g_PhdWinMinX + g_PhdWinWidth);
Expand Down
19 changes: 5 additions & 14 deletions src/tr2/game/overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,10 @@ static void M_DrawPickup3D(const DISPLAY_PICKUP *const pickup)
const int32_t vp_x = vp_src_x + (vp_dst_x - vp_src_x) * ease;
const int32_t vp_y = vp_src_y + (vp_dst_y - vp_src_y) * ease;

g_PhdWinCenterX = vp_x;
g_PhdWinCenterY = vp_y;
VIEWPORT new_vp = old_vp;
new_vp.game_vars.win_center_x = vp_x;
new_vp.game_vars.win_center_y = vp_y;
Viewport_Restore(&new_vp);

Matrix_PushUnit();
Matrix_TranslateRel(0, 0, scale);
Expand Down Expand Up @@ -446,18 +448,7 @@ static void M_DrawPickup3D(const DISPLAY_PICKUP *const pickup)
}
Matrix_Pop();

// clang-format off
Viewport_Init(
old_vp.x,
old_vp.y,
old_vp.width,
old_vp.height,
old_vp.near_z,
old_vp.far_z,
old_vp.view_angle,
old_vp.screen_width,
old_vp.screen_height);
// clang-format on
Viewport_Restore(&old_vp);
}

static void M_DrawPickupSprite(const DISPLAY_PICKUP *const pickup)
Expand Down
206 changes: 146 additions & 60 deletions src/tr2/game/viewport.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,144 @@
#include "global/const.h"
#include "global/vars.h"

#define MAP_GAME_VARS() \
MAP_GAME_VAR(win_min_x, g_PhdWinMinX); \
MAP_GAME_VAR(win_min_y, g_PhdWinMinY); \
MAP_GAME_VAR(win_max_x, g_PhdWinMaxX); \
MAP_GAME_VAR(win_max_y, g_PhdWinMaxY); \
MAP_GAME_VAR(win_width, g_PhdWinWidth); \
MAP_GAME_VAR(win_height, g_PhdWinHeight); \
MAP_GAME_VAR(win_center_x, g_PhdWinCenterX); \
MAP_GAME_VAR(win_center_y, g_PhdWinCenterY); \
MAP_GAME_VAR(win_left, g_PhdWinLeft); \
MAP_GAME_VAR(win_top, g_PhdWinTop); \
MAP_GAME_VAR(win_right, g_PhdWinRight); \
MAP_GAME_VAR(win_bottom, g_PhdWinBottom); \
MAP_GAME_VAR(win_rect.left, g_PhdWinRect.left); \
MAP_GAME_VAR(win_rect.bottom, g_PhdWinRect.bottom); \
MAP_GAME_VAR(win_rect.top, g_PhdWinRect.top); \
MAP_GAME_VAR(win_rect.right, g_PhdWinRect.right); \
MAP_GAME_VAR(near_z, g_PhdNearZ); \
MAP_GAME_VAR(far_z, g_PhdFarZ); \
MAP_GAME_VAR(flt_near_z, g_FltNearZ); \
MAP_GAME_VAR(flt_far_z, g_FltFarZ); \
MAP_GAME_VAR(persp, g_PhdPersp); \
MAP_GAME_VAR(flt_res_z, g_FltResZ); \
MAP_GAME_VAR(flt_res_z_o_rhw, g_FltResZORhw); \
MAP_GAME_VAR(flt_res_z_buf, g_FltResZBuf); \
MAP_GAME_VAR(flt_rhw_o_near_z, g_FltRhwONearZ); \
MAP_GAME_VAR(flt_rhw_o_persp, g_FltRhwOPersp); \
MAP_GAME_VAR(flt_persp, g_FltPersp); \
MAP_GAME_VAR(flt_persp_o_near_z, g_FltPerspONearZ); \
MAP_GAME_VAR(view_distance, g_PhdViewDistance); \
MAP_GAME_VAR(screen_width, g_PhdScreenWidth); \
MAP_GAME_VAR(screen_height, g_PhdScreenHeight); \
MAP_GAME_VAR(flt_win_left, g_FltWinLeft); \
MAP_GAME_VAR(flt_win_top, g_FltWinTop); \
MAP_GAME_VAR(flt_win_right, g_FltWinRight); \
MAP_GAME_VAR(flt_win_bottom, g_FltWinBottom); \
MAP_GAME_VAR(flt_win_center_x, g_FltWinCenterX); \
MAP_GAME_VAR(flt_win_center_y, g_FltWinCenterY); \
MAP_GAME_VAR(viewport_aspect_ratio, g_ViewportAspectRatio);

static VIEWPORT m_Viewport = { 0 };

static void M_Apply(void);
static void M_AlterFov(VIEWPORT *vp);
static void M_InitGameVars(VIEWPORT *vp);
static void M_PullGameVars(VIEWPORT *vp);
static void M_ApplyGameVars(const VIEWPORT *vp);

static void M_AlterFov(VIEWPORT *const vp)
{
vp->game_vars.persp = vp->game_vars.win_width / 2
* Math_Cos(vp->view_angle / 2) / Math_Sin(vp->view_angle / 2);

vp->game_vars.flt_persp = vp->game_vars.persp;
vp->game_vars.flt_rhw_o_persp = g_RhwFactor / vp->game_vars.flt_persp;
vp->game_vars.flt_persp_o_near_z =
vp->game_vars.flt_persp / vp->game_vars.flt_near_z;

double window_aspect_ratio = 4.0 / 3.0;
if (!g_SavedAppSettings.fullscreen
&& g_SavedAppSettings.aspect_mode == AM_16_9) {
window_aspect_ratio = 16.0 / 9.0;
}

vp->game_vars.viewport_aspect_ratio = window_aspect_ratio
/ ((double)vp->game_vars.win_width / (double)vp->game_vars.win_height);
}

static void M_InitGameVars(VIEWPORT *const vp)
{
vp->game_vars.win_min_x = vp->x;
vp->game_vars.win_min_y = vp->y;
vp->game_vars.win_max_x = vp->width - 1;
vp->game_vars.win_max_y = vp->height - 1;
vp->game_vars.win_width = vp->width;
vp->game_vars.win_height = vp->height;
vp->game_vars.win_center_x = vp->width / 2;
vp->game_vars.win_center_y = vp->height / 2;

vp->game_vars.win_left = 0;
vp->game_vars.win_top = 0;
vp->game_vars.win_right = vp->game_vars.win_max_x;
vp->game_vars.win_bottom = vp->game_vars.win_max_y;

vp->game_vars.win_rect.left = vp->game_vars.win_min_x;
vp->game_vars.win_rect.bottom =
vp->game_vars.win_min_y + vp->game_vars.win_height;
vp->game_vars.win_rect.top = vp->game_vars.win_min_y;
vp->game_vars.win_rect.right =
vp->game_vars.win_min_x + vp->game_vars.win_width;

vp->game_vars.flt_win_left =
vp->game_vars.win_min_x + vp->game_vars.win_left;
vp->game_vars.flt_win_top = vp->game_vars.win_min_y + vp->game_vars.win_top;
vp->game_vars.flt_win_right =
vp->game_vars.win_min_x + vp->game_vars.win_right + 1;
vp->game_vars.flt_win_bottom =
vp->game_vars.win_min_y + vp->game_vars.win_bottom + 1;
vp->game_vars.flt_win_center_x =
vp->game_vars.win_min_x + vp->game_vars.win_center_x;
vp->game_vars.flt_win_center_y =
vp->game_vars.win_min_y + vp->game_vars.win_center_y;

vp->game_vars.near_z = vp->near_z << W2V_SHIFT;
vp->game_vars.far_z = vp->far_z << W2V_SHIFT;

vp->game_vars.flt_near_z = vp->game_vars.near_z;
vp->game_vars.flt_far_z = vp->game_vars.far_z;

const double res_z = 0.99 * vp->game_vars.flt_near_z
* vp->game_vars.flt_far_z
/ (vp->game_vars.flt_far_z - vp->game_vars.flt_near_z);
vp->game_vars.flt_res_z = res_z;
vp->game_vars.flt_res_z_o_rhw = res_z / g_RhwFactor;
vp->game_vars.flt_res_z_buf = 0.005 + res_z / vp->game_vars.flt_near_z;
vp->game_vars.flt_rhw_o_near_z = g_RhwFactor / vp->game_vars.flt_near_z;
vp->game_vars.flt_persp = vp->game_vars.flt_persp;
vp->game_vars.flt_persp_o_near_z =
vp->game_vars.flt_persp / vp->game_vars.flt_near_z;
vp->game_vars.view_distance = vp->far_z;

vp->game_vars.screen_width = vp->screen_width;
vp->game_vars.screen_height = vp->screen_height;

M_AlterFov(vp);
}

static void M_PullGameVars(VIEWPORT *const vp)
{
#undef MAP_GAME_VAR
#define MAP_GAME_VAR(a, b) vp->game_vars.a = b;
MAP_GAME_VARS();
}

static void M_Apply(void)
static void M_ApplyGameVars(const VIEWPORT *const vp)
{
// TODO: remove most of these variables if possible
g_PhdWinMinX = m_Viewport.x;
g_PhdWinMinY = m_Viewport.y;
g_PhdWinMaxX = m_Viewport.width - 1;
g_PhdWinMaxY = m_Viewport.height - 1;
g_PhdWinWidth = m_Viewport.width;
g_PhdWinHeight = m_Viewport.height;
g_PhdWinCenterX = m_Viewport.width / 2;
g_PhdWinCenterY = m_Viewport.height / 2;

g_PhdWinLeft = 0;
g_PhdWinTop = 0;
g_PhdWinRight = g_PhdWinMaxX;
g_PhdWinBottom = g_PhdWinMaxY;

g_PhdWinRect.left = g_PhdWinMinX;
g_PhdWinRect.bottom = g_PhdWinMinY + g_PhdWinHeight;
g_PhdWinRect.top = g_PhdWinMinY;
g_PhdWinRect.right = g_PhdWinMinX + g_PhdWinWidth;

g_PhdNearZ = m_Viewport.near_z << W2V_SHIFT;
g_PhdFarZ = m_Viewport.far_z << W2V_SHIFT;

g_FltNearZ = g_PhdNearZ;
g_FltFarZ = g_PhdFarZ;

const double res_z =
0.99 * g_FltNearZ * g_FltFarZ / (g_FltFarZ - g_FltNearZ);
g_FltResZ = res_z;
g_FltResZORhw = res_z / g_RhwFactor;
g_FltResZBuf = 0.005 + res_z / g_FltNearZ;
g_FltRhwONearZ = g_RhwFactor / g_FltNearZ;
g_FltPerspONearZ = g_FltPersp / g_FltNearZ;
g_PhdViewDistance = m_Viewport.far_z;

Viewport_AlterFOV(m_Viewport.view_angle);

g_PhdScreenWidth = m_Viewport.screen_width;
g_PhdScreenHeight = m_Viewport.screen_height;
#undef MAP_GAME_VAR
#define MAP_GAME_VAR(a, b) b = vp->game_vars.a;
MAP_GAME_VARS();
}

void Viewport_Init(
Expand All @@ -68,35 +161,28 @@ void Viewport_Init(
m_Viewport.screen_width = screen_width;
m_Viewport.screen_height = screen_height;

M_Apply();
M_InitGameVars(&m_Viewport);
M_ApplyGameVars(&m_Viewport);
}

const VIEWPORT *Viewport_Get(void)
{
M_PullGameVars(&m_Viewport);
return &m_Viewport;
}

void Viewport_AlterFOV(int16_t view_angle)
void Viewport_Restore(const VIEWPORT *ref_vp)
{
m_Viewport.view_angle = view_angle;

view_angle /= 2;

g_PhdPersp =
g_PhdWinWidth / 2 * Math_Cos(view_angle) / Math_Sin(view_angle);

g_FltPersp = g_PhdPersp;
g_FltRhwOPersp = g_RhwFactor / g_FltPersp;
g_FltPerspONearZ = g_FltPersp / g_FltNearZ;
memcpy(&m_Viewport, ref_vp, sizeof(VIEWPORT));
M_ApplyGameVars(&m_Viewport);
}

double window_aspect_ratio = 4.0 / 3.0;
if (!g_SavedAppSettings.fullscreen
&& g_SavedAppSettings.aspect_mode == AM_16_9) {
window_aspect_ratio = 16.0 / 9.0;
}
void Viewport_AlterFOV(const int16_t view_angle)
{
m_Viewport.view_angle = view_angle;

g_ViewportAspectRatio =
window_aspect_ratio / ((double)g_PhdWinWidth / (double)g_PhdWinHeight);
M_PullGameVars(&m_Viewport);
M_AlterFov(&m_Viewport);
}

int16_t Viewport_GetFOV(void)
Expand Down
50 changes: 50 additions & 0 deletions src/tr2/game/viewport.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,63 @@ typedef struct {
int16_t view_angle;
int32_t screen_width;
int32_t screen_height;

// TODO: remove most of these variables if possible
struct {
int32_t win_min_x;
int32_t win_min_y;
int32_t win_max_x;
int32_t win_max_y;
int32_t win_width;
int32_t win_height;
int32_t win_center_x;
int32_t win_center_y;

int32_t win_left;
int32_t win_top;
int32_t win_right;
int32_t win_bottom;

struct {
int32_t left;
int32_t bottom;
int32_t top;
int32_t right;
} win_rect;

int32_t persp;
int32_t near_z;
int32_t far_z;

float flt_near_z;
float flt_far_z;
float flt_res_z;
float flt_res_z_o_rhw;
float flt_res_z_buf;
float flt_rhw_o_persp;
float flt_rhw_o_near_z;
float flt_persp;
float flt_persp_o_near_z;
float flt_win_left;
float flt_win_top;
float flt_win_right;
float flt_win_bottom;
float flt_win_center_x;
float flt_win_center_y;
int32_t view_distance;
int32_t screen_width;
int32_t screen_height;
float viewport_aspect_ratio;
} game_vars;
} VIEWPORT;

void Viewport_Init(
int16_t x, int16_t y, int32_t width, int32_t height, int32_t near_z,
int32_t far_z, int16_t view_angle, int32_t screen_width,
int32_t screen_height);

void Viewport_Restore(const VIEWPORT *ref_vp);

void Viewport_AlterFOV(int16_t view_angle);

const VIEWPORT *Viewport_Get(void);
Expand Down

0 comments on commit d8f2a09

Please sign in to comment.