From 1a2e03de4715c2eac30a7442128f2598f80b3d28 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Wed, 23 Jul 2025 13:18:05 -0700 Subject: [PATCH] Make Anisotropic filtering configurable (#641) --- ISLE/isleapp.cpp | 4 ++- ISLE/isleapp.h | 1 + LEGO1/mxdirectx/mxdirect3d.cpp | 1 + LEGO1/mxdirectx/mxdirectxinfo.cpp | 1 + LEGO1/omni/include/mxvideoparam.h | 4 +++ LEGO1/omni/src/video/mxvideoparam.cpp | 3 ++ miniwin/include/miniwin/miniwind3d.h | 2 ++ .../src/d3drm/backends/opengles3/renderer.cpp | 32 +++++++++++++------ miniwin/src/d3drm/d3drmrenderer.cpp | 7 +++- miniwin/src/ddraw/ddraw.cpp | 11 ------- .../src/internal/d3drmrenderer_opengles3.h | 15 +++++++-- miniwin/src/internal/ddraw_impl.h | 15 +++++++-- 12 files changed, 69 insertions(+), 27 deletions(-) diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index b2a39dcc..c8e9f980 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -183,6 +183,7 @@ IsleApp::IsleApp() m_frameRate = 100.0f; m_exclusiveFullScreen = FALSE; m_msaaSamples = 0; + m_anisotropic = 0.0f; } // FUNCTION: ISLE 0x4011a0 @@ -1190,7 +1191,8 @@ bool IsleApp::LoadConfig() } m_frameRate = (1000.0f / iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta)); m_frameDelta = static_cast(std::round(iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta))); - m_videoParam.SetMSAASamples(iniparser_getint(dict, "isle:MSAA", m_msaaSamples)); + m_videoParam.SetMSAASamples((m_msaaSamples = iniparser_getint(dict, "isle:MSAA", m_msaaSamples))); + m_videoParam.SetAnisotropic((m_anisotropic = iniparser_getdouble(dict, "isle:Anisotropic", m_anisotropic))); const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL); if (deviceId != NULL) { diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index 7346d817..66e8e6e1 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -115,6 +115,7 @@ private: MxFloat m_frameRate; MxBool m_exclusiveFullScreen; MxU32 m_msaaSamples; + MxFloat m_anisotropic; }; extern IsleApp* g_isle; diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp index 5eacf824..84ff77d3 100644 --- a/LEGO1/mxdirectx/mxdirect3d.cpp +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -81,6 +81,7 @@ BOOL MxDirect3D::Create( #endif if (videoParam) { miniwind3d->RequestMSAA(videoParam->GetMSAASamples()); + miniwind3d->RequestAnisotropic(videoParam->GetAnisotropic()); } } diff --git a/LEGO1/mxdirectx/mxdirectxinfo.cpp b/LEGO1/mxdirectx/mxdirectxinfo.cpp index bbff9534..765d32f7 100644 --- a/LEGO1/mxdirectx/mxdirectxinfo.cpp +++ b/LEGO1/mxdirectx/mxdirectxinfo.cpp @@ -238,6 +238,7 @@ BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc #endif if (videoParam) { miniwind3d->RequestMSAA(videoParam->GetMSAASamples()); + miniwind3d->RequestAnisotropic(videoParam->GetAnisotropic()); } } diff --git a/LEGO1/omni/include/mxvideoparam.h b/LEGO1/omni/include/mxvideoparam.h index af2fcddf..cd425ba9 100644 --- a/LEGO1/omni/include/mxvideoparam.h +++ b/LEGO1/omni/include/mxvideoparam.h @@ -56,6 +56,9 @@ public: void SetMSAASamples(MxU32 p_msaaSamples) { m_msaaSamples = p_msaaSamples; } MxU32 GetMSAASamples() { return m_msaaSamples; } + void SetAnisotropic(MxFloat p_anisotropic) { m_anisotropic = p_anisotropic; } + MxFloat GetAnisotropic() { return m_anisotropic; } + private: MxRect32 m_rect; // 0x00 MxPalette* m_palette; // 0x10 @@ -64,6 +67,7 @@ private: int m_unk0x1c; // 0x1c char* m_deviceId; // 0x20 MxU32 m_msaaSamples; + MxFloat m_anisotropic; }; #endif // MXVIDEOPARAM_H diff --git a/LEGO1/omni/src/video/mxvideoparam.cpp b/LEGO1/omni/src/video/mxvideoparam.cpp index 7c029e52..45a9a688 100644 --- a/LEGO1/omni/src/video/mxvideoparam.cpp +++ b/LEGO1/omni/src/video/mxvideoparam.cpp @@ -29,6 +29,7 @@ MxVideoParam::MxVideoParam(MxRect32& p_rect, MxPalette* p_palette, MxULong p_bac m_unk0x1c = 0; m_deviceId = NULL; m_msaaSamples = 0; + m_anisotropic = 0.0f; } // FUNCTION: LEGO1 0x100becf0 @@ -43,6 +44,7 @@ MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam) m_deviceId = NULL; SetDeviceName(p_videoParam.m_deviceId); m_msaaSamples = p_videoParam.m_msaaSamples; + m_anisotropic = p_videoParam.m_anisotropic; } // FUNCTION: LEGO1 0x100bed50 @@ -85,6 +87,7 @@ MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam) m_unk0x1c = p_videoParam.m_unk0x1c; SetDeviceName(p_videoParam.m_deviceId); m_msaaSamples = p_videoParam.m_msaaSamples; + m_anisotropic = p_videoParam.m_anisotropic; return *this; } diff --git a/miniwin/include/miniwin/miniwind3d.h b/miniwin/include/miniwin/miniwind3d.h index 8204af17..aea2e25c 100644 --- a/miniwin/include/miniwin/miniwind3d.h +++ b/miniwin/include/miniwin/miniwind3d.h @@ -5,4 +5,6 @@ DEFINE_GUID(IID_IDirect3DMiniwin, 0xf8a97f2d, 0x9b3a, 0x4f1c, 0x9e, 0x8d, 0x6a, struct IDirect3DMiniwin : virtual public IUnknown { virtual HRESULT RequestMSAA(DWORD msaaSamples) = 0; virtual DWORD GetMSAASamples() const = 0; + virtual HRESULT RequestAnisotropic(float anisotropic) = 0; + virtual float GetAnisotropic() const = 0; }; diff --git a/miniwin/src/d3drm/backends/opengles3/renderer.cpp b/miniwin/src/d3drm/backends/opengles3/renderer.cpp index 5c3ac1e5..e2304ce5 100644 --- a/miniwin/src/d3drm/backends/opengles3/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles3/renderer.cpp @@ -37,7 +37,7 @@ struct SceneLightGLES3 { float direction[4]; }; -Direct3DRMRenderer* OpenGLES3Renderer::Create(DWORD width, DWORD height, DWORD msaaSamples) +Direct3DRMRenderer* OpenGLES3Renderer::Create(DWORD width, DWORD height, DWORD msaaSamples, float anisotropic) { // We have to reset the attributes here after having enumerated the // OpenGL ES 2.0 renderer, or else SDL gets very confused by SDL_GL_DEPTH_SIZE @@ -179,7 +179,7 @@ Direct3DRMRenderer* OpenGLES3Renderer::Create(DWORD width, DWORD height, DWORD m glDeleteShader(vs); glDeleteShader(fs); - return new OpenGLES3Renderer(width, height, msaaSamples, context, shaderProgram); + return new OpenGLES3Renderer(width, height, msaaSamples, anisotropic, context, shaderProgram); } GLES3MeshCacheEntry OpenGLES3Renderer::GLES3UploadMesh(const MeshGroup& meshGroup, bool forceUV) @@ -259,7 +259,7 @@ GLES3MeshCacheEntry OpenGLES3Renderer::GLES3UploadMesh(const MeshGroup& meshGrou return cache; } -bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI) +bool OpenGLES3Renderer::UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI) { SDL_Surface* surf = source; if (source->format != SDL_PIXELFORMAT_RGBA32) { @@ -284,11 +284,8 @@ bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if (SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic")) { - GLfloat maxAniso = 0.0f; - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso); - GLfloat desiredAniso = fminf(8.0f, maxAniso); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, desiredAniso); + if (m_anisotropic > 1.0f) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_anisotropic); } glGenerateMipmap(GL_TEXTURE_2D); } @@ -304,10 +301,11 @@ OpenGLES3Renderer::OpenGLES3Renderer( DWORD width, DWORD height, DWORD msaaSamples, + float anisotropic, SDL_GLContext context, GLuint shaderProgram ) - : m_context(context), m_shaderProgram(shaderProgram), m_msaa(msaaSamples) + : m_context(context), m_shaderProgram(shaderProgram), m_msaa(msaaSamples), m_anisotropic(anisotropic) { glGenFramebuffers(1, &m_fbo); glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); @@ -329,6 +327,22 @@ OpenGLES3Renderer::OpenGLES3Renderer( glGenFramebuffers(1, &m_resolveFBO); } + bool anisoAvailable = SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic"); + GLfloat maxAniso = 0.0f; + if (anisoAvailable) { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso); + } + if (m_anisotropic > maxAniso) { + m_anisotropic = maxAniso; + } + SDL_Log( + "Anisotropic is %s. Requested: %f, active: %f, max aniso: %f", + m_anisotropic > 1.0f ? "on" : "off", + anisotropic, + m_anisotropic, + maxAniso + ); + m_virtualWidth = width; m_virtualHeight = height; ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f}; diff --git a/miniwin/src/d3drm/d3drmrenderer.cpp b/miniwin/src/d3drm/d3drmrenderer.cpp index a19b31fb..8fe210b5 100644 --- a/miniwin/src/d3drm/d3drmrenderer.cpp +++ b/miniwin/src/d3drm/d3drmrenderer.cpp @@ -36,7 +36,12 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer( #endif #ifdef USE_OPENGLES3 if (SDL_memcmp(guid, &OpenGLES3_GUID, sizeof(GUID)) == 0) { - return OpenGLES3Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples()); + return OpenGLES3Renderer::Create( + DDSDesc.dwWidth, + DDSDesc.dwHeight, + d3d->GetMSAASamples(), + d3d->GetAnisotropic() + ); } #endif #ifdef USE_OPENGL1 diff --git a/miniwin/src/ddraw/ddraw.cpp b/miniwin/src/ddraw/ddraw.cpp index bb0e40ce..b28a105b 100644 --- a/miniwin/src/ddraw/ddraw.cpp +++ b/miniwin/src/ddraw/ddraw.cpp @@ -331,17 +331,6 @@ HRESULT DirectDrawImpl::CreateDevice( return DD_OK; } -HRESULT DirectDrawImpl::RequestMSAA(DWORD msaaSamples) -{ - m_msaaSamples = msaaSamples; - return DD_OK; -} - -DWORD DirectDrawImpl::GetMSAASamples() const -{ - return m_msaaSamples; -} - HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context) { const char* driverName = SDL_GetCurrentVideoDriver(); diff --git a/miniwin/src/internal/d3drmrenderer_opengles3.h b/miniwin/src/internal/d3drmrenderer_opengles3.h index 1e029cd8..e3f3f59d 100644 --- a/miniwin/src/internal/d3drmrenderer_opengles3.h +++ b/miniwin/src/internal/d3drmrenderer_opengles3.h @@ -33,8 +33,15 @@ struct GLES3MeshCacheEntry { class OpenGLES3Renderer : public Direct3DRMRenderer { public: - static Direct3DRMRenderer* Create(DWORD width, DWORD height, DWORD msaaSamples); - OpenGLES3Renderer(DWORD width, DWORD height, DWORD msaaSamples, SDL_GLContext context, GLuint shaderProgram); + static Direct3DRMRenderer* Create(DWORD width, DWORD height, DWORD msaaSamples, float anisotropic); + OpenGLES3Renderer( + DWORD width, + DWORD height, + DWORD msaaSamples, + float anisotropic, + SDL_GLContext context, + GLuint shaderProgram + ); ~OpenGLES3Renderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; @@ -64,6 +71,7 @@ private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); GLES3MeshCacheEntry GLES3UploadMesh(const MeshGroup& meshGroup, bool forceUV = false); + bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI); MeshGroup m_uiMesh; GLES3MeshCacheEntry m_uiMeshCache; @@ -75,6 +83,7 @@ private: std::vector m_lights; SDL_GLContext m_context; uint32_t m_msaa; + float m_anisotropic; GLuint m_fbo; GLuint m_resolveFBO; GLuint m_colorTarget; @@ -99,7 +108,7 @@ private: inline static void OpenGLES3Renderer_EnumDevice(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx) { - Direct3DRMRenderer* device = OpenGLES3Renderer::Create(640, 480, d3d->GetMSAASamples()); + Direct3DRMRenderer* device = OpenGLES3Renderer::Create(640, 480, d3d->GetMSAASamples(), d3d->GetAnisotropic()); if (!device) { return; } diff --git a/miniwin/src/internal/ddraw_impl.h b/miniwin/src/internal/ddraw_impl.h index ac4e01a9..0da2d883 100644 --- a/miniwin/src/internal/ddraw_impl.h +++ b/miniwin/src/internal/ddraw_impl.h @@ -47,14 +47,25 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2, public IDirect3D override; HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) override; // IDirect3DMiniwin interface - HRESULT RequestMSAA(DWORD msaaSamples) override; - DWORD GetMSAASamples() const override; + HRESULT RequestMSAA(DWORD msaaSamples) override + { + m_msaaSamples = msaaSamples; + return DD_OK; + } + DWORD GetMSAASamples() const override { return m_msaaSamples; } + HRESULT RequestAnisotropic(float anisotropic) override + { + m_anisotropic = anisotropic; + return DD_OK; + } + float GetAnisotropic() const override { return m_anisotropic; } private: FrameBufferImpl* m_frameBuffer; int m_virtualWidth = 0; int m_virtualHeight = 0; DWORD m_msaaSamples = 0; + float m_anisotropic = 0.0f; }; HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context);