This commit is contained in:
visionmercer 2026-04-30 13:16:00 +02:00
commit b4678feada
2 changed files with 235 additions and 32 deletions

145
include/tools.bm Normal file
View file

@ -0,0 +1,145 @@
sub filledPolygon (Points() as single, 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(i - 1), pa(i - 2),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

View file

@ -5,6 +5,10 @@ type statetype
offsetX as single offsetX as single
offsetY as single offsetY as single
zoom as single zoom as single
brushsize as integer
startX as integer
startY as integer
isDrawing as integer
end type end type
type layertype type layertype
@ -14,11 +18,10 @@ type layertype
kind as long kind as long
end type end type
redim shared layers(1) as layertype redim shared layers(2) as layertype
dim shared state as statetype dim shared state as statetype
dim shared mouseclicked as integer dim shared mouseclicked as integer
dim shared mousedown as integer dim shared mousedown as integer
dim shared rmouseclicked as integer dim shared rmouseclicked as integer
@ -33,6 +36,7 @@ dim as integer ch1,ch2,ch3,bt
loadpalette "endesga16",pal() loadpalette "endesga16",pal()
layers(0).ihandle=_newimage(640,350,32) layers(0).ihandle=_newimage(640,350,32)
layers(1).ihandle=_newimage(640,350,32) layers(1).ihandle=_newimage(640,350,32)
layers(2).ihandle=_newimage(640,350,32)
_dest layers(0).ihandle _dest layers(0).ihandle
line (0,0)-(_width-1,_height-1),_rgb32(255),bf line (0,0)-(_width-1,_height-1),_rgb32(255),bf
_dest 0 _dest 0
@ -42,11 +46,13 @@ state.bcolor = 2
state.zoom = 1.0 state.zoom = 1.0
state.offsetX = 70 + 20 ' To the right of the toolbox state.offsetX = 70 + 20 ' To the right of the toolbox
state.offsetY = 20 state.offsetY = 20
state. brushsize = 1
dim lastMX, lastMY dim lastMX, lastMY
dim diffX as integer dim diffX as integer
dim diffY as integer dim diffY as integer
dim oldWidth as integer dim oldWidth as integer
dim oldHeight as integer dim oldHeight as integer
dim keyin as string
oldWidth=_width oldWidth=_width
oldHeight=_height oldHeight=_height
@ -62,9 +68,9 @@ do
cls cls
line (0,0)-(_width-1,_height-1),backgroundcolor1,bf line (0,0)-(_width-1,_height-1),backgroundcolor1,bf
while _mouseinput:mw=mw+_mousewheel:wend
' --- Global Mouse Handling (Left & Right) --- 'Mouse Handling
while _mouseinput:mw=mw+_mousewheel:wend
mouseclicked = 0 mouseclicked = 0
rmouseclicked = 0 rmouseclicked = 0
if mousedown = -1 and _mousebutton(1) = 0 then mouseclicked = -1 if mousedown = -1 and _mousebutton(1) = 0 then mouseclicked = -1
@ -85,10 +91,19 @@ do
if state.zoom < 0.1 then state.zoom = 0.1 if state.zoom < 0.1 then state.zoom = 0.1
mw=0 mw=0
end if end if
'state.zoom=mw/100
canvas ' Uses mousedown and rmousedown for drawing/erasing ' Keyboarding
keyin=inkey$
select case keyin
case "+"
state.brushsize=state.brushsize+1
case "-"
if state.brushsize>1 then state.brushsize=state.brushsize-1
end select
_dest 0
canvas 'draw canvas first so it doesn't over
toolbox toolbox
colorpicker ' Uses rmouseclicked for bcolor colorpicker
_limit 30 _limit 30
_display _display
@ -140,7 +155,7 @@ sub canvas
' Workspace background ' Workspace background
line (boxX1, 0)-(_width - 1, boxHeight), _rgb32(32), bf line (boxX1, 0)-(_width - 1, boxHeight), _rgb32(32), bf
' Render Layers with Zoom/Offset[cite: 4] ' Render Layers (0 = background,1 = drawlayer, 2=reference 3 = Preview)
dim i as integer dim i as integer
for i = 0 to ubound(layers) for i = 0 to ubound(layers)
dim w as integer: w = _width(layers(i).ihandle) * state.zoom dim w as integer: w = _width(layers(i).ihandle) * state.zoom
@ -148,31 +163,73 @@ sub canvas
_putimage (state.offsetX, state.offsetY)-(state.offsetX + w, state.offsetY + h), layers(i).ihandle _putimage (state.offsetX, state.offsetY)-(state.offsetX + w, state.offsetY + h), layers(i).ihandle
next next
' --- Drawing Logic (Multi-Button) --- ' Translate Mouse to Canvas Space
if (mousedown or rmousedown) and _mousex > boxX1 then dim canX as integer: canX = (_mousex - state.offsetX) / state.zoom
' Translate to Canvas Space dim canY as integer: canY = (_mousey - state.offsetY) / state.zoom
dim canX as integer: canX = (_mousex - state.offsetX) / state.zoom
dim canY as integer: canY = (_mousey - state.offsetY) / state.zoom
' Boundary Check ' Color Selection: Left Click = Foreground, Right Click = Background
if canX >= 0 and canX < _width(layers(0).ihandle) then dim drawCol as _unsigned long
if canY >= 0 and canY < _height(layers(0).ihandle) then if mousedown or mouseclicked then drawCol = state.fcolor else drawCol = state.bcolor
_dest layers(0).ihandle
' Select color based on button pressed ' Interaction Boundary Check
dim drawCol as _unsigned long if _mousex > boxX1 then
if mousedown then drawCol = state.fcolor else drawCol = state.bcolor ' On Initial Click: Set the anchor point for shapes
if (mousedown or rmousedown) and state.isDrawing = 0 then
state.startX = canX
state.startY = canY
state.isDrawing = -1
end if
' Apply Tool if state.isDrawing then
if state.tool = 1 then ' preview layer handles the "rubber-banding" of shapes
pset (canX, canY), drawCol _dest layers(2).ihandle
elseif state.tool = 2 then cls , 0
' Example: Square brush
line (canX - 1, canY - 1)-(canX + 1, canY + 1), drawCol, bf
end if
_dest 0 select case state.tool
case 1 ' Pencil (Direct to Canvas)
_dest layers(1).ihandle
thickline state.startX, state.startY, canX, canY, drawCol
state.startX = canX: state.startY = canY
case 2 ' Straight Line
thickline state.startX, state.startY, canX, canY, drawCol
case 3 ' Thick Circle (Outline)
dim r as single: r = sqr((canX - state.startX)^2 + (canY - state.startY)^2)
r=abs(r)+1
thickcircle state.startX, state.startY, r, drawCol
case 4 ' Filled Circle
dim r_fill as single: r_fill = sqr((canX - state.startX)^2 + (canY - state.startY)^2)
filledcircle state.startX, state.startY, r_fill, drawCol
case 5 ' Rectangle Outline (using thickline)
thickline state.startX, state.startY, canX, state.startY, drawCol
thickline canX, state.startY, canX, canY, drawCol
thickline canX, canY, state.startX, canY, drawCol
thickline state.startX, canY, state.startX, state.startY, drawCol
case 6 ' Filled Rectangle
line (state.startX, state.startY)-(canX, canY), drawCol, bf
case 7
case 8 ' Polygon Outline (using thickline)
' Simple preview of a line; complex polygons usually require
' a point-collection state machine.
thickline state.startX, state.startY, canX, canY, drawCol
end select
' Release Logic: Commit preview to permanent layer
if _mousebutton(1) = 0 and _mousebutton(2) = 0 then
_dest layers(1).ihandle
_putimage , layers(2).ihandle
_dest layers(2).ihandle
cls , 0
state.isDrawing = 0
end if end if
_dest 0
end if end if
end if end if
end sub end sub
@ -208,6 +265,7 @@ end function
'$include: 'include/ui.bm' '$include: 'include/ui.bm'
'$include: 'include/imgout.bm' '$include: 'include/imgout.bm'
'$include: 'include/palette.bm' '$include: 'include/palette.bm'
'$include: 'include/tools.bm'
function adduiicon(imagehandle as long) function adduiicon(imagehandle as long)
dim unknown as long dim unknown as long