From 95445e7b7f75752553c4f15beabcb0e89c472a43 Mon Sep 17 00:00:00 2001 From: James R Larrowe Date: Sun, 25 Aug 2024 00:02:13 -0400 Subject: [PATCH 1/4] Fix scaling on HiDPI screens with Wayland The game expects getWidth and getHeight to return framebuffer coordinates rather than screen-space coordinates (as shown by the calls to glViewport). This was broken on scaling factors greater than 1 but also masked by GL_SCALE_FRAMEBUFFER. Additionally, the game's mouse code *also* expects framebuffer coordinates to be returned. This fixes that by converting to and from screen-space during calls to mouse code. Disable GLFW_COCOA_RETINA_FRAMEBUFFER for now, it seems to not play nice on non-MacOS systems. At least for me it makes the title screen larger than the window when playing in fullscreen --- src/main/java/org/lwjglx/input/Mouse.java | 12 +++++++++++- src/main/java/org/lwjglx/opengl/Display.java | 17 ++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/lwjglx/input/Mouse.java b/src/main/java/org/lwjglx/input/Mouse.java index dd4e799e..fed42708 100644 --- a/src/main/java/org/lwjglx/input/Mouse.java +++ b/src/main/java/org/lwjglx/input/Mouse.java @@ -53,6 +53,10 @@ public static void addMoveEvent(double mouseX, double mouseY) { ignoreNextMove--; return; } + float scale = Display.getPixelScaleFactor(); + // convert from screen-space coordinates to framebuffer coordinates + mouseX *= scale; + mouseY *= scale; dx += (int) mouseX - latestX; dy += Display.getHeight() - (int) mouseY - latestY; latestX = (int) mouseX; @@ -279,7 +283,13 @@ public static void setCursorPosition(int new_x, int new_y) { if (grabbed) { return; } - GLFW.glfwSetCursorPos(Display.getWindow(), new_x, new_y); + // convert back from framebuffer coordinates to screen-space coordinates + float inv_scale = 1.0f / Display.getPixelScaleFactor(); + new_x *= inv_scale; + new_y *= inv_scale; + GLFW.glfwSetCursorPos(Display.getWindow(), new_x * inv_scale, new_y * inv_scale); + // this might lose accuracy, since we just went from fb->screen and this will + // undo that change. Yay floating point numbers! addMoveEvent(new_x, new_y); } diff --git a/src/main/java/org/lwjglx/opengl/Display.java b/src/main/java/org/lwjglx/opengl/Display.java index a045c55e..8163fbe4 100644 --- a/src/main/java/org/lwjglx/opengl/Display.java +++ b/src/main/java/org/lwjglx/opengl/Display.java @@ -195,8 +195,8 @@ public static void create(PixelFormat pixelFormat, ContextAttribs attribs, long glfwWindowHintString(GLFW_X11_CLASS_NAME, Config.X11_CLASS_NAME); glfwWindowHintString(GLFW_COCOA_FRAME_NAME, Config.COCOA_FRAME_NAME); - glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); // request a non-hidpi framebuffer on Retina displays - // on MacOS + // request a non-hidpi framebuffer on Retina displays on MacOS + // glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); if (Config.WINDOW_CENTERED) { glfwWindowHint(GLFW_POSITION_X, (monitorWidth - mode.getWidth()) / 2); @@ -607,19 +607,14 @@ public static int getY() { return displayY; } + // vanilla and forge both expect these to return the framebuffer width + // rather than the window width, and they both call glViewport with the + // result public static int getWidth() { - return displayWidth; - } - - public static int getHeight() { - return displayHeight; - } - - public static int getFramebufferWidth() { return displayFramebufferWidth; } - public static int getFramebufferHeight() { + public static int getHeight() { return displayFramebufferHeight; } From 2b5c73cead8429e8ca5283cfe4d364cdd421ebae Mon Sep 17 00:00:00 2001 From: James R Larrowe Date: Sun, 25 Aug 2024 02:16:51 -0400 Subject: [PATCH 2/4] add back hack for macOS I think their framebuffer implementation is buggy? I don't really want to touch this since I don't have a Mac to test on I think their GPUs are weak anyways and probably can't handle rendering GTNH at 260 DPI or whatever Retina does --- src/main/java/org/lwjglx/opengl/Display.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/lwjglx/opengl/Display.java b/src/main/java/org/lwjglx/opengl/Display.java index 8163fbe4..6a671ccf 100644 --- a/src/main/java/org/lwjglx/opengl/Display.java +++ b/src/main/java/org/lwjglx/opengl/Display.java @@ -196,7 +196,7 @@ public static void create(PixelFormat pixelFormat, ContextAttribs attribs, long glfwWindowHintString(GLFW_COCOA_FRAME_NAME, Config.COCOA_FRAME_NAME); // request a non-hidpi framebuffer on Retina displays on MacOS - // glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); + if (glfwGetPlatform() == GLFW_PLATFORM_COCOA) glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); if (Config.WINDOW_CENTERED) { glfwWindowHint(GLFW_POSITION_X, (monitorWidth - mode.getWidth()) / 2); From b0a2004de484a58eae05e2e10448fe272164b293 Mon Sep 17 00:00:00 2001 From: James R Larrowe Date: Sun, 1 Sep 2024 14:23:34 -0400 Subject: [PATCH 3/4] Fix getPixelScaleFactor Previous implementation was broken on hidpi platforms where the size of the framebuffer and the size of the window correlate 1:1. This manifested in the mouse code thinking the mouse was in a different location than it actually was. New implementation explicitly calculates the ratio between the framebuffer size and the window size, rather than relying on glfwGetWindowContentScale. Remove GLFW_SCALE_FRAMEBUFFER/GLFW_COCOA_RETINA_FRAMEBUFFER, it appears that it is not needed. --- src/main/java/org/lwjglx/opengl/Display.java | 21 +++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/lwjglx/opengl/Display.java b/src/main/java/org/lwjglx/opengl/Display.java index 6a671ccf..edccc152 100644 --- a/src/main/java/org/lwjglx/opengl/Display.java +++ b/src/main/java/org/lwjglx/opengl/Display.java @@ -195,9 +195,6 @@ public static void create(PixelFormat pixelFormat, ContextAttribs attribs, long glfwWindowHintString(GLFW_X11_CLASS_NAME, Config.X11_CLASS_NAME); glfwWindowHintString(GLFW_COCOA_FRAME_NAME, Config.COCOA_FRAME_NAME); - // request a non-hidpi framebuffer on Retina displays on MacOS - if (glfwGetPlatform() == GLFW_PLATFORM_COCOA) glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); - if (Config.WINDOW_CENTERED) { glfwWindowHint(GLFW_POSITION_X, (monitorWidth - mode.getWidth()) / 2); glfwWindowHint(GLFW_POSITION_Y, (monitorHeight - mode.getHeight()) / 2); @@ -887,10 +884,20 @@ public static float getPixelScaleFactor() { if (!isCreated()) { return 1.0f; } - float[] xScale = new float[1]; - float[] yScale = new float[1]; - glfwGetWindowContentScale(getWindow(), xScale, yScale); - return Math.max(xScale[0], yScale[0]); + int[] windowWidth = new int[1]; + int[] windowHeight = new int[1]; + int[] framebufferWidth = new int[1]; + int[] framebufferHeight = new int[1]; + float xScale, yScale; + // via technicality we actually have to divide the framebuffer + // size by the window size here, since glfwGetWindowContentScale + // returns a value not equal to 1 even on platforms where the + // framebuffer size and window size always map 1:1 + glfwGetWindowSize(getWindow(), windowWidth, windowHeight); + glfwGetFramebufferSize(getWindow(), framebufferWidth, framebufferHeight); + xScale = (float)framebufferWidth[0]/windowWidth[0]; + yScale = (float)framebufferHeight[0]/windowHeight[0]; + return Math.max(xScale, yScale); } public static void setSwapInterval(int value) { From bd820ddfdcfd9cb9b522444a3424fba2b04e1f2f Mon Sep 17 00:00:00 2001 From: James R Larrowe Date: Sun, 1 Sep 2024 14:31:22 -0400 Subject: [PATCH 4/4] fucking spotless --- src/main/java/org/lwjglx/opengl/Display.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/lwjglx/opengl/Display.java b/src/main/java/org/lwjglx/opengl/Display.java index edccc152..ec96337d 100644 --- a/src/main/java/org/lwjglx/opengl/Display.java +++ b/src/main/java/org/lwjglx/opengl/Display.java @@ -895,8 +895,8 @@ public static float getPixelScaleFactor() { // framebuffer size and window size always map 1:1 glfwGetWindowSize(getWindow(), windowWidth, windowHeight); glfwGetFramebufferSize(getWindow(), framebufferWidth, framebufferHeight); - xScale = (float)framebufferWidth[0]/windowWidth[0]; - yScale = (float)framebufferHeight[0]/windowHeight[0]; + xScale = (float) framebufferWidth[0] / windowWidth[0]; + yScale = (float) framebufferHeight[0] / windowHeight[0]; return Math.max(xScale, yScale); }