clip.go raw
1 package gpu
2
3 import (
4 "github.com/p9c/p9/pkg/gel/gio/f32"
5 "github.com/p9c/p9/pkg/gel/gio/internal/stroke"
6 )
7
8 type quadSplitter struct {
9 bounds f32.Rectangle
10 contour uint32
11 d *drawOps
12 }
13
14 func encodeQuadTo(data []byte, meta uint32, from, ctrl, to f32.Point) {
15 // NW.
16 encodeVertex(data, meta, -1, 1, from, ctrl, to)
17 // NE.
18 encodeVertex(data[vertStride:], meta, 1, 1, from, ctrl, to)
19 // SW.
20 encodeVertex(data[vertStride*2:], meta, -1, -1, from, ctrl, to)
21 // SE.
22 encodeVertex(data[vertStride*3:], meta, 1, -1, from, ctrl, to)
23 }
24
25 func encodeVertex(data []byte, meta uint32, cornerx, cornery int16, from, ctrl, to f32.Point) {
26 var corner float32
27 if cornerx == 1 {
28 corner += .5
29 }
30 if cornery == 1 {
31 corner += .25
32 }
33 v := vertex{
34 Corner: corner,
35 FromX: from.X,
36 FromY: from.Y,
37 CtrlX: ctrl.X,
38 CtrlY: ctrl.Y,
39 ToX: to.X,
40 ToY: to.Y,
41 }
42 v.encode(data, meta)
43 }
44
45 func (qs *quadSplitter) encodeQuadTo(from, ctrl, to f32.Point) {
46 data := qs.d.writeVertCache(vertStride * 4)
47 encodeQuadTo(data, qs.contour, from, ctrl, to)
48 }
49
50 func (qs *quadSplitter) splitAndEncode(quad stroke.QuadSegment) {
51 cbnd := f32.Rectangle{
52 Min: quad.From,
53 Max: quad.To,
54 }.Canon()
55 from, ctrl, to := quad.From, quad.Ctrl, quad.To
56
57 // If the curve contain areas where a vertical line
58 // intersects it twice, split the curve in two x monotone
59 // lower and upper curves. The stencil fragment program
60 // expects only one intersection per curve.
61
62 // Find the t where the derivative in x is 0.
63 v0 := ctrl.Sub(from)
64 v1 := to.Sub(ctrl)
65 d := v0.X - v1.X
66 // t = v0 / d. Split if t is in ]0;1[.
67 if v0.X > 0 && d > v0.X || v0.X < 0 && d < v0.X {
68 t := v0.X / d
69 ctrl0 := from.Mul(1 - t).Add(ctrl.Mul(t))
70 ctrl1 := ctrl.Mul(1 - t).Add(to.Mul(t))
71 mid := ctrl0.Mul(1 - t).Add(ctrl1.Mul(t))
72 qs.encodeQuadTo(from, ctrl0, mid)
73 qs.encodeQuadTo(mid, ctrl1, to)
74 if mid.X > cbnd.Max.X {
75 cbnd.Max.X = mid.X
76 }
77 if mid.X < cbnd.Min.X {
78 cbnd.Min.X = mid.X
79 }
80 } else {
81 qs.encodeQuadTo(from, ctrl, to)
82 }
83 // Find the y extremum, if any.
84 d = v0.Y - v1.Y
85 if v0.Y > 0 && d > v0.Y || v0.Y < 0 && d < v0.Y {
86 t := v0.Y / d
87 y := (1-t)*(1-t)*from.Y + 2*(1-t)*t*ctrl.Y + t*t*to.Y
88 if y > cbnd.Max.Y {
89 cbnd.Max.Y = y
90 }
91 if y < cbnd.Min.Y {
92 cbnd.Min.Y = y
93 }
94 }
95
96 qs.bounds = qs.bounds.Union(cbnd)
97 }
98