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

docking
ocornut 10 years ago
parent 500a8a0e02
commit 1746b04065

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

@ -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();

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

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

@ -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();
}

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

Loading…
Cancel
Save