diff --git a/bin/imgui-java.dll b/bin/imgui-java.dll index dabaf01..e0e74ec 100755 Binary files a/bin/imgui-java.dll and b/bin/imgui-java.dll differ diff --git a/bin/imgui-java64.dll b/bin/imgui-java64.dll index 43a7b90..9d4c599 100755 Binary files a/bin/imgui-java64.dll and b/bin/imgui-java64.dll differ diff --git a/bin/libimgui-java.so b/bin/libimgui-java.so index 684cc11..add29f4 100755 Binary files a/bin/libimgui-java.so and b/bin/libimgui-java.so differ diff --git a/bin/libimgui-java64.so b/bin/libimgui-java64.so index d65fa47..efdfecd 100755 Binary files a/bin/libimgui-java64.so and b/bin/libimgui-java64.so differ diff --git a/buildSrc/scripts/build-natives-win64.sh b/buildSrc/scripts/build-natives-win64.sh new file mode 100644 index 0000000..08dba67 --- /dev/null +++ b/buildSrc/scripts/build-natives-win64.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +BASEDIR=$(dirname "$0") +cd $BASEDIR/../../imgui-binding || exit + +rm -frd /tmp/imgui +../gradlew clean generateLibs -Denvs=win64 diff --git a/imgui-binding/src/main/java/imgui/ImGui.java b/imgui-binding/src/main/java/imgui/ImGui.java index 7972532..d6f8193 100644 --- a/imgui-binding/src/main/java/imgui/ImGui.java +++ b/imgui-binding/src/main/java/imgui/ImGui.java @@ -5439,7 +5439,7 @@ public final class ImGui { } private static native long nGetPlatformIO(); /* - return (intptr_t)ImGui::GetMainViewport(); + return (intptr_t)&ImGui::GetPlatformIO(); */ /** @@ -5491,4 +5491,16 @@ public final class ImGui { private static native long nFindViewportByID(int imGuiID); /* return (intptr_t)ImGui::FindViewportByID(imGuiID); */ + + /** + * This is a helper for back-ends. The type platform_handle is decided by the back-end (e.g. HWND, MyWindow*, GLFWwindow* etc.) + */ + public static ImGuiViewport findViewportByPlatformHandle(long platformHandle) { + FIND_VIEWPORT.ptr = nFindViewportByPlatformHandle(platformHandle); + return FIND_VIEWPORT; + } + + private static native long nFindViewportByPlatformHandle(long platformHandle); /* + return (intptr_t)ImGui::FindViewportByPlatformHandle((void*)platformHandle); + */ } diff --git a/imgui-binding/src/main/java/imgui/ImGuiIO.java b/imgui-binding/src/main/java/imgui/ImGuiIO.java index b298cd7..08c8cb8 100644 --- a/imgui-binding/src/main/java/imgui/ImGuiIO.java +++ b/imgui-binding/src/main/java/imgui/ImGuiIO.java @@ -390,7 +390,7 @@ public final class ImGuiIO { * Optional: Platform back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff. */ public native String getBackendPlatformName(); /* - return env -> NewStringUTF(ImGui::GetIO().BackendPlatformName); + return env->NewStringUTF(ImGui::GetIO().BackendPlatformName); */ /** @@ -404,7 +404,7 @@ public final class ImGuiIO { * Optional: Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff. */ public native String getBackendRendererName(); /* - return env -> NewStringUTF(ImGui::GetIO().BackendRendererName); + return env->NewStringUTF(ImGui::GetIO().BackendRendererName); */ /** @@ -699,6 +699,24 @@ public final class ImGuiIO { ImGui::GetIO().MouseWheelH = mouseDeltaX; */ + /** + * (Optional) When using multiple viewports: viewport the OS mouse cursor is hovering _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag, + * and _REGARDLESS_ of whether another viewport is focused. Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. + * If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). + */ + public native float getMouseHoveredViewport(); /* + return ImGui::GetIO().MouseHoveredViewport; + */ + + /** + * (Optional) When using multiple viewports: viewport the OS mouse cursor is hovering _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag, + * and _REGARDLESS_ of whether another viewport is focused. Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. + * If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). + */ + public native void setMouseHoveredViewport(int imGuiId); /* + ImGui::GetIO().MouseHoveredViewport = imGuiId; + */ + /** * Keyboard modifier pressed: Control */ diff --git a/imgui-binding/src/main/java/imgui/ImGuiPlatformIO.java b/imgui-binding/src/main/java/imgui/ImGuiPlatformIO.java index 16639fc..23a85db 100644 --- a/imgui-binding/src/main/java/imgui/ImGuiPlatformIO.java +++ b/imgui-binding/src/main/java/imgui/ImGuiPlatformIO.java @@ -70,6 +70,7 @@ import imgui.callback.ImPlatformFuncViewportSuppImVec2; * Platform functions are typically called before their Renderer counterpart, apart from Destroy which are called the other way. */ public final class ImGuiPlatformIO extends ImGuiStruct { + private static final ImGuiViewport MAIN_VIEWPORT = new ImGuiViewport(0); private static final ImGuiViewport TMP_VIEWPORT = new ImGuiViewport(0); private static final ImVec2 TMP_IM_VEC2 = new ImVec2(); @@ -307,7 +308,7 @@ public final class ImGuiPlatformIO extends ImGuiStruct { IMGUI_PLATFORM_IO->Platform_SetWindowTitle = PlatformStubSetWindowTitle; */ - /*JNI + /*JNI jobject platformCallbackSetWindowAlpha = NULL; void PlatformStubSetWindowAlpha(ImGuiViewport* vp, float alpha) { if (platformCallbackSetWindowAlpha != NULL) { @@ -485,4 +486,62 @@ public final class ImGuiPlatformIO extends ImGuiStruct { public native void setRendererSwapBuffers(ImPlatformFuncViewport func); /* IM_RENDERER_FUNC_VIEWPORT_METHOD_TMPL(SwapBuffers) */ + + // (Optional) Monitor list + // - Updated by: app/back-end. Update every frame to dynamically support changing monitor or DPI configuration. + // - Used by: dear imgui to query DPI info, clamp popups/tooltips within same monitor and not have them straddle monitors. + + //------------------------------------------------------------------ + // Output - List of viewports to render into platform windows + //------------------------------------------------------------------ + + public native void resizeMonitors(int size); /* + IMGUI_PLATFORM_IO->Monitors.resize(0); + */ + + public native int getMonitorsSize(); /* + return IMGUI_PLATFORM_IO->Monitors.Size; + */ + + public native void pushMonitors(float mainPosX, float mainPosY, float mainSizeX, float mainSizeY, float workPosX, float workPosY, float workSizeX, float workSizeY, float dpiScale); /* + ImGuiPlatformMonitor monitor; + + monitor.MainPos = ImVec2(mainPosX, mainPosY); + monitor.MainSize = ImVec2(mainSizeX, mainSizeY); + + monitor.WorkPos = ImVec2(workPosX, workPosY); + monitor.WorkSize = ImVec2(workSizeX, workSizeY); + + monitor.DpiScale = dpiScale; + + IMGUI_PLATFORM_IO->Monitors.push_back(monitor); + */ + + // Viewports list (the list is updated by calling ImGui::EndFrame or ImGui::Render) + // (in the future we will attempt to organize this feature to remove the need for a "main viewport") + + /** + * Guaranteed to be == Viewports[0] + */ + public ImGuiViewport getMainViewport() { + MAIN_VIEWPORT.ptr = nGetMainViewport(); + return MAIN_VIEWPORT; + } + + private native long nGetMainViewport(); /* + return (intptr_t)IMGUI_PLATFORM_IO->MainViewport; + */ + + public native int getViewportsSize(); /* + return IMGUI_PLATFORM_IO->Viewports.Size; + */ + + public ImGuiViewport getViewports(final int idx) { + TMP_VIEWPORT.ptr = nGetViewports(idx); + return TMP_VIEWPORT; + } + + private native long nGetViewports(int idx); /* + return (intptr_t)IMGUI_PLATFORM_IO->Viewports[idx]; + */ } diff --git a/imgui-binding/src/main/java/imgui/ImGuiViewport.java b/imgui-binding/src/main/java/imgui/ImGuiViewport.java index b1373a8..952adfd 100644 --- a/imgui-binding/src/main/java/imgui/ImGuiViewport.java +++ b/imgui-binding/src/main/java/imgui/ImGuiViewport.java @@ -212,7 +212,67 @@ public final class ImGuiViewport extends ImGuiStruct { // by the same system and you may not need to use all the UserData/Handle fields. // The library never uses those fields, they are merely storage to facilitate back-end implementation. - // TODO: PlatformUserData, PlatformHandle, PlatformHandleRaw + /** + * void* to hold custom data structure for the renderer (e.g. swap chain, framebuffers etc.). generally set by your Renderer_CreateWindow function. + */ + public native void setRendererUserData(Object data); /* + if (IMGUI_VIEWPORT->RendererUserData != NULL) { + env->DeleteGlobalRef((jobject)IMGUI_VIEWPORT->RendererUserData); + } + IMGUI_VIEWPORT->RendererUserData = (data == NULL ? NULL : (void*)env->NewGlobalRef(data)); + */ + + /** + * void* to hold custom data structure for the renderer (e.g. swap chain, framebuffers etc.). generally set by your Renderer_CreateWindow function. + */ + public native Object getRendererUserData(); /* + return (jobject)IMGUI_VIEWPORT->RendererUserData; + */ + + /** + * void* to hold custom data structure for the OS / platform (e.g. windowing info, render context). generally set by your Platform_CreateWindow function. + */ + public native void setPlatformUserData(Object data); /* + if (IMGUI_VIEWPORT->PlatformUserData != NULL) { + env->DeleteGlobalRef((jobject)IMGUI_VIEWPORT->PlatformUserData); + } + IMGUI_VIEWPORT->PlatformUserData = (data == NULL ? NULL : (void*)env->NewGlobalRef(data)); + */ + + /** + * void* to hold custom data structure for the OS / platform (e.g. windowing info, render context). generally set by your Platform_CreateWindow function. + */ + public native Object getPlatformUserData(); /* + return (jobject)IMGUI_VIEWPORT->PlatformUserData; + */ + + /** + * void* for FindViewportByPlatformHandle(). (e.g. suggested to use natural platform handle such as HWND, GLFWWindow*, SDL_Window*) + */ + public native void setPlatformHandle(long data); /* + IMGUI_VIEWPORT->PlatformHandle = (void*)data; + */ + + /** + * void* for FindViewportByPlatformHandle(). (e.g. suggested to use natural platform handle such as HWND, GLFWWindow*, SDL_Window*) + */ + public native long getPlatformHandle(); /* + return (intptr_t)IMGUI_VIEWPORT->PlatformHandle; + */ + + /** + * void* to hold lower-level, platform-native window handle (e.g. the HWND) when using an abstraction layer like GLFW or SDL (where PlatformHandle would be a SDL_Window*) + */ + public native void setPlatformHandleRaw(long data); /* + IMGUI_VIEWPORT->PlatformHandleRaw = (void*)data; + */ + + /** + * void* to hold lower-level, platform-native window handle (e.g. the HWND) when using an abstraction layer like GLFW or SDL (where PlatformHandle would be a SDL_Window*) + */ + public native long getPlatformHandleRaw(); /* + return (intptr_t)IMGUI_VIEWPORT->PlatformHandleRaw; + */ /** * Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position). diff --git a/imgui-binding/src/main/java/imgui/callback/ImPlatformFuncViewportFloat.java b/imgui-binding/src/main/java/imgui/callback/ImPlatformFuncViewportFloat.java index 1308447..d39f75c 100644 --- a/imgui-binding/src/main/java/imgui/callback/ImPlatformFuncViewportFloat.java +++ b/imgui-binding/src/main/java/imgui/callback/ImPlatformFuncViewportFloat.java @@ -6,5 +6,5 @@ import imgui.ImGuiViewport; * Callback to represent ImGuiPlatformIO function with args: (ImGuiViewport*, String) */ public abstract class ImPlatformFuncViewportFloat { - public abstract void accept(ImGuiViewport vp, Float f); + public abstract void accept(ImGuiViewport vp, float f); } diff --git a/imgui-binding/src/main/java/imgui/flag/ImGuiBackendFlags.java b/imgui-binding/src/main/java/imgui/flag/ImGuiBackendFlags.java index 9e440fd..5c45c2b 100644 --- a/imgui-binding/src/main/java/imgui/flag/ImGuiBackendFlags.java +++ b/imgui-binding/src/main/java/imgui/flag/ImGuiBackendFlags.java @@ -24,4 +24,21 @@ public final class ImGuiBackendFlags { * Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. */ public static final int RendererHasVtxOffset = 1 << 3; + + // [BETA] Viewports + + /** + * Back-end Platform supports multiple viewports. + */ + public static final int PlatformHasViewports = 1 << 10; + /** + * Back-end Platform supports setting io.MouseHoveredViewport to the viewport directly under the mouse _IGNORING_ viewports + * with the ImGuiViewportFlags_NoInputs flag and _REGARDLESS_ of whether another viewport is focused and may be capturing the mouse. + * This information is _NOT EASY_ to provide correctly with most high-level engines! Don't set this without studying how the examples/ back-end handle it! + */ + public static final int HasMouseHoveredViewport = 1 << 11; + /** + * Back-end Renderer supports multiple viewports. + */ + public static final int RendererHasViewports = 1 << 12; } diff --git a/imgui-binding/src/main/java/imgui/flag/ImGuiConfigFlags.java b/imgui-binding/src/main/java/imgui/flag/ImGuiConfigFlags.java index f092b7b..05737e7 100644 --- a/imgui-binding/src/main/java/imgui/flag/ImGuiConfigFlags.java +++ b/imgui-binding/src/main/java/imgui/flag/ImGuiConfigFlags.java @@ -43,6 +43,24 @@ public final class ImGuiConfigFlags { */ public static final int DockingEnable = 1 << 6; + // [BETA] Viewports + // When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable. + + /** + * Viewport enable flags (require both ImGuiConfigFlags_PlatformHasViewports + ImGuiConfigFlags_RendererHasViewports set by the respective back-ends) + */ + public static final int ViewportsEnable = 1 << 10; + /** + * [BETA: Don't use] FIXME-DPI: Reposition and resize imgui windows when the DpiScale of a viewport changed (mostly useful for the main viewport hosting other window). + * Note that resizing the main window itself is up to your application. + */ + public static final int DpiEnableScaleViewports = 1 << 14; + /** + * [BETA: Don't use] FIXME-DPI: Request bitmap-scaled fonts to match DpiScale. This is a very low-quality workaround. + * The correct way to handle DPI is _currently_ to replace the atlas and/or fonts in the Platform_OnChangedViewport callback, but this is all early work in progress. + */ + public static final int DpiEnableScaleFonts = 1 << 15; + // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core Dear ImGui) /** diff --git a/imgui-binding/src/main/native/jni_callbacks.cpp b/imgui-binding/src/main/native/jni_callbacks.cpp index 0b9016c..3e6445f 100644 --- a/imgui-binding/src/main/native/jni_callbacks.cpp +++ b/imgui-binding/src/main/native/jni_callbacks.cpp @@ -72,7 +72,7 @@ namespace Jni } void CallImPlatformFuncViewportString(JNIEnv* env, jobject func, jobject vp, const char* str) { - env->CallVoidMethod(func, jImPlatformFuncViewportStringAcceptMID, env->NewStringUTF(str)); + env->CallVoidMethod(func, jImPlatformFuncViewportStringAcceptMID, vp, env->NewStringUTF(str)); } void CallImPlatformFuncViewportSuppImVec2(JNIEnv* env, jobject func, jobject vp, jobject imVec2) { diff --git a/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java b/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java index 1e8a0f2..3f3a641 100644 --- a/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java +++ b/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java @@ -4,9 +4,13 @@ import imgui.ImDrawData; import imgui.ImFontAtlas; import imgui.ImGui; import imgui.ImGuiIO; -import imgui.type.ImInt; +import imgui.ImGuiViewport; import imgui.ImVec2; import imgui.ImVec4; +import imgui.callback.ImPlatformFuncViewport; +import imgui.flag.ImGuiConfigFlags; +import imgui.flag.ImGuiViewportFlags; +import imgui.type.ImInt; import imgui.flag.ImGuiBackendFlags; import java.nio.ByteBuffer; @@ -31,17 +35,17 @@ public final class ImGuiImplGl3 { // OpenGL Data private int glVersion = 0; private String glslVersion = ""; - private int gVboHandle = 0; - private int gElementsHandle = 0; + private int gFontTexture = 0; private int gShaderHandle = 0; - private int gFragHandle = 0; private int gVertHandle = 0; + private int gFragHandle = 0; private int gAttribLocationTex = 0; private int gAttribLocationProjMtx = 0; private int gAttribLocationVtxPos = 0; private int gAttribLocationVtxUV = 0; private int gAttribLocationVtxColor = 0; - private int gFontTexture = 0; + private int gVboHandle = 0; + private int gElementsHandle = 0; private int gVertexArrayObjectHandle = 0; // Used to store tmp renderer data @@ -72,7 +76,7 @@ public final class ImGuiImplGl3 { /** * Method to do an initialization of the {@link ImGuiImplGl3} state. - * It SHOULD be called before calling of the {@link ImGuiImplGl3#render(ImDrawData)} method. + * It SHOULD be called before calling of the {@link ImGuiImplGl3#renderDrawData(ImDrawData)} method. *
* Unlike in the {@link #init(String)} method, here the glslVersion argument is omitted. * Thus a "#version 130" string will be used instead. @@ -83,7 +87,7 @@ public final class ImGuiImplGl3 { /** * Method to do an initialization of the {@link ImGuiImplGl3} state. - * It SHOULD be called before calling of the {@link ImGuiImplGl3#render(ImDrawData)} method. + * It SHOULD be called before calling of the {@link ImGuiImplGl3#renderDrawData(ImDrawData)} method. *
* Method takes an argument, which should be a valid GLSL string with the version to use. *
@@ -117,12 +121,16 @@ public final class ImGuiImplGl3 {
}
createDeviceObjects();
+
+ if ((ImGui.getIO().getConfigFlags() & ImGuiConfigFlags.ViewportsEnable) != 0) {
+ initPlatformInterface();
+ }
}
/**
* Method to render {@link ImDrawData} into current OpenGL context.
*/
- public void render(final ImDrawData drawData) {
+ public void renderDrawData(final ImDrawData drawData) {
if (drawData.getCmdListsCount() <= 0) {
return;
}
@@ -142,7 +150,7 @@ public final class ImGuiImplGl3 {
drawData.getDisplayPos(displayPos);
backupGlState();
- bind();
+ bind(fbWidth, fbHeight);
// Render command lists
for (int cmdListIdx = 0; cmdListIdx < drawData.getCmdListsCount(); cmdListIdx++) {
@@ -194,6 +202,7 @@ public final class ImGuiImplGl3 {
glDetachShader(gShaderHandle, gFragHandle);
glDeleteProgram(gShaderHandle);
glDeleteTextures(gFontTexture);
+ shutdownPlatformInterface();
}
/**
@@ -232,8 +241,11 @@ public final class ImGuiImplGl3 {
// We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
if (glVersion >= 320) {
- io.setBackendFlags(io.getBackendFlags() | ImGuiBackendFlags.RendererHasVtxOffset);
+ io.addBackendFlags(ImGuiBackendFlags.RendererHasVtxOffset);
}
+
+ // We can create multi-viewports on the Renderer side (optional)
+ io.addBackendFlags(ImGuiBackendFlags.RendererHasViewports);
}
private void createDeviceObjects() {
@@ -347,7 +359,7 @@ public final class ImGuiImplGl3 {
}
// Setup desired GL state
- private void bind() {
+ private void bind(final int fbWidth, final int fbHeight) {
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
gVertexArrayObjectHandle = glGenVertexArrays();
@@ -363,7 +375,7 @@ public final class ImGuiImplGl3 {
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
// DisplayPos is (0,0) for single viewport apps.
- glViewport(0, 0, (int) (displaySize.x * framebufferScale.x), (int) (displaySize.y * framebufferScale.y));
+ glViewport(0, 0, fbWidth, fbHeight);
final float left = displayPos.x;
final float right = displayPos.x + displaySize.x;
final float top = displayPos.y;
@@ -400,6 +412,29 @@ public final class ImGuiImplGl3 {
glDeleteVertexArrays(gVertexArrayObjectHandle);
}
+ //--------------------------------------------------------------------------------------------------------
+ // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
+ // This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
+ // If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
+ //--------------------------------------------------------------------------------------------------------
+
+ private void initPlatformInterface() {
+ ImGui.getPlatformIO().setRendererRenderWindow(new ImPlatformFuncViewport() {
+ @Override
+ public void accept(final ImGuiViewport vp) {
+ if ((vp.getFlags() & ImGuiViewportFlags.NoRendererClear) == 0) {
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ renderDrawData(vp.getDrawData());
+ }
+ });
+ }
+
+ private void shutdownPlatformInterface() {
+ ImGui.destroyPlatformWindows();
+ }
+
private int createAndCompileShader(final int type, final CharSequence source) {
final int id = glCreateShader(type);
diff --git a/imgui-lwjgl3/src/main/java/imgui/glfw/ImGuiImplGlfw.java b/imgui-lwjgl3/src/main/java/imgui/glfw/ImGuiImplGlfw.java
index be588c3..632420d 100644
--- a/imgui-lwjgl3/src/main/java/imgui/glfw/ImGuiImplGlfw.java
+++ b/imgui-lwjgl3/src/main/java/imgui/glfw/ImGuiImplGlfw.java
@@ -2,7 +2,15 @@ package imgui.glfw;
import imgui.ImGui;
import imgui.ImGuiIO;
+import imgui.ImGuiPlatformIO;
+import imgui.ImGuiViewport;
import imgui.ImVec2;
+import imgui.callback.ImPlatformFuncViewport;
+import imgui.callback.ImPlatformFuncViewportFloat;
+import imgui.callback.ImPlatformFuncViewportImVec2;
+import imgui.callback.ImPlatformFuncViewportString;
+import imgui.callback.ImPlatformFuncViewportSuppBoolean;
+import imgui.callback.ImPlatformFuncViewportSuppImVec2;
import imgui.callback.ImStrConsumer;
import imgui.callback.ImStrSupplier;
import imgui.flag.ImGuiBackendFlags;
@@ -11,79 +19,21 @@ import imgui.flag.ImGuiKey;
import imgui.flag.ImGuiMouseButton;
import imgui.flag.ImGuiMouseCursor;
import imgui.flag.ImGuiNavInput;
+import imgui.flag.ImGuiViewportFlags;
+import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.GLFWCharCallback;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
+import org.lwjgl.glfw.GLFWMonitorCallback;
import org.lwjgl.glfw.GLFWMouseButtonCallback;
import org.lwjgl.glfw.GLFWScrollCallback;
+import org.lwjgl.glfw.GLFWVidMode;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
-import static org.lwjgl.glfw.GLFW.GLFW_ARROW_CURSOR;
-import static org.lwjgl.glfw.GLFW.GLFW_CURSOR;
-import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_DISABLED;
-import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_HIDDEN;
-import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_NORMAL;
-import static org.lwjgl.glfw.GLFW.GLFW_FOCUSED;
-import static org.lwjgl.glfw.GLFW.GLFW_HAND_CURSOR;
-import static org.lwjgl.glfw.GLFW.GLFW_HRESIZE_CURSOR;
-import static org.lwjgl.glfw.GLFW.GLFW_IBEAM_CURSOR;
-import static org.lwjgl.glfw.GLFW.GLFW_JOYSTICK_1;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_A;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_BACKSPACE;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_C;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_DELETE;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_DOWN;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_END;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_ENTER;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_HOME;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_INSERT;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_KP_ENTER;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_ALT;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_CONTROL;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_SHIFT;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_SUPER;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_PAGE_DOWN;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_PAGE_UP;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_ALT;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_CONTROL;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_SHIFT;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_SUPER;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_SPACE;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_TAB;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_UP;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_V;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_X;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_Y;
-import static org.lwjgl.glfw.GLFW.GLFW_KEY_Z;
-import static org.lwjgl.glfw.GLFW.GLFW_PRESS;
-import static org.lwjgl.glfw.GLFW.GLFW_RELEASE;
-import static org.lwjgl.glfw.GLFW.GLFW_VRESIZE_CURSOR;
-import static org.lwjgl.glfw.GLFW.glfwCreateStandardCursor;
-import static org.lwjgl.glfw.GLFW.glfwDestroyCursor;
-import static org.lwjgl.glfw.GLFW.glfwGetClipboardString;
-import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
-import static org.lwjgl.glfw.GLFW.glfwGetFramebufferSize;
-import static org.lwjgl.glfw.GLFW.glfwGetInputMode;
-import static org.lwjgl.glfw.GLFW.glfwGetJoystickAxes;
-import static org.lwjgl.glfw.GLFW.glfwGetJoystickButtons;
-import static org.lwjgl.glfw.GLFW.glfwGetMouseButton;
-import static org.lwjgl.glfw.GLFW.glfwGetTime;
-import static org.lwjgl.glfw.GLFW.glfwGetWindowAttrib;
-import static org.lwjgl.glfw.GLFW.glfwGetWindowSize;
-import static org.lwjgl.glfw.GLFW.glfwSetCharCallback;
-import static org.lwjgl.glfw.GLFW.glfwSetClipboardString;
-import static org.lwjgl.glfw.GLFW.glfwSetCursor;
-import static org.lwjgl.glfw.GLFW.glfwSetCursorPos;
-import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
-import static org.lwjgl.glfw.GLFW.glfwSetInputMode;
-import static org.lwjgl.glfw.GLFW.glfwSetKeyCallback;
-import static org.lwjgl.glfw.GLFW.glfwSetMouseButtonCallback;
-import static org.lwjgl.glfw.GLFW.glfwSetScrollCallback;
+import static org.lwjgl.glfw.GLFW.*;
+import static org.lwjgl.system.MemoryUtil.NULL;
/**
* This class is a straightforward port of the
@@ -111,24 +61,38 @@ public class ImGuiImplGlfw {
// For mouse tracking
private final boolean[] mouseJustPressed = new boolean[ImGuiMouseButton.COUNT];
private final ImVec2 mousePosBackup = new ImVec2();
- private final double[] cursorPosX = new double[1];
- private final double[] cursorPosY = new double[1];
+ private final double[] mouseX = new double[1];
+ private final double[] mouseY = new double[1];
+
+ private final int[] windowX = new int[1];
+ private final int[] windowY = new int[1];
+
+ private final int[] monitorX = new int[1];
+ private final int[] monitorY = new int[1];
+ private final int[] monitorWorkAreaX = new int[1];
+ private final int[] monitorWorkAreaY = new int[1];
+ private final int[] monitorWorkAreaWidth = new int[1];
+ private final int[] monitorWorkAreaHeight = new int[1];
+ private final float[] monitorContentScaleX = new float[1];
+ private final float[] monitorContentScaleY = new float[1];
// GLFW callbacks
- private GLFWMouseButtonCallback previousMouseButtonCallback = null;
- private GLFWScrollCallback previousScrollCallback = null;
- private GLFWKeyCallback previousKeyCallback = null;
- private GLFWCharCallback previousCharCallback = null;
+ private GLFWMouseButtonCallback prevUserCallbackMouseButton = null;
+ private GLFWScrollCallback prevUserCallbackScroll = null;
+ private GLFWKeyCallback prevUserCallbackKey = null;
+ private GLFWCharCallback prevUserCallbackChar = null;
+ private GLFWMonitorCallback prevUserCallbackMonitor = null;
- private boolean callbacksInstalled;
+ private boolean callbacksInstalled = false;
+ private boolean wantUpdateMonitors = true;
private double time = 0.0;
/**
* Method to set the {@link GLFWMouseButtonCallback}.
*/
public void mouseButtonCallback(final long windowId, final int button, final int action, final int mods) {
- if (previousMouseButtonCallback != null) {
- previousMouseButtonCallback.invoke(windowId, button, action, mods);
+ if (prevUserCallbackMouseButton != null && windowId == windowPtr) {
+ prevUserCallbackMouseButton.invoke(windowId, button, action, mods);
}
if (action == GLFW_PRESS && button >= 0 && button < mouseJustPressed.length) {
@@ -140,8 +104,8 @@ public class ImGuiImplGlfw {
* Method to set the {@link GLFWScrollCallback}.
*/
public void scrollCallback(final long windowId, final double xOffset, final double yOffset) {
- if (previousScrollCallback != null) {
- previousScrollCallback.invoke(windowId, xOffset, yOffset);
+ if (prevUserCallbackScroll != null && windowId == windowPtr) {
+ prevUserCallbackScroll.invoke(windowId, xOffset, yOffset);
}
final ImGuiIO io = ImGui.getIO();
@@ -153,8 +117,8 @@ public class ImGuiImplGlfw {
* Method to set the {@link GLFWKeyCallback}.
*/
public void keyCallback(final long windowId, final int key, final int scancode, final int action, final int mods) {
- if (previousKeyCallback != null) {
- previousKeyCallback.invoke(windowId, key, scancode, action, mods);
+ if (prevUserCallbackKey != null && windowId == windowPtr) {
+ prevUserCallbackKey.invoke(windowId, key, scancode, action, mods);
}
final ImGuiIO io = ImGui.getIO();
@@ -175,14 +139,21 @@ public class ImGuiImplGlfw {
* Method to set the {@link GLFWCharCallback}.
*/
public void charCallback(final long windowId, final int c) {
- if (previousCharCallback != null) {
- previousCharCallback.invoke(windowId, c);
+ if (prevUserCallbackChar != null && windowId == windowPtr) {
+ prevUserCallbackChar.invoke(windowId, c);
}
final ImGuiIO io = ImGui.getIO();
io.addInputCharacter(c);
}
+ /**
+ * Method to set the {@link GLFWMonitorCallback}.
+ */
+ public void monitorCallback(final long windowId, final int event) {
+ wantUpdateMonitors = true;
+ }
+
/**
* Method to do an initialization of the {@link ImGuiImplGlfw} state. It SHOULD be called before calling the {@link ImGuiImplGlfw#newFrame()} method.
*
@@ -193,7 +164,7 @@ public class ImGuiImplGlfw {
final ImGuiIO io = ImGui.getIO();
- io.addBackendFlags(ImGuiBackendFlags.HasMouseCursors | ImGuiBackendFlags.HasSetMousePos);
+ io.addBackendFlags(ImGuiBackendFlags.HasMouseCursors | ImGuiBackendFlags.HasSetMousePos | ImGuiBackendFlags.PlatformHasViewports);
io.setBackendPlatformName("imgui_java_impl_glfw");
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
@@ -253,24 +224,72 @@ public class ImGuiImplGlfw {
if (installCallbacks) {
callbacksInstalled = true;
- previousMouseButtonCallback = glfwSetMouseButtonCallback(windowId, this::mouseButtonCallback);
- previousScrollCallback = glfwSetScrollCallback(windowId, this::scrollCallback);
- previousKeyCallback = glfwSetKeyCallback(windowId, this::keyCallback);
- previousCharCallback = glfwSetCharCallback(windowId, this::charCallback);
+ prevUserCallbackMouseButton = glfwSetMouseButtonCallback(windowId, this::mouseButtonCallback);
+ prevUserCallbackScroll = glfwSetScrollCallback(windowId, this::scrollCallback);
+ prevUserCallbackKey = glfwSetKeyCallback(windowId, this::keyCallback);
+ prevUserCallbackChar = glfwSetCharCallback(windowId, this::charCallback);
+ prevUserCallbackMonitor = glfwSetMonitorCallback(this::monitorCallback);
+ }
+
+ // Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
+ updateMonitors();
+ glfwSetMonitorCallback(this::monitorCallback);
+
+ // Our mouse update function expect PlatformHandle to be filled for the main viewport
+ final ImGuiViewport mainViewport = ImGui.getMainViewport();
+ mainViewport.setPlatformHandle(windowPtr);
+
+ if ((io.getConfigFlags() & ImGuiConfigFlags.ViewportsEnable) != 0) {
+ initPlatformInterface();
}
return true;
}
+ /**
+ * Updates {@link ImGuiIO} and {@link org.lwjgl.glfw.GLFW} state.
+ */
+ public void newFrame() {
+ final ImGuiIO io = ImGui.getIO();
+ if (!io.getFonts().isBuilt()) {
+ throw new IllegalStateException(
+ "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer init() method? e.g. ImGuiImplGl3.init()"
+ );
+ }
+
+ glfwGetWindowSize(windowPtr, winWidth, winHeight);
+ glfwGetFramebufferSize(windowPtr, fbWidth, fbHeight);
+
+ io.setDisplaySize((float) winWidth[0], (float) winHeight[0]);
+ if (winWidth[0] > 0 && winHeight[0] > 0) {
+ final float scaleX = (float) fbWidth[0] / winWidth[0];
+ final float scaleY = (float) fbHeight[0] / winHeight[0];
+ io.setDisplayFramebufferScale(scaleX, scaleY);
+ }
+ if (wantUpdateMonitors) {
+ updateMonitors();
+ }
+
+ final double currentTime = glfwGetTime();
+ io.setDeltaTime(time > 0.0 ? (float) (currentTime - time) : 1.0f / 60.0f);
+ time = currentTime;
+
+ updateMousePosAndButtons();
+ updateMouseCursor();
+ updateGamepads();
+ }
+
/**
* Method to restore {@link org.lwjgl.glfw.GLFW} to it's state prior to calling method {@link ImGuiImplGlfw#init(long, boolean)}.
*/
public void dispose() {
+ shutdownPlatformInterface();
+
if (callbacksInstalled) {
- glfwSetMouseButtonCallback(windowPtr, previousMouseButtonCallback);
- glfwSetScrollCallback(windowPtr, previousScrollCallback);
- glfwSetKeyCallback(windowPtr, previousKeyCallback);
- glfwSetCharCallback(windowPtr, previousCharCallback);
+ glfwSetMouseButtonCallback(windowPtr, prevUserCallbackMouseButton);
+ glfwSetScrollCallback(windowPtr, prevUserCallbackScroll);
+ glfwSetKeyCallback(windowPtr, prevUserCallbackKey);
+ glfwSetCharCallback(windowPtr, prevUserCallbackChar);
callbacksInstalled = false;
}
@@ -290,14 +309,35 @@ public class ImGuiImplGlfw {
io.getMousePos(mousePosBackup);
io.setMousePos(-Float.MAX_VALUE, -Float.MAX_VALUE);
+ io.setMouseHoveredViewport(0);
- final boolean focused = glfwGetWindowAttrib(windowPtr, GLFW_FOCUSED) != 0;
- if (focused) {
- if (io.getWantSetMousePos()) {
- glfwSetCursorPos(windowPtr, mousePosBackup.x, mousePosBackup.y);
- } else {
- glfwGetCursorPos(windowPtr, cursorPosX, cursorPosY);
- io.setMousePos((float) cursorPosX[0], (float) cursorPosY[0]);
+ final ImGuiPlatformIO platformIO = ImGui.getPlatformIO();
+
+ for (int n = 0; n < platformIO.getViewportsSize(); n++) {
+ final ImGuiViewport viewport = platformIO.getViewports(n);
+ final long windowPtr = viewport.getPlatformHandle();
+
+ final boolean focused = glfwGetWindowAttrib(windowPtr, GLFW_FOCUSED) != 0;
+
+ if (focused) {
+ if (io.getWantSetMousePos()) {
+ glfwSetCursorPos(windowPtr, mousePosBackup.x - viewport.getPosX(), mousePosBackup.y - viewport.getPosY());
+ } else {
+ glfwGetCursorPos(windowPtr, mouseX, mouseY);
+
+ if ((io.getConfigFlags() & ImGuiConfigFlags.ViewportsEnable) != 0) {
+ // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
+ glfwGetWindowPos(windowPtr, windowX, windowY);
+ io.setMousePos((float) mouseX[0] + windowX[0], (float) mouseY[0] + windowY[0]);
+ } else {
+ // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
+ io.setMousePos((float) mouseX[0], (float) mouseY[0]);
+ }
+ }
+
+ for (int i = 0; i < ImGuiMouseButton.COUNT; i++) {
+ io.setMouseDown(i, glfwGetMouseButton(windowPtr, i) != 0);
+ }
}
}
}
@@ -312,13 +352,21 @@ public class ImGuiImplGlfw {
return;
}
- final int cursor = ImGui.getMouseCursor();
+ final int imguiCursor = ImGui.getMouseCursor();
+ final ImGuiPlatformIO platformIO = ImGui.getPlatformIO();
- if (cursor == ImGuiMouseCursor.None || io.getMouseDrawCursor()) {
- glfwSetInputMode(windowPtr, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
- } else {
- glfwSetCursor(windowPtr, mouseCursors[cursor] != 0 ? mouseCursors[cursor] : mouseCursors[ImGuiMouseCursor.Arrow]);
- glfwSetInputMode(windowPtr, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+ for (int n = 0; n < platformIO.getViewportsSize(); n++) {
+ final long windowPtr = platformIO.getViewports(n).getPlatformHandle();
+
+ if (imguiCursor == ImGuiMouseCursor.None || io.getMouseDrawCursor()) {
+ // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
+ glfwSetInputMode(windowPtr, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+ } else {
+ // Show OS mouse cursor
+ // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
+ glfwSetCursor(windowPtr, mouseCursors[imguiCursor] != 0 ? mouseCursors[imguiCursor] : mouseCursors[ImGuiMouseCursor.Arrow]);
+ glfwSetInputMode(windowPtr, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+ }
}
}
@@ -355,9 +403,9 @@ public class ImGuiImplGlfw {
mapAnalog(ImGuiNavInput.LStickDown, 1, -0.3f, -0.9f, axis, axisCount, io);
if (axisCount > 0 && buttonsCount > 0) {
- io.setBackendFlags(io.getBackendFlags() | ImGuiBackendFlags.HasGamepad);
+ io.addBackendFlags(ImGuiBackendFlags.HasGamepad);
} else {
- io.setBackendFlags(io.getBackendFlags() & ~ImGuiBackendFlags.HasGamepad);
+ io.removeBackendFlags(ImGuiBackendFlags.HasGamepad);
}
}
@@ -386,33 +434,274 @@ public class ImGuiImplGlfw {
}
}
- /**
- * Updates {@link ImGuiIO} and {@link org.lwjgl.glfw.GLFW} state.
- */
- public void newFrame() {
- final ImGuiIO io = ImGui.getIO();
- if (!io.getFonts().isBuilt()) {
- throw new IllegalStateException(
- "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer init() method? e.g. ImGuiImplGl3.init()"
- );
+ private void updateMonitors() {
+ final ImGuiPlatformIO platformIO = ImGui.getPlatformIO();
+ final PointerBuffer monitors = glfwGetMonitors();
+
+ platformIO.resizeMonitors(0);
+
+ for (int n = 0; n < monitors.limit(); n++) {
+ final long monitor = monitors.get(n);
+
+ glfwGetMonitorPos(monitor, monitorX, monitorY);
+ final GLFWVidMode vidMode = glfwGetVideoMode(monitor);
+ final float mainPosX = monitorX[0];
+ final float mainPosY = monitorY[0];
+ final float mainSizeX = vidMode.width();
+ final float mainSizeY = vidMode.height();
+
+ glfwGetMonitorWorkarea(monitor, monitorWorkAreaX, monitorWorkAreaY, monitorWorkAreaWidth, monitorWorkAreaHeight);
+ final float workPosX = monitorWorkAreaX[0];
+ final float workPosY = monitorWorkAreaY[0];
+ final float workSizeX = monitorWorkAreaWidth[0];
+ final float workSizeY = monitorWorkAreaHeight[0];
+
+ // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings,
+ // which generally needs to be set in the manifest or at runtime.
+ glfwGetMonitorContentScale(monitor, monitorContentScaleX, monitorContentScaleY);
+ final float dpiScale = monitorContentScaleX[0];
+
+ platformIO.pushMonitors(mainPosX, mainPosY, mainSizeX, mainSizeY, workPosX, workPosY, workSizeX, workSizeY, dpiScale);
}
- glfwGetWindowSize(windowPtr, winWidth, winHeight);
- glfwGetFramebufferSize(windowPtr, fbWidth, fbHeight);
+ wantUpdateMonitors = false;
+ }
- io.setDisplaySize((float) winWidth[0], (float) winHeight[0]);
- if (winWidth[0] > 0 && winHeight[0] > 0) {
- final float scaleX = (float) fbWidth[0] / winWidth[0];
- final float scaleY = (float) fbHeight[0] / winHeight[0];
- io.setDisplayFramebufferScale(scaleX, scaleY);
+ //--------------------------------------------------------------------------------------------------------
+ // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
+ // This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
+ // If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
+ //--------------------------------------------------------------------------------------------------------
+
+ private void windowCloseCallback(final long windowId) {
+ final ImGuiViewport vp = ImGui.findViewportByPlatformHandle(windowId);
+ vp.setPlatformRequestClose(true);
+ }
+
+ // GLFW may dispatch window pos/size events after calling glfwSetWindowPos()/glfwSetWindowSize().
+ // However: depending on the platform the callback may be invoked at different time:
+ // - on Windows it appears to be called within the glfwSetWindowPos()/glfwSetWindowSize() call
+ // - on Linux it is queued and invoked during glfwPollEvents()
+ // Because the event doesn't always fire on glfwSetWindowXXX() we use a frame counter tag to only
+ // ignore recent glfwSetWindowXXX() calls.
+ private void windowPosCallback(final long windowId, final int xPos, final int yPos) {
+ final ImGuiViewport vp = ImGui.findViewportByPlatformHandle(windowId);
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ final boolean ignoreEvent = (ImGui.getFrameCount() <= data.ignoreWindowPosEventFrame + 1);
+
+ if (ignoreEvent) {
+ return;
}
- final double currentTime = glfwGetTime();
- io.setDeltaTime(time > 0.0 ? (float) (currentTime - time) : 1.0f / 60.0f);
- time = currentTime;
+ vp.setPlatformRequestMove(true);
+ }
- updateMousePosAndButtons();
- updateMouseCursor();
- updateGamepads();
+ private void windowSizeCallback(final long windowId, final int width, final int height) {
+ final ImGuiViewport vp = ImGui.findViewportByPlatformHandle(windowId);
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ final boolean ignoreEvent = (ImGui.getFrameCount() <= data.ignoreWindowSizeEventFrame + 1);
+
+ if (ignoreEvent) {
+ return;
+ }
+
+ vp.setPlatformRequestResize(true);
+ }
+
+ private final class CreateWindowFunction extends ImPlatformFuncViewport {
+ @Override
+ public void accept(final ImGuiViewport vp) {
+ final ImGuiViewportDataGlfw data = new ImGuiViewportDataGlfw();
+
+ vp.setPlatformUserData(data);
+
+ // GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED
+ // With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem
+ glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
+ glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
+ glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE);
+ glfwWindowHint(GLFW_DECORATED, (vp.getFlags() & ImGuiViewportFlags.NoDecoration) != 0 ? GLFW_FALSE : GLFW_TRUE);
+ glfwWindowHint(GLFW_FLOATING, (vp.getFlags() & ImGuiViewportFlags.TopMost) != 0 ? GLFW_TRUE : GLFW_FALSE);
+
+ data.window = glfwCreateWindow((int) vp.getSizeX(), (int) vp.getSizeY(), "No Title Yet", NULL, windowPtr);
+ data.windowOwned = true;
+
+ vp.setPlatformHandle(data.window);
+
+ glfwSetWindowPos(data.window, (int) vp.getPosX(), (int) vp.getPosY());
+
+ // Install GLFW callbacks for secondary viewports
+ glfwSetMouseButtonCallback(data.window, ImGuiImplGlfw.this::mouseButtonCallback);
+ glfwSetScrollCallback(data.window, ImGuiImplGlfw.this::scrollCallback);
+ glfwSetKeyCallback(data.window, ImGuiImplGlfw.this::keyCallback);
+ glfwSetCharCallback(data.window, ImGuiImplGlfw.this::charCallback);
+ glfwSetWindowCloseCallback(data.window, ImGuiImplGlfw.this::windowCloseCallback);
+ glfwSetWindowPosCallback(data.window, ImGuiImplGlfw.this::windowPosCallback);
+ glfwSetWindowSizeCallback(data.window, ImGuiImplGlfw.this::windowSizeCallback);
+
+ glfwMakeContextCurrent(data.window);
+ glfwSwapInterval(0);
+ }
+ }
+
+ private static final class DestroyWindowFunction extends ImPlatformFuncViewport {
+ @Override
+ public void accept(final ImGuiViewport vp) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+
+ if (data != null && data.windowOwned) {
+ glfwDestroyWindow(data.window);
+ }
+
+ vp.setPlatformUserData(null);
+ vp.setPlatformHandle(0);
+ }
+ }
+
+ private static final class ShowWindowFunction extends ImPlatformFuncViewport {
+ @Override
+ public void accept(final ImGuiViewport vp) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ glfwShowWindow(data.window);
+ }
+ }
+
+ private static final class GetWindowPosFunction extends ImPlatformFuncViewportSuppImVec2 {
+ private final int[] posX = new int[1];
+ private final int[] posY = new int[1];
+
+ @Override
+ public void get(final ImGuiViewport vp, final ImVec2 dstImVec2) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ glfwGetWindowPos(data.window, posX, posY);
+ dstImVec2.x = posX[0];
+ dstImVec2.y = posY[0];
+ }
+ }
+
+ private static final class SetWindowPosFunction extends ImPlatformFuncViewportImVec2 {
+ @Override
+ public void accept(final ImGuiViewport vp, final ImVec2 imVec2) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ data.ignoreWindowPosEventFrame = ImGui.getFrameCount();
+ glfwSetWindowPos(data.window, (int) imVec2.x, (int) imVec2.y);
+ }
+ }
+
+ private static final class GetWindowSizeFunction extends ImPlatformFuncViewportSuppImVec2 {
+ private final int[] width = new int[1];
+ private final int[] height = new int[1];
+
+ @Override
+ public void get(final ImGuiViewport vp, final ImVec2 dstImVec2) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ glfwGetWindowSize(data.window, width, height);
+ dstImVec2.x = width[0];
+ dstImVec2.y = height[0];
+ }
+ }
+
+ private static final class SetWindowSizeFunction extends ImPlatformFuncViewportImVec2 {
+ @Override
+ public void accept(final ImGuiViewport vp, final ImVec2 imVec2) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ data.ignoreWindowSizeEventFrame = ImGui.getFrameCount();
+ glfwSetWindowSize(data.window, (int) imVec2.y, (int) imVec2.y);
+ }
+ }
+
+ private static final class SetWindowTitleFunction extends ImPlatformFuncViewportString {
+ @Override
+ public void accept(final ImGuiViewport vp, final String str) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ glfwSetWindowTitle(data.window, str);
+ }
+ }
+
+ private static final class SetWindowFocusFunction extends ImPlatformFuncViewport {
+ @Override
+ public void accept(final ImGuiViewport vp) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ glfwFocusWindow(data.window);
+ }
+ }
+
+ private static final class GetWindowFocusFunction extends ImPlatformFuncViewportSuppBoolean {
+ @Override
+ public boolean get(final ImGuiViewport vp) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ return glfwGetWindowAttrib(data.window, GLFW_FOCUSED) != 0;
+ }
+ }
+
+ private static final class GetWindowMinimizedFunction extends ImPlatformFuncViewportSuppBoolean {
+ @Override
+ public boolean get(final ImGuiViewport vp) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ return glfwGetWindowAttrib(data.window, GLFW_ICONIFIED) != 0;
+ }
+ }
+
+ private static final class SetWindowAlphaFunction extends ImPlatformFuncViewportFloat {
+ @Override
+ public void accept(final ImGuiViewport vp, final float f) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ glfwSetWindowOpacity(data.window, f);
+ }
+ }
+
+ private static final class RenderWindowFunction extends ImPlatformFuncViewport {
+ @Override
+ public void accept(final ImGuiViewport vp) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ glfwMakeContextCurrent(data.window);
+ }
+ }
+
+ private static final class SwapBuffersFunction extends ImPlatformFuncViewport {
+ @Override
+ public void accept(final ImGuiViewport vp) {
+ final ImGuiViewportDataGlfw data = (ImGuiViewportDataGlfw) vp.getPlatformUserData();
+ glfwMakeContextCurrent(data.window);
+ glfwSwapBuffers(data.window);
+ }
+ }
+
+ private void initPlatformInterface() {
+ final ImGuiPlatformIO platformIO = ImGui.getPlatformIO();
+
+ // Register platform interface (will be coupled with a renderer interface)
+ platformIO.setPlatformCreateWindow(new CreateWindowFunction());
+ platformIO.setPlatformDestroyWindow(new DestroyWindowFunction());
+ platformIO.setPlatformShowWindow(new ShowWindowFunction());
+ platformIO.setPlatformGetWindowPos(new GetWindowPosFunction());
+ platformIO.setPlatformSetWindowPos(new SetWindowPosFunction());
+ platformIO.setPlatformGetWindowSize(new GetWindowSizeFunction());
+ platformIO.setPlatformSetWindowSize(new SetWindowSizeFunction());
+ platformIO.setPlatformSetWindowTitle(new SetWindowTitleFunction());
+ platformIO.setPlatformSetWindowFocus(new SetWindowFocusFunction());
+ platformIO.setPlatformGetWindowFocus(new GetWindowFocusFunction());
+ platformIO.setPlatformGetWindowMinimized(new GetWindowMinimizedFunction());
+ platformIO.setPlatformSetWindowAlpha(new SetWindowAlphaFunction());
+ platformIO.setPlatformRenderWindow(new RenderWindowFunction());
+ platformIO.setPlatformSwapBuffers(new SwapBuffersFunction());
+
+ // Register main window handle (which is owned by the main application, not by us)
+ // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
+ final ImGuiViewport mainViewport = ImGui.getMainViewport();
+ final ImGuiViewportDataGlfw data = new ImGuiViewportDataGlfw();
+ data.window = windowPtr;
+ data.windowOwned = false;
+ mainViewport.setPlatformUserData(data);
+ }
+
+ private void shutdownPlatformInterface() {
+ }
+
+ private static final class ImGuiViewportDataGlfw {
+ long window;
+ boolean windowOwned = false;
+ int ignoreWindowPosEventFrame = -1;
+ int ignoreWindowSizeEventFrame = -1;
}
}
diff --git a/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java b/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java
index 8ba4de1..6f81dd3 100644
--- a/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java
+++ b/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java
@@ -1,29 +1,5 @@
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
-import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR;
-import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR;
-import static org.lwjgl.glfw.GLFW.GLFW_FALSE;
-import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE;
-import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_FORWARD_COMPAT;
-import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE;
-import static org.lwjgl.glfw.GLFW.GLFW_TRUE;
-import static org.lwjgl.glfw.GLFW.GLFW_VISIBLE;
-import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
-import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
-import static org.lwjgl.glfw.GLFW.glfwDestroyWindow;
-import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor;
-import static org.lwjgl.glfw.GLFW.glfwGetVideoMode;
-import static org.lwjgl.glfw.GLFW.glfwGetWindowSize;
-import static org.lwjgl.glfw.GLFW.glfwInit;
-import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
-import static org.lwjgl.glfw.GLFW.glfwPollEvents;
-import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
-import static org.lwjgl.glfw.GLFW.glfwSetWindowPos;
-import static org.lwjgl.glfw.GLFW.glfwShowWindow;
-import static org.lwjgl.glfw.GLFW.glfwSwapBuffers;
-import static org.lwjgl.glfw.GLFW.glfwSwapInterval;
-import static org.lwjgl.glfw.GLFW.glfwTerminate;
-import static org.lwjgl.glfw.GLFW.glfwWindowHint;
-import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose;
+import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL32.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL32.GL_TRUE;
import static org.lwjgl.opengl.GL32.glClear;
@@ -65,23 +41,20 @@ public final class ImGuiGlfwExample {
private final ExampleUi exampleUi = new ExampleUi();
public void run() throws Exception {
- // IMPORTANT!!
- // This line is critical for Dear ImGui to work.
- ImGui.createContext();
+ setupGlfw();
+ setupImGui();
// Method initializes GLFW backend.
// This method SHOULD be called after you've setup GLFW.
// ImGui context should be created as well.
- setupGlfw();
imGuiGlfw.init(windowPtr, true);
-
// Method initializes LWJGL3 renderer.
// This method SHOULD be called after you've initialized your ImGui configuration (fonts and so on).
// ImGui context should be created as well.
- setupImGui();
imGuiGl3.init(glslVersion);
exampleUi.init();
+
loop();
// You should clean up after yourself in reverse order.
@@ -162,12 +135,16 @@ public final class ImGuiGlfwExample {
// Initialize Dear ImGui.
private void setupImGui() {
+ // IMPORTANT!!
+ // This line is critical for Dear ImGui to work.
+ ImGui.createContext();
+
// ------------------------------------------------------------
// Initialize ImGuiIO config
final ImGuiIO io = ImGui.getIO();
io.setIniFilename(null); // We don't want to save .ini file
- io.addConfigFlags(ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable); // Navigation with keyboard and enabled docking
+ io.addConfigFlags(ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable);
// ------------------------------------------------------------
// Fonts configuration
@@ -235,7 +212,14 @@ public final class ImGuiGlfwExample {
private void endFrame() {
// After Dear ImGui prepared a draw data, we use it in the LWJGL3 renderer.
// At that moment ImGui will be rendered to the current OpenGL context.
- imGuiGl3.render(ImGui.getDrawData());
+ imGuiGl3.renderDrawData(ImGui.getDrawData());
+
+ if ((ImGui.getIO().getConfigFlags() & ImGuiConfigFlags.ViewportsEnable) != 0) {
+ final long backupWindowPtr = glfwGetCurrentContext();
+ ImGui.updatePlatformWindows();
+ ImGui.renderPlatformWindowsDefault();
+ glfwMakeContextCurrent(backupWindowPtr);
+ }
glfwSwapBuffers(windowPtr);
glfwPollEvents();