Skip to content

Source: draw.h

draw

Bounds-clipped, integer-only drawing from 1D through 3D over the flat light buffer.

The Bresenham walk and the clipping live here once, so an effect calls line rather than re-rolling it.

Classes

Name Description
Canvas The surface a draw call writes to: a buffer plus the grid dimensions that address it.
BlobPath One blob's orbit: where it sits at time t on a grid of w by h.
UpscaleTap One destination column's blend: the two source columns and the weight between them.

Canvas

struct Canvas
src/light/powerfunctions/draw.h:58

The surface a draw call writes to: a buffer plus the grid dimensions that address it.

Binding the two makes a mismatch unrepresentable, and applies the depth guard once rather than per effect.

Public Attributes

uint8_t * data = nullptr : first byte of the light array

size_t bytes = 0 : total writable bytes (the bound every write is clipped to)

Coord3D dims {0, 0, 0} : logical extents; z is >= 1 (see the depth guard above)

uint8_t cpl = 3 : channels per light

Public Methods

inline size_t offsetOf(Coord3D p) const : Byte offset of a coordinate, or bytes when it is outside the grid.

Public Static Methods

static inline Canvas of(Buffer & buf, lengthType w, lengthType h, lengthType d) : Build from a [Buffer] + the layer's logical extents, applying the depth guard.

BlobPath

struct BlobPath
src/light/powerfunctions/draw.h:372

One blob's orbit: where it sits at time t on a grid of w by h.

Public Attributes

uint8_t speedMul : multiplies the shared time base, so blobs drift apart

uint8_t phaseX : phase offset on x, keeping the paths from coinciding

uint8_t phaseY : the vertical path's phase offset

UpscaleTap

struct UpscaleTap
src/light/powerfunctions/draw.h:1064

One destination column's blend: the two source columns and the weight between them.

Public Attributes

uint16_t a

uint16_t b

uint16_t w

Sprite

struct Sprite
src/light/powerfunctions/draw.h:647

A small movable bitmap: palette-indexed pixels (index 0 = the transparent key, the classic key-color scheme), frames stacked vertically (frame f = rows [fh, (f+1)h)).

Carried as constexpr data, the [fonts.h] shape. Full alpha (Porter-Duff over) stays deferred until a consumer needs it. A transparent index is what classic sprites used and what LED walls need.

Public Attributes

const uint8_t * pixels : palette-indexed bytes, one per pixel per frame

const RGB * palette : the sprite's own colors; index 0 is never read

uint8_t w

uint8_t h

uint8_t frames

uint8_t paletteCount : the sprite's extents and its palette size

More info

Why the box is clipped

addPixel already rejects an out-of-bounds pixel, but only AFTER the distance function has run for it, which leaves two faults the clip removes. A radius the caller chose makes the walk cost r squared however small the grid is, so one large number stalls the render thread. And lengthType is 16 bits, so a radius near its ceiling puts x1 at INT16_MAX, the increment wraps to negative, and the loop never ends at all.

An empty canvas is emptied at BOTH ends for the same reason: the walk is inclusive. Setting only x1 = -1 left x0 at whatever negative value the caller computed, and -2 to -1 is a two-iteration range writing outside the buffer.

Addressing

Index order matches the engine, and a pixel outside the grid is silently clipped, so a line running off the edge stops drawing.

Signed distance fields

An SDF answers how far a point is from a shape's edge: negative inside, zero on it, positive outside. One number then gives a fill, an edge, an outline, a glow and a smooth blend, and the same expression serves a strand, a matrix and a volume.

Squared first

Measured on an S3 at 128 by 128: about 14 cycles a pixel squared, against about 108 for the true distance. So every shape has a squared variant, and an effect asks for a real distance only when it needs one.

Rendering below the output resolution

A field's cost is per light, so computing fewer and interpolating the rest is what affords one on a large fixture. The stretch costs a fixed price per output light, so it saves nothing on a field that was already cheap. On a 64 by 64 layer a two-octave field goes 59 to 34 microseconds at half resolution, a curl field 212 to 71.