Преглед изворни кода

Indexed rendering. Not in main branch because breaks rendering code too much. Will merge in trunk along with more major graphics changes lat

ocornut пре 10 година
родитељ
комит
1746b04065

+ 30 - 7
examples/directx11_example/imgui_impl_dx11.cpp

@@ -18,6 +18,7 @@ static HWND                     g_hWnd = 0;
 static ID3D11Device*            g_pd3dDevice = NULL;
 static ID3D11DeviceContext*     g_pd3dDeviceContext = NULL;
 static ID3D11Buffer*            g_pVB = NULL;
+static ID3D11Buffer*            g_pIB = NULL;
 static ID3D10Blob *             g_pVertexShaderBlob = NULL;
 static ID3D11VertexShader*      g_pVertexShader = NULL;
 static ID3D11InputLayout*       g_pInputLayout = NULL;
@@ -27,7 +28,8 @@ static ID3D11PixelShader*       g_pPixelShader = NULL;
 static ID3D11SamplerState*      g_pFontSampler = NULL;
 static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
 static ID3D11BlendState*        g_blendState = NULL;
-static int                      VERTEX_BUFFER_SIZE = 30000;     // TODO: Make vertex buffer smaller and grow dynamically as needed.
+static int                      VERTEX_BUFFER_SIZE = 30000;     // TODO: Make buffers smaller and grow dynamically as needed.
+static int                      INDEX_BUFFER_SIZE = 30000;      // TODO: Make buffers smaller and grow dynamically as needed.
 
 struct CUSTOMVERTEX
 {
@@ -47,10 +49,13 @@ struct VERTEX_CONSTANT_BUFFER
 static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
 {
     // Copy and convert all vertices into a single contiguous buffer
-    D3D11_MAPPED_SUBRESOURCE mappedResource;
-    if (g_pd3dDeviceContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK)
+    D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
+    if (g_pd3dDeviceContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
         return;
-    CUSTOMVERTEX* vtx_dst = (CUSTOMVERTEX*)mappedResource.pData;
+    if (g_pd3dDeviceContext->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
+        return;
+    CUSTOMVERTEX* vtx_dst = (CUSTOMVERTEX*)vtx_resource.pData;
+    ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
     for (int n = 0; n < cmd_lists_count; n++)
     {
         const ImDrawList* cmd_list = cmd_lists[n];
@@ -65,8 +70,11 @@ static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
             vtx_dst++;
             vtx_src++;
         }
+        memcpy(idx_dst, &cmd_list->idx_buffer[0], cmd_list->idx_buffer.size() * sizeof(ImDrawIdx));
+        idx_dst += cmd_list->idx_buffer.size();
     }
     g_pd3dDeviceContext->Unmap(g_pVB, 0);
+    g_pd3dDeviceContext->Unmap(g_pIB, 0);
 
     // Setup orthographic projection matrix into our constant buffer
     {
@@ -108,6 +116,7 @@ static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
     unsigned int offset = 0;
     g_pd3dDeviceContext->IASetInputLayout(g_pInputLayout);
     g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
+    g_pd3dDeviceContext->IASetIndexBuffer(g_pIB, DXGI_FORMAT_R16_UINT, 0);
     g_pd3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
     g_pd3dDeviceContext->VSSetShader(g_pVertexShader, NULL, 0);
     g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
@@ -120,6 +129,7 @@ static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
 
     // Render command lists
     int vtx_offset = 0;
+    int idx_offset = 0;
     for (int n = 0; n < cmd_lists_count; n++)
     {
         const ImDrawList* cmd_list = cmd_lists[n];
@@ -135,10 +145,11 @@ static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
                 const D3D11_RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w };
                 g_pd3dDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->texture_id);
                 g_pd3dDeviceContext->RSSetScissorRects(1, &r); 
-                g_pd3dDeviceContext->Draw(pcmd->vtx_count, vtx_offset);
+                g_pd3dDeviceContext->DrawIndexed(pcmd->idx_count, idx_offset, vtx_offset);
             }
-            vtx_offset += pcmd->vtx_count;
+            idx_offset += pcmd->idx_count;
         }
+        vtx_offset += cmd_list->vtx_buffer.size();
     }
 
     // Restore modified state
@@ -362,11 +373,22 @@ bool    ImGui_ImplDX11_CreateDeviceObjects()
         bufferDesc.ByteWidth = VERTEX_BUFFER_SIZE * sizeof(CUSTOMVERTEX);
         bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
         bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
-        bufferDesc.MiscFlags = 0;
         if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0)
             return false;
     }
 
+    // Create the index buffer
+    {
+        D3D11_BUFFER_DESC bufferDesc;
+        memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC));
+        bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
+        bufferDesc.ByteWidth = INDEX_BUFFER_SIZE * sizeof(ImDrawIdx);
+        bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+        bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+        if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pIB) < 0)
+            return false;
+    }
+
     ImGui_ImplDX11_CreateFontsTexture();
 
     return true;
