Skip to content

std.draw

Drawing into an Image on the CPU: filled rectangles, lines, filled circles, source-over blending, blits of one image onto another, text in a built-in 8 by 13 bitmap font, and the layout record and frame capture that let a person or an agent see what a program drew. Every shape is clipped, so a shape partly outside draws its inside part and none traps. Coordinates are i64, so a shape may start left of or above the image. Pixel (x, y) belongs to a rectangle when x0 <= x < x0 + w and y0 <= y < y0 + h, and to a circle when dx * dx + dy * dy <= r * r. Colours blend source over destination with integer rounding: each colour channel becomes (s * a + d * (255 - a) + 127) / 255, and alpha becomes a + (d_a * (255 - a) + 127) / 255, so an opaque colour replaces a pixel and a clear one leaves it. The glyphs are the X11 misc-fixed 8x13 font, which is in the public domain, as console-setup ships it (Lat15-Fixed13.psf). Cost: a shape is a sequential loop over the pixels it covers; layer and image.fill are parallel regions. A Layout allocates as it grows, and capture allocates, reads the environment and writes files.

// A marked rectangle. `place` finds one by name, and `inside` and `apart` compare two, so a test can hold a layout to
// its rules in CAIRN itself.
pub struct Mark { x:i64; y:i64; w:i64; h:i64; }

// Named rectangles a program reports as it draws, so a person or an agent can check where things landed without reading
// pixels: `json` gives {"width":W,"height":H,"at_ns":T,"elements":[{"name":"panel","x":0,...},...]}.
pub struct Layout { text:Vec[u8]; count:usize; names:Vec[u8]; ends:Vec[usize]; marks:Vec[Mark]; }

pub const GLYPH_W:i64 = 8;
pub const GLYPH_H:i64 = 13;

// `s` over `d`.
pub fn over(d:u32, s:u32) -> u32  // effects: trap

// One pixel, blended; a pixel outside the image is not drawn.
pub fn plot(img:rw<std.image.Image>, x:i64, y:i64, c:u32)  // effects: read:img, trap, write:img

// The rectangle whose top left corner is (x, y), w wide and h high; a zero or negative size draws nothing.
pub fn rect(img:rw<std.image.Image>, x:i64, y:i64, w:i64, h:i64, c:u32)  // effects: read:img, trap, write:img

// The line from (x0, y0) to (x1, y1), both ends included, by Bresenham's integer steps. Its cost is its length,
// including the part outside the image.
// effects: diverge, read:img, trap, write:img
pub fn line(img:rw<std.image.Image>, x0:i64, y0:i64, x1:i64, y1:i64, c:u32)

// The filled circle of radius r around (cx, cy); a negative radius draws nothing and a radius of 0 is one pixel.
pub fn circle(img:rw<std.image.Image>, cx:i64, cy:i64, r:i64, c:u32)  // effects: read:img, trap, write:img

// `src` over `dst` with its top left corner at (x, y), clipped to `dst`.
// effects: read:dst, read:src, trap, write:dst
pub fn blit(dst:rw<std.image.Image>, src:ro<std.image.Image>, x:i64, y:i64)

// The w by h part of `src` whose corner is (sx, sy), such as one cell of a sprite sheet, over `dst` at (x, y); clipped
// to both images.
// effects: read:dst, read:src, trap, write:dst
pub fn blit_part(dst:rw<std.image.Image>, src:ro<std.image.Image>, sx:usize, sy:usize, w:usize, h:usize, x:i64, y:i64)

// `top` over `base`, pixel by pixel, as a parallel region: a whole layer composited at once. The two must be the same
// size; different sizes are a guard failure.
// effects: par:host, read:base, read:top, trap, write:base
pub fn layer(base:rw<std.image.Image>, top:ro<std.image.Image>)

// Text in the built-in font, each font pixel `scale` pixels square, with its top left corner at (x, y). A byte outside
// printable ASCII draws as '?'. `text_width` says how far it reaches, for laying out what follows.
// effects: ffi_precondition, local_read, read:img, read:s, trap, write:img
pub fn text(img:rw<std.image.Image>, x:i64, y:i64, n:usize, s:ro<u8>[n]@host, c:u32, scale:i64)

pub fn text_width(n:usize, scale:i64) -> i64  // effects: trap
pub fn layout() -> std.draw.Layout  // effects: alloc, free, trap, zero_init

// The rectangle last marked `name`. A name never marked is a guard failure, which is what a test wants.
// effects: ffi_precondition, read:l, read:name, trap
pub fn place(l:ro<std.draw.Layout>, n:usize, name:ro<u8>[n]@host) -> std.draw.Mark

// effects: ffi_precondition, read:l, read:name, trap
pub fn marked(l:ro<std.draw.Layout>, n:usize, name:ro<u8>[n]@host) -> bool

pub fn inside(a:std.draw.Mark, b:std.draw.Mark) -> bool  // effects: trap
pub fn apart(a:std.draw.Mark, b:std.draw.Mark) -> bool  // effects: trap

// Report the rectangle `name` covers. The name is written as a JSON string, its quotes, backslashes and control bytes
// escaped.
// effects: alloc, diverge, ffi_precondition, free, local_read, local_write, read:l, read:name, stack_storage, trap,
// write:l, zero_init
pub fn mark(l:rw<std.draw.Layout>, n:usize, name:ro<u8>[n]@host, x:i64, y:i64, w:i64, h:i64)

// The layout record of a frame of `img`, taken at monotonic time `at_ns`.
// effects: alloc, diverge, ffi_precondition, free, local_read, local_write, read:img, read:l, read:out, stack_storage,
// trap, write:out, zero_init
pub fn json(l:ro<std.draw.Layout>, img:ro<std.image.Image>, at_ns:u64, out:rw<std.vec.Vec[u8]>)

// Frame k of a shot: when the program runs under `cairn shot`, which names a directory in CAIRN_SHOT, write frame-k.png
// and frame-k.json there and answer true; otherwise do nothing and answer false.
// effects: alloc, diverge, ffi:__errno_location, ffi:clock_gettime, ffi:close, ffi:lseek, ffi:open, ffi:read,
// ffi:write, ffi_precondition, free, io, local_read, local_write, mmio, read:img, read:l, stack_storage, trap,
// zero_init
pub fn capture(img:ro<std.image.Image>, l:ro<std.draw.Layout>, k:usize) -> std.core.Result[bool, std.io.IoError]

A generic function's effects are what it may do for any arguments within its bounds, besides what their own trait members do.