Skip to content

Commit

Permalink
Fix scaling on HiDPI screens with Wayland (#171)
Browse files Browse the repository at this point in the history
* 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

* 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

* 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.

* fucking spotless
  • Loading branch information
JL2210 authored Sep 13, 2024
1 parent 86d9a76 commit bff0296
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 17 deletions.
12 changes: 11 additions & 1 deletion src/main/java/org/lwjglx/input/Mouse.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down
34 changes: 18 additions & 16 deletions src/main/java/org/lwjglx/opengl/Display.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);

glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); // request a non-hidpi framebuffer on Retina displays
// on MacOS

if (Config.WINDOW_CENTERED) {
glfwWindowHint(GLFW_POSITION_X, (monitorWidth - mode.getWidth()) / 2);
glfwWindowHint(GLFW_POSITION_Y, (monitorHeight - mode.getHeight()) / 2);
Expand Down Expand Up @@ -607,19 +604,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;
}

Expand Down Expand Up @@ -892,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) {
Expand Down

0 comments on commit bff0296

Please sign in to comment.