@@ -379,6 +401,7 @@ void    ImGui_ImplDX11_InvalidateDeviceObjects()
 
     if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
     if (g_pFontTextureView) { g_pFontTextureView->Release(); ImGui::GetIO().Fonts->TexID = 0; }
+    if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
     if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
 
     if (g_blendState) { g_blendState->Release(); g_blendState = NULL; }

+ 26 - 3
examples/directx9_example/imgui_impl_dx9.cpp

@@ -15,7 +15,9 @@ static INT64                    g_Time = 0;
 static INT64                    g_TicksPerSecond = 0;
 static LPDIRECT3DDEVICE9        g_pd3dDevice = NULL;
 static LPDIRECT3DVERTEXBUFFER9  g_pVB = NULL;
-static int                      VERTEX_BUFFER_SIZE = 30000;     // TODO: Make vertex buffer smaller and grow dynamically as needed.
+static LPDIRECT3DINDEXBUFFER9   g_pIB = NULL;
+static int                      VERTEX_BUFFER_SIZE = 30000;     // TODO: Make buffers smaller and grow dynamically as needed.
+static int                      INDEX_BUFFER_SIZE = 30000;      // TODO: Make buffers smaller and grow dynamically as needed.
 
 struct CUSTOMVERTEX
 {
@@ -31,15 +33,22 @@ struct CUSTOMVERTEX
 static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
 {
     size_t total_vtx_count = 0;
+    size_t total_idx_count = 0;
     for (int n = 0; n < cmd_lists_count; n++)
+    {
         total_vtx_count += cmd_lists[n]->vtx_buffer.size();
+        total_idx_count += cmd_lists[n]->idx_buffer.size();
+    }
     if (total_vtx_count == 0)
         return;
 
     // Copy and convert all vertices into a single contiguous buffer
     CUSTOMVERTEX* vtx_dst;
+    ImDrawIdx* idx_dst;
     if (g_pVB->Lock(0, (UINT)total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
         return;
+    if (g_pIB->Lock(0, (UINT)total_idx_count, (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
+        return;
     for (int n = 0; n < cmd_lists_count; n++)
     {
         const ImDrawList* cmd_list = cmd_lists[n];
@@ -55,9 +64,13 @@ static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_
             vtx_dst++;
             vtx_src++;
         }
+        memcpy(idx_dst, &cmd_list->idx_buffer[0], cmd_list->idx_buffer.size() * sizeof(ImDrawIdx));
+        idx_dst += cmd_list->idx_buffer.size();
     }
     g_pVB->Unlock();
+    g_pIB->Unlock();
     g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
+    g_pd3dDevice->SetIndices( g_pIB );
     g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
 
     // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing
@@ -90,6 +103,7 @@ static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_
 
     // Render command lists
     int vtx_offset = 0;
+    int idx_offset = 0;
     for (int n = 0; n < cmd_lists_count; n++)
     {
         const ImDrawList* cmd_list = cmd_lists[n];
@@ -105,10 +119,11 @@ static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_
                 const RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w };
                 g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->texture_id );
                 g_pd3dDevice->SetScissorRect(&r);
-                g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3);
+                g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vtx_offset, 0, cmd_list->vtx_buffer.size(), idx_offset, pcmd->idx_count/3);
             }
-            vtx_offset += pcmd->vtx_count;
+            idx_offset += pcmd->idx_count;
         }
+        vtx_offset += cmd_list->vtx_buffer.size();
     }
 }
 
