Explorar el Código

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

ocornut hace 10 años
padre
commit
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 ID3D11Device*            g_pd3dDevice = NULL;
 static ID3D11DeviceContext*     g_pd3dDeviceContext = NULL;
 static ID3D11DeviceContext*     g_pd3dDeviceContext = NULL;
 static ID3D11Buffer*            g_pVB = NULL;
 static ID3D11Buffer*            g_pVB = NULL;
+static ID3D11Buffer*            g_pIB = NULL;
 static ID3D10Blob *             g_pVertexShaderBlob = NULL;
 static ID3D10Blob *             g_pVertexShaderBlob = NULL;
 static ID3D11VertexShader*      g_pVertexShader = NULL;
 static ID3D11VertexShader*      g_pVertexShader = NULL;
 static ID3D11InputLayout*       g_pInputLayout = NULL;
 static ID3D11InputLayout*       g_pInputLayout = NULL;
@@ -27,7 +28,8 @@ static ID3D11PixelShader*       g_pPixelShader = NULL;
 static ID3D11SamplerState*      g_pFontSampler = NULL;
 static ID3D11SamplerState*      g_pFontSampler = NULL;
 static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
 static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
 static ID3D11BlendState*        g_blendState = 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
 struct CUSTOMVERTEX
 {
 {
@@ -47,10 +49,13 @@ struct VERTEX_CONSTANT_BUFFER
 static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
 static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
 {
 {
     // Copy and convert all vertices into a single contiguous buffer
     // 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;
         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++)
     for (int n = 0; n < cmd_lists_count; n++)
     {
     {
         const ImDrawList* cmd_list = cmd_lists[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_dst++;
             vtx_src++;
             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_pVB, 0);
+    g_pd3dDeviceContext->Unmap(g_pIB, 0);
 
 
     // Setup orthographic projection matrix into our constant buffer
     // 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;
     unsigned int offset = 0;
     g_pd3dDeviceContext->IASetInputLayout(g_pInputLayout);
     g_pd3dDeviceContext->IASetInputLayout(g_pInputLayout);
     g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
     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->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
     g_pd3dDeviceContext->VSSetShader(g_pVertexShader, NULL, 0);
     g_pd3dDeviceContext->VSSetShader(g_pVertexShader, NULL, 0);
     g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
     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
     // Render command lists
     int vtx_offset = 0;
     int vtx_offset = 0;
+    int idx_offset = 0;
     for (int n = 0; n < cmd_lists_count; n++)
     for (int n = 0; n < cmd_lists_count; n++)
     {
     {
         const ImDrawList* cmd_list = cmd_lists[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 };
                 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->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->texture_id);
                 g_pd3dDeviceContext->RSSetScissorRects(1, &r); 
                 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
     // Restore modified state
@@ -362,11 +373,22 @@ bool    ImGui_ImplDX11_CreateDeviceObjects()
         bufferDesc.ByteWidth = VERTEX_BUFFER_SIZE * sizeof(CUSTOMVERTEX);
         bufferDesc.ByteWidth = VERTEX_BUFFER_SIZE * sizeof(CUSTOMVERTEX);
         bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
         bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
         bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
         bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
-        bufferDesc.MiscFlags = 0;
         if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0)
         if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0)
             return false;
             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();
     ImGui_ImplDX11_CreateFontsTexture();
 
 
     return true;
     return true;
@@ -379,6 +401,7 @@ void    ImGui_ImplDX11_InvalidateDeviceObjects()
 
 
     if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
     if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
     if (g_pFontTextureView) { g_pFontTextureView->Release(); ImGui::GetIO().Fonts->TexID = 0; }
     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_pVB) { g_pVB->Release(); g_pVB = NULL; }
 
 
     if (g_blendState) { g_blendState->Release(); g_blendState = 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 INT64                    g_TicksPerSecond = 0;
 static LPDIRECT3DDEVICE9        g_pd3dDevice = NULL;
 static LPDIRECT3DDEVICE9        g_pd3dDevice = NULL;
 static LPDIRECT3DVERTEXBUFFER9  g_pVB = 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
 struct CUSTOMVERTEX
 {
 {
@@ -31,15 +33,22 @@ struct CUSTOMVERTEX
 static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
 static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
 {
 {
     size_t total_vtx_count = 0;
     size_t total_vtx_count = 0;
+    size_t total_idx_count = 0;
     for (int n = 0; n < cmd_lists_count; n++)
     for (int n = 0; n < cmd_lists_count; n++)
+    {
         total_vtx_count += cmd_lists[n]->vtx_buffer.size();
         total_vtx_count += cmd_lists[n]->vtx_buffer.size();
+        total_idx_count += cmd_lists[n]->idx_buffer.size();
+    }
     if (total_vtx_count == 0)
     if (total_vtx_count == 0)
         return;
         return;
 
 
     // Copy and convert all vertices into a single contiguous buffer
     // Copy and convert all vertices into a single contiguous buffer
     CUSTOMVERTEX* vtx_dst;
     CUSTOMVERTEX* vtx_dst;
+    ImDrawIdx* idx_dst;
     if (g_pVB->Lock(0, (UINT)total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
     if (g_pVB->Lock(0, (UINT)total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
         return;
         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++)
     for (int n = 0; n < cmd_lists_count; n++)
     {
     {
         const ImDrawList* cmd_list = cmd_lists[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_dst++;
             vtx_src++;
             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_pVB->Unlock();
+    g_pIB->Unlock();
     g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
     g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
+    g_pd3dDevice->SetIndices( g_pIB );
     g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
     g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
 
 
     // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing
     // 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
     // Render command lists
     int vtx_offset = 0;
     int vtx_offset = 0;
+    int idx_offset = 0;
     for (int n = 0; n < cmd_lists_count; n++)
     for (int n = 0; n < cmd_lists_count; n++)
     {
     {
         const ImDrawList* cmd_list = cmd_lists[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 };
                 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->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->texture_id );
                 g_pd3dDevice->SetScissorRect(&r);
                 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)
     if (g_pd3dDevice->CreateVertexBuffer(VERTEX_BUFFER_SIZE * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
         return false;
         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();
     ImGui_ImplDX9_CreateFontsTexture();
     return true;
     return true;
 }
 }
@@ -247,6 +265,11 @@ void ImGui_ImplDX9_InvalidateDeviceObjects()
         g_pVB->Release();
         g_pVB->Release();
         g_pVB = NULL;
         g_pVB = NULL;
     }
     }
+    if (g_pIB)
+    {
+        g_pIB->Release();
+        g_pIB = NULL;
+    }
     if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().Fonts->TexID)
     if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().Fonts->TexID)
     {
     {
         tex->Release();
         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_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
 static int          g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
 static int          g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
 static int          g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 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;
 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)
 // 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++)
     for (int n = 0; n < cmd_lists_count; n++)
         total_vtx_count += cmd_lists[n]->vtx_buffer.size();
         total_vtx_count += cmd_lists[n]->vtx_buffer.size();
     glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
     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
     // 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;
         return;
     for (int n = 0; n < cmd_lists_count; n++)
     for (int n = 0; n < cmd_lists_count; n++)
     {
     {
         const ImDrawList* cmd_list = cmd_lists[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);
     glUnmapBuffer(GL_ARRAY_BUFFER);
     glBindBuffer(GL_ARRAY_BUFFER, 0);
     glBindBuffer(GL_ARRAY_BUFFER, 0);
     glBindVertexArray(g_VaoHandle);
     glBindVertexArray(g_VaoHandle);
 
 
-    int cmd_offset = 0;
+    int vtx_offset = 0;
     for (int n = 0; n < cmd_lists_count; n++)
     for (int n = 0; n < cmd_lists_count; n++)
     {
     {
         const ImDrawList* cmd_list = cmd_lists[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();
         const ImDrawCmd* pcmd_end = cmd_list->commands.end();
         for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
         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);
                 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));
                 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
     // Restore modified state
@@ -217,8 +218,6 @@ bool ImGui_ImplGlfwGL3_CreateDeviceObjects()
     g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color");
     g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color");
 
 
     glGenBuffers(1, &g_VboHandle);
     glGenBuffers(1, &g_VboHandle);
-    glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
-    glBufferData(GL_ARRAY_BUFFER, g_VboMaxSize, NULL, GL_DYNAMIC_DRAW);
 
 
     glGenVertexArrays(1, &g_VaoHandle);
     glGenVertexArrays(1, &g_VaoHandle);
     glBindVertexArray(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 ImDrawList* cmd_list = cmd_lists[n];
         const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front();
         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)));
         glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos)));
         glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv)));
         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)));
         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++)
         for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
         {
         {
             const ImDrawCmd* pcmd = &cmd_list->commands[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);
                 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));
                 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
     #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.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();
             draw_list->commands.pop_back();
         out_render_list.push_back(draw_list);
         out_render_list.push_back(draw_list);
         GImGui->IO.MetricsRenderVertices += (int)draw_list->vtx_buffer.size();
         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
         // 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++)
         for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
             g.RenderDrawLists[i].resize(0);
             g.RenderDrawLists[i].resize(0);
         for (size_t i = 0; i != g.Windows.size(); i++)
         for (size_t i = 0; i != g.Windows.size(); i++)
@@ -7590,6 +7591,9 @@ void ImDrawList::Clear()
     commands.resize(0);
     commands.resize(0);
     vtx_buffer.resize(0);
     vtx_buffer.resize(0);
     vtx_write = NULL;
     vtx_write = NULL;
+    vtx_current_idx = 0;
+    idx_buffer.resize(0);
+    idx_write = NULL;
     clip_rect_stack.resize(0);
     clip_rect_stack.resize(0);
     texture_id_stack.resize(0);
     texture_id_stack.resize(0);
 }
 }
