From d7e00201301c841ae0382c66c344ee9f0d52cf47 Mon Sep 17 00:00:00 2001 From: Drewry Pope Date: Sun, 13 Jul 2025 03:19:03 -0500 Subject: [PATCH] formats --- Camera.roc | 15 ++++++---- Color.roc | 46 +++++++++++++++--------------- HitRecord.roc | 9 +++--- Material.roc | 40 +++++++++++++++----------- Math.roc | 12 ++++---- RNG.roc | 78 +++++++++++++++++++++++++-------------------------- Ray.roc | 8 +++--- Sphere.roc | 41 ++++++++++++++------------- Vec.roc | 76 ++++++++++++++++++++++++------------------------- World.roc | 31 ++++++++++++-------- main.roc | 61 +++++++++++++++++++--------------------- 11 files changed, 214 insertions(+), 203 deletions(-) diff --git a/Camera.roc b/Camera.roc index 8ff7151..78a7a89 100644 --- a/Camera.roc +++ b/Camera.roc @@ -1,6 +1,9 @@ -interface Camera - exposes [Camera, make, ray] - imports [Vec.{ Vec }, Ray.{ Ray }, RNG.{ RNG }, Math] +module [Camera, make, ray] + +import Vec exposing [Vec] +import Ray exposing [Ray] +import RNG exposing [RNG] +import Math Camera : { origin : Vec, @@ -14,7 +17,7 @@ Camera : { } make : { lookFrom : Vec, lookAt : Vec, up : Vec, fov : F64, aspectRatio : F64, aperture : F64, focusDist : F64 } -> Camera -make = \{ lookFrom, lookAt, up, fov, aspectRatio, aperture, focusDist } -> +make = |{ lookFrom, lookAt, up, fov, aspectRatio, aperture, focusDist }| theta = Math.degToRad fov h = Num.tan (theta / 2) viewportHeight = 2 * h @@ -48,8 +51,8 @@ make = \{ lookFrom, lookAt, up, fov, aspectRatio, aperture, focusDist } -> } ray : Camera, F64, F64, RNG, (RNG, Ray -> a) -> a -ray = \{ u, v, lowerLeftCorner, lensRadius, horizontal, vertical, origin }, s, t, rng, fn -> - newRng, unitDisk <- RNG.vecInUnitDisk rng +ray = |{ u, v, lowerLeftCorner, lensRadius, horizontal, vertical, origin }, s, t, rng, fn| + { newRng, unitDisk } = RNG.vecInUnitDisk rng rd = Vec.scale unitDisk lensRadius offset = Vec.add (Vec.scale u rd.x) (Vec.scale v rd.y) diff --git a/Color.roc b/Color.roc index b46dd50..2b851e1 100644 --- a/Color.roc +++ b/Color.roc @@ -1,18 +1,18 @@ -interface Color - exposes [ - Color, - zero, - one, - neg, - add, - sub, - mul, - div, - scale, - shrink, - toPixel, - ] - imports [Math] +module [ + Color, + zero, + one, + neg, + add, + sub, + mul, + div, + scale, + shrink, + toPixel, +] + +import Math Color : { r : F64, g : F64, b : F64 } @@ -23,53 +23,53 @@ one : Color one = { r: 1, g: 1, b: 1 } neg : Color -> Color -neg = \c -> { +neg = |c| { r: -c.r, g: -c.g, b: -c.b, } add : Color, Color -> Color -add = \a, b -> { +add = |a, b| { r: a.r + b.r, g: a.g + b.g, b: a.b + b.b, } sub : Color, Color -> Color -sub = \a, b -> { +sub = |a, b| { r: a.r - b.r, g: a.g - b.g, b: a.b - b.b, } mul : Color, Color -> Color -mul = \a, b -> { +mul = |a, b| { r: a.r * b.r, g: a.g * b.g, b: a.b * b.b, } div : Color, Color -> Color -div = \a, b -> { +div = |a, b| { r: a.r / b.r, g: a.g / b.g, b: a.b / b.b, } scale : Color, F64 -> Color -scale = \c, t -> { +scale = |c, t| { r: c.r * t, g: c.g * t, b: c.b * t, } shrink : Color, F64 -> Color -shrink = \c, t -> +shrink = |c, t| scale c (1 / t) toPixel : Color, Num * -> { r : U8, g : U8, b : U8 } -toPixel = \{ r, g, b }, samples -> +toPixel = |{ r, g, b }, samples| if Num.isZero samples then { r: 0, g: 0, b: 0 } else diff --git a/HitRecord.roc b/HitRecord.roc index 9b37f1d..e8f3309 100644 --- a/HitRecord.roc +++ b/HitRecord.roc @@ -1,11 +1,12 @@ -interface HitRecord - exposes [HitRecord, make] - imports [Vec.{ Vec }, Ray.{ Ray }] +module [HitRecord, make] + +import Vec exposing [Vec] +import Ray exposing [Ray] HitRecord : { p : Vec, normal : Vec, t : F64, frontFace : Bool } make : { p : Vec, t : F64, ray : Ray, outwardNormal : Vec } -> HitRecord -make = \{ p, t, ray, outwardNormal } -> +make = |{ p, t, ray, outwardNormal }| frontFace = Vec.dot ray.direction outwardNormal < 0 normal = if frontFace then outwardNormal else Vec.neg outwardNormal diff --git a/Material.roc b/Material.roc index 7d0b1ab..81f3e28 100644 --- a/Material.roc +++ b/Material.roc @@ -1,30 +1,36 @@ -interface Material - exposes [Material, scatter] - imports [Color.{ Color }, RNG.{ RNG }, Vec, Ray.{ Ray }, HitRecord.{ HitRecord }, Math] +module [Material, scatter] + +import Color exposing [Color] +import RNG exposing [RNG] +import Vec +import Ray exposing [Ray] +import HitRecord exposing [HitRecord] +import Math ScatterRecord : { attenuation : Color, scattered : Ray } Material : [Lambertian Color, Metal Color F64, Dielectric F64] scatter : Material, Ray, HitRecord, RNG, (RNG, Result ScatterRecord [NoHit] -> a) -> a -scatter = \material, ray, rec, rng, fn -> +scatter = |material, ray, rec, rng, fn| when material is Lambertian albedo -> lambertian albedo rec rng fn Metal albedo fuzz -> metal albedo fuzz ray rec rng fn Dielectric ir -> dielectric ir ray rec rng fn -lambertian = \albedo, rec, rng, fn -> - newRng, unitVec <- RNG.unitVec rng +lambertian = |albedo, rec, rng, fn| + { newRng, unitVec } = RNG.unitVec rng fn scatterDirection = Vec.add rec.normal unitVec direction = if Vec.nearZero scatterDirection then rec.normal else scatterDirection scattered = { origin: rec.p, direction } - fn newRng (Ok { attenuation: albedo, scattered }) - -metal = \albedo, fuzz, ray, rec, rng, fn -> - newRng, unitSphere <- RNG.vecInUnitSphere rng + fn newRng |{ x, y, z }| { x, y, z } +# fn newRng (Ok { attenuation: albedo, scattered }) +# fn newRng (Ok { attenuation: albedo, scattered = { origin: rec.p, direction } }) +metal = |albedo, fuzz, ray, rec, rng, fn| + { newRng, unitSphere } = RNG.vecInUnitSphere rng fn reflected = Vec.unit ray.direction |> Vec.reflect rec.normal scattered = { origin: rec.p, direction: Vec.scale unitSphere fuzz |> Vec.add reflected } @@ -33,8 +39,7 @@ metal = \albedo, fuzz, ray, rec, rng, fn -> fn newRng (Ok { attenuation: albedo, scattered }) else fn newRng (Err NoHit) - -dielectric = \ir, ray, rec, rng, fn -> +dielectric = |ir, ray, rec, rng, fn| refractionRatio = if rec.frontFace then 1 / ir else ir unitDirection = Vec.unit ray.direction @@ -44,18 +49,19 @@ dielectric = \ir, ray, rec, rng, fn -> cannotRefract = refractionRatio * sinTheta > 1 - newRng, real <- RNG.real rng + { newRng, real } = RNG.real |rng, x| x - direction = if cannotRefract || reflectance cosTheta refractionRatio > real then + direction = ( + if cannotRefract or reflectance cosTheta refractionRatio > real then Vec.reflect unitDirection rec.normal else Vec.refract unitDirection rec.normal refractionRatio + ) - scattered = { origin: rec.p, direction} + scattered = { origin: rec.p, direction } fn newRng (Ok { attenuation: Color.one, scattered }) - -reflectance = \cosine, refIdx -> +reflectance = |cosine, refIdx| r = (1 - refIdx) / (1 + refIdx) r0 = r * r r0 + (1 - r0) * Num.pow (1 - cosine) 5 diff --git a/Math.roc b/Math.roc index 9404d53..1864ef1 100644 --- a/Math.roc +++ b/Math.roc @@ -1,16 +1,14 @@ -interface Math - exposes [pi, degToRad, clamp, min, max] - imports [] +module [pi, degToRad, clamp, min, max] pi : F64 pi = 3.1415926535897932385 degToRad : F64 -> F64 -degToRad = \deg -> +degToRad = |deg| deg * pi / 180 clamp : F64, { min : F64, max : F64 } -> F64 -clamp = \x, range -> +clamp = |x, range| if x < range.min then range.min else if x > range.max then @@ -19,14 +17,14 @@ clamp = \x, range -> x min : F64, F64 -> F64 -min = \a, b -> +min = |a, b| if a < b then a else b max : F64, F64 -> F64 -max = \a, b -> +max = |a, b| if a > b then a else diff --git a/RNG.roc b/RNG.roc index 3979940..1148cb4 100644 --- a/RNG.roc +++ b/RNG.roc @@ -1,7 +1,9 @@ -interface RNG +module # TODO: find a way to implement a map somehow - exposes [RNG, init, real, between, vec, color, vecBetween, vecInUnitSphere, unitVec, vecInHemisphere, vecInUnitDisk] - imports [Vec.{ Vec }, Color.{ Color }] + [RNG, init, real, between, vec, color, vec_between, vecInUnitSphere, unitVec, vecInHemisphere, vecInUnitDisk] + +import Vec exposing [Vec] +import Color exposing [Color] # Simple linear congruential generator RNG := U32 @@ -10,55 +12,51 @@ init : RNG init = @RNG 0 u32 : RNG, (RNG, U32 -> a) -> a -u32 = \@RNG seed, fn -> - value = - seed - |> Num.mulWrap 1664525 - |> Num.addWrap 1013904223 +u32 = |seed, fn| + value = Num.add_wrap (Num.mul_wrap seed 1664525) 1013904223 fn (@RNG value) value real : RNG, (RNG, F64 -> a) -> a -real = \rng, fn -> - newRng, u32Value <- u32 rng - max = Num.toF64 Num.maxU32 |> Num.add 1 - value = Num.toF64 u32Value / max - - fn newRng value +real = |rng, cont| + u32 rng |newRng, seed| + denom = Num.to_f64 Num.max_u32 |> Num.add 1.0 + value = Num.to_f64 seed / denom + cont newRng value between : RNG, { min : F64, max : F64 }, (RNG, F64 -> a) -> a -between = \rng, { min, max }, fn -> - newRng, realValue <- real rng +between = |rng, { min, max }, fn| + { newRng, real_value } = real rng - value = min + (max - min) * realValue + value = min + (max - min) * real_value fn newRng value vec : RNG, (RNG, Vec -> a) -> a -vec = \rng, fn -> - xRng, x <- real rng - yRng, y <- real xRng - zRng, z <- real yRng +vec = |rng, fn| + { xRng, x } = real rng + { yRng, y } = real xRng + { zRng, z } = real yRng value = { x, y, z } fn zRng value color : RNG, (RNG, Color -> a) -> a -color = \rng, fn -> - rRng, r <- real rng - gRng, g <- real rRng - bRng, b <- real gRng +color = |rng, fn| + { rRng, r } = real rng + { gRng, g } = real rRng + { bRng, b } = real gRng value = { r, g, b } fn bRng value -vecBetween : RNG, { min : F64, max : F64 }, (RNG, Vec -> a) -> a -vecBetween = \rng, range, fn -> - xRng, x <- between rng range - yRng, y <- between xRng range - zRng, z <- between yRng range +vec_between : RNG, { min : F64, max : F64 }, (RNG, Vec -> a) -> a +vec_between = |rng, range, fn| + { xRng, x } = between rng range + { yRng, y } = between xRng range + { zRng, z } = between yRng range value = { x, y, z } @@ -66,23 +64,23 @@ vecBetween = \rng, range, fn -> # TODO: Is this recursion okay? vecInUnitSphere : RNG, (RNG, Vec -> a) -> a -vecInUnitSphere = \rng, fn -> - newRng, candidate <- vecBetween rng { min: -1, max: 1 } - +vecInUnitSphere = |rng, fn| + { newRng, candidate } = vec_between rng { min: -1, max: 1 } fn + # newRng, candidate <- vecBetween rng { min: -1, max: 1 } if Vec.lengthSquared candidate >= 1 then vecInUnitSphere newRng fn else fn newRng candidate unitVec : RNG, (RNG, Vec -> a) -> a -unitVec = \rng, fn -> - newRng, unitSphereVec <- vecInUnitSphere rng +unitVec = |rng, fn| + { newRng, unitSphereVec } = vecInUnitSphere rng fn newRng (Vec.unit unitSphereVec) vecInHemisphere : RNG, Vec, (RNG, Vec -> a) -> a -vecInHemisphere = \rng, normal, fn -> - newRng, unitSphereVec <- vecInUnitSphere rng +vecInHemisphere = |rng, normal, fn| + { newRng, unitSphereVec } = vecInUnitSphere rng v = if Vec.dot unitSphereVec normal > 0 then @@ -93,9 +91,9 @@ vecInHemisphere = \rng, normal, fn -> fn newRng v vecInUnitDisk : RNG, (RNG, Vec -> a) -> a -vecInUnitDisk = \rng, fn -> - xRng, x <- between rng { min: -1, max: 1 } - yRng, y <- between xRng { min: -1, max: 1 } +vecInUnitDisk = |rng, fn| + { xRng, x } = between rng { min: -1, max: 1 } fn + { yRng, y } = between xRng { min: -1, max: 1 } fn p = { x, y, z: 0 } diff --git a/Ray.roc b/Ray.roc index 68a6574..a34390f 100644 --- a/Ray.roc +++ b/Ray.roc @@ -1,10 +1,10 @@ -interface Ray - exposes [Ray, at] - imports [Vec.{ Vec }] +module [Ray, at] + +import Vec exposing [Vec] Ray : { origin : Vec, direction : Vec } at : Ray, F64 -> Vec -at = \ray, t -> +at = |ray, t| Vec.scale ray.direction t |> Vec.add ray.origin diff --git a/Sphere.roc b/Sphere.roc index c99d433..b43b093 100644 --- a/Sphere.roc +++ b/Sphere.roc @@ -1,15 +1,18 @@ -interface Sphere - exposes [Sphere, make, hit] - imports [Vec.{ Vec }, Ray.{ Ray }, Material.{ Material }, HitRecord.{ HitRecord }] +module [Sphere, make, hit] + +import Vec exposing [Vec] +import Ray exposing [Ray] +import Material exposing [Material] +import HitRecord exposing [HitRecord] Sphere : { center : Vec, radius : F64, material : Material } make : Vec, F64, Material -> Sphere -make = \center, radius, material -> - {center, radius, material} +make = |center, radius, material| + { center, radius, material } hit : Sphere, Ray, { min : F64, max : F64 } -> Result { rec : HitRecord, mat : Material } [NoHit] -hit = \{ center, radius, material }, ray, { min, max } -> +hit = |{ center, radius, material }, ray, { min, max }| oc = Vec.sub ray.origin center a = Vec.lengthSquared ray.direction halfB = Vec.dot oc ray.direction @@ -21,23 +24,21 @@ hit = \{ center, radius, material }, ray, { min, max } -> else sqrtd = Num.sqrt discriminant - negativeRoot = (-halfB - sqrtd) / a - positiveRoot = (-halfB + sqrtd) / a + negativeRoot = ((-halfB) - sqrtd) / a + positiveRoot = ((-halfB) + sqrtd) / a + + root = if negativeRoot > min and negativeRoot < max then + Ok negativeRoot + else if positiveRoot > min and positiveRoot < max then + Ok positiveRoot + else + Err NoHit - root = if negativeRoot > min && negativeRoot < max then - Ok negativeRoot - else if positiveRoot > min && positiveRoot < max then - Ok positiveRoot - else - Err NoHit - - t <- Result.map root + t = Result.map root p = Ray.at ray t outwardNormal = Vec.sub p center |> Vec.shrink radius - rec = HitRecord.make {p, t, ray, outwardNormal } - - {rec, mat: material} - + rec = HitRecord.make { p, t, ray, outwardNormal } + { rec, mat: material } diff --git a/Vec.roc b/Vec.roc index ec3650d..7716724 100644 --- a/Vec.roc +++ b/Vec.roc @@ -1,25 +1,25 @@ -interface Vec - exposes [ - Vec, - zero, - one, - neg, - add, - sub, - mul, - div, - scale, - shrink, - dot, - cross, - unit, - length, - lengthSquared, - nearZero, - reflect, - refract, - ] - imports [Math] +module [ + Vec, + zero, + one, + neg, + add, + sub, + mul, + div, + scale, + shrink, + dot, + cross, + unit, + length, + lengthSquared, + nearZero, + reflect, + refract, +] + +import Math Vec : { x : F64, y : F64, z : F64 } @@ -30,86 +30,86 @@ one : Vec one = { x: 1, y: 1, z: 1 } neg : Vec -> Vec -neg = \{ x, y, z } -> { +neg = |{ x, y, z }| { x: -x, y: -y, z: -z, } add : Vec, Vec -> Vec -add = \a, b -> { +add = |a, b| { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z, } sub : Vec, Vec -> Vec -sub = \a, b -> { +sub = |a, b| { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z, } mul : Vec, Vec -> Vec -mul = \a, b -> { +mul = |a, b| { x: a.x * b.x, y: a.y * b.y, z: a.z * b.z, } div : Vec, Vec -> Vec -div = \a, b -> { +div = |a, b| { x: a.x / b.x, y: a.y / b.y, z: a.z / b.z, } scale : Vec, F64 -> Vec -scale = \{ x, y, z }, t -> { +scale = |{ x, y, z }, t| { x: x * t, y: y * t, z: z * t, } shrink : Vec, F64 -> Vec -shrink = \v, t -> +shrink = |v, t| scale v (1 / t) dot : Vec, Vec -> F64 -dot = \u, v -> +dot = |u, v| u.x * v.x + u.y * v.y + u.z * v.z cross : Vec, Vec -> Vec -cross = \u, v -> { +cross = |u, v| { x: u.y * v.z - u.z * v.y, y: u.z * v.x - u.x * v.z, z: u.x * v.y - u.y * v.x, } unit : Vec -> Vec -unit = \v -> +unit = |v| shrink v (length v) length : Vec -> F64 -length = \v -> +length = |v| lengthSquared v |> Num.sqrt lengthSquared : Vec -> F64 -lengthSquared = \{ x, y, z } -> +lengthSquared = |{ x, y, z }| x * x + y * y + z * z nearZero : Vec -> Bool -nearZero = \{ x, y, z } -> +nearZero = |{ x, y, z }| s = 1e-8 - Num.abs x < s && Num.abs y < s && Num.abs z < s + Num.abs x < s and Num.abs y < s and Num.abs z < s reflect : Vec, Vec -> Vec -reflect = \v, n -> +reflect = |v, n| Vec.sub v (Vec.scale n (2 * Vec.dot v n)) refract : Vec, Vec, F64 -> Vec -refract = \uv, n, etaiOverEtat -> +refract = |uv, n, etaiOverEtat| cosTheta = neg uv |> dot n |> Math.min 1 rOutPerp = scale n cosTheta |> add uv |> scale etaiOverEtat s = Num.abs (1 - lengthSquared rOutPerp) |> Num.sqrt diff --git a/World.roc b/World.roc index d300386..3d1dccc 100644 --- a/World.roc +++ b/World.roc @@ -1,19 +1,26 @@ -interface World - exposes [World, hit] - imports [Sphere.{ Sphere }, Ray.{ Ray }, HitRecord.{ HitRecord }, Material.{ Material }] +module [World, hit] + +import Sphere exposing [Sphere] +import Ray exposing [Ray] +import HitRecord exposing [HitRecord] +import Material exposing [Material] World : List Sphere hit : World, Ray, { min : F64, max : F64 } -> Result { rec : HitRecord, mat : Material } [NoHit] -hit = \world, ray, { min, max } -> +hit = |world, ray, { min, max }| final = - state, sphere <- List.walk world { closestSoFar: max, recAndMat: Err NoHit } - - when Sphere.hit sphere ray { min, max: state.closestSoFar } is - Ok recAndMat -> - { closestSoFar: recAndMat.rec.t, recAndMat: Ok recAndMat } - - Err _ -> - state + List.walk + world + { closestSoFar: max, recAndMat: Err NoHit } + |state, sphere| + when Sphere.hit sphere ray { min, max } is + Ok recAndMat -> + if recAndMat.rec.t < state.closestSoFar then + { closestSoFar: recAndMat.rec.t, recAndMat: Ok recAndMat } + else + state + Err _ -> + state final.recAndMat diff --git a/main.roc b/main.roc index 49c20a1..0fae5af 100644 --- a/main.roc +++ b/main.roc @@ -1,23 +1,20 @@ -app "Raytrace" - packages { pf: "platform/main.roc" } - imports [ - Camera.{ Camera }, - Vec.{ Vec }, - Color.{ Color }, - RNG.{ RNG }, - Ray.{ Ray }, - World.{ World }, - Material, - Sphere, - ] - provides [main] { State } to pf +app [main, State] { pf: platform "platform/main.roc" } + +import Camera exposing [Camera] +import Vec exposing [Vec] +import Color exposing [Color] +import RNG exposing [RNG] +import Ray exposing [Ray] +import World exposing [World] +import Material +import Sphere State : { rng : RNG, color : Color, samples : Nat, width : U32, height : U32, i : U32, j : U32 } -init = \{ width, height, i, j } -> +init = |{ width, height, i, j }| { width, height, i, j, rng: RNG.init, color: Color.zero, samples: 0 } -update = \state -> +update = |state| camera = Camera.make { lookFrom: { x: 13, y: 2, z: 3 }, lookAt: { x: 0, y: 0, z: 0 }, @@ -28,32 +25,32 @@ update = \state -> focusDist: 10, } - uRng, uRand <- RNG.real state.rng - vRng, vRand <- RNG.real uRng + { uRng, uRand } = RNG.real state.rng + { vRng, vRand } = RNG.real uRng u = (Num.toFrac state.i + uRand) / Num.toFrac (state.width - 1) v = (Num.toFrac state.j + vRand) / Num.toFrac (state.height - 1) - cameraRng, ray <- Camera.ray camera u v vRng - colorRng, c <- raytrace ray scene 50 cameraRng + { cameraRng, ray } = Camera.ray camera u v state.rng + { colorRng, c } = raytrace ray scene 50 cameraRng (|rng, color| (rng, color)) { state & rng: colorRng, color: Color.add state.color c, samples: state.samples + 1 } -render = \{ color, samples } -> Color.toPixel color samples +render = |{ color, samples }| Color.toPixel color samples main = { init, update, render } raytrace : Ray, World, Nat, RNG, (RNG, Color -> a) -> a -raytrace = \ray, world, depth, rng, fn -> +raytrace = |ray, world, depth, rng, fn| if depth == 0 then fn rng Color.zero else when World.hit world ray { min: 0.001, max: Num.maxF64 } is Ok { rec, mat } -> - newRng, scatter <- Material.scatter mat ray rec rng + { newRng, scatter } = Material.scatter mat ray rec rng when scatter is Ok { attenuation, scattered } -> - innerNewRng, newColor <- raytrace scattered world (depth - 1) newRng + { innerNewRng, newColor } = raytrace scattered world (depth - 1) newRng fn innerNewRng (Color.mul attenuation newColor) Err NoHit -> @@ -70,12 +67,12 @@ raytrace = \ray, world, depth, rng, fn -> scene = spheres = - state, a <- List.range { start: At -11, end: Before 11 } |> List.walk { acc: [], rng: RNG.init } - innerState, b <- List.range { start: At -11, end: Before 11 } |> List.walk state + { state, a } = List.range { start: At -11, end: Before 11 } |> List.walk { acc: [], rng: state.rng } + { innerState, b } = List.range { start: At -11, end: Before 11 } |> List.walk state - chooseRng, choose <- RNG.real innerState.rng - xRng, x <- RNG.real chooseRng - zRng, z <- RNG.real xRng + { chooseRng, choose } = RNG.real innerState.rng + { xRng, x } = RNG.real chooseRng + { zRng, z } = RNG.real xRng center = { x: a + 0.9 * x, y: 0.2, z: b + 0.9 * z } size = Vec.sub center { x: 4, y: 0.2, z: 0 } |> Vec.length @@ -83,8 +80,8 @@ scene = if size > 0.9 then if choose < 0.8 then # diffuse - colorRng1, color1 <- RNG.color zRng - colorRng2, color2 <- RNG.color colorRng1 + { colorRng1, color1 } = RNG.color zRng + { colorRng2, color2 } = RNG.color colorRng1 albedo = Color.mul color1 color2 sphere = Sphere.make center 0.2 (Lambertian albedo) @@ -92,8 +89,8 @@ scene = { acc: List.append innerState.acc sphere, rng: colorRng2 } else if choose < 0.95 then # metal - albedoRng, albedo <- RNG.color zRng - fuzzRng, fuzz <- RNG.between albedoRng { min: 0, max: 0.5 } + { albedoRng, albedo } = RNG.color zRng + { fuzzRng, fuzz } = RNG.between albedoRng { min: 0, max: 0.5 } sphere = Sphere.make center 0.2 (Metal albedo fuzz)