From 85f616877f0eb2effe1882e44c055b6ec510f07e Mon Sep 17 00:00:00 2001 From: tzSharing <90680948+tzSharing@users.noreply.github.com> Date: Wed, 27 Apr 2022 16:22:57 +0800 Subject: [PATCH] gg: fix gg.draw_rounded_rect_empty() graphical abnormalities and some optimizations (#14186) --- vlib/gg/draw.c.v | 227 ++++++++++++++++++++++++++++------------------- 1 file changed, 138 insertions(+), 89 deletions(-) diff --git a/vlib/gg/draw.c.v b/vlib/gg/draw.c.v index 1e4b588960..de4de1fd66 100644 --- a/vlib/gg/draw.c.v +++ b/vlib/gg/draw.c.v @@ -211,66 +211,111 @@ pub fn (ctx &Context) draw_rect_filled(x f32, y f32, w f32, h f32, c gx.Color) { sgl.end() } -// draw_rounded_rect_empty draws the outline of a rounded rectangle +// draw_rounded_rect_empty draws the outline of a rounded rectangle with a thickness of 1 px. // `x`,`y` is the top-left corner of the rectangle. // `w` is the width, `h` is the height. // `radius` is the radius of the corner-rounding in pixels. // `c` is the color of the outline. pub fn (ctx &Context) draw_rounded_rect_empty(x f32, y f32, w f32, h f32, radius f32, c gx.Color) { - mut theta := f32(0) - mut xx := f32(0) - mut yy := f32(0) - r := radius * ctx.scale - nx := x * ctx.scale - ny := y * ctx.scale + if w <= 0 || h <= 0 || radius < 0 { + return + } + if c.a != 255 { + sgl.load_pipeline(ctx.timage_pip) + } + sgl.c4b(c.r, c.g, c.b, c.a) + + mut new_radius := radius + if w >= h && radius > h / 2 { + new_radius = h / 2 + } else if radius > w / 2 { + new_radius = w / 2 + } + r := new_radius * ctx.scale + sx := x * ctx.scale // start point x + sy := y * ctx.scale width := w * ctx.scale height := h * ctx.scale - segments := 2 * math.pi * r - segdiv := segments / 4 - rb := 0 - lb := int(rb + segdiv) - lt := int(lb + segdiv) - rt := int(lt + segdiv) - sgl.c4b(c.r, c.g, c.b, c.a) + // circle center coordinates + ltx := sx + r + lty := sy + r + rtx := sx + width - r + rty := lty + rbx := rtx + rby := sy + height - r + lbx := ltx + lby := rby + + mut rad := f32(0) + mut dx := f32(0) + mut dy := f32(0) + + // left top quarter sgl.begin_line_strip() - // left top - lx := nx + r - ly := ny + r - theta_coeff := 2 * f32(math.pi) / segments - for i in lt .. rt { - theta = theta_coeff * f32(i) - xx = r * math.cosf(theta) - yy = r * math.sinf(theta) - sgl.v2f(xx + lx, yy + ly) + for i in 0 .. 31 { + if r == 0 { + break + } + rad = f32(math.radians(i * 3)) + dx = r * math.cosf(rad) + dy = r * math.sinf(rad) + sgl.v2f(ltx - dx, lty - dy) } - // right top - mut rx := nx + width - r - mut ry := ny + r - for i in rt .. int(segments) { - theta = theta_coeff * f32(i) - xx = r * math.cosf(theta) - yy = r * math.sinf(theta) - sgl.v2f(xx + rx, yy + ry) + sgl.end() + + // right top quarter + sgl.begin_line_strip() + for i in 0 .. 31 { + if r == 0 { + break + } + rad = f32(math.radians(i * 3)) + dx = r * math.cosf(rad) + dy = r * math.sinf(rad) + sgl.v2f(rtx + dx, rty - dy) } - // right bottom - mut rbx := rx - mut rby := ny + height - r - for i in rb .. lb { - theta = theta_coeff * f32(i) - xx = r * math.cosf(theta) - yy = r * math.sinf(theta) - sgl.v2f(xx + rbx, yy + rby) + sgl.end() + + // right bottom quarter + sgl.begin_line_strip() + for i in 0 .. 31 { + if r == 0 { + break + } + rad = f32(math.radians(i * 3)) + dx = r * math.cosf(rad) + dy = r * math.sinf(rad) + sgl.v2f(rbx + dx, rby + dy) } - // left bottom - mut lbx := lx - mut lby := ny + height - r - for i in lb .. lt { - theta = theta_coeff * f32(i) - xx = r * math.cosf(theta) - yy = r * math.sinf(theta) - sgl.v2f(xx + lbx, yy + lby) + sgl.end() + + // left bottom quarter + sgl.begin_line_strip() + for i in 0 .. 31 { + if r == 0 { + break + } + rad = f32(math.radians(i * 3)) + dx = r * math.cosf(rad) + dy = r * math.sinf(rad) + sgl.v2f(lbx - dx, lby + dy) } - sgl.v2f(lx + xx, ly) + sgl.end() + + // Currently don't use 'gg.draw_line()' directly, it will repeatedly execute '*ctx.scale'. + sgl.begin_lines() + // top + sgl.v2f(ltx, sy) + sgl.v2f(rtx, sy) + // right + sgl.v2f(rtx + r, rty) + sgl.v2f(rtx + r, rby) + // bottom + sgl.v2f(lbx, lby + r) + sgl.v2f(rbx, rby + r) + // left + sgl.v2f(sx, lty) + sgl.v2f(sx, lby) sgl.end() } @@ -280,87 +325,91 @@ pub fn (ctx &Context) draw_rounded_rect_empty(x f32, y f32, w f32, h f32, radius // `radius` is the radius of the corner-rounding in pixels. // `c` is the color of the filled. pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radius f32, c gx.Color) { - assert w > 0 && h > 0 && radius >= 0 + if w <= 0 || h <= 0 || radius < 0 { + return + } if c.a != 255 { sgl.load_pipeline(ctx.timage_pip) } sgl.c4b(c.r, c.g, c.b, c.a) - mut xx := f32(0) - mut yy := f32(0) - mut radians := f32(0) + mut new_radius := radius if w >= h && radius > h / 2 { new_radius = h / 2 } else if radius > w / 2 { new_radius = w / 2 } - r := new_radius * ctx.scale - nx := x * ctx.scale - ny := y * ctx.scale + sx := x * ctx.scale // start point x + sy := y * ctx.scale width := w * ctx.scale height := h * ctx.scale + // circle center coordinates + ltx := sx + r + lty := sy + r + rtx := sx + width - r + rty := lty + rbx := rtx + rby := sy + height - r + lbx := ltx + lby := rby + + mut rad := f32(0) + mut dx := f32(0) + mut dy := f32(0) // left top quarter sgl.begin_triangle_strip() - ltx := nx + r - lty := ny + r - for i in 0 .. 91 { + for i in 0 .. 31 { if r == 0 { break } - radians = f32(math.radians(i)) - xx = r * math.cosf(radians) - yy = r * math.sinf(radians) - sgl.v2f(ltx - xx, lty - yy) + rad = f32(math.radians(i * 3)) + dx = r * math.cosf(rad) + dy = r * math.sinf(rad) + sgl.v2f(ltx - dx, lty - dy) sgl.v2f(ltx, lty) } sgl.end() // right top quarter sgl.begin_triangle_strip() - rtx := nx + width - r - rty := ny + r - for i in 0 .. 91 { + for i in 0 .. 31 { if r == 0 { break } - radians = f32(math.radians(i)) - xx = r * math.cosf(radians) - yy = r * math.sinf(radians) - sgl.v2f(rtx + xx, rty - yy) + rad = f32(math.radians(i * 3)) + dx = r * math.cosf(rad) + dy = r * math.sinf(rad) + sgl.v2f(rtx + dx, rty - dy) sgl.v2f(rtx, rty) } sgl.end() // right bottom quarter sgl.begin_triangle_strip() - rbx := nx + width - r - rby := ny + height - r - for i in 0 .. 91 { + for i in 0 .. 31 { if r == 0 { break } - radians = f32(math.radians(i)) - xx = r * math.cosf(radians) - yy = r * math.sinf(radians) - sgl.v2f(rbx + xx, rby + yy) + rad = f32(math.radians(i * 3)) + dx = r * math.cosf(rad) + dy = r * math.sinf(rad) + sgl.v2f(rbx + dx, rby + dy) sgl.v2f(rbx, rby) } sgl.end() // left bottom quarter sgl.begin_triangle_strip() - lbx := nx + r - lby := ny + height - r - for i in 0 .. 91 { + for i in 0 .. 31 { if r == 0 { break } - radians = f32(math.radians(i)) - xx = r * math.cosf(radians) - yy = r * math.sinf(radians) - sgl.v2f(lbx - xx, lby + yy) + rad = f32(math.radians(i * 3)) + dx = r * math.cosf(rad) + dy = r * math.sinf(rad) + sgl.v2f(lbx - dx, lby + dy) sgl.v2f(lbx, lby) } sgl.end() @@ -368,24 +417,24 @@ pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radiu // Separate drawing is to prevent transparent color overlap // top rectangle sgl.begin_quads() - sgl.v2f(ltx, ny) - sgl.v2f(rtx, ny) + sgl.v2f(ltx, sy) + sgl.v2f(rtx, sy) sgl.v2f(rtx, rty) sgl.v2f(ltx, lty) sgl.end() // middle rectangle sgl.begin_quads() - sgl.v2f(nx, ny + r) + sgl.v2f(sx, lty) sgl.v2f(rtx + r, rty) sgl.v2f(rbx + r, rby) - sgl.v2f(nx, lby) + sgl.v2f(sx, lby) sgl.end() // bottom rectangle sgl.begin_quads() sgl.v2f(lbx, lby) sgl.v2f(rbx, rby) - sgl.v2f(rbx, ny + height) - sgl.v2f(lbx, ny + height) + sgl.v2f(rbx, rby + r) + sgl.v2f(lbx, rby + r) sgl.end() }