From 05d950207556e29fba445c5ae38cca002601fc1d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Jun 2020 21:29:05 +0200 Subject: [PATCH] Texture-based round corners: Moved RenderResizeGripWithTex to RenderWindowResizeGrip --- imgui.cpp | 87 +----------------------------------------------- imgui_draw.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++++++ imgui_internal.h | 1 + 3 files changed, 88 insertions(+), 86 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d98ea23c..13fd1b2a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5547,91 +5547,6 @@ static const ImGuiResizeBorderDef resize_border_def[4] = { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down }; -// Add a resize grip using the rounded corner textures, if possible. -// Returns false if rendering could not be performed, true otherwise -// 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 (!(draw_list->Flags & ImDrawListFlags_RoundCornersUseTex)) // Disabled by the draw list flags - return false; - - ImFontAtlas* atlas = draw_list->_Data->Font->ContainerAtlas; - 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 (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 - // 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)), - ImVec2(uvs.x, uvs.y), - ImVec2(uvs.z, uvs.w), - }; - - // 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)) - { - in_y.y += rad; - out_y.y += overall_grip_size; - } - else if (corners_flags & (ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight)) - { - in_y.y -= rad; - out_y.y -= overall_grip_size; - } - - if (corners_flags & (ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomLeft)) - { - in_x.x += rad; - out_x.x += overall_grip_size; - } - else if (corners_flags & (ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomRight)) - { - in_x.x -= rad; - out_x.x -= overall_grip_size; - } - - // 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_indices = 12; // Number of indices we are going to write - draw_list->PrimReserve(num_indices, num_verts); - - 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; - vtx_write_ptr[3].pos = in_x; vtx_write_ptr[3].uv = uv[1]; vtx_write_ptr[3].col = col; - vtx_write_ptr[4].pos = out_x; vtx_write_ptr[4].uv = uv[1]; vtx_write_ptr[4].col = col; - vtx_write_ptr[5].pos = out_y; vtx_write_ptr[5].uv = uv[1]; vtx_write_ptr[5].col = col; - - // 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); - - draw_list->_VtxWritePtr += num_verts; - draw_list->_VtxCurrentIdx += num_verts; - draw_list->_IdxWritePtr += num_indices; - - return true; -} - static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) { ImRect rect = window->Rect(); @@ -5910,7 +5825,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 (!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])) + if (!RenderWindowResizeGrip(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_draw.cpp b/imgui_draw.cpp index b2fe57ca..9523d0b4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4510,6 +4510,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col // - RenderArrowPointingAt() // - RenderRectFilledRangeH() // - RenderRectFilledWithHole() +// - RenderWindowResizeGrip() //----------------------------------------------------------------------------- // Function in need of a redesign (legacy mess) // - RenderColorRectWithAlphaCheckerboard() @@ -4665,6 +4666,91 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight); } +// Add a resize grip using the rounded corner textures, if possible. +// Returns false if rendering could not be performed, true otherwise +// FIXME: Probably ok to move this to imgui_draw.cpp in 'Internal Render Helpers' section. +bool ImGui::RenderWindowResizeGrip(ImDrawList* draw_list, const ImVec2& corner, unsigned int rad, unsigned int overall_grip_size, ImDrawFlags flags, ImU32 col) +{ + // Texture path disabled by the draw list flags + // Texture path disabled for radius 0 which cause issues with the UV lookup below + const bool use_tex = (draw_list->Flags & ImDrawListFlags_RoundCornersUseTex) && (rad >= 1 && rad <= ImFontAtlasRoundCornersMaxSize); + if (use_tex == false) + return false; + + ImFontAtlas* atlas = draw_list->_Data->Font->ContainerAtlas; + IM_ASSERT(atlas->TexID == draw_list->_TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + IM_ASSERT(ImIsPowerOfTwo(flags)); // Only allow a single corner to be specified here. + IM_ASSERT_PARANOID((atlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners) == 0); + + // Calculate UVs for the three points we are interested in from the texture + // - 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)), + ImVec2(uvs.x, uvs.y), + ImVec2(uvs.z, uvs.w), + }; + + // 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 (flags & (ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight)) + { + in_y.y += rad; + out_y.y += overall_grip_size; + } + else if (flags & (ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight)) + { + in_y.y -= rad; + out_y.y -= overall_grip_size; + } + + if (flags & (ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomLeft)) + { + in_x.x += rad; + out_x.x += overall_grip_size; + } + else if (flags & (ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomRight)) + { + in_x.x -= rad; + out_x.x -= overall_grip_size; + } + + // 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_indices = 12; // Number of indices we are going to write + draw_list->PrimReserve(num_indices, num_verts); + + unsigned int idx = 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; + vtx_write_ptr[3].pos = in_x; vtx_write_ptr[3].uv = uv[1]; vtx_write_ptr[3].col = col; + vtx_write_ptr[4].pos = out_x; vtx_write_ptr[4].uv = uv[1]; vtx_write_ptr[4].col = col; + vtx_write_ptr[5].pos = out_y; vtx_write_ptr[5].uv = uv[1]; vtx_write_ptr[5].col = col; + + // Curved section + idx_write_ptr[0] = (ImDrawIdx)(idx); idx_write_ptr[1] = (ImDrawIdx)(idx + 1); idx_write_ptr[2] = (ImDrawIdx)(idx + 2); + idx_write_ptr[3] = (ImDrawIdx)(idx); idx_write_ptr[4] = (ImDrawIdx)(idx + 2); idx_write_ptr[5] = (ImDrawIdx)(idx + 3); + + // Outer section + idx_write_ptr[6] = (ImDrawIdx)(idx + 4); idx_write_ptr[7] = (ImDrawIdx)(idx + 3); idx_write_ptr[8] = (ImDrawIdx)(idx + 5); + idx_write_ptr[9] = (ImDrawIdx)(idx + 3); idx_write_ptr[10] = (ImDrawIdx)(idx + 5); idx_write_ptr[11] = (ImDrawIdx)(idx + 1); + + draw_list->_VtxWritePtr += num_verts; + draw_list->_VtxCurrentIdx += num_verts; + draw_list->_IdxWritePtr += num_indices; + + return true; +} + // Helper for ColorPicker4() // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. // Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. diff --git a/imgui_internal.h b/imgui_internal.h index 11f8e34f..df3a986b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2773,6 +2773,7 @@ namespace ImGui IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col); IMGUI_API void RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); + IMGUI_API bool RenderWindowResizeGrip(ImDrawList* draw_list, const ImVec2& corner, unsigned int rad, unsigned int overall_grip_size, ImDrawFlags flags, ImU32 col); IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding);