From 283e78070ce6c369b8d05d014766330fe3e56812 Mon Sep 17 00:00:00 2001 From: SpaiR Date: Sun, 17 May 2020 16:15:12 +0300 Subject: [PATCH] Simplify, improve and optimize the rendering for LWJGL3 --- config/checkstyle/checkstyle.xml | 2 +- .../src/main/java/imgui/ImDrawData.java | 335 +++++++++++------- .../src/main/java/imgui/ImDrawList.java | 7 +- imgui-binding/src/main/java/imgui/ImGui.java | 20 +- .../src/main/java/imgui/gl3/ImGuiImplGl3.java | 149 +++----- .../src/test/java/ImGuiGlfwExample.java | 2 +- 6 files changed, 274 insertions(+), 241 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 97e9d1d..3f4e356 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -121,7 +121,7 @@ - + diff --git a/imgui-binding/src/main/java/imgui/ImDrawData.java b/imgui-binding/src/main/java/imgui/ImDrawData.java index 3b3055b..6011af4 100644 --- a/imgui-binding/src/main/java/imgui/ImDrawData.java +++ b/imgui-binding/src/main/java/imgui/ImDrawData.java @@ -1,173 +1,234 @@ package imgui; -import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** - * All draw data to render a Dear ImGui frame. + * All draw data to render Dear ImGui frame + * (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose, + * as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) *

