Merge branch '2015-04-indexed-rendering' into 2015-03-antialiased-primitives

Conflicts:
	imgui.cpp
	imgui.h
This commit is contained in:
ocornut 2015-06-30 12:43:26 -06:00
commit ebfe4637d4
6 changed files with 264 additions and 95 deletions

View File

@ -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;
@ -28,7 +29,8 @@ static ID3D11SamplerState* g_pFontSampler = NULL;
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
static ID3D11RasterizerState* g_pRasterizerState = NULL;
static ID3D11BlendState* g_pBlendState = 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 VERTEX_CONSTANT_BUFFER
{
@ -41,17 +43,23 @@ 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;
ImDrawVert* vtx_dst = (ImDrawVert*)mappedResource.pData;
if (g_pd3dDeviceContext->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
return;
ImDrawVert* vtx_dst = (ImDrawVert*)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];
memcpy(vtx_dst, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
memcpy(idx_dst, &cmd_list->idx_buffer[0], cmd_list->idx_buffer.size() * sizeof(ImDrawIdx));
vtx_dst += cmd_list->vtx_buffer.size();
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
{
@ -93,6 +101,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);
@ -106,6 +115,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];
@ -121,10 +131,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 += (int)cmd_list->vtx_buffer.size();
}
// Restore modified state
@ -368,6 +379,18 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
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;
@ -380,6 +403,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_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }

View File

@ -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, (UINT)cmd_list->vtx_buffer.size(), idx_offset, pcmd->idx_count/3);
}
vtx_offset += pcmd->vtx_count;
idx_offset += pcmd->idx_count;
}
vtx_offset += (int)cmd_list->vtx_buffer.size();
}
}
@ -238,6 +253,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;
}
@ -251,6 +269,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();

View File

@ -73,24 +73,25 @@ static void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawList** const cmd_lists, int
}
// 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++)
{
@ -102,11 +103,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 += (int)cmd_list->vtx_buffer.size();
}
// Restore modified state

View File

@ -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

248
imgui.cpp
View File

