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  }