import type { QueryFilterFlags, World } from "@dimforge/rapier3d-compat";
import { AnimationClip, Color, Material, Mesh, Object3D, Quaternion, Vector4Like } from "three";
import { Vector3 } from "three";
import { type GLTF as THREE_GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
import type { Camera as CameraComponent } from "../engine-components/api.js";
import type { Context } from "./engine_context.js";
import { InstantiateContext } from "./engine_gameobject.js";
import { CollisionDetectionMode, type PhysicsMaterial, RigidbodyConstraints } from "./engine_physics.types.js";
import type { NeedleXRSession } from "./engine_xr.js";
/** Removes all properties that match TypesToFilter */
type FilterTypes<T, TypesToFilter> = {
    [P in keyof T as T[P] extends TypesToFilter ? never : P]: T[P];
};
/** Removes all undefined functions */
type NoUndefinedNoFunctions<T> = FilterTypes<T, Function | undefined | null>;
type FilterStartingWith<T, Prefix extends string> = {
    [K in keyof T as K extends string ? (K extends `${Prefix}${infer _}` ? never : K) : never]: T[K];
};
/** Removes all properties that start with an underscore */
type NoInternals<T> = FilterStartingWith<T, "_">;
type NoInternalNeedleEngineState<T> = Omit<T, "destroyed" | "gameObject" | "activeAndEnabled" | "context" | "isComponent" | "scene" | "up" | "forward" | "right" | "worldRotation" | "worldEuler" | "worldPosition" | "worldQuaternion">;
export type ComponentInit<T> = Partial<NoInternalNeedleEngineState<NoInternals<NoUndefinedNoFunctions<T>>>>;
/** GLTF, GLB or VRM */
export type GLTF = THREE_GLTF;
/** FBX type */
export type FBX = {
    animations: AnimationClip[];
    scene: Object3D;
    scenes: Object3D[];
};
/** OBJ type */
export type OBJ = {
    animations: AnimationClip[];
    scene: Object3D;
    scenes: Object3D[];
};
export type CustomModel = {
    animations: AnimationClip[];
    scene: Object3D;
    scenes: Object3D[];
};
/** All possible model types that Needle Engine can load */
export type Model = (GLTF | FBX | OBJ | CustomModel);
export declare function isGLTFModel(model: Model): model is GLTF;
/** A loaded model */
export type LoadedModel = {
    src: string;
    file: Model;
};
/** used to find data registered via gltf files e.g. find lightmaps for a Renderer component that were shipped inside a gltf */
export declare type SourceIdentifier = string;
export type Constructor<T> = abstract new (...args: any[]) => T;
export type ConstructorConcrete<T> = new (...args: any[]) => T;
export type GuidsMap = {
    [key: string]: string;
};
export interface UIDProvider {
    seed: number;
    generateUUID(): string;
}
export declare type CoroutineData = {
    comp: IComponent;
    main: Generator;
    chained?: Array<Generator>;
};
export interface ITime {
    get time(): number;
    get deltaTime(): number;
}
export interface IInput {
    convertScreenspaceToRaycastSpace(vec: Vec2): void;
    getPointerPosition(i: number): Vec2 | null;
}
export interface IPhysics {
    engine?: IPhysicsEngine;
}
export type IContext = Context;
export type INeedleXRSession = NeedleXRSession;
export declare interface INeedleEngineComponent extends HTMLElement {
    getAROverlayContainer(): HTMLElement;
    onEnterAR(session: XRSession, overlayContainer: HTMLElement): any;
    onExitAR(session: XRSession): any;
}
export declare enum HideFlags {
    None = 0,
    /** When enabled the glTF exporter will omit this object and all children from being exported */
    DontExport = 1
}
export declare interface IGameObject extends Object3D {
    /** the object's unique identifier */
    guid: string | undefined;
    /** if the object is enabled in the hierarchy (usually equivalent to `visible`) */
    activeSelf: boolean;
    /** call to destroy this object including all components that are attached to it. Will destroy all children recursively */
    destroy(): void;
    /** Add a new component to this object. Expects a component type (e.g. `addNewComponent(Animator)`) */
    addNewComponent<T extends IComponent>(type: Constructor<T>, init?: ComponentInit<T>): T;
    /** Remove a component from this object. Expected a component instance
     * @returns the removed component (equal to the passed in component)
     */
    addComponent<T extends IComponent>(comp: T | ConstructorConcrete<T>, init?: ComponentInit<T>): T;
    removeComponent<T extends IComponent>(comp: T): T;
    /** Searches for a component type on this object. If no component of the searched type exists yet a new instance will be created and returned */
    getOrAddComponent<T>(typeName: Constructor<T> | null): T;
    /** Tries to find a component of a type on this object.
     * @returns the first instance of a component on this object that matches the passed in type or null if no component of this type (or a subtype) exists */
    getComponent<T>(type: Constructor<T>): T | null;
    /** @returns all components of a certain type on this object */
    getComponents<T>(type: Constructor<T>, arr?: T[]): Array<T>;
    /** Finds a component of a certain type on this object OR a child object if any exists */
    getComponentInChildren<T>(type: Constructor<T>): T | null;
    /** Finds all components of a certain type on this object AND all children (recursively) */
    getComponentsInChildren<T>(type: Constructor<T>, arr?: T[]): Array<T>;
    /** Finds a component of a certain type on this object OR a parent object if any exists */
    getComponentInParent<T>(type: Constructor<T>): T | null;
    /** Finds all components of a certain type on this object AND all parents (recursively) */
    getComponentsInParent<T>(type: Constructor<T>, arr?: T[]): Array<T>;
    get worldPosition(): Vector3;
    set worldPosition(val: Vector3);
    get worldQuaternion(): Quaternion;
    set worldQuaternion(val: Quaternion);
    get worldRotation(): Vector3;
    set worldRotation(val: Vector3);
    get worldScale(): Vector3;
    set worldScale(val: Vector3);
    get worldForward(): Vector3;
    get worldRight(): Vector3;
    get worldUp(): Vector3;
}
export interface IHasGuid {
    guid: string;
}
export declare const $componentName: unique symbol;
export interface IComponent extends IHasGuid {
    get isComponent(): boolean;
    get [$componentName](): string | undefined;
    /** the object this component is attached to */
    gameObject: IGameObject;
    enabled: boolean;
    sourceId?: SourceIdentifier;
    get name(): string;
    get layer(): number;
    get destroyed(): boolean;
    get tag(): string;
    context: any;
    get activeAndEnabled(): boolean;
    /** @internal */
    __internalNewInstanceCreated(init?: ComponentInit<any>): any;
    /** @internal */
    _internalInit(init?: ComponentInit<any>): any;
    /** @internal */
    __internalAwake(): any;
    /** @internal */
    __internalStart(): any;
    /** @internal */
    __internalEnable(isAddingOrRemovingFromScene?: boolean): any;
    /** @internal */
    __internalDisable(isAddingOrRemovingFromScene?: boolean): any;
    /** @internal */
    __internalDestroy(): any;
    /** @internal */
    resolveGuids?(guidsMap: GuidsMap): void;
    /** experimental, called when the script is registered for the first time, this is called even if the component is not enabled. */
    registering?(): any;
    awake(): any;
    onEnable(): any;
    onDisable(): any;
    onDestroy(): any;
    destroy(): any;
    /** called for properties decorated with the @validate decorator */
    onValidate?(property?: string): any;
    /** called when this.context.isPaused changes or when rendering loop changes due to changing DOM element visibility
     * e.g. when the DOM element becomes hidden or out ot view
     */
    onPausedChanged?(isPaused: boolean, wasPaused: boolean): any;
    start?(): void;
    earlyUpdate?(): void;
    update?(): void;
    lateUpdate?(): void;
    onBeforeRender?(frame: XRFrame | null): void;
    onAfterRender?(): void;
    onCollisionEnter?(col: Collision): any;
    onCollisionExit?(col: Collision): any;
    onCollisionStay?(col: Collision): any;
    onTriggerEnter?(col: ICollider): any;
    onTriggerStay?(col: ICollider): any;
    onTriggerExit?(col: ICollider): any;
    get forward(): Vector3;
    get worldPosition(): Vector3;
    get worldQuaternion(): Quaternion;
}
export declare function isComponent(obj: any): obj is IComponent;
export type ICamera = CameraComponent;
export type IAnimationComponent = Pick<IComponent, "gameObject"> & {
    isAnimationComponent: boolean;
    addClip?(clip: AnimationClip): any;
};
/** Interface for a camera controller component that can be attached to a camera to control it */
export declare interface ICameraController {
    get isCameraController(): boolean;
}
export declare interface ILight extends IComponent {
    intensity: number;
    color: Color;
}
export declare interface ISharedMaterials {
    [num: number]: Material;
    get length(): number;
}
export declare interface IRenderer extends IComponent {
    sharedMaterial: Material;
    get sharedMaterials(): ISharedMaterials;
}
export declare interface IEventList {
    readonly isEventList: true;
    __internalOnInstantiate(map: InstantiateContext): IEventList;
}
export declare interface ICollider extends IComponent {
    get isCollider(): any;
    attachedRigidbody: IRigidbody | null;
    /**
     * Note: Make sure to call updatePhysicsMaterial after having changed this property
     */
    isTrigger: boolean;
    /**
     * The physics material determines how the collider interacts with other colliders (e.g. bouncyness)
     * Note: Make sure to call updatePhysicsMaterial after having changed this property
     */
    sharedMaterial?: PhysicsMaterial;
    center?: Vec3 & {
        multiply(vec: Vec3): any;
    };
    updateProperties(): void;
    updatePhysicsMaterial(): void;
    /** The collider membership indicates what groups the collider is part of (e.g. group 2 and 3)
     * An `undefined` array indicates that the collider is part of all groups
     * Note: Make sure to call updateProperties after having changed this property
     * Default: [0]
    */
    membership?: number[];
    /** The collider filter indicates what groups the collider can interact with (e.g. group 3 and 4)
     * An `undefined` array indicates that the collider can interact with all groups
     * Note: Make sure to call updateProperties after having changed this property
     * Default: undefined
    */
    filter?: number[];
}
export declare interface ISphereCollider extends ICollider {
    radius: number;
}
export declare interface IBoxCollider extends ICollider {
    size: Vec3;
}
export declare interface IRigidbody extends IComponent {
    get isRigidbody(): boolean;
    constraints: RigidbodyConstraints;
    isKinematic: boolean;
    /** When true the mass will automatically calculated by attached colliders */
    autoMass: boolean;
    mass: number;
    drag: number;
    angularDrag: number;
    useGravity: boolean;
    centerOfMass: Vec3;
    gravityScale: number;
    dominanceGroup: number;
    collisionDetectionMode: CollisionDetectionMode;
    lockPositionX: boolean;
    lockPositionY: boolean;
    lockPositionZ: boolean;
    lockRotationX: boolean;
    lockRotationY: boolean;
    lockRotationZ: boolean;
}
export declare const $physicsKey: unique symbol;
export declare type ICollisionContext = {
    getCollider(obj: Object3D): ICollider;
};
export type Vec2 = {
    x: number;
    y: number;
};
export type Vec3 = {
    x: number;
    y: number;
    z: number;
};
export type Vec4 = {
    x: number;
    y: number;
    z: number;
    w: number;
};
/**
 * Holds information about physics contacts
 */
export declare class ContactPoint {
    private readonly _point;
    private readonly _normal;
    private readonly _tangentVelocity;
    /** the distance of the collision point */
    readonly distance: number;
    /** the impulse velocity */
    readonly impulse: number;
    readonly friction: number;
    /** worldspace point */
    get point(): Vector3;
    /** worldspace normal */
    get normal(): Vector3;
    /** worldspace tangent */
    get tangentVelocity(): Vector3;
    /** @internal */
    constructor(point: Vec3, dist: number, normal: Vec3, impulse: number, friction: number, tangentVelocity: Vec3);
}
/**
 * Holds information about a collision event. Includes a list of contact points and the colliders involved
 */
export declare class Collision {
    /** The contact points of this collision. Contains information about positions, normals, distance, friction, impulse... */
    readonly contacts: ContactPoint[];
    /** @internal */
    constructor(obj: IGameObject, otherCollider: ICollider, contacts: ContactPoint[]);
    /** the gameobject this collision event belongs to (e.g. if onCollisionEnter is called then `me` is the same as `this.gameObject`) */
    readonly me: IGameObject;
    private _collider;
    /** the other collider the collision happened with */
    get collider(): ICollider;
    private _gameObject;
    /** the other object the collision happened with */
    get gameObject(): IGameObject;
    /** the other rigidbody we hit, null if none attached */
    get rigidBody(): IRigidbody | null;
}
export type RaycastResult = null | {
    point: Vector3;
    collider: ICollider;
    normal?: Vector3;
};
export declare class ShapeOverlapResult {
    readonly object: Object3D;
    readonly collider: ICollider;
    constructor(object: Object3D, collider: ICollider);
}
export interface IPhysicsEngine {
    /** Initializes the physics engine */
    initialize(): Promise<boolean>;
    /** Indicates whether the physics engine has been initialized */
    get isInitialized(): boolean;
    /** Advances physics simulation by the given time step */
    step(dt: number): void;
    postStep(): any;
    /** Indicates whether the physics engine is currently updating */
    get isUpdating(): boolean;
    /** Clears all cached data (e.g., mesh data when creating scaled mesh colliders) */
    clearCaches(): any;
    /** Enables or disables the physics engine */
    enabled: boolean;
    /** Returns the underlying physics world object */
    get world(): World | undefined;
    /** Sets the gravity vector for the physics simulation */
    set gravity(vec3: Vec3);
    /** Gets the current gravity vector */
    get gravity(): Vec3;
    /**
     * Gets the rapier physics body for a Needle component
     * @param obj The collider or rigidbody component
     * @returns The underlying physics body or null if not found
     */
    getBody(obj: ICollider | IRigidbody): null | any;
    /**
     * Gets the Needle Engine component for a rapier physics object
     * @param rapierObject The rapier physics object
     * @returns The associated component or null if not found
     */
    getComponent(rapierObject: object): IComponent | null;
    /**
     * Performs a fast raycast against physics colliders
     * @param origin Ray origin in screen or worldspace
     * @param direction Ray direction in worldspace
     * @param options Additional raycast configuration options
     * @returns Raycast result containing hit point and collider, or null if no hit
     */
    raycast(origin?: Vec2 | Vec3, direction?: Vec3, options?: {
        maxDistance?: number;
        /** True if you want to also hit objects when the raycast starts from inside a collider */
        solid?: boolean;
        queryFilterFlags?: QueryFilterFlags;
        /**
         * Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
         * The scene query will only consider hits with colliders with collision groups compatible with
         * this collision group (using the bitwise test described in the collision groups section).
         * For example membership 0x0001 and filter 0x0002 should be 0x00010002
         * @see https://rapier.rs/docs/user_guides/javascript/colliders#collision-groups-and-solver-groups
         */
        filterGroups?: number;
        /**
         * Predicate to filter colliders in raycast results
         * @param collider The collider being tested
         * @returns False to ignore this collider, true to include it
         */
        filterPredicate?: (collider: ICollider) => boolean;
    }): RaycastResult;
    /**
     * Performs a raycast that also returns the normal vector at the hit point
     * @param origin Ray origin in screen or worldspace
     * @param direction Ray direction in worldspace
     * @param options Additional raycast configuration options
     * @returns Raycast result containing hit point, normal, and collider, or null if no hit
     */
    raycastAndGetNormal(origin?: Vec2 | Vec3, direction?: Vec3, options?: {
        maxDistance?: number;
        /** True if you want to also hit objects when the raycast starts from inside a collider */
        solid?: boolean;
        queryFilterFlags?: QueryFilterFlags;
        /**
         * Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
         * The scene query will only consider hits with colliders with collision groups compatible with
         * this collision group (using the bitwise test described in the collision groups section).
         * For example membership 0x0001 and filter 0x0002 should be 0x00010002
         * @see https://rapier.rs/docs/user_guides/javascript/colliders#collision-groups-and-solver-groups
         */
        filterGroups?: number;
        /**
         * Predicate to filter colliders in raycast results
         * @param collider The collider being tested
         * @returns False to ignore this collider, true to include it
         */
        filterPredicate?: (collider: ICollider) => boolean;
    }): RaycastResult;
    /**
     * Finds all colliders within a sphere
     * @param point The center point of the sphere
     * @param radius The radius of the sphere
     * @returns Array of objects that overlap with the sphere
     */
    sphereOverlap(point: Vector3, radius: number): Array<ShapeOverlapResult>;
    /** box overlap detection using rapier against colliders
     * @param point center of the box in worldspace
     * @param size size of the box
     * @param rotation quaternion representation of the rotation in world space
     * @returns array of colliders that overlap with the box. Note: they currently only contain the collider and the gameobject
     */
    boxOverlap(point: Vector3, size: Vector3, rotation: Vector4Like | null): Array<ShapeOverlapResult>;
    /**
     * Creates a collider in the physics world.
     *
     * @param collider - The collider component.
     * @param desc - The collider description.
     * @returns The created collider.
     *
     * @throws Will throw an error if the physics world is not initialized. Make sure to call `initialize()` before creating colliders.
     *
     * @example
     * ```typescript
     * const boxColliderDesc = NEEDLE_ENGINE_MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.cuboid(1, 1, 1);
     * const collider = physicsEngine.createCollider(myBoxColliderComponent, boxColliderDesc);
     * ```
     */
    createCollider(collider: ICollider, desc: any): any;
    /**
     * Adds a sphere collider to the physics world
     * @param collider The collider component to add
     */
    addSphereCollider(collider: ICollider): any;
    /**
     * Adds a box collider to the physics world
     * @param collider The collider component to add
     * @param size The size of the box
     */
    addBoxCollider(collider: ICollider, size: Vector3): any;
    /**
     * Adds a capsule collider to the physics world
     * @param collider The collider component to add
     * @param radius The radius of the capsule
     * @param height The height of the capsule
     */
    addCapsuleCollider(collider: ICollider, radius: number, height: number): any;
    /**
     * Adds a mesh collider to the physics world
     * @param collider The collider component to add
     * @param mesh The mesh to use for collision
     * @param convex Whether the collision mesh should be treated as convex
     * @param scale Optional scale to apply to the mesh
     */
    addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, scale?: Vector3 | undefined): any;
    /**
     * Updates the physics material properties of a collider
     * @param collider The collider to update
     */
    updatePhysicsMaterial(collider: ICollider): any;
    /**
     * Wakes up a sleeping rigidbody
     * @param rb The rigidbody to wake up
     */
    wakeup(rb: IRigidbody): any;
    /**
     * Checks if a rigidbody is currently sleeping
     * @param rb The rigidbody to check
     * @returns Whether the rigidbody is sleeping or undefined if cannot be determined
     */
    isSleeping(rb: IRigidbody): boolean | undefined;
    /**
     * Updates the physical properties of a rigidbody or collider
     * @param rb The rigidbody or collider to update
     */
    updateProperties(rb: IRigidbody | ICollider): any;
    /**
     * Resets all forces acting on a rigidbody
     * @param rb The rigidbody to reset forces on
     * @param wakeup Whether to wake up the rigidbody
     */
    resetForces(rb: IRigidbody, wakeup: boolean): any;
    /**
     * Resets all torques acting on a rigidbody
     * @param rb The rigidbody to reset torques on
     * @param wakeup Whether to wake up the rigidbody
     */
    resetTorques(rb: IRigidbody, wakeup: boolean): any;
    /**
     * Adds a continuous force to a rigidbody
     * @param rb The rigidbody to add force to
     * @param vec The force vector to add
     * @param wakeup Whether to wake up the rigidbody
     */
    addForce(rb: IRigidbody, vec: Vec3, wakeup: boolean): any;
    /**
     * Applies an instantaneous impulse to a rigidbody
     * @param rb The rigidbody to apply impulse to
     * @param vec The impulse vector to apply
     * @param wakeup Whether to wake up the rigidbody
     */
    applyImpulse(rb: IRigidbody, vec: Vec3, wakeup: boolean): any;
    /**
     * Gets the linear velocity of a rigidbody or the rigidbody attached to a collider
     * @param rb The rigidbody or collider to get velocity from
     * @returns The linear velocity vector or null if not available
     */
    getLinearVelocity(rb: IRigidbody | ICollider): Vec3 | null;
    /**
     * Gets the angular velocity of a rigidbody
     * @param rb The rigidbody to get angular velocity from
     * @returns The angular velocity vector or null if not available
     */
    getAngularVelocity(rb: IRigidbody): Vec3 | null;
    /**
     * Sets the angular velocity of a rigidbody
     * @param rb The rigidbody to set angular velocity for
     * @param vec The angular velocity vector to set
     * @param wakeup Whether to wake up the rigidbody
     */
    setAngularVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean): any;
    /**
     * Sets the linear velocity of a rigidbody
     * @param rb The rigidbody to set linear velocity for
     * @param vec The linear velocity vector to set
     * @param wakeup Whether to wake up the rigidbody
     */
    setLinearVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean): any;
    /**
     * Updates the position and/or rotation of a physics body
     * @param comp The collider or rigidbody component to update
     * @param translation Whether to update the position
     * @param rotation Whether to update the rotation
     */
    updateBody(comp: ICollider | IRigidbody, translation: boolean, rotation: boolean): any;
    /**
     * Removes a physics body from the simulation
     * @param body The component whose physics body should be removed
     */
    removeBody(body: IComponent): any;
    /**
     * Gets the physics body for a component
     * @param obj The collider or rigidbody component
     * @returns The underlying physics body or null if not found
     */
    getBody(obj: ICollider | IRigidbody): null | any;
    addFixedJoint(body1: IRigidbody, body2: IRigidbody): any;
    addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: Vec3, axis: Vec3): any;
    /** Enable to render collider shapes */
    debugRenderColliders: boolean;
    /** Enable to visualize raycasts in the scene with gizmos */
    debugRenderRaycasts: boolean;
}
/**
 * Available cursor types
 * @link https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
 */