@ -1874,10 +1874,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();
}
}
@ -2439,8 +2440,7 @@ void ImGui::Render()
}
// Gather windows to render
g.IO.MetricsRenderVertices = 0;
g.IO.MetricsActiveWindows = 0;
g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsActiveWindows = 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++)
@ -8820,6 +8820,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);
}
@ -8829,6 +8832,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();
}
@ -8836,7 +8842,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;
@ -8849,7 +8855,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();
@ -8865,7 +8871,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();
}
@ -8906,7 +8912,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();
}
@ -8929,29 +8935,51 @@ 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::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);
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)
{
const ImVec2 b(c.x, a.y);
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;
const ImVec2 b(c.x, a.y);
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);
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;
}
static ImVector<ImVec2> GTempPolyData;
@ -8972,7 +9000,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
count = points_count-1;
}
const bool aa_enabled = true;//!ImGui::GetIO().KeyCtrl;
const bool aa_enabled = !ImGui::GetIO().KeyCtrl;
if (aa_enabled)
{
// Anti-aliased stroke
@ -9006,7 +9034,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
temp_inner[points_count-1] = points[points_count-1] - temp_normals[points_count-1]*aa_size;
}
for (int i = start; i < count; i++)
for (int i = 0; i < count; i++)
{
const int ni = (i+1) < points_count ? i+1 : 0;
const ImVec2& dl0 = temp_normals[i];
@ -9025,6 +9053,39 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
}
const ImU32 col_trans = col & 0x00ffffff;
#if 1
// Indexed
// FIXME-OPT: merge with loops above
const int idx_count = count*12;
const int vtx_count = points_count*3;
PrimReserve(idx_count, vtx_count);
// FIXME-OPT: merge with loops above
for (int i = 0; i < points_count; i++)
{
vtx_write[0].pos = points[i]; vtx_write[0].uv = uv; vtx_write[0].col = col;
vtx_write[1].pos = temp_inner[i]; vtx_write[1].uv = uv; vtx_write[1].col = col_trans;
vtx_write[2].pos = temp_outer[i]; vtx_write[2].uv = uv; vtx_write[2].col = col_trans;
vtx_write += 3;
}
ImDrawIdx vtx_inner_idx = vtx_current_idx+1;
ImDrawIdx vtx_outer_idx = vtx_current_idx+2;
for (int i = 0; i < count; i++)
{
const int ni = (i+1) < points_count ? i+1 : 0;
int i3 = i * 3;
int ni3 = ni * 3;
idx_write[0] = (ImDrawIdx)(vtx_current_idx + ni3); idx_write[1] = (ImDrawIdx)(vtx_current_idx + i3); idx_write[2] = (ImDrawIdx)(vtx_outer_idx + i3);
idx_write[3] = (ImDrawIdx)(vtx_outer_idx + i3); idx_write[4] = (ImDrawIdx)(vtx_outer_idx + ni3); idx_write[5] = (ImDrawIdx)(vtx_current_idx + ni3);
idx_write[6] = (ImDrawIdx)(vtx_inner_idx + ni3); idx_write[7] = (ImDrawIdx)(vtx_inner_idx + i3); idx_write[8] = (ImDrawIdx)(vtx_current_idx + i3);
idx_write[9] = (ImDrawIdx)(vtx_current_idx + i3); idx_write[10]= (ImDrawIdx)(vtx_current_idx + ni3); idx_write[11]= (ImDrawIdx)(vtx_inner_idx + ni3);
idx_write += 12;
}
vtx_current_idx += (ImDrawIdx)vtx_count;
#else
const int vertex_count = count*12;
PrimReserve(vertex_count);
@ -9048,12 +9109,14 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
PrimVtx(points[ni], uv, col);
PrimVtx(temp_inner[ni], uv, col_trans);
}
#endif
}
else
{
// Non Anti-aliased Stroke
const int vertex_count = count*6;
PrimReserve(vertex_count);
const int idx_count = count*6;
const int vtx_count = count*4; // FIXME-OPT: Not sharing edges
PrimReserve(idx_count, vtx_count);
for (int i = 0; i < count; i++)
{
@ -9072,12 +9135,16 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
const ImVec2 pb(v1.x + dy, v1.y - dx);
const ImVec2 pc(v1.x - dy, v1.y + dx);
const ImVec2 pd(v0.x - dy, v0.y + dx);
PrimVtx(pa, uv, col);
PrimVtx(pb, uv, col);
PrimVtx(pc, uv, col);
PrimVtx(pa, uv, col);
PrimVtx(pc, uv, col);
PrimVtx(pd, uv, col);
vtx_write[0].pos = pa; vtx_write[0].uv = uv; vtx_write[0].col = col;
vtx_write[1].pos = pb; vtx_write[1].uv = uv; vtx_write[1].col = col;
vtx_write[2].pos = pc; vtx_write[2].uv = uv; vtx_write[2].col = col;
vtx_write[3].pos = pd; vtx_write[3].uv = uv; vtx_write[3].col = col;
vtx_write += 4;
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;
idx_write += 6;
vtx_current_idx += 4;
}
}
}
@ -9086,7 +9153,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
{
const ImVec2 uv = GImGui->FontTexUvWhitePixel;
const bool aa_enabled = true;//!ImGui::GetIO().KeyCtrl;
const bool aa_enabled = !ImGui::GetIO().KeyCtrl;
if (aa_enabled)
{
// Anti-aliased Fill
@ -9128,6 +9195,41 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
}
const ImU32 col_trans = col & 0x00ffffff;
#if 1
// Indexed
const int idx_count = (points_count-2)*3 + points_count*6;
const int vtx_count = (points_count*2);
PrimReserve(idx_count, vtx_count);
// FIXME-OPT: merge with loops above
for (int i = 0; i < points_count; i++)
{
vtx_write[0].pos = temp_inner[i]; vtx_write[0].uv = uv; vtx_write[0].col = col;
vtx_write[1].pos = temp_outer[i]; vtx_write[1].uv = uv; vtx_write[1].col = col_trans;
vtx_write += 2;
}
// Fill
ImDrawIdx vtx_inner_idx = vtx_current_idx;
ImDrawIdx vtx_outer_idx = vtx_current_idx+1;
for (int i = 2; i < points_count; i++)
{
idx_write[0] = (ImDrawIdx)(vtx_inner_idx); idx_write[1] = (ImDrawIdx)(vtx_inner_idx+((i-1)<<1)); idx_write[2] = (ImDrawIdx)(vtx_inner_idx+(i<<1));
idx_write += 3;
}
// AA fringe
for (int i = 0, j = points_count-1; i < points_count; j=i++)
{
idx_write[0] = (ImDrawIdx)(vtx_inner_idx+(i<<1)); idx_write[1] = (ImDrawIdx)(vtx_inner_idx+(j<<1)); idx_write[2] = (ImDrawIdx)(vtx_outer_idx+(j<<1));
idx_write[3] = (ImDrawIdx)(vtx_outer_idx+(j<<1)); idx_write[4] = (ImDrawIdx)(vtx_outer_idx+(i<<1)); idx_write[5] = (ImDrawIdx)(vtx_inner_idx+(i<<1));
idx_write += 6;
}
vtx_current_idx += (ImDrawIdx)vtx_count;
#else
// Not Indexed
const int vertex_count = (points_count-2)*3 + points_count*6;
PrimReserve(vertex_count);
@ -9150,18 +9252,25 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
PrimVtx(temp_outer[i], uv, col_trans);
PrimVtx(temp_inner[i], uv, col);
}
#endif
}
else
{
// Non Anti-aliased Fill
const int vertex_count = (points_count-2)*3;
PrimReserve(vertex_count);
const int idx_count = (points_count-2)*3;
const int vtx_count = points_count;
PrimReserve(idx_count, vtx_count);
for (int i = 0; i < vtx_count; i++)
{
vtx_write[0].pos = points[i]; vtx_write[0].uv = uv; vtx_write[0].col = col;
vtx_write++;
}
for (int i = 2; i < points_count; i++)
{
PrimVtx(points[0], uv, col);
PrimVtx(points[i-1], uv, col);
PrimVtx(points[i], uv, col);
idx_write[0] = vtx_current_idx; idx_write[1] = (ImDrawIdx)(vtx_current_idx+i-1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+i);
idx_write += 3;
}
vtx_current_idx += (ImDrawIdx)vtx_count;
}
}
@ -9327,9 +9436,11 @@ 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);
ImVec4 clip_rect = clip_rect_stack.back();
if (cpu_fine_clip_rect)
@ -9342,10 +9453,15 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
font->RenderText(font_size, pos, col, clip_rect, text_begin, text_end, this, wrap_width, cpu_fine_clip_rect != NULL);
// 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)
@ -9358,7 +9474,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)
@ -10391,7 +10507,9 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
const bool word_wrap_enabled = (wrap_width > 0.0f);
const char* word_wrap_eol = NULL;
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;
if (!word_wrap_enabled && y + line_height < clip_rect.y)
@ -10505,26 +10623,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;
}
}
}
}
@ -10532,7 +10642,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;
}
//-----------------------------------------------------------------------------
@ -11992,7 +12104,7 @@ 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::Text("%d allocations", ImGui::GetIO().MetricsAllocs);
ImGui::Separator();
@ -12000,7 +12112,7 @@ void ImGui::ShowMetricsWindow(bool* opened)
{
static void NodeDrawList(ImDrawList* draw_list, const char* label)
{
bool node_opened = ImGui::TreeNode(draw_list, "%s: %d vtx, %d cmds", label, draw_list->vtx_buffer.size(), draw_list->commands.size());
bool node_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();
@ -12012,7 +12124,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();
}

21
imgui.h
View File

@ -695,6 +695,7 @@ struct ImGuiIO
float Framerate; // Framerate estimation, in frame per second. Rolling average estimation based on IO.DeltaTime over 120 frames
int MetricsAllocs; // Number of active memory allocations
int MetricsRenderVertices; // Vertices processed during last call to Render()
int MetricsRenderIndices; //
int MetricsActiveWindows; // Number of visible windows (exclude child windows)
//------------------------------------------------------------------
@ -979,13 +980,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
@ -1013,12 +1017,15 @@ 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)
ImVector<ImVec2> path; // [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();
@ -1051,15 +1058,17 @@ struct ImDrawList
IMGUI_API void AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col);
// 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 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 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.