@@ -234,6 +249,9 @@ bool ImGui_ImplDX9_CreateDeviceObjects()
     if (g_pd3dDevice->CreateVertexBuffer(VERTEX_BUFFER_SIZE * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
         return false;
 
+    if (g_pd3dDevice->CreateIndexBuffer(INDEX_BUFFER_SIZE * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
+        return false;
+
     ImGui_ImplDX9_CreateFontsTexture();
     return true;
 }
@@ -247,6 +265,11 @@ void ImGui_ImplDX9_InvalidateDeviceObjects()
         g_pVB->Release();
         g_pVB = NULL;
     }
+    if (g_pIB)
+    {
+        g_pIB->Release();
+        g_pIB = NULL;
+    }
     if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().Fonts->TexID)
     {
         tex->Release();

+ 15 - 16
examples/opengl3_example/imgui_impl_glfw_gl3.cpp

@@ -23,7 +23,7 @@ static GLuint       g_FontTexture = 0;
 static int          g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
 static int          g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
 static int          g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0;
-static size_t       g_VboMaxSize = 20000;
+static size_t       g_VboSize = 0;
 static unsigned int g_VboHandle = 0, g_VaoHandle = 0;
 
 // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
@@ -62,32 +62,33 @@ static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int
     for (int n = 0; n < cmd_lists_count; n++)
         total_vtx_count += cmd_lists[n]->vtx_buffer.size();
     glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
-    size_t neededBufferSize = total_vtx_count * sizeof(ImDrawVert);
-    if (neededBufferSize > g_VboMaxSize)
+    size_t needed_vtx_size = total_vtx_count * sizeof(ImDrawVert);
+    if (g_VboSize < needed_vtx_size)
     {
-        g_VboMaxSize = neededBufferSize + 5000;  // Grow buffer
-        glBufferData(GL_ARRAY_BUFFER, g_VboMaxSize, NULL, GL_STREAM_DRAW);
+        g_VboSize = needed_vtx_size + 8192;  // Grow buffer
+        glBufferData(GL_ARRAY_BUFFER, g_VboSize, NULL, GL_STREAM_DRAW);
     }
 
     // Copy and convert all vertices into a single contiguous buffer
-    unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
-    if (!buffer_data)
+    unsigned char* vtx_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+    if (!vtx_data)
         return;
     for (int n = 0; n < cmd_lists_count; n++)
     {
         const ImDrawList* cmd_list = cmd_lists[n];
-        memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
-        buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert);
+        memcpy(vtx_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
+        vtx_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert);
     }
     glUnmapBuffer(GL_ARRAY_BUFFER);
     glBindBuffer(GL_ARRAY_BUFFER, 0);
     glBindVertexArray(g_VaoHandle);
 
-    int cmd_offset = 0;
+    int vtx_offset = 0;
     for (int n = 0; n < cmd_lists_count; n++)
     {
         const ImDrawList* cmd_list = cmd_lists[n];
-        int vtx_offset = cmd_offset;
+        const ImDrawIdx* idx_buffer = (const unsigned short*)&cmd_list->idx_buffer.front();
+
         const ImDrawCmd* pcmd_end = cmd_list->commands.end();
         for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
         {
@@ -99,11 +100,11 @@ static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int
             {
                 glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id);
                 glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
-                glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
+                glDrawElementsBaseVertex(GL_TRIANGLES, pcmd->idx_count, GL_UNSIGNED_SHORT, idx_buffer, vtx_offset);
             }
-            vtx_offset += pcmd->vtx_count;
+            idx_buffer += pcmd->idx_count;
         }
-        cmd_offset = vtx_offset;
+        vtx_offset += cmd_list->vtx_buffer.size();
     }
 
     // Restore modified state
@@ -217,8 +218,6 @@ bool ImGui_ImplGlfwGL3_CreateDeviceObjects()
     g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color");
 
     glGenBuffers(1, &g_VboHandle);
-    glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
-    glBufferData(GL_ARRAY_BUFFER, g_VboMaxSize, NULL, GL_DYNAMIC_DRAW);
 
     glGenVertexArrays(1, &g_VaoHandle);
     glBindVertexArray(g_VaoHandle);

+ 3 - 3
examples/opengl_example/imgui_impl_glfw.cpp

@@ -60,11 +60,11 @@ static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
     {
         const ImDrawList* cmd_list = cmd_lists[n];
         const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front();
+        const ImDrawIdx* idx_buffer = (const unsigned short*)&cmd_list->idx_buffer.front();
         glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos)));
         glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv)));
         glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col)));
 
-        int vtx_offset = 0;
         for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
         {
             const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
@@ -76,9 +76,9 @@ static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
             {
                 glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id);
                 glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
-                glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
+                glDrawElements(GL_TRIANGLES, pcmd->idx_count, GL_UNSIGNED_SHORT, idx_buffer);
             }
-            vtx_offset += pcmd->vtx_count;
+            idx_buffer += pcmd->idx_count;
         }
     }
     #undef OFFSETOF

+ 123 - 91
imgui.cpp

@@ -1670,10 +1670,11 @@ static inline void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_lis
 {
     if (!draw_list->commands.empty() && !draw_list->vtx_buffer.empty())
     {
-        if (draw_list->commands.back().vtx_count == 0)
+        if (draw_list->commands.back().idx_count == 0)
             draw_list->commands.pop_back();
         out_render_list.push_back(draw_list);
         GImGui->IO.MetricsRenderVertices += (int)draw_list->vtx_buffer.size();
+        GImGui->IO.MetricsRenderIndices += (int)draw_list->idx_buffer.size();
     }
 }
 
@@ -2207,7 +2208,7 @@ void ImGui::Render()
         }
 
         // Gather windows to render
-        g.IO.MetricsRenderVertices = 0;
+        g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0;
         for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
             g.RenderDrawLists[i].resize(0);
         for (size_t i = 0; i != g.Windows.size(); i++)
@@ -7590,6 +7591,9 @@ void ImDrawList::Clear()
     commands.resize(0);
     vtx_buffer.resize(0);
     vtx_write = NULL;
+    vtx_current_idx = 0;
+    idx_buffer.resize(0);
+    idx_write = NULL;
     clip_rect_stack.resize(0);
     texture_id_stack.resize(0);
 }
@@ -7599,6 +7603,9 @@ void ImDrawList::ClearFreeMemory()
     commands.clear();
     vtx_buffer.clear();
     vtx_write = NULL;
