import { AnimationTrack } from './animationtrack.js';
import { BoundingBox } from '../utility/bounding_volume.js';
import { MAX_MORPH_TARGETS } from '../values.js';
import { calculateMorphBoundingBox } from './morphtarget.js';
import { Vector3 } from '@zephyr3d/base';

/**
 * Morph target track
 * @public
 */ class MorphTargetTrack extends AnimationTrack {
    _state;
    _originBox;
    _boundingBox;
    _defaultWeights;
    _interpolator;
    /**
   * Create an instance of MorphTargetTrack
   */ constructor(interpolator, defaultMorphWeights, targetBox, originBox, embedded){
        super(embedded);
        if (interpolator === undefined) {
            this._interpolator = null;
            this._state = null;
            this._boundingBox = null;
            this._originBox = null;
            this._defaultWeights = null;
        } else {
            this._interpolator = interpolator;
            this._state = {
                numTargets: interpolator.stride,
                boundingBox: new BoundingBox(),
                weights: new Float32Array(MAX_MORPH_TARGETS)
            };
            this._boundingBox = targetBox ?? null;
            this._originBox = originBox ?? null;
            this._defaultWeights = defaultMorphWeights ?? Array.from({
                length: this._state.numTargets
            }).map(()=>0);
        }
    }
    get interpolator() {
        return this._interpolator;
    }
    set interpolator(interp) {
        this._interpolator = interp ?? null;
        this._state = this._interpolator ? {
            numTargets: this._interpolator.stride,
            boundingBox: new BoundingBox(),
            weights: new Float32Array(MAX_MORPH_TARGETS)
        } : null;
    }
    get boundingBox() {
        return this._boundingBox;
    }
    set boundingBox(box) {
        this._boundingBox = box;
    }
    get defaultWeights() {
        return this._defaultWeights;
    }
    set defaultWeights(value) {
        this._defaultWeights = value;
    }
    get originBoundingBox() {
        return this._originBox;
    }
    set originBoundingBox(box) {
        this._originBox = box;
    }
    /** {@inheritDoc AnimationTrack.calculateState} */ calculateState(target, currentTime) {
        this._interpolator.interpolate(currentTime, this._state.weights);
        calculateMorphBoundingBox(this._state.boundingBox, this._boundingBox, this._state.weights, this._state.numTargets);
        return this._state;
    }
    /** {@inheritDoc AnimationTrack.applyState} */ applyState(node, state) {
        node.getMorphInfo().buffer.get().bufferSubData(4 * 4, state.weights);
        state.boundingBox.minPoint.addBy(this._originBox.minPoint);
        state.boundingBox.maxPoint.addBy(this._originBox.maxPoint);
        node.setAnimatedBoundingBox(state.boundingBox);
    }
    /** {@inheritDoc AnimationTrack.mixState} */ mixState(a, b, t) {
        const state = {
            weights: new Float32Array(a.numTargets),
            boundingBox: new BoundingBox(),
            numTargets: a.numTargets
        };
        for(let i = 0; i < a.numTargets; i++){
            state.weights[i] = a.weights[i] + (b.weights[i] - a.weights[i]) * t;
            state.boundingBox.minPoint = Vector3.min(a.boundingBox.minPoint, b.boundingBox.minPoint);
            state.boundingBox.maxPoint = Vector3.max(a.boundingBox.maxPoint, b.boundingBox.maxPoint);
        }
        return state;
    }
    /** {@inheritDoc AnimationTrack.getBlendId} */ getBlendId() {
        return 'node-morph';
    }
    /** {@inheritDoc AnimationTrack.getDuration} */ getDuration() {
        return this._interpolator?.maxTime ?? 0;
    }
    /** {@inheritDoc AnimationTrack.reset} */ reset(node) {
        // apply default weights
        this._state.weights.set(this._defaultWeights);
        this.applyState(node, this._state);
    }
}

export { MorphTargetTrack };
//# sourceMappingURL=morphtrack.js.map
