diff --git a/port/fast3d/gfx_api.h b/port/fast3d/gfx_api.h index f79c4075d..6a0bc3f43 100644 --- a/port/fast3d/gfx_api.h +++ b/port/fast3d/gfx_api.h @@ -45,6 +45,7 @@ void gfx_run(Gfx* commands); void gfx_end_frame(void); void gfx_set_target_fps(int); void gfx_set_texture_filter(enum FilteringMode mode); +void gfx_set_mipmap_filter(enum MipmapFilteringMode mode); void gfx_texture_cache_clear(void); void gfx_texture_cache_delete(const uint8_t *orig_addr); int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize); diff --git a/port/fast3d/gfx_opengl.cpp b/port/fast3d/gfx_opengl.cpp index 55fa7d788..d489014eb 100644 --- a/port/fast3d/gfx_opengl.cpp +++ b/port/fast3d/gfx_opengl.cpp @@ -54,7 +54,9 @@ static uint32_t frame_count; static std::vector framebuffers; static size_t current_framebuffer; static float current_noise_scale; +static int current_anisotropy_level; static FilteringMode current_filter_mode = FILTER_LINEAR; +static MipmapFilteringMode current_mipmap_filter_mode = MIPMAP_LINEAR; static bool current_textures_linear_filter[2] = {false, false}; static int gl_glsl_version = 130; @@ -692,8 +694,11 @@ static void gfx_opengl_select_texture(int tile, GLuint texture_id, bool linear_f current_textures_linear_filter[tile] = linear_filter; } -static void gfx_opengl_upload_texture(const uint8_t* rgba32_buf, uint32_t width, uint32_t height) { +static void gfx_opengl_upload_texture(const uint8_t* rgba32_buf, uint32_t width, uint32_t height, bool gen_mipmaps) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); + if (gen_mipmaps || current_filter_mode == FILTER_THREE_POINT) { + glGenerateMipmap(GL_TEXTURE_2D); + } } static uint32_t gfx_cm_to_opengl(uint32_t val) { @@ -710,11 +715,27 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) { return 0; } -static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { - const GLint filter = linear_filter && (current_filter_mode == FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST; - glActiveTexture(GL_TEXTURE0 + tile); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); +static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt, bool mipmaps) { + const GLint min_filters[3][3] = { + // MIPMAP_DISABLED MIPMAP_NEAREST MIPMAP_LINEAR + {GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR}, // FILTER_NONE + {GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR}, // FILTER_BILINEAR + {GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR}, // FILTER_TRILINEAR + }; + + mipmaps = mipmaps && (current_mipmap_filter_mode != MIPMAP_DISABLED); + const int mip_idx = mipmaps ? current_mipmap_filter_mode : 0; + const GLint min_filter = linear_filter ? min_filters[current_filter_mode][mip_idx] : GL_NEAREST; + const GLint max_filter = linear_filter && (current_filter_mode != FILTER_NONE) ? GL_LINEAR : GL_NEAREST; + + glActiveTexture(GL_TEXTURE0 + tile); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, max_filter); + + if (mipmaps) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, current_anisotropy_level); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt)); } @@ -1244,7 +1265,21 @@ FilteringMode gfx_opengl_get_texture_filter(void) { return current_filter_mode; } -struct GfxRenderingAPI gfx_opengl_api = { +void gfx_opengl_set_mipmap_filter(MipmapFilteringMode mode) { + current_mipmap_filter_mode = mode; +} + +static int gfx_opengl_get_max_anisotropy_level() { + GLfloat max_aniso_level; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_aniso_level); + return (int)max_aniso_level; +} + +static void gfx_opengl_set_anisotropy_level(int level) { + current_anisotropy_level = level; +} + +struct GfxRenderingAPI gfx_opengl_api = { gfx_opengl_get_name, gfx_opengl_get_max_texture_size, gfx_opengl_get_clip_parameters, @@ -1279,5 +1314,8 @@ struct GfxRenderingAPI gfx_opengl_api = { gfx_opengl_select_texture_fb, gfx_opengl_delete_texture, gfx_opengl_set_texture_filter, - gfx_opengl_get_texture_filter + gfx_opengl_get_texture_filter, + gfx_opengl_set_mipmap_filter, + gfx_opengl_set_anisotropy_level, + gfx_opengl_get_max_anisotropy_level }; diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 0acaff3fc..14c6ec3ef 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -551,7 +551,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) { node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it }); gfx_rapi->select_texture(i, texture_id, false); - gfx_rapi->set_sampler_parameters(i, false, 0, 0); + gfx_rapi->set_sampler_parameters(i, false, 0, 0, rdp.tex_lod); *n = node; return false; } @@ -585,8 +585,7 @@ void gfx_texture_cache_delete(const uint8_t* orig_addr) { } } -static void import_texture_rgba16(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { - const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; +static void import_texture_rgba16(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = @@ -612,11 +611,11 @@ static void import_texture_rgba16(int tile, const LoadedTexture& loaded_texture, const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_rgba32(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { +static void import_texture_rgba32(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; @@ -633,11 +632,11 @@ static void import_texture_rgba32(int tile, const LoadedTexture& loaded_texture, const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; const uint32_t height = (size_bytes / 2) / rdp.texture_tile[tile].line_size_bytes; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); // DumpTexture(loaded_texture.otr_path, addr, width, height); } -static void import_texture_ia4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { +static void import_texture_ia4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; @@ -662,11 +661,11 @@ static void import_texture_ia4(int tile, const LoadedTexture& loaded_texture, bo const uint32_t width = rdp.texture_tile[tile].line_size_bytes * 2; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_ia8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { +static void import_texture_ia8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; @@ -688,11 +687,11 @@ static void import_texture_ia8(int tile, const LoadedTexture& loaded_texture, bo const uint32_t width = rdp.texture_tile[tile].line_size_bytes; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_ia16(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { +static void import_texture_ia16(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; @@ -714,11 +713,11 @@ static void import_texture_ia16(int tile, const LoadedTexture& loaded_texture, b const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_i4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { +static void import_texture_i4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; @@ -741,11 +740,11 @@ static void import_texture_i4(int tile, const LoadedTexture& loaded_texture, boo const uint32_t width = rdp.texture_tile[tile].line_size_bytes * 2; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_i8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { +static void import_texture_i8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; @@ -766,7 +765,7 @@ static void import_texture_i8(int tile, const LoadedTexture& loaded_texture, boo const uint32_t width = rdp.texture_tile[tile].line_size_bytes; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } @@ -791,8 +790,8 @@ static inline void palette_to_rgba32(const uint16_t palentry, uint8_t *rgba32_bu } } -static void import_texture_ci4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { - const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; +static void import_texture_ci4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = @@ -816,11 +815,11 @@ static void import_texture_ci4(int tile, const LoadedTexture& loaded_texture, bo const uint32_t width = result_line_size * 2; const uint32_t height = size_bytes / result_line_size; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); } -static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { - const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; +static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const uint8_t* addr = loaded_texture.addr; const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = @@ -842,8 +841,7 @@ static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bo const uint32_t width = result_line_size; const uint32_t height = size_bytes / result_line_size; - gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); } static void import_texture(int i, int tile, bool importReplacement) { @@ -885,35 +883,35 @@ static void import_texture(int i, int tile, bool importReplacement) { if (fmt == G_IM_FMT_RGBA) { if (siz == G_IM_SIZ_16b) { - import_texture_rgba16(tile, loaded_texture, importReplacement); + import_texture_rgba16(tile, loaded_texture, rdp.tex_lod); } else if (siz == G_IM_SIZ_32b) { - import_texture_rgba32(tile, loaded_texture, importReplacement); + import_texture_rgba32(tile, loaded_texture, rdp.tex_lod); } else { sysFatalError("Bad size for RGBA texture in tile %d: %02x", tile, siz); } } else if (fmt == G_IM_FMT_IA) { if (siz == G_IM_SIZ_4b) { - import_texture_ia4(tile, loaded_texture, importReplacement); + import_texture_ia4(tile, loaded_texture, rdp.tex_lod); } else if (siz == G_IM_SIZ_8b) { - import_texture_ia8(tile, loaded_texture, importReplacement); + import_texture_ia8(tile, loaded_texture, rdp.tex_lod); } else if (siz == G_IM_SIZ_16b) { - import_texture_ia16(tile, loaded_texture, importReplacement); + import_texture_ia16(tile, loaded_texture, rdp.tex_lod); } else { sysFatalError("Bad size for IA texture in tile %d: %02x", tile, siz); } } else if (fmt == G_IM_FMT_CI) { if (siz == G_IM_SIZ_4b) { - import_texture_ci4(tile, loaded_texture, importReplacement); + import_texture_ci4(tile, loaded_texture, rdp.tex_lod); } else if (siz == G_IM_SIZ_8b) { - import_texture_ci8(tile, loaded_texture, importReplacement); + import_texture_ci8(tile, loaded_texture, rdp.tex_lod); } else { sysFatalError("Bad size for CI texture in tile %d: %02x", tile, siz); } } else if (fmt == G_IM_FMT_I) { if (siz == G_IM_SIZ_4b) { - import_texture_i4(tile, loaded_texture, importReplacement); + import_texture_i4(tile, loaded_texture, rdp.tex_lod); } else if (siz == G_IM_SIZ_8b) { - import_texture_i8(tile, loaded_texture, importReplacement); + import_texture_i8(tile, loaded_texture, rdp.tex_lod); } else { sysFatalError("Bad size for I texture in tile %d: %02x", tile, siz); } @@ -1383,7 +1381,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo if (linear_filter != rendering_state.textures[i]->second.linear_filter || cms != rendering_state.textures[i]->second.cms || cmt != rendering_state.textures[i]->second.cmt) { gfx_flush(); - gfx_rapi->set_sampler_parameters(i, linear_filter, cms, cmt); + gfx_rapi->set_sampler_parameters(i, linear_filter, cms, cmt, rdp.tex_lod); rendering_state.textures[i]->second.linear_filter = linear_filter; rendering_state.textures[i]->second.cms = cms; rendering_state.textures[i]->second.cmt = cmt; @@ -2692,7 +2690,7 @@ extern "C" void gfx_set_target_fps(int fps) { gfx_wapi->set_target_fps(fps); } -extern "C" void gfx_set_texture_filter(enum FilteringMode mode) { +extern "C" void reset_texture_state() { gfx_texture_cache_clear(); if (rendering_state.shader_program) { gfx_rapi->unload_shader(rendering_state.shader_program); @@ -2701,9 +2699,18 @@ extern "C" void gfx_set_texture_filter(enum FilteringMode mode) { gfx_rapi->clear_shaders(); color_combiner_pool.clear(); prev_combiner = color_combiner_pool.end(); +} + +extern "C" void gfx_set_texture_filter(enum FilteringMode mode) { + reset_texture_state(); gfx_rapi->set_texture_filter(mode); } +extern "C" void gfx_set_mipmap_filter(enum MipmapFilteringMode mode) { + reset_texture_state(); + gfx_rapi->set_mipmap_filter(mode); +} + extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize) { int fb = gfx_rapi->create_framebuffer(); gfx_resize_framebuffer(fb, width, height, upscale, autoresize); diff --git a/port/fast3d/gfx_rendering_api.h b/port/fast3d/gfx_rendering_api.h index 2b499479c..d21b3f759 100644 --- a/port/fast3d/gfx_rendering_api.h +++ b/port/fast3d/gfx_rendering_api.h @@ -13,6 +13,7 @@ struct GfxClipParameters { }; enum FilteringMode { FILTER_NONE, FILTER_LINEAR, FILTER_THREE_POINT }; +enum MipmapFilteringMode { MIPMAP_DISABLED, MIPMAP_NEAREST, MIPMAP_LINEAR }; struct GfxRenderingAPI { const char* (*get_name)(void); @@ -26,8 +27,8 @@ struct GfxRenderingAPI { void (*clear_shaders)(void); uint32_t (*new_texture)(void); void (*select_texture)(int tile, uint32_t texture_id, bool linear_filter); - void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height); - void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt); + void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height, bool gen_mipmaps); + void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt, bool mipmaps); void (*set_depth_mode)(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode); void (*set_depth_range)(float znear, float zfar); void (*set_viewport)(int x, int y, int width, int height); @@ -52,6 +53,9 @@ struct GfxRenderingAPI { void (*delete_texture)(uint32_t texID); void (*set_texture_filter)(enum FilteringMode mode); enum FilteringMode (*get_texture_filter)(void); + void (*set_mipmap_filter)(enum MipmapFilteringMode mode); + void (*set_anisotropy_level)(int); + int (*get_max_anisotropy_level)(void); }; #endif diff --git a/port/fast3d/glad/glad.c b/port/fast3d/glad/glad.c index 79815de5f..02b14db11 100644 --- a/port/fast3d/glad/glad.c +++ b/port/fast3d/glad/glad.c @@ -1,6 +1,6 @@ /* - OpenGL, OpenGL ES loader generated by glad 0.1.36 on Wed Nov 20 09:57:47 2024. + OpenGL, OpenGL ES loader generated by glad 0.1.36 on Wed Oct 8 13:10:56 2025. Language/Generator: C/C++ Specification: gl @@ -10,6 +10,7 @@ GL_APPLE_framebuffer_multisample, GL_ARB_depth_clamp, GL_ARB_framebuffer_object, + GL_ARB_texture_filter_anisotropic, GL_ARB_texture_mirror_clamp_to_edge, GL_ARB_vertex_array_object, GL_EXT_depth_clamp, @@ -17,6 +18,7 @@ GL_EXT_framebuffer_multisample, GL_EXT_framebuffer_object, GL_EXT_gpu_shader4, + GL_EXT_texture_filter_anisotropic, GL_EXT_texture_mirror_clamp_to_edge, GL_KHR_debug, GL_NV_depth_clamp, @@ -27,9 +29,9 @@ Reproducible: False Commandline: - --profile="core" --api="gl=4.1,gles2=3.0" --generator="c" --spec="gl" --no-loader --local-files --extensions="GL_APPLE_framebuffer_multisample,GL_ARB_depth_clamp,GL_ARB_framebuffer_object,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_vertex_array_object,GL_EXT_depth_clamp,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_gpu_shader4,GL_EXT_texture_mirror_clamp_to_edge,GL_KHR_debug,GL_NV_depth_clamp,GL_NV_framebuffer_multisample" + --profile="core" --api="gl=4.1,gles2=3.0" --generator="c" --spec="gl" --no-loader --local-files --extensions="GL_APPLE_framebuffer_multisample,GL_ARB_depth_clamp,GL_ARB_framebuffer_object,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_vertex_array_object,GL_EXT_depth_clamp,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_gpu_shader4,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_mirror_clamp_to_edge,GL_KHR_debug,GL_NV_depth_clamp,GL_NV_framebuffer_multisample" Online: - https://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D4.1&api=gles2%3D3.0&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_vertex_array_object&extensions=GL_EXT_depth_clamp&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_texture_mirror_clamp_to_edge&extensions=GL_KHR_debug&extensions=GL_NV_depth_clamp&extensions=GL_NV_framebuffer_multisample + https://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D4.1&api=gles2%3D3.0&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_texture_filter_anisotropic&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_vertex_array_object&extensions=GL_EXT_depth_clamp&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_mirror_clamp_to_edge&extensions=GL_KHR_debug&extensions=GL_NV_depth_clamp&extensions=GL_NV_framebuffer_multisample */ #include @@ -668,6 +670,7 @@ PFNGLWAITSYNCPROC glad_glWaitSync = NULL; int GLAD_GL_APPLE_framebuffer_multisample = 0; int GLAD_GL_ARB_depth_clamp = 0; int GLAD_GL_ARB_framebuffer_object = 0; +int GLAD_GL_ARB_texture_filter_anisotropic = 0; int GLAD_GL_ARB_texture_mirror_clamp_to_edge = 0; int GLAD_GL_ARB_vertex_array_object = 0; int GLAD_GL_EXT_depth_clamp = 0; @@ -675,6 +678,7 @@ int GLAD_GL_EXT_framebuffer_blit = 0; int GLAD_GL_EXT_framebuffer_multisample = 0; int GLAD_GL_EXT_framebuffer_object = 0; int GLAD_GL_EXT_gpu_shader4 = 0; +int GLAD_GL_EXT_texture_filter_anisotropic = 0; int GLAD_GL_EXT_texture_mirror_clamp_to_edge = 0; int GLAD_GL_KHR_debug = 0; int GLAD_GL_NV_depth_clamp = 0; @@ -1435,12 +1439,14 @@ static int find_extensionsGL(void) { if (!get_exts()) return 0; GLAD_GL_ARB_depth_clamp = has_ext("GL_ARB_depth_clamp"); GLAD_GL_ARB_framebuffer_object = has_ext("GL_ARB_framebuffer_object"); + GLAD_GL_ARB_texture_filter_anisotropic = has_ext("GL_ARB_texture_filter_anisotropic"); GLAD_GL_ARB_texture_mirror_clamp_to_edge = has_ext("GL_ARB_texture_mirror_clamp_to_edge"); GLAD_GL_ARB_vertex_array_object = has_ext("GL_ARB_vertex_array_object"); GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit"); GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample"); GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object"); GLAD_GL_EXT_gpu_shader4 = has_ext("GL_EXT_gpu_shader4"); + GLAD_GL_EXT_texture_filter_anisotropic = has_ext("GL_EXT_texture_filter_anisotropic"); GLAD_GL_KHR_debug = has_ext("GL_KHR_debug"); GLAD_GL_NV_depth_clamp = has_ext("GL_NV_depth_clamp"); free_exts(); @@ -1800,6 +1806,7 @@ static int find_extensionsGLES2(void) { if (!get_exts()) return 0; GLAD_GL_APPLE_framebuffer_multisample = has_ext("GL_APPLE_framebuffer_multisample"); GLAD_GL_EXT_depth_clamp = has_ext("GL_EXT_depth_clamp"); + GLAD_GL_EXT_texture_filter_anisotropic = has_ext("GL_EXT_texture_filter_anisotropic"); GLAD_GL_EXT_texture_mirror_clamp_to_edge = has_ext("GL_EXT_texture_mirror_clamp_to_edge"); GLAD_GL_KHR_debug = has_ext("GL_KHR_debug"); GLAD_GL_NV_framebuffer_multisample = has_ext("GL_NV_framebuffer_multisample"); diff --git a/port/fast3d/glad/glad.h b/port/fast3d/glad/glad.h index 464339558..2d2ed8bb1 100644 --- a/port/fast3d/glad/glad.h +++ b/port/fast3d/glad/glad.h @@ -1,6 +1,6 @@ /* - OpenGL, OpenGL ES loader generated by glad 0.1.36 on Wed Nov 20 09:57:47 2024. + OpenGL, OpenGL ES loader generated by glad 0.1.36 on Wed Oct 8 13:10:56 2025. Language/Generator: C/C++ Specification: gl @@ -10,6 +10,7 @@ GL_APPLE_framebuffer_multisample, GL_ARB_depth_clamp, GL_ARB_framebuffer_object, + GL_ARB_texture_filter_anisotropic, GL_ARB_texture_mirror_clamp_to_edge, GL_ARB_vertex_array_object, GL_EXT_depth_clamp, @@ -17,6 +18,7 @@ GL_EXT_framebuffer_multisample, GL_EXT_framebuffer_object, GL_EXT_gpu_shader4, + GL_EXT_texture_filter_anisotropic, GL_EXT_texture_mirror_clamp_to_edge, GL_KHR_debug, GL_NV_depth_clamp, @@ -27,9 +29,9 @@ Reproducible: False Commandline: - --profile="core" --api="gl=4.1,gles2=3.0" --generator="c" --spec="gl" --no-loader --local-files --extensions="GL_APPLE_framebuffer_multisample,GL_ARB_depth_clamp,GL_ARB_framebuffer_object,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_vertex_array_object,GL_EXT_depth_clamp,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_gpu_shader4,GL_EXT_texture_mirror_clamp_to_edge,GL_KHR_debug,GL_NV_depth_clamp,GL_NV_framebuffer_multisample" + --profile="core" --api="gl=4.1,gles2=3.0" --generator="c" --spec="gl" --no-loader --local-files --extensions="GL_APPLE_framebuffer_multisample,GL_ARB_depth_clamp,GL_ARB_framebuffer_object,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_vertex_array_object,GL_EXT_depth_clamp,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_gpu_shader4,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_mirror_clamp_to_edge,GL_KHR_debug,GL_NV_depth_clamp,GL_NV_framebuffer_multisample" Online: - https://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D4.1&api=gles2%3D3.0&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_vertex_array_object&extensions=GL_EXT_depth_clamp&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_texture_mirror_clamp_to_edge&extensions=GL_KHR_debug&extensions=GL_NV_depth_clamp&extensions=GL_NV_framebuffer_multisample + https://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D4.1&api=gles2%3D3.0&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_texture_filter_anisotropic&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_vertex_array_object&extensions=GL_EXT_depth_clamp&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_mirror_clamp_to_edge&extensions=GL_KHR_debug&extensions=GL_NV_depth_clamp&extensions=GL_NV_framebuffer_multisample */ @@ -2721,6 +2723,8 @@ GLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ; #define glGetInternalformativ glad_glGetInternalformativ #endif #define GL_INDEX 0x8222 +#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF #define GL_MIRROR_CLAMP_TO_EDGE 0x8743 #define GL_READ_FRAMEBUFFER_EXT 0x8CA8 #define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 @@ -2808,6 +2812,8 @@ GLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ; #define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION 0x8244 @@ -2910,6 +2916,10 @@ GLAPI int GLAD_GL_ARB_depth_clamp; #define GL_ARB_framebuffer_object 1 GLAPI int GLAD_GL_ARB_framebuffer_object; #endif +#ifndef GL_ARB_texture_filter_anisotropic +#define GL_ARB_texture_filter_anisotropic 1 +GLAPI int GLAD_GL_ARB_texture_filter_anisotropic; +#endif #ifndef GL_ARB_texture_mirror_clamp_to_edge #define GL_ARB_texture_mirror_clamp_to_edge 1 GLAPI int GLAD_GL_ARB_texture_mirror_clamp_to_edge; @@ -3093,6 +3103,10 @@ typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC)(GLuint index, GLenum pn GLAPI PFNGLGETVERTEXATTRIBIUIVEXTPROC glad_glGetVertexAttribIuivEXT; #define glGetVertexAttribIuivEXT glad_glGetVertexAttribIuivEXT #endif +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +GLAPI int GLAD_GL_EXT_texture_filter_anisotropic; +#endif #ifndef GL_KHR_debug #define GL_KHR_debug 1 GLAPI int GLAD_GL_KHR_debug; @@ -3181,6 +3195,10 @@ GLAPI PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC glad_glResolveMultisampleFrame #define GL_EXT_depth_clamp 1 GLAPI int GLAD_GL_EXT_depth_clamp; #endif +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +GLAPI int GLAD_GL_EXT_texture_filter_anisotropic; +#endif #ifndef GL_EXT_texture_mirror_clamp_to_edge #define GL_EXT_texture_mirror_clamp_to_edge 1 GLAPI int GLAD_GL_EXT_texture_mirror_clamp_to_edge; diff --git a/port/include/video.h b/port/include/video.h index a9ba16262..d0a81a29d 100644 --- a/port/include/video.h +++ b/port/include/video.h @@ -39,6 +39,8 @@ s32 videoGetCenterWindow(void); void videoSetCenterWindow(s32 center); u32 videoGetTextureFilter(void); s32 videoGetTextureFilter2D(void); +u32 videoGetAnisotropicFilter(void); +u32 videoGetMaxAnisotropyLevel(void); s32 videoGetDetailTextures(void); s32 videoGetDisplayModeIndex(void); s32 videoGetDisplayMode(displaymode *out, const s32 index); @@ -55,6 +57,7 @@ void videoSetFullscreen(s32 fs); void videoSetFullscreenMode(s32 mode); void videoSetTextureFilter(u32 filter); void videoSetTextureFilter2D(s32 filter); +void videoSetAnisotropicFilter(u32 filter); void videoSetDetailTextures(s32 detail); void videoSetDisplayMode(const s32 index); void videoSetVsync(const s32 vsync); diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index 139059800..415ff6331 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -908,6 +908,20 @@ static MenuItemHandlerResult menuhandlerTexFilter2D(s32 operation, struct menuit return 0; } +static MenuItemHandlerResult menuhandlerAnisotropicFiltering(s32 operation, struct menuitem *item, union handlerdata *data) +{ + switch (operation) { + case MENUOP_GETSLIDER: + data->slider.value = videoGetAnisotropicFilter(); + break; + case MENUOP_SET: + videoSetAnisotropicFilter(data->slider.value); + break; + } + + return 0; +} + static MenuItemHandlerResult menuhandlerDisplayFPS(s32 operation, struct menuitem *item, union handlerdata *data) { switch (operation) { @@ -1099,6 +1113,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, menuhandlerTexFilter2D, }, + { + MENUITEMTYPE_SLIDER, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, + (uintptr_t)"Anisotropic Filtering", + 8, + menuhandlerAnisotropicFiltering, + }, { MENUITEMTYPE_CHECKBOX, 0, @@ -1947,3 +1969,23 @@ struct menudialogdef g_ExtendedMenuDialog = { MENUDIALOGFLAG_LITERAL_TEXT, NULL, }; + +void updateMaxAnisotropyLevel() +{ + for (int i = 0; i < ARRAYCOUNT(g_ExtendedVideoMenuItems); ++i) { + struct menuitem *item = &g_ExtendedVideoMenuItems[i]; + const char *text = menuResolveParam2Text(item); + if (text == NULL) continue; + + if (strstr(text, "Anisotropic Filtering") != NULL) { + item->param3 = videoGetMaxAnisotropyLevel(); + break; + } + } + +} + +void optionsMenuInit() +{ + updateMaxAnisotropyLevel(); +} diff --git a/port/src/video.c b/port/src/video.c index 1ba256243..63ad78293 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -53,6 +53,8 @@ static displaymode *vidModes = &vidModeDefault; static s32 texFilter = FILTER_LINEAR; static s32 texFilter2D = true; static s32 texDetail = false; +static s32 texMipmapFilter = MIPMAP_LINEAR; +static u32 texAnisotropicFilter = 4; static u32 dlcount = 0; static u32 frames = 0; @@ -62,6 +64,7 @@ static f64 fpsTime = 0.0; static s32 fpsNumFrames = 0; static s32 videoInitDisplayModes(void); +void optionsMenuInit(); s32 videoInit(void) { @@ -99,6 +102,9 @@ s32 videoInit(void) videoSetFramerateLimit(vidFramerateLimit); gfx_set_texture_filter((enum FilteringMode)texFilter); + gfx_set_mipmap_filter((enum MipmapFilteringMode)texMipmapFilter); + videoSetAnisotropicFilter(texAnisotropicFilter); + optionsMenuInit(); initDone = true; return 0; @@ -362,6 +368,16 @@ u32 videoGetTextureFilter(void) return texFilter; } +u32 videoGetAnisotropicFilter() +{ + return texAnisotropicFilter; +} + +u32 videoGetMaxAnisotropyLevel() +{ + return renderingAPI->get_max_anisotropy_level(); +} + s32 videoGetDetailTextures(void) { return texDetail; @@ -434,6 +450,12 @@ void videoSetTextureFilter2D(s32 filter) texFilter2D = !!filter; } +void videoSetAnisotropicFilter(u32 level) +{ + texAnisotropicFilter = level; + renderingAPI->set_anisotropy_level(level); +} + void videoSetDetailTextures(s32 detail) { texDetail = !!detail; @@ -531,4 +553,6 @@ PD_CONSTRUCTOR static void videoConfigInit(void) configRegisterInt("Video.TextureFilter", &texFilter, 0, 2); configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1); configRegisterInt("Video.DetailTextures", &texDetail, 0, 1); + configRegisterInt("Video.MipmapFilter", &texMipmapFilter, 0, 2); + configRegisterInt("Video.AnisotropicFilter", &texAnisotropicFilter, 0, 16); }