import { cloneMat4, composeMat4, decomposeMat4, identityMat4, invertMat4, multiplyMat4, normalizeQuat } from "./MathTypes.js";
export class TransformNode {
    dirty = true;
    dirtyListeners = new Set();
    matrixAutoUpdate = true;
    position = [0, 0, 0];
    rotation = [0, 0, 0, 1];
    scale = [1, 1, 1];
    localMatrix = identityMat4();
    worldMatrix = identityMat4();
    inverseWorldMatrix = identityMat4();
    setPosition(x, y, z) {
        this.position[0] = x;
        this.position[1] = y;
        this.position[2] = z;
        return this.markDirty();
    }
    setRotation(x, y, z, w) {
        const normalized = normalizeQuat([x, y, z, w]);
        this.rotation[0] = normalized[0];
        this.rotation[1] = normalized[1];
        this.rotation[2] = normalized[2];
        this.rotation[3] = normalized[3];
        return this.markDirty();
    }
    setScale(x, y, z) {
        this.scale[0] = x;
        this.scale[1] = y;
        this.scale[2] = z;
        return this.markDirty();
    }
    setFromLocalMatrix(matrix) {
        const decomposed = decomposeMat4(matrix);
        this.position[0] = decomposed.position[0];
        this.position[1] = decomposed.position[1];
        this.position[2] = decomposed.position[2];
        this.rotation[0] = decomposed.rotation[0];
        this.rotation[1] = decomposed.rotation[1];
        this.rotation[2] = decomposed.rotation[2];
        this.rotation[3] = decomposed.rotation[3];
        this.scale[0] = decomposed.scale[0];
        this.scale[1] = decomposed.scale[1];
        this.scale[2] = decomposed.scale[2];
        return this.markDirty();
    }
    setLocalMatrix(matrix, options = {}) {
        if (!matrix.every(Number.isFinite))
            throw new Error("Transform local matrix must contain finite values.");
        this.localMatrix = cloneMat4(matrix);
        this.matrixAutoUpdate = options.matrixAutoUpdate ?? false;
        if (options.decompose ?? true) {
            const decomposed = decomposeMat4(matrix);
            this.position[0] = decomposed.position[0];
            this.position[1] = decomposed.position[1];
            this.position[2] = decomposed.position[2];
            this.rotation[0] = decomposed.rotation[0];
            this.rotation[1] = decomposed.rotation[1];
            this.rotation[2] = decomposed.rotation[2];
            this.rotation[3] = decomposed.rotation[3];
            this.scale[0] = decomposed.scale[0];
            this.scale[1] = decomposed.scale[1];
            this.scale[2] = decomposed.scale[2];
        }
        return this.markDirty();
    }
    setMatrixAutoUpdate(enabled) {
        this.matrixAutoUpdate = enabled;
        return this.markDirty();
    }
    markDirty() {
        if (!this.dirty) {
            this.dirty = true;
            for (const listener of [...this.dirtyListeners])
                listener();
        }
        return this;
    }
    onDirty(listener) {
        this.dirtyListeners.add(listener);
        return () => this.dirtyListeners.delete(listener);
    }
    isDirty() {
        return this.dirty;
    }
    updateWorld(parentWorld, force = false) {
        const shouldUpdate = force || this.dirty;
        if (!shouldUpdate)
            return false;
        if (this.matrixAutoUpdate) {
            this.localMatrix = composeMat4(this.position, this.rotation, this.scale);
        }
        this.worldMatrix = parentWorld ? multiplyMat4(parentWorld, this.localMatrix) : cloneMat4(this.localMatrix);
        this.inverseWorldMatrix = invertMat4(this.worldMatrix);
        this.dirty = false;
        return true;
    }
}
//# sourceMappingURL=TransformNode.js.map