Table of Contents
cl-sdf
cl-sdf makes distance fields from 2D outlines, in pure Common Lisp. A distance field is a small texture that a shader can draw at many sizes and stay sharp. The shader can also draw outlines, glows and soft shadows from the same texture. cl-sdf makes three kinds:
- SDF: one channel, the signed distance to the outline. Corners come out rounded.
- MSDF: three channels. The median of the three draws the outline with sharp corners.
- MTSDF: the MSDF in red, green and blue, plus the true distance in alpha, for effects.
It takes outlines as lists of lines, quadratic and cubic Bézier segments, in the form cl-textrender's glyph outlines use, and it also answers point queries: is a point inside, and how far is it from the edge.
cl-sdf is one of the libraries of the Pyssel game engine, whose SDF painter draws text with it through cl-textrender/sdf. It has no dependencies, knows nothing of fonts or GPUs, and is usable on its own.
A first look
(asdf:load-system :cl-sdf)
(defpackage #:example
(:use #:cl)
(:local-nicknames (#:sdf #:cl-sdf)))
(in-package #:example)
;; A unit square, counterclockwise, as one contour of four lines.
(let* ((square '(((:line 0 0 1 0) (:line 1 0 1 1) (:line 1 1 0 1) (:line 0 1 0 0))))
;; A 64 by 64 MTSDF texture of it, with a quarter unit of margin all round.
(field (sdf:generate-mtsdf square 64 64 :padding 0.25))
;; Point queries, on a shape prepared once.
(shape (sdf:make-shape square)))
(list (sdf:field-bounds field) ; the square and its padding
(sdf:field-spread field) ; shape units mapped to 0..1
(sdf:field-ref field 32 32 3) ; deep inside; 0.5 is the edge
(length (sdf:field-octets field)) ; an RGBA8 texture's bytes
(sdf:signed-distance shape 0.5 0.25) ; positive inside
(sdf:signed-distance shape 2 2)
(sdf:inside-p shape 2 2)))
;; => ((-0.25d0 -0.25d0 1.25d0 1.25d0) 0.09375d0 1.0 16384
;; 0.25d0 -1.4142135623730951d0 NIL)
The field covers the square plus the padding. Each texel stores the distance from its center to the edge, mapped to 0..1: 0.5 on the edge, and 0 or 1 at field-spread units outside or inside it. Drawing with Fields turns that back into pixels.
Pages
Using cl-sdf
- Getting Started: requirements, installing with stift, loading, running the tests.
- Concepts: SDF, MSDF and MTSDF; shape units, texels and spread; which kind to use. Read this first.
- Contours and Fill Rules: the outline format, closing, winding, fill rules, overlaps, glyphs from a font.
- Generating Fields:
generate-sdf,generate-msdf,generate-mtsdfand every option. - Reading Fields: the
fieldobject, its layout, octets for upload. - Drawing with Fields: the shader side: quads, texture coordinates, coverage, outlines, glows, shadows.
- Edge Coloring: how MSDF channels are assigned, and coloring by hand.
- Error Correction: the MSDF artifact pass and when to turn it off.
- Distance Queries:
make-shape,inside-p,signed-distance,unsigned-distance, encoding. - Recipes: glyphs, circles and rings, fixed texel density, checking a field on the CPU, saving an image.
Reference
- API Reference: every exported symbol.
- Errors: the conditions and every message.
- Accuracy and Performance: tolerances, precision, how cl-sdf compares with msdfgen, timings.
- How It Works: the pipeline inside, for maintainers and the curious.
- Development: source layout, tests, the msdfgen fixtures, CI.
Status
Done: SDF, MSDF and MTSDF generation from lines, quadratics and cubics; both fill rules; overlapping and self-intersecting contours; automatic and manual edge coloring; msdfgen's default MSDF error correction; point queries on prepared shapes. The output has been checked against upstream msdfgen. See Accuracy and Performance.
Not provided, by design: atlas packing (see cl-atlas, or cl-textrender/sdf for glyphs), font loading, and GPU code.
License
MIT. See LICENSE in the repository.