@@ -7599,6 +7603,9 @@ void ImDrawList::ClearFreeMemory()
     commands.clear();
     commands.clear();
     vtx_buffer.clear();
     vtx_buffer.clear();
     vtx_write = NULL;
     vtx_write = NULL;
+    vtx_current_idx = 0;
+    idx_buffer.clear();
+    idx_write = NULL;
     clip_rect_stack.clear();
     clip_rect_stack.clear();
     texture_id_stack.clear();
     texture_id_stack.clear();
 }
 }
@@ -7606,7 +7613,7 @@ void ImDrawList::ClearFreeMemory()
 void ImDrawList::AddDrawCmd()
 void ImDrawList::AddDrawCmd()
 {
 {
     ImDrawCmd draw_cmd;
     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.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.texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.back();
     draw_cmd.user_callback = NULL;
     draw_cmd.user_callback = NULL;
@@ -7619,7 +7626,7 @@ void ImDrawList::AddDrawCmd()
 void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
 void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
 {
 {
     ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
     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();
         AddDrawCmd();
         current_cmd = &commands.back();
         current_cmd = &commands.back();
@@ -7635,7 +7642,7 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
 void ImDrawList::UpdateClipRect()
 void ImDrawList::UpdateClipRect()
 {
 {
     ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
     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();
         AddDrawCmd();
     }
     }
@@ -7675,7 +7682,7 @@ void ImDrawList::UpdateTextureID()
 {
 {
     ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
     ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
     const ImTextureID texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.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();
         AddDrawCmd();
     }
     }
@@ -7698,23 +7705,30 @@ void ImDrawList::PopTextureID()
     UpdateTextureID();
     UpdateTextureID();
 }
 }
 
 
-void ImDrawList::PrimReserve(unsigned int vtx_count)
+void ImDrawList::PrimReserve(unsigned int idx_count, unsigned int vtx_count)
 {
 {
     ImDrawCmd& draw_cmd = commands.back();
     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();
     size_t vtx_buffer_size = vtx_buffer.size();
     vtx_buffer.resize(vtx_buffer_size + vtx_count);
     vtx_buffer.resize(vtx_buffer_size + vtx_count);
     vtx_write = &vtx_buffer[vtx_buffer_size];
     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)
 void ImDrawList::PrimTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col)
 {
 {
     const ImVec2 uv = GImGui->FontTexUvWhitePixel;
     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_write += 3;
+    vtx_current_idx += 3;
+    idx_write += 3;
 }
 }
 
 
 void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
 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 uv = GImGui->FontTexUvWhitePixel;
 	const ImVec2 b(c.x, a.y);
 	const ImVec2 b(c.x, a.y);
 	const ImVec2 d(a.x, c.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)
 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 d(a.x, c.y);
 	const ImVec2 uv_b(uv_c.x, uv_a.y);
 	const ImVec2 uv_b(uv_c.x, uv_a.y);
 	const ImVec2 uv_d(uv_a.x, uv_c.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)
 void ImDrawList::PrimQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col)
 {
 {
     const ImVec2 uv = GImGui->FontTexUvWhitePixel;
     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.
 // 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)
     if ((col >> 24) == 0)
         return;
         return;
 
 
-    PrimReserve(6);
+    PrimReserve(6, 4);
     PrimLine(a, b, col, thickness);
     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;
         circle_vtx_builds = true;
     }
     }
-    
-    const ImVec2 uv = GImGui->FontTexUvWhitePixel;
+
     if (filled)
     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
     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++)
         for (int a0 = a_min; a0 < a_max; a0++)
