diff --git a/src/main/java/cc/fros/util/render/FrosFont.java b/src/main/java/cc/fros/util/render/FrosFont.java index 61e4c20..8ca728d 100644 --- a/src/main/java/cc/fros/util/render/FrosFont.java +++ b/src/main/java/cc/fros/util/render/FrosFont.java @@ -82,6 +82,7 @@ public final class FrosFont { private static FontMetrics metrics; private static String loadedName; private static float loadedSize = Float.NaN; + private static int loadedScale = 1; private static long lastAttempt; private static int glyphCounter; @@ -92,7 +93,7 @@ public final class FrosFont { if (text == null || text.isEmpty()) return 0; sync(); if (awtFont == null) return mc.font.width(text); - return metrics.stringWidth(stripCodes(text)); + return toGui(metrics.stringWidth(stripCodes(text))); } public static int width(Component component) { @@ -104,7 +105,20 @@ public final class FrosFont { public static int lineHeight() { sync(); - return awtFont == null ? mc.font.lineHeight : metrics.getHeight(); + return awtFont == null ? mc.font.lineHeight : toGui(metrics.getHeight()); + } + + /** converts a raster pixel measurement to gui units */ + private static int toGui(int pixels) { + return (pixels + loadedScale - 1) / loadedScale; + } + + private static int currentScale() { + try { + return Math.max(1, (int) Math.round(mc.getWindow().getGuiScale())); + } catch (Exception e) { + return 1; + } } public static void draw(GuiGraphics context, String text, int x, int y, int color) { @@ -140,20 +154,22 @@ public final class FrosFont { String name = gui == null || vanilla ? "" : gui.font.getValue(); int size = gui == null ? 10 : gui.fontSize.getValue(); if (name == null) name = ""; + int scale = currentScale(); - boolean changed = !Objects.equals(name, loadedName) || size != loadedSize; + boolean changed = !Objects.equals(name, loadedName) || size != loadedSize || scale != loadedScale; if (!changed) { boolean missing = awtFont == null && !name.isBlank(); // retry a missing file every couple of seconds so dropping one // into the folder loads without touching the setting again if (!missing || System.currentTimeMillis() - lastAttempt < 2000) return; } - reset(name, size, changed); + reset(name, size, scale, changed); } - private static void reset(String name, float size, boolean verbose) { + private static void reset(String name, float size, int scale, boolean verbose) { loadedName = name; loadedSize = size; + loadedScale = scale; lastAttempt = System.currentTimeMillis(); awtFont = null; metrics = null; @@ -170,13 +186,13 @@ public final class FrosFont { Path file = resolveFontFile(name); if (file != null) { applyFont(java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, file.toFile()), - size, "Loaded font " + file.getFileName(), verbose); + size * scale, "Loaded font " + file.getFileName(), verbose); return; } java.awt.Font installed = installedFont(name); if (installed != null) { - applyFont(installed, size, "Using system font '" + name + "'", verbose); + applyFont(installed, size * scale, "Using system font '" + name + "'", verbose); return; } @@ -279,18 +295,28 @@ public final class FrosFont { if (glyph == null) return; GLYPHS.put(key, glyph); } + + // the bitmap is rasterized at device resolution (one texel per screen + // pixel); scale the pose down into gui space so the gpu never has to + // magnify it with nearest-neighbour sampling + float scale = loadedScale; + context.pose().pushMatrix(); + context.pose().scale(1f / scale, 1f / scale); + context.pose().translate((x - 1) * scale, (y - 1) * scale); context.blit(RenderPipelines.GUI_TEXTURED, glyph.id(), - x - 1, y - 1, 0.0f, 0.0f, glyph.width(), glyph.height(), glyph.width(), glyph.height()); + 0, 0, 0.0f, 0.0f, glyph.width(), glyph.height(), glyph.width(), glyph.height()); + context.pose().popMatrix(); } private static Glyph createGlyph(String text, int baseColor) { String plain = stripCodes(text); if (plain.isEmpty()) return null; + int pad = loadedScale; int width = Math.max(1, metrics.stringWidth(plain)); int height = metrics.getHeight(); - int imageWidth = width + 2; - int imageHeight = height + 2; + int imageWidth = width + 2 * pad; + int imageHeight = height + 2 * pad; BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = image.createGraphics(); @@ -319,7 +345,7 @@ public final class FrosFont { } private static void drawSegments(Graphics2D graphics, String text, int baseColor) { - int baseline = metrics.getAscent() + 1; + int baseline = metrics.getAscent() + loadedScale; int cursor = 1; int current = baseColor; int segmentStart = 0;