scene.mx raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 // Scene command types and encoding for the compute renderer.
4
5 package gio
6
7 import (
8 "fmt"
9 "image"
10 "image/color"
11 "math"
12 )
13
14 type Op uint32
15
16 const sceneElemSize = 36
17
18 type Command [sceneElemSize / 4]uint32
19
20 // GPU commands from piet/scene.h in package gioui.org/shaders.
21 const (
22 OpNop Op = iota
23 OpLine
24 OpQuad
25 OpCubic
26 OpFillColor
27 OpLineWidth
28 OpTransform
29 OpBeginClip
30 OpEndClip
31 OpFillImage
32 OpSetFillMode
33 OpGap
34 )
35
36 // FillModes, from setup.h.
37 type FillMode uint32
38
39 const (
40 FillModeNonzero = 0
41 FillModeStroke = 1
42 )
43
44 // CommandSize is the byte size of a Command (sceneElemSize = 36).
45 const CommandSize = sceneElemSize
46
47 func (c Command) Op() Op {
48 return Op(c[0])
49 }
50
51 func (c Command) String() string {
52 switch Op(c[0]) {
53 case OpNop:
54 return "nop"
55 case OpLine:
56 from, to := DecodeLine(c)
57 return fmt.Sprintf("line(%v, %v)", from, to)
58 case OpGap:
59 from, to := DecodeGap(c)
60 return fmt.Sprintf("gap(%v, %v)", from, to)
61 case OpQuad:
62 from, ctrl, to := DecodeQuad(c)
63 return fmt.Sprintf("quad(%v, %v, %v)", from, ctrl, to)
64 case OpCubic:
65 from, ctrl0, ctrl1, to := DecodeCubic(c)
66 return fmt.Sprintf("cubic(%v, %v, %v, %v)", from, ctrl0, ctrl1, to)
67 case OpFillColor:
68 return fmt.Sprintf("fillcolor %#.8x", c[1])
69 case OpLineWidth:
70 return "linewidth"
71 case OpTransform:
72 t := NewAffine2D(
73 math.Float32frombits(c[1]),
74 math.Float32frombits(c[3]),
75 math.Float32frombits(c[5]),
76 math.Float32frombits(c[2]),
77 math.Float32frombits(c[4]),
78 math.Float32frombits(c[6]),
79 )
80 return fmt.Sprintf("transform (%v)", t)
81 case OpBeginClip:
82 bounds := Rectangle{
83 Min: Pt(math.Float32frombits(c[1]), math.Float32frombits(c[2])),
84 Max: Pt(math.Float32frombits(c[3]), math.Float32frombits(c[4])),
85 }
86 return fmt.Sprintf("beginclip (%v)", bounds)
87 case OpEndClip:
88 bounds := Rectangle{
89 Min: Pt(math.Float32frombits(c[1]), math.Float32frombits(c[2])),
90 Max: Pt(math.Float32frombits(c[3]), math.Float32frombits(c[4])),
91 }
92 return fmt.Sprintf("endclip (%v)", bounds)
93 case OpFillImage:
94 return "fillimage"
95 case OpSetFillMode:
96 return "setfillmode"
97 default:
98 panic("unreachable")
99 }
100 }
101
102 func Line(start, end Point) Command {
103 return Command{
104 0: uint32(OpLine),
105 1: math.Float32bits(start.X),
106 2: math.Float32bits(start.Y),
107 3: math.Float32bits(end.X),
108 4: math.Float32bits(end.Y),
109 }
110 }
111
112 func Gap(start, end Point) Command {
113 return Command{
114 0: uint32(OpGap),
115 1: math.Float32bits(start.X),
116 2: math.Float32bits(start.Y),
117 3: math.Float32bits(end.X),
118 4: math.Float32bits(end.Y),
119 }
120 }
121
122 func Cubic(start, ctrl0, ctrl1, end Point) Command {
123 return Command{
124 0: uint32(OpCubic),
125 1: math.Float32bits(start.X),
126 2: math.Float32bits(start.Y),
127 3: math.Float32bits(ctrl0.X),
128 4: math.Float32bits(ctrl0.Y),
129 5: math.Float32bits(ctrl1.X),
130 6: math.Float32bits(ctrl1.Y),
131 7: math.Float32bits(end.X),
132 8: math.Float32bits(end.Y),
133 }
134 }
135
136 func Quad(start, ctrl, end Point) Command {
137 return Command{
138 0: uint32(OpQuad),
139 1: math.Float32bits(start.X),
140 2: math.Float32bits(start.Y),
141 3: math.Float32bits(ctrl.X),
142 4: math.Float32bits(ctrl.Y),
143 5: math.Float32bits(end.X),
144 6: math.Float32bits(end.Y),
145 }
146 }
147
148 func Transform(m Affine2D) Command {
149 sx, hx, ox, hy, sy, oy := m.Elems()
150 return Command{
151 0: uint32(OpTransform),
152 1: math.Float32bits(sx),
153 2: math.Float32bits(hy),
154 3: math.Float32bits(hx),
155 4: math.Float32bits(sy),
156 5: math.Float32bits(ox),
157 6: math.Float32bits(oy),
158 }
159 }
160
161 func SetLineWidth(width float32) Command {
162 return Command{
163 0: uint32(OpLineWidth),
164 1: math.Float32bits(width),
165 }
166 }
167
168 func BeginClip(bbox Rectangle) Command {
169 return Command{
170 0: uint32(OpBeginClip),
171 1: math.Float32bits(bbox.Min.X),
172 2: math.Float32bits(bbox.Min.Y),
173 3: math.Float32bits(bbox.Max.X),
174 4: math.Float32bits(bbox.Max.Y),
175 }
176 }
177
178 func EndClip(bbox Rectangle) Command {
179 return Command{
180 0: uint32(OpEndClip),
181 1: math.Float32bits(bbox.Min.X),
182 2: math.Float32bits(bbox.Min.Y),
183 3: math.Float32bits(bbox.Max.X),
184 4: math.Float32bits(bbox.Max.Y),
185 }
186 }
187
188 func FillColor(col color.RGBA) Command {
189 return Command{
190 0: uint32(OpFillColor),
191 1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A),
192 }
193 }
194
195 func FillImage(index int, offset image.Point) Command {
196 x := int16(offset.X)
197 y := int16(offset.Y)
198 return Command{
199 0: uint32(OpFillImage),
200 1: uint32(index),
201 2: uint32(uint16(x)) | uint32(uint16(y))<<16,
202 }
203 }
204
205 func SetFillMode(mode FillMode) Command {
206 return Command{
207 0: uint32(OpSetFillMode),
208 1: uint32(mode),
209 }
210 }
211
212 func DecodeLine(cmd Command) (from, to Point) {
213 if cmd[0] != uint32(OpLine) {
214 panic("invalid command")
215 }
216 from = Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2]))
217 to = Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4]))
218 return
219 }
220
221 func DecodeGap(cmd Command) (from, to Point) {
222 if cmd[0] != uint32(OpGap) {
223 panic("invalid command")
224 }
225 from = Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2]))
226 to = Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4]))
227 return
228 }
229
230 func DecodeQuad(cmd Command) (from, ctrl, to Point) {
231 if cmd[0] != uint32(OpQuad) {
232 panic("invalid command")
233 }
234 from = Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2]))
235 ctrl = Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4]))
236 to = Pt(math.Float32frombits(cmd[5]), math.Float32frombits(cmd[6]))
237 return
238 }
239
240 func DecodeCubic(cmd Command) (from, ctrl0, ctrl1, to Point) {
241 if cmd[0] != uint32(OpCubic) {
242 panic("invalid command")
243 }
244 from = Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2]))
245 ctrl0 = Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4]))
246 ctrl1 = Pt(math.Float32frombits(cmd[5]), math.Float32frombits(cmd[6]))
247 to = Pt(math.Float32frombits(cmd[7]), math.Float32frombits(cmd[8]))
248 return
249 }
250