From 5edecccfe6eabc35d32d0d8ba5ea16646bdeb71d Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Wed, 4 Sep 2024 00:44:02 +0200 Subject: [PATCH] output: fix texture edges when bilinear filter off Resolves #1483. --- CHANGELOG.md | 2 ++ data/ship/cfg/TR1X_gameflow.json5 | 1 + data/ship/cfg/TR1X_gameflow_demo_pc.json5 | 1 + data/ship/cfg/TR1X_gameflow_ub.json5 | 1 + src/config.h | 1 + src/config_map.def | 1 + src/game/game_string.def | 1 + src/game/option/option_graphics.c | 42 ++++++++++++++++++----- src/specific/s_output.c | 26 ++++++++------ 9 files changed, 58 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2f7c32f9..258e1e837 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ - fixed console commands causing improper ring shutdown with selected inventory item (#1460, regression from 3.0) - fixed console input immediately ending demo (#1480, regression from 4.1) - changed `/tp` console command to look for the closest place to teleport to when targeting items (#1484) +- improved appearance of textures around edges when bilinear filter is off (#1483) + Since this removes the seams on pushblocks, this was made optional. - improved level load times - improved logs module names readability - improved crash debug information on Windows diff --git a/data/ship/cfg/TR1X_gameflow.json5 b/data/ship/cfg/TR1X_gameflow.json5 index a461b76b7..1a586c615 100644 --- a/data/ship/cfg/TR1X_gameflow.json5 +++ b/data/ship/cfg/TR1X_gameflow.json5 @@ -610,6 +610,7 @@ "DETAIL_LEVEL_LOW": "Low", "DETAIL_FPS": "FPS", "DETAIL_PERSPECTIVE": "Perspective", + "DETAIL_PRETTY_PIXELS": "Pretty pixels", "DETAIL_BILINEAR": "Bilinear", "DETAIL_TEXTURE_FILTER": "Texture filter", "DETAIL_FBO_FILTER": "FBO filter", diff --git a/data/ship/cfg/TR1X_gameflow_demo_pc.json5 b/data/ship/cfg/TR1X_gameflow_demo_pc.json5 index 1c7b9e62d..dfa54506b 100644 --- a/data/ship/cfg/TR1X_gameflow_demo_pc.json5 +++ b/data/ship/cfg/TR1X_gameflow_demo_pc.json5 @@ -106,6 +106,7 @@ "DETAIL_LEVEL_LOW": "Low", "DETAIL_FPS": "FPS", "DETAIL_PERSPECTIVE": "Perspective", + "DETAIL_PRETTY_PIXELS": "Pretty pixels", "DETAIL_BILINEAR": "Bilinear", "DETAIL_TEXTURE_FILTER": "Texture filter", "DETAIL_FBO_FILTER": "FBO filter", diff --git a/data/ship/cfg/TR1X_gameflow_ub.json5 b/data/ship/cfg/TR1X_gameflow_ub.json5 index 7b14d10a0..b95c77a84 100644 --- a/data/ship/cfg/TR1X_gameflow_ub.json5 +++ b/data/ship/cfg/TR1X_gameflow_ub.json5 @@ -178,6 +178,7 @@ "DETAIL_LEVEL_LOW": "Low", "DETAIL_FPS": "FPS", "DETAIL_PERSPECTIVE": "Perspective", + "DETAIL_PRETTY_PIXELS": "Pretty pixels", "DETAIL_BILINEAR": "Bilinear", "DETAIL_TEXTURE_FILTER": "Texture filter", "DETAIL_FBO_FILTER": "FBO filter", diff --git a/src/config.h b/src/config.h index 519a7a718..9a98de138 100644 --- a/src/config.h +++ b/src/config.h @@ -117,6 +117,7 @@ typedef struct { bool enable_fps_counter; float anisotropy_filter; int32_t turbo_speed; + bool pretty_pixels; } rendering; struct { diff --git a/src/config_map.def b/src/config_map.def index b7c37bf83..a000b48a5 100644 --- a/src/config_map.def +++ b/src/config_map.def @@ -96,6 +96,7 @@ CFG_BOOL(g_Config, rendering.enable_wireframe, false) CFG_DOUBLE(g_Config, rendering.wireframe_width, 2.5) CFG_BOOL(g_Config, rendering.enable_perspective_filter, true) CFG_BOOL(g_Config, rendering.enable_vsync, true) +CFG_BOOL(g_Config, rendering.pretty_pixels, true) CFG_INT32(g_Config, music_volume, 8) CFG_INT32(g_Config, sound_volume, 8) CFG_INT32(g_Config, input.layout, 0) diff --git a/src/game/game_string.def b/src/game/game_string.def index 6e508ace4..ba5b99762 100644 --- a/src/game/game_string.def +++ b/src/game/game_string.def @@ -23,6 +23,7 @@ GS_DEFINE(DETAIL_LEVEL_MEDIUM, "Medium") GS_DEFINE(DETAIL_LEVEL_LOW, "Low") GS_DEFINE(DETAIL_FPS, "FPS") GS_DEFINE(DETAIL_PERSPECTIVE, "Perspective") +GS_DEFINE(DETAIL_PRETTY_PIXELS, "Pretty pixels") GS_DEFINE(DETAIL_BILINEAR, "Bilinear") GS_DEFINE(DETAIL_TEXTURE_FILTER, "Texture filter") GS_DEFINE(DETAIL_FBO_FILTER, "FBO filter") diff --git a/src/game/option/option_graphics.c b/src/game/option/option_graphics.c index 5d167c4cf..b31636fdf 100644 --- a/src/game/option/option_graphics.c +++ b/src/game/option/option_graphics.c @@ -49,9 +49,10 @@ typedef enum GRAPHICS_OPTION_NAME { OPTION_RENDER_MODE, OPTION_RESOLUTION, OPTION_PERSPECTIVE, + OPTION_PRETTY_PIXELS, OPTION_NUMBER_OF, OPTION_MIN = OPTION_FPS, - OPTION_MAX = OPTION_PERSPECTIVE, + OPTION_MAX = OPTION_PRETTY_PIXELS, } GRAPHICS_OPTION_NAME; typedef struct GRAPHICS_OPTION_ROW { @@ -83,6 +84,7 @@ static const GRAPHICS_OPTION_ROW m_GfxOptionRows[] = { { OPTION_RENDER_MODE, GS_DETAIL_RENDER_MODE, GS_DETAIL_STRING_FMT }, { OPTION_RESOLUTION, GS_DETAIL_RESOLUTION, GS_DETAIL_RESOLUTION_FMT }, { OPTION_PERSPECTIVE, GS_DETAIL_PERSPECTIVE, GS_MISC_ON }, + { OPTION_PRETTY_PIXELS, GS_DETAIL_PRETTY_PIXELS, GS_MISC_ON }, // end { OPTION_NUMBER_OF, 0, 0 }, }; @@ -110,13 +112,13 @@ static int16_t Option_Graphics_PlaceColumns(bool create); static void Option_Graphics_InitMenu(void) { - m_GraphicsMenu.first_option = &m_GfxOptionRows[OPTION_FPS]; - m_GraphicsMenu.last_option = &m_GfxOptionRows[OPTION_PERSPECTIVE]; - m_GraphicsMenu.cur_option = &m_GfxOptionRows[OPTION_FPS]; + m_GraphicsMenu.first_option = &m_GfxOptionRows[OPTION_MIN]; + m_GraphicsMenu.last_option = &m_GfxOptionRows[OPTION_MAX]; + m_GraphicsMenu.cur_option = &m_GfxOptionRows[OPTION_MIN]; m_GraphicsMenu.row_num = 0; m_GraphicsMenu.num_vis_options = 0; - m_GraphicsMenu.first_visible = &m_GfxOptionRows[OPTION_FPS]; - m_GraphicsMenu.last_visible = &m_GfxOptionRows[OPTION_FPS]; + m_GraphicsMenu.first_visible = &m_GfxOptionRows[OPTION_MIN]; + m_GraphicsMenu.last_visible = &m_GfxOptionRows[OPTION_MIN]; } static void Option_Graphics_UpdateMenuVisible(void) @@ -132,9 +134,9 @@ static void Option_Graphics_UpdateMenuVisible(void) visible_lines = 16; } m_GraphicsMenu.num_vis_options = MIN(OPTION_NUMBER_OF, visible_lines); - m_GraphicsMenu.first_visible = &m_GfxOptionRows[OPTION_FPS]; + m_GraphicsMenu.first_visible = &m_GfxOptionRows[OPTION_MIN]; m_GraphicsMenu.last_visible = - &m_GfxOptionRows[OPTION_FPS] + m_GraphicsMenu.num_vis_options - 1; + &m_GfxOptionRows[OPTION_MIN] + m_GraphicsMenu.num_vis_options - 1; } static void Option_Graphics_Reinitialize(GRAPHICS_OPTION_NAME starting_option) @@ -296,6 +298,10 @@ static void Option_Graphics_UpdateArrows( m_HideArrowLeft = !g_Config.rendering.enable_perspective_filter; m_HideArrowRight = g_Config.rendering.enable_perspective_filter; break; + case OPTION_PRETTY_PIXELS: + m_HideArrowLeft = !g_Config.rendering.pretty_pixels; + m_HideArrowRight = g_Config.rendering.pretty_pixels; + break; case OPTION_NUMBER_OF: default: @@ -435,6 +441,12 @@ static void Option_Graphics_ChangeTextOption( break; } + case OPTION_PRETTY_PIXELS: { + bool is_enabled = g_Config.rendering.pretty_pixels; + Text_ChangeText(value_text, is_enabled ? GS(MISC_ON) : GS(MISC_OFF)); + break; + } + case OPTION_NUMBER_OF: default: break; @@ -538,6 +550,13 @@ void Option_Graphics(INVENTORY_ITEM *inv_item) } break; + case OPTION_PRETTY_PIXELS: + if (!g_Config.rendering.pretty_pixels) { + g_Config.rendering.pretty_pixels = true; + reset = OPTION_PRETTY_PIXELS; + } + break; + case OPTION_NUMBER_OF: default: break; @@ -618,6 +637,13 @@ void Option_Graphics(INVENTORY_ITEM *inv_item) } break; + case OPTION_PRETTY_PIXELS: + if (g_Config.rendering.pretty_pixels) { + g_Config.rendering.pretty_pixels = false; + reset = OPTION_PRETTY_PIXELS; + } + break; + case OPTION_NUMBER_OF: default: break; diff --git a/src/specific/s_output.c b/src/specific/s_output.c index 9a07a40cd..77e3e38e7 100644 --- a/src/specific/s_output.c +++ b/src/specific/s_output.c @@ -63,6 +63,14 @@ static int32_t S_Output_VisibleZClip( static int32_t S_Output_ZedClipper( int32_t vertex_count, POINT_INFO *pts, GFX_3D_Vertex *vertices); +static inline float S_Output_GetUV(const uint16_t uv) +{ + return g_Config.rendering.pretty_pixels + && g_Config.rendering.texture_filter == GFX_TF_NN + ? uv / 256.0f + : ((uv & 0xFF00) + 127) / 256.0f; +} + static void S_Output_ReleaseTextures(void) { if (!m_Renderer3D) { @@ -962,10 +970,10 @@ void S_Output_DrawTexturedTriangle( vertices[i].z = src_vbuf[i]->zv * 0.0001f; vertices[i].w = 65536.0f / src_vbuf[i]->zv; - vertices[i].s = (((src_uv[i]->u & 0xFF00) + 127) / 256.0f) - * (vertices[i].w / 256.0f); - vertices[i].t = (((src_uv[i]->v & 0xFF00) + 127) / 256.0f) - * (vertices[i].w / 256.0f); + vertices[i].s = + S_Output_GetUV(src_uv[i]->u) * (vertices[i].w / 256.0f); + vertices[i].t = + S_Output_GetUV(src_uv[i]->v) * (vertices[i].w / 256.0f); vertices[i].r = vertices[i].g = vertices[i].b = (8192.0f - src_vbuf[i]->g) * multiplier; @@ -990,8 +998,8 @@ void S_Output_DrawTexturedTriangle( points[i].xs = src_vbuf[i]->xs; points[i].ys = src_vbuf[i]->ys; points[i].g = src_vbuf[i]->g; - points[i].u = (((src_uv[i]->u & 0xFF00) + 127) / 256.0f); - points[i].v = (((src_uv[i]->v & 0xFF00) + 127) / 256.0f); + points[i].u = S_Output_GetUV(src_uv[i]->u); + points[i].v = S_Output_GetUV(src_uv[i]->v); } vertex_count = S_Output_ZedClipper(vertex_count, points, vertices); @@ -1068,10 +1076,8 @@ void S_Output_DrawTexturedQuad( vertices[i].z = src_vbuf[i]->zv * 0.0001f; vertices[i].w = 65536.0f / src_vbuf[i]->zv; - vertices[i].s = (((src_uv[i]->u & 0xFF00) + 127) / 256.0f) - * (vertices[i].w / 256.0f); - vertices[i].t = (((src_uv[i]->v & 0xFF00) + 127) / 256.0f) - * (vertices[i].w / 256.0f); + vertices[i].s = S_Output_GetUV(src_uv[i]->u) * (vertices[i].w / 256.0f); + vertices[i].t = S_Output_GetUV(src_uv[i]->v) * (vertices[i].w / 256.0f); vertices[i].r = vertices[i].g = vertices[i].b = (8192.0f - src_vbuf[i]->g) * multiplier;