Drawing
All drawing goes through the gfx table and lands on a canvas the size of the panel. The canvas is copied to the LEDs after _draw returns.
The calls
Section titled “The calls”| Call | What it draws |
|---|---|
gfx.cls(r, g, b) |
Fills the canvas. gfx.cls() with no arguments fills with black |
gfx.pset(x, y, r, g, b) |
One pixel |
gfx.rectfill(x, y, w, h, r, g, b) |
A filled rectangle with its top-left corner at x, y |
gfx.line(x0, y0, x1, y1, r, g, b) |
A line between two points, one pixel wide |
gfx.width(), gfx.height() |
The panel size in pixels |
- Coordinates count from the top-left pixel,
(0, 0).xgrows to the right andygrows downwards. The bottom-right pixel is(gfx.width() - 1, gfx.height() - 1). - Colours are three numbers from 0 to 255: red, green, blue. Values outside that range are clamped.
- Anything off the canvas is ignored. You can draw a rectangle that hangs over the edge, or a pixel at
(-5, 200), without an error. - Coordinates are whole pixels. Pass
math.floor(x)when your position is a fraction, so a moving shape does not shimmer.
Order matters
Section titled “Order matters”Later calls draw over earlier ones. Clear first, then draw back to front:
function _draw() gfx.cls(10, 10, 30) -- sky gfx.rectfill(0, 48, 64, 16, 20, 90, 30) -- ground gfx.rectfill(20, 30, 12, 18, 150, 80, 40) -- house gfx.line(20, 30, 26, 22, 200, 60, 60) -- roof gfx.line(26, 22, 32, 30, 200, 60, 60)endA small sprite
Section titled “A small sprite”There is no sprite call; a sprite is a loop over a table of rows. Strings make compact rows:
local SHIP = { "..#..", ".###.", "#####", "#.#.#",}
local function sprite(rows, left, top, r, g, b) for row, line in ipairs(rows) do for column = 1, #line do if line:sub(column, column) == "#" then gfx.pset(left + column - 1, top + row - 1, r, g, b) end end endend
function _draw() gfx.cls() sprite(SHIP, 30, 50, 120, 220, 255)endPacked colours
Section titled “Packed colours”If you set the same colour many times, pack it once and use gfx.pset565:
local white = gfx.rgb(255, 255, 255) -- one number, in the panel's own format
function _draw() gfx.cls() for x = 0, gfx.width() - 1, 2 do gfx.pset565(x, 10, white) endendgfx.rgb(r, g, b) returns the colour as a 16-bit number (5 bits of red, 6 of green, 5 of blue). That is also the precision of the canvas: neighbouring shades that differ by less than 8 in red or blue, or 4 in green, come out the same.
Filling the whole screen
Section titled “Filling the whole screen”Setting every pixel with gfx.pset in a Lua loop works, and for simple patterns it is fast enough:
local t = 0
function _update(dt) t = t + dtend
function _draw() local shift = math.floor(t * 40) for y = 0, gfx.height() - 1 do for x = 0, gfx.width() - 1 do gfx.pset(x, y, (x * 4 + shift) & 255, (y * 4) & 255, 128) end endendWhen every pixel needs real math, a fragment shader is the better tool, and a compiled one is much faster than this loop.
Next: Animation and uniforms.