mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
gg: improve arc/slice drawing (#15856)
This commit is contained in:
parent
58f7342465
commit
089e89f865
167
examples/gg/arcs_and_slices.v
Normal file
167
examples/gg/arcs_and_slices.v
Normal file
@ -0,0 +1,167 @@
|
||||
module main
|
||||
|
||||
import gg
|
||||
import gx
|
||||
import math
|
||||
|
||||
const (
|
||||
win_width = 700
|
||||
win_height = 800
|
||||
bg_color = gx.white
|
||||
colour = gx.black
|
||||
)
|
||||
|
||||
enum Selection {
|
||||
segs = 0
|
||||
len
|
||||
}
|
||||
|
||||
struct App {
|
||||
mut:
|
||||
gg &gg.Context = unsafe { nil }
|
||||
mouse struct {
|
||||
mut:
|
||||
x f32
|
||||
y f32
|
||||
}
|
||||
|
||||
sel Selection
|
||||
segs int = 8
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut app := &App{
|
||||
gg: 0
|
||||
}
|
||||
app.gg = gg.new_context(
|
||||
width: win_width
|
||||
height: win_height
|
||||
create_window: true
|
||||
window_title: 'Arcs and Slices'
|
||||
user_data: app
|
||||
bg_color: bg_color
|
||||
frame_fn: on_frame
|
||||
event_fn: on_event
|
||||
)
|
||||
app.gg.run()
|
||||
}
|
||||
|
||||
fn on_frame(mut app App) {
|
||||
app.gg.begin()
|
||||
|
||||
start := math.tau * app.mouse.y / (win_width * app.gg.scale)
|
||||
end := math.tau * app.mouse.x / (win_width * app.gg.scale)
|
||||
|
||||
segs := if app.sel == .segs { '[$app.segs]' } else { '$app.segs' }
|
||||
app.gg.draw_text_def(10, 10, 'Segments: $segs')
|
||||
app.gg.draw_text_def(250, 10, 'Drawing Angles (radians)')
|
||||
app.gg.draw_text_def(200, 26, 'Start: $start°')
|
||||
app.gg.draw_text_def(350, 26, 'End: $end°')
|
||||
mut x, mut y := 0, -80
|
||||
|
||||
y += 150
|
||||
x = 20
|
||||
app.gg.draw_text_def(10, y + 40, 'slice')
|
||||
x += 150
|
||||
app.gg.draw_slice_empty(x, y + 60, 50, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=50 empty')
|
||||
x += 150
|
||||
app.gg.draw_slice_empty(x, y + 60, 0, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=0 empty')
|
||||
x += 150
|
||||
app.gg.draw_slice_filled(x, y + 60, 50, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=50 filled')
|
||||
x += 150
|
||||
app.gg.draw_slice_filled(x, y + 60, 0, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=0 filled')
|
||||
|
||||
y += 150
|
||||
x = 20
|
||||
app.gg.draw_text_def(10, y + 40, 'arc_empty')
|
||||
x += 150
|
||||
app.gg.draw_arc_empty(x, y + 60, 30, 20, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=[30,50]')
|
||||
x += 150
|
||||
app.gg.draw_arc_empty(x, y + 60, -10, 60, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=[-10,50]')
|
||||
x += 150
|
||||
app.gg.draw_arc_empty(x, y + 60, 50, 0, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=[50,50]')
|
||||
x += 150
|
||||
app.gg.draw_arc_empty(x, y + 60, 0, 0, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=[0,0]')
|
||||
|
||||
y += 150
|
||||
x = 20
|
||||
app.gg.draw_text_def(10, y + 40, 'arc_filled')
|
||||
x += 150
|
||||
app.gg.draw_arc_filled(x, y + 60, 30, 20, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=[30,50]')
|
||||
x += 150
|
||||
app.gg.draw_arc_filled(x, y + 60, -10, 60, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=[-10,50]')
|
||||
x += 150
|
||||
app.gg.draw_arc_filled(x, y + 60, 50, 0, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=[50,50]')
|
||||
x += 150
|
||||
app.gg.draw_arc_filled(x, y + 60, 0, 0, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=[0,0]')
|
||||
|
||||
y += 150
|
||||
x = 20
|
||||
app.gg.draw_text_def(10, y + 40, 'arc_line')
|
||||
x += 150
|
||||
app.gg.draw_arc_line(x, y + 60, 50, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=50')
|
||||
x += 150
|
||||
app.gg.draw_arc_line(x, y + 60, 0, start, end, app.segs, colour)
|
||||
app.gg.draw_text_def(x - 50, y + 120, 'r=0')
|
||||
|
||||
y += 150
|
||||
app.gg.draw_text_def(10, y + 20, 'Use arrow keys to increase/decrease number of segments.')
|
||||
app.gg.draw_text_def(10, y + 36, 'Use the mouse to adjust the start/end angles, in radians. Mouse position (0,0) is at the top-left of the window.')
|
||||
app.gg.draw_text_def(10, y + 52, 'Note: because y=0 is at the top of the screen and not the bottom, angle=0 is at the bottom of an arc, not the top!')
|
||||
app.gg.draw_text_def(10, y + 68, 'Compared to a graph, where y=0 is at the bottom, arcs therefore appear y-flipped.')
|
||||
|
||||
app.gg.end()
|
||||
}
|
||||
|
||||
fn on_event(e &gg.Event, mut app App) {
|
||||
match e.typ {
|
||||
.key_down {
|
||||
match e.key_code {
|
||||
.escape {
|
||||
app.gg.quit()
|
||||
}
|
||||
.up {
|
||||
app.sel = Selection(math.max(0, int(app.sel) - 1))
|
||||
}
|
||||
.down {
|
||||
app.sel = Selection(math.min(int(Selection.len) - 1, int(app.sel) + 1))
|
||||
}
|
||||
.left {
|
||||
match app.sel {
|
||||
.segs {
|
||||
app.segs = math.max(1, app.segs / 2)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
.right {
|
||||
match app.sel {
|
||||
.segs {
|
||||
app.segs = math.min(64, app.segs * 2)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
.mouse_move {
|
||||
app.mouse.x = e.mouse_x
|
||||
app.mouse.y = e.mouse_y
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
350
vlib/gg/draw.c.v
350
vlib/gg/draw.c.v
@ -17,8 +17,8 @@ pub fn (ctx &Context) draw_pixel(x f32, y f32, c gx.Color) {
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_points()
|
||||
sgl.v2f(x * ctx.scale, y * ctx.scale)
|
||||
sgl.end()
|
||||
@ -31,14 +31,16 @@ pub fn (ctx &Context) draw_pixel(x f32, y f32, c gx.Color) {
|
||||
// functions like `draw_rect_empty` or `draw_triangle_empty` etc.
|
||||
[direct_array_access; inline]
|
||||
pub fn (ctx &Context) draw_pixels(points []f32, c gx.Color) {
|
||||
assert points.len % 2 == 0
|
||||
if points.len % 2 != 0 {
|
||||
return
|
||||
}
|
||||
len := points.len / 2
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_points()
|
||||
for i in 0 .. len {
|
||||
x, y := points[i * 2], points[i * 2 + 1]
|
||||
@ -63,10 +65,12 @@ pub fn (ctx &Context) draw_line(x f32, y f32, x2 f32, y2 f32, c gx.Color) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_line_strip()
|
||||
sgl.v2f(x * ctx.scale, y * ctx.scale)
|
||||
sgl.v2f(x2 * ctx.scale, y2 * ctx.scale)
|
||||
@ -127,9 +131,10 @@ pub fn (ctx &Context) draw_line_with_config(x f32, y f32, x2 f32, y2 f32, config
|
||||
// draw_poly_empty draws the outline of a polygon, given an array of points, and a color.
|
||||
// NOTE that the points must be given in clockwise winding order.
|
||||
pub fn (ctx &Context) draw_poly_empty(points []f32, c gx.Color) {
|
||||
assert points.len % 2 == 0
|
||||
len := points.len / 2
|
||||
assert len >= 3
|
||||
if points.len % 2 != 0 || len < 3 {
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
@ -148,9 +153,10 @@ pub fn (ctx &Context) draw_poly_empty(points []f32, c gx.Color) {
|
||||
// NOTE that the points must be given in clockwise winding order.
|
||||
// The contents of the `points` array should be `x` and `y` coordinate pairs.
|
||||
pub fn (ctx &Context) draw_convex_poly(points []f32, c gx.Color) {
|
||||
assert points.len % 2 == 0
|
||||
len := points.len / 2
|
||||
assert len >= 3
|
||||
if points.len % 2 != 0 || len < 3 {
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
@ -160,14 +166,13 @@ pub fn (ctx &Context) draw_convex_poly(points []f32, c gx.Color) {
|
||||
sgl.begin_triangle_strip()
|
||||
x0 := points[0] * ctx.scale
|
||||
y0 := points[1] * ctx.scale
|
||||
for i in 1 .. (len / 2 + 1) {
|
||||
sgl.v2f(x0, y0)
|
||||
sgl.v2f(points[i * 4 - 2] * ctx.scale, points[i * 4 - 1] * ctx.scale)
|
||||
sgl.v2f(points[i * 4] * ctx.scale, points[i * 4 + 1] * ctx.scale)
|
||||
}
|
||||
|
||||
if len % 2 == 0 {
|
||||
sgl.v2f(points[2 * len - 2] * ctx.scale, points[2 * len - 1] * ctx.scale)
|
||||
for i in 1 .. len {
|
||||
x := points[i * 2] * ctx.scale
|
||||
y := points[i * 2 + 1] * ctx.scale
|
||||
sgl.v2f(x, y)
|
||||
if i & 0 == 0 {
|
||||
sgl.v2f(x0, y0)
|
||||
}
|
||||
}
|
||||
sgl.end()
|
||||
}
|
||||
@ -180,6 +185,7 @@ pub fn (ctx &Context) draw_rect_empty(x f32, y f32, w f32, h f32, c gx.Color) {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_line_strip()
|
||||
sgl.v2f(x * ctx.scale, y * ctx.scale)
|
||||
sgl.v2f((x + w) * ctx.scale, y * ctx.scale)
|
||||
@ -199,10 +205,12 @@ pub fn (ctx &Context) draw_rect_filled(x f32, y f32, w f32, h f32, c gx.Color) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_quads()
|
||||
sgl.v2f(x * ctx.scale, y * ctx.scale)
|
||||
sgl.v2f((x + w) * ctx.scale, y * ctx.scale)
|
||||
@ -220,6 +228,7 @@ pub fn (ctx &Context) draw_rounded_rect_empty(x f32, y f32, w f32, h f32, radius
|
||||
if w <= 0 || h <= 0 || radius < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
@ -318,6 +327,7 @@ pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radiu
|
||||
if w <= 0 || h <= 0 || radius < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
@ -427,8 +437,8 @@ pub fn (ctx &Context) draw_triangle_empty(x f32, y f32, x2 f32, y2 f32, x3 f32,
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_line_strip()
|
||||
sgl.v2f(x * ctx.scale, y * ctx.scale)
|
||||
sgl.v2f(x2 * ctx.scale, y2 * ctx.scale)
|
||||
@ -447,6 +457,7 @@ pub fn (ctx &Context) draw_triangle_filled(x f32, y f32, x2 f32, y2 f32, x3 f32,
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_triangles()
|
||||
sgl.v2f(x * ctx.scale, y * ctx.scale)
|
||||
sgl.v2f(x2 * ctx.scale, y2 * ctx.scale)
|
||||
@ -478,14 +489,14 @@ const small_circle_segments = [0, 2, 4, 6, 6, 8, 8, 13, 10, 18, 12, 12, 10, 13,
|
||||
|
||||
[direct_array_access]
|
||||
fn radius_to_segments(r f32) int {
|
||||
if r < 30.0 {
|
||||
if r < 30 {
|
||||
ir := int(math.ceil(r))
|
||||
if ir > 0 && ir < gg.small_circle_segments.len {
|
||||
return gg.small_circle_segments[ir]
|
||||
}
|
||||
return ir
|
||||
}
|
||||
return int(math.ceil(2 * math.pi * r / 8))
|
||||
return int(math.ceil(math.tau * r / 8))
|
||||
}
|
||||
|
||||
// draw_circle_empty draws the outline of a circle.
|
||||
@ -496,19 +507,19 @@ pub fn (ctx &Context) draw_circle_empty(x f32, y f32, radius f32, c gx.Color) {
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
nr := radius * ctx.scale
|
||||
mut theta := f32(0)
|
||||
mut xx := f32(0)
|
||||
mut yy := f32(0)
|
||||
|
||||
segments := radius_to_segments(radius)
|
||||
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
sgl.begin_line_strip()
|
||||
for i := 0; i < segments + 1; i++ {
|
||||
theta = 2.0 * f32(math.pi) * f32(i) / f32(segments)
|
||||
theta = f32(math.tau) * f32(i) / f32(segments)
|
||||
xx = nr * math.cosf(theta)
|
||||
yy = nr * math.sinf(theta)
|
||||
sgl.v2f(xx + nx, yy + ny)
|
||||
@ -534,23 +545,29 @@ pub fn (ctx &Context) draw_circle_filled(x f32, y f32, radius f32, c gx.Color) {
|
||||
// draw_polygon_filled draws a filled polygon.
|
||||
// `x`,`y` defines the center of the polygon.
|
||||
// `size` defines the size of the polygon.
|
||||
// `edge` defines edge number of the polygon.
|
||||
// `edges` defines number of edges in the polygon.
|
||||
// `rotation` defines rotation of the polygon.
|
||||
// `c` is the fill color.
|
||||
pub fn (ctx &Context) draw_polygon_filled(x f32, y f32, size f32, edge int, rotation f32, c gx.Color) {
|
||||
pub fn (ctx &Context) draw_polygon_filled(x f32, y f32, size f32, edges int, rotation f32, c gx.Color) {
|
||||
if edges <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
nr := size * ctx.scale
|
||||
mut theta := f32(0)
|
||||
mut xx := f32(0)
|
||||
mut yy := f32(0)
|
||||
|
||||
sgl.begin_triangle_strip()
|
||||
for i := 0; i < edge + 1; i++ {
|
||||
theta = 2.0 * f32(math.pi) * f32(i) / f32(edge)
|
||||
for i := 0; i < edges + 1; i++ {
|
||||
theta = f32(math.tau) * f32(i) / f32(edges)
|
||||
xx = nr * math.cosf(theta + f32(math.radians(rotation)))
|
||||
yy = nr * math.sinf(theta + f32(math.radians(rotation)))
|
||||
sgl.v2f(xx + nx, yy + ny)
|
||||
@ -574,6 +591,10 @@ pub fn (ctx &Context) draw_circle_with_segments(x f32, y f32, radius f32, segmen
|
||||
// `segments` affects how smooth/round the circle is.
|
||||
// `c` is the color of the outline.
|
||||
pub fn (ctx &Context) draw_circle_line(x f32, y f32, radius int, segments int, c gx.Color) {
|
||||
if segments <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
$if macos {
|
||||
if ctx.native_rendering {
|
||||
C.darwin_draw_circle(x - radius + 1, ctx.height - (y + radius + 3), radius,
|
||||
@ -581,19 +602,22 @@ pub fn (ctx &Context) draw_circle_line(x f32, y f32, radius int, segments int, c
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
nr := radius * ctx.scale
|
||||
mut theta := f32(0)
|
||||
mut xx := f32(0)
|
||||
mut yy := f32(0)
|
||||
|
||||
sgl.begin_line_strip()
|
||||
for i := 0; i < segments + 1; i++ {
|
||||
theta = 2.0 * f32(math.pi) * f32(i) / f32(segments)
|
||||
theta = f32(math.tau) * f32(i) / f32(segments)
|
||||
xx = nr * math.cosf(theta)
|
||||
yy = nr * math.sinf(theta)
|
||||
sgl.v2f(xx + nx, yy + ny)
|
||||
@ -602,26 +626,28 @@ pub fn (ctx &Context) draw_circle_line(x f32, y f32, radius int, segments int, c
|
||||
}
|
||||
|
||||
// draw_slice_empty draws the outline of a circle slice/pie
|
||||
pub fn (ctx &Context) draw_slice_empty(x f32, y f32, outer_radius f32, start_angle f32, end_angle f32, segments int, c gx.Color) {
|
||||
pub fn (ctx &Context) draw_slice_empty(x f32, y f32, radius f32, start_angle f32, end_angle f32, segments int, c gx.Color) {
|
||||
if segments <= 0 || radius <= 0 {
|
||||
return
|
||||
}
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
theta := f32(end_angle / f32(segments))
|
||||
tan_factor := math.tanf(theta)
|
||||
rad_factor := math.cosf(theta)
|
||||
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
mut xx := outer_radius * math.cosf(start_angle)
|
||||
mut yy := outer_radius * math.sinf(start_angle)
|
||||
theta := f32(end_angle - start_angle) / f32(segments)
|
||||
tan_factor := math.tanf(theta)
|
||||
rad_factor := math.cosf(theta)
|
||||
mut xx := radius * ctx.scale * math.sinf(start_angle)
|
||||
mut yy := radius * ctx.scale * math.cosf(start_angle)
|
||||
|
||||
sgl.begin_line_strip()
|
||||
sgl.v2f(nx, ny)
|
||||
for i := 0; i < segments + 1; i++ {
|
||||
sgl.v2f(xx + nx, yy + ny)
|
||||
tx := -yy
|
||||
ty := xx
|
||||
xx += tx * tan_factor
|
||||
yy += ty * tan_factor
|
||||
xx, yy = xx + yy * tan_factor, yy - xx * tan_factor
|
||||
xx *= rad_factor
|
||||
yy *= rad_factor
|
||||
}
|
||||
@ -632,32 +658,88 @@ pub fn (ctx &Context) draw_slice_empty(x f32, y f32, outer_radius f32, start_ang
|
||||
// draw_slice_filled draws a filled circle slice/pie
|
||||
// `x`,`y` defines the end point of the slice (center of the circle that the slice is part of).
|
||||
// `radius` defines the radius ("length") of the slice.
|
||||
// `start_angle` is the radians at which the slice starts.
|
||||
// `end_angle` is the radians at which the slice ends.
|
||||
// `start_angle` is the angle in radians at which the slice starts.
|
||||
// `end_angle` is the angle in radians at which the slice ends.
|
||||
// `segments` affects how smooth/round the slice is.
|
||||
// `c` is the fill color.
|
||||
pub fn (ctx &Context) draw_slice_filled(x f32, y f32, radius f32, start_angle f32, end_angle f32, segments int, c gx.Color) {
|
||||
if segments <= 0 || radius < 0 {
|
||||
return
|
||||
}
|
||||
if start_angle == end_angle {
|
||||
ctx.draw_slice_empty(x, y, radius, start_angle, end_angle, 1, c)
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
theta := f32(end_angle / f32(segments))
|
||||
theta := f32(end_angle - start_angle) / f32(segments)
|
||||
tan_factor := math.tanf(theta)
|
||||
rad_factor := math.cosf(theta)
|
||||
mut xx := radius * math.cosf(start_angle)
|
||||
mut yy := radius * math.sinf(start_angle)
|
||||
mut xx := radius * ctx.scale * math.sinf(start_angle)
|
||||
mut yy := radius * ctx.scale * math.cosf(start_angle)
|
||||
|
||||
sgl.begin_triangle_strip()
|
||||
for i := 0; i < segments + 1; i++ {
|
||||
sgl.v2f(xx + nx, yy + ny)
|
||||
sgl.v2f(nx, ny)
|
||||
tx := -yy
|
||||
ty := xx
|
||||
xx += tx * tan_factor
|
||||
yy += ty * tan_factor
|
||||
sgl.v2f(xx + nx, yy + ny)
|
||||
for i := 0; i < segments; i++ {
|
||||
xx, yy = xx + yy * tan_factor, yy - xx * tan_factor
|
||||
xx *= rad_factor
|
||||
yy *= rad_factor
|
||||
sgl.v2f(xx + nx, yy + ny)
|
||||
if i & 1 == 0 {
|
||||
sgl.v2f(nx, ny)
|
||||
}
|
||||
}
|
||||
sgl.end()
|
||||
}
|
||||
|
||||
// draw_arc_line draws a line arc.
|
||||
// `x`,`y` defines the end point of the arc (center of the circle that the arc is part of).
|
||||
// `radius` defines the radius of the arc (length from the center point where the arc is drawn).
|
||||
// `start_angle` is the angle in radians at which the arc starts.
|
||||
// `end_angle` is the angle in radians at which the arc ends.
|
||||
// `segments` affects how smooth/round the arc is.
|
||||
// `c` is the color of the arc/outline.
|
||||
pub fn (ctx Context) draw_arc_line(x f32, y f32, radius f32, start_angle f32, end_angle f32, segments int, c gx.Color) {
|
||||
if segments <= 0 || radius < 0 {
|
||||
return
|
||||
}
|
||||
if radius == 0 {
|
||||
ctx.draw_pixel(x, y, c)
|
||||
return
|
||||
}
|
||||
if start_angle == end_angle {
|
||||
xx := x + radius * math.sinf(start_angle)
|
||||
yy := y + radius * math.cosf(start_angle)
|
||||
ctx.draw_pixel(xx, yy, c)
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
theta := f32(end_angle - start_angle) / f32(segments)
|
||||
tan_factor := math.tanf(theta)
|
||||
rad_factor := math.cosf(theta)
|
||||
mut xx := radius * ctx.scale * math.sinf(start_angle)
|
||||
mut yy := radius * ctx.scale * math.cosf(start_angle)
|
||||
|
||||
sgl.begin_line_strip()
|
||||
sgl.v2f(nx + xx, ny + yy)
|
||||
for i := 0; i < segments; i++ {
|
||||
xx, yy = xx + yy * tan_factor, yy - xx * tan_factor
|
||||
xx *= rad_factor
|
||||
yy *= rad_factor
|
||||
sgl.v2f(nx + xx, ny + yy)
|
||||
}
|
||||
sgl.end()
|
||||
}
|
||||
@ -666,66 +748,62 @@ pub fn (ctx &Context) draw_slice_filled(x f32, y f32, radius f32, start_angle f3
|
||||
// `x`,`y` defines the end point of the arc (center of the circle that the arc is part of).
|
||||
// `inner_radius` defines the radius of the arc (length from the center point where the arc is drawn).
|
||||
// `thickness` defines how wide the arc is drawn.
|
||||
// `start_angle` is the radians at which the arc starts.
|
||||
// `end_angle` is the radians at which the arc ends.
|
||||
// `start_angle` is the angle in radians at which the arc starts.
|
||||
// `end_angle` is the angle in radians at which the arc ends.
|
||||
// `segments` affects how smooth/round the arc is.
|
||||
// `c` is the color of the arc/outline.
|
||||
// `c` is the color of the arc outline.
|
||||
pub fn (ctx &Context) draw_arc_empty(x f32, y f32, inner_radius f32, thickness f32, start_angle f32, end_angle f32, segments int, c gx.Color) {
|
||||
if start_angle == end_angle || inner_radius <= 0.0 {
|
||||
outer_radius := inner_radius + thickness
|
||||
if segments <= 0 || outer_radius < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if inner_radius <= 0 {
|
||||
ctx.draw_slice_empty(x, y, outer_radius, start_angle, end_angle, segments, c)
|
||||
return
|
||||
}
|
||||
if inner_radius == outer_radius {
|
||||
ctx.draw_arc_line(x, y, outer_radius, start_angle, end_angle, segments, c)
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
|
||||
mut a1 := start_angle
|
||||
mut a2 := end_angle
|
||||
|
||||
if a2 < a1 {
|
||||
a1, a2 = a2, a1
|
||||
}
|
||||
|
||||
if inner_radius <= 0.0 {
|
||||
ctx.draw_slice_empty(x, y, int(thickness), a1, a2, segments, c)
|
||||
return
|
||||
}
|
||||
|
||||
outer_radius := inner_radius + thickness
|
||||
mut step_length := (a2 - a1) / f32(segments)
|
||||
mut angle := a1
|
||||
|
||||
sgl.begin_line_strip()
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
// Outer circle
|
||||
for _ in 0 .. segments {
|
||||
msa := f32(math.sin(angle))
|
||||
mca := f32(math.cos(angle))
|
||||
ms := f32(math.sin(angle + step_length))
|
||||
mc := f32(math.cos(angle + step_length))
|
||||
sgl.v2f(x + msa * outer_radius, y + mca * outer_radius)
|
||||
sgl.v2f(x + ms * outer_radius, y + mc * outer_radius)
|
||||
angle += step_length
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
theta := f32(end_angle - start_angle) / f32(segments)
|
||||
tan_factor := math.tanf(theta)
|
||||
rad_factor := math.cosf(theta)
|
||||
|
||||
sgl.begin_line_strip()
|
||||
|
||||
// outer
|
||||
mut xx := outer_radius * ctx.scale * math.sinf(start_angle)
|
||||
mut yy := outer_radius * ctx.scale * math.cosf(start_angle)
|
||||
sxx, syy := xx, yy
|
||||
sgl.v2f(nx + xx, ny + yy)
|
||||
for i := 0; i < segments; i++ {
|
||||
xx, yy = xx + yy * tan_factor, yy - xx * tan_factor
|
||||
xx *= rad_factor
|
||||
yy *= rad_factor
|
||||
sgl.v2f(nx + xx, ny + yy)
|
||||
}
|
||||
|
||||
// Inner circle
|
||||
for _ in 0 .. segments {
|
||||
msa := f32(math.sin(angle))
|
||||
mca := f32(math.cos(angle))
|
||||
msb := f32(math.sin(angle - step_length))
|
||||
mcb := f32(math.cos(angle - step_length))
|
||||
sgl.v2f(x + msa * inner_radius, y + mca * inner_radius)
|
||||
sgl.v2f(x + msb * inner_radius, y + mcb * inner_radius)
|
||||
|
||||
angle -= step_length
|
||||
// inner
|
||||
xx = inner_radius * ctx.scale * math.sinf(end_angle)
|
||||
yy = inner_radius * ctx.scale * math.cosf(end_angle)
|
||||
sgl.v2f(nx + xx, ny + yy)
|
||||
for i := 0; i < segments; i++ {
|
||||
xx, yy = xx - yy * tan_factor, yy + xx * tan_factor
|
||||
xx *= rad_factor
|
||||
yy *= rad_factor
|
||||
sgl.v2f(nx + xx, ny + yy)
|
||||
}
|
||||
|
||||
// Closing end
|
||||
msa := f32(math.sin(angle))
|
||||
mca := f32(math.cos(angle))
|
||||
sgl.v2f(x + msa * inner_radius, y + mca * inner_radius)
|
||||
sgl.v2f(x + msa * outer_radius, y + mca * outer_radius)
|
||||
sgl.v2f(nx + sxx, ny + syy)
|
||||
sgl.end()
|
||||
}
|
||||
|
||||
@ -733,48 +811,58 @@ pub fn (ctx &Context) draw_arc_empty(x f32, y f32, inner_radius f32, thickness f
|
||||
// `x`,`y` defines the central point of the arc (center of the circle that the arc is part of).
|
||||
// `inner_radius` defines the radius of the arc (length from the center point where the arc is drawn).
|
||||
// `thickness` defines how wide the arc is drawn.
|
||||
// `start_angle` is the radians at which the arc starts.
|
||||
// `end_angle` is the radians at which the arc ends.
|
||||
// `start_angle` is the angle in radians at which the arc starts.
|
||||
// `end_angle` is the angle in radians at which the arc ends.
|
||||
// `segments` affects how smooth/round the arc is.
|
||||
// `c` is the fill color of the arc.
|
||||
pub fn (ctx &Context) draw_arc_filled(x f32, y f32, inner_radius f32, thickness f32, start_angle f32, end_angle f32, segments int, c gx.Color) {
|
||||
if start_angle == end_angle || inner_radius <= 0.0 {
|
||||
outer_radius := inner_radius + thickness
|
||||
if segments <= 0 || outer_radius < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if inner_radius <= 0 {
|
||||
ctx.draw_slice_filled(x, y, outer_radius, start_angle, end_angle, segments, c)
|
||||
return
|
||||
}
|
||||
if inner_radius == outer_radius {
|
||||
ctx.draw_arc_line(x, y, outer_radius, start_angle, end_angle, segments, c)
|
||||
return
|
||||
}
|
||||
if start_angle == end_angle {
|
||||
ctx.draw_arc_empty(x, y, inner_radius, thickness, start_angle, end_angle, 1, c)
|
||||
return
|
||||
}
|
||||
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
|
||||
mut a1 := start_angle
|
||||
mut a2 := end_angle
|
||||
|
||||
if a2 < a1 {
|
||||
a1, a2 = a2, a1
|
||||
}
|
||||
|
||||
if inner_radius <= 0.0 {
|
||||
ctx.draw_slice_filled(x, y, int(thickness), a1, a2, segments, c)
|
||||
}
|
||||
|
||||
outer_radius := inner_radius + thickness
|
||||
mut step_length := (a2 - a1) / f32(segments)
|
||||
mut angle := a1
|
||||
|
||||
sgl.begin_quads()
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
for _ in 0 .. segments {
|
||||
msa := f32(math.sin(angle))
|
||||
mca := f32(math.cos(angle))
|
||||
sgl.v2f(x + msa * inner_radius, y + mca * inner_radius)
|
||||
sgl.v2f(x + msa * outer_radius, y + mca * outer_radius)
|
||||
|
||||
ms := f32(math.sin(angle + step_length))
|
||||
mc := f32(math.cos(angle + step_length))
|
||||
sgl.v2f(x + ms * outer_radius, y + mc * outer_radius)
|
||||
sgl.v2f(x + ms * inner_radius, y + mc * inner_radius)
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
theta := f32(end_angle - start_angle) / f32(segments)
|
||||
tan_factor := math.tanf(theta)
|
||||
rad_factor := math.cosf(theta)
|
||||
mut ix := ctx.scale * math.sinf(start_angle)
|
||||
mut iy := ctx.scale * math.cosf(start_angle)
|
||||
mut ox := outer_radius * ix
|
||||
mut oy := outer_radius * iy
|
||||
ix *= inner_radius
|
||||
iy *= inner_radius
|
||||
|
||||
angle += step_length
|
||||
sgl.begin_triangle_strip()
|
||||
sgl.v2f(nx + ix, ny + iy)
|
||||
sgl.v2f(nx + ox, ny + oy)
|
||||
for i := 0; i < segments; i++ {
|
||||
ix, iy = ix + iy * tan_factor, iy - ix * tan_factor
|
||||
ix *= rad_factor
|
||||
iy *= rad_factor
|
||||
sgl.v2f(nx + ix, ny + iy)
|
||||
ox, oy = ox + oy * tan_factor, oy - ox * tan_factor
|
||||
ox *= rad_factor
|
||||
oy *= rad_factor
|
||||
sgl.v2f(nx + ox, ny + oy)
|
||||
}
|
||||
sgl.end()
|
||||
}
|
||||
@ -788,8 +876,8 @@ pub fn (ctx &Context) draw_ellipse_empty(x f32, y f32, rw f32, rh f32, c gx.Colo
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_line_strip()
|
||||
for i := 0; i < 360; i += 10 {
|
||||
sgl.v2f(x + math.sinf(f32(math.radians(i))) * rw, y + math.cosf(f32(math.radians(i))) * rh)
|
||||
@ -808,8 +896,8 @@ pub fn (ctx &Context) draw_ellipse_filled(x f32, y f32, rw f32, rh f32, c gx.Col
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
|
||||
sgl.begin_triangle_strip()
|
||||
for i := 0; i < 360; i += 10 {
|
||||
sgl.v2f(x, y)
|
||||
@ -834,9 +922,9 @@ pub fn (ctx &Context) draw_cubic_bezier(points []f32, c gx.Color) {
|
||||
// The four points is provided as one `points` array which contains a stream of point pairs (x and y coordinates).
|
||||
// Thus a cubic Bézier could be declared as: `points := [x1, y1, control_x1, control_y1, control_x2, control_y2, x2, y2]`.
|
||||
pub fn (ctx &Context) draw_cubic_bezier_in_steps(points []f32, steps u32, c gx.Color) {
|
||||
assert steps > 0
|
||||
assert points.len == 8
|
||||
|
||||
if steps <= 0 || points.len != 8 {
|
||||
return
|
||||
}
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
@ -852,9 +940,9 @@ pub fn (ctx &Context) draw_cubic_bezier_in_steps(points []f32, steps u32, c gx.C
|
||||
|
||||
// The constant 3 is actually points.len() - 1;
|
||||
|
||||
step := f32(1.0) / steps
|
||||
step := f32(1) / steps
|
||||
sgl.v2f(p1_x * ctx.scale, p1_y * ctx.scale)
|
||||
for u := f32(0.0); u <= f32(1.0); u += step {
|
||||
for u := f32(0); u <= f32(1); u += step {
|
||||
pow_2_u := u * u
|
||||
pow_3_u := pow_2_u * u
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user