+    vtx_current_idx = 0;
+    idx_buffer.clear();
+    idx_write = NULL;
     clip_rect_stack.clear();
     texture_id_stack.clear();
 }
@@ -7606,7 +7613,7 @@ void ImDrawList::ClearFreeMemory()
 void ImDrawList::AddDrawCmd()
 {
     ImDrawCmd draw_cmd;
-    draw_cmd.vtx_count = 0;
+    draw_cmd.idx_count = 0;
     draw_cmd.clip_rect = clip_rect_stack.empty() ? GNullClipRect : clip_rect_stack.back();
     draw_cmd.texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.back();
     draw_cmd.user_callback = NULL;
@@ -7619,7 +7626,7 @@ void ImDrawList::AddDrawCmd()
 void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
 {
     ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
-    if (!current_cmd || current_cmd->vtx_count != 0 || current_cmd->user_callback != NULL)
+    if (!current_cmd || current_cmd->idx_count != 0 || current_cmd->user_callback != NULL)
     {
         AddDrawCmd();
         current_cmd = &commands.back();
@@ -7635,7 +7642,7 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
 void ImDrawList::UpdateClipRect()
 {
     ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
-    if (!current_cmd || (current_cmd->vtx_count != 0) || current_cmd->user_callback != NULL)
+    if (!current_cmd || (current_cmd->idx_count != 0) || current_cmd->user_callback != NULL)
     {
         AddDrawCmd();
     }
@@ -7675,7 +7682,7 @@ void ImDrawList::UpdateTextureID()
 {
     ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
     const ImTextureID texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.back();
-    if (!current_cmd || (current_cmd->vtx_count != 0 && current_cmd->texture_id != texture_id) || current_cmd->user_callback != NULL)
+    if (!current_cmd || (current_cmd->idx_count != 0 && current_cmd->texture_id != texture_id) || current_cmd->user_callback != NULL)
     {
         AddDrawCmd();
     }
@@ -7698,23 +7705,30 @@ void ImDrawList::PopTextureID()
     UpdateTextureID();
 }
 
-void ImDrawList::PrimReserve(unsigned int vtx_count)
+void ImDrawList::PrimReserve(unsigned int idx_count, unsigned int vtx_count)
 {
     ImDrawCmd& draw_cmd = commands.back();
-    draw_cmd.vtx_count += vtx_count;
-
+    draw_cmd.idx_count += idx_count;
+        
     size_t vtx_buffer_size = vtx_buffer.size();
     vtx_buffer.resize(vtx_buffer_size + vtx_count);
     vtx_write = &vtx_buffer[vtx_buffer_size];
+
+    size_t idx_buffer_size = idx_buffer.size();
+    idx_buffer.resize(idx_buffer_size + idx_count);
+    idx_write = &idx_buffer[idx_buffer_size];
 }
 
 void ImDrawList::PrimTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col)
 {
     const ImVec2 uv = GImGui->FontTexUvWhitePixel;
-    vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col;
-    vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col;
-    vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col;
+    idx_write[0] = vtx_current_idx; idx_write[1] = vtx_current_idx+1; idx_write[2] = vtx_current_idx+2; 
+    vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col; 
+    vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col; 
+    vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col; 
     vtx_write += 3;
+    vtx_current_idx += 3;
+    idx_write += 3;
 }
 
 void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
@@ -7722,13 +7736,15 @@ void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
     const ImVec2 uv = GImGui->FontTexUvWhitePixel;
 	const ImVec2 b(c.x, a.y);
 	const ImVec2 d(a.x, c.y);
-    vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col;
-    vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col;
-    vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col;
-    vtx_write[3].pos = a; vtx_write[3].uv = uv; vtx_write[3].col = col;
-    vtx_write[4].pos = c; vtx_write[4].uv = uv; vtx_write[4].col = col;
-    vtx_write[5].pos = d; vtx_write[5].uv = uv; vtx_write[5].col = col;
-    vtx_write += 6;
+    idx_write[0] = vtx_current_idx; idx_write[1] = vtx_current_idx+1; idx_write[2] = vtx_current_idx+2; 
+    idx_write[3] = vtx_current_idx; idx_write[4] = vtx_current_idx+2; idx_write[5] = vtx_current_idx+3; 
+    vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col; 
+    vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col; 
+    vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col; 
+    vtx_write[3].pos = d; vtx_write[3].uv = uv; vtx_write[3].col = col;
+    vtx_write += 4;
+    vtx_current_idx += 4;
+    idx_write += 6;
 }
 
 void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
@@ -7737,25 +7753,29 @@ void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a
 	const ImVec2 d(a.x, c.y);
 	const ImVec2 uv_b(uv_c.x, uv_a.y);
 	const ImVec2 uv_d(uv_a.x, uv_c.y);
-    vtx_write[0].pos = a; vtx_write[0].uv = uv_a; vtx_write[0].col = col;
-    vtx_write[1].pos = b; vtx_write[1].uv = uv_b; vtx_write[1].col = col;
-    vtx_write[2].pos = c; vtx_write[2].uv = uv_c; vtx_write[2].col = col;
-    vtx_write[3].pos = a; vtx_write[3].uv = uv_a; vtx_write[3].col = col;
-    vtx_write[4].pos = c; vtx_write[4].uv = uv_c; vtx_write[4].col = col;
-    vtx_write[5].pos = d; vtx_write[5].uv = uv_d; vtx_write[5].col = col;
-    vtx_write += 6;
+    idx_write[0] = vtx_current_idx; idx_write[1] = vtx_current_idx+1; idx_write[2] = vtx_current_idx+2; 
+    idx_write[3] = vtx_current_idx; idx_write[4] = vtx_current_idx+2; idx_write[5] = vtx_current_idx+3; 
+    vtx_write[0].pos = a; vtx_write[0].uv = uv_a; vtx_write[0].col = col; 
+    vtx_write[1].pos = b; vtx_write[1].uv = uv_b; vtx_write[1].col = col; 
+    vtx_write[2].pos = c; vtx_write[2].uv = uv_c; vtx_write[2].col = col; 
+    vtx_write[3].pos = d; vtx_write[3].uv = uv_d; vtx_write[3].col = col;
+    vtx_write += 4;
+    vtx_current_idx += 4;
+    idx_write += 6;
 }
 
 void ImDrawList::PrimQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col)
 {
     const ImVec2 uv = GImGui->FontTexUvWhitePixel;
-    vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col;
-    vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col;
-    vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col;
-    vtx_write[3].pos = a; vtx_write[3].uv = uv; vtx_write[3].col = col;
-    vtx_write[4].pos = c; vtx_write[4].uv = uv; vtx_write[4].col = col;
-    vtx_write[5].pos = d; vtx_write[5].uv = uv; vtx_write[5].col = col;
-    vtx_write += 6;
+    idx_write[0] = vtx_current_idx; idx_write[1] = vtx_current_idx+1; idx_write[2] = vtx_current_idx+2; 
+    idx_write[3] = vtx_current_idx; idx_write[4] = vtx_current_idx+2; idx_write[5] = vtx_current_idx+3; 
+    vtx_write[0].pos = a; vtx_write[0].uv = uv; vtx_write[0].col = col; 
+    vtx_write[1].pos = b; vtx_write[1].uv = uv; vtx_write[1].col = col; 
+    vtx_write[2].pos = c; vtx_write[2].uv = uv; vtx_write[2].col = col; 
+    vtx_write[3].pos = d; vtx_write[3].uv = uv; vtx_write[3].col = col; 
+    vtx_write += 4;
+    vtx_current_idx += 4;
+    idx_write += 6;
 }
 
 // FIXME-OPT: In many instances the caller could provide a normal.
