1 # Draw a second-degree bezier curve using 3 control points.
3 # http://members.chello.at/easyfilter/bresenham.html says that this algorithm
4 # works only if "the gradient does not change sign". Either:
8 # Similarly for y0, y1 and y2.
10 # This seems superficially similar to the notions of convex and concave, but I
11 # think it isn't. I think it's purely a property of the frame of reference.
12 # Rotating the axes can make the gradient change sign or stop changing sign
13 # even as 3 points preserve fixed relative bearings to each other.
14 fn draw-monotonic-bezier screen: (addr screen), x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int {
21 var tmp/eax: int <- copy x2
37 var cur-f/xmm4: float <- convert xx
39 var sy-f/xmm1: float <- convert sy
40 cur-f <- multiply sy-f
41 var tmp2-f/xmm1: float <- convert yy
42 var sx-f/xmm2: float <- convert sx
43 tmp2-f <- multiply sx-f
44 cur-f <- subtract tmp2-f
46 # if (xx*sx > 0) abort
52 abort "bezier: gradient of x changes sign"
54 # if (yy*sy > 0) abort
60 abort "bezier: gradient of y changes sign"
62 # swap P0 and P2 if necessary
64 # dist1 = sx*sx + sy*sy
65 var dist1/ecx: int <- copy sx
70 abort "bezier: overflow 1"
76 abort "bezier: overflow 2"
80 # dist2 = xx*xx + yy*yy
81 var dist2/edx: int <- copy xx
86 abort "bezier: overflow 3"
92 abort "bezier: overflow 4"
96 # if (dist1 <= dist2) break
112 var negative-1/eax: int <- copy -1
113 var negative-1-f/xmm1: float <- convert negative-1
114 cur-f <- multiply negative-1-f
116 var x/ecx: int <- copy x0
117 var y/edx: int <- copy y0
119 # plot a curved part if necessary
120 $draw-monotonic-bezier:curve: {
121 compare cur-f, zero-f
151 break-if-not-overflow
152 abort "bezier: overflow 5"
156 break-if-not-overflow
157 abort "bezier: overflow 6"
164 break-if-not-overflow
165 abort "bezier: overflow 7"
172 break-if-not-overflow
173 abort "bezier: overflow 7"
176 # if (cur*sx*sy < 0) negative curvature
178 var tmp-f/xmm0: float <- copy cur-f
179 var sx-f/xmm1: float <- convert sx
180 tmp-f <- multiply sx-f
181 var sy-f/xmm1: float <- convert sy
182 tmp-f <- multiply sy-f
183 compare tmp-f, zero-f
190 var negative-1/eax: int <- copy -1
191 var negative-1-f/xmm1: float <- convert negative-1
192 cur-f <- multiply negative-1-f
194 var four/ebx: int <- copy 4
195 var dx-f/xmm5: float <- convert four
196 var dy-f/xmm6: float <- convert four
197 # dx = 4*sy*cur*(x1-x0) + xx - xy
199 var tmp/xmm0: float <- convert sy
201 dx-f <- multiply cur-f
203 var tmp2/xmm3: float <- convert x
211 # dy-f = 4*sx*cur*(y0-y1) + yy - xy
213 var tmp/xmm0: float <- convert sx
215 dy-f <- multiply cur-f
217 var tmp2/xmm3: float <- convert y1
232 var err-f/xmm7: float <- copy dx-f
234 var xy-f/xmm0: float <- convert xy
237 $draw-monotonic-bezier:loop: {
238 pixel screen, x, y, color
239 # if (x == x2 && y == y2) return
247 # perform-y-step? = (2*err < dx)
248 var perform-y-step?/eax: boolean <- copy 0/false
249 var two-err-f/xmm0: float <- copy err-f
251 var two/ebx: int <- copy 2
252 var two-f/xmm1: float <- convert two
253 two-err-f <- multiply two-f
254 compare two-err-f, dx-f
256 perform-y-step? <- copy 1/true
260 compare two-err-f, dy-f
265 var xy-f/xmm0: float <- convert xy
266 dx-f <- subtract xy-f
268 var yy-f/xmm0: float <- convert yy
275 compare perform-y-step?, 0/false
280 var xy-f/xmm0: float <- convert xy
281 dy-f <- subtract xy-f
283 var xx-f/xmm0: float <- convert xx
293 # plot the remaining straight line
294 draw-line screen, x y, x2 y2, color
298 fn bezier-point u: float, x0: int, x1: int, x2: int -> _/eax: int {
299 var one/eax: int <- copy 1
300 var u-prime/xmm0: float <- convert one
301 u-prime <- subtract u
302 var result/xmm1: float <- convert x0
303 result <- multiply u-prime
304 result <- multiply u-prime
305 var term2/xmm2: float <- convert x1
307 term2 <- multiply u-prime
310 var term3/xmm2: float <- convert x2
314 var result/eax: int <- convert result