-        {
+		{
             int a1 = (a0 + 1 == SAMPLES) ? 0 : a0 + 1;
             int a1 = (a0 + 1 == SAMPLES) ? 0 : a0 + 1;
             PrimLine(center + circle_vtx[a0] * radius, center + circle_vtx[a1] * radius, col);
             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)
     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(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,a.y), ImVec2(b.x,b.y), col);
         PrimLine(ImVec2(b.x,b.y), ImVec2(a.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
     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(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, 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);
         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.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 ));
     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)
     if (r == 0.0f || rounding_corners == 0)
     {
     {
         // Use triangle so we can merge more draw calls together (at the cost of extra vertices)
         // 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);
         PrimRect(a, b, col);
     }
     }
     else
     else
     {
     {
-        PrimReserve(6+6*2);
+        PrimReserve(6*3, 4*3);
         PrimRect(ImVec2(a.x+r,a.y), ImVec2(b.x-r,b.y), col);
         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;
         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)
     if ((col >> 24) == 0)
         return;
         return;
 
 
-    PrimReserve(3);
+    PrimReserve(3, 3);
     PrimTriangle(a, b, c, col);
     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)
     if ((col >> 24) == 0)
         return;
         return;
 
 
-    PrimReserve((unsigned int)num_segments*6);
+    PrimReserve(num_segments * 6, num_segments * 4);
+
     const float a_step = 2*PI/(float)num_segments;
     const float a_step = 2*PI/(float)num_segments;
     float a0 = 0.0f;
     float a0 = 0.0f;
