Processing-style Drawing (P5)¶
P5 is a Processing / p5.js-style drawing DSL. It wraps FmrbGfx internally and lets you draw shapes in a p5 style with stateful fill / stroke / translate / rotate and more. P5 is built into picoruby-fmrb-app, so no additional require is needed.
Usage¶
class MyApp < FmrbApp
def on_create
@p5 = P5.new(@gfx)
end
def on_update
@p5.background(P5::BLACK)
@p5.fill(P5::RED)
@p5.no_stroke
@p5.rect(10, 10, 60, 40)
@p5.present
33
end
end
MyApp.new.start
Construction¶
P5.new(gfx)
Argument: FmrbApp#@gfx (a FmrbGfx instance). Store it in your subclass as @p5 = P5.new(@gfx).
Screen¶
| Method | Purpose |
|---|---|
width |
Canvas width |
height |
Canvas height |
background(color) |
Fill the entire screen with color |
present (alias: commit) |
Apply the frame to the screen |
Color Constants¶
Mirrors of FmrbGfx::* (RGB332).
P5::BLACK / WHITE / RED / GREEN / BLUE / YELLOW / CYAN / MAGENTA / GRAY
Custom colors can be specified with P5#color(r, g, b) (which calls FmrbGfx.rgb_to_332 internally) or directly as an RGB332 integer.
Drawing State¶
| Method | Purpose |
|---|---|
fill(color) / no_fill |
Fill color / disable fill |
stroke(color) / no_stroke |
Stroke color / disable stroke |
stroke_weight(w) |
Stroke width (>1 is implemented with parallel lines) |
blend_mode(mode) |
Blend mode (see below) |
Blend Mode¶
Constants provided: P5::REPLACE / P5::ADD / P5::XOR / P5::SUBTRACT / P5::MULTIPLY / P5::SCREEN.
Blend mode limitations
The backend only supports REPLACE / ADD / XOR, and these only take effect on rectangle fills (rect(), background()). Other shapes and SUBTRACT / MULTIPLY / SCREEN fall back to REPLACE behavior.
Basic Shapes¶
| Method | Signature |
|---|---|
point(x, y) |
Single pixel (uses stroke color) |
line(x0, y0, x1, y1) |
Line |
rect(x, y, w, h) |
Rectangle (fill + stroke) |
circle(cx, cy, r) |
Circle |
ellipse(cx, cy, rx, ry) |
Ellipse |
triangle(x0, y0, x1, y1, x2, y2) |
Triangle |
arc(cx, cy, r, start, stop) |
Arc (angles in radians) |
bezier(x1, y1, x2, y2, x3, y3, x4, y4) |
Cubic Bezier (subdivided into 20 line segments) |
curve(x1, y1, x2, y2, x3, y3, x4, y4) |
Catmull-Rom spline |
Arc mode
The p5.js OPEN / CHORD / PIE modes are not supported. Arcs are always drawn as a combination of pie shape (fill_arc) and outer ring (draw_arc).
Affine Transforms¶
Uses the same post-multiply composition as p5.js / Processing (M' = M * op). translate(tx, ty); rotate(theta); rect(-30,-20,60,40) produces the standard behavior of rotating around the local origin after translation.
| Method | Purpose |
|---|---|
translate(tx, ty) |
Translation |
rotate(angle) |
Rotation (radians) |
scale(sx, sy = sx) |
Scaling |
push_matrix / pop_matrix |
Save / restore the matrix |
reset_matrix |
Reset to the identity matrix |
When the matrix contains only translations, a fast path is used. When rotation or scaling is involved, it switches to a slower path with triangle decomposition.
Text¶
| Method | Purpose |
|---|---|
text_font(font, wide_font = nil) |
Switch font. :default / :ja, 8 / :ja, 12 |
text_color(color) |
Text color |
text_align(h, v = :top) |
Alignment. h: :left / :center / :right, v: :top / :center / :bottom |
text_leading(pixels) |
Line spacing (state only; \n is not supported) |
text_width(str) |
Drawing width of a string (assumes fixed-width) |
text(str, x, y) |
Draw text |
For Japanese fonts, see FmrbGfx > Japanese Text.
@p5.text_font(:ja, 12)
@p5.text_color(P5::BLACK)
@p5.text_align(:center, :center)
@p5.text("こんにちは", @p5.width / 2, @p5.height / 2)
Image¶
| Method | Purpose |
|---|---|
image(image_id, x, y, scale_x = 1.0, scale_y = 0.0) |
Draw an image obtained via FmrbGfx#create_image_from_file. When scale_y = 0.0, it uses the same value as scale_x |
image_masked(image_id, mask_data, x, y, w, h) |
Draw with a 1bpp mask |
Pixel Operations¶
| Method | Purpose |
|---|---|
set_pixel(x, y, color) |
Direct pixel write |
get_pixel(x, y) |
Read back a pixel (slow due to round-trip to graphics side) |
get_pixel cost
get_pixel is a synchronous call: it flushes every unsent drawing command, reads on the graphics side, and waits for the answer. On Retro that answer crosses the UART link, so a single pixel costs several milliseconds; it is cheaper on Modern but still a round trip. Avoid calling it in loops. Maintaining a local 2D array of drawing state is much faster than per-pixel reads.
Example¶
class P5Spinner < FmrbApp
def on_create
@p5 = P5.new(@gfx)
@angle = 0.0
end
def on_update
@p5.background(P5::BLACK)
cx = @p5.width / 2
cy = @p5.height / 2
@p5.push_matrix
@p5.translate(cx, cy)
@p5.rotate(@angle)
@p5.fill(P5::CYAN)
@p5.no_stroke
@p5.rect(-20, -20, 40, 40)
@p5.pop_matrix
@p5.present
@angle += 0.1
33
end
end
P5Spinner.new.start
A sample that switches between features (basic shapes / affine transforms / Bezier / text / arcs / blend / get_pixel) is available in /app/demo/p5_test.app.rb.