Skip to content

Commit a3a77eb

Browse files
jmecn闫茂源闫茂源
authored
fix incorrect input cursor position on MacOS with retina screen in use (#1607)
* [M]Fix code error when checking UTF-8 data Let a 3 bytes UTF-8 data = [0xE4, 0x8A, 0xBC], when b = 0xE4 (1110 0100), it will be treated as 2 bytes. See this part: ```java if (b < 0x80) { // good } else if ((b & 0xC0) == 0xC0) {// (0xE4 & 0xC0) == 0xC0 =====> true utf8State = UTF8_2BYTE; } else if ((b & 0xE0) == 0xE0) {// (0xE4 & 0xE0) == 0xE0 =====> true utf8State = UTF8_3BYTE_1; } else { utf8State = UTF8_ILLEGAL; } ``` 3 bytes UTF-8 data while always be treated as 2 bytes UTF-8 data. It's better that always treat String data as UTF-8 now. see https://hub.jmonkeyengine.org/t/code-error-on-checking-utf-8-data/43909 * [M]Use StandardCharsets.UTF_8 instead of constant 'UTF8' * [Add]Add HiDPI support with lwjgl3-glfw * [M]Add a parameter UseRetinaFrameBuffer to enable/disable usage of full resolution framebuffers on Retina Display * [M]WindowContentScale is incorrect when glfw window is created, and we don't get any callback when it is changed.So just get it from time to time when mouse cursor is moved. * [M]Get the real frame buffer size at the 2nd frame after the context is restarted. * [M]Change default value of UseRetinaFrameBuffer to true. * [M]Add resolution check before reshape Co-authored-by: 闫茂源 <[email protected]> Co-authored-by: 闫茂源 <[email protected]>
1 parent 0433a63 commit a3a77eb

File tree

3 files changed

+81
-6
lines changed

3 files changed

+81
-6
lines changed

jme3-core/src/main/java/com/jme3/system/AppSettings.java

+19
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ public final class AppSettings extends HashMap<String, Object> {
289289
defaults.put("SwapBuffers", true);
290290
defaults.put("OpenCL", false);
291291
defaults.put("OpenCLPlatformChooser", DefaultPlatformChooser.class.getName());
292+
defaults.put("UseRetinaFrameBuffer", true);// MacOS spec
292293
// defaults.put("Icons", null);
293294
}
294295

@@ -1331,4 +1332,22 @@ public boolean isGraphicsTrace() {
13311332
public void setGraphicsTrace(boolean trace) {
13321333
putBoolean("GraphicsTrace", trace);
13331334
}
1335+
1336+
/**
1337+
* Determine whether to use full resolution framebuffers on Retina displays.
1338+
*
1339+
* @return whether to use full resolution framebuffers on Retina displays.
1340+
*/
1341+
public boolean isUseRetinaFrameBuffer() {
1342+
return getBoolean("UseRetinaFrameBuffer");
1343+
}
1344+
1345+
/**
1346+
* Specifies whether to use full resolution framebuffers on Retina displays. This is ignored on other platforms.
1347+
*
1348+
* @param useRetinaFrameBuffer whether to use full resolution framebuffers on Retina displays.
1349+
*/
1350+
public void setUseRetinaFrameBuffer(boolean useRetinaFrameBuffer) {
1351+
putBoolean("UseRetinaFrameBuffer", useRetinaFrameBuffer);
1352+
}
13341353
}

jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java

+17-6
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,18 @@
3636
import com.jme3.input.RawInputListener;
3737
import com.jme3.input.event.MouseButtonEvent;
3838
import com.jme3.input.event.MouseMotionEvent;
39+
import com.jme3.math.Vector2f;
3940
import com.jme3.system.lwjgl.LwjglWindow;
4041
import com.jme3.util.BufferUtils;
4142
import java.nio.ByteBuffer;
4243
import java.nio.DoubleBuffer;
44+
import java.nio.FloatBuffer;
4345
import java.nio.IntBuffer;
4446
import java.util.ArrayDeque;
4547
import java.util.HashMap;
4648
import java.util.Map;
4749
import java.util.Queue;
50+
import java.util.logging.Level;
4851
import java.util.logging.Logger;
4952
import org.lwjgl.glfw.*;
5053
import static org.lwjgl.glfw.GLFW.*;
@@ -141,11 +144,14 @@ public GlfwMouseInput(final LwjglWindow context) {
141144
}
142145

143146
private void onCursorPos(final long window, final double xpos, final double ypos) {
147+
float[] xScale = new float[1];
148+
float[] yScale = new float[1];
149+
glfwGetWindowContentScale(window, xScale, yScale);
144150

145151
int xDelta;
146152
int yDelta;
147-
int x = (int) Math.round(xpos);
148-
int y = currentHeight - (int) Math.round(ypos);
153+
int x = (int) Math.round(xpos * xScale[0]);
154+
int y = (int) Math.round((currentHeight - ypos) * yScale[0]);
149155

150156
xDelta = x - mouseX;
151157
yDelta = y - mouseY;
@@ -243,11 +249,16 @@ public void invoke(final long window, final int width, final int height) {
243249
}
244250

245251
private void initCurrentMousePosition(long window) {
246-
DoubleBuffer x = BufferUtils.createDoubleBuffer(1);
247-
DoubleBuffer y = BufferUtils.createDoubleBuffer(1);
252+
double[] x = new double[1];
253+
double[] y = new double[1];
248254
glfwGetCursorPos(window, x, y);
249-
mouseX = (int) Math.round(x.get());
250-
mouseY = currentHeight - (int) Math.round(y.get());
255+
256+
float[] xScale = new float[1];
257+
float[] yScale = new float[1];
258+
glfwGetWindowContentScale(window, xScale, yScale);
259+
260+
mouseX = (int) Math.round(x[0] * xScale[0]);
261+
mouseY = (int) Math.round((currentHeight - y[0]) * yScale[0]);
251262
}
252263

253264
/**

jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java

+45
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.jme3.input.lwjgl.GlfwJoystickInput;
4040
import com.jme3.input.lwjgl.GlfwKeyInput;
4141
import com.jme3.input.lwjgl.GlfwMouseInput;
42+
import com.jme3.math.Vector2f;
4243
import com.jme3.system.AppSettings;
4344
import com.jme3.system.JmeContext;
4445
import com.jme3.system.JmeSystem;
@@ -226,6 +227,7 @@ public void invoke(int error, long description) {
226227
glfwWindowHint(GLFW_SAMPLES, settings.getSamples());
227228
glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GLFW_TRUE : GLFW_FALSE);
228229
glfwWindowHint(GLFW_REFRESH_RATE, settings.getFrequency()<=0?GLFW_DONT_CARE:settings.getFrequency());
230+
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, settings.isUseRetinaFrameBuffer() ? GLFW_TRUE : GLFW_FALSE);
229231

230232
if (settings.getBitsPerPixel() == 24) {
231233
glfwWindowHint(GLFW_RED_BITS, 8);
@@ -330,6 +332,8 @@ public void invoke(final long window, final int width, final int height) {
330332
if (settings.isOpenCLSupport()) {
331333
initOpenCL(window);
332334
}
335+
336+
framesAfterContextStarted = 0;
333337
}
334338

335339
private void onWindowSizeChanged(final int width, final int height) {
@@ -521,6 +525,8 @@ protected boolean initInThread() {
521525
return true;
522526
}
523527

528+
private int framesAfterContextStarted = 0;
529+
524530
/**
525531
* execute one iteration of the render loop in the OpenGL thread
526532
*/
@@ -534,6 +540,21 @@ protected void runLoop() {
534540
throw new IllegalStateException();
535541
}
536542

543+
// Update the frame buffer size from 2nd frame since the initial value
544+
// of frame buffer size from glfw maybe incorrect when HiDPI display is in use
545+
if (framesAfterContextStarted < 2) {
546+
framesAfterContextStarted++;
547+
if (framesAfterContextStarted == 2) {
548+
int[] width = new int[1];
549+
int[] height = new int[1];
550+
glfwGetFramebufferSize(window, width, height);
551+
552+
if (settings.getWidth() != width[0] || settings.getHeight() != height[0]) {
553+
listener.reshape(width[0], height[0]);
554+
}
555+
}
556+
}
557+
537558
listener.update();
538559

539560
// All this does is call swap buffers
@@ -688,4 +709,28 @@ public void destroy(boolean waitFor) {
688709
public long getWindowHandle() {
689710
return window;
690711
}
712+
713+
/**
714+
* Get the window content scale, for HiDPI support.
715+
*
716+
* The content scale is the ratio between the current DPI and the platform's default DPI.
717+
* This is especially important for text and any UI elements. If the pixel dimensions of
718+
* your UI scaled by this look appropriate on your machine then it should appear at a
719+
* reasonable size on other machines regardless of their DPI and scaling settings. This
720+
* relies on the system DPI and scaling settings being somewhat correct.
721+
*
722+
* @param store A vector2f to store the result
723+
* @return The window content scale
724+
* @see <a href="https://www.glfw.org/docs/latest/window_guide.html#window_scale">Window content scale</a>
725+
*/
726+
public Vector2f getWindowContentScale(Vector2f store) {
727+
float[] xScale = new float[1];
728+
float[] yScale = new float[1];
729+
glfwGetWindowContentScale(window, xScale, yScale);
730+
731+
if (store != null) {
732+
return store.set(xScale[0], yScale[0]);
733+
}
734+
return new Vector2f(xScale[0], yScale[0]);
735+
}
691736
}

0 commit comments

Comments
 (0)