content: {-# OPTIONS -fno-warn-missing-methods #-}
  
  module Vec3
          ( Vec3(..)
          , magnitudeV3
          , normaliseV3
          , mulsV3
          , dotV3
          , clampV3
          , clipV3)
  where
  
  
  data Vec3
          = Vec3 !Float !Float !Float
          deriving (Eq, Show)
  
  
  instance Num Vec3 where
   (+) (Vec3 x1 x2 x3) (Vec3 y1 y2 y3)
          = Vec3 (x1 + y1) (x2 + y2) (x3 + y3)
   {-# INLINE (+) #-}
  
   (-) (Vec3 x1 x2 x3) (Vec3 y1 y2 y3)
          = Vec3 (x1 - y1) (x2 - y2) (x3 - y3)
   {-# INLINE (-) #-}
  
   (*) (Vec3 x1 x2 x3) (Vec3 y1 y2 y3)
          = Vec3 (x1 * y1) (x2 * y2) (x3 * y3)
   {-# INLINE (*) #-}
  
  
  -- | Yield the magnitude of a vector.
  magnitudeV3 :: Vec3 -> Float
  magnitudeV3 (Vec3 x y z)
          = sqrt (x * x + y * y + z * z)
  {-# INLINE magnitudeV3 #-}
  
  
  -- | Normalise a vector to have unit length.
  normaliseV3 :: Vec3 -> Vec3
  normaliseV3 v
          = v `mulsV3` (1.0 / magnitudeV3 v)
  {-# INLINE normaliseV3 #-}
  
  
  -- | Multiply a vector by a scalar.
  mulsV3 :: Vec3 -> Float -> Vec3
  mulsV3 (Vec3 x1 y1 z1) s
          = Vec3 (s * x1) (s * y1) (s * z1)
  {-# INLINE mulsV3 #-}
  
  
  -- | Compute the dot product of two vectors.
  dotV3 :: Vec3 -> Vec3 -> Float
  dotV3 (Vec3 x1 y1 z1) (Vec3 x2 y2 z2)
          = x1 * x2 + y1 * y2 + z1 * z2
  {-# INLINE dotV3 #-}
  
  
  -- | Clamp a vectors components to some minimum and maximum values.
  clampV3 :: Vec3 -> Float -> Float -> Vec3
  clampV3 (Vec3 r g b) minVal maxVal
   = Vec3 (clamp r) (clamp g) (clamp b)
   where {-# INLINE clamp #-}
         clamp x
          | x <= minVal   = minVal
          | x >= maxVal   = maxVal
          | otherwise     = x
  {-# INLINE clampV3 #-}
  
  
  -- | Clip a vector's components to some maxiumum value.
  clipV3 :: Vec3 -> Float -> Vec3
  clipV3 (Vec3 r g b) maxVal
   = Vec3 (clip r) (clip g) (clip b)
   where {-# INLINE clip #-}
         clip x
          | x > maxVal    = maxVal
          | otherwise     = x
  {-# INLINE clipV3 #-}
  