- * BINDING NOTICE: DO NOT TRY TO MODIFY FIELDS OF THIS CLASS MANUALLY! You should only access their values after {@link ImGui#render()} call. + * BINDING NOTICE: Since it's impossible to do a 1:1 mapping with JNI, current class provides "getCmdList*()" methods. + * Those are used to get the data needed to do a rendering. */ -public final class ImDrawData { - public static final int V_BUFFER_SIZE = (4 + 1) * 4; - public static final int I_BUFFER_SIZE = 2; - public static final int CMD_BUFFER_SIZE = (1 + 4 + 1) * 4; +public final class ImDrawData implements ImDestroyable { + public static final int SIZEOF_IM_DRAW_IDX = 2; + public static final int SIZEOF_IM_DRAW_VERT = (4 + 1) * 4; - public ByteBuffer vByteBuffer; - public ByteBuffer iByteBuffer; - public ByteBuffer cmdByteBuffer; + private static final int COUNT_FACTOR = 5_000; - public int totalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size - public int totalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size - public int cmdListsCount; // Number of ImDrawList* to render + final long ptr; - // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) - // - public float displayPosX; - public float displayPosY; + private ByteBuffer idxBuffer = ByteBuffer.allocateDirect(SIZEOF_IM_DRAW_IDX * COUNT_FACTOR).order(ByteOrder.nativeOrder()); + private ByteBuffer vtxBuffer = ByteBuffer.allocateDirect(SIZEOF_IM_DRAW_VERT * COUNT_FACTOR).order(ByteOrder.nativeOrder()); - // Size of the viewport to render (== io.DisplaySize for the main viewport) - // (DisplayPos+DisplaySize == lower-right of the orthogonal projection matrix to use) - // - public float displaySizeX; - public float displaySizeY; + /** + * This class will create a native structure. + * Call {@link #destroy()} method to manually free used memory. + */ + public ImDrawData() { + ImGui.touch(); + ptr = nCreate(); + } - // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. - // - public float framebufferScaleX; - public float framebufferScaleY; + ImDrawData(final long ptr) { + this.ptr = ptr; + } - ImDrawData(final int maxVertices, final int maxIndices, final int maxCmd) { - vByteBuffer = ByteBuffer.allocateDirect(maxVertices * V_BUFFER_SIZE).order(ByteOrder.nativeOrder()); - iByteBuffer = ByteBuffer.allocateDirect(maxIndices * I_BUFFER_SIZE).order(ByteOrder.nativeOrder()); - cmdByteBuffer = ByteBuffer.allocateDirect(maxCmd * CMD_BUFFER_SIZE).order(ByteOrder.nativeOrder()); + @Override + public void destroy() { + nDestroy(ptr); } /*JNI #include #include + #include "jni_common.h" - jfieldID totalVtxCountID; - jfieldID totalIdxCountID; - jfieldID CmdListsCountID; - jfieldID displayPosXID; - jfieldID displayPosYID; - jfieldID displaySizeXID; - jfieldID displaySizeYID; - jfieldID framebufferScaleXID; - jfieldID framebufferScaleYID; + jfieldID imDrawDataPtrID; + + #define IM_DRAW_DATA ((ImDrawData*)env->GetLongField(object, imDrawDataPtrID)) */ static native void nInit(); /* - jclass jDrawDataClass = env->FindClass("imgui/ImDrawData"); - - totalVtxCountID = env->GetFieldID(jDrawDataClass, "totalVtxCount", "I"); - totalIdxCountID = env->GetFieldID(jDrawDataClass, "totalIdxCount", "I"); - CmdListsCountID = env->GetFieldID(jDrawDataClass, "cmdListsCount", "I"); - displayPosXID = env->GetFieldID(jDrawDataClass, "displayPosX", "F"); - displayPosYID = env->GetFieldID(jDrawDataClass, "displayPosY", "F"); - displaySizeXID = env->GetFieldID(jDrawDataClass, "displaySizeX", "F"); - displaySizeYID = env->GetFieldID(jDrawDataClass, "displaySizeY", "F"); - framebufferScaleXID = env->GetFieldID(jDrawDataClass, "framebufferScaleX", "F"); - framebufferScaleYID = env->GetFieldID(jDrawDataClass, "framebufferScaleY", "F"); + jclass jImDrawDataClass = env->FindClass("imgui/ImDrawData"); + imDrawDataPtrID = env->GetFieldID(jImDrawDataClass, "ptr", "J"); */ - native void nFillDrawData(Buffer indexBuffer, Buffer vertexBuffer, Buffer cmdBuffer); /* - ImDrawData* drawData = ImGui::GetDrawData(); + private native long nCreate(); /* + ImDrawData* imDrawData = new ImDrawData(); + return (intptr_t)imDrawData; + */ - if (drawData == NULL) { - return; + private native void nDestroy(long ptr); /* + delete (ImDrawData*)ptr; + */ + + ///////// Start of Render Methods | Binding + + /** + * Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. + */ + public native int getCmdListCmdBufferSize(int cmdListIdx); /* + return IM_DRAW_DATA->CmdLists[cmdListIdx]->CmdBuffer.Size; + */ + + /** + * Number of indices (multiple of 3) to be rendered as triangles. + * Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. + */ + public native int getCmdListCmdBufferElemCount(int cmdListIdx, int cmdBufferIdx); /* + return IM_DRAW_DATA->CmdLists[cmdListIdx]->CmdBuffer[cmdBufferIdx].ElemCount; + */ + + /** + * Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates + */ + public native void getCmdListCmdBufferClipRect(int cmdListIdx, int cmdBufferIdx, ImVec4 dstImVec4); /* + Jni::ImVec4Cpy(env, &IM_DRAW_DATA->CmdLists[cmdListIdx]->CmdBuffer[cmdBufferIdx].ClipRect, dstImVec4); + */ + + /** + * User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. + * Ignore if never using images or multiple fonts atlas. + */ + public native int getCmdListCmdBufferTextureId(int cmdListIdx, int cmdBufferIdx); /* + return (intptr_t)IM_DRAW_DATA->CmdLists[cmdListIdx]->CmdBuffer[cmdBufferIdx].TextureId; + */ + + /** + * Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. + * With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bit indices. + */ + public native int getCmdListCmdBufferVtxOffset(int cmdListIdx, int cmdBufferIdx); /* + return IM_DRAW_DATA->CmdLists[cmdListIdx]->CmdBuffer[cmdBufferIdx].VtxOffset; + */ + + /** + * Start offset in index buffer. Always equal to sum of ElemCount drawn so far. + */ + public native int getCmdListCmdBufferIdxOffset(int cmdListIdx, int cmdBufferIdx); /* + return IM_DRAW_DATA->CmdLists[cmdListIdx]->CmdBuffer[cmdBufferIdx].IdxOffset; + */ + + /** + * Index buffer. Each command consume ImDrawCmd::ElemCount of those + */ + public native int getCmdListIdxBufferSize(int cmdListIdx); /* + return IM_DRAW_DATA->CmdLists[cmdListIdx]->IdxBuffer.Size; + */ + + public ByteBuffer getCmdListIdxBufferData(final int cmdListIdx) { + final int idxBufferCapacity = getCmdListIdxBufferSize(cmdListIdx) * SIZEOF_IM_DRAW_IDX; + if (idxBuffer.capacity() < idxBufferCapacity) { + idxBuffer = ByteBuffer.allocateDirect(idxBufferCapacity + COUNT_FACTOR).order(ByteOrder.nativeOrder()); } - int cmdListsCount = drawData->CmdListsCount; + nGetCmdListIdxBufferData(cmdListIdx, idxBuffer, idxBufferCapacity); - // Set values - env->SetIntField(object, totalVtxCountID, drawData->TotalVtxCount); - env->SetIntField(object, totalIdxCountID, drawData->TotalIdxCount); - env->SetIntField(object, CmdListsCountID, cmdListsCount); + idxBuffer.position(0); + idxBuffer.limit(idxBufferCapacity); - env->SetFloatField(object, displayPosXID, drawData->DisplayPos.x); - env->SetFloatField(object, displayPosYID, drawData->DisplayPos.y); + return idxBuffer; + } - env->SetFloatField(object, displaySizeXID, drawData->DisplaySize.x); - env->SetFloatField(object, displaySizeYID, drawData->DisplaySize.y); + private native void nGetCmdListIdxBufferData(int cmdListIdx, ByteBuffer idxBuffer, int idxBufferCapacity); /* + memcpy(idxBuffer, IM_DRAW_DATA->CmdLists[cmdListIdx]->IdxBuffer.Data, idxBufferCapacity); + */ - env->SetFloatField(object, framebufferScaleXID, drawData->FramebufferScale.x); - env->SetFloatField(object, framebufferScaleYID, drawData->FramebufferScale.y); + /** + * Vertex buffer. + */ + public native int getCmdListVtxBufferSize(int cmdListIdx); /* + return IM_DRAW_DATA->CmdLists[cmdListIdx]->VtxBuffer.Size; + */ - ImDrawList** drawLists = drawData->CmdLists; - - int verticesOffset = 0; - int indicesOffset = 0; - int cmdOffset = 0; - - for(int i = 0; i < cmdListsCount; i++) { - ImDrawList& drawList = *drawLists[i]; - ImVector& imDrawCmdList = drawList.CmdBuffer; - ImVector& idxBuffer = drawList.IdxBuffer; - ImVector& vtxBuffer = drawList.VtxBuffer; - - float* vertexArrayDest = (float*)vertexBuffer; - short* indexArrayDest = (short*)indexBuffer; - - int colorSize = 1; - int verticesItemSize = (4 + colorSize); - - vertexArrayDest[verticesOffset++] = vtxBuffer.Size; - - // copy vertices to Destination buffer - for(int j = 0; j < vtxBuffer.Size; j++) { - ImDrawVert v = vtxBuffer[j]; - float posX = v.pos.x; - float posY = v.pos.y; - float uvX = v.uv.x; - float uvY = v.uv.y; - - int byteIndex = (j * verticesItemSize) + verticesOffset; - - float color = 0; - memcpy(&color, &v.col, 4); // move unsigned int color to float - - vertexArrayDest[byteIndex + 0] = posX; - vertexArrayDest[byteIndex + 1] = posY; - vertexArrayDest[byteIndex + 2] = uvX; - vertexArrayDest[byteIndex + 3] = uvY; - vertexArrayDest[byteIndex + 4] = color; - } - verticesOffset += vtxBuffer.Size * verticesItemSize; - - // copy index to destination buffer - indexArrayDest[indicesOffset++] = idxBuffer.Size; - - for(int j = 0; j < idxBuffer.Size; j++) { - indexArrayDest[j + indicesOffset] = idxBuffer[j]; - } - - indicesOffset += idxBuffer.Size; - - float* cmdArrayDest = (float*)cmdBuffer; - - cmdArrayDest[cmdOffset++] = imDrawCmdList.Size; - int bytesOffset = 0; - int imDrawCmdSize = 1 + 4 + 1; - - for (int cmd_i = 0; cmd_i < imDrawCmdList.Size; cmd_i++) { - const ImDrawCmd* pcmd = &imDrawCmdList[cmd_i]; - - float textureID = (float)(intptr_t)pcmd->TextureId; - float tempArray [6] = { - (float)pcmd->ElemCount, - pcmd->ClipRect.x, pcmd->ClipRect.y, - pcmd->ClipRect.z, pcmd->ClipRect.w, - textureID - }; - - memcpy((cmdArrayDest + (cmd_i * imDrawCmdSize) + cmdOffset), tempArray, imDrawCmdSize * 4); - bytesOffset = bytesOffset + imDrawCmdSize; - } - - cmdOffset += imDrawCmdList.Size * imDrawCmdSize; + public ByteBuffer getCmdListVtxBufferData(final int cmdListIdx) { + final int vtxBufferCapacity = getCmdListVtxBufferSize(cmdListIdx) * SIZEOF_IM_DRAW_VERT; + if (vtxBuffer.capacity() < vtxBufferCapacity) { + vtxBuffer = ByteBuffer.allocateDirect(vtxBufferCapacity + COUNT_FACTOR).order(ByteOrder.nativeOrder()); } + + nGetCmdListVtxBufferData(cmdListIdx, vtxBuffer, vtxBufferCapacity); + + vtxBuffer.position(0); + vtxBuffer.limit(vtxBufferCapacity); + + return vtxBuffer; + } + + private native void nGetCmdListVtxBufferData(int cmdListIdx, ByteBuffer vtxBuffer, int vtxBufferCapacity); /* + memcpy(vtxBuffer, IM_DRAW_DATA->CmdLists[cmdListIdx]->VtxBuffer.Data, vtxBufferCapacity); + */ + + ///////// End of Render Methods + + /** + * Only valid after Render() is called and before the next NewFrame() is called. + */ + public native boolean getValid(); /* + return IM_DRAW_DATA->Valid; + */ + + /** + * Number of ImDrawList* to render + */ + public native int getCmdListsCount(); /* + return IM_DRAW_DATA->CmdListsCount; + */ + + /** + * For convenience, sum of all ImDrawList's IdxBuffer.Size + */ + public native int getTotalIdxCount(); /* + return IM_DRAW_DATA->TotalIdxCount; + */ + + /** + * For convenience, sum of all ImDrawList's VtxBuffer.Size + */ + public native int getTotalVtxCount(); /* + return IM_DRAW_DATA->TotalVtxCount; + */ + + /** + * Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) + */ + public native void getDisplayPos(ImVec2 dstImVec2); /* + Jni::ImVec2Cpy(env, &IM_DRAW_DATA->DisplayPos, dstImVec2); + */ + + /** + * Size of the viewport to render (== io.DisplaySize for the main viewport) + * (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use) + */ + public native void getDisplaySize(ImVec2 dstImVec2); /* + Jni::ImVec2Cpy(env, &IM_DRAW_DATA->DisplaySize, dstImVec2); + */ + + /** + * Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. + */ + public native void getFramebufferScale(ImVec2 dstImVec2); /* + Jni::ImVec2Cpy(env, &IM_DRAW_DATA->FramebufferScale, dstImVec2); + */ + + // Functions + + /** + * Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. + * Always prefer indexed rendering! + */ + public native void deIndexAllBuffers(); /* + IM_DRAW_DATA->DeIndexAllBuffers(); + */ + + /** + * Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, + * or if there is a difference between your window resolution and framebuffer resolution. + */ + public native void scaleClipRects(float fbScaleX, float fbScaleY); /* + const ImVec2 fbScale = ImVec2(fbScaleX, fbScaleY); + IM_DRAW_DATA->ScaleClipRects(fbScale); */ } diff --git a/imgui-binding/src/main/java/imgui/ImDrawList.java b/imgui-binding/src/main/java/imgui/ImDrawList.java index ee4ce0d..7879596 100644 --- a/imgui-binding/src/main/java/imgui/ImDrawList.java +++ b/imgui-binding/src/main/java/imgui/ImDrawList.java @@ -55,11 +55,16 @@ public final class ImDrawList { drawListTypeID = env->GetFieldID(jImDrawListClass, "drawListType", "I"); */ - // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + /** + * Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + */ public native int getImDrawListFlags(); /* return IM_DRAW_LIST->Flags; */ + /** + * Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + */ public native void setImDrawListFlags(int imDrawListFlags); /* IM_DRAW_LIST->Flags = imDrawListFlags; */ diff --git a/imgui-binding/src/main/java/imgui/ImGui.java b/imgui-binding/src/main/java/imgui/ImGui.java index eb94d1b..f198a06 100644 --- a/imgui-binding/src/main/java/imgui/ImGui.java +++ b/imgui-binding/src/main/java/imgui/ImGui.java @@ -5,7 +5,6 @@ import imgui.enums.ImGuiInputTextFlags; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; -import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -17,13 +16,13 @@ public final class ImGui { private static final String LIB_NAME_DEFAULT = System.getProperty("os.arch").contains("64") ? "imgui-java64" : "imgui-java"; private static final String LIB_TMP_DIR_PREFIX = "imgui-java-bin_" + System.getProperty("user.name", "user"); - private static final ImDrawData DRAW_DATA; private static final ImGuiIO IMGUI_IO; private static final ImDrawList IM_DRAW_LIST_WINDOW = new ImDrawList(ImDrawList.TYPE_WINDOW); private static final ImDrawList IM_DRAW_LIST_BACKGROUND = new ImDrawList(ImDrawList.TYPE_BACKGROUND); private static final ImDrawList IM_DRAW_LIST_FOREGROUND = new ImDrawList(ImDrawList.TYPE_FOREGROUND); + private static ImDrawData drawData; private static ImFont font; private static ImGuiStyle style; @@ -42,7 +41,6 @@ public final class ImGui { System.loadLibrary(libName); } - DRAW_DATA = new ImDrawData(100_000, 100_000, 1000); IMGUI_IO = new ImGuiIO(); nInitJni(); @@ -188,16 +186,16 @@ public final class ImGui { * Valid after Render() and until the next call to NewFrame(). this is what you have to render. */ public static ImDrawData getDrawData() { - final ByteBuffer cmdByteBuffer = DRAW_DATA.cmdByteBuffer; - final ByteBuffer vByteBuffer = DRAW_DATA.vByteBuffer; - final ByteBuffer iByteBuffer = DRAW_DATA.iByteBuffer; - vByteBuffer.position(0); - iByteBuffer.position(0); - cmdByteBuffer.position(0); - DRAW_DATA.nFillDrawData(iByteBuffer, vByteBuffer, cmdByteBuffer); - return DRAW_DATA; + if (drawData == null) { + drawData = new ImDrawData(nGetDrawData()); + } + return drawData; } + private static native long nGetDrawData(); /* + return (intptr_t)ImGui::GetDrawData(); + */ + // Demo, Debug, Information /** diff --git a/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java b/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java index eeed6f1..78b8b5a 100644 --- a/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java +++ b/imgui-lwjgl3/src/main/java/imgui/gl3/ImGuiImplGl3.java @@ -4,6 +4,8 @@ import imgui.ImDrawData; import imgui.ImFontAtlas; import imgui.ImGui; import imgui.ImInt; +import imgui.ImVec2; +import imgui.ImVec4; import java.io.BufferedReader; import java.io.IOException; @@ -13,7 +15,7 @@ import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.util.Objects; -import static org.lwjgl.opengl.GL30.*; +import static org.lwjgl.opengl.GL32.*; /** * This class mostly a straightforward port of the @@ -27,10 +29,14 @@ import static org.lwjgl.opengl.GL30.*; */ @SuppressWarnings("MagicNumber") public final class ImGuiImplGl3 { - private int vBufferHandle = 0; - private int iBufferHandle = 0; + private int vboHandle = 0; + private int elementsHandle = 0; - private boolean isFontInitialized = false; + // Used to store tmp renderer data + private final ImVec2 displaySize = new ImVec2(); + private final ImVec2 framebufferScale = new ImVec2(); + private final ImVec2 displayPos = new ImVec2(); + private final ImVec4 clipRect = new ImVec4(); // Shader stuff private int programId = 0; @@ -67,6 +73,8 @@ public final class ImGuiImplGl3 { public void init() { prepareShader(); prepareFont(); + vboHandle = glGenBuffers(); + elementsHandle = glGenBuffers(); } /** @@ -75,86 +83,52 @@ public final class ImGuiImplGl3 { * @param drawData data used to draw ImGui interface to your current OpenGL context */ public void render(final ImDrawData drawData) { - if (drawData.cmdListsCount <= 0) { + if (drawData.getCmdListsCount() <= 0) { return; } + drawData.getDisplaySize(displaySize); + drawData.getFramebufferScale(framebufferScale); + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - final int fbWidth = (int) (drawData.displaySizeX * drawData.framebufferScaleX); - final int fbHeight = (int) (drawData.displaySizeY * drawData.framebufferScaleY); + final int fbWidth = (int) (displaySize.x * framebufferScale.x); + final int fbHeight = (int) (displaySize.y * framebufferScale.y); if (fbWidth <= 0 || fbHeight <= 0) { return; } - if (!isFontInitialized) { - isFontInitialized = true; - vBufferHandle = glGenBuffers(); - iBufferHandle = glGenBuffers(); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iBufferHandle); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, drawData.iByteBuffer.capacity(), GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } + drawData.getDisplayPos(displayPos); backupGlState(); - bind(drawData); + bind(); - int verticesOffset = 0; - int indexOffset = 0; + // Render command lists + for (int cmdListIdx = 0; cmdListIdx < drawData.getCmdListsCount(); cmdListIdx++) { + // Upload vertex/index buffers + glBufferData(GL_ARRAY_BUFFER, drawData.getCmdListVtxBufferData(cmdListIdx), GL_STREAM_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, drawData.getCmdListIdxBufferData(cmdListIdx), GL_STREAM_DRAW); - for (int i = 0; i < drawData.cmdListsCount; i++) { - drawData.vByteBuffer.limit(verticesOffset + 4); - final int verticesSize = (int) drawData.vByteBuffer.getFloat(verticesOffset); + for (int cmdBufferIdx = 0; cmdBufferIdx < drawData.getCmdListCmdBufferSize(cmdListIdx); cmdBufferIdx++) { + drawData.getCmdListCmdBufferClipRect(cmdListIdx, cmdBufferIdx, clipRect); - drawData.iByteBuffer.limit(indexOffset + 2); - final short indexSize = drawData.iByteBuffer.getShort(indexOffset); - final int cmdSize = (int) drawData.cmdByteBuffer.getFloat(); - - final int verticesStartOffset = verticesOffset + 4; - final int indexStartOffset = indexOffset + 2; - - drawData.vByteBuffer.position(verticesStartOffset); - drawData.iByteBuffer.position(indexStartOffset); - - final int newVlimit = verticesStartOffset + verticesSize * ImDrawData.V_BUFFER_SIZE; - final int newIlimit = indexStartOffset + indexSize * ImDrawData.I_BUFFER_SIZE; - - drawData.vByteBuffer.limit(newVlimit); - drawData.iByteBuffer.limit(newIlimit); - - glBufferData(GL_ARRAY_BUFFER, drawData.vByteBuffer, GL_STATIC_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, drawData.iByteBuffer, GL_STATIC_DRAW); - - verticesOffset += ((verticesSize) * ImDrawData.V_BUFFER_SIZE) + 4; - indexOffset += ((indexSize) * ImDrawData.I_BUFFER_SIZE) + 2; - - final float clipOffX = drawData.displayPosX; // (0,0) unless using multi-viewports - final float clipOffY = drawData.displayPosY; - final float clipScaleX = drawData.framebufferScaleX; // (1,1) unless using retina display which are often (2,2) - final float clipScaleY = drawData.framebufferScaleY; - - int idxBufferOffset = 0; - - for (int j = 0; j < cmdSize; j++) { - final int elemCount = (int) drawData.cmdByteBuffer.getFloat(); - float clipRectX = drawData.cmdByteBuffer.getFloat(); - float clipRectY = drawData.cmdByteBuffer.getFloat(); - float clipRectZ = drawData.cmdByteBuffer.getFloat(); - float clipRectW = drawData.cmdByteBuffer.getFloat(); - final int textureID = (int) drawData.cmdByteBuffer.getFloat(); - - clipRectX = (clipRectX - clipOffX) * clipScaleX; - clipRectY = (clipRectY - clipOffY) * clipScaleY; - clipRectZ = (clipRectZ - clipOffX) * clipScaleX; - clipRectW = (clipRectW - clipOffY) * clipScaleY; + final float clipRectX = (clipRect.x - displayPos.x) * framebufferScale.x; + final float clipRectY = (clipRect.y - displayPos.y) * framebufferScale.y; + final float clipRectZ = (clipRect.z - displayPos.x) * framebufferScale.x; + final float clipRectW = (clipRect.w - displayPos.y) * framebufferScale.y; if (clipRectX < fbWidth && clipRectY < fbHeight && clipRectZ >= 0.0f && clipRectW >= 0.0f) { + // Apply scissor/clipping rectangle glScissor((int) clipRectX, (int) (fbHeight - clipRectW), (int) (clipRectZ - clipRectX), (int) (clipRectW - clipRectY)); - glBindTexture(GL_TEXTURE_2D, textureID); - glDrawElements(GL_TRIANGLES, elemCount, GL_UNSIGNED_SHORT, idxBufferOffset); - } - idxBufferOffset += elemCount * 2; + // Bind texture, Draw + final int textureId = drawData.getCmdListCmdBufferTextureId(cmdListIdx, cmdBufferIdx); + final int elemCount = drawData.getCmdListCmdBufferElemCount(cmdListIdx, cmdBufferIdx); + final int idxBufferOffset = drawData.getCmdListCmdBufferIdxOffset(cmdListIdx, cmdBufferIdx); + + glBindTexture(GL_TEXTURE_2D, textureId); + glDrawElements(GL_TRIANGLES, elemCount, GL_UNSIGNED_SHORT, idxBufferOffset * ImDrawData.SIZEOF_IM_DRAW_IDX); + } } } @@ -168,8 +142,8 @@ public final class ImGuiImplGl3 { public void dispose() { glDeleteTextures(gFontTexture); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDeleteBuffers(iBufferHandle); - glDeleteBuffers(vBufferHandle); + glDeleteBuffers(elementsHandle); + glDeleteBuffers(vboHandle); glDetachShader(programId, vertexShaderId); glDetachShader(programId, fragmentShaderId); glDeleteProgram(programId); @@ -214,10 +188,7 @@ public final class ImGuiImplGl3 { glGetIntegerv(GL_ACTIVE_TEXTURE, lastActiveTexture); glGetIntegerv(GL_CURRENT_PROGRAM, lastProgram); glGetIntegerv(GL_TEXTURE_BINDING_2D, lastTexture); - // int[] last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); // do it by yourself if needed glGetIntegerv(GL_ARRAY_BUFFER_BINDING, lastArrayBuffer); - // int[] last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); // do it by yourself if needed - // int[] last_polygon_mode; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); // do it by yourself if needed glGetIntegerv(GL_VIEWPORT, lastViewport); glGetIntegerv(GL_SCISSOR_BOX, lastScissorBox); glGetIntegerv(GL_BLEND_SRC_RGB, lastBlendSrcRgb); @@ -249,8 +220,8 @@ public final class ImGuiImplGl3 { glScissor(lastScissorBox[0], lastScissorBox[1], lastScissorBox[2], lastScissorBox[3]); } - private void bind(final ImDrawData drawData) { - glViewport(0, 0, (int) drawData.displaySizeX, (int) drawData.displaySizeY); + private void bind() { + glViewport(0, 0, (int) displaySize.x, (int) displaySize.y); glActiveTexture(GL_TEXTURE0); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); @@ -259,10 +230,10 @@ public final class ImGuiImplGl3 { glDisable(GL_DEPTH_TEST); glEnable(GL_SCISSOR_TEST); - final float left = drawData.displayPosX; - final float right = drawData.displayPosX + drawData.displaySizeX; - final float top = drawData.displayPosY; - final float bottom = drawData.displayPosY + drawData.displaySizeY; + final float left = displayPos.x; + final float right = displayPos.x + displaySize.x; + final float top = displayPos.y; + final float bottom = displayPos.y + displaySize.y; // Orthographic matrix projection projMatrix[0] = 2.0f / (right - left); @@ -272,28 +243,26 @@ public final class ImGuiImplGl3 { projMatrix[13] = (top + bottom) / (bottom - top); projMatrix[15] = 1.0f; - // Bind vertices - glBindBuffer(GL_ARRAY_BUFFER, vBufferHandle); + // Bind shader + glUseProgram(programId); + glUniform1i(glGetUniformLocation(programId, "Texture"), 0); + glUniformMatrix4fv(glGetUniformLocation(programId, "ProjMtx"), false, projMatrix); + + // Bind vertex/index buffers and setup attributes for ImDrawVert + glBindBuffer(GL_ARRAY_BUFFER, vboHandle); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementsHandle); int location = glGetAttribLocation(programId, "Position"); glEnableVertexAttribArray(location); - glVertexAttribPointer(location, 2, GL_FLOAT, false, 20, 0); + glVertexAttribPointer(location, 2, GL_FLOAT, false, ImDrawData.SIZEOF_IM_DRAW_VERT, 0); location = glGetAttribLocation(programId, "UV"); glEnableVertexAttribArray(location); - glVertexAttribPointer(location, 2, GL_FLOAT, false, 20, 8); + glVertexAttribPointer(location, 2, GL_FLOAT, false, ImDrawData.SIZEOF_IM_DRAW_VERT, 8); location = glGetAttribLocation(programId, "Color"); glEnableVertexAttribArray(location); - glVertexAttribPointer(location, 4, GL_UNSIGNED_BYTE, true, 20, 16); - - //Bind index - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iBufferHandle); - - // Bind shader - glUseProgram(programId); - glUniformMatrix4fv(glGetUniformLocation(programId, "ProjMtx"), false, projMatrix); - glUniform1i(glGetUniformLocation(programId, "Texture"), 0); + glVertexAttribPointer(location, 4, GL_UNSIGNED_BYTE, true, ImDrawData.SIZEOF_IM_DRAW_VERT, 16); } private void unbind() { diff --git a/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java b/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java index d28536f..7452a55 100644 --- a/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java +++ b/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java @@ -34,7 +34,7 @@ import java.util.Objects; import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks; import static org.lwjgl.glfw.GLFW.*; -import static org.lwjgl.opengl.GL30.*; +import static org.lwjgl.opengl.GL32.*; import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.system.MemoryUtil.NULL;