diff --git a/port/fast3d/gfx_api.h b/port/fast3d/gfx_api.h index 271e8abb6..279a684ef 100644 --- a/port/fast3d/gfx_api.h +++ b/port/fast3d/gfx_api.h @@ -35,6 +35,7 @@ extern uint32_t gfx_msaa_level; extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native video mode of the game extern float gfx_current_native_aspect; // The aspect ratio of the above mode extern bool gfx_framebuffers_enabled; +extern bool gfx_detail_textures_enabled; void gfx_init(const struct GfxInitSettings *settings); void gfx_destroy(void); diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index a9fd646a0..7938fdd77 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -216,6 +216,7 @@ struct XYWidthHeight gfx_current_game_window_viewport; struct XYWidthHeight gfx_current_native_viewport; float gfx_current_native_aspect = 4.f / 3.f; bool gfx_framebuffers_enabled = true; +bool gfx_detail_textures_enabled = true; static bool game_renders_to_framebuffer; static int game_framebuffer; @@ -1185,6 +1186,12 @@ static void gfx_sp_modify_vertex(uint16_t vtx_idx, uint8_t where, uint32_t val) v->v = t; } +static inline int gfx_lod_tile_offset(const int i) { + if (gfx_detail_textures_enabled) + return ((rdp.tex_lod && !rdp.tex_detail) ? 0 : i); + return (rdp.tex_lod ? rdp.tex_detail : i); +} + static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bool is_rect) { struct LoadedVertex* v1 = &rsp.loaded_vertices[vtx1_idx]; struct LoadedVertex* v2 = &rsp.loaded_vertices[vtx2_idx]; @@ -1329,7 +1336,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo for (int i = 0; i < 2; i++) { // TODO: fix this; for now just ignore smaller mips - const uint32_t tile = rdp.first_tile_index + ((rdp.tex_lod && !rdp.tex_detail) ? 0 : i); + const uint32_t tile = rdp.first_tile_index + gfx_lod_tile_offset(i); if (comb->used_textures[i]) { if (rdp.textures_changed[i]) { gfx_flush(); @@ -1434,7 +1441,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo } // TODO: fix this; for now just ignore smaller mips - const uint32_t tile = ((rdp.tex_lod && !rdp.tex_detail) ? 0 : t); + const uint32_t tile = gfx_lod_tile_offset(t); float u = v_arr[i]->u / 32.0f; float v = v_arr[i]->v / 32.0f; diff --git a/port/include/video.h b/port/include/video.h index 105f78699..d7a888886 100644 --- a/port/include/video.h +++ b/port/include/video.h @@ -30,12 +30,14 @@ s32 videoGetFullscreen(void); s32 videoGetMaximizeWindow(void); void videoSetMaximizeWindow(s32 fs); u32 videoGetTextureFilter(void); -u32 videoGetTextureFilter2D(void); +s32 videoGetTextureFilter2D(void); +s32 videoGetDetailTextures(void); void videoSetWindowOffset(s32 x, s32 y); void videoSetFullscreen(s32 fs); void videoSetTextureFilter(u32 filter); -void videoSetTextureFilter2D(u32 filter); +void videoSetTextureFilter2D(s32 filter); +void videoSetDetailTextures(s32 detail); s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize); void videoSetFramebuffer(s32 target); diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index e8085b564..b6ac6dab7 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -678,6 +678,19 @@ static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem return 0; } +static MenuItemHandlerResult menuhandlerTexDetail(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_GET: + return (videoGetDetailTextures() != 0); + case MENUOP_SET: + videoSetDetailTextures(data->checkbox.value); + break; + } + + return 0; +} + static MenuItemHandlerResult menuhandlerTexFilter2D(s32 operation, struct menuitem *item, union handlerdata *data) { switch (operation) { @@ -769,6 +782,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, menuhandlerMaximizeWindow, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Detail Textures", + 0, + menuhandlerTexDetail, + }, { MENUITEMTYPE_CHECKBOX, 0, diff --git a/port/src/video.c b/port/src/video.c index c838bc524..181af3ab5 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -30,6 +30,7 @@ static s32 vidFramerateLimit = 0; static s32 texFilter = FILTER_LINEAR; static s32 texFilter2D = true; +static s32 texDetail = true; static u32 dlcount = 0; static u32 frames = 0; @@ -45,6 +46,7 @@ s32 videoInit(void) gfx_current_native_viewport.height = 220; gfx_current_native_aspect = 320.f / 220.f; gfx_framebuffers_enabled = (bool)vidFramebuffers; + gfx_detail_textures_enabled = (bool)texDetail; gfx_msaa_level = vidMSAA; struct GfxInitSettings set = { @@ -176,7 +178,7 @@ f32 videoGetAspect(void) return gfx_current_dimensions.aspect_ratio; } -u32 videoGetTextureFilter2D(void) +s32 videoGetTextureFilter2D(void) { return texFilter2D; } @@ -186,6 +188,11 @@ u32 videoGetTextureFilter(void) return texFilter; } +s32 videoGetDetailTextures(void) +{ + return texDetail; +} + void videoSetWindowOffset(s32 x, s32 y) { gfx_current_game_window_viewport.x = x; @@ -215,11 +222,17 @@ void videoSetTextureFilter(u32 filter) renderingAPI->set_texture_filter((enum FilteringMode)filter); } -void videoSetTextureFilter2D(u32 filter) +void videoSetTextureFilter2D(s32 filter) { texFilter2D = !!filter; } +void videoSetDetailTextures(s32 detail) +{ + texDetail = !!detail; + gfx_detail_textures_enabled = (bool)texDetail; +} + s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize) { return gfx_create_framebuffer(w, h, upscale, autoresize); @@ -275,4 +288,5 @@ PD_CONSTRUCTOR static void videoConfigInit(void) configRegisterInt("Video.MSAA", &vidMSAA, 1, 16); configRegisterInt("Video.TextureFilter", &texFilter, 0, 2); configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1); + configRegisterInt("Video.DetailTextures", &texDetail, 0, 1); }