Box3D
Safe HaskellNone
LanguageGHC2021

Box3D.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 Box3D.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

Box3D 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 -> Vec3 -> Float -> Word64 -> CInt -> CInt -> IO Float Source #

Cast visitor: called for each shape a world ray/shape cast finds, with the hit point, normal, fraction, user material id and triangle/child indices. 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 -> Vec3 -> 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 -> Vector PlaneResult -> IO Bool Source #

Mover collision visitor: the batch of collision planes gathered against one shape (see collideMover); return True to keep gathering.

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.

type MoverFilter = ShapeId -> IO Bool Source #

Mover shape filter: return True to consider the shape for mover collision.

withMoverFilterFcn :: MoverFilter -> (FunPtr MoverFilterFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a mover filter and the context to pass alongside it; both are released on exit.

type CompoundQuery = Ptr CompoundData -> CInt -> IO Bool Source #

Compound query visitor: compoundData childIndex; return True to continue. The compound data stays a raw Ptr (no Storable yet).

withCompoundQueryFcn :: CompoundQuery -> (FunPtr CompoundQueryFcn -> Ptr () -> IO a) -> IO a Source #

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

type MeshQuery = Vec3 -> Vec3 -> Vec3 -> CInt -> IO Bool Source #

Mesh query visitor: one triangle (three vertices and its index) per call; return True to continue. The vertices arrive by value in C, so this routes through hs_b3MeshQueryTrampoline.

withMeshQueryFcn :: MeshQuery -> (FunPtr MeshQueryFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a mesh-query visitor and the context to pass alongside it; 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 TreeQueryClosest = Float -> CInt -> Word64 -> IO Float Source #

Closest-point tree query visitor: distanceSqrMin proxyId userData; the returned value narrows the search radius (squared).

withTreeQueryClosestFcn :: TreeQueryClosest -> (FunPtr TreeQueryClosestCallbackFcn -> Ptr () -> IO a) -> IO a Source #

Run an action with a closest-query visitor and the context to pass alongside it (to queryClosest); 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 cloud).

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 Box3D 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.