///
declare namespace Box2D {
/**
* merge in an extra {@link b2RopeDef} property; we were unable to describe this (pointer to array of floats)
* with WebIDL, so created bindings to it more manually.
*/
export interface b2RopeDef {
/** pointer to float */
masses: number;
/** @return pointer to float */
get_masses(): number;
/** @param masses pointer to float */
set_masses(masses: Box2D.WrapperObject | number): void;
}
/**
* Compute the point states given two manifolds. The states pertain to the transition from manifold1
* to manifold2. So state1 is either persist or remove while state2 is either add or persist.
* @param state1 a b2PointState enum value
* @param state2 a b2PointState enum value
*/
export const b2GetPointStates: (
state1: number, state2: number,
manifold1: Box2D.b2Manifold | number, manifold2: Box2D.b2Manifold | number
) => void;
/** Compute the collision manifold between two circles. */
export const b2CollideCircles: (
manifold: Box2D.b2Manifold | number,
circleA: Box2D.b2CircleShape | number, xfA: Box2D.b2Transform | number,
circleB: Box2D.b2CircleShape | number, xfB: Box2D.b2Transform | number
) => void;
/** Compute the collision manifold between a polygon and a circle. */
export const b2CollidePolygonAndCircle: (
manifold: Box2D.b2Manifold | number,
polygonA: Box2D.b2PolygonShape | number, xfA: Box2D.b2Transform | number,
circleB: Box2D.b2CircleShape | number, xfB: Box2D.b2Transform | number
) => void;
/** Compute the collision manifold between two polygons. */
export const b2CollidePolygons: (
manifold: Box2D.b2Manifold | number,
polygonA: Box2D.b2PolygonShape | number, xfA: Box2D.b2Transform | number,
polygonB: Box2D.b2PolygonShape | number, xfB: Box2D.b2Transform | number
) => void;
/** Compute the collision manifold between an edge and a circle. */
export const b2CollideEdgeAndCircle: (
manifold: Box2D.b2Manifold | number,
edgeA: Box2D.b2EdgeShape | number, xfA: Box2D.b2Transform | number,
circleB: Box2D.b2CircleShape | number, xfB: Box2D.b2Transform | number
) => void;
/** Compute the collision manifold between an edge and a polygon. */
export const b2CollideEdgeAndPolygon: (
manifold: Box2D.b2Manifold | number,
edgeA: Box2D.b2EdgeShape | number, xfA: Box2D.b2Transform | number,
polygonB: Box2D.b2PolygonShape | number, xfB: Box2D.b2Transform | number
) => void;
/** Clipping for contact manifolds. */
export const b2ClipSegmentToLine: (
vOut: Box2D.b2ClipVertex | number, vIn: Box2D.b2ClipVertex | number,
normal: Box2D.b2Vec2 | number,
offset: number,
vertexIndexA: number
) => number;
export const b2TestOverlap: {
/** determine if two AABBs overlap */
(a: Box2D.b2AABB | number, b: Box2D.b2AABB | number): boolean;
/** determine if two generic shapes overlap */
(
shapeA: Box2D.b2Shape | number, indexA: number,
shapeB: Box2D.b2Shape | number, indexB: number,
xfA: Box2D.b2Transform | number, xfB: Box2D.b2Transform | number,
): boolean;
};
/**
* Utility to compute linear stiffness values frequency and damping ratio.
* The result will be written-out into the {@link stiffness} and {@link damping} parameters you provide.
* @example
* const { _malloc, _free, b2LinearStiffness, HEAPF32 } = box2D;
* // allocate two 4-byte floats on emscripten heap
* const output_p = _malloc(Float32Array.BYTES_PER_ELEMENT * 2);
* // give Box2D pointers to our floats on the heap, so it can mutate them
* b2LinearStiffness(output_p, output_p + Float32Array.BYTES_PER_ELEMENT, 0.9, 0.3, bodyA, bodyB)
* // create a Float32Array view over our heap offset, destructure two floats out of it
* const [stiffness, damping] = HEAPF32.subarray(output_p >> 2)
* // free the memory we allocated
* _free(output_p);
*/
export const b2LinearStiffness: (
stiffness: Box2D.WrapperObject | number, damping: Box2D.WrapperObject | number,
frequencyHertz: number, dampingRatio: number,
bodyA: Box2D.b2Body | number, bodyB: Box2D.b2Body | number
) => void;
/**
* Utility to compute rotational stiffness values frequency and damping ratio.
* The result will be written-out into the {@link stiffness} and {@link damping} parameters you provide.
* @example
* const { _malloc, _free, b2AngularStiffness, HEAPF32 } = box2D;
* // allocate two 4-byte floats on emscripten heap
* const output_p = _malloc(Float32Array.BYTES_PER_ELEMENT * 2);
* // give Box2D pointers to our floats on the heap, so it can mutate them
* b2AngularStiffness(output_p, output_p + Float32Array.BYTES_PER_ELEMENT, 0.9, 0.3, bodyA, bodyB)
* // create a Float32Array view over our heap offset, destructure two floats out of it
* const [stiffness, damping] = HEAPF32.subarray(output_p >> 2)
* // free the memory we allocated
* _free(output_p);
*/
export const b2AngularStiffness: (
stiffness: Box2D.WrapperObject | number, damping: Box2D.WrapperObject | number,
frequencyHertz: number, dampingRatio: number,
bodyA: Box2D.b2Body | number, bodyB: Box2D.b2Body | number
) => void;
/**
* If Box2D sends you a number, but you know it's (for example) a pointer to
* an array of {@link b2Vec2}: use this to convert the pointer to JS objects.
* @param array_p pointer to (subclass of {@link WrapperObject})
* @param numElements length of array
* @param elementSize size of an instance of the array element (in bytes)
* @param ctor constructor for the array element
*/
export const reifyArray: ;
} = typeof WrapperObject>(
array_p: number,
numElements: number,
elementSize: number,
ctor: TargetClass
) => InstanceType[];
export interface Point {
x: number;
y: number;
}
/**
* If you need to give to Box2D an array of Box2D.b2Vec2: use this to turn JS objects
* into a Box2D.b2Vec2 object (which can be used to locate an array of b2Vec2s).
* @param points
* @return Tuple containing 0: A Box2D.b2Vec2 object, whose pointer can be taken to locate an array of b2Vec2s. 1: A destructor.
*/
export const pointsToVec2Array: (points: Point[]) => [vectors: Box2D.b2Vec2, destroy: () => void];
/**
* If you need to give to Box2D an array of Box2D.b2Vec2: use this to turn JS objects
* into a Box2D.b2Vec2 object (which can be used to locate an array of b2Vec2s).
* @param tuples
* @return Tuple containing 0: A Box2D.b2Vec2 object, whose pointer can be taken to locate an array of b2Vec2s. 1: A destructor.
*/
export const tuplesToVec2Array: (tuples: [x: number, y: number][]) => [vectors: Box2D.b2Vec2, destroy: () => void];
/**
* If you need to give to Box2D an array of floats: use this to turn JS numbers
* into a Box2D.WrapperObject (which can be used to locate an array of floats).
* @param floats
* @return Tuple containing 0: A Box2D.WrapperObject object, whose pointer can be taken to locate an array of floats. 1: A destructor.
*/
export const toFloatArray: (floats: number[]) => [wrapper: Box2D.WrapperObject, destroy: () => void];
/**
* Reveals the size (in bytes) of the instance constructed by any Box2D.WrapperObject subclass.
* Works by creating two instances, and calculating the difference between their pointers.
* This is not a *good* way to do this. For exploration only!
* @param ctor constructor for a subclass of Box2D.WrapperObject
* @return Size of the element which ctor constructs
*/
export const sizeof: ;
}>(ctor: TargetClass) => number;
/**
* If you need to give to Box2D an output param: use this to allocate the memory. We wrap it in a
* Box2D.WrapperObject subclass instance, so that you can read its members once Box2D fills them in.
* @param ctor constructor for the array element
* @param elementSizeBytes Size of array element in bytes
* @param {number} [elements=1] Number of array elements to allocate
* @return Tuple containing 0: Instance of Box2D.WrapperObject subclass (i.e. your ctor), whose pointer can be taken to locate your memory. 1: A destructor.
*/
export const allocateArray: ;
}>(
ctor: TargetClass,
elementSizeBytes: number,
elements?: number
) => [wrapper: InstanceType, destroy: () => void];
/**
* Calling `new` on an Emscripten object does two things:
* - allocates memory on the emscripten heap with {@link Box2D.malloc}()
* - creates an Emscripten-wrapped JS object using {@link Box2D.wrapPointer}().
*
* When you're done with the Emscripten-wrapped JS object, you should {@link Box2D.destroy}() it.
* destroy() does two things:
* - invokes the class's __destroy__, which performs {@link Box2D.free}()
* - this frees the dynamically-allocated memory from the WASM heap
* - deletes from the class's cache, the reference it retains to the Emscripten-wrapped JS object
* - this eliminates a JS memory leak
*
* There's a couple of gaps here.
* - how should we clean up after we ourselves invoke wrapPointer()?
* - how should we clean up after we receive an Emscripten-wrapped JS object from a method?
*
* LeakMitigator provides helper methods to solve those gaps.
*
* @example
* import Box2DFactory from 'box2d-wasm';
* import { LeakMitigator } from 'box2d-wasm';
* const { b2BodyDef, b2Vec2, b2World, getPointer }: typeof Box2D & EmscriptenModule = await Box2DFactory()
* const { freeLeaked, recordLeak } = new LeakMitigator()
*
* // we invoked `new`; we should `destroy()` when we're done with it
* const gravity = new b2Vec2(0, 10)
*
* // b2World takes a copy-by-value of gravity; we are done with it
* const world = new b2World(gravity)
* // free from WASM heap + delete cached JS reference
* destroy(gravity)
*
* const bd_ground = new b2BodyDef()
*
* // world#CreateBody() returns a JS object built via wrapPointer
* // b2Body::__cache__ retains a reference to the object
* const ground: Box2D.b2Body = recordLeak(world.CreateBody(bd_ground))
*
* // if we have created all the bodies we need from this template, we are free to destroy it.
* // world#CreateBody() does not retain any reference to it (it accepts b2BodyDef via copy-by-value)
* destroy(bd_ground)
*
* // fast-forward to later, where we tear down the Box2D experiment...
*
* for (let body: Box2D.b2Body = world.GetBodyList(); getPointer(body) !== getPointer(NULL); body = body.GetNext()) {
* // this b2Body was created with b2World#CreateBody(), so Box2D manages the memory, not us.
* // we should not use destroy(body). instead we should use b2World#DestroyBody()
* // this also destroys all fixtures on the body.
* world.DestroyBody(body);
* }
*
* // delete from the __cache__ of applicable b2* classes:
* // every JS object reference that this LeakMitigator recorded
* freeLeaked()
*/
export class LeakMitigator {
private readonly instances: Map>;
/**
* Convenience method to free an object from an Emscripten class's __cache__
*/
static freeFromCache: (
instance: Box2D.WrapperObject,
b2Class?: typeof Box2D.WrapperObject
) => void;
/**
* wrap this around any Emscripten method which returns an object.
* records the instance, so that we can free it from cache later
*/
recordLeak: (
instance: Instance,
b2Class?: typeof Box2D.WrapperObject
) => Instance;
/**
* prefer this over {@link Box2D.wrapPointer}.
* records the instance that's created, so that we can free it from cache later
*/
safeWrapPointer: <
TargetClass extends typeof Box2D.WrapperObject & (
new (...args: any[]) => InstanceType
) = typeof Box2D.WrapperObject
>(
pointer: number,
targetType?: TargetClass
) => InstanceType;
/**
* access the cache structure of each Emscripten class for which we recorded instances,
* then free from cache every instance that we recorded.
*/
freeLeaked: () => void;
}
}