@@ -7774,7 +7794,7 @@ void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thic
     if ((col >> 24) == 0)
         return;
 
-    PrimReserve(6);
+    PrimReserve(6, 4);
     PrimLine(a, b, col, thickness);
 }
 
@@ -7796,27 +7816,31 @@ void ImDrawList::AddArcFast(const ImVec2& center, float radius, ImU32 col, int a
         }
         circle_vtx_builds = true;
     }
-    
-    const ImVec2 uv = GImGui->FontTexUvWhitePixel;
+
     if (filled)
     {
-        PrimReserve((unsigned int)(a_max-a_min) * 3);
-        for (int a0 = a_min; a0 < a_max; a0++)
+        PrimReserve((unsigned int)(a_max-a_min) * 3, (unsigned int)(a_max-a_min+1) + 1);
+        ImDrawIdx idx = vtx_current_idx;
+        for (int a = 0; a < a_max - a_min; a++)
         {
-            int a1 = (a0 + 1 == SAMPLES) ? 0 : a0 + 1;
-            PrimVtx(center + circle_vtx[a0] * radius, uv, col);
-            PrimVtx(center + circle_vtx[a1] * radius, uv, col);
-            PrimVtx(center + third_point_offset, uv, col);
+            PrimIdx(idx + 1 + a);
+            PrimIdx(idx + 1 + a + 1);
+            PrimIdx(idx);
         }
+        const ImVec2 uv = GImGui->FontTexUvWhitePixel;
+        PrimVtx(center + third_point_offset, uv, col);
+        for (int a = a_min; a < a_max+1; a++)
+            PrimVtx(center + circle_vtx[(a >= SAMPLES) ? a - SAMPLES : a] * radius, uv, col);
     }
     else
     {
-        PrimReserve((unsigned int)(a_max-a_min) * 6);
+        // FIXME-OPT: Wasting vertices.
+        PrimReserve((unsigned int)(a_max-a_min) * 6, (unsigned int)(a_max-a_min) * 4);
         for (int a0 = a_min; a0 < a_max; a0++)
-        {
+		{
             int a1 = (a0 + 1 == SAMPLES) ? 0 : a0 + 1;
             PrimLine(center + circle_vtx[a0] * radius, center + circle_vtx[a1] * radius, col);
-        }
+		}
     }
 }
 
