import type { Vec3 } from '../math/Vec3' import type { Quaternion } from '../math/Quaternion' import type { Body } from '../objects/Body' import type { Material } from '../material/Material' /** * The available shape types. */ export const SHAPE_TYPES = { /** SPHERE */ SPHERE: 1, /** PLANE */ PLANE: 2, /** BOX */ BOX: 4, /** COMPOUND */ COMPOUND: 8, /** CONVEXPOLYHEDRON */ CONVEXPOLYHEDRON: 16, /** HEIGHTFIELD */ HEIGHTFIELD: 32, /** PARTICLE */ PARTICLE: 64, /** CYLINDER */ CYLINDER: 128, /** TRIMESH */ TRIMESH: 256, } as const /** * ShapeType */ export type ShapeType = typeof SHAPE_TYPES[keyof typeof SHAPE_TYPES] export type ShapeOptions = ConstructorParameters[0] /** * Base class for shapes */ export class Shape { /** * Identifier of the Shape. */ id: number /** * The type of this shape. Must be set to an int > 0 by subclasses. */ type: ShapeType | 0 /** * The local bounding sphere radius of this shape. */ boundingSphereRadius: number /** * Whether to produce contact forces when in contact with other bodies. Note that contacts will be generated, but they will be disabled. * @default true */ collisionResponse: boolean /** * @default 1 */ collisionFilterGroup: number /** * @default -1 */ collisionFilterMask: number /** * Optional material of the shape that regulates contact properties. */ material: Material | null /** * The body to which the shape is added to. */ body: Body | null static idCounter = 0 /** * All the Shape types. */ static types = SHAPE_TYPES constructor( options: { /** * The type of this shape. */ type?: ShapeType /** * Whether to produce contact forces when in contact with other bodies. * @default true */ collisionResponse?: boolean /** * @default 1 */ collisionFilterGroup?: number /** * @default -1 */ collisionFilterMask?: number /** * Optional material of the shape that regulates contact properties. * @default null * @todo check this, the material is passed to the body, right? */ material?: Material } = {} ) { this.id = Shape.idCounter++ this.type = options.type || 0 this.boundingSphereRadius = 0 this.collisionResponse = options.collisionResponse ? options.collisionResponse : true this.collisionFilterGroup = options.collisionFilterGroup !== undefined ? options.collisionFilterGroup : 1 this.collisionFilterMask = options.collisionFilterMask !== undefined ? options.collisionFilterMask : -1 this.material = options.material ? options.material : null this.body = null } /** * Computes the bounding sphere radius. * The result is stored in the property `.boundingSphereRadius` */ updateBoundingSphereRadius(): void { throw `computeBoundingSphereRadius() not implemented for shape type ${this.type}` } /** * Get the volume of this shape */ volume(): number { throw `volume() not implemented for shape type ${this.type}` } /** * Calculates the inertia in the local frame for this shape. * @see http://en.wikipedia.org/wiki/List_of_moments_of_inertia */ calculateLocalInertia(mass: number, target: Vec3): void { throw `calculateLocalInertia() not implemented for shape type ${this.type}` } /** * @todo use abstract for these kind of methods */ calculateWorldAABB(pos: Vec3, quat: Quaternion, min: Vec3, max: Vec3): void { throw `calculateWorldAABB() not implemented for shape type ${this.type}` } }