From 828bec5fb56721945d287c6ee4d8bfb0c69b0cac Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 16 Jun 2026 12:02:07 +0200 Subject: [PATCH] @ fix(D.2b): point-sample the dat-font atlas so UI text is pixel-crisp The font glyph atlas was uploaded with bilinear (Linear) min/mag filtering, which softens the small dat-font glyphs (the menu/button text "blur"). Add a nearest-filter path to UploadRgba8/GetOrUploadRenderSurface and use it for the font atlases only (world + other UI surfaces keep bilinear). Combined with the existing per-glyph pixel-snap, glyph texels now map 1:1 to screen pixels. Sharpens all dat-font text (transcript, menu, Send/Chat buttons, vitals numbers). Co-Authored-By: Claude Opus 4.8 (1M context) @ --- src/AcDream.App/Rendering/TextureCache.cs | 13 ++++++++----- src/AcDream.App/UI/UiDatFont.cs | 6 ++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/AcDream.App/Rendering/TextureCache.cs b/src/AcDream.App/Rendering/TextureCache.cs index 1fbf0817..7d1c0b25 100644 --- a/src/AcDream.App/Rendering/TextureCache.cs +++ b/src/AcDream.App/Rendering/TextureCache.cs @@ -119,7 +119,7 @@ public sealed unsafe class TextureCache : Wb.ITextureCachePerInstance, IDisposab /// Magenta — wire a UI palette when one is actually encountered). Returns a /// 1x1 magenta handle on miss. /// - public uint GetOrUploadRenderSurface(uint renderSurfaceId, out int width, out int height) + public uint GetOrUploadRenderSurface(uint renderSurfaceId, out int width, out int height, bool nearest = false) { if (_handlesByRenderSurfaceId.TryGetValue(renderSurfaceId, out var existing) && _rsSizeById.TryGetValue(renderSurfaceId, out var sz)) @@ -139,7 +139,7 @@ public sealed unsafe class TextureCache : Wb.ITextureCachePerInstance, IDisposab decoded = DecodedTexture.Magenta; } - uint h = UploadRgba8(decoded); + uint h = UploadRgba8(decoded, nearest); _handlesByRenderSurfaceId[renderSurfaceId] = h; _rsSizeById[renderSurfaceId] = (decoded.Width, decoded.Height); width = decoded.Width; height = decoded.Height; @@ -542,7 +542,7 @@ public sealed unsafe class TextureCache : Wb.ITextureCachePerInstance, IDisposab return composed; } - private uint UploadRgba8(DecodedTexture decoded) + private uint UploadRgba8(DecodedTexture decoded, bool nearest = false) { uint tex = _gl.GenTexture(); _gl.BindTexture(TextureTarget.Texture2D, tex); @@ -559,8 +559,11 @@ public sealed unsafe class TextureCache : Wb.ITextureCachePerInstance, IDisposab PixelType.UnsignedByte, p); - _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); - _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + // Point (nearest) sampling for pixel-exact UI text — bilinear softens the dat + // font's small glyphs. Other surfaces use bilinear. + int filter = nearest ? (int)TextureMinFilter.Nearest : (int)TextureMinFilter.Linear; + _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, filter); + _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, filter); _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat); _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat); diff --git a/src/AcDream.App/UI/UiDatFont.cs b/src/AcDream.App/UI/UiDatFont.cs index c08e20de..400ccf0f 100644 --- a/src/AcDream.App/UI/UiDatFont.cs +++ b/src/AcDream.App/UI/UiDatFont.cs @@ -101,11 +101,13 @@ public sealed class UiDatFont if (font.ForegroundSurfaceDataId == 0) return null; - uint fgTex = cache.GetOrUploadRenderSurface(font.ForegroundSurfaceDataId, out int fgW, out int fgH); + // Point-sample the glyph atlases (nearest) so small UI text stays pixel-crisp; + // bilinear softens the dat font noticeably (the chat menu/button text "blur"). + uint fgTex = cache.GetOrUploadRenderSurface(font.ForegroundSurfaceDataId, out int fgW, out int fgH, nearest: true); uint bgTex = 0; int bgW = 0, bgH = 0; if (font.BackgroundSurfaceDataId != 0) - bgTex = cache.GetOrUploadRenderSurface(font.BackgroundSurfaceDataId, out bgW, out bgH); + bgTex = cache.GetOrUploadRenderSurface(font.BackgroundSurfaceDataId, out bgW, out bgH, nearest: true); // Build the char->descriptor lookup. FontCharDesc.Unicode is the code // point; for Latin-1 fonts this is a direct char cast. Last write wins