2021-04-25 20:13:56 (UTC-03:00)
Marcel Rodrigues <marcelgmr@gmail.com>
add support for holes in polygons
diff --git a/surf.lua b/surf.lua index 4f67c51..9ec1bf0 100644 --- a/surf.lua +++ b/surf.lua @@ -86,28 +86,36 @@ function Surf:polylines(polys, v, r) end end -function Surf:polygon(points, v) - local scans = {} - for i = 0, self.h-1 do - scans[i] = {} +local function cross_comp(a, b) + return a[1] < b[1] +end + +function Surf:scan(points) + if not self.scans then + self.scans = {} + for i = 0, self.h-1 do + self.scans[i] = {} + end end local x0, y0, x1, y1 local ax, ay, bx, by -- same line as above, but enforce ay < by - -- collect crossings + local sign x0, y0 = unpack(points[1]) for i = 2, #points do x1, y1 = unpack(points[i]) if y1 ~= y0 then if y0 < y1 then ax, ay, bx, by = x0, y0, x1, y1 + sign = 1 else ax, ay, bx, by = x1, y1, x0, y0 + sign = -1 end local slope = (bx-ax) / (by-ay) ay, by = round(ay), round(by) while ay < by do if ay >= 0 and ay < self.h then - table.insert(scans[ay], ax) + table.insert(self.scans[ay], {ax, sign}) end ax = ax + slope ay = ay + 1 @@ -115,15 +123,41 @@ function Surf:polygon(points, v) end x0, y0 = x1, y1 end - -- fill scanlines +end + +function Surf:fill_scans(v) + local scan, wind + local x, sign + local ax, bx for i = 0, self.h-1 do - local scan = scans[i] - table.sort(scan) - for j = 2, #scan, 2 do - ax, bx = round(scan[j-1]), round(scan[j]) - self:hline(ax, i, bx-ax, v) + scan = self.scans[i] + table.sort(scan, cross_comp) + wind = 0 + for j, cross in ipairs(scan) do + x, sign = unpack(cross) + if wind == 0 then + ax = round(x) + end + wind = wind + sign + if wind == 0 then + bx = round(x) + self:hline(ax, i, bx-ax, v) + end end end + self.scans = nil +end + +function Surf:polygon(points, v) + self:scan(points) + self:fill_scans(v) +end + +function Surf:polygons(polygons, v) + for _, points in ipairs(polygons) do + self:scan(points) + end + self:fill_scans(v) end function Surf:blit(x, y, surf, sx, sy, w, h)