1
1
package imgui .glfw ;
2
2
3
+ import imgui .ImGui ;
4
+ import imgui .ImGuiIO ;
5
+ import imgui .ImVec2 ;
6
+ import imgui .callback .ImStrConsumer ;
7
+ import imgui .callback .ImStrSupplier ;
8
+ import imgui .flag .ImGuiBackendFlags ;
9
+ import imgui .flag .ImGuiConfigFlags ;
10
+ import imgui .flag .ImGuiKey ;
11
+ import imgui .flag .ImGuiMouseButton ;
12
+ import imgui .flag .ImGuiMouseCursor ;
13
+ import imgui .flag .ImGuiNavInput ;
14
+ import org .lwjgl .glfw .GLFWCharCallback ;
15
+ import org .lwjgl .glfw .GLFWErrorCallback ;
16
+ import org .lwjgl .glfw .GLFWKeyCallback ;
17
+ import org .lwjgl .glfw .GLFWMouseButtonCallback ;
18
+ import org .lwjgl .glfw .GLFWScrollCallback ;
19
+
20
+ import java .nio .ByteBuffer ;
21
+ import java .nio .FloatBuffer ;
22
+
3
23
import static org .lwjgl .glfw .GLFW .GLFW_ARROW_CURSOR ;
4
24
import static org .lwjgl .glfw .GLFW .GLFW_CURSOR ;
5
25
import static org .lwjgl .glfw .GLFW .GLFW_CURSOR_DISABLED ;
65
85
import static org .lwjgl .glfw .GLFW .glfwSetMouseButtonCallback ;
66
86
import static org .lwjgl .glfw .GLFW .glfwSetScrollCallback ;
67
87
68
- import imgui .ImGui ;
69
- import imgui .ImGuiIO ;
70
- import imgui .ImVec2 ;
71
- import imgui .callback .ImStrConsumer ;
72
- import imgui .callback .ImStrSupplier ;
73
- import imgui .flag .ImGuiBackendFlags ;
74
- import imgui .flag .ImGuiConfigFlags ;
75
- import imgui .flag .ImGuiKey ;
76
- import imgui .flag .ImGuiMouseButton ;
77
- import imgui .flag .ImGuiMouseCursor ;
78
- import imgui .flag .ImGuiNavInput ;
79
- import java .nio .ByteBuffer ;
80
- import java .nio .FloatBuffer ;
81
- import org .lwjgl .glfw .GLFWCharCallback ;
82
- import org .lwjgl .glfw .GLFWErrorCallback ;
83
- import org .lwjgl .glfw .GLFWKeyCallback ;
84
- import org .lwjgl .glfw .GLFWMouseButtonCallback ;
85
- import org .lwjgl .glfw .GLFWScrollCallback ;
86
-
87
88
/**
88
89
* This class is a straightforward port of the
89
90
* <a href="https://raw.githubusercontent.com/ocornut/imgui/v1.76/examples/imgui_impl_glfw.cpp">imgui_impl_glfw.cpp</a>.
90
91
* <p>
91
92
* It supports clipboard, gamepad, mouse and keyboard in the same way the original Dear ImGui code does. You can copy-paste this class in your codebase and
92
93
* modify the rendering routine in the way you'd like.
93
- * <p>
94
94
*/
95
95
public class ImGuiImplGlfw {
96
96
97
97
// Id of the current GLFW window
98
- private long windowId ;
98
+ private long windowPtr ;
99
99
100
100
// For application window properties
101
101
private final int [] winWidth = new int [1 ];
@@ -106,8 +106,12 @@ public class ImGuiImplGlfw {
106
106
// Mouse cursors provided by GLFW
107
107
private final long [] mouseCursors = new long [ImGuiMouseCursor .COUNT ];
108
108
109
+ // Empty array to fill ImGuiIO.NavInputs with zeroes
110
+ private final float [] emptyNavInputs = new float [ImGuiNavInput .COUNT ];
111
+
109
112
// For mouse tracking
110
113
private final boolean [] mouseJustPressed = new boolean [ImGuiMouseButton .COUNT ];
114
+ private final ImVec2 mousePosBackup = new ImVec2 ();
111
115
private final double [] cursorPosX = new double [1 ];
112
116
private final double [] cursorPosY = new double [1 ];
113
117
@@ -142,8 +146,8 @@ public void scrollCallback(final long windowId, final double xOffset, final doub
142
146
}
143
147
144
148
final ImGuiIO io = ImGui .getIO ();
145
- io .setMouseWheelH ((float ) xOffset );
146
- io .setMouseWheel ((float ) yOffset );
149
+ io .setMouseWheelH (io . getMouseWheelH () + (float ) xOffset );
150
+ io .setMouseWheel (io . getMouseWheel () + (float ) yOffset );
147
151
}
148
152
149
153
/**
@@ -155,10 +159,10 @@ public void keyCallback(final long windowId, final int key, final int scancode,
155
159
}
156
160
157
161
final ImGuiIO io = ImGui .getIO ();
162
+
158
163
if (action == GLFW_PRESS ) {
159
164
io .setKeysDown (key , true );
160
- }
161
- if (action == GLFW_RELEASE ) {
165
+ } else if (action == GLFW_RELEASE ) {
162
166
io .setKeysDown (key , false );
163
167
}
164
168
@@ -186,8 +190,7 @@ public void charCallback(final long windowId, final int c) {
186
190
* Method takes two arguments, which should be a valid GLFW window pointer and a boolean indicating whether or not to install callbacks.
187
191
*/
188
192
public boolean init (final long windowId , final boolean installCallbacks ) {
189
- this .windowId = windowId ;
190
- time = 0.0 ;
193
+ this .windowPtr = windowId ;
191
194
192
195
final ImGuiIO io = ImGui .getIO ();
193
196
@@ -265,10 +268,10 @@ public void accept(final String str) {
265
268
*/
266
269
public void dispose () {
267
270
if (callbacksInstalled ) {
268
- glfwSetMouseButtonCallback (windowId , previousMouseButtonCallback );
269
- glfwSetScrollCallback (windowId , previousScrollCallback );
270
- glfwSetKeyCallback (windowId , previousKeyCallback );
271
- glfwSetCharCallback (windowId , previousCharCallback );
271
+ glfwSetMouseButtonCallback (windowPtr , previousMouseButtonCallback );
272
+ glfwSetScrollCallback (windowPtr , previousScrollCallback );
273
+ glfwSetKeyCallback (windowPtr , previousKeyCallback );
274
+ glfwSetCharCallback (windowPtr , previousCharCallback );
272
275
callbacksInstalled = false ;
273
276
}
274
277
@@ -279,73 +282,74 @@ public void dispose() {
279
282
280
283
private void updateMousePosAndButtons (final float scaleX , final float scaleY ) {
281
284
final ImGuiIO io = ImGui .getIO ();
285
+
282
286
for (int i = 0 ; i < ImGuiMouseButton .COUNT ; i ++) {
283
- io .setMouseDown (i , mouseJustPressed [i ] || glfwGetMouseButton (windowId , i ) != 0 );
287
+ // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
288
+ io .setMouseDown (i , mouseJustPressed [i ] || glfwGetMouseButton (windowPtr , i ) != 0 );
284
289
mouseJustPressed [i ] = false ;
285
290
}
286
291
287
- final ImVec2 mousePosBackup = new ImVec2 ();
288
292
io .getMousePos (mousePosBackup );
289
293
io .setMousePos (-Float .MAX_VALUE , -Float .MAX_VALUE );
290
294
291
- final boolean focused = glfwGetWindowAttrib (windowId , GLFW_FOCUSED ) != 0 ;
295
+ final boolean focused = glfwGetWindowAttrib (windowPtr , GLFW_FOCUSED ) != 0 ;
292
296
if (focused ) {
293
297
if (io .getWantSetMousePos ()) {
294
- glfwSetCursorPos (windowId , mousePosBackup .x , mousePosBackup .y );
298
+ glfwSetCursorPos (windowPtr , mousePosBackup .x , mousePosBackup .y );
295
299
} else {
296
- glfwGetCursorPos (windowId , cursorPosX , cursorPosY );
300
+ glfwGetCursorPos (windowPtr , cursorPosX , cursorPosY );
297
301
io .setMousePos ((float ) cursorPosX [0 ] * scaleX , (float ) cursorPosY [0 ] * scaleY );
298
302
}
299
303
}
300
304
}
301
305
302
306
private void updateMouseCursor () {
303
307
final ImGuiIO io = ImGui .getIO ();
304
- final boolean noCursorChange = (io .getConfigFlags () & ImGuiConfigFlags .NoMouseCursorChange )
305
- == ImGuiConfigFlags .NoMouseCursorChange ;
306
- final boolean cursorDisabled = glfwGetInputMode (windowId , GLFW_CURSOR ) == GLFW_CURSOR_DISABLED ;
308
+
309
+ final boolean noCursorChange = (io .getConfigFlags () & ImGuiConfigFlags .NoMouseCursorChange ) == ImGuiConfigFlags .NoMouseCursorChange ;
310
+ final boolean cursorDisabled = glfwGetInputMode (windowPtr , GLFW_CURSOR ) == GLFW_CURSOR_DISABLED ;
311
+
307
312
if (noCursorChange || cursorDisabled ) {
308
313
return ;
309
314
}
310
315
311
316
final int cursor = ImGui .getMouseCursor ();
317
+
312
318
if (cursor == ImGuiMouseCursor .None || io .getMouseDrawCursor ()) {
313
- glfwSetInputMode (windowId , GLFW_CURSOR , GLFW_CURSOR_HIDDEN );
319
+ glfwSetInputMode (windowPtr , GLFW_CURSOR , GLFW_CURSOR_HIDDEN );
314
320
} else {
315
- glfwSetCursor (windowId , mouseCursors [cursor ] != 0 ? mouseCursors [cursor ]
316
- : mouseCursors [ImGuiMouseCursor .Arrow ]);
317
- glfwSetInputMode (windowId , GLFW_CURSOR , GLFW_CURSOR_NORMAL );
321
+ glfwSetCursor (windowPtr , mouseCursors [cursor ] != 0 ? mouseCursors [cursor ] : mouseCursors [ImGuiMouseCursor .Arrow ]);
322
+ glfwSetInputMode (windowPtr , GLFW_CURSOR , GLFW_CURSOR_NORMAL );
318
323
}
319
324
}
320
325
321
326
private void updateGamepads () {
322
327
final ImGuiIO io = ImGui .getIO ();
323
328
324
- final float [] navInputs = new float [ImGuiNavInput .COUNT ];
325
- io .setNavInputs (navInputs );
326
-
327
329
if ((io .getConfigFlags () & ImGuiConfigFlags .NavEnableGamepad ) == 0 ) {
328
330
return ;
329
331
}
330
332
333
+ io .setNavInputs (emptyNavInputs );
334
+
331
335
final ByteBuffer buttons = glfwGetJoystickButtons (GLFW_JOYSTICK_1 );
332
336
final int buttonsCount = buttons .limit ();
333
337
334
338
final FloatBuffer axis = glfwGetJoystickAxes (GLFW_JOYSTICK_1 );
335
339
final int axisCount = axis .limit ();
336
340
337
- mapButton (ImGuiNavInput .Activate , 0 , buttons , buttonsCount , io ); // Cross / A
341
+ mapButton (ImGuiNavInput .Activate , 0 , buttons , buttonsCount , io ); // Cross / A
338
342
mapButton (ImGuiNavInput .Cancel , 1 , buttons , buttonsCount , io ); // Circle / B
339
- mapButton (ImGuiNavInput .Menu , 2 , buttons , buttonsCount , io ); // Square / X
340
- mapButton (ImGuiNavInput .Input , 3 , buttons , buttonsCount , io ); // Triangle / Y
341
- mapButton (ImGuiNavInput .DpadLeft , 13 , buttons , buttonsCount , io ); // D-Pad Left
342
- mapButton (ImGuiNavInput .DpadRight , 11 , buttons , buttonsCount , io ); // D-Pad Right
343
+ mapButton (ImGuiNavInput .Menu , 2 , buttons , buttonsCount , io ); // Square / X
344
+ mapButton (ImGuiNavInput .Input , 3 , buttons , buttonsCount , io ); // Triangle / Y
345
+ mapButton (ImGuiNavInput .DpadLeft , 13 , buttons , buttonsCount , io ); // D-Pad Left
346
+ mapButton (ImGuiNavInput .DpadRight , 11 , buttons , buttonsCount , io ); // D-Pad Right
343
347
mapButton (ImGuiNavInput .DpadUp , 10 , buttons , buttonsCount , io ); // D-Pad Up
344
- mapButton (ImGuiNavInput .DpadDown , 12 , buttons , buttonsCount , io ); // D-Pad Down
345
- mapButton (ImGuiNavInput .FocusPrev , 4 , buttons , buttonsCount , io ); // L1 / LB
346
- mapButton (ImGuiNavInput .FocusNext , 5 , buttons , buttonsCount , io ); // R1 / RB
347
- mapButton (ImGuiNavInput .TweakSlow , 4 , buttons , buttonsCount , io ); // L1 / LB
348
- mapButton (ImGuiNavInput .TweakFast , 5 , buttons , buttonsCount , io ); // R1 / RB
348
+ mapButton (ImGuiNavInput .DpadDown , 12 , buttons , buttonsCount , io ); // D-Pad Down
349
+ mapButton (ImGuiNavInput .FocusPrev , 4 , buttons , buttonsCount , io ); // L1 / LB
350
+ mapButton (ImGuiNavInput .FocusNext , 5 , buttons , buttonsCount , io ); // R1 / RB
351
+ mapButton (ImGuiNavInput .TweakSlow , 4 , buttons , buttonsCount , io ); // L1 / LB
352
+ mapButton (ImGuiNavInput .TweakFast , 5 , buttons , buttonsCount , io ); // R1 / RB
349
353
mapAnalog (ImGuiNavInput .LStickLeft , 0 , -0.3f , -0.9f , axis , axisCount , io );
350
354
mapAnalog (ImGuiNavInput .LStickRight , 0 , +0.3f , +0.9f , axis , axisCount , io );
351
355
mapAnalog (ImGuiNavInput .LStickUp , 1 , +0.3f , +0.9f , axis , axisCount , io );
@@ -390,11 +394,12 @@ public void newFrame() {
390
394
final ImGuiIO io = ImGui .getIO ();
391
395
if (!io .getFonts ().isBuilt ()) {
392
396
throw new IllegalStateException (
393
- "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer init() method? e.g. ImGuiImplGl3.init()." );
397
+ "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer init() method? e.g. ImGuiImplGl3.init()"
398
+ );
394
399
}
395
400
396
- glfwGetWindowSize (windowId , winWidth , winHeight );
397
- glfwGetFramebufferSize (windowId , fbWidth , fbHeight );
401
+ glfwGetWindowSize (windowPtr , winWidth , winHeight );
402
+ glfwGetFramebufferSize (windowPtr , fbWidth , fbHeight );
398
403
399
404
final float scaleX = (float ) fbWidth [0 ] / winWidth [0 ];
400
405
final float scaleY = (float ) fbHeight [0 ] / winHeight [0 ];
@@ -406,6 +411,7 @@ public void newFrame() {
406
411
407
412
final double currentTime = glfwGetTime ();
408
413
io .setDeltaTime (time > 0.0 ? (float ) (currentTime - time ) : 1.0f / 60.0f );
414
+ time = currentTime ;
409
415
410
416
updateMousePosAndButtons (scaleX , scaleY );
411
417
updateMouseCursor ();
0 commit comments