From 5d93d3b1f53421f6ea79f83eed65d00d9b3fe413 Mon Sep 17 00:00:00 2001 From: arimu1 <19286898+arimu1@users.noreply.github.com> Date: Fri, 31 Jul 2026 17:54:04 +0700 Subject: [PATCH] fix(lwjgl3): ensure GL device objects before renderDrawData Since 1.87, ImGuiImplGl3 creates the shader/program/VBO and font texture lazily in newFrame() rather than in init(), matching upstream. Call sites that only call init() + renderDrawData() (the pre-1.87 pattern used by many jME / custom loops) then hit a native NULL dereference inside glDrawElementsBaseVertex. Share the lazy create path with renderDrawData so those upgrades no longer crash. Prefer calling newFrame() every frame; this is a safety net for the upgrade path reported in #361. Fixes #361 --- .../src/main/java/imgui/gl3/ImGuiImplGl3.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java b/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java index 7a135a84..ba5c7fa8 100644 --- a/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java +++ b/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java @@ -242,6 +242,10 @@ public boolean init() { * Method to do an initialization of the {@link ImGuiImplGl3} state. * It SHOULD be called before calling of the {@link ImGuiImplGl3#renderDrawData(ImDrawData)} method. *
+ * GL device objects (shader, buffers, font texture) are not created here; they are + * created lazily on the first {@link #newFrame()} or {@link #renderDrawData(ImDrawData)} call + * (behavior since 1.87, matching upstream). Prefer calling {@link #newFrame()} every frame. + *
* Method takes an argument, which should be a valid GLSL string with the version to use. *
* ----------------------------------------
@@ -371,7 +375,25 @@ public void shutdown() {
data = null;
}
+ /**
+ * Prepare per-frame GL resources.
+ *
+ * Since Dear ImGui 1.87 / imgui-java 1.87, shader program, buffers and the font
+ * texture are created lazily here (not in {@link #init(String)}). Call this every
+ * frame before {@link ImGui#newFrame()}, or at least once after {@code init} and
+ * before the first {@link #renderDrawData(ImDrawData)}.
+ */
public void newFrame() {
+ ensureDeviceObjects();
+ }
+
+ /**
+ * Create shader/program/VBO and font texture if they are not yet available.
+ * Shared by {@link #newFrame()} and {@link #renderDrawData(ImDrawData)} so that
+ * integrators that only call {@code init} + {@code renderDrawData} (the pre-1.87
+ * pattern) do not hit a native NULL dereference in {@code glDrawElementsBaseVertex}.
+ */
+ protected void ensureDeviceObjects() {
if (data.shaderHandle == 0) {
createDeviceObjects();
}
@@ -470,6 +492,12 @@ public void renderDrawData(final ImDrawData drawData) {
return;
}
+ // Device objects used to be created in init() (imgui-java <= 1.86). Since 1.87 they are
+ // created lazily in newFrame() to match upstream imgui_impl_opengl3. Ensure them here as
+ // well so call sites that skip newFrame() (common after upgrades; see #361) do not crash
+ // with a native NULL pointer inside glDrawElementsBaseVertex.
+ ensureDeviceObjects();
+
// In C++: iterates draw_data->Textures and calls ImGui_ImplOpenGL3_UpdateTexture for each non-OK status.
// In Java: ImTextureData is not exposed in imgui-binding (follow-up); we keep the legacy createFontsTexture
// path triggered from newFrame(), so dynamic atlas updates are not honored here yet.