{-# LANGUAGE ForeignFunctionInterface #-}

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

Box2D 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 @B2_API@ are bound here: the validators (handy
as ABI oracles for the "Box2D.MathTypes" 'Foreign.Storable.Storable'
instances) and a couple of by-value constructors.
-}
module Box2D.MathFunctions
  ( isValidVec2
  , isValidRotation
  , isValidTransform
  , isValidAABB
  , isValidPlane
  , computeCosSin
  , makeRot
  , rotGetAngle
  ) where

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

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

foreign import ccall unsafe "hs_b2IsValidVec2"
  c_b2IsValidVec2 :: Ptr Vec2 -> IO CBool

foreign import ccall unsafe "hs_b2IsValidRotation"
  c_b2IsValidRotation :: Ptr Rot -> IO CBool

foreign import ccall unsafe "hs_b2IsValidTransform"
  c_b2IsValidTransform :: Ptr Transform -> IO CBool

foreign import ccall unsafe "hs_b2IsValidAABB"
  c_b2IsValidAABB :: Ptr AABB -> IO CBool

foreign import ccall unsafe "hs_b2IsValidPlane"
  c_b2IsValidPlane :: Ptr Plane -> IO CBool

foreign import ccall unsafe "hs_b2ComputeCosSin"
  c_b2ComputeCosSin :: Float -> Ptr CosSin -> IO ()

foreign import ccall unsafe "hs_b2MakeRot"
  c_b2MakeRot :: Float -> Ptr Rot -> IO ()

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

-- | Is this a valid, normalized rotation?
isValidRotation :: Rot -> IO Bool
isValidRotation :: Rot -> IO Bool
isValidRotation = (Ptr Rot -> IO CBool) -> Rot -> IO Bool
forall a. Storable a => (Ptr a -> IO CBool) -> a -> IO Bool
withValid Ptr Rot -> IO CBool
c_b2IsValidRotation

-- | 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_b2IsValidTransform

-- | 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_b2IsValidAABB

-- | 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_b2IsValidPlane

-- | 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_b2ComputeCosSin Float
radians)

-- | Make a normalized rotation from an angle in radians.
makeRot :: Float -> IO Rot
makeRot :: Float -> IO Rot
makeRot Float
radians = (Ptr Rot -> IO ()) -> IO Rot
forall a. Storable a => (Ptr a -> IO ()) -> IO a
allocaOut (Float -> Ptr Rot -> IO ()
c_b2MakeRot Float
radians)

-- | The angle of a rotation in radians, in @(-pi, pi]@; the inverse of
-- 'makeRot'. Pure (upstream @b2Rot_GetAngle@ is an inline header function).
rotGetAngle :: Rot -> Float
rotGetAngle :: Rot -> Float
rotGetAngle (Rot Float
c Float
s) = Float -> Float -> Float
forall a. RealFloat a => a -> a -> a
atan2 Float
s Float
c