"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LookAtCameraUC = void 0;
exports.makeLookAtCameraUC = makeLookAtCameraUC;
const core_1 = require("@vived/core");
const SceneRootEntity_1 = require("../../SceneRoot/Entities/SceneRootEntity");
const CalloutEntity_1 = require("../Entities/CalloutEntity");
class LookAtCameraUC extends core_1.AppObjectUC {
    static get(appObj) {
        return appObj.getComponent(this.type);
    }
}
exports.LookAtCameraUC = LookAtCameraUC;
LookAtCameraUC.type = "LookAtCameraUC";
function makeLookAtCameraUC(appObject) {
    return new LookAtCameraUCIMP(appObject);
}
class LookAtCameraUCIMP extends LookAtCameraUC {
    get sceneRootEntity() {
        return this.getCachedSingleton(SceneRootEntity_1.SceneRootEntity.type);
    }
    get callout() {
        return this.getCachedLocalComponent(CalloutEntity_1.CalloutEntity.type);
    }
    kickOffSlerping() {
        if (this.slerpInterval) {
            this.stopSlerping();
        }
        this.isSlerping = true;
        const transform = this.callout?.labelTransform;
        if (!transform)
            return;
        let previousError = core_1.Quaternion.AngleBetween(transform.worldRotation, this.targetQ).degrees;
        this.slerpInterval = setInterval(() => {
            const error = core_1.Quaternion.AngleBetween(transform.worldRotation, this.targetQ).degrees;
            if (error < 0.15) {
                this.stopSlerping();
                return;
            }
            const deltaError = error - previousError;
            if (deltaError === 0) {
                this.stopSlerping();
                return;
            }
            const kp = 0.05;
            const kd = 5;
            const pEffect = kp * error;
            const dEffect = kd * (deltaError / 10);
            const deltaAng = pEffect + dEffect;
            let slerpPercent = deltaAng / error;
            if (slerpPercent > 1) {
                slerpPercent = 1;
            }
            const slerpedQ = core_1.Quaternion.Slerp(transform.worldRotation, this.targetQ, slerpPercent);
            transform.worldRotation = slerpedQ;
            previousError = error;
        }, 10);
    }
    constructor(appObject) {
        super(appObject, LookAtCameraUC.type);
        this.cameraPos = new core_1.Vector3(0, 0, -0.6);
        this.targetQ = core_1.Quaternion.Identity();
        this.isSlerping = false;
        this.onChange = () => {
            if (!this.callout)
                return;
            const parent = this.callout.labelTransform.parent;
            if (!parent) {
                return;
            }
            const worldDir = core_1.Vector3.Subtract(this.cameraPos, this.callout.labelTransform.worldPosition);
            // const localDir = parent.worldDirectionToLocal(worldDir);
            const desiredQ = core_1.Quaternion.FromDirectionVector(worldDir);
            if (core_1.Quaternion.Close(this.targetQ, desiredQ)) {
                return;
            }
            this.targetQ = desiredQ;
            if (!this.isSlerping) {
                this.kickOffSlerping();
            }
        };
        this.stopSlerping = () => {
            if (this.callout) {
                this.callout.labelTransform.worldRotation = this.targetQ;
            }
            if (this.slerpInterval) {
                clearInterval(this.slerpInterval);
                this.slerpInterval = undefined;
            }
            this.isSlerping = false;
        };
        this.dispose = () => {
            super.dispose();
            this.sceneRootEntity?.removeChangeObserver(this.onChange);
        };
        this.sceneRootEntity?.addChangeObserver(this.onChange);
        this.callout?.addChangeObserver(this.onChange);
        this.onChange();
    }
}
//# sourceMappingURL=LookAtCameraUC.js.map