mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 17:05:38 +00:00
gpu,op/clip: implement stroked paths with round caps
Signed-off-by: Sebastien Binet <s@sbinet.org>
This commit is contained in:
committed by
Elias Naur
parent
ae256b5be8
commit
1106d90f11
@@ -28,6 +28,7 @@ import (
|
|||||||
|
|
||||||
"gioui.org/f32"
|
"gioui.org/f32"
|
||||||
"gioui.org/internal/ops"
|
"gioui.org/internal/ops"
|
||||||
|
"gioui.org/op"
|
||||||
"gioui.org/op/clip"
|
"gioui.org/op/clip"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,6 +46,10 @@ type strokeState struct {
|
|||||||
|
|
||||||
type strokeQuads []strokeQuad
|
type strokeQuads []strokeQuad
|
||||||
|
|
||||||
|
func (qs *strokeQuads) pen() f32.Point {
|
||||||
|
return (*qs)[len(*qs)-1].quad.To
|
||||||
|
}
|
||||||
|
|
||||||
func (qs *strokeQuads) lineTo(pt f32.Point) {
|
func (qs *strokeQuads) lineTo(pt f32.Point) {
|
||||||
end := (*qs)[len(*qs)-1].quad.To
|
end := (*qs)[len(*qs)-1].quad.To
|
||||||
*qs = append(*qs, strokeQuad{
|
*qs = append(*qs, strokeQuad{
|
||||||
@@ -56,6 +61,27 @@ func (qs *strokeQuads) lineTo(pt f32.Point) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (qs *strokeQuads) arc(f1, f2 f32.Point, angle float32) {
|
||||||
|
var (
|
||||||
|
p clip.Path
|
||||||
|
o = new(op.Ops)
|
||||||
|
)
|
||||||
|
p.Begin(o)
|
||||||
|
p.Move(qs.pen())
|
||||||
|
beg := len(o.Data())
|
||||||
|
p.Arc(f1, f2, angle)
|
||||||
|
end := len(o.Data())
|
||||||
|
raw := o.Data()[beg:end]
|
||||||
|
|
||||||
|
for qi := 0; len(raw) >= (ops.QuadSize + 4); qi++ {
|
||||||
|
quad := ops.DecodeQuad(raw[4:])
|
||||||
|
raw = raw[ops.QuadSize+4:]
|
||||||
|
*qs = append(*qs, strokeQuad{
|
||||||
|
quad: quad,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// split splits a slice of quads into slices of quads grouped
|
// split splits a slice of quads into slices of quads grouped
|
||||||
// by contours (ie: splitted at move-to boundaries).
|
// by contours (ie: splitted at move-to boundaries).
|
||||||
func (qs strokeQuads) split() []strokeQuads {
|
func (qs strokeQuads) split() []strokeQuads {
|
||||||
@@ -409,6 +435,8 @@ func strokePathCap(sty clip.StrokeStyle, qs *strokeQuads, hw float32, pivot, n0
|
|||||||
strokePathFlatCap(qs, hw, pivot, n0)
|
strokePathFlatCap(qs, hw, pivot, n0)
|
||||||
case clip.SquareCap:
|
case clip.SquareCap:
|
||||||
strokePathSquareCap(qs, hw, pivot, n0)
|
strokePathSquareCap(qs, hw, pivot, n0)
|
||||||
|
case clip.RoundCap:
|
||||||
|
strokePathRoundCap(qs, hw, pivot, n0)
|
||||||
default:
|
default:
|
||||||
panic("impossible")
|
panic("impossible")
|
||||||
}
|
}
|
||||||
@@ -433,3 +461,9 @@ func strokePathSquareCap(qs *strokeQuads, hw float32, pivot, n0 f32.Point) {
|
|||||||
qs.lineTo(corner2)
|
qs.lineTo(corner2)
|
||||||
qs.lineTo(end)
|
qs.lineTo(end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// strokePathRoundCap caps the start or end of a path with a round cap.
|
||||||
|
func strokePathRoundCap(qs *strokeQuads, hw float32, pivot, n0 f32.Point) {
|
||||||
|
c := pivot.Sub(qs.pen())
|
||||||
|
qs.arc(c, c, math.Pi)
|
||||||
|
}
|
||||||
|
|||||||
@@ -129,6 +129,32 @@ func TestStrokedPathBevelFlat(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStrokedPathBevelRound(t *testing.T) {
|
||||||
|
run(t, func(o *op.Ops) {
|
||||||
|
const width = 2.5
|
||||||
|
sty := clip.StrokeStyle{
|
||||||
|
Cap: clip.RoundCap,
|
||||||
|
}
|
||||||
|
|
||||||
|
p := new(clip.Path)
|
||||||
|
p.Begin(o)
|
||||||
|
p.Move(f32.Pt(10, 50))
|
||||||
|
p.Line(f32.Pt(10, 0))
|
||||||
|
p.Arc(f32.Pt(10, 0), f32.Pt(20, 0), math.Pi)
|
||||||
|
p.Line(f32.Pt(10, 0))
|
||||||
|
p.Line(f32.Pt(10, 10))
|
||||||
|
p.Arc(f32.Pt(0, 30), f32.Pt(0, 30), 2*math.Pi)
|
||||||
|
p.Line(f32.Pt(-20, 0))
|
||||||
|
p.Quad(f32.Pt(-10, -10), f32.Pt(-30, 30))
|
||||||
|
p.Stroke(width, sty).Add(o)
|
||||||
|
|
||||||
|
paint.Fill(o, colornames.Red)
|
||||||
|
}, func(r result) {
|
||||||
|
r.expect(0, 0, colornames.White)
|
||||||
|
r.expect(10, 50, colornames.Red)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestStrokedPathBevelSquare(t *testing.T) {
|
func TestStrokedPathBevelSquare(t *testing.T) {
|
||||||
run(t, func(o *op.Ops) {
|
run(t, func(o *op.Ops) {
|
||||||
const width = 2.5
|
const width = 2.5
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
@@ -20,4 +20,9 @@ const (
|
|||||||
// and left-hand sides of a stroked path with a half square of length
|
// and left-hand sides of a stroked path with a half square of length
|
||||||
// the stroked path's width.
|
// the stroked path's width.
|
||||||
SquareCap
|
SquareCap
|
||||||
|
|
||||||
|
// RoundCap caps stroked paths with a round cap, joining the right-hand and
|
||||||
|
// left-hand sides of a stroked path with a half disc of diameter the
|
||||||
|
// stroked path's width.
|
||||||
|
RoundCap
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user