diff --git a/pixler.bas b/pixler.bas index b69973c..bfda553 100644 --- a/pixler.bas +++ b/pixler.bas @@ -21,6 +21,8 @@ end type redim shared layers(3) as layertype dim shared state as statetype +dim shared showtoolbox as _byte: showtoolbox=-1 +dim shared showcolorpicker as _byte: showcolorpicker=-1 dim shared mouseclicked as integer dim shared mousedown as integer @@ -86,13 +88,21 @@ do state.offsetY = state.offsetY + (_mousey - lastMY) end if lastMX = _mousex: lastMY = _mousey - + ' Zooming - if mw <> 0 then - state.zoom = state.zoom + (mw * 0.1) - if state.zoom < 0.1 then state.zoom = 0.1 - mw=0 - end if + if mw <> 0 then + ' 1. Capture the current world position under the mouse + dim mouseWorldX as single: mouseWorldX = (_mousex - state.offsetX) / state.zoom + dim mouseWorldY as single: mouseWorldY = (_mousey - state.offsetY) / state.zoom + ' 2. Calculate the new zoom level + state.zoom = state.zoom + (mw * 0.1 * state.zoom) ' Multiplier makes it feel smoother + if state.zoom < 0.05 then state.zoom = 0.05 + if state.zoom > 20 then state.zoom = 20 + ' 3. Adjust offsets so the world position stays under the mouse + state.offsetX = _mousex - (mouseWorldX * state.zoom) + state.offsetY = _mousey - (mouseWorldY * state.zoom) + mw = 0 + end if ' Keyboarding keyin=inkey$ @@ -105,12 +115,19 @@ do 'TODO: save logic case chr$(27)' esc 'TODO: main menu - + case "h" + state.zoom = 1.0 + state.offsetX = (_width / 2) - (_width(layers(0).ihandle) / 2) + state.offsetY = (_height / 2) - (_height(layers(0).ihandle) / 2) + case "t" + showtoolbox=not showtoolbox + case "c" + showcolorpicker=not showcolorpicker end select - canvas - toolbox - colorpicker + canvas + if showtoolbox then toolbox + if showcolorpicker then colorpicker _limit 30 _display @@ -155,26 +172,59 @@ sub colorpicker end sub sub canvas - dim boxX1 as integer: boxX1 = 70 - dim boxWidth as integer: boxWidth = _width - 1 - boxX1 - dim boxHeight as integer: boxHeight = _height - 20 - static polypoints(200) as single - static pointCount as integer - + ' 1. Define the Viewport (The "Window" on your screen) + dim viewX1 as integer + if showtoolbox then viewX1 = 70 else viewX1 = 0 + dim viewY1 as integer: viewY1 = 0 + dim viewX2 as integer: viewX2 = _width - 1 + dim viewY2 as integer + if showcolorpicker then viewY2 = _height - 20 else viewY2 = _height - 1 + _dest 0 - line (boxX1, 0)-(_width - 1, boxHeight), _rgb32(32), bf + + ' 2. Render Layers with Clipping dim i as integer for i = 0 to ubound(layers) - dim w as integer: w = _width(layers(i).ihandle) * state.zoom - dim h as integer: h = _height(layers(i).ihandle) * state.zoom - _putimage (state.offsetX, state.offsetY)-(state.offsetX + w, state.offsetY + h), layers(i).ihandle + dim img as long: img = layers(i).ihandle + dim imgW as integer: imgW = _width(img) + dim imgH as integer: imgH = _height(img) + + ' Current scaled dimensions + dim fullScaledW as single: fullScaledW = imgW * state.zoom + dim fullScaledH as single: fullScaledH = imgH * state.zoom + + ' Calculate visible area in screen coordinates (Overlap of image and viewport) + dim drawX1 as single: drawX1 = state.offsetX + dim drawY1 as single: drawY1 = state.offsetY + dim drawX2 as single: drawX2 = state.offsetX + fullScaledW + dim drawY2 as single: drawY2 = state.offsetY + fullScaledH + + ' Clip the destination to the Viewport + if drawX1 < viewX1 then drawX1 = viewX1 + if drawY1 < viewY1 then drawY1 = viewY1 + if drawX2 > viewX2 then drawX2 = viewX2 + if drawY2 > viewY2 then drawY2 = viewY2 + + ' Only draw if the image is actually inside the viewport + if drawX2 > drawX1 and drawY2 > drawY1 then + ' Map screen-clipped coordinates back to the source image coordinates + dim srcX1 as single: srcX1 = (drawX1 - state.offsetX) / state.zoom + dim srcY1 as single: srcY1 = (drawY1 - state.offsetY) / state.zoom + dim srcX2 as single: srcX2 = (drawX2 - state.offsetX) / state.zoom + dim srcY2 as single: srcY2 = (drawY2 - state.offsetY) / state.zoom + + ' Syntax: _PUTIMAGE (destX1, destY1)-(destX2, destY2), sourceHandle, 0, (srcX1, srcY1)-(srcX2, srcY2) + _putimage (drawX1, drawY1)-(drawX2, drawY2), img, 0, (srcX1, srcY1)-(srcX2, srcY2) + end if next + ' 3. Calculate Canvas Coordinates dim canX as integer: canX = (_mousex - state.offsetX) / state.zoom dim canY as integer: canY = (_mousey - state.offsetY) / state.zoom - dim drawCol as _unsigned long - drawCol = state.fcolor + static drawCol + if _mousebutton(1) then drawCol = state.fcolor + if _mousebutton(2) then drawCol = state.bcolor ' 4. Interaction Logic if _mousex > boxX1 then @@ -189,7 +239,9 @@ sub canvas end if _dest 0 _source 0 + exit sub end if + if state.tool = 7 or state.tool = 8 then if mouseclicked then polypoints(pointCount * 2) = canX @@ -211,7 +263,7 @@ sub canvas cls , 0 select case state.tool - case 1 ' Pencil: This is the only tool that writes to Layer 1 IMMEDIATELY + case 1 ' Pencil _dest layers(1).ihandle thickline state.startX, state.startY, canX, canY, drawCol state.startX = canX: state.startY = canY @@ -233,9 +285,9 @@ sub canvas case 7, 8 ' Polygons if pointCount > 0 then for p = 1 to pointCount - 1 - thickline polypoints((p - 1) * 2), polypoints((p - 1) * 2 + 1), polypoints(p * 2), polypoints(p * 2 + 1), drawCol + thickline polypoints((p - 1) * 2), polypoints((p - 1) * 2 + 1), polypoints(p * 2), polypoints(p * 2 + 1), state.fcolor next p - thickline polypoints((pointCount - 1) * 2), polypoints((pointCount - 1) * 2 + 1), canX, canY, drawCol + thickline polypoints((pointCount - 1) * 2), polypoints((pointCount - 1) * 2 + 1), canX, canY, state.fcolor end if end select @@ -244,7 +296,7 @@ sub canvas if state.tool = 7 or state.tool = 8 then if rmouseclicked then commit = -1 else - if mousedown = 0 then commit = -1 + if (mousedown=0) and (rmousedown=0) then commit = -1 end if if commit then @@ -252,7 +304,7 @@ sub canvas if (state.tool = 8 or state.tool=7) and pointCount > 2 then redim finalP(pointCount * 2 - 1) as long for p = 0 to (pointCount * 2) - 1: finalP(p) = polypoints(p): next - if state.tool =8 then filledPolygon finalP(), drawCol else Polygon finalP(), drawCol + if state.tool =8 then filledPolygon finalP(), state.fcolor else Polygon finalP(), state.fcolor else ' Merge the preview into the drawing layer _putimage , layers(2).ihandle, layers(1).ihandle @@ -264,7 +316,7 @@ sub canvas end if end if end if - _dest 0 ' Ensure we return to main screen[cite: 1] + _dest 0 ' Ensure we return to main screen end sub function icon (index as long) @@ -274,11 +326,11 @@ function icon (index as long) redim icons(19) as long ' Room for 20 icons ' Define your specific tool icons here - icons(0) = _newimage(32, 32, 32): _dest icons(0): line (5, 27)-(27, 5): _dest 0 - icons(1) = _newimage(32, 32, 32): _dest icons(1): circle (15, 15), 13: _dest 0 - icons(2) = _newimage(32, 32, 32): _dest icons(2): line (5, 5)-(27, 27), , b: _dest 0 - icons(6) = _newimage(32, 32, 32): _dest icons(6) - line (5, 15)-(15, 5): line -(25, 15): line -(20, 25): line -(10, 25): line -(5, 15) + icons(0) = _newimage(32,32,32): _dest icons(0): line (5, 27)-(27, 5): _dest 0 + icons(1) = _newimage(32,32,32): _dest icons(1): circle (15, 15), 13: _dest 0 + icons(2) = _newimage(32,32,32): _dest icons(2): line (5, 5)-(27, 27), , b: _dest 0 + icons(6) = _newimage(32,32,32): _dest icons(6) + line (5,15)-(15,5):line -(25,15):line -(20,25): line -(10,25):line -(5,15) _dest 0 icons(7) = _newimage(32, 32, 32): _dest icons(7) @@ -311,6 +363,7 @@ end function '$include: 'include/imgout.bm' '$include: 'include/palette.bm' '$include: 'include/tools.bm' +''$include: 'include/effects.bm' function adduiicon(imagehandle as long) dim unknown as long