mirror of
https://github.com/Smaug123/ray-tracing-fsharp
synced 2025-10-13 07:48:40 +00:00
101 lines
3.5 KiB
Forth
101 lines
3.5 KiB
Forth
namespace RayTracing
|
|
|
|
open System.Runtime.CompilerServices
|
|
|
|
/// An n-dimensional point.
|
|
/// We don't let you compare these for equality, because floats are hard.
|
|
[<NoEquality ; NoComparison ; Struct ; IsReadOnly>]
|
|
type Point = | Point of struct (float * float * float)
|
|
|
|
[<NoEquality ; NoComparison ; Struct ; IsReadOnly>]
|
|
type Vector = | Vector of struct (float * float * float)
|
|
|
|
[<Struct ; IsReadOnly ; NoEquality ; NoComparison>]
|
|
type UnitVector = | UnitVector of Vector
|
|
|
|
[<RequireQualifiedAccess>]
|
|
module Vector =
|
|
let dot (Vector (x, y, z)) (Vector (a, b, c)) : float = x * a + y * b + z * c
|
|
|
|
let sum (Vector (a, b, c)) (Vector (d, e, f)) = Vector (a + d, b + e, c + f)
|
|
|
|
let scale (scale : float) (vec : Vector) : Vector =
|
|
match vec with
|
|
| Vector (a, b, c) -> Vector (scale * a, scale * b, scale * c)
|
|
|
|
let difference (Vector (a, b, c)) (Vector (x, y, z)) : Vector = Vector (a - x, b - y, c - z)
|
|
|
|
let unitise (vec : Vector) : UnitVector voption =
|
|
let dot = dot vec vec
|
|
|
|
if Float.equal dot 0.0 then
|
|
ValueNone
|
|
else
|
|
let factor = 1.0 / sqrt dot
|
|
scale factor vec |> UnitVector |> ValueSome
|
|
|
|
let normSquared (vec : Vector) : float = dot vec vec
|
|
|
|
let equal (Vector (a, b, c)) (Vector (x, y, z)) : bool =
|
|
Float.equal a x && Float.equal b y && Float.equal c z
|
|
|
|
let make (x : float) (y : float) (z : float) = Vector (x, y, z)
|
|
|
|
let cross (Vector (x, y, z)) (Vector (a, b, c)) : Vector =
|
|
make (y * c - z * b) (z * a - x * c) (x * b - a * y)
|
|
|
|
[<RequireQualifiedAccess>]
|
|
module UnitVector =
|
|
let rec random (floatProducer : FloatProducer) (dimension : int) : UnitVector =
|
|
let struct (rand1, rand2, rand3) = floatProducer.GetThree ()
|
|
let x = (2.0 * rand1) - 1.0
|
|
let y = (2.0 * rand2) - 1.0
|
|
let z = (2.0 * rand3) - 1.0
|
|
|
|
Vector.make x y z
|
|
|> Vector.unitise
|
|
|> function
|
|
| ValueNone -> random floatProducer dimension
|
|
| ValueSome result -> result
|
|
|
|
let inline dot (UnitVector a) (UnitVector b) = Vector.dot a b
|
|
let inline dot' (UnitVector a) (b : Vector) = Vector.dot a b
|
|
let inline difference (UnitVector v1) (UnitVector v2) = Vector.difference v1 v2
|
|
let inline difference' (UnitVector v1) (v2 : Vector) = Vector.difference v1 v2
|
|
let inline scale (scale : float) (UnitVector vec) = Vector.scale scale vec
|
|
let inline flip (UnitVector vec) = UnitVector (Vector.scale -1.0 vec)
|
|
|
|
let basis (_ : int) : UnitVector[] =
|
|
[|
|
|
Vector (1.0, 0.0, 0.0) |> UnitVector
|
|
Vector (0.0, 1.0, 0.0) |> UnitVector
|
|
Vector (0.0, 0.0, 1.0) |> UnitVector
|
|
|]
|
|
|
|
let inline coordinate (i : int) (UnitVector (Vector (a, b, c))) : float =
|
|
match i with
|
|
| 0 -> a
|
|
| 1 -> b
|
|
| 2 -> c
|
|
| _ -> failwithf "Bad coordinate: %i" i
|
|
|
|
[<RequireQualifiedAccess>]
|
|
module Point =
|
|
|
|
let inline coordinate (i : int) (Point (x, y, z)) =
|
|
match i with
|
|
| 0 -> x
|
|
| 1 -> y
|
|
| 2 -> z
|
|
| _ -> failwithf "Bad coordinate: %i" i
|
|
|
|
let sum (Point (a, b, c)) (Point (x, y, z)) : Point = Point (a + x, b + y, c + z)
|
|
|
|
let differenceToThenFrom (Point (a, b, c)) (Point (x, y, z)) : Vector = Vector (a - x, b - y, c - z)
|
|
|
|
let equal (Point (a, b, c)) (Point (x, y, z)) : bool =
|
|
Float.equal a x && Float.equal b y && Float.equal c z
|
|
|
|
let make (x : float) (y : float) (z : float) = Point (x, y, z)
|
|
let inline dimension _ = 3
|