Drawing text, curves, and shapes in 2D
Shapes, color, images, type, curves, custom polygons, SVG shapes, and offscreen buffers.
Basic shapes
The primitives match Processing one-for-one:
point(x, y);
line(x1, y1, x2, y2);
rect(x, y, w, h);
square(x, y, extent);
circle(x, y, diameter);
ellipse(x, y, w, h);
triangle(x1, y1, x2, y2, x3, y3);
quad(x1, y1, x2, y2, x3, y3, x4, y4);
arc() takes start and stop angles (radians) plus a mode — PIE, OPEN, or CHORD:
arc(50, 55, 50, 50, 0, HALF_PI, PIE);
arc(200, 200, 300, 300, 0, PI + QUARTER_PI, CHORD);
Change how coordinates are read with rectMode() / ellipseMode()
(CENTER, RADIUS, CORNER, CORNERS):
ellipseMode(RADIUS);
ellipse(200, 200, 120, 120); // 120 is now the radius
Stroke and fill
fill(255); // white interior
stroke(0); // black outline
strokeWeight(8); // line thickness
noFill(); // outline only
noStroke(); // fill only
Style line corners and ends with strokeJoin() (ROUND, BEVEL, MITER) and strokeCap()
(ROUND, SQUARE, PROJECT):
strokeWeight(15);
strokeJoin(ROUND);
strokeCap(ROUND);
Working with colors
Channels run 0–255, like Processing’s default. A second value on a grey, or a fourth on an
RGB color, is the alpha:
fill(255); // white
fill(255, 204); // white at ~80% opacity
fill(255, 63, 89); // an RGB color
fill(0, 0, 0, 12); // near-transparent black
Store a color in a color_t, and pull channels back out with red(), green(), blue():
const color_t soft_red = color(255, 63, 89);
fill(soft_red);
float r = red(soft_red) / 255.0f;
Need HSB? Umfeld ships the GLM math library; convert with it:
#include "glm/gtx/color_space.hpp"
glm::vec3 rgb = glm::rgbColor(glm::vec3(hue * 360.0f, saturation, brightness));
fill(rgb.r * 255.0f, rgb.g * 255.0f, rgb.b * 255.0f);
Working with images
Load once in setup(), draw with image(). Files live in a data/ folder beside the sketch;
loadImage() also accepts a URL.
PImage* img;
void setup() {
img = loadImage("umfeld.png"); // or a "https://…" URL
imageMode(CENTER);
}
void draw() {
image(img, mouseX, mouseY); // or image(img, x, y, w, h)
}
tint() colors/fades an image and noTint() clears it. img->width / img->height give the
size, and img->resize(w, h) rescales (pass 0 for one side to keep the aspect ratio):
img->resize(0, height);
tint(255, 0, 0, 128); // red wash at half alpha
image(img, mouseX, mouseY);
noTint();
Drawing text
Load a font (its size is baked in), set it, then text():
PFont* font;
void setup() {
font = loadFont("RobotoMono-Regular.ttf", 44);
textFont(font);
}
void draw() {
fill(0);
textSize(32);
textAlign(CENTER, CENTER); // horizontal, vertical
text("hello umfeld", width / 2, height / 2);
}
Alignment constants: LEFT / CENTER / RIGHT and TOP / CENTER / BOTTOM / BASELINE.
textLeading() sets line spacing for multi-line strings.
For a quick on-screen readout (FPS, debug values), skip font loading and use debug_text(),
which draws with a built-in font:
debug_text("FPS: " + nf(frameRate, 3, 1), 10, 20);
Drawing curves
bezier() draws a cubic curve from four control points; curveVertex() builds a smooth
Catmull-Rom spline through points inside a shape:
bezier(120, 80, 120, 300, 340, 80, 340, 300);
beginShape();
curveVertex(100, 200); // control point
curveVertex(100, 200); // first visible point (repeated)
curveVertex(200, 100);
curveVertex(300, 200);
curveVertex(300, 200); // last visible point (repeated)
endShape();
To compute a point on a Bézier yourself (Umfeld has no bezierPoint() helper), evaluate the
formula — useful for placing objects along a curve:
float bezier_at(float a, float b, float c, float d, float t) {
float u = 1 - t;
return u*u*u*a + 3*u*u*t*b + 3*u*t*t*c + t*t*t*d;
}
// float x = bezier_at(120, 120, 340, 340, 0.5f);
Drawing custom shapes
Build any polygon with beginShape() / vertex() / endShape(). Pass CLOSE to join the last
point to the first. The optional mode (POINTS, LINES, TRIANGLES, TRIANGLE_STRIP,
TRIANGLE_FAN, QUAD_STRIP, LINE_STRIP) controls how vertices connect:
beginShape();
vertex(120, 80);
vertex(340, 80);
vertex(340, 300);
vertex(120, 300);
endShape(CLOSE);
Cut a hole with beginContour() / endContour() (wind it opposite to the outer shape):
beginShape();
vertex(20, 20); vertex(180, 20); vertex(180, 180); vertex(20, 180);
beginContour();
vertex(60, 60); vertex(60, 120); vertex(120, 120); vertex(120, 60);
endContour();
endShape(CLOSE);
SVG and PShape
Vector shapes load into a PShape and draw with shape():
PShape* s;
void setup() {
s = loadShape("bot.svg");
}
void draw() {
shape(s, 100, 100);
}
Offscreen drawing
createGraphics() makes a PGraphics buffer you draw into off-screen, then stamp onto the
window with image(). Wrap its drawing in beginDraw() / endDraw():
PGraphics* pg;
void setup() {
pg = createGraphics(100, 100);
}
void draw() {
pg->beginDraw();
pg->background(102);
pg->stroke(255);
pg->line(0, 0, mouseX, mouseY);
pg->endDraw();
image(pg, 150, 50);
}