packages feed

Box3D-0.1.0.0: cbits/box3d_shim.h

// SPDX-License-Identifier: BSD-3-Clause
//
// Thin C shim for the Box3D Haskell bindings.
//
// The Box3D public API passes and returns several small structs *by value*,
// which GHC's FFI cannot express in general. Ids are exempt: they are
// integer-only structs of at most 8 bytes, and on the supported 64-bit ABIs
// (x86-64 SysV and Win64, AArch64) they travel in a general-purpose register
// exactly like a uint32_t/uint64_t, so the Haskell side imports id-only
// functions directly with word-sized newtypes (see the _Static_asserts in
// box3d_shim.c). Everything else — float structs, which travel in vector
// registers or by hidden reference, and the config defs — is wrapped here
// into a pointer-based form. The naming convention is hs_<original b3 name>;
// a value that was returned by value is written through a trailing
// out-pointer, and a non-id value that was passed by value is taken through
// a const in-pointer.

#pragma once

#include "box3d/box3d.h"

// base.h -----------------------------------------------------------------

// b3Version b3GetVersion(void)
void hs_b3GetVersion(b3Version* out);

// math_functions.h -------------------------------------------------------

bool hs_b3IsValidVec3(const b3Vec3* a);
bool hs_b3IsValidQuat(const b3Quat* q);
bool hs_b3IsValidTransform(const b3Transform* a);
bool hs_b3IsValidMatrix3(const b3Matrix3* a);
bool hs_b3IsValidAABB(const b3AABB* a);
bool hs_b3IsValidPlane(const b3Plane* a);

// b3CosSin b3ComputeCosSin(float radians)
void hs_b3ComputeCosSin(float radians, b3CosSin* out);

// b3Quat b3ComputeQuatBetweenUnitVectors(b3Vec3 v1, b3Vec3 v2)
void hs_b3ComputeQuatBetweenUnitVectors(const b3Vec3* v1, const b3Vec3* v2, b3Quat* out);

// types.h: default definition constructors --------------------------------

void hs_b3DefaultWorldDef(b3WorldDef* out);
void hs_b3DefaultBodyDef(b3BodyDef* out);
void hs_b3DefaultShapeDef(b3ShapeDef* out);
void hs_b3DefaultFilter(b3Filter* out);
void hs_b3DefaultSurfaceMaterial(b3SurfaceMaterial* out);
void hs_b3DefaultQueryFilter(b3QueryFilter* out);
void hs_b3DefaultExplosionDef(b3ExplosionDef* out);
void hs_b3DefaultDebugDraw(b3DebugDraw* out);

// The world / body by-value accessors now live in the generated
// box3d_gen_shim.{h,c} (hsg_ prefix). This file keeps only the shims backing
// the hand-written scaffolding (base.h, math_functions.h, the *Def defaults).

// types.h: joint definition defaults ---------------------------------------

void hs_b3DefaultDistanceJointDef(b3DistanceJointDef* out);
void hs_b3DefaultMotorJointDef(b3MotorJointDef* out);
void hs_b3DefaultParallelJointDef(b3ParallelJointDef* out);
void hs_b3DefaultPrismaticJointDef(b3PrismaticJointDef* out);
void hs_b3DefaultRevoluteJointDef(b3RevoluteJointDef* out);
void hs_b3DefaultSphericalJointDef(b3SphericalJointDef* out);
void hs_b3DefaultWeldJointDef(b3WeldJointDef* out);
void hs_b3DefaultWheelJointDef(b3WheelJointDef* out);
void hs_b3DefaultFilterJointDef(b3FilterJointDef* out);

// shape queries -------------------------------------------------------------

// Box3D has no b3Shape_TestPoint (unlike 2D's b2Shape_TestPoint). This runs
// the GJK distance query between the shape and the point with radii applied
// and reports a clamped distance of zero; it needs engine-internal access to
// the shape's proxy, so it lives in the hand shim. Convex shapes only: mesh,
// height field and compound shapes report false, mirroring the 2D original.
bool hs_b3Shape_TestPoint(b3ShapeId shapeId, const b3Pos* point);

// Callback trampolines: fixed C functions with the engine's callback
// signatures. The context must point at an hs_b3Closure whose fn is a
// Haskell-wrapped function of the pointer-argument variant of the signature
// and whose context is the user context it receives.

typedef struct hs_b3Closure
{
	void* fn;
	void* context;
} hs_b3Closure;

float hs_b3CastResultTrampoline(b3ShapeId shapeId, b3Pos point, b3Vec3 normal, float fraction, uint64_t userMaterialId,
								int triangleIndex, int childIndex, void* context);
bool hs_b3PreSolveTrampoline(b3ShapeId shapeIdA, b3ShapeId shapeIdB, b3Pos point, b3Vec3 normal, void* context);
bool hs_b3MeshQueryTrampoline(b3Vec3 a, b3Vec3 b, b3Vec3 c, int triangleIndex, void* context);

// b3DebugDraw trampolines. The struct's nine callback slots share one context
// field, so they take a wider closure than hs_b3Closure: one Haskell-wrapped
// function per slot, in the declaration order of b3DebugDraw, followed by the
// user context. A NULL slot draws nothing.

typedef struct hs_b3DrawClosure
{
	void* shape;
	void* segment;
	void* transform;
	void* point;
	void* sphere;
	void* capsule;
	void* bounds;
	void* box;
	void* string;
	void* context;
} hs_b3DrawClosure;

void hs_b3DrawShapeTrampoline(void* userShape, b3WorldTransform transform, b3HexColor color, void* context);
void hs_b3DrawSegmentTrampoline(b3Pos p1, b3Pos p2, b3HexColor color, void* context);
void hs_b3DrawTransformTrampoline(b3WorldTransform transform, void* context);
void hs_b3DrawPointTrampoline(b3Pos p, float size, b3HexColor color, void* context);
void hs_b3DrawSphereTrampoline(b3Pos p, float radius, b3HexColor color, float alpha, void* context);
void hs_b3DrawCapsuleTrampoline(b3Pos p1, b3Pos p2, float radius, b3HexColor color, float alpha, void* context);
void hs_b3DrawBoundsTrampoline(b3AABB aabb, b3HexColor color, void* context);
void hs_b3DrawBoxTrampoline(b3Vec3 extents, b3WorldTransform transform, b3HexColor color, void* context);
void hs_b3DrawStringTrampoline(b3Pos p, const char* s, b3HexColor color, void* context);

// debug shapes --------------------------------------------------------------
// This is the slot to use when there is nothing to free.
void hs_b3NoopDestroyDebugShape(void* userShape, void* userContext);