export type CursorTypeName = "auto" | "default" | "none" | "context-menu" | "help" | "pointer" | "progress" | "wait" | "cell" | "crosshair" | "text" | "vertical-text" | "alias" | "copy" | "move" | "no-drop" | "not-allowed" | "grab" | "grabbing" | "all-scroll" | "col-resize" | "row-resize" | "n-resize" | "e-resize" | "s-resize" | "w-resize" | "nw-resize" | "se-resize" | "sw-resize" | "ew-resize" | "ns-resize" | "nesw-resize" | "nwse-resize" | "zoom-in" | "zoom-out";
/** Typical mouse button names for most devices */
export type MouseButtonName = "left" | "right" | "middle";
/** Button names on typical controllers (since there seems to be no agreed naming)
 * https://w3c.github.io/gamepad/#remapping
 */
export type GamepadButtonName = "a-button" | "b-button" | "x-button" | "y-button";
/** Needle-defined names for stylus (MX Ink) */
export type StylusButtonName = "stylus-touch" | "stylus-tip";
/** Button names as used in the xr profile */
export type XRControllerButtonName = "thumbrest" | "xr-standard-trigger" | "xr-standard-squeeze" | "xr-standard-thumbstick" | "xr-standard-touchpad" | "menu" | GamepadButtonName | StylusButtonName;
export type XRGestureName = "pinch";
/** All known (types) button names for various devices and cases combined. You should use the device specific names if you e.g. know you only deal with a mouse use MouseButtonName  */
export type ButtonName = "unknown" | MouseButtonName | GamepadButtonName | XRControllerButtonName | XRGestureName;
export {};
