The Drawing canvas object provides a drawing surface that you can draw your own content on to using some drawing actions. This includes basic geometric shapes like rectangles, lines, polygons and ellipses, as well as the ability to paste other objects in to the canvas.
The colors for drawing commands or pixels, such as the color to fill a rectangle, are typically specified with the rgba system expression. This specifies the red, green, blue and alpha components of the color in the range 0-100. The rgba255 expression is identical but uses a 0-255 scale that artists may be more familiar with. The rgbEx and rgbEx255 expressions can also be used, but do not provide a parameter for alpha, so will act as if the alpha was fully opaque.
Handling resizing and resolution
By default, the canvas uses the same display resolution as the game. However the display resolution usually changes when the window is resized. For example in letterbox scale mode, when the window is resized larger the game displays the same content but at a larger size (using more pixels). A similar thing happens when you resize the object itself. The Drawing canvas object automatically changes the resolution of its canvas when this happens. This is destructive, though: the next draw to the canvas will clear it, because internally the drawing surface is destroyed and recreated at the new resolution.
The reason it waits until the next draw to recreate the drawing surface is so that if you draw to it once, the same content is simply displayed stretched at the new resolution. This is often an acceptable result after drawing in On start of layout. Normally a better idea is to draw one-off content in the trigger On resolution changed - this also triggers on startup, and again any time the resolution changes, ensuring your content can increase in detail if the window is resized larger.
Alternatively if you clear and re-render the canvas in Every tick, since it is always redrawing it will always draw at the current resolution. This approach is similar to how the runtime itself renders, although you may want to stop drawing if nothing is changing in the game, which is also what the runtime does.
The Drawing canvas object allows you to draw shapes and lines, using a co-ordinate system relative to the object in layout co-ordinates. For example if the object is sized 100x100 in the layout, then the point (50, 50) is always in the middle of the canvas, regardless of the resolution. This means you don't need to change the drawing co-ordinates depending on the canvas resolution: everything scales automatically, so if the user resizes the window larger, content automatically increases in detail.
The one exception to this is using snapshots to read and write pixel data. In this case snapshot pixels are given in actual pixel co-ordinates rather than object co-ordinates. The PixelScale expression also gives the size of an actual pixel on the drawing surface in object co-ordinates, allowing you to convert between object and pixel co-ordinates.
Pixel manipulation with snapshots
The way computer graphics works makes requesting to retrieve the color of even just a single pixel an extremely costly operation. Rendering is highly optimised to go one way: sending drawing commands from the CPU, rendering on the GPU, and then displaying the result on the user's screen. Getting the color of a pixel back to the CPU goes in the opposite direction, and if the system has to wait for the result, it would completely stall the rendering process, almost certainly janking the framerate.
In order to avoid the performance pitfalls while allowing access to individual pixels, the Drawing canvas object uses a snapshot system, which works like this:
- The Save snapshot action copies the entire canvas image on the GPU.
- The copied image is then sent asynchronously (in parallel) back to the CPU. Rendering can continue while this happens.
- When the copied image is available on the CPU, On snapshot triggers. Now the pixel data can be read using the snapshot expressions, e.g. SnapshotRedAt(x, y).
- If the pixel data needs to be altered, it can be modified using the Set snapshot pixel action. This only changes the copy available to the CPU and does not visibly affect the canvas. To make changes visible, use the Load snapshot action, which copies the snapshot back to the canvas.
The Noise textures example demonstrates how to do this, writing random pixel data generated by the Advanced Random object.
Drawing canvas properties
- Initially visible
- Whether the object is initially visible at runtime.
- Choose the location of the object origin relative to its box.
- Enable multisample antialiasing (MSAA) for better quality drawing. For example normally polygon and line edges will be hard ("jagged"). Enabling antialiasing improves the quality of the edges (making them "softer"), but makes rendering slower and uses more memory. Higher levels of antialiasing reduce performance further. This option requires WebGL 2+, and not all devices support all levels of antialiasing. For example if you select 8x MSAA but a particular device only supports 4x MSAA, it will fall back to 4x MSAA instead.
Drawing canvas conditions
- On resolution changed
- Triggered when the display resolution of the canvas changes, e.g. due to resizing the window in Letterbox scale mode. See the section on Handling resizing and resolution above. If you draw to the canvas in this trigger, it will mean the canvas image always automatically scales to the display resolution. If you do not draw to the canvas in this trigger, it will simply display the old image stretched to the new size.
- On saved image
- Triggered after the Save image action when the saved image is ready. The image can be accessed using the SavedImageURL expression, e.g. to download it using the Browser object's Invoke download action.
- On snapshot
- Triggered after the Save snapshot action when the snapshot is ready. This allows reading and writing individual pixels in the snapshot image, e.g. using the SnapshotRedAt expression. See the section Pixel manipulation with snapshots above for more information.
Drawing canvas - canvas actions
This group of actions generally relates to the canvas image as a whole.
- Clear snapshot
- Release a snapshot saved with the Save snapshot action, saving the memory used to store it. This returns the state to as if no snapshot was taken at all. Any expressions attempting to retrieve snapshot pixels after this action will return 0.
- Load snapshot
- Copy the snapshot in memory back to the canvas, so any changes to its pixel data become visible in the object. The snapshot must match the resolution of the canvas - if the resolution has changed, the snapshot cannot be loaded. Note this still leaves the snapshot in memory - use the Clear snapshot action to remove it and save memory if the snapshot is no longer needed.
- Save image
- Save the current canvas image in a compressed format (PNG or JPEG) suitable for the user to download. A subset of the canvas area can be saved (e.g. for saving a cropped image) by specifying the X, Y, Width and Height parameters, all given in device pixels. The expressions SurfaceDeviceWidth and SurfaceDeviceHeight give the size of the canvas in device pixels. The default (leaving all values as zero) will save the entire canvas area. This action triggers On saved image when ready, and sets the SavedImageURL expression to a URL that can be downloaded.
- Save snapshot
- Copy the current canvas image to make its pixel data available. Triggers On snapshot when ready. For more information see the section Pixel manipulation with snapshots above.
- Set snapshot pixel
- Set the color of a pixel in the saved snapshot. A snapshot must have previously been taken and On snapshot triggered. Unlike the other drawing commands, this takes a position in pixel co-ordinates. Use the rgba expression to set the pixel color to the given red, green, blue and alpha components. Note changes will not be visible until the Load snapshot action is used.
Drawing canvas - general actions
This group of actions provides general drawing actions such as filling rectangles and drawing lines. Drawing polygons involves more actions so is separated out in to its own group.
- Clear canvas
- Clear the entire canvas to a color. This overwrites all existing image content. For example clearing to transparent will make the entire canvas transparent, unlike drawing a transparent rectangle which will not make any visible difference.
- Clear rectangle
- As with Clear canvas, but only clears a rectangular area on the canvas.
- Dashed line
- Draw a line between two points on the canvas, specifying the color and thickness of the line. The line cap specifies whether the end of the line ends exactly at the start and end points (Butt) or is squared off, extending slightly beyond the start and end points (Square). The Dashed line variant also allows specifying a Dash length, which alternates between the line color and transparency for a dash effect.
- Fill ellipse
- Outline ellipse
- Draw either a filled or outlined ellipse shape on the canvas. The shape is specified using the center point and the radius on the X and Y axes. If the radius on both axes is the same, the shape will be a circle. The outline variant also specifies the thickness of the outline. The edge can also be set to Hard for an aliased edge (suitable for pixellated games), or Smooth for a better quality soft-edged appearance.
- Fill linear gradient
- Fill a rectangular area on the canvas with a linear gradient from one color to another. The gradient direction can be either horizontal or vertical.
- Fill rectangle
- Outline rectangle
- Draw either a filled or outlined rectangle shape on the canvas. The outline variant also specifies the thickness of the outline.
- Paste object
- Draw all instances of the given object that are overlapping the canvas onto the canvas at their current positions. By default objects are drawn exactly as they appear, taking in to account any effects added to them; drawing without effects will draw as if all the object's effects were disabled.
- Set drawing blend
- Set the background blending mode used for all drawing operations except Paste object (which takes the blend mode from the object being pasted). The options match the same blend modes as can be used by objects, but applies to the drawing to the canvas, rather than the display of the Drawing Canvas object itself. Two useful options are setting the "copy" blend mode and drawing with transparency to clear an area, or using "destination out" to erase content.
Drawing canvas - polygon actions
This group of actions allows for drawing polygon shapes. Use Add poly point multiple times to add points. Then outlined or filled polygons can be drawn. Use Reset poly to clear added points and start again.
- Add poly point
- Add a new point to the current polygon. At least three points must be added before a polygon can be drawn.
- Outline poly
- Dashed outline poly
- Draw dashed lines between the points of the current polygon, joining back to the start point. The parameters are similar to the Line and Dashed line actions.
- Fill poly
- Fill the current polygon area with a color.
- Reset poly
- Clear all polygon points that were added, so the next Add poly point action starts a new polygon.
Drawing canvas expressions
- The size of a single canvas pixel in object co-ordinates. See the section Co-ordinate systems above for more information.
- In On saved image, the URL of the saved image. This can be downloaded using the Browser object's Invoke download action.
- SnapshotRedAt(x, y)
- SnapshotGreenAt(x, y)
- SnapshotBlueAt(x, y)
- SnapshotAlphaAt(x, y)
- Return the red, green, blue and alpha components of a pixel in a saved snapshot. The position is given in pixel co-ordinates, and the returned value is returned in the 0-100 range. For more information see the section Pixel manipulation with snapshots above.
- Return the size of a saved snapshot in pixels. For more information see the section Pixel manipulation with snapshots above.
- Returns the current size of the canvas surface in device pixels. These are useful to use when defining a subset area to use in the Save image action.