{-# LINE 1 "src/Box2D/Base.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}

-- | Low-level bindings to @box2d/base.h@: version info, global allocator /
-- assert / log hooks, and timing helpers.
module Box2D.Base
  ( -- * Version
    Version (..)
  , getVersion
  , isDoublePrecision

    -- * Allocator
  , AllocFcn
  , FreeFcn
  , setAllocator
  , getByteCount

    -- * Assert / log hooks
  , AssertFcn
  , LogFcn
  , setAssertFcn
  , setLogFcn

    -- * Timing
  , getTicks
  , getMilliseconds
  , getMillisecondsAndReset
  , yield
  , hash
  ) where

import Foreign
import Foreign.C.Types
import Foreign.C.String (CString)

import Box2D.Internal (allocaOut)



-- | Version numbering scheme, see <https://semver.org/>.
data Version = Version
  { Version -> CInt
versionMajor    :: CInt
  , Version -> CInt
versionMinor    :: CInt
  , Version -> CInt
versionRevision :: CInt
  }
  deriving (Version -> Version -> Bool
(Version -> Version -> Bool)
-> (Version -> Version -> Bool) -> Eq Version
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Version -> Version -> Bool
== :: Version -> Version -> Bool
$c/= :: Version -> Version -> Bool
/= :: Version -> Version -> Bool
Eq, Int -> Version -> ShowS
[Version] -> ShowS
Version -> String
(Int -> Version -> ShowS)
-> (Version -> String) -> ([Version] -> ShowS) -> Show Version
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Version -> ShowS
showsPrec :: Int -> Version -> ShowS
$cshow :: Version -> String
show :: Version -> String
$cshowList :: [Version] -> ShowS
showList :: [Version] -> ShowS
Show)

instance Storable Version where
  sizeOf :: Version -> Int
sizeOf Version
_ = (Int
12)
{-# LINE 49 "src/Box2D/Base.hsc" #-}
  alignment _ = 4
{-# LINE 50 "src/Box2D/Base.hsc" #-}
  peek p =
    Version
      <$> (\hsc_ptr -> peekByteOff hsc_ptr 0) p
{-# LINE 53 "src/Box2D/Base.hsc" #-}
      <*> (\hsc_ptr -> peekByteOff hsc_ptr 4) p
{-# LINE 54 "src/Box2D/Base.hsc" #-}
      <*> (\hsc_ptr -> peekByteOff hsc_ptr 8) p
{-# LINE 55 "src/Box2D/Base.hsc" #-}
  poke p (Version ma mi re) = do
    (\hsc_ptr -> pokeByteOff hsc_ptr 0) p ma
{-# LINE 57 "src/Box2D/Base.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 4) p mi
{-# LINE 58 "src/Box2D/Base.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 8) p re
{-# LINE 59 "src/Box2D/Base.hsc" #-}

foreign import ccall unsafe "hs_b2GetVersion"
  c_b2GetVersion :: Ptr Version -> IO ()

-- | Get the current version of Box2D.
getVersion :: IO Version
getVersion :: IO Version
getVersion = (Ptr Version -> IO ()) -> IO Version
forall a. Storable a => (Ptr a -> IO ()) -> IO a
allocaOut Ptr Version -> IO ()
c_b2GetVersion

-- | 'True' if the library was built with @BOX2D_DOUBLE_PRECISION@.
foreign import ccall unsafe "b2IsDoublePrecision"
  c_b2IsDoublePrecision :: IO CBool

isDoublePrecision :: IO Bool
isDoublePrecision :: IO Bool
isDoublePrecision = (CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/= CBool
0) (CBool -> Bool) -> IO CBool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO CBool
c_b2IsDoublePrecision

-- Allocator ---------------------------------------------------------------

-- | User allocation function: @void* (size_t size, int alignment)@.
type AllocFcn = CSize -> CInt -> IO (Ptr ())

-- | User free function: @void (void* mem, size_t size)@.
type FreeFcn = Ptr () -> CSize -> IO ()

-- | Override the default allocation functions. Set during application startup.
--
-- The 'FunPtr's must point to C functions: the engine calls the hooks from
-- inside @unsafe@ FFI calls, where re-entering Haskell is undefined
-- behaviour, so wrapping Haskell functions is not supported yet.
foreign import ccall unsafe "b2SetAllocator"
  setAllocator :: FunPtr AllocFcn -> FunPtr FreeFcn -> IO ()

-- | Total bytes allocated by Box2D.
foreign import ccall unsafe "b2GetByteCount"
  getByteCount :: IO Int64

-- Assert / log ------------------------------------------------------------

-- | Assert callback: @int (const char* condition, const char* file, int line)@.
-- Return 0 to skip the debugger break.
type AssertFcn = CString -> CString -> CInt -> IO CInt

-- | Log callback: @void (const char* message)@.
type LogFcn = CString -> IO ()

-- | Override the default assert callback. Must point to a C function, see
-- 'setAllocator'.
foreign import ccall unsafe "b2SetAssertFcn"
  setAssertFcn :: FunPtr AssertFcn -> IO ()

-- | Override the default logging callback. Must point to a C function, see
-- 'setAllocator'.
foreign import ccall unsafe "b2SetLogFcn"
  setLogFcn :: FunPtr LogFcn -> IO ()

-- Timing ------------------------------------------------------------------

-- | Absolute number of system ticks. The value is platform specific.
foreign import ccall unsafe "b2GetTicks"
  getTicks :: IO Word64

-- | Milliseconds passed from an initial tick value.
foreign import ccall unsafe "b2GetMilliseconds"
  getMilliseconds :: Word64 -> IO CFloat

-- | Milliseconds passed from an initial tick value, resetting it to now.
foreign import ccall unsafe "b2GetMillisecondsAndReset"
  getMillisecondsAndReset :: Ptr Word64 -> IO CFloat

-- | Yield to be used in a busy loop.
foreign import ccall unsafe "b2Yield"
  yield :: IO ()

-- | Simple djb2 hash function for determinism testing.
foreign import ccall unsafe "b2Hash"
  hash :: Word32 -> Ptr Word8 -> CInt -> IO Word32