9fans.net/go@v0.0.5/draw/memdraw/fillpoly.go (about) 1 // #include <u.h> 2 // #include <libc.h> 3 // #include <draw.h> 4 // #include <memdraw.h> 5 6 package memdraw 7 8 import ( 9 "sort" 10 11 "9fans.net/go/draw" 12 ) 13 14 type polySeg struct { 15 p0 draw.Point 16 p1 draw.Point 17 num int 18 den int 19 dz int 20 dzrem int 21 z int 22 zerr int 23 d int 24 } 25 26 func fillline(dst *Image, left int, right int, y int, src *Image, p draw.Point, op draw.Op) { 27 var r draw.Rectangle 28 r.Min.X = left 29 r.Min.Y = y 30 r.Max.X = right 31 r.Max.Y = y + 1 32 p.X += left 33 p.Y += y 34 Draw(dst, r, src, p, Opaque, p, op) 35 } 36 37 func fillpoint(dst *Image, x int, y int, src *Image, p draw.Point, op draw.Op) { 38 var r draw.Rectangle 39 r.Min.X = x 40 r.Min.Y = y 41 r.Max.X = x + 1 42 r.Max.Y = y + 1 43 p.X += x 44 p.Y += y 45 Draw(dst, r, src, p, Opaque, p, op) 46 } 47 48 func FillPoly(dst *Image, vert []draw.Point, w int, src *Image, sp draw.Point, op draw.Op) { 49 _memfillpolysc(dst, vert, w, src, sp, 0, 0, 0, op) 50 } 51 52 func _memfillpolysc(dst *Image, vert []draw.Point, w int, src *Image, sp draw.Point, detail int, fixshift int, clipped int, op draw.Op) { 53 if len(vert) == 0 { 54 return 55 } 56 57 seg := make([]*polySeg, len(vert)+2) 58 segtab := make([]polySeg, len(vert)+1) 59 60 sp.X = (sp.X - vert[0].X) >> fixshift 61 sp.Y = (sp.Y - vert[0].Y) >> fixshift 62 p0 := vert[len(vert)-1] 63 if fixshift == 0 { 64 p0.X <<= 1 65 p0.Y <<= 1 66 } 67 for i := 0; i < len(vert); i++ { 68 segtab[i].p0 = p0 69 p0 = vert[i] 70 if fixshift == 0 { 71 p0.X <<= 1 72 p0.Y <<= 1 73 } 74 segtab[i].p1 = p0 75 segtab[i].d = 1 76 } 77 if fixshift == 0 { 78 fixshift = 1 79 } 80 81 xscan(dst, seg, segtab, len(vert), w, src, sp, detail, fixshift, clipped, op) 82 if detail != 0 { 83 yscan(dst, seg, segtab, len(vert), w, src, sp, fixshift, op) 84 } 85 } 86 87 func mod(x int, y int) int { 88 z := x % y 89 if int((int(z))^(int(y))) > 0 || z == 0 { 90 return z 91 } 92 return z + y 93 } 94 95 func sdiv(x int, y int) int { 96 if int((int(x))^(int(y))) >= 0 || x == 0 { 97 return x / y 98 } 99 100 return (x+(y>>30|1))/y - 1 101 } 102 103 func smuldivmod(x int, y int, z int, mod *int) int { 104 if x == 0 || y == 0 { 105 *mod = 0 106 return 0 107 } 108 vx := x 109 vx *= y 110 *mod = vx % z 111 if *mod < 0 { 112 *mod += z /* z is always >0 */ 113 } 114 if (vx < 0) == (z < 0) { 115 return vx / z 116 } 117 return -((-vx) / z) 118 } 119 120 func xscan(dst *Image, seg []*polySeg, segtab []polySeg, nseg int, wind int, src *Image, sp draw.Point, detail int, fixshift int, clipped int, op draw.Op) { 121 fill := fillline 122 /* 123 * This can only work on 8-bit destinations, since fillcolor is 124 * just using memset on sp.x. 125 * 126 * I'd rather not even enable it then, since then if the general 127 * code is too slow, someone will come up with a better improvement 128 * than this sleazy hack. -rsc 129 * 130 if(clipped && (src->flags&Frepl) && src->depth==8 && Dx(src->r)==1 && Dy(src->r)==1) { 131 fill = fillcolor; 132 sp.x = membyteval(src); 133 } 134 * 135 */ 136 137 p := 0 138 for i := 0; i < nseg; i++ { 139 s := &segtab[i] 140 seg[p] = s 141 if s.p0.Y == s.p1.Y { 142 continue 143 } 144 if s.p0.Y > s.p1.Y { 145 pt := s.p0 146 s.p0 = s.p1 147 s.p1 = pt 148 s.d = -s.d 149 } 150 s.num = s.p1.X - s.p0.X 151 s.den = s.p1.Y - s.p0.Y 152 s.dz = sdiv(s.num, s.den) << fixshift 153 s.dzrem = mod(s.num, s.den) << fixshift 154 s.dz += sdiv(s.dzrem, s.den) 155 s.dzrem = mod(s.dzrem, s.den) 156 p++ 157 } 158 if p == 0 { 159 return 160 } 161 seg[p] = nil 162 sort.Slice(seg[:p], func(i, j int) bool { return seg[i].p0.Y < seg[j].p0.Y }) 163 164 onehalf := 0 165 if fixshift != 0 { 166 onehalf = 1 << (fixshift - 1) 167 } 168 169 minx := dst.Clipr.Min.X 170 maxx := dst.Clipr.Max.X 171 172 y := seg[0].p0.Y 173 if y < dst.Clipr.Min.Y<<fixshift { 174 y = dst.Clipr.Min.Y << fixshift 175 } 176 iy := (y + onehalf) >> fixshift 177 y = (iy << fixshift) + onehalf 178 maxy := dst.Clipr.Max.Y << fixshift 179 180 next := 0 181 ep := next 182 183 for y < maxy { 184 p = 0 185 var q int 186 for q = p; p < ep; p++ { 187 s := seg[p] 188 if s.p1.Y < y { 189 continue 190 } 191 s.z += s.dz 192 s.zerr += s.dzrem 193 if s.zerr >= s.den { 194 s.z++ 195 s.zerr -= s.den 196 if s.zerr < 0 || s.zerr >= s.den { 197 print("bad ratzerr1: %ld den %ld dzrem %ld\n", s.zerr, s.den, s.dzrem) 198 } 199 } 200 seg[q] = s 201 q++ 202 } 203 204 for p = next; seg[p] != nil; p++ { 205 s := seg[p] 206 if s.p0.Y >= y { 207 break 208 } 209 if s.p1.Y < y { 210 continue 211 } 212 s.z = s.p0.X 213 s.z += smuldivmod(y-s.p0.Y, s.num, s.den, &s.zerr) 214 if s.zerr < 0 || s.zerr >= s.den { 215 print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s.zerr, s.den, s.dzrem) 216 } 217 seg[q] = s 218 q++ 219 } 220 ep = q 221 next = p 222 223 if ep == 0 { 224 if seg[next] == nil { 225 break 226 } 227 iy = (seg[next].p0.Y + onehalf) >> fixshift 228 y = (iy << fixshift) + onehalf 229 continue 230 } 231 232 zsort(seg, ep) 233 234 for p = 0; p < ep; p++ { 235 s := seg[p] 236 cnt := 0 237 x := s.z 238 xerr := s.zerr 239 xden := s.den 240 ix := (x + onehalf) >> fixshift 241 if ix >= maxx { 242 break 243 } 244 if ix < minx { 245 ix = minx 246 } 247 cnt += s.d 248 p++ 249 s = seg[p] 250 for { 251 if p == ep { 252 print("xscan: fill to infinity") 253 return 254 } 255 cnt += s.d 256 if cnt&wind == 0 { 257 break 258 } 259 p++ 260 s = seg[p] 261 } 262 x2 := s.z 263 ix2 := (x2 + onehalf) >> fixshift 264 if ix2 <= minx { 265 continue 266 } 267 if ix2 > maxx { 268 ix2 = maxx 269 } 270 if ix == ix2 && detail != 0 { 271 if xerr*s.den+s.zerr*xden > s.den*xden { 272 x++ 273 } 274 ix = (x + x2) >> (fixshift + 1) 275 ix2 = ix + 1 276 } 277 fill(dst, ix, ix2, iy, src, sp, op) 278 } 279 y += (1 << fixshift) 280 iy++ 281 } 282 } 283 284 func yscan(dst *Image, seg []*polySeg, segtab []polySeg, nseg int, wind int, src *Image, sp draw.Point, fixshift int, op draw.Op) { 285 p := 0 286 for i := 0; i < nseg; i++ { 287 s := &segtab[i] 288 seg[p] = s 289 if s.p0.X == s.p1.X { 290 continue 291 } 292 if s.p0.X > s.p1.X { 293 pt := s.p0 294 s.p0 = s.p1 295 s.p1 = pt 296 s.d = -s.d 297 } 298 s.num = s.p1.Y - s.p0.Y 299 s.den = s.p1.X - s.p0.X 300 s.dz = sdiv(s.num, s.den) << fixshift 301 s.dzrem = mod(s.num, s.den) << fixshift 302 s.dz += sdiv(s.dzrem, s.den) 303 s.dzrem = mod(s.dzrem, s.den) 304 p++ 305 } 306 if p == 0 { 307 return 308 } 309 seg[p] = nil 310 sort.Slice(seg[:p], func(i, j int) bool { return seg[i].p0.X < seg[j].p0.X }) 311 312 onehalf := 0 313 if fixshift != 0 { 314 onehalf = 1 << (fixshift - 1) 315 } 316 317 miny := dst.Clipr.Min.Y 318 maxy := dst.Clipr.Max.Y 319 320 x := seg[0].p0.X 321 if x < dst.Clipr.Min.X<<fixshift { 322 x = dst.Clipr.Min.X << fixshift 323 } 324 ix := (x + onehalf) >> fixshift 325 x = (ix << fixshift) + onehalf 326 maxx := dst.Clipr.Max.X << fixshift 327 328 next := 0 329 ep := next 330 331 for x < maxx { 332 p = 0 333 var q int 334 for q = p; p < ep; p++ { 335 s := seg[p] 336 if s.p1.X < x { 337 continue 338 } 339 s.z += s.dz 340 s.zerr += s.dzrem 341 if s.zerr >= s.den { 342 s.z++ 343 s.zerr -= s.den 344 if s.zerr < 0 || s.zerr >= s.den { 345 print("bad ratzerr1: %ld den %ld ratdzrem %ld\n", s.zerr, s.den, s.dzrem) 346 } 347 } 348 seg[q] = s 349 q++ 350 } 351 352 for p = next; seg[p] != nil; p++ { 353 s := seg[p] 354 if s.p0.X >= x { 355 break 356 } 357 if s.p1.X < x { 358 continue 359 } 360 s.z = s.p0.Y 361 s.z += smuldivmod(x-s.p0.X, s.num, s.den, &s.zerr) 362 if s.zerr < 0 || s.zerr >= s.den { 363 print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s.zerr, s.den, s.dzrem) 364 } 365 seg[q] = s 366 q++ 367 } 368 ep = q 369 next = p 370 371 if ep == 0 { 372 if seg[next] == nil { 373 break 374 } 375 ix = (seg[next].p0.X + onehalf) >> fixshift 376 x = (ix << fixshift) + onehalf 377 continue 378 } 379 380 zsort(seg, ep) 381 382 for p = 0; p < ep; p++ { 383 cnt := 0 384 y := seg[p].z 385 yerr := seg[p].zerr 386 yden := seg[p].den 387 iy := (y + onehalf) >> fixshift 388 if iy >= maxy { 389 break 390 } 391 if iy < miny { 392 iy = miny 393 } 394 cnt += seg[p].d 395 p++ 396 for { 397 if p == ep { 398 print("yscan: fill to infinity") 399 return 400 } 401 cnt += seg[p].d 402 if cnt&wind == 0 { 403 break 404 } 405 p++ 406 } 407 y2 := seg[p].z 408 iy2 := (y2 + onehalf) >> fixshift 409 if iy2 <= miny { 410 continue 411 } 412 if iy2 > maxy { 413 iy2 = maxy 414 } 415 if iy == iy2 { 416 if yerr*seg[p].den+seg[p].zerr*yden > seg[p].den*yden { 417 y++ 418 } 419 iy = (y + y2) >> (fixshift + 1) 420 fillpoint(dst, ix, iy, src, sp, op) 421 } 422 } 423 x += (1 << fixshift) 424 ix++ 425 } 426 } 427 428 func zsort(seg []*polySeg, ep int) { 429 if ep < 20 { 430 /* bubble sort by z - they should be almost sorted already */ 431 q := ep 432 for { 433 done := true 434 q-- 435 for p := 0; p < q; p++ { 436 if seg[p].z > seg[p+1].z { 437 s := seg[p] 438 seg[p] = seg[p+1] 439 seg[p+1] = s 440 done = false 441 } 442 } 443 if done { 444 break 445 } 446 } 447 } else { 448 q := ep - 1 449 for p := 0; p < q; p++ { 450 if seg[p].z > seg[p+1].z { 451 sort.Slice(seg[:ep], func(i, j int) bool { return seg[i].z < seg[j].z }) 452 break 453 } 454 } 455 } 456 }