{-# LANGUAGE ForeignFunctionInterface #-}

{-| Low-level bindings to the exported (non-@inline@) functions of
@box3d/math_functions.h@.

Box3D implements most of its vector math as @static inline@ helpers, which
have no linkable symbols and are therefore out of scope for FFI. Only the
handful of functions marked @B3_API@ are bound here: the validators (handy
as ABI oracles for the "Box3D.MathTypes" 'Foreign.Storable.Storable'
instances) and a couple of by-value constructors.
-}
module Box3D.MathFunctions
  ( isValidVec3
  , isValidQuat
  , isValidTransform
  , isValidMatrix3
  , isValidAABB
  , isValidPlane
  , computeCosSin
  , computeQuatBetweenUnitVectors
  ) where

import Foreign
import Foreign.C.Types (CBool (..))

import Box3D.Internal (allocaOut, withValid)
import Box3D.MathTypes

foreign import ccall unsafe "hs_b3IsValidVec3"
  c_b3IsValidVec3 :: Ptr Vec3 -> IO CBool

foreign import ccall unsafe "hs_b3IsValidQuat"
  c_b3IsValidQuat :: Ptr Quat -> IO CBool

foreign import ccall unsafe "hs_b3IsValidTransform"
  c_b3IsValidTransform :: Ptr Transform -> IO CBool

foreign import ccall unsafe "hs_b3IsValidMatrix3"
  c_b3IsValidMatrix3 :: Ptr Matrix3 -> IO CBool

foreign import ccall unsafe "hs_b3IsValidAABB"
  c_b3IsValidAABB :: Ptr AABB -> IO CBool

foreign import ccall unsafe "hs_b3IsValidPlane"
  c_b3IsValidPlane :: Ptr Plane -> IO CBool

foreign import ccall unsafe "hs_b3ComputeCosSin"
  c_b3ComputeCosSin :: Float -> Ptr CosSin -> IO ()

foreign import ccall unsafe "hs_b3ComputeQuatBetweenUnitVectors"
  c_b3ComputeQuatBetweenUnitVectors :: Ptr Vec3 -> Ptr Vec3 -> Ptr Quat -> IO ()

-- | Is this a valid (finite, non-NaN) vector?
isValidVec3 :: Vec3 -> IO Bool
isValidVec3 :: Vec3 -> IO Bool
isValidVec3 = (Ptr Vec3 -> IO CBool) -> Vec3 -> IO Bool
forall a. Storable a => (Ptr a -> IO CBool) -> a -> IO Bool
withValid Ptr Vec3 -> IO CBool
c_b3IsValidVec3

-- | Is this a valid, normalized quaternion?
isValidQuat :: Quat -> IO Bool
isValidQuat :: Quat -> IO Bool
isValidQuat = (Ptr Quat -> IO CBool) -> Quat -> IO Bool
forall a. Storable a => (Ptr a -> IO CBool) -> a -> IO Bool
withValid Ptr Quat -> IO CBool
c_b3IsValidQuat

-- | Is this a valid rigid transform?
isValidTransform :: Transform -> IO Bool
isValidTransform :: Transform -> IO Bool
isValidTransform = (Ptr Transform -> IO CBool) -> Transform -> IO Bool
forall a. Storable a => (Ptr a -> IO CBool) -> a -> IO Bool
withValid Ptr Transform -> IO CBool
c_b3IsValidTransform

-- | Is this a valid 3x3 matrix?
isValidMatrix3 :: Matrix3 -> IO Bool
isValidMatrix3 :: Matrix3 -> IO Bool
isValidMatrix3 = (Ptr Matrix3 -> IO CBool) -> Matrix3 -> IO Bool
forall a. Storable a => (Ptr a -> IO CBool) -> a -> IO Bool
withValid Ptr Matrix3 -> IO CBool
c_b3IsValidMatrix3

-- | Is this a valid, bounded AABB?
isValidAABB :: AABB -> IO Bool
isValidAABB :: AABB -> IO Bool
isValidAABB = (Ptr AABB -> IO CBool) -> AABB -> IO Bool
forall a. Storable a => (Ptr a -> IO CBool) -> a -> IO Bool
withValid Ptr AABB -> IO CBool
c_b3IsValidAABB

-- | Is this a valid plane (finite, unit normal)?
isValidPlane :: Plane -> IO Bool
isValidPlane :: Plane -> IO Bool
isValidPlane = (Ptr Plane -> IO CBool) -> Plane -> IO Bool
forall a. Storable a => (Ptr a -> IO CBool) -> a -> IO Bool
withValid Ptr Plane -> IO CBool
c_b3IsValidPlane

-- | Compute a deterministic cosine/sine pair for the given angle in radians.
computeCosSin :: Float -> IO CosSin
computeCosSin :: Float -> IO CosSin
computeCosSin Float
radians = (Ptr CosSin -> IO ()) -> IO CosSin
forall a. Storable a => (Ptr a -> IO ()) -> IO a
allocaOut (Float -> Ptr CosSin -> IO ()
c_b3ComputeCosSin Float
radians)

-- | Compute the shortest-arc rotation between two unit vectors.
computeQuatBetweenUnitVectors :: Vec3 -> Vec3 -> IO Quat
computeQuatBetweenUnitVectors :: Vec3 -> Vec3 -> IO Quat
computeQuatBetweenUnitVectors Vec3
v1 Vec3
v2 =
  Vec3 -> (Ptr Vec3 -> IO Quat) -> IO Quat
forall a b. Storable a => a -> (Ptr a -> IO b) -> IO b
with Vec3
v1 ((Ptr Vec3 -> IO Quat) -> IO Quat)
-> (Ptr Vec3 -> IO Quat) -> IO Quat
forall a b. (a -> b) -> a -> b
$ \Ptr Vec3
p1 -> Vec3 -> (Ptr Vec3 -> IO Quat) -> IO Quat
forall a b. Storable a => a -> (Ptr a -> IO b) -> IO b
with Vec3
v2 ((Ptr Vec3 -> IO Quat) -> IO Quat)
-> (Ptr Vec3 -> IO Quat) -> IO Quat
forall a b. (a -> b) -> a -> b
$ \Ptr Vec3
p2 -> (Ptr Quat -> IO ()) -> IO Quat
forall a. Storable a => (Ptr a -> IO ()) -> IO a
allocaOut (Ptr Vec3 -> Ptr Vec3 -> Ptr Quat -> IO ()
c_b3ComputeQuatBetweenUnitVectors Ptr Vec3
p1 Ptr Vec3
p2)