@@ -7831,7 +7855,7 @@ void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float roun
 
     if (r == 0.0f || rounding_corners == 0)
     {
-        PrimReserve(4*6);
+        PrimReserve(6*4, 4*4);
         PrimLine(ImVec2(a.x,a.y), ImVec2(b.x,a.y), col);
         PrimLine(ImVec2(b.x,a.y), ImVec2(b.x,b.y), col);
         PrimLine(ImVec2(b.x,b.y), ImVec2(a.x,b.y), col);
@@ -7839,7 +7863,7 @@ void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float roun
     }
     else
     {
-        PrimReserve(4*6);
+        PrimReserve(6*4, 4*4);
         PrimLine(ImVec2(a.x + ((rounding_corners & 1)?r:0), a.y), ImVec2(b.x - ((rounding_corners & 2)?r:0), a.y), col);
         PrimLine(ImVec2(b.x, a.y + ((rounding_corners & 2)?r:0)), ImVec2(b.x, b.y - ((rounding_corners & 4)?r:0)), col);
         PrimLine(ImVec2(b.x - ((rounding_corners & 4)?r:0), b.y), ImVec2(a.x + ((rounding_corners & 8)?r:0), b.y), col);
@@ -7861,16 +7885,15 @@ void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, floa
     r = ImMin(r, fabsf(b.x-a.x) * ( ((rounding_corners&(1|2))==(1|2)) || ((rounding_corners&(4|8))==(4|8)) ? 0.5f : 1.0f ));
     r = ImMin(r, fabsf(b.y-a.y) * ( ((rounding_corners&(1|8))==(1|8)) || ((rounding_corners&(2|4))==(2|4)) ? 0.5f : 1.0f ));
 
-    const ImVec2 uv = GImGui->FontTexUvWhitePixel;
     if (r == 0.0f || rounding_corners == 0)
     {
         // Use triangle so we can merge more draw calls together (at the cost of extra vertices)
-        PrimReserve(6);
+        PrimReserve(6, 4);
         PrimRect(a, b, col);
     }
     else
     {
-        PrimReserve(6+6*2);
+        PrimReserve(6*3, 4*3);
         PrimRect(ImVec2(a.x+r,a.y), ImVec2(b.x-r,b.y), col);
         
         float top_y = (rounding_corners & 1) ? a.y+r : a.y;
@@ -7893,7 +7916,7 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec
     if ((col >> 24) == 0)
         return;
 
-    PrimReserve(3);
+    PrimReserve(3, 3);
     PrimTriangle(a, b, c, col);
 }
 
@@ -7902,14 +7925,18 @@ void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int nu
     if ((col >> 24) == 0)
         return;
 
-    PrimReserve((unsigned int)num_segments*6);
+    PrimReserve(num_segments * 6, num_segments * 4);
+
     const float a_step = 2*PI/(float)num_segments;
     float a0 = 0.0f;
+    ImVec2 p0 = centre + ImVec2(cosf(a0), sinf(a0)) * radius;
     for (int i = 0; i < num_segments; i++)
     {
         const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step;
-        PrimLine(centre + ImVec2(cosf(a0), sinf(a0))*radius, centre + ImVec2(cosf(a1), sinf(a1))*radius, col);
+        const ImVec2 p1 = centre + ImVec2(cosf(a1), sinf(a1)) * radius;
+        PrimLine(p0, p1, col);
         a0 = a1;
+        p0 = p1;
     }
 }
 
@@ -7919,16 +7946,18 @@ void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col,
         return;
 
     const ImVec2 uv = GImGui->FontTexUvWhitePixel;
-    PrimReserve((unsigned int)num_segments*3);
+    const ImDrawIdx idx = vtx_current_idx;
+    PrimReserve((unsigned int)(num_segments*3), (unsigned int)(1 + num_segments));
+
     const float a_step = 2*PI/(float)num_segments;
     float a0 = 0.0f;
-    for (int i = 0; i < num_segments; i++)
+    PrimVtx(centre, uv, col);
+    for (int i = 0; i < num_segments; i++, a0 += a_step)
     {
-        const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step;
-        PrimVtx(centre + ImVec2(cosf(a0), sinf(a0))*radius, uv, col);
-        PrimVtx(centre + ImVec2(cosf(a1), sinf(a1))*radius, uv, col);
-        PrimVtx(centre, uv, col);
-        a0 = a1;
+        PrimVtx(centre + ImVec2(cosf(a0), sinf(a0)) * radius, uv, col);
+        PrimIdx(idx);
+        PrimIdx(idx + 1 + i);
+        PrimIdx(idx + 1 + ((i + 1 == num_segments) ? 0 : i + 1));
     }
 }
 
@@ -7946,17 +7975,24 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
 
     // reserve vertices for worse case
     const unsigned int char_count = (unsigned int)(text_end - text_begin);
