UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

125 lines (124 loc) 4.11 kB
"use strict"; import { ChannelInterpolation } from "./KeyframeCommon"; import { setCurveFromKeyframePairCubic, getValueCubic } from "./channel/Cubic"; import { setCurveFromKeyframePairLinear, getValueLinear } from "./channel/Linear"; import { mix } from "../math/_Module"; import { pushOnArrayAtEntry } from "../MapUtils"; import { copyKeyframeData, createKeyframeData } from "./KeyframeSerialize"; export class Channel { constructor(data) { this.data = data; this._valuesByPos = /* @__PURE__ */ new Map(); this._setCurveCallback = setCurveFromKeyframePairLinear; this._getValueCallback = getValueLinear; Channel.validate(this.data); this.compute(); } static fromJSON(data) { return new Channel(data); } value(t) { if (t == Math.floor(t)) { const value = this._valuesByPos.get(t); if (value != null) { return value; } const keyframes = this.data.keyframes; if (keyframes.length == 0) { return 0; } const firstPos = keyframes[0].pos; const lastPos = keyframes[keyframes.length - 1].pos; if (t < firstPos) { return this._valuesByPos.get(firstPos) || 0; } if (t > lastPos) { return this._valuesByPos.get(lastPos) || 0; } } const t0 = Math.floor(t); const t1 = Math.ceil(t); const v0 = this._valuesByPos.get(t0) || 0; const v1 = this._valuesByPos.get(t1) || 0; return mix(v0, v1, t - t0); } static validate(data) { let keyframes = data.keyframes; const keyframesByPos = /* @__PURE__ */ new Map(); for (const keyframe of keyframes) { pushOnArrayAtEntry(keyframesByPos, keyframe.pos, keyframe); } if (keyframes.length != keyframesByPos.size) { const expectedSize = keyframesByPos.size; const keptKeyframes = new Array(expectedSize); let i2 = 0; keyframesByPos.forEach((keyframes2, pos) => { keptKeyframes[i2] = keyframes2[0]; i2++; }); keyframes = keptKeyframes; data.keyframes.splice(expectedSize, data.keyframes.length - expectedSize); } const sortedKeyframes = keyframes.sort((k1, k2) => k1.pos - k2.pos).map((k) => { const target = createKeyframeData(); copyKeyframeData(k, target); return target; }); let i = 0; for (const keyframe of sortedKeyframes) { copyKeyframeData(keyframe, data.keyframes[i]); i++; } } _setCallbacks() { switch (this.data.interpolation) { case ChannelInterpolation.CUBIC: { this._setCurveCallback = setCurveFromKeyframePairCubic; this._getValueCallback = getValueCubic; return; } case ChannelInterpolation.LINEAR: { this._setCurveCallback = setCurveFromKeyframePairLinear; this._getValueCallback = getValueLinear; return; } } } compute() { Channel.validate(this.data); const keyframes = this.data.keyframes; if (keyframes.length == 0) { return; } this._setCallbacks(); const firstPos = keyframes[0].pos; const lastPos = keyframes[keyframes.length - 1].pos; this._valuesByPos.clear(); if (keyframes.length == 0) { return; } if (keyframes.length == 1) { this._valuesByPos.set(keyframes[0].pos, keyframes[0].value); return; } let segmentIndex = 0; const keyframePair = { start: keyframes[0], end: keyframes[1] }; this._setCurveCallback(keyframePair.start, keyframePair.end); for (let pos = firstPos; pos <= lastPos; pos++) { if (pos > keyframePair.end.pos) { segmentIndex++; keyframePair.start = keyframePair.end; keyframePair.end = keyframes[segmentIndex + 1]; this._setCurveCallback(keyframePair.start, keyframePair.end); } const value = this._getValueCallback(pos); this._valuesByPos.set(pos, value); } } // private _computeValue(pos: number, curve: CubicBezierCurve): number { // const t = this._findTForXCallback(pos, curve); // curve.getPoint(t, _v2); // console.log(pos, t, _v2.x, _v2.y); // return _v2.y; // } }