trace' scene@(Scene _ world _ objs lights mats) ray@(Ray _ v) level
    = case fstIntersection objs ray of
        Nothing       -> mSky world
        Just (obj, t) -> let
            mat  = mats M.! mMaterialID obj
            x'   = extend t ray
            n    = normal (mSurface obj) x'
            col  = mconcat . map (lighting mat x' n objs) $ lights
            ray' = Ray x' $ normalize $ v <-> 2 * v <.> n *> n
            ref  = mReflect mat
            in if ref == 0 then col
                else col <> ref *> trace' scene ray' (level - 1)

-- | Compute the colour that a light source contributes at a particular point.
trace' scene@(Scene _ world _ objs lights mats) ray@(Ray _ v) level
    = case fstIntersection objs ray of
        Nothing       -> mSky world
        Just (obj, t) -> let
            mat  = mats M.! mMaterialID obj
            x'   = extend t ray
            n    = normal (mSurface obj) x'
            col  = mconcat . map (lighting mat x' n objs) $ lights
            ray' = Ray x' $ normalize $ v <-> 2 * v <.> n *> n
            ref  = mReflect mat
            in if ref == 0 then col
                else col <> ref *> trace' scene ray' (level - 1)

-- | Compute the colour that a light source contributes at a particular point.
trace' scene@(Scene _ world _ objs lights mats) ray@(Ray _ v) level
    = case fstIntersection objs ray of
        Nothing       -> mSky world
        Just (obj, t) -> let
            mat  = mats M.! mMaterialID obj
            x'   = extend t ray
            n    = normal (mSurface obj) x'
            col  = mconcat . map (lighting mat x' n objs) $ lights
            ray' = Ray x' $ normalize $ v <-> 2 * v <.> n *> n
            ref  = mReflect mat
            in if ref == 0 then col
                else col <> ref *> trace' scene ray' (level - 1)

-- | Compute the colour that a light source contributes at a particular point.