var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Euler, Plane, Quaternion, Vector3 } from "three";
import { serializable } from "../engine/engine_serialization_decorator.js";
import * as utils from "./../engine/engine_three_utils.js";
import { Behaviour, GameObject } from "./Component.js";
/**
 * The [OffsetConstraint](https://engine.needle.tools/docs/api/OffsetConstraint) maintains a fixed positional and rotational offset relative to a target object.
 * Useful for attaching objects to moving targets while preserving a specific spatial relationship.
 *
 * **Use cases:**
 * - Camera following a player with offset
 * - UI elements attached to characters
 * - Weapons attached to hands
 * - Objects orbiting around a target
 *
 * **Options:**
 * - `affectPosition` - Apply position offset
 * - `affectRotation` - Apply rotation offset
 * - `alignLookDirection` - Make object face same direction as target
 * - `levelLookDirection` - Keep look direction horizontal (ignore pitch)
 * - `levelPosition` - Project position onto horizontal plane
 * - `referenceSpace` - Transform offset in this object's coordinate space
 *
 * @example Attach camera offset to player
 * ```ts
 * const constraint = camera.addComponent(OffsetConstraint);
 * // Configure via serialized properties in editor
 * ```
 *
 * @summary Maintains positional/rotational offset relative to target
 * @category Constraints
 * @group Components
 * @see {@link SmoothFollow} for smoothed following
 * @see {@link LookAtConstraint} for aim constraints
 * @see {@link AlignmentConstraint} for alignment between two objects
 */
export class OffsetConstraint extends Behaviour {
    referenceSpace;
    from;
    affectPosition = false;
    affectRotation = false;
    alignLookDirection = false;
    levelLookDirection = false;
    levelPosition = false;
    positionOffset = new Vector3(0, 0, 0);
    rotationOffset = new Vector3(0, 0, 0);
    offset = new Vector3(0, 0, 0);
    update() {
        if (!this.from)
            return;
        var pos = utils.getWorldPosition(this.from);
        var rot = utils.getWorldQuaternion(this.from);
        this.offset.copy(this.positionOffset);
        const l = this.offset.length();
        if (this.referenceSpace)
            this.offset.transformDirection(this.referenceSpace.matrixWorld).multiplyScalar(l);
        pos.add(this.offset);
        if (this.levelPosition && this.referenceSpace) {
            const plane = new Plane(this.gameObject.up, 0);
            const refSpacePoint = utils.getWorldPosition(this.referenceSpace);
            plane.setFromNormalAndCoplanarPoint(this.gameObject.up, refSpacePoint);
            const v2 = new Vector3(0, 0, 0);
            plane.projectPoint(pos, v2);
            pos.copy(v2);
        }
        if (this.affectPosition)
            utils.setWorldPosition(this.gameObject, pos);
        const euler = new Euler(this.rotationOffset.x, this.rotationOffset.y, this.rotationOffset.z);
        const quat = new Quaternion().setFromEuler(euler);
        if (this.affectRotation)
            utils.setWorldQuaternion(this.gameObject, rot.multiply(quat));
        const lookDirection = new Vector3();
        this.from.getWorldDirection(lookDirection).multiplyScalar(50);
        if (this.levelLookDirection)
            lookDirection.y = 0;
        if (this.alignLookDirection)
            this.gameObject.lookAt(lookDirection);
    }
}
__decorate([
    serializable(GameObject)
], OffsetConstraint.prototype, "referenceSpace", void 0);
__decorate([
    serializable(GameObject)
], OffsetConstraint.prototype, "from", void 0);
__decorate([
    serializable(Vector3)
], OffsetConstraint.prototype, "positionOffset", void 0);
__decorate([
    serializable(Vector3)
], OffsetConstraint.prototype, "rotationOffset", void 0);
//# sourceMappingURL=OffsetConstraint.js.map