Box2D
Safe HaskellNone
LanguageGHC2021

Box2D.Callbacks

Description

Producing FunPtr callbacks from Haskell closures, and a ready-made multithreaded task system.

The generated bindings take callbacks as raw FunPtr Tag (see Box2D.Tags); this module is the hand-written counterpart that turns an ordinary Haskell function into such a FunPtr via foreign import "wrapper", and frees it again. Every mk* returns a FunPtr the caller must freeHaskellFunPtr (use the with* brackets to get that for free).

Threads

Box2D invokes these callbacks from its solver, which runs on background worker threads when worldDefWorkerCount > 1 — either its own scheduler, or the TaskSystem installed here. A Haskell closure wrapped as a FunPtr is therefore entered concurrently from several non-Haskell OS threads, so the program must be built with the threaded runtime (-threaded) and the closure must be thread-safe. Because the solver's task work re-enters Haskell through these callbacks, the task dispatch is a safe call.

Synopsis

Leaf callbacks

type CustomFilter = ShapeId -> ShapeId -> Ptr () -> IO Bool Source #

Decide whether two shapes should collide (see setCustomFilterCallback). The Ptr is the user context.

mkCustomFilterFcn :: CustomFilter -> IO (FunPtr CustomFilterFcn) Source #

Wrap a Haskell predicate as a custom-filter callback. Free it with freeHaskellFunPtr when the world no longer references it.

withCustomFilterFcn :: CustomFilter -> (FunPtr CustomFilterFcn -> IO a) -> IO a Source #

Run an action with a custom-filter callback that is freed on exit.

type Friction = Float -> Word64 -> Float -> Word64 -> IO Float Source #

Combine the friction of two materials (see setFrictionCallback): frictionA userMatA frictionB userMatB.

mkFrictionCallback :: Friction -> IO (FunPtr FrictionCallback) Source #

Wrap a Haskell function as a friction-mixing callback.

withFrictionCallback :: Friction -> (FunPtr FrictionCallback -> IO a) -> IO a Source #

Run an action with a friction callback that is freed on exit.

type Restitution = Float -> Word64 -> Float -> Word64 -> IO Float Source #

Combine the restitution of two materials (see setRestitutionCallback); same shape as Friction.

mkRestitutionCallback :: Restitution -> IO (FunPtr RestitutionCallback) Source #

Wrap a Haskell function as a restitution-mixing callback.

withRestitutionCallback :: Restitution -> (FunPtr RestitutionCallback -> IO a) -> IO a Source #

Run an action with a restitution callback that is freed on exit.

Query and cast visitors

type OverlapResult = ShapeId -> IO Bool Source #

Overlap query visitor: called for each shape found; return True to continue the query.

withOverlapResultFcn :: OverlapResult -> (FunPtr OverlapResultFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with an overlap visitor and the context to pass alongside it (e.g. to overlapAABB); both are released on exit.

type CastResult = ShapeId -> Pos -> Vec2 -> Float -> IO Float Source #

Cast visitor: called for each shape a world ray/shape cast finds, with the hit point, normal and fraction. The returned fraction controls the query: 0 terminates, the given fraction clips the ray, 1 continues.

withCastResultFcn :: CastResult -> (FunPtr CastResultFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a cast visitor and the context to pass alongside it (e.g. to castRay); both are released on exit.

type PreSolve = ShapeId -> ShapeId -> Pos -> Vec2 -> IO Bool Source #

Contact gate, called after narrow phase but before the solver: return False to disable the contact. Fired from solver worker threads when the world is multithreaded, so it must be thread-safe. Requires shapeDefEnablePreSolveEvents on the shapes.

withPreSolveFcn :: PreSolve -> (FunPtr PreSolveFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a pre-solve gate and the context to pass alongside it (to setPreSolveCallback). Unhook the callback from the world before the action returns: both are released on exit.

type PlaneResultVisitor = ShapeId -> PlaneResult -> IO Bool Source #

Mover collision visitor: one collision plane per convex shape the mover capsule touches (see collideMover); return True to keep gathering planes.

withPlaneResultFcn :: PlaneResultVisitor -> (FunPtr PlaneResultFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a mover-plane visitor and the context to pass alongside it (to collideMover); both are released on exit.

Dynamic-tree visitors

type TreeQuery = CInt -> Word64 -> IO Bool Source #

Tree query visitor: proxyId userData; return True to continue the query.

withTreeQueryFcn :: TreeQuery -> (FunPtr TreeQueryCallbackFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a tree-query visitor and the context to pass alongside it (to query); both are released on exit.

type TreeRayCast = RayCastInput -> CInt -> Word64 -> IO Float Source #

Tree ray-cast visitor: the (possibly clipped) input, proxyId and userData. The returned fraction controls the query: 0 terminates, the given fraction clips the ray, 1 continues.

withTreeRayCastFcn :: TreeRayCast -> (FunPtr TreeRayCastCallbackFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a tree ray-cast visitor and the context to pass alongside it (to rayCast); both are released on exit.

type TreeBoxCast = Ptr BoxCastInput -> CInt -> Word64 -> IO Float Source #

Tree box-cast visitor. The input stays a raw Ptr (BoxCastInput has no Storable yet: it embeds a ShapeProxy point array).

withTreeBoxCastFcn :: TreeBoxCast -> (FunPtr TreeBoxCastCallbackFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a tree box-cast visitor and the context to pass alongside it (to boxCast); both are released on exit.

A multithreaded task system

data TaskSystem Source #

The two callbacks (ready to poke into worldDefEnqueueTask / worldDefFinishTask) plus the worker count to set on worldDefWorkerCount.

withThreadPoolTaskSystem :: Int -> (TaskSystem -> IO a) -> IO a Source #

Install a Haskell thread-pool task system for the duration of an action, so the Box2D solver runs across the threaded runtime's capabilities. Set worldDefWorkerCount, worldDefEnqueueTask and worldDefFinishTask from the TaskSystem before creating the world.

Each enqueued task is run on a fresh forkIO thread; finishTask joins it. The task's handle travels through the engine as a StablePtr to its join MVar. Requires -threaded.