-    const unsigned int vtx_count_max = char_count * 6;
+    const unsigned int vtx_count_max = char_count * 4;
+    const unsigned int idx_count_max = char_count * 6;
     const size_t vtx_begin = vtx_buffer.size();
-    PrimReserve(vtx_count_max);
+    const size_t idx_begin = idx_buffer.size();
+    PrimReserve(idx_count_max, vtx_count_max);
 
     font->RenderText(font_size, pos, col, clip_rect_stack.back(), text_begin, text_end, this, wrap_width, cpu_clip_max);
 
     // give back unused vertices
+    // FIXME-OPT
     vtx_buffer.resize((size_t)(vtx_write - &vtx_buffer.front()));
-    const size_t vtx_count = vtx_buffer.size() - vtx_begin;
-    commands.back().vtx_count -= (unsigned int)(vtx_count_max - vtx_count);
-    vtx_write -= (vtx_count_max - vtx_count);
+    idx_buffer.resize((size_t)(idx_write - &idx_buffer.front()));
+    unsigned int vtx_unused = vtx_count_max - (unsigned int)(vtx_buffer.size() - vtx_begin);
+    unsigned int idx_unused = idx_count_max - (unsigned int)(idx_buffer.size() - idx_begin);
+    commands.back().idx_count -= idx_unused;
+    vtx_write -= vtx_unused;
+    idx_write -= idx_unused;
+    vtx_current_idx = (ImDrawIdx)vtx_buffer.size();
 }
 
 void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col)
@@ -7969,7 +8005,7 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const Im
     if (push_texture_id)
         PushTextureID(user_texture_id);
 
-    PrimReserve(6);
+    PrimReserve(6, 4);
     PrimRectUV(a, b, uv0, uv1, col);
 
     if (push_texture_id)
@@ -9010,7 +9046,9 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
     float x = pos.x;
     float y = pos.y;
 
-    ImDrawVert* out_vertices = draw_list->vtx_write;
+    ImDrawVert* vtx_write = draw_list->vtx_write;
+    ImDrawIdx vtx_current_idx = draw_list->vtx_current_idx;
+    ImDrawIdx* idx_write = draw_list->idx_write;
 
     const char* s = text_begin;
     while (s < text_end)
@@ -9100,26 +9138,18 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
                         }
 
                         // NB: we are not calling PrimRectUV() here because non-inlined causes too much overhead in a debug build.
-                        out_vertices[0].pos = ImVec2(x1, y1);
-                        out_vertices[0].uv  = ImVec2(u1, v1);
-                        out_vertices[0].col = col;
-
-                        out_vertices[1].pos = ImVec2(x2, y1);
-                        out_vertices[1].uv  = ImVec2(u2, v1);
-                        out_vertices[1].col = col;
-
-                        out_vertices[2].pos = ImVec2(x2, y2);
-                        out_vertices[2].uv  = ImVec2(u2, v2);
-                        out_vertices[2].col = col;
-
-                        out_vertices[3] = out_vertices[0];
-                        out_vertices[4] = out_vertices[2];
-
-                        out_vertices[5].pos = ImVec2(x1, y2);
-                        out_vertices[5].uv  = ImVec2(u1, v2);
-                        out_vertices[5].col = col;
-
-                        out_vertices += 6;
+                        // inlined:
+                        {
+                            idx_write[0] = vtx_current_idx; idx_write[1] = vtx_current_idx+1; idx_write[2] = vtx_current_idx+2; 
+                            idx_write[3] = vtx_current_idx; idx_write[4] = vtx_current_idx+2; idx_write[5] = vtx_current_idx+3; 
+                            vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
+                            vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
+                            vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
+                            vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
+                            vtx_write += 4;
+                            vtx_current_idx += 4;
+                            idx_write += 6;
+                        }
                     }
                 }
             }
@@ -9128,7 +9158,9 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
         x += char_width;
     }
 
-    draw_list->vtx_write = out_vertices;
+    draw_list->vtx_write = vtx_write;
+    draw_list->vtx_current_idx = vtx_current_idx;
+    draw_list->idx_write = idx_write;
 }
 
 //-----------------------------------------------------------------------------
