All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m28s
- Add JAX text rendering with font atlas, styled text placement, and typography primitives - Add xector (element-wise/reduction) operations library and sexp effects - Add deferred effect chain fusion for JIT-compiled effect pipelines - Expand drawing primitives with font management, alignment, shadow, and outline - Add interpreter support for function-style define and require - Add GPU persistence mode and hardware decode support to streaming - Add new sexp effects: cell_pattern, halftone, mosaic, and derived definitions - Add path registry for asset resolution - Add integration, primitives, and xector tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
50 lines
1.7 KiB
Common Lisp
50 lines
1.7 KiB
Common Lisp
;; Halftone/dot effect - built from primitive xector operations
|
||
;;
|
||
;; Uses:
|
||
;; pool-frame - downsample to cell luminances
|
||
;; cell-indices - which cell each pixel belongs to
|
||
;; gather - look up cell value for each pixel
|
||
;; local-x/y-norm - position within cell [0,1]
|
||
;; where - conditional per-pixel
|
||
|
||
(require-primitives "xector")
|
||
|
||
(define-effect halftone
|
||
:params (
|
||
(cell-size :type int :default 12 :range [4 32] :desc "Size of halftone cells")
|
||
(dot-scale :type float :default 0.9 :range [0.1 1.0] :desc "Max dot radius")
|
||
(invert :type bool :default false :desc "Invert (white dots on black)")
|
||
)
|
||
(let* (
|
||
;; Pool frame to get luminance per cell
|
||
(pooled (pool-frame frame cell-size))
|
||
(cell-lum (nth pooled 3)) ; luminance is 4th element
|
||
|
||
;; For each output pixel, get its cell index
|
||
(cell-idx (cell-indices frame cell-size))
|
||
|
||
;; Get cell luminance for each pixel
|
||
(pixel-lum (α/ (gather cell-lum cell-idx) 255))
|
||
|
||
;; Position within cell, normalized to [-0.5, 0.5]
|
||
(lx (α- (local-x-norm frame cell-size) 0.5))
|
||
(ly (α- (local-y-norm frame cell-size) 0.5))
|
||
|
||
;; Distance from cell center (0 at center, ~0.7 at corners)
|
||
(dist (αsqrt (α+ (α² lx) (α² ly))))
|
||
|
||
;; Radius based on luminance (brighter = bigger dot)
|
||
(radius (α* (if invert (α- 1 pixel-lum) pixel-lum)
|
||
(α* dot-scale 0.5)))
|
||
|
||
;; Is this pixel inside the dot?
|
||
(inside (α< dist radius))
|
||
|
||
;; Output color
|
||
(fg (if invert 255 0))
|
||
(bg (if invert 0 255))
|
||
(out (where inside fg bg)))
|
||
|
||
;; Grayscale output
|
||
(rgb out out out)))
|