From 512d39d03169fdaa5a122eae586ab90577ee9af7 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 29 Mar 2019 16:17:04 +0100 Subject: [PATCH 01/10] Examples: OpenGL3: Minor tweaks, clarifications + not calling glBindBuffer more than necessary in the render loop. --- docs/CHANGELOG.txt | 1 + examples/imgui_impl_allegro5.cpp | 2 +- examples/imgui_impl_opengl3.cpp | 50 +++++++++++++++++--------------- examples/imgui_impl_vulkan.cpp | 3 +- imgui.h | 2 +- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e1911d3e..5193b8bf 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,7 @@ Other Changes: - Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood] - Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early, and help users understand what they are missing. (#2421) +- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop. - Examples: FreeGLUT: Made io.DeltaTime always > 0. (#2430) diff --git a/examples/imgui_impl_allegro5.cpp b/examples/imgui_impl_allegro5.cpp index ffd59d73..3b589c32 100644 --- a/examples/imgui_impl_allegro5.cpp +++ b/examples/imgui_impl_allegro5.cpp @@ -154,7 +154,7 @@ bool ImGui_ImplAllegro5_CreateDeviceObjects() { // Build texture atlas ImGuiIO &io = ImGui::GetIO(); - unsigned char *pixels; + unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); diff --git a/examples/imgui_impl_opengl3.cpp b/examples/imgui_impl_opengl3.cpp index 98904363..347da470 100644 --- a/examples/imgui_impl_opengl3.cpp +++ b/examples/imgui_impl_opengl3.cpp @@ -12,6 +12,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop. // 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early. // 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0). // 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader. @@ -104,8 +105,8 @@ static char g_GlslVersionString[32] = ""; static GLuint g_FontTexture = 0; static GLuint 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 int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location +static int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location static unsigned int g_VboHandle = 0, g_ElementsHandle = 0; // Functions @@ -170,7 +171,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) #endif GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); #ifndef IMGUI_IMPL_OPENGL_ES2 - GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); + GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); #endif #ifdef GL_POLYGON_MODE GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); @@ -226,20 +227,23 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. #endif + // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) + // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. #ifndef IMGUI_IMPL_OPENGL_ES2 - // Recreate the VAO every time - // (This is to easily allow multiple GL contexts. VAO are not shared among GL contexts, and we don't track creation/deletion of windows so we don't have an obvious key to use to cache them.) - GLuint vao_handle = 0; - glGenVertexArrays(1, &vao_handle); - glBindVertexArray(vao_handle); + GLuint vertex_array_object = 0; + glGenVertexArrays(1, &vertex_array_object); + glBindVertexArray(vertex_array_object); #endif + + // Bind vertex/index buffers and setup attributes for ImDrawVert glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); - glEnableVertexAttribArray(g_AttribLocationPosition); - glEnableVertexAttribArray(g_AttribLocationUV); - glEnableVertexAttribArray(g_AttribLocationColor); - glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); - glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); - glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); + glEnableVertexAttribArray(g_AttribLocationVtxPos); + glEnableVertexAttribArray(g_AttribLocationVtxUV); + glEnableVertexAttribArray(g_AttribLocationVtxColor); + glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); + glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); + glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports @@ -251,10 +255,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) const ImDrawList* cmd_list = draw_data->CmdLists[n]; size_t idx_buffer_offset = 0; - glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); + // Upload vertex/index buffers glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) @@ -280,7 +282,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) if (clip_origin_lower_left) glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); else - glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT) + glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) // Bind texture, Draw glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); @@ -290,8 +292,10 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) idx_buffer_offset += pcmd->ElemCount * sizeof(ImDrawIdx); } } + + // Destroy the temporary VAO #ifndef IMGUI_IMPL_OPENGL_ES2 - glDeleteVertexArrays(1, &vao_handle); + glDeleteVertexArrays(1, &vertex_array_object); #endif // Restore modified GL state @@ -302,7 +306,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) #endif glActiveTexture(last_active_texture); #ifndef IMGUI_IMPL_OPENGL_ES2 - glBindVertexArray(last_vertex_array); + glBindVertexArray(last_vertex_array_object); #endif glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); @@ -554,9 +558,9 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); - g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position"); - g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV"); - g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color"); + g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position"); + g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV"); + g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color"); // Create buffers glGenBuffers(1, &g_VboHandle); diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index eabc49ea..77c9408c 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -221,7 +221,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm if (!fd->IndexBuffer || fd->IndexBufferSize < index_size) CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - // Upload Vertex and index Data: + // Upload vertex/index data into a single contiguous GPU buffer { ImDrawVert* vtx_dst = NULL; ImDrawIdx* idx_dst = NULL; @@ -305,6 +305,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { + // User callback (registered via ImDrawList::AddCallback) pcmd->UserCallback(cmd_list, pcmd); } else diff --git a/imgui.h b/imgui.h index 4c8ab81d..1d907b04 100644 --- a/imgui.h +++ b/imgui.h @@ -19,7 +19,7 @@ Index of this file: // Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) // Obsolete functions // Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) -// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData) +// Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData) // Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) */ From 163779da5108ad8d54c1d3fdaef6fa276b8bd36b Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 29 Mar 2019 16:18:26 +0100 Subject: [PATCH 02/10] Examples: DirectX12: Various tidying up. --- examples/imgui_impl_dx11.cpp | 2 +- examples/imgui_impl_dx12.cpp | 95 +++++++++++++++++------------------- 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/examples/imgui_impl_dx11.cpp b/examples/imgui_impl_dx11.cpp index a686d6bb..060d86cd 100644 --- a/examples/imgui_impl_dx11.cpp +++ b/examples/imgui_impl_dx11.cpp @@ -90,7 +90,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) return; } - // Copy and convert all vertices into a single contiguous buffer + // Upload vertex/index data into a single contiguous GPU buffer D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource; if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) return; diff --git a/examples/imgui_impl_dx12.cpp b/examples/imgui_impl_dx12.cpp index f9e1884f..04fe7fd0 100644 --- a/examples/imgui_impl_dx12.cpp +++ b/examples/imgui_impl_dx12.cpp @@ -12,6 +12,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-03-29: Misc: Various minor tidying up. // 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile(). // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-06-12: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from NewFrame() to RenderDrawData(). @@ -43,14 +44,14 @@ static D3D12_GPU_DESCRIPTOR_HANDLE g_hFontSrvGpuDescHandle = {}; struct FrameResources { - ID3D12Resource* IB; - ID3D12Resource* VB; - int VertexBufferSize; - int IndexBufferSize; + ID3D12Resource* IndexBuffer; + ID3D12Resource* VertexBuffer; + int IndexBufferSize; + int VertexBufferSize; }; -static FrameResources* g_pFrameResources = NULL; -static UINT g_numFramesInFlight = 0; -static UINT g_frameIndex = UINT_MAX; +static FrameResources* g_pFrameResources = NULL; +static UINT g_numFramesInFlight = 0; +static UINT g_frameIndex = UINT_MAX; struct VERTEX_CONSTANT_BUFFER { @@ -64,17 +65,13 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL // FIXME: I'm assuming that this only gets called once per frame! // If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator. g_frameIndex = g_frameIndex + 1; - FrameResources* frameResources = &g_pFrameResources[g_frameIndex % g_numFramesInFlight]; - ID3D12Resource* g_pVB = frameResources->VB; - ID3D12Resource* g_pIB = frameResources->IB; - int g_VertexBufferSize = frameResources->VertexBufferSize; - int g_IndexBufferSize = frameResources->IndexBufferSize; + FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight]; // Create and grow vertex/index buffers if needed - if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) + if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount) { - if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } - g_VertexBufferSize = draw_data->TotalVtxCount + 5000; + if (fr->VertexBuffer != NULL) { fr->VertexBuffer->Release(); fr->VertexBuffer = NULL; } + fr->VertexBufferSize = draw_data->TotalVtxCount + 5000; D3D12_HEAP_PROPERTIES props; memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); props.Type = D3D12_HEAP_TYPE_UPLOAD; @@ -83,7 +80,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL D3D12_RESOURCE_DESC desc; memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC)); desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - desc.Width = g_VertexBufferSize * sizeof(ImDrawVert); + desc.Width = fr->VertexBufferSize * sizeof(ImDrawVert); desc.Height = 1; desc.DepthOrArraySize = 1; desc.MipLevels = 1; @@ -91,15 +88,13 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL desc.SampleDesc.Count = 1; desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; desc.Flags = D3D12_RESOURCE_FLAG_NONE; - if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&g_pVB)) < 0) + if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->VertexBuffer)) < 0) return; - frameResources->VB = g_pVB; - frameResources->VertexBufferSize = g_VertexBufferSize; } - if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) + if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount) { - if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } - g_IndexBufferSize = draw_data->TotalIdxCount + 10000; + if (fr->IndexBuffer != NULL) { fr->IndexBuffer->Release(); fr->IndexBuffer = NULL; } + fr->IndexBufferSize = draw_data->TotalIdxCount + 10000; D3D12_HEAP_PROPERTIES props; memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); props.Type = D3D12_HEAP_TYPE_UPLOAD; @@ -108,7 +103,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL D3D12_RESOURCE_DESC desc; memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC)); desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - desc.Width = g_IndexBufferSize * sizeof(ImDrawIdx); + desc.Width = fr->IndexBufferSize * sizeof(ImDrawIdx); desc.Height = 1; desc.DepthOrArraySize = 1; desc.MipLevels = 1; @@ -116,19 +111,17 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL desc.SampleDesc.Count = 1; desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; desc.Flags = D3D12_RESOURCE_FLAG_NONE; - if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&g_pIB)) < 0) + if (g_pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->IndexBuffer)) < 0) return; - frameResources->IB = g_pIB; - frameResources->IndexBufferSize = g_IndexBufferSize; } - // Copy and convert all vertices into a single contiguous buffer + // Upload vertex/index data into a single contiguous GPU buffer void* vtx_resource, *idx_resource; D3D12_RANGE range; memset(&range, 0, sizeof(D3D12_RANGE)); - if (g_pVB->Map(0, &range, &vtx_resource) != S_OK) + if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK) return; - if (g_pIB->Map(0, &range, &idx_resource) != S_OK) + if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK) return; ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource; ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource; @@ -140,14 +133,13 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL vtx_dst += cmd_list->VtxBuffer.Size; idx_dst += cmd_list->IdxBuffer.Size; } - g_pVB->Unmap(0, &range); - g_pIB->Unmap(0, &range); + fr->VertexBuffer->Unmap(0, &range); + fr->IndexBuffer->Unmap(0, &range); // Setup orthographic projection matrix into our constant buffer // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). VERTEX_CONSTANT_BUFFER vertex_constant_buffer; { - VERTEX_CONSTANT_BUFFER* constant_buffer = &vertex_constant_buffer; float L = draw_data->DisplayPos.x; float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; float T = draw_data->DisplayPos.y; @@ -159,7 +151,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL { 0.0f, 0.0f, 0.5f, 0.0f }, { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, }; - memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); + memcpy(&vertex_constant_buffer.mvp, mvp, sizeof(mvp)); } // Setup viewport @@ -177,14 +169,14 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL unsigned int offset = 0; D3D12_VERTEX_BUFFER_VIEW vbv; memset(&vbv, 0, sizeof(D3D12_VERTEX_BUFFER_VIEW)); - vbv.BufferLocation = g_pVB->GetGPUVirtualAddress() + offset; - vbv.SizeInBytes = g_VertexBufferSize * stride; + vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset; + vbv.SizeInBytes = fr->VertexBufferSize * stride; vbv.StrideInBytes = stride; ctx->IASetVertexBuffers(0, 1, &vbv); D3D12_INDEX_BUFFER_VIEW ibv; memset(&ibv, 0, sizeof(D3D12_INDEX_BUFFER_VIEW)); - ibv.BufferLocation = g_pIB->GetGPUVirtualAddress(); - ibv.SizeInBytes = g_IndexBufferSize * sizeof(ImDrawIdx); + ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress(); + ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx); ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; ctx->IASetIndexBuffer(&ibv); ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -192,7 +184,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL ctx->SetGraphicsRootSignature(g_pRootSignature); ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0); - // Setup render state + // Setup blend factor const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; ctx->OMSetBlendFactor(blend_factor); @@ -208,10 +200,12 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { + // User callback (registered via ImDrawList::AddCallback) pcmd->UserCallback(cmd_list, pcmd); } else { + // Apply Scissor, Bind texture, Draw const D3D12_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) }; ctx->SetGraphicsRootDescriptorTable(1, *(D3D12_GPU_DESCRIPTOR_HANDLE*)&pcmd->TextureId); ctx->RSSetScissorRects(1, &r); @@ -490,9 +484,9 @@ bool ImGui_ImplDX12_CreateDeviceObjects() // Create the input layout static D3D12_INPUT_ELEMENT_DESC local_layout[] = { - { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, IM_OFFSETOF(ImDrawVert, pos), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, IM_OFFSETOF(ImDrawVert, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, IM_OFFSETOF(ImDrawVert, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; psoDesc.InputLayout = { local_layout, 3 }; } @@ -576,15 +570,17 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() if (!g_pd3dDevice) return; + ImGuiIO& io = ImGui::GetIO(); if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; } if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; } if (g_pRootSignature) { g_pRootSignature->Release(); g_pRootSignature = NULL; } if (g_pPipelineState) { g_pPipelineState->Release(); g_pPipelineState = NULL; } - if (g_pFontTextureResource) { g_pFontTextureResource->Release(); g_pFontTextureResource = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. + if (g_pFontTextureResource) { g_pFontTextureResource->Release(); g_pFontTextureResource = NULL; io.Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. for (UINT i = 0; i < g_numFramesInFlight; i++) { - if (g_pFrameResources[i].IB) { g_pFrameResources[i].IB->Release(); g_pFrameResources[i].IB = NULL; } - if (g_pFrameResources[i].VB) { g_pFrameResources[i].VB->Release(); g_pFrameResources[i].VB = NULL; } + FrameResources* fr = &g_pFrameResources[i]; + if (fr->IndexBuffer) { fr->IndexBuffer->Release(); fr->IndexBuffer = NULL; } + if (fr->VertexBuffer) { fr->VertexBuffer->Release(); fr->VertexBuffer = NULL; } } } @@ -605,10 +601,11 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO // Create buffers with a default size (they will later be grown as needed) for (int i = 0; i < num_frames_in_flight; i++) { - g_pFrameResources[i].IB = NULL; - g_pFrameResources[i].VB = NULL; - g_pFrameResources[i].VertexBufferSize = 5000; - g_pFrameResources[i].IndexBufferSize = 10000; + FrameResources* fr = &g_pFrameResources[i]; + fr->IndexBuffer = NULL; + fr->VertexBuffer = NULL; + fr->IndexBufferSize = 10000; + fr->VertexBufferSize = 5000; } return true; @@ -618,10 +615,10 @@ void ImGui_ImplDX12_Shutdown() { ImGui_ImplDX12_InvalidateDeviceObjects(); delete[] g_pFrameResources; + g_pFrameResources = NULL; g_pd3dDevice = NULL; g_hFontSrvCpuDescHandle.ptr = 0; g_hFontSrvGpuDescHandle.ptr = 0; - g_pFrameResources = NULL; g_numFramesInFlight = 0; g_frameIndex = UINT_MAX; } From e21bbee311a13c451a72fb0710fd25d963d2a974 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 29 Mar 2019 18:29:15 +0100 Subject: [PATCH 03/10] Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). FreeType: Fixed suggested code to not require an initial build call.. (#2454) --- docs/CHANGELOG.txt | 1 + examples/imgui_impl_dx9.cpp | 22 ++++------------------ misc/freetype/README.md | 9 +++++---- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5193b8bf..e3b717d9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,7 @@ Other Changes: - Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early, and help users understand what they are missing. (#2421) - Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop. +- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454) - Examples: FreeGLUT: Made io.DeltaTime always > 0. (#2430) diff --git a/examples/imgui_impl_dx9.cpp b/examples/imgui_impl_dx9.cpp index c0b9c74e..566ea4ce 100644 --- a/examples/imgui_impl_dx9.cpp +++ b/examples/imgui_impl_dx9.cpp @@ -10,6 +10,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). // 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288. // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example. @@ -253,24 +254,9 @@ void ImGui_ImplDX9_InvalidateDeviceObjects() { if (!g_pd3dDevice) return; - if (g_pVB) - { - g_pVB->Release(); - g_pVB = NULL; - } - if (g_pIB) - { - g_pIB->Release(); - g_pIB = NULL; - } - - // At this point note that we set ImGui::GetIO().Fonts->TexID to be == g_FontTexture, so clear both. - ImGuiIO& io = ImGui::GetIO(); - IM_ASSERT(g_FontTexture == io.Fonts->TexID); - if (g_FontTexture) - g_FontTexture->Release(); - g_FontTexture = NULL; - io.Fonts->TexID = NULL; + if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } + if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } + if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. } void ImGui_ImplDX9_NewFrame() diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 4c53cd9c..397adec7 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -43,7 +43,8 @@ while (true) if (freetype_test.UpdateRebuild()) { // REUPLOAD FONT TEXTURE TO GPU - // e.g ImGui_ImplOpenGL3_DestroyDeviceObjects() + ImGui_ImplOpenGL3_CreateDeviceObjects() + ImGui_ImplXXX_DestroyDeviceObjects(); + ImGui_ImplXXX_CreateDeviceObjects(); } ImGui::NewFrame(); freetype_test.ShowFreetypeOptionsWindow(); @@ -85,10 +86,10 @@ struct FreeTypeTest if (!WantRebuild) return false; ImGuiIO& io = ImGui::GetIO(); - for (int n = 0; n < io.Fonts->Fonts.Size; n++) + io.Fonts->TexGlyphPadding = FontsPadding; + for (int n = 0; n < io.Fonts->ConfigData.Size; n++) { - ImFontConfig* font_config = (ImFontConfig*)io.Fonts->Fonts[n]->ConfigData; - io.Fonts->TexGlyphPadding = FontsPadding; + ImFontConfig* font_config = (ImFontConfig*)&io.Fonts->ConfigData[n]; font_config->RasterizerMultiply = FontsMultiply; font_config->RasterizerFlags = (BuildMode == FontBuildMode_FreeType) ? FontsFlags : 0x00; } From d9568c717de8ec53445bad00be73133f1a110317 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Sun, 31 Mar 2019 01:35:03 -0700 Subject: [PATCH 04/10] Silencing -Wstack-protector (#2459) --- imgui_draw.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 06340c07..dcdf0e3f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -73,6 +73,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer #if __GNUC__ >= 8 #pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif From 3a737e665ab3f663c29596f18a6c8ed96b152a70 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 Apr 2019 17:32:14 +0200 Subject: [PATCH 05/10] Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int). + demo typo --- docs/CHANGELOG.txt | 1 + examples/imgui_impl_vulkan.cpp | 7 ++++--- imgui_demo.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e3b717d9..4834cb3f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,7 @@ Other Changes: - Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early, and help users understand what they are missing. (#2421) - Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop. +- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int). - Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454) - Examples: FreeGLUT: Made io.DeltaTime always > 0. (#2430) diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index 77c9408c..ad9406ca 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -13,6 +13,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int). // 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display. // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-08-25: Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case. @@ -216,9 +217,9 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // Create the Vertex and Index buffers: size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); - if (!fd->VertexBuffer || fd->VertexBufferSize < vertex_size) + if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size) CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - if (!fd->IndexBuffer || fd->IndexBufferSize < index_size) + if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size) CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); // Upload vertex/index data into a single contiguous GPU buffer @@ -262,7 +263,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm VkBuffer vertex_buffers[1] = { fd->VertexBuffer }; VkDeviceSize vertex_offset[1] = { 0 }; vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset); - vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, VK_INDEX_TYPE_UINT16); + vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); } // Setup viewport: diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 37eacfa3..7496cd23 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1546,7 +1546,7 @@ static void ShowDemoWindowWidgets() "IsItemEdited() = %d\n" "IsItemActivated() = %d\n" "IsItemDeactivated() = %d\n" - "IsItemDeactivatedEdit() = %d\n" + "IsItemDeactivatedAfterEdit() = %d\n" "IsItemVisible() = %d\n" "GetItemRectMin() = (%.1f, %.1f)\n" "GetItemRectMax() = (%.1f, %.1f)\n" From e3cd6b1cbb025d62289a550c913d1a6f8e97357f Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 1 Apr 2019 18:12:24 +0200 Subject: [PATCH 06/10] Examples: Vulkan: Using IM_ARRAYSIZE() where possible. --- examples/imgui_impl_vulkan.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index ad9406ca..3aafb555 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -212,7 +212,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm VkResult err; FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex]; - g_FrameIndex = (g_FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES; + g_FrameIndex = (g_FrameIndex + 1) % IM_ARRAYSIZE(g_FramesDataBuffers); // Create the Vertex and Index buffers: size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); @@ -694,7 +694,7 @@ void ImGui_ImplVulkan_InvalidateDeviceObjects() { ImGui_ImplVulkan_InvalidateFontUploadObjects(); - for (int i = 0; i < IMGUI_VK_QUEUED_FRAMES; i++) + for (int i = 0; i < IM_ARRAYSIZE(g_FramesDataBuffers); i++) { FrameDataForRender* fd = &g_FramesDataBuffers[i]; if (fd->VertexBuffer) { vkDestroyBuffer (g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; } @@ -867,7 +867,7 @@ void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_ // Create Command Buffers VkResult err; - for (int i = 0; i < IMGUI_VK_QUEUED_FRAMES; i++) + for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++) { ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i]; { @@ -1068,7 +1068,7 @@ void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, I vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals) //vkQueueWaitIdle(g_Queue); - for (int i = 0; i < IMGUI_VK_QUEUED_FRAMES; i++) + for (int i = 0; i < IM_ARRAYSIZE(wd->Frames); i++) { ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i]; vkDestroyFence(device, fd->Fence, allocator); From 4a57507f75e1e0da7d3bd72345ab3ae86f4df81e Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 3 Apr 2019 10:40:14 +0200 Subject: [PATCH 07/10] InputText: Work-around for buggy standard libraries where isprint('\t') returns true. (#2467, #1336) Not using isprint. + todo items. --- docs/CHANGELOG.txt | 1 + docs/TODO.txt | 3 ++- imgui.cpp | 2 +- imgui_demo.cpp | 3 ++- imgui_widgets.cpp | 10 +++++++--- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4834cb3f..f2b0b447 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -38,6 +38,7 @@ Breaking Changes: Other Changes: - InputText: Fixed selection background starts rendering one frame after the cursor movement when first transitioning from no-selection to has-selection. (Bug in 1.69) (#2436) [@Nazg-Gul] +- InputText: Work-around for buggy standard libraries where isprint('\t') returns true. (#2467, #1336) - GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419) - GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero. - Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood] diff --git a/docs/TODO.txt b/docs/TODO.txt index f1774f8c..7e540b7b 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -138,7 +138,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - button: provide a button that looks framed. (?) - image/image button: misalignment on padded/bordered button? - image/image button: parameters are confusing, image() has tint_col,border_col whereas imagebutton() has bg_col/tint_col. Even thou they are different parameters ordering could be more consistent. can we fix that? - - image button: not taking an explicit id is odd. + - image button: not taking an explicit id can be problematic. (#2464, #1390) - slider/drag: ctrl+click when format doesn't include a % character.. disable? display underlying value in default format? (see InputScalarAsWidgetReplacement) - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() - slider: initial absolute click is imprecise. change to relative movement slider (same as scrollbar). (#1946) @@ -329,6 +329,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - examples: glfw: could go idle when minimized? if (glfwGetWindowAttrib(window, GLFW_ICONIFIED)) { glfwWaitEvents(); continue; } // issue: DeltaTime will be super high on resume, perhaps provide a way to let impl know (#440) - examples: opengl: rename imgui_impl_opengl2 to impl_opengl_legacy and imgui_impl_opengl3 to imgui_impl_opengl? (#1900) - examples: opengl: could use a single vertex buffer and glBufferSubData for uploads? + - examples: vulkan: viewport: support for synchronized swapping of multiple swap chains. - optimization: replace vsnprintf with stb_printf? or enable the defines/infrastructure to allow it (#1038) - optimization: add clipping for multi-component widgets (SliderFloatX, ColorEditX, etc.). one problem is that nav branch can't easily clip parent group when there is a move request. - optimization: add a flag to disable most of rendering, for the case where the user expect to skip it (#335) diff --git a/imgui.cpp b/imgui.cpp index b129cb18..506a22aa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -933,7 +933,7 @@ CODE #endif #include "imgui_internal.h" -#include // toupper, isprint +#include // toupper #include // vsnprintf, sscanf, printf #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #include // intptr_t diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7496cd23..423022c1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -49,7 +49,7 @@ Index of this file: #endif #include "imgui.h" -#include // toupper, isprint +#include // toupper #include // INT_MIN, INT_MAX #include // sqrtf, powf, cosf, sinf, floorf, ceilf #include // vsnprintf, sscanf, printf @@ -2571,6 +2571,7 @@ static void ShowDemoWindowMisc() ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f151e119..88e90cbc 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -37,7 +37,7 @@ Index of this file: #endif #include "imgui_internal.h" -#include // toupper, isprint +#include // toupper #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #include // intptr_t #else @@ -3139,7 +3139,8 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f { unsigned int c = *p_char; - if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF))) + // Filter non-printable (NB: isprint is unreliable! see #2467) + if (c < 0x20) { bool pass = false; pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); @@ -3148,9 +3149,11 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f return false; } - if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys. + // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) + if (c >= 0xE000 && c <= 0xF8FF) return false; + // Generic named filters if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)) { if (flags & ImGuiInputTextFlags_CharsDecimal) @@ -3174,6 +3177,7 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f return false; } + // Custom callback filter if (flags & ImGuiInputTextFlags_CallbackCharFilter) { ImGuiInputTextCallbackData callback_data; From 01e29a393340aeac3fbc63fa5f618bb9d3555c7f Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 3 Apr 2019 10:45:51 +0200 Subject: [PATCH 08/10] InputText: Fixed ImGuiInputTextFlags_AllowTabInput leading to two tabs characters being inserted if the back-end provided both Key and Character input. (#2467, #1336) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 8 +------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f2b0b447..b4f7a9c2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,6 +39,8 @@ Other Changes: - InputText: Fixed selection background starts rendering one frame after the cursor movement when first transitioning from no-selection to has-selection. (Bug in 1.69) (#2436) [@Nazg-Gul] - InputText: Work-around for buggy standard libraries where isprint('\t') returns true. (#2467, #1336) +- InputText: Fixed ImGuiInputTextFlags_AllowTabInput leading to two tabs characters being inserted + if the back-end provided both Key and Character input. (#2467, #1336) - GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419) - GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero. - Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 88e90cbc..04fe9d61 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3333,7 +3333,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ FocusWindow(window); IM_ASSERT(ImGuiNavInput_COUNT < 32); g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel); - if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out + if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. g.ActiveIdBlockNavInputFlags |= (1 << ImGuiNavInput_KeyTab_); if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory)) g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down)); @@ -3506,12 +3506,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->OnKeyPressed((int)c); } } - else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !is_readonly) - { - unsigned int c = '\t'; // Insert TAB - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) - state->OnKeyPressed((int)c); - } else if (IsKeyPressedMap(ImGuiKey_Escape)) { clear_active_id = cancel_edit = true; From da035ced9752224050f88bec01ba3313972d30ab Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 3 Apr 2019 11:04:00 +0200 Subject: [PATCH 09/10] InputText, Examples/SDL: Emulate \t input if back-end doesn't provide it. (#1336, #2467) + Fix some output filename in SDL build batch files. --- docs/TODO.txt | 1 + examples/example_sdl_opengl2/build_win32.bat | 4 ++-- examples/example_sdl_opengl3/build_win32.bat | 2 +- imgui_widgets.cpp | 18 ++++++++++++++---- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 7e540b7b..45d34748 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -80,6 +80,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - input text: force scroll to end or scroll to a given line/contents (so user can implement a log or a search feature) - input text: a side bar that could e.g. preview where errors are. probably left to the user to draw but we'd need to give them the info there. - input text: a way for the user to provide syntax coloring. + - input text: Shift+TAB with ImGuiInputTextFlags_AllowTabInput works inconsistently depending on whether back-end emits actual Tab Key + \t Char or not (SDL doesn't). - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). - input text multi-line: support for cut/paste without selection (cut/paste the current line) - input text multi-line: line numbers? status bar? (follow up on #200) diff --git a/examples/example_sdl_opengl2/build_win32.bat b/examples/example_sdl_opengl2/build_win32.bat index 97692d9e..d209b2a2 100644 --- a/examples/example_sdl_opengl2/build_win32.bat +++ b/examples/example_sdl_opengl2/build_win32.bat @@ -1,8 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. set OUT_DIR=Debug -set OUT_EXE=example_sdl_opengl2.exe +set OUT_EXE=example_sdl_opengl2 set INCLUDES=/I.. /I..\.. /I%SDL2_DIR%\include set SOURCES=main.cpp ..\imgui_impl_sdl.cpp ..\imgui_impl_opengl2.cpp ..\..\imgui*.cpp set LIBS=/libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib mkdir %OUT_DIR% -cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_DIR%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console +cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console diff --git a/examples/example_sdl_opengl3/build_win32.bat b/examples/example_sdl_opengl3/build_win32.bat index f263c4b3..ce105602 100644 --- a/examples/example_sdl_opengl3/build_win32.bat +++ b/examples/example_sdl_opengl3/build_win32.bat @@ -1,6 +1,6 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. set OUT_DIR=Debug -set OUT_EXE=example_sdl_opengl3.exe +set OUT_EXE=example_sdl_opengl3 set INCLUDES=/I.. /I..\.. /I%SDL2_DIR%\include /I..\libs\gl3w set SOURCES=main.cpp ..\imgui_impl_sdl.cpp ..\imgui_impl_opengl3.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c set LIBS=/libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 04fe9d61..941b02ef 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3435,12 +3435,22 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (state->SelectedAllMouseLock && !io.MouseDown[0]) state->SelectedAllMouseLock = false; + // It is ill-defined whether the back-end needs to send a \t character when pressing the TAB keys. + // Win32 and GLFW naturally do it but not SDL. + const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); + if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) + if (!io.InputQueueCharacters.contains('\t')) + { + unsigned int c = '\t'; // Insert TAB + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + + // Process regular text input (before we check for Return because using some IME will effectively send a Return?) + // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. if (io.InputQueueCharacters.Size > 0) { - // Process text input (before we check for Return because using some IME will effectively send a Return?) - // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. - bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); - if (!ignore_inputs && !is_readonly && !user_nav_input_start) + if (!ignore_char_inputs && !is_readonly && !user_nav_input_start) for (int n = 0; n < io.InputQueueCharacters.Size; n++) { // Insert character if they pass filtering From 8dab7ac0213088af8f2ce28ab0c2df65b2a6873d Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 3 Apr 2019 11:14:34 +0200 Subject: [PATCH 10/10] InputText: Made Shift+Tab consistently do nothing regardless of whether the back-end emits both char and keys or just keys. (#2467, #1336) --- docs/TODO.txt | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 1 + imgui_widgets.cpp | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 45d34748..24525947 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -80,7 +80,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - input text: force scroll to end or scroll to a given line/contents (so user can implement a log or a search feature) - input text: a side bar that could e.g. preview where errors are. probably left to the user to draw but we'd need to give them the info there. - input text: a way for the user to provide syntax coloring. - - input text: Shift+TAB with ImGuiInputTextFlags_AllowTabInput works inconsistently depending on whether back-end emits actual Tab Key + \t Char or not (SDL doesn't). + - input text: Shift+TAB with ImGuiInputTextFlags_AllowTabInput could eat preceding blanks, up to tab_count. - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). - input text multi-line: support for cut/paste without selection (cut/paste the current line) - input text multi-line: line numbers? status bar? (follow up on #200) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index dcdf0e3f..97f25bd4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2468,7 +2468,7 @@ void ImFont::BuildLookupTable() ImFontGlyph& tab_glyph = Glyphs.back(); tab_glyph = *FindGlyph((ImWchar)' '); tab_glyph.Codepoint = '\t'; - tab_glyph.AdvanceX *= 4; + tab_glyph.AdvanceX *= IM_TABSIZE; IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size-1); } diff --git a/imgui_internal.h b/imgui_internal.h index 824c2824..bcbaec6a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -129,6 +129,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe #else #define IM_NEWLINE "\n" #endif +#define IM_TABSIZE (4) #define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) #define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 941b02ef..4ebbc1f5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3455,6 +3455,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Insert character if they pass filtering unsigned int c = (unsigned int)io.InputQueueCharacters[n]; + if (c == '\t' && io.KeyShift) + continue; if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) state->OnKeyPressed((int)c); }