1
2
3
4
5
6
7
8
9
10
11 package vector
12
13
14
15
16
17
18
19
20
21
22
23
24 import (
25 "image"
26 "image/color"
27 "image/draw"
28 "math"
29 )
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 const floatingPointMathThreshold = 512
50
51 func lerp(t, px, py, qx, qy float32) (x, y float32) {
52 return px + t*(qx-px), py + t*(qy-py)
53 }
54
55 func clamp(i, width int32) uint {
56 if i < 0 {
57 return 0
58 }
59 if i < width {
60 return uint(i)
61 }
62 return uint(width)
63 }
64
65
66
67 func NewRasterizer(w, h int) *Rasterizer {
68 z := &Rasterizer{}
69 z.Reset(w, h)
70 return z
71 }
72
73
74
75
76
77 type Rasterizer struct {
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 bufF32 []float32
93 bufU32 []uint32
94
95 useFloatingPointMath bool
96
97 size image.Point
98 firstX float32
99 firstY float32
100 penX float32
101 penY float32
102
103
104
105
106 DrawOp draw.Op
107
108
109
110 }
111
112
113
114
115 func (z *Rasterizer) Reset(w, h int) {
116 z.size = image.Point{w, h}
117 z.firstX = 0
118 z.firstY = 0
119 z.penX = 0
120 z.penY = 0
121 z.DrawOp = draw.Over
122
123 z.setUseFloatingPointMath(w > floatingPointMathThreshold || h > floatingPointMathThreshold)
124 }
125
126 func (z *Rasterizer) setUseFloatingPointMath(b bool) {
127 z.useFloatingPointMath = b
128
129
130 if z.useFloatingPointMath {
131 if n := z.size.X * z.size.Y; n > cap(z.bufF32) {
132 z.bufF32 = make([]float32, n)
133 } else {
134 z.bufF32 = z.bufF32[:n]
135 for i := range z.bufF32 {
136 z.bufF32[i] = 0
137 }
138 }
139 } else {
140 if n := z.size.X * z.size.Y; n > cap(z.bufU32) {
141 z.bufU32 = make([]uint32, n)
142 } else {
143 z.bufU32 = z.bufU32[:n]
144 for i := range z.bufU32 {
145 z.bufU32[i] = 0
146 }
147 }
148 }
149 }
150
151
152 func (z *Rasterizer) Size() image.Point {
153 return z.size
154 }
155
156
157
158 func (z *Rasterizer) Bounds() image.Rectangle {
159 return image.Rectangle{Max: z.size}
160 }
161
162
163
164 func (z *Rasterizer) Pen() (x, y float32) {
165 return z.penX, z.penY
166 }
167
168
169 func (z *Rasterizer) ClosePath() {
170 z.LineTo(z.firstX, z.firstY)
171 }
172
173
174
175
176 func (z *Rasterizer) MoveTo(ax, ay float32) {
177 z.firstX = ax
178 z.firstY = ay
179 z.penX = ax
180 z.penY = ay
181 }
182
183
184
185
186
187 func (z *Rasterizer) LineTo(bx, by float32) {
188 if z.useFloatingPointMath {
189 z.floatingLineTo(bx, by)
190 } else {
191 z.fixedLineTo(bx, by)
192 }
193 }
194
195
196
197
198
199 func (z *Rasterizer) QuadTo(bx, by, cx, cy float32) {
200 ax, ay := z.penX, z.penY
201 devsq := devSquared(ax, ay, bx, by, cx, cy)
202 if devsq >= 0.333 {
203 const tol = 3
204 n := 1 + int(math.Sqrt(math.Sqrt(tol*float64(devsq))))
205 t, nInv := float32(0), 1/float32(n)
206 for i := 0; i < n-1; i++ {
207 t += nInv
208 abx, aby := lerp(t, ax, ay, bx, by)
209 bcx, bcy := lerp(t, bx, by, cx, cy)
210 z.LineTo(lerp(t, abx, aby, bcx, bcy))
211 }
212 }
213 z.LineTo(cx, cy)
214 }
215
216
217
218
219
220 func (z *Rasterizer) CubeTo(bx, by, cx, cy, dx, dy float32) {
221 ax, ay := z.penX, z.penY
222 devsq := devSquared(ax, ay, bx, by, dx, dy)
223 if devsqAlt := devSquared(ax, ay, cx, cy, dx, dy); devsq < devsqAlt {
224 devsq = devsqAlt
225 }
226 if devsq >= 0.333 {
227 const tol = 3
228 n := 1 + int(math.Sqrt(math.Sqrt(tol*float64(devsq))))
229 t, nInv := float32(0), 1/float32(n)
230 for i := 0; i < n-1; i++ {
231 t += nInv
232 abx, aby := lerp(t, ax, ay, bx, by)
233 bcx, bcy := lerp(t, bx, by, cx, cy)
234 cdx, cdy := lerp(t, cx, cy, dx, dy)
235 abcx, abcy := lerp(t, abx, aby, bcx, bcy)
236 bcdx, bcdy := lerp(t, bcx, bcy, cdx, cdy)
237 z.LineTo(lerp(t, abcx, abcy, bcdx, bcdy))
238 }
239 }
240 z.LineTo(dx, dy)
241 }
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257 func devSquared(ax, ay, bx, by, cx, cy float32) float32 {
258 devx := ax - 2*bx + cx
259 devy := ay - 2*by + cy
260 return devx*devx + devy*devy
261 }
262
263
264
265
266
267
268 func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
269
270
271
272 if src, ok := src.(*image.Uniform); ok {
273 srcR, srcG, srcB, srcA := src.RGBA()
274 switch dst := dst.(type) {
275 case *image.Alpha:
276
277 if srcA == 0xffff {
278 if z.DrawOp == draw.Over {
279 z.rasterizeDstAlphaSrcOpaqueOpOver(dst, r)
280 } else {
281 z.rasterizeDstAlphaSrcOpaqueOpSrc(dst, r)
282 }
283 return
284 }
285 case *image.RGBA:
286 if z.DrawOp == draw.Over {
287 z.rasterizeDstRGBASrcUniformOpOver(dst, r, srcR, srcG, srcB, srcA)
288 } else {
289 z.rasterizeDstRGBASrcUniformOpSrc(dst, r, srcR, srcG, srcB, srcA)
290 }
291 return
292 }
293 }
294
295 if z.DrawOp == draw.Over {
296 z.rasterizeOpOver(dst, r, src, sp)
297 } else {
298 z.rasterizeOpSrc(dst, r, src, sp)
299 }
300 }
301
302 func (z *Rasterizer) accumulateMask() {
303 if z.useFloatingPointMath {
304 if n := z.size.X * z.size.Y; n > cap(z.bufU32) {
305 z.bufU32 = make([]uint32, n)
306 } else {
307 z.bufU32 = z.bufU32[:n]
308 }
309 if haveAccumulateSIMD {
310 floatingAccumulateMaskSIMD(z.bufU32, z.bufF32)
311 } else {
312 floatingAccumulateMask(z.bufU32, z.bufF32)
313 }
314 } else {
315 if haveAccumulateSIMD {
316 fixedAccumulateMaskSIMD(z.bufU32)
317 } else {
318 fixedAccumulateMask(z.bufU32)
319 }
320 }
321 }
322
323 func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpOver(dst *image.Alpha, r image.Rectangle) {
324
325 if r == dst.Bounds() && r == z.Bounds() {
326
327
328 if z.useFloatingPointMath {
329 if haveAccumulateSIMD {
330 floatingAccumulateOpOverSIMD(dst.Pix, z.bufF32)
331 } else {
332 floatingAccumulateOpOver(dst.Pix, z.bufF32)
333 }
334 } else {
335 if haveAccumulateSIMD {
336 fixedAccumulateOpOverSIMD(dst.Pix, z.bufU32)
337 } else {
338 fixedAccumulateOpOver(dst.Pix, z.bufU32)
339 }
340 }
341 return
342 }
343
344 z.accumulateMask()
345 pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
346 for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
347 for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
348 ma := z.bufU32[y*z.size.X+x]
349 i := y*dst.Stride + x
350
351
352
353 a := 0xffff - ma
354 pix[i] = uint8((uint32(pix[i])*0x101*a/0xffff + ma) >> 8)
355 }
356 }
357 }
358
359 func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpSrc(dst *image.Alpha, r image.Rectangle) {
360
361 if r == dst.Bounds() && r == z.Bounds() {
362
363
364 if z.useFloatingPointMath {
365 if haveAccumulateSIMD {
366 floatingAccumulateOpSrcSIMD(dst.Pix, z.bufF32)
367 } else {
368 floatingAccumulateOpSrc(dst.Pix, z.bufF32)
369 }
370 } else {
371 if haveAccumulateSIMD {
372 fixedAccumulateOpSrcSIMD(dst.Pix, z.bufU32)
373 } else {
374 fixedAccumulateOpSrc(dst.Pix, z.bufU32)
375 }
376 }
377 return
378 }
379
380 z.accumulateMask()
381 pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
382 for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
383 for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
384 ma := z.bufU32[y*z.size.X+x]
385
386
387
388 pix[y*dst.Stride+x] = uint8(ma >> 8)
389 }
390 }
391 }
392
393 func (z *Rasterizer) rasterizeDstRGBASrcUniformOpOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
394 z.accumulateMask()
395 pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
396 for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
397 for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
398 ma := z.bufU32[y*z.size.X+x]
399
400
401
402 a := 0xffff - (sa * ma / 0xffff)
403 i := y*dst.Stride + 4*x
404 pix[i+0] = uint8(((uint32(pix[i+0])*0x101*a + sr*ma) / 0xffff) >> 8)
405 pix[i+1] = uint8(((uint32(pix[i+1])*0x101*a + sg*ma) / 0xffff) >> 8)
406 pix[i+2] = uint8(((uint32(pix[i+2])*0x101*a + sb*ma) / 0xffff) >> 8)
407 pix[i+3] = uint8(((uint32(pix[i+3])*0x101*a + sa*ma) / 0xffff) >> 8)
408 }
409 }
410 }
411
412 func (z *Rasterizer) rasterizeDstRGBASrcUniformOpSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
413 z.accumulateMask()
414 pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
415 for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
416 for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
417 ma := z.bufU32[y*z.size.X+x]
418
419
420
421 i := y*dst.Stride + 4*x
422 pix[i+0] = uint8((sr * ma / 0xffff) >> 8)
423 pix[i+1] = uint8((sg * ma / 0xffff) >> 8)
424 pix[i+2] = uint8((sb * ma / 0xffff) >> 8)
425 pix[i+3] = uint8((sa * ma / 0xffff) >> 8)
426 }
427 }
428 }
429
430 func (z *Rasterizer) rasterizeOpOver(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
431 z.accumulateMask()
432 out := color.RGBA64{}
433 outc := color.Color(&out)
434 for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
435 for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
436 sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
437 ma := z.bufU32[y*z.size.X+x]
438
439
440
441 dr, dg, db, da := dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
442 a := 0xffff - (sa * ma / 0xffff)
443 out.R = uint16((dr*a + sr*ma) / 0xffff)
444 out.G = uint16((dg*a + sg*ma) / 0xffff)
445 out.B = uint16((db*a + sb*ma) / 0xffff)
446 out.A = uint16((da*a + sa*ma) / 0xffff)
447
448 dst.Set(r.Min.X+x, r.Min.Y+y, outc)
449 }
450 }
451 }
452
453 func (z *Rasterizer) rasterizeOpSrc(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
454 z.accumulateMask()
455 out := color.RGBA64{}
456 outc := color.Color(&out)
457 for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
458 for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
459 sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
460 ma := z.bufU32[y*z.size.X+x]
461
462
463
464 out.R = uint16(sr * ma / 0xffff)
465 out.G = uint16(sg * ma / 0xffff)
466 out.B = uint16(sb * ma / 0xffff)
467 out.A = uint16(sa * ma / 0xffff)
468
469 dst.Set(r.Min.X+x, r.Min.Y+y, outc)
470 }
471 }
472 }
473
View as plain text