import { AppObjectUC, getSingletonComponent, } from "@vived/core";
import { Angle, Quaternion, Vector2, Vector3 } from "@vived/core";
import { scenePixelPick } from "../../Babylon";
import { dispatchStateChange } from "../../Dispatcher";
import { SceneRootEntity } from "../Entities/SceneRootEntity";
export class OrbitSceneRootUC extends AppObjectUC {
}
OrbitSceneRootUC.type = "OrbitSceneRootUC";
OrbitSceneRootUC.get = (appObjects) => getSingletonComponent(OrbitSceneRootUC.type, appObjects);
export function makeOrbitSceneRootUC(appObject) {
    return new OrbitSceneRootImp(appObject);
}
class OrbitSceneRootImp extends OrbitSceneRootUC {
    constructor(appObject) {
        super(appObject, OrbitSceneRootUC.type);
        this.sensitivity = 0.1;
        this.lastPixelPos = Vector2.Zero();
        this.pickPoint = Vector3.Zero();
        this.localPickOffset = Vector3.Zero();
        this.initialQuat = Quaternion.Identity();
        this.hasBeenInitialized = false;
        this.doOrbit = (pixelPosition) => {
            if (!this.transformNode)
                return;
            if (!this.hasBeenInitialized)
                return;
            const pixelChange = Vector2.Subtract(pixelPosition, this.lastPixelPos);
            const pitchAngle = Angle.FromDegrees(pixelChange.y * this.sensitivity);
            const pitchQuaternion = Quaternion.FromAngleAxis(Vector3.Left(), pitchAngle);
            this.transformNode.worldRotation = Quaternion.Multiply(pitchQuaternion, this.transformNode.worldRotation);
            const worldUp = this.transformNode.localDirectionToWorld(Vector3.Up());
            let xMovement = pixelChange.x;
            if (worldUp.y < 0) {
                xMovement = -pixelChange.x;
            }
            const headingAngle = Angle.FromDegrees(xMovement * this.sensitivity);
            const headingQuaternion = Quaternion.FromAngleAxis(Vector3.Down(), headingAngle);
            this.transformNode.localRotation = Quaternion.Multiply(this.transformNode.localRotation, headingQuaternion);
            const worldPickOffset = this.transformNode.localPointToWorld(this.localPickOffset);
            const bump = Vector3.Subtract(this.pickPoint, worldPickOffset);
            this.transformNode.worldPosition = Vector3.Add(bump, this.transformNode.worldPosition);
            this.lastPixelPos = pixelPosition;
        };
        this.initializeOrbit = (initialPixelPos) => {
            if (!this.transformNode)
                return;
            this.lastPixelPos = initialPixelPos;
            const pick = scenePixelPick(initialPixelPos, this.appObjects);
            this.pickPoint = pick?.worldPickPoint ?? Vector3.Zero();
            this.localPickOffset = this.transformNode.worldPointToLocal(this.pickPoint);
            this.transformNode.cancelLerp();
            this.hasBeenInitialized = true;
            this.initialQuat = this.transformNode.localRotation;
        };
        this.finishOrbit = () => {
            this.hasBeenInitialized = false;
            if (!this.transformNode)
                return;
            if (Quaternion.Equal(this.initialQuat, this.transformNode.localRotation))
                return;
            dispatchStateChange(this.appObjects);
        };
        this.cancelOrbit = () => {
            this.hasBeenInitialized = false;
        };
        this.sceneRoot = appObject.getComponent(SceneRootEntity.type);
        if (!this.sceneRoot) {
            this.warn("OrbitSceneRootImp UC has been added to an App Object that does not have a SceneRoot Entity");
            return;
        }
        this.transformNode = this.sceneRoot?.transform;
    }
}
//# sourceMappingURL=OrbitSceneRoot.js.map