Files
gio-patched/gpu/clip.go
T
Elias Naur 8c8d1dc16f internal/stroke,gpu: create internal package for stroke to path conversion
Complex strokes are not yet supported in either of the current renderers,
so they are converted to filled outlines in package gpu.

We're about to move that complexity up to the op/clip package, so we're
going to need the converter available from outside package gpu. This
change extracts the conversion code and related types to the separate,
internal package stroke.

No functional changes; a follow-up moves the stroke conversion.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-23 12:35:41 +01:00

98 lines
2.2 KiB
Go

package gpu
import (
"gioui.org/f32"
"gioui.org/internal/stroke"
)
type quadSplitter struct {
bounds f32.Rectangle
contour uint32
d *drawOps
}
func encodeQuadTo(data []byte, meta uint32, from, ctrl, to f32.Point) {
// NW.
encodeVertex(data, meta, -1, 1, from, ctrl, to)
// NE.
encodeVertex(data[vertStride:], meta, 1, 1, from, ctrl, to)
// SW.
encodeVertex(data[vertStride*2:], meta, -1, -1, from, ctrl, to)
// SE.
encodeVertex(data[vertStride*3:], meta, 1, -1, from, ctrl, to)
}
func encodeVertex(data []byte, meta uint32, cornerx, cornery int16, from, ctrl, to f32.Point) {
var corner float32
if cornerx == 1 {
corner += .5
}
if cornery == 1 {
corner += .25
}
v := vertex{
Corner: corner,
FromX: from.X,
FromY: from.Y,
CtrlX: ctrl.X,
CtrlY: ctrl.Y,
ToX: to.X,
ToY: to.Y,
}
v.encode(data, meta)
}
func (qs *quadSplitter) encodeQuadTo(from, ctrl, to f32.Point) {
data := qs.d.writeVertCache(vertStride * 4)
encodeQuadTo(data, qs.contour, from, ctrl, to)
}
func (qs *quadSplitter) splitAndEncode(quad stroke.QuadSegment) {
cbnd := f32.Rectangle{
Min: quad.From,
Max: quad.To,
}.Canon()
from, ctrl, to := quad.From, quad.Ctrl, quad.To
// If the curve contain areas where a vertical line
// intersects it twice, split the curve in two x monotone
// lower and upper curves. The stencil fragment program
// expects only one intersection per curve.
// Find the t where the derivative in x is 0.
v0 := ctrl.Sub(from)
v1 := to.Sub(ctrl)
d := v0.X - v1.X
// t = v0 / d. Split if t is in ]0;1[.
if v0.X > 0 && d > v0.X || v0.X < 0 && d < v0.X {
t := v0.X / d
ctrl0 := from.Mul(1 - t).Add(ctrl.Mul(t))
ctrl1 := ctrl.Mul(1 - t).Add(to.Mul(t))
mid := ctrl0.Mul(1 - t).Add(ctrl1.Mul(t))
qs.encodeQuadTo(from, ctrl0, mid)
qs.encodeQuadTo(mid, ctrl1, to)
if mid.X > cbnd.Max.X {
cbnd.Max.X = mid.X
}
if mid.X < cbnd.Min.X {
cbnd.Min.X = mid.X
}
} else {
qs.encodeQuadTo(from, ctrl, to)
}
// Find the y extremum, if any.
d = v0.Y - v1.Y
if v0.Y > 0 && d > v0.Y || v0.Y < 0 && d < v0.Y {
t := v0.Y / d
y := (1-t)*(1-t)*from.Y + 2*(1-t)*t*ctrl.Y + t*t*to.Y
if y > cbnd.Max.Y {
cbnd.Max.Y = y
}
if y < cbnd.Min.Y {
cbnd.Min.Y = y
}
}
qs.bounds = qs.bounds.Union(cbnd)
}