From 1858d8d3f527429015eb0cdf0f95aa7f78c05aa6 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 8 Dec 2019 15:40:21 +0100 Subject: [PATCH] Texture-based round corners: Removed polling for Shift key in draw functions, moved that responsibility to demo code. Minor coding style tweaks. Using IM_ASSERT_PARANOID where suitable. --- imgui.cpp | 51 +++++++++++++++++++++----------------------------- imgui_demo.cpp | 3 ++- imgui_draw.cpp | 46 +++++++++++++++++---------------------------- 3 files changed, 40 insertions(+), 60 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 509c9903..c82f5f8e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5549,31 +5549,26 @@ static const ImGuiResizeBorderDef resize_border_def[4] = // Add a resize grip using the rounded corner textures, if possible. // Returns false if rendering could not be performed, true otherwise -static bool AddResizeGrip(ImDrawList* dl, const ImVec2& corner, unsigned int rad, unsigned int overall_grip_size, ImDrawFlags corners_flags, ImU32 col) +// FIXME: Probably ok to move this to imgui_draw.cpp in 'Internal Render Helpers' section. +static bool RenderResizeGripWithTex(ImDrawList* draw_list, const ImVec2& corner, unsigned int rad, unsigned int overall_grip_size, ImDrawCornerFlags corners_flags, ImU32 col) { - if (!(dl->Flags & ImDrawListFlags_TexturedRoundCorners)) // Disabled by the draw list flags + if (!(draw_list->Flags & ImDrawListFlags_TexturedRoundCorners)) // Disabled by the draw list flags return false; - ImGuiContext& g = *GImGui; + ImFontAtlas* atlas = draw_list->_Data->Font->ContainerAtlas; + IM_UNUSED(atlas); + IM_ASSERT(atlas->TexID == draw_list->_TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + IM_ASSERT(ImIsPowerOfTwo(corners_flags)); // Only allow a single corner to be specified here. + IM_ASSERT_PARANOID(!(atlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners)); - if (!g.IO.KeyAlt) // Debug - only use texture-based rendering if alt is pressed - return false; - - ImTextureID tex = dl->_Data->Font->ContainerAtlas->TexID; - IM_ASSERT(tex == dl->_TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. - IM_ASSERT(ImIsPowerOfTwo(corners_flags)); // Only allow a single corner to be specified here. - - if (dl->_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners) // No data in font - return false; - - if (rad < 1 || rad > ImFontAtlasRoundCornersMaxSize) // Radius 0 will cause issues with the UV lookup below + if (rad < 1 || rad > ImFontAtlasRoundCornersMaxSize) // Radius 0 will cause issues with the UV lookup below return false; // Calculate UVs for the three points we are interested in from the texture - const ImVec4& uvs = (*dl->_Data->TexRoundCornerData)[rad - 1].TexUvFilled; - // uv[0] is the mid-point from the corner towards the centre of the circle (solid) + // uv[0] is the mid-point from the corner towards the center of the circle (solid) // uv[1] is a solid point on the edge of the circle // uv[2] is the outer edge (blank, outside the circle) + const ImVec4& uvs = (*draw_list->_Data->TexRoundCornerData)[rad - 1].TexUvFilled; const ImVec2 uv[] = { ImVec2(ImLerp(uvs.x, uvs.z, 0.5f), ImLerp(uvs.y, uvs.w, 0.5f)), @@ -5582,7 +5577,6 @@ static bool AddResizeGrip(ImDrawList* dl, const ImVec2& corner, unsigned int rad }; // Calculate the coordinates of the points at the inside of the rounded area of the corner, and the outside of the grip on the X/Y axes - ImVec2 in_x = corner, in_y = corner, out_x = corner, out_y = corner; if (corners_flags & (ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight)) { @@ -5607,20 +5601,16 @@ static bool AddResizeGrip(ImDrawList* dl, const ImVec2& corner, unsigned int rad } // Calculate the mid-point on the diagonal - const ImVec2 mid = ImVec2(ImLerp(in_x.x, in_y.x, 0.5f), ImLerp(in_x.y, in_y.y, 0.5f)); // Now write out the geometry - - const int num_verts = 6; // Number of vertices we are going to write + const int num_verts = 6; // Number of vertices we are going to write const int num_indices = 12; // Number of indices we are going to write + draw_list->PrimReserve(num_indices, num_verts); - dl->PrimReserve(num_indices, num_verts); - - ImDrawIdx current_idx = (ImDrawIdx)dl->_VtxCurrentIdx; - ImDrawVert* vtx_write_ptr = dl->_VtxWritePtr; - ImDrawIdx* idx_write_ptr = dl->_IdxWritePtr; - + ImDrawIdx current_idx = (ImDrawIdx)draw_list->_VtxCurrentIdx; + ImDrawVert* vtx_write_ptr = draw_list->_VtxWritePtr; + ImDrawIdx* idx_write_ptr = draw_list->_IdxWritePtr; vtx_write_ptr[0].pos = mid; vtx_write_ptr[0].uv = uv[0]; vtx_write_ptr[0].col = col; vtx_write_ptr[1].pos = in_y; vtx_write_ptr[1].uv = uv[1]; vtx_write_ptr[1].col = col; vtx_write_ptr[2].pos = corner; vtx_write_ptr[2].uv = uv[2]; vtx_write_ptr[2].col = col; @@ -5631,13 +5621,14 @@ static bool AddResizeGrip(ImDrawList* dl, const ImVec2& corner, unsigned int rad // Curved section idx_write_ptr[0] = current_idx; idx_write_ptr[1] = (ImDrawIdx)(current_idx + 1); idx_write_ptr[2] = (ImDrawIdx)(current_idx + 2); idx_write_ptr[3] = current_idx; idx_write_ptr[4] = (ImDrawIdx)(current_idx + 2); idx_write_ptr[5] = (ImDrawIdx)(current_idx + 3); + // Outer section idx_write_ptr[6] = (ImDrawIdx)(current_idx + 4); idx_write_ptr[7] = (ImDrawIdx)(current_idx + 3); idx_write_ptr[8] = (ImDrawIdx)(current_idx + 5); idx_write_ptr[9] = (ImDrawIdx)(current_idx + 3); idx_write_ptr[10] = (ImDrawIdx)(current_idx + 5); idx_write_ptr[11] = (ImDrawIdx)(current_idx + 1); - dl->_VtxWritePtr += num_verts; - dl->_VtxCurrentIdx += num_verts; - dl->_IdxWritePtr += num_indices; + draw_list->_VtxWritePtr += num_verts; + draw_list->_VtxCurrentIdx += num_verts; + draw_list->_IdxWritePtr += num_indices; return true; } @@ -5920,7 +5911,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar grip_corner.y += grip.InnerDir.y * window_border_size; // Try and use a rounded texture to draw the grip - if (!AddResizeGrip(window->DrawList, grip_corner, (unsigned int)window_rounding, (unsigned int)(resize_grip_draw_size - window_border_size), grip.CornerFlags, resize_grip_col[resize_grip_n])) + if (!RenderResizeGripWithTex(window->DrawList, grip_corner, (unsigned int)window_rounding, (unsigned int)(resize_grip_draw_size - window_border_size), grip.CornerFlags, resize_grip_col[resize_grip_n])) { // Fall back to using geometry to draw the whole grip if texture-based draw failed window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index fee9ddb0..f4b37a74 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -265,7 +265,8 @@ static void TestTextureBasedRender() ImGui::Begin("tex_round_corners"); - ImGui::Text("Hold SHIFT to toggle (%s)", io.KeyShift ? "SHIFT ON -- Using textures." : "SHIFT OFF -- Old method."); + style.TexturedRoundCorners = io.KeyShift; + ImGui::Checkbox("style.TexturedRoundCorners (hold SHIFT to toggle)", &style.TexturedRoundCorners); static float radius = 16.0f; // ImFontAtlasRoundCornersMaxSize * 0.5f; static int segments = 20; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c1ff3acb..61971e14 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1406,27 +1406,21 @@ inline bool AddRoundCornerRect(ImDrawList* draw_list, const ImVec2& a, const ImV #endif const ImDrawListSharedData* data = draw_list->_Data; - if (data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners) // No data in font - return false; + IM_ASSERT_PARANOID(!(data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners)); // No data in font // Filled rectangles have no stroke width const int stroke_width = fill ? 1 : (int)thickness; - if ((stroke_width <= 0) || - (stroke_width > ImFontAtlasRoundCornersMaxStrokeWidth)) + if ((stroke_width <= 0) || (stroke_width > ImFontAtlasRoundCornersMaxStrokeWidth)) return false; // We can't handle this // If we have a >1 stroke width, we actually need to increase the radius appropriately as well to match how the geometry renderer does things const int rad = (int)rounding + (stroke_width - 1); - if ((rad <= 0) || // We don't support zero radius - (rad > ImFontAtlasRoundCornersMaxSize)) + // We don't support zero radius + if ((rad <= 0) || (rad > ImFontAtlasRoundCornersMaxSize)) return false; // We can't handle this - // Debug command to force this render path to only execute when shift is held - if (!ImGui::GetIO().KeyShift) - return false; - const unsigned int index = (stroke_width - 1) + ((rad - 1) * ImFontAtlasRoundCornersMaxStrokeWidth); ImFontRoundedCornerData& round_corner_data = (*data->TexRoundCornerData)[index]; @@ -1531,7 +1525,7 @@ inline bool AddRoundCornerRect(ImDrawList* draw_list, const ImVec2& a, const ImV ImVec2(ImLerp(corner_uv[0].x, corner_uv[b##corner ? 2 : 1].x, px), ImLerp(corner_uv[0].y, corner_uv[b##corner ? 2 : 1].y, py)); \ draw_list->_VtxWritePtr[d].col = col - // Optimised versions of the above, for the cases where either px or py is always zero + // Optimized versions of the above, for the cases where either px or py is always zero #define VTX_WRITE_LERPED_X(d, corner, px) \ draw_list->_VtxWritePtr[d].pos = ImVec2(ImLerp(i##corner.x, c##corner.x, px), i##corner.y); \ @@ -1623,7 +1617,7 @@ inline bool AddRoundCornerRect(ImDrawList* draw_list, const ImVec2& a, const ImV vxd2 = dv + 7; const float width_offset_parametric = round_corner_data.ParametricStrokeWidth; // Edge width in our parametric coordinate space - const float parametric_offset = 1.0f - width_offset_parametric; // Offset from the centre-most edge + const float parametric_offset = 1.0f - width_offset_parametric; // Offset from the center-most edge VTX_WRITE_LERPED_X(vxa2, a, parametric_offset); VTX_WRITE_LERPED_Y(vya2, a, parametric_offset); @@ -1876,9 +1870,7 @@ inline bool AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& center, fl const ImDrawListSharedData* data = draw_list->_Data; ImTextureID tex_id = data->Font->ContainerAtlas->TexID; IM_ASSERT(tex_id == draw_list->_TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. - - if (data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners) // No data in font - return false; + IM_ASSERT_PARANOID(!(data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners)); // No data in font // Filled rectangles have no stroke width const int stroke_width = fill ? 1 : (int)thickness; @@ -1890,14 +1882,10 @@ inline bool AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& center, fl // If we have a >1 stroke width, we actually need to increase the radius appropriately as well to match how the geometry renderer does things const int rad = (int)radius + (stroke_width - 1); - if ((rad <= 0) || // We don't support zero radius - (rad > ImFontAtlasRoundCornersMaxSize)) + // We don't support zero radius + if ((rad <= 0) || (rad > ImFontAtlasRoundCornersMaxSize)) return false; // We can't handle this - // Debug command to force this render path to only execute when shift is held - if (!ImGui::GetIO().KeyShift) - return false; - const unsigned int index = (stroke_width - 1) + ((rad - 1) * ImFontAtlasRoundCornersMaxStrokeWidth); ImFontRoundedCornerData& round_corner_data = (*data->TexRoundCornerData)[index]; @@ -3364,9 +3352,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) } const int FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING = 2; -// Padding applied to the Y axis to separate the two halves of the image -// This must be a multiple of two -const int FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING = 4; +const int FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING = 4; // Padding applied to the Y axis to separate the two halves of the image (this must be a multiple of two) // Register the rectangles we need for the rounded corner images static void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas) @@ -3385,16 +3371,13 @@ static void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas) for (unsigned int radius_index = 0; radius_index < max_radius; radius_index++) { int spare_rect_id = -1; // The last rectangle ID we generated with a spare half - for (unsigned int stroke_width_index = 0; stroke_width_index < max_thickness; stroke_width_index++) { //const unsigned int index = stroke_width_index + (radius_index * ImFontAtlasRoundCornersMaxStrokeWidth); - const int width = radius_index + 1 + pad * 2; const int height = radius_index + 1 + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING + pad * 2; ImFontRoundedCornerData corner_data; - if (ImFontAtlasRoundCornersStrokeWidthMask & (1 << stroke_width_index)) { if ((stroke_width_index == 0) || (spare_rect_id < 0)) @@ -3413,9 +3396,11 @@ static void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas) } } else + { corner_data.RectId = -1; // Set RectId to -1 if we don't want any data + } - IM_ASSERT_PARANOID(atlas->TexRoundCornerData.size() == (int)index); + IM_ASSERT_PARANOID(atlas->TexRoundCornerData.Size == (int)index); atlas->TexRoundCornerData.push_back(corner_data); } } @@ -3443,7 +3428,6 @@ static void ImFontAtlasBuildRenderRoundCornersTexData(ImFontAtlas* atlas) for (unsigned int stroke_width_index = 0; stroke_width_index < max_thickness; stroke_width_index++) { const unsigned int index = stroke_width_index + (radius_index * ImFontAtlasRoundCornersMaxStrokeWidth); - const unsigned int radius = radius_index + 1; const float stroke_width = (float)stroke_width_index + 1; @@ -3527,7 +3511,9 @@ static void ImFontAtlasBuildRenderRoundCornersTexData(ImFontAtlas* atlas) } } else + { alpha = ImClamp(-dist, 0.0f, 1.0f); // Filled version + } } else { @@ -3562,7 +3548,9 @@ static void ImFontAtlasBuildRenderRoundCornersTexData(ImFontAtlas* atlas) data.TexUvFilled = ImVec4(uv0.x, uv0.y, uv1.x, uv1.y); } else + { data.TexUvStroked = ImVec4(uv0.x, uv0.y, uv1.x, uv1.y); + } } } }