In this step of the Bitmap Painting tool development, we will add some better stroke drawing code to avoid the dotted appearance.
NATURAL LANGUAGE
We will extend the existing MacroScript by adding a new function.
The new function will be passed the old and the new position of the mouse and a line will be drawn between the two points to define a continuous stroke.
SCRIPT:
macroScript MicroPaint category: "HowTo" ( global MicroPaint_CanvasRollout try (destroyDialog MicroPaint_CanvasRollout) catch() local isDrawing = false local bitmapX = bitmapY = 512 local theCanvasBitmap = bitmap bitmapX bitmapY color:white local currentPos = lastPos = [0,0] rollout MicroPaint_CanvasRollout "MicroPaint" ( bitmap theCanvas pos:[0,0] width:bitmapX height:bitmapY bitmap:theCanvasBitmap fn paintBrush pos = ( setPixels theCanvasBitmap pos #(color 0 0 0) ) fn drawStroke lastPos pos = ( currentPos = lastPos deltaX = pos.x - lastPos.x deltaY = pos.y - lastPos.y maxSteps = amax #(abs(deltaX),abs(deltaY)) deltaStepX = deltaX / maxSteps deltaStepY = deltaY / maxSteps for i = 0 to maxSteps do ( paintBrush currentPos currentPos += [deltaStepX, deltaStepY] ) theCanvas.bitmap = theCanvasBitmap ) on MicroPaint_CanvasRollout lbuttondown pos do ( lastPos = pos isDrawing = true drawStroke lastPos pos ) on MicroPaint_CanvasRollout lbuttonup pos do isDrawing = false on MicroPaint_CanvasRollout mousemove pos do ( if isDrawing do drawStroke lastPos pos lastPos = pos ) ) createDialog MicroPaint_CanvasRollout bitmapX bitmapY )
--Code in italic has no changes since the previous version. macroScript MicroPaint category:"HowTo"
(
global MicroPaint_CanvasRollout
try(destroyDialog CanvasRollout)catch()
local isDrawing = false
local bitmapX = bitmapY = 512
local theCanvasBitmap = bitmap bitmapX bitmapY color:white local currentPos = lastPos = [0,0]
The first change we will have to do is to define the current and the last known position variables that will be used to keep track of the current stroke. We initialize both to [0,0].
rolloutMicroPaint_CanvasRollout "MicroPaint" ( bitmap theCanvas pos:[0,0] width:400 height:400 bitmap:theCanvasBitmap fn paintBrush pos = ( setPixels theCanvasBitmap pos #(black) )
We will simplify the paintbrush function. It will only draw the point, but will not update the canvas. This is necessary because the stroke will contain a large number of brush points, but will have to be updated just once after the stroke to maintain interactivity.
fn drawStroke lastPos pos =
(
This will be the stroke drawing function called by the mouse handlers. Two arguments are passed to it - the last mouse position (beginning of the stroke) and the current mouse position (the end of the stroke).
currentPos = lastPos
The current position variable is initialized to the beginning of the stroke. It will be used to draw the line from the start to the end point of the stroke.
deltaX = pos.x - lastPos.x
deltaY = pos.y - lastPos.y
To draw a straight line from the last to the new position, we must know how far these two points are from each other along both X and Y.
maxSteps = amax #(abs(deltaX),abs(deltaY))
Then, we compare the absolute values along X and Y to see which one is larger. MaxSteps will be equal to either the number of pixels between the two along X or along Y.
deltaStepX = deltaX / maxSteps
deltaStepY = deltaY / maxSteps
Now, we calculate the increment per step we will need for the X and Y axis. If maxSteps is equal to the distance along X, then deltaStepX will be +1 or -1, while deltaStepY will be a number less than 1.0. If maxSteps is equal to the distance along Y, then deltaStepY will be +1 or -1, and deltaStepX will be < 1.0.
for i = 0 to maxSteps do
(
Now, we loop from 0 to the number of steps,
paintBrush currentPos
paint a black dot at the current position by calling our custom paintbrush function,
currentPos += [deltaStepX, deltaStepY]
and then increment the current position with the deltaStep values until the current mouse position is reached.
)
theCanvas.bitmap = theCanvasBitmap
Finally, when the stroke is done, we update the bitmap in the rollout.
) on MicroPaint_CanvasRollout lbuttondown pos do
(
lastPos = pos
If the user pressed the mouse button, we will have to reset the stroke to the currently clicked point.
isDrawing = true drawStroke lastPos pos
Instead of calling the PaintBrush function, we call the drawStroke function and pass the last and the current position (which are equal at this point) to it. This will create a single dot at the clicked point (the stroke has length 0, both deltaX and deltaY are 0, thus maxSteps is 0, but since the for i loop starts counting at 0, we get at least one iteration to draw the point).
) on MicroPaint_CanvasRollout mousemove pos do ( if isDrawing do drawStroke lastPos pos on MicroPaint_CanvasRollout lbuttonup pos do isDrawing = false
Instead of calling the PaintBrush function, we call the drawStroke function again. At this point, the lastPos and the pos values are different and require a longer stroke to be drawn.
lastPos = pos
After the stroke is drawn, we record the current mouse position into the lastPos variable to be used as the starting point of the next stroke.
)
)
createDialog MicroPaint_CanvasRollout bitmapX bitmapY
)
Previous Tutorial:
How To ... Develop a Bitmap Painting Tool - Basic Utility
Next Tutorial:
How To ... Develop a Bitmap Painting Tool - Brush Size and Color