@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
125 lines (124 loc) • 4.11 kB
JavaScript
"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;
// }
}