-
Notifications
You must be signed in to change notification settings - Fork 1
/
clip.go
99 lines (90 loc) · 2.28 KB
/
clip.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package gpu
import (
"github.com/cybriq/p9/pkg/gel/gio/f32"
"github.com/cybriq/p9/pkg/gel/gio/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)
}