pixler/include/tools.bm
2026-05-01 13:58:36 +02:00

243 lines
8.2 KiB
Text

sub filledPolygon (Points() as long, col as long)
dim i as integer, j as integer
dim x1 as single, y1 as single, x2 as single, y2 as single
dim intersectX as single
' get the number of points from the upper bound of the array
' divide by 2 since we have x,y pairs
dim numPoints as integer
numPoints = (ubound(Points) + 1) \ 2
' loop through each scanline (rows of pixels)
dim intersections(100) as single
dim numIntersections as integer
for y = 0 to _height ' adjust for screen height
numIntersections = 0
' check for intersections between the polygon edges and this scanline
for i = 0 to numPoints - 1
x1 = Points(i * 2)
y1 = Points(i * 2 + 1)
x2 = Points(((i + 1) mod numPoints) * 2)
y2 = Points(((i + 1) mod numPoints) * 2 + 1)
' check if the scanline intersects with the edge of the polygon
if ((y1 > y and y2 <= y) or (y2 > y and y1 <= y)) then
' calculate intersection point with the scanline
intersectX = x1 + (y - y1) * (x2 - x1) / (y2 - y1)
intersections(numIntersections) = intersectX
numIntersections = numIntersections + 1
end if
next i
' sort the intersections (sort by x-coordinates)
for i = 0 to numIntersections - 1
for j = i + 1 to numIntersections - 1
if intersections(i) > intersections(j) then
swap intersections(i), intersections(j)
end if
next j
next i
' fill the area between pairs of intersections
for i = 0 to numIntersections - 1 step 2
line(intersections(i),y)-(intersections(i+1),y),col
next i
next y
end sub
sub thickline(x1,y1,x2,y2, col as long)
if state.brushsize=1 then
line(x1,y1)-(x2,y2),col
else
dim tempimg as long
dim od as long
tempimg=_newimage(10,10,32)
od =_dest
_dest tempimg
pset(0,0),col
_dest od
a = _Atan2(y2 - y1, x2 - x1)
a = a + _Pi / 2
x0 = 0.5 * state.brushsize * Cos(a)
y0 = 0.5 * state.brushsize * Sin(a)
_maptriangle _seamless(0,0)-(0,0)-(0,0),tempimg to(x1-x0, y1-y0)-(x1+x0,y1+y0)-(x2+x0,y2+y0),,_smooth
_maptriangle _seamless(0,0)-(0,0)-(0,0),tempimg to(x1-x0, y1-y0)-(x2+x0,y2+y0)-(x2-x0,y2-y0),,_smooth
_freeimage tempimg
end if
end sub
Sub polygon (pa() As Long,col as long)
For i = 2 To UBound(pa) Step 2
thickLine pa(i - 2), pa(i - 1),pa(i), pa(i + 1),col
Next i
thickLine pa(ubound(pa)-1), pa(ubound(pa)),pa(0), pa(1),col
End Sub
sub thickcircle(x, y, r, col as long)
if state.brushsize <= 1 then
circle (x, y), r, col
else
dim rp as single, rm as single, rp2 as single, rm2 as single
dim rpi2 as single, rmi2 as single, sp as single, sm as single
dim i as single
rp = r + state.brushsize / 2
rm = r - state.brushsize / 2
' If the brush is thicker than the circle, it's just a filled circle
if rm < 0 then
filledcircle x, y, rp, col
exit sub
end if
rp2 = rp ^ 2
rm2 = rm ^ 2
' Outer edges (Top/Bottom caps)
for i = -rp to -rm step .2
rpi2 = rp2 - i ^ 2
if rpi2 < 0 then rpi2 = 0 ' Safety Gate
sp = sqr(rpi2)
line (x + i, y - sp)-(x + i, y + sp), col, bf
next
' Side rings (where the hole in the middle exists)
for i = -rm to rm step .2
rpi2 = rp2 - i ^ 2
rmi2 = rm2 - i ^ 2
if rpi2 < 0 then rpi2 = 0 ' Safety Gate
if rmi2 < 0 then rmi2 = 0 ' Safety Gate
sp = sqr(rpi2)
sm = sqr(rmi2)
' Draw the top and bottom segments only
line (x + i, y + sm)-(x + i, y + sp), col, bf
line (x + i, y - sm)-(x + i, y - sp), col, bf
next
' Outer edges (Right cap)
for i = rm to rp step .2
rpi2 = rp2 - i ^ 2
if rpi2 < 0 then rpi2 = 0 ' Safety Gate
sp = sqr(rpi2)
line (x + i, y - sp)-(x + i, y + sp), col, bf
next
end if
end sub
sub filledcircle(x,y,r,col as long)
dim __radius as integer, radiuserror as integer
dim tx as integer, ty as integer
__radius=abs(r)-1
radiuserror=-__radius
tx=__radius
ty=0
line (x-tx,y)-(x+tx,y),col
while tx>ty
radiuserror=radiuserror+ty*2+1
if radiuserror >= 0 then
if tx<>ty+1 then
line (x-ty,y-tx)-(x+ty,y-tx),col
line (x-ty,y+tx)-(x+ty,y+tx),col
end if
tx=tx-1
radiuserror=radiuserror-tx*2
end if
ty=ty+1
line (x-tx,y-ty)-(x+tx,y-ty),col
line (x-tx,y+ty)-(x+tx,y+ty),col
wend
end sub
sub floodfill (x as integer, y as integer, fillcolor as long)
dim as integer leftx, rightx, currenty
dim as integer arrsize, stackptr
' Create a stack for storing coordinates
arrsize = 1000 ' Adjust based on expected complexity
redim stack(1 to arrsize, 1 to 2) as integer
stackptr = 0
' Get the color at starting point
dim startcolor as long
startcolor = point(x, y)
' If starting on boundary color or fill color, exit
if startcolor = fillcolor then exit sub
' Push starting point to stack
stackptr = stackptr + 1
stack(stackptr, 1) = x
stack(stackptr, 2) = y
' Process until stack is empty
do while stackptr > 0
' Pop a point from stack
x = stack(stackptr, 1)
y = stack(stackptr, 2)
stackptr = stackptr - 1
' Skip if current point is not startcolor
if point(x, y) <> startcolor then _continue
' Find leftmost point on this scanline
leftx = x
do while leftx > 0 and point(leftx - 1, y) = startcolor
leftx = leftx - 1
loop
' Find rightmost point on this scanline
rightx = x
do while rightx < _width - 1 and point(rightx + 1, y) = startcolor
rightx = rightx + 1
loop
' Fill the scanline
line (leftx, y)-(rightx, y), fillcolor
' Check scanline above
currenty = y - 1
if currenty >= 0 then
for x = leftx to rightx
if point(x, currenty) = startcolor then
' Push seed point to stack
stackptr = stackptr + 1
if stackptr > arrsize then
' Resize stack if needed
arrsize = arrsize * 2
redim _preserve stack(1 to arrsize, 1 to 2) as integer
end if
stack(stackptr, 1) = x
stack(stackptr, 2) = currenty
' Skip adjacent pixels of same color
do while x <= rightx and point(x, currenty) = startcolor
x = x + 1
loop
x = x - 1 ' Adjust for loop increment
end if
next x
end if
' Check scanline below
currenty = y + 1
if currenty < _height then
for x = leftx to rightx
if point(x, currenty) = startcolor then
' Push seed point to stack
stackptr = stackptr + 1
if stackptr > arrsize then
' Resize stack if needed
arrsize = arrsize * 2
redim _preserve stack(1 to arrsize, 1 to 2) as integer
end if
stack(stackptr, 1) = x
stack(stackptr, 2) = currenty
' Skip adjacent pixels of same color
do while x <= rightx and point(x, currenty) = startcolor
x = x + 1
loop
x = x - 1 ' Adjust for loop increment
end if
next x
end if
loop
end sub