module Geometry.Intersect
  ( Hit
  , ray'plane
  ) where

import RIO

import Geomancy.Vec3 (dot, (^*))

import Geometry.Hit (Hit(..))
import Geometry.Plane (Plane)
import Geometry.Plane qualified as Plane
import Geometry.Ray (Ray)
import Geometry.Ray qualified as Ray

ray'plane
  :: Ray
  -> Plane
  -> Maybe Hit
ray'plane :: Ray -> Plane -> Maybe Hit
ray'plane Ray
ray Plane
plane =
  -- XXX: Ignore "glancing" hits from either side of a plane
  if (forall a. Num a => a -> a
abs Float
denom forall a. Ord a => a -> a -> Bool
> Float
eps) then
    forall a. a -> Maybe a
Just Hit
      { $sel:distance:Hit :: Float
distance = Float
t
      , $sel:cosine:Hit :: Float
cosine   = Float
denom
      , $sel:position:Hit :: Vec3
position = Vec3
hit
      }
  else
    forall a. Maybe a
Nothing
  where
    eps :: Float
eps = Float
1forall a. Fractional a => a -> a -> a
/Float
32

    denom :: Float
denom =
      Plane -> Vec3
Plane.normal Plane
plane Vec3 -> Vec3 -> Float
`dot` Ray -> Vec3
Ray.direction Ray
ray

    t :: Float
t =
      forall a. Num a => a -> a
negate ((Plane -> Vec3
Plane.normal Plane
plane Vec3 -> Vec3 -> Float
`dot` Ray -> Vec3
Ray.origin Ray
ray) forall a. Num a => a -> a -> a
+ Plane -> Float
Plane.depth Plane
plane) forall a. Fractional a => a -> a -> a
/ Float
denom

    hit :: Vec3
hit =
      Ray -> Vec3
Ray.origin Ray
ray forall a. Num a => a -> a -> a
+ Ray -> Vec3
Ray.direction Ray
ray Vec3 -> Float -> Vec3
^* Float
t