# 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 Base import 0xc6ecb72f45a1b2f83318765698582f7f/lib.bend as Color import 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)