~/bend-docscommunity

lib.bend source

lib.bend on the hub · documented module

# ColorSample — Color layer 3: sample RGB within a ColorRange using Prng.## Hub deps (own CAS ids; not folded into this package's published blob):#   Color  0xc6ecb72f45a1b2f83318765698582f7f#   Prng   0xfd7037736e4fa1794a671d0278638da7## Maybe gate is U32-only: Color.range_valid uses F32.is_le on alpha, which is# opaque to definitional equality. Callers who need alpha ordering should still# call Color.range_valid first. No Hsl range type in Color layer 1 → RGB only.# Base + hub imports only; no termination escapes.import Baseimport 0xc6ecb72f45a1b2f83318765698582f7f/lib.bend as Colorimport 0xfd7037736e4fa1794a671d0278638da7/lib.bend as Prng# Inclusive U32 width. Precondition: lo <= hi (enforced by the Maybe gate).def ColorSample.span(+lo: U32, +hi: U32) -> U32:  U32.add(U32.sub(hi, lo), 1)def ColorSample.channel.go(+lo: U32, r: U32 & Prng.Prng) -> U32 & Prng.Prng:  (v, p2) = r  (U32.add(lo, v), p2)# Uniform draw in lo..=hi via next_bounded(span).def ColorSample.channel(p: Prng.Prng, +lo: U32, +hi: U32) -> U32 & Prng.Prng:  ColorSample.channel.go(lo, Prng.Prng.next_bounded(p, ColorSample.span(lo, hi)))def ColorSample.alpha.go(+lo: F32, +hi: F32, r: F32 & Prng.Prng) -> F32 & Prng.Prng:  (t, p2) = r  (F32.add(lo, F32.mul(F32.sub(hi, lo), t)), p2)# Lerp alpha with next_f32 in [0, 1). Always advances the PRNG.def ColorSample.alpha(p: Prng.Prng, +lo: F32, +hi: F32) -> F32 & Prng.Prng:  ColorSample.alpha.go(lo, hi, Prng.Prng.next_f32(p))# Thread PRNG through r → g → b → a. Helpers are ordered bottom-up; each match# scrutinizes a parameter (Bend forbids matching computed pairs inline).def ColorSample.after_a.go(  +r: U32, +g: U32, +b: U32, ra: F32 & Prng.Prng) -> Color.Rgb & Prng.Prng:  (a, p4) = ra  (Color.Rgb{r, g, b, a}, p4)def ColorSample.after_b.go(  +aa: F32, +ba: F32,  +r: U32, +g: U32, rb: U32 & Prng.Prng) -> Color.Rgb & Prng.Prng:  (b, p3) = rb  ColorSample.after_a.go(r, g, b, ColorSample.alpha(p3, aa, ba))def ColorSample.after_g.go(  +ab: U32, +aa: F32,  +bb: U32, +ba: F32,  +r: U32, rg: U32 & Prng.Prng) -> Color.Rgb & Prng.Prng:  (g, p2) = rg  ColorSample.after_b.go(aa, ba, r, g, ColorSample.channel(p2, ab, bb))def ColorSample.after_r.go(  +ag: U32, +ab: U32, +aa: F32,  +bg: U32, +bb: U32, +ba: F32,  +r: U32, p1: Prng.Prng) -> Color.Rgb & Prng.Prng:  ColorSample.after_g.go(ab, aa, bb, ba, r, ColorSample.channel(p1, ag, bg))def ColorSample.rgb.go(  +ar: U32, +ag: U32, +ab: U32, +aa: F32,  +br: U32, +bg: U32, +bb: U32, +ba: F32,  rr: U32 & Prng.Prng) -> Color.Rgb & Prng.Prng:  (r, p1) = rr  ColorSample.after_r.go(ag, ab, aa, bg, bb, ba, r, p1)def ColorSample.rgb.from_ends(  +ar: U32, +ag: U32, +ab: U32, +aa: F32,  +br: U32, +bg: U32, +bb: U32, +ba: F32,  p: Prng.Prng) -> Color.Rgb & Prng.Prng:  ColorSample.rgb.go(ar, ag, ab, aa, br, bg, bb, ba, ColorSample.channel(p, ar, br))# Gate on U32 min<=max for r/g/b; sample when ok. Pair payload ⇒ Maybe<&1, …>.def ColorSample.rgb.with_ends(  +ar: U32, +ag: U32, +ab: U32, +aa: F32,  +br: U32, +bg: U32, +bb: U32, +ba: F32,  p: Prng.Prng) -> Maybe<&1, Color.Rgb & Prng.Prng>:  Bool.pick(Maybe<&1, Color.Rgb & Prng.Prng>,    Bool.and(U32.is_le(ar, br),      Bool.and(U32.is_le(ag, bg), U32.is_le(ab, bb))),    Some{ColorSample.rgb.from_ends(ar, ag, ab, aa, br, bg, bb, ba, p)},    None{})def ColorSample.rgb(range: Color.ColorRange, p: Prng.Prng) -> Maybe<&1, Color.Rgb & Prng.Prng>:  match range:    case Color.ColorRange{min, max}:      match min max:        case Color.Rgb{ar, ag, ab, aa} Color.Rgb{br, bg, bb, ba}:          ColorSample.rgb.with_ends(ar, ag, ab, aa, br, bg, bb, ba, p)# Same U32 predicate as the Maybe gate (for laws / callers).def ColorSample.range_ok_u32(r: Color.ColorRange) -> Bool:  match r:    case Color.ColorRange{min, max}:      match min max:        case Color.Rgb{ar, ag, ab, aa} Color.Rgb{br, bg, bb, ba}:          Bool.and(U32.is_le(ar, br),            Bool.and(U32.is_le(ag, bg), U32.is_le(ab, bb)))# Projection helper for laws. None{} yields black (laws only call on Some).def ColorSample.unwrap_rgb(m: Maybe<&1, Color.Rgb & Prng.Prng>) -> Color.Rgb:  match m:    case None{}:      Color.Rgb{0, 0, 0, 0.0}    case Some{pair}:      Pair.fst(Color.Rgb, Prng.Prng, pair)