+    ImVec2 p0 = centre + ImVec2(cosf(a0), sinf(a0)) * radius;
     for (int i = 0; i < num_segments; i++)
     for (int i = 0; i < num_segments; i++)
     {
     {
         const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step;
         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;
         a0 = a1;
+        p0 = p1;
     }
     }
 }
 }
 
 
@@ -7919,16 +7946,18 @@ void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col,
         return;
         return;
 
 
     const ImVec2 uv = GImGui->FontTexUvWhitePixel;
     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;
     const float a_step = 2*PI/(float)num_segments;
     float a0 = 0.0f;
     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
     // reserve vertices for worse case
     const unsigned int char_count = (unsigned int)(text_end - text_begin);
     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();
     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);
     font->RenderText(font_size, pos, col, clip_rect_stack.back(), text_begin, text_end, this, wrap_width, cpu_clip_max);
 
 
     // give back unused vertices
     // give back unused vertices
+    // FIXME-OPT
     vtx_buffer.resize((size_t)(vtx_write - &vtx_buffer.front()));
     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)
 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)
     if (push_texture_id)
         PushTextureID(user_texture_id);
         PushTextureID(user_texture_id);
 
 
-    PrimReserve(6);
+    PrimReserve(6, 4);
     PrimRectUV(a, b, uv0, uv1, col);
     PrimRectUV(a, b, uv0, uv1, col);
 
 
     if (push_texture_id)
     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 x = pos.x;
     float y = pos.y;
     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;
     const char* s = text_begin;
     while (s < text_end)
     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.
                         // 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;
         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("ImGui %s", ImGui::GetVersion());
         ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
         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();
         ImGui::Separator();
 
 
         struct Funcs
         struct Funcs
         {
         {
             static void NodeDrawList(ImDrawList* draw_list, const char* label)
             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())
                 if (draw_list == ImGui::GetWindowDrawList())
                 {
                 {
                     ImGui::SameLine();
                     ImGui::SameLine();
@@ -10429,7 +10461,7 @@ void ImGui::ShowMetricsWindow(bool* opened)
                     if (pcmd->user_callback)
                     if (pcmd->user_callback)
                         ImGui::BulletText("Callback %p, user_data %p", pcmd->user_callback, pcmd->user_callback_data);
                         ImGui::BulletText("Callback %p, user_data %p", pcmd->user_callback, pcmd->user_callback_data);
                     else
                     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();
                 ImGui::TreePop();
             }
             }
 
 

+ 13 - 5
imgui.h

@@ -671,6 +671,7 @@ struct ImGuiIO
     bool        WantCaptureKeyboard;        // Widget is active (= ImGui will use your keyboard input)
     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
     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         MetricsRenderVertices;      // Vertices processed during last call to Render()
+    int         MetricsRenderIndices;       // 
 
 
     //------------------------------------------------------------------
     //------------------------------------------------------------------
     // [Internal] ImGui will maintain those fields for you
     // [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)
 // Typically, 1 command = 1 gpu draw call (unless command is a callback)
 struct ImDrawCmd
 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)
     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.
     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.
     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.
     void*           user_callback_data;         // The draw callback code can access this.
 };
 };
 
 
+// Vertex index
+typedef unsigned short ImDrawIdx;
+
 // Vertex layout
 // Vertex layout
 #ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT
 #ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT
 struct ImDrawVert
 struct ImDrawVert
@@ -891,11 +895,14 @@ struct ImDrawList
     // This is what you have to render
     // This is what you have to render
     ImVector<ImDrawCmd>     commands;           // Commands. Typically 1 command = 1 gpu draw call.
     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<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]
     // [Internal to ImGui]
     ImVector<ImVec4>        clip_rect_stack;    // [Internal]
     ImVector<ImVec4>        clip_rect_stack;    // [Internal]
     ImVector<ImTextureID>   texture_id_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)
     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(); }
     ImDrawList() { Clear(); }
     IMGUI_API void  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);
     IMGUI_API void  AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col = 0xFFFFFFFF);
 
 
     // Advanced
     // 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
     // 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  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  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);
     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  PrimLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f);
     IMGUI_API void  UpdateClipRect();
     IMGUI_API void  UpdateClipRect();
     IMGUI_API void  UpdateTextureID();
     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.
 // Load and rasterize multiple TTF fonts into a same texture.