How To ... Develop a Bitmap Painting Tool - Basic Utility

The original code of the complete advanced version was developed in less than an hour and showcases the flexibility of MAXScript for prototyping applications of any kind.

Here is the very basic initial version:

NATURAL LANGUAGE

We will develop a simple MacroScript that creates a dialog from a rollout.

The rollout will contain only a bitmap UI control

The user will paint by pressing the left mouse button and dragging the mouse inside the bitmap.

The brush will be a single black dot - if the mouse moves fast, the strokes will appear dotted.

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

   rollout MicroPaint_CanvasRollout "MicroPaint"
   (
    bitmap theCanvas pos:[0,0] width:bitmapX height:bitmapY bitmap:theCanvasBitmap
    fn paintBrush pos =
    (
     setPixels theCanvasBitmap pos #(black)
     theCanvas.bitmap = theCanvasBitmap
    )
    on MicroPaint_CanvasRollout lbuttondown pos do
    (
     isDrawing = true
     paintBrush pos
    )
    on MicroPaint_CanvasRollout lbuttonup pos do isDrawing = false
    on MicroPaint_CanvasRollout mousemove pos do if isDrawing do paintBrush pos
   )
   createDialog MicroPaint_CanvasRollout bitmapX bitmapY
   )

Step-By-Step

macroScript MicroPaint category:"HowTo" (

We define a macroScript called MicroPaint which will appear in the "HowTo" category.

global MicroPaint_CanvasRollout

In order to be able to close any existing dialog from previous sessions, we define the variable of the rollout to be used as dialog as a global variable.

Local and Global Variables

try(destroyDialog CanvasRollout)catch()

Then we try to destroy any existing dialog from a previous session. If there is none, the try()catch() error trap will prevent any error messages.

Try Expression

local isDrawing = false

This local variable will be used as a flag for enabling drawing. When the variable is false, the mouse move event handler will not draw. When the left mouse button has been pressed, this variable will be set to true and allow drawing until the left mouse button is released.

BooleanClass Values

local bitmapX = bitmapY = 512

These local variables will contain the size of the bitmap to be painted. Simply changing this value would resize the tool to paint on a different canvas size!

local theCanvasBitmap = bitmap bitmapX bitmapY color:white

This variable will contain the canvas to draw on. We initialize it to a white bitmap with a size of 400 by 400 pixels.

Bitmap Values

rollout MicroPaint_CanvasRollout "MicroPaint" (

This is the rollout which will define the dialog with the bitmap canvas.

bitmap theCanvas pos:[0,0] width:bitmapX height:bitmapY bitmap:theCanvasBitmap 

This is the bitmap User Interface control. It is aligned to the upper left corner of the rollout and displays the 400 by 400 canvas bitmap.

Bitmap

Note:

that there are two different constructors with the name bitmap - the User Interface control used here and the bitmap value constructor used two lines higher! MAXScript knows which one you have in mind based on the context - if you are inside a rollout definition scope and type in

bitmap my_bmp width:100 height:100

MAXScript will create a User Interface control.

If you are inside the same rollout and type in

local my_bmp = bitmap 100 100

a new local bitmap value will be created and NOT a User Interface control!

fn paintBrush pos = (

This function will be called to draw a point on the bitmap. The argument pos will contain the 2D coordinates to place the new point at.

Defining Custom Functions

setPixels theCanvasBitmap pos #(black)

setPixels is used to change the color of one or more pixels in a row. The pos defines the location in the bitmap (where 0,0 is the upper left corner) the paining should start at.The colors to be changes are provided in an array. In our case, the array contains a single element, the color black.

setpixels

theCanvas.bitmap = theCanvasBitmap

After the black point is drawn into the bitmap, we assign it to the user interface control to update the drawing.

) onMicroPaint_CanvasRollout lbuttondown pos do (

This dialog event handler is called whenever the left mouse button is pressed while the mouse is located over the rollout. The argument pos will contain the 2D position in rollout coordinates.

CreateDialog

isDrawing = true

We raise the flag to notify the mousemove handler (see below) that the drawing can be started.

paintBrush pos

We also call the paintbrush function by passing the currently clicked point to it. This way, simply clicking without moving the mouse will cause a black point to be placed on the bitmap.

 ) on MicroPaint_CanvasRollout lbuttonup pos do isDrawing = false

This dialog event handler is called whenever the left mouse button is released. We just lower the flag again so the drawing can be stopped.

on MicroPaint_CanvasRollout mousemove pos do if isDrawing do paintBrush pos

This dialog event handler is called whenever the mouse movies over the rollout, regardless of the button state. The argument pos contains the 2D position in pixels inside the rollout, coinciding with the position in pixels inside the bitmap (remember? Both have the same origin [0,0].

We check to see whether the left mouse button has been pressed but not released yet by looking into the isDrawing variable. If it contains true, we call the drawing paintbrush function with the current position of the mouse inside the dialog.

) createDialogMicroPaint_CanvasRollout bitmapX bitmapY

Finally, we create a dialog using the rollout we just defined.

)

Result

Next Tutorial:

How To ... Develop a Bitmap Painting Tool - Strokes Support