@@ -10410,14 +10442,14 @@ void ImGui::ShowMetricsWindow(bool* opened)
     {
         ImGui::Text("ImGui %s", ImGui::GetVersion());
         ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
-        ImGui::Text("%d vertices", ImGui::GetIO().MetricsRenderVertices);
+        ImGui::Text("%d vertices, %d triangles", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices / 3);
         ImGui::Separator();
 
         struct Funcs
         {
             static void NodeDrawList(ImDrawList* draw_list, const char* label)
             {
-                bool opened = ImGui::TreeNode(draw_list, "%s: %d vtx, %d cmds", label, draw_list->vtx_buffer.size(), draw_list->commands.size());
+                bool opened = ImGui::TreeNode(draw_list, "%s: %d vtx, %d indices, %d cmds", label, draw_list->vtx_buffer.size(), draw_list->idx_buffer.size(), draw_list->commands.size());
                 if (draw_list == ImGui::GetWindowDrawList())
                 {
                     ImGui::SameLine();
@@ -10429,7 +10461,7 @@ void ImGui::ShowMetricsWindow(bool* opened)
                     if (pcmd->user_callback)
                         ImGui::BulletText("Callback %p, user_data %p", pcmd->user_callback, pcmd->user_callback_data);
                     else
-                        ImGui::BulletText("Draw %d vtx, tex = %p", pcmd->vtx_count, pcmd->texture_id);
+                        ImGui::BulletText("Draw %d indexed vtx, tex = %p", pcmd->idx_count, pcmd->texture_id);
                 ImGui::TreePop();
             }
 

+ 13 - 5
imgui.h

@@ -671,6 +671,7 @@ struct ImGuiIO
     bool        WantCaptureKeyboard;        // Widget is active (= ImGui will use your keyboard input)
     float       Framerate;                  // Framerate estimation, in frame per second. Rolling average estimation based on IO.DeltaTime over 120 frames
     int         MetricsRenderVertices;      // Vertices processed during last call to Render()
+    int         MetricsRenderIndices;       // 
 
     //------------------------------------------------------------------
     // [Internal] ImGui will maintain those fields for you
@@ -857,13 +858,16 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c
 // Typically, 1 command = 1 gpu draw call (unless command is a callback)
 struct ImDrawCmd
 {
-    unsigned int    vtx_count;                  // Number of vertices (multiple of 3) to be drawn as triangles. The vertices are stored in the callee ImDrawList's vtx_buffer[] array.
+    unsigned int    idx_count;                  // 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[].
     ImVec4          clip_rect;                  // Clipping rectangle (x1, y1, x2, y2)
     ImTextureID     texture_id;                 // 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.
     ImDrawCallback  user_callback;              // If != NULL, call the function instead of rendering the vertices. vtx_count will be 0. clip_rect and texture_id will be set normally.
     void*           user_callback_data;         // The draw callback code can access this.
 };
 
+// Vertex index
+typedef unsigned short ImDrawIdx;
+
 // Vertex layout
 #ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT
 struct ImDrawVert
@@ -891,11 +895,14 @@ struct ImDrawList
     // This is what you have to render
     ImVector<ImDrawCmd>     commands;           // Commands. Typically 1 command = 1 gpu draw call.
     ImVector<ImDrawVert>    vtx_buffer;         // Vertex buffer. Each command consume ImDrawCmd::vtx_count of those
+    ImVector<ImDrawIdx>     idx_buffer;         // Index buffer. Each command consume ImDrawCmd::idx_count of those
 
     // [Internal to ImGui]
     ImVector<ImVec4>        clip_rect_stack;    // [Internal]
     ImVector<ImTextureID>   texture_id_stack;   // [Internal] 
     ImDrawVert*             vtx_write;          // [Internal] point within vtx_buffer after each add command (to avoid using the ImVector<> operators too much)
+    ImDrawIdx               vtx_current_idx;    // [Internal] == vtx_buffer.size()
+    ImDrawIdx*              idx_write;          // [Internal] point within idx_buffer after each add command (to avoid using the ImVector<> operators too much)
 
     ImDrawList() { Clear(); }
     IMGUI_API void  Clear();
@@ -918,11 +925,11 @@ struct ImDrawList
     IMGUI_API void  AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col = 0xFFFFFFFF);
 
     // Advanced
-    IMGUI_API void  AddCallback(ImDrawCallback callback, void* callback_data);  // Your rendering function must check for 'user_callback' in ImDrawCmd and call the function instead of rendering triangles.
-    IMGUI_API void  AddDrawCmd();                                               // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
+    IMGUI_API void  AddCallback(ImDrawCallback callback, void* callback_data);   // Your rendering function must check for 'user_callback' in ImDrawCmd and call the function instead of rendering triangles.
+    IMGUI_API void  AddDrawCmd();               // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
 
     // Internal helpers
-    IMGUI_API void  PrimReserve(unsigned int vtx_count);
+    IMGUI_API void  PrimReserve(unsigned int idx_count, unsigned int vtx_count);
     IMGUI_API void  PrimTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col);
     IMGUI_API void  PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col);
     IMGUI_API void  PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col);
@@ -930,7 +937,8 @@ struct ImDrawList
     IMGUI_API void  PrimLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f);
     IMGUI_API void  UpdateClipRect();
     IMGUI_API void  UpdateTextureID();
-    IMGUI_API void  PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col)  { vtx_write->pos = pos; vtx_write->uv = uv; vtx_write->col = col; vtx_write++; }
+    IMGUI_API void  PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col)   { vtx_write->pos = pos; vtx_write->uv = uv; vtx_write->col = col; vtx_write++; vtx_current_idx++; }
+    IMGUI_API void  PrimIdx(unsigned int idx)                                 { *idx_write++ = (ImDrawIdx)idx; }
 };
 
 // Load and rasterize multiple TTF fonts into a same texture.