UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

200 lines (199 loc) 5.92 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { CURVE_SMOOTHSTEP } from "./constants.js"; import { CurveEvaluator } from "./curve-evaluator.js"; class Curve { /** * Creates a new Curve instance. * * @param {number[]} [data] - An array of keys (pairs of numbers with the time first and value * second). * @example * const curve = new pc.Curve([ * 0, 0, // At 0 time, value of 0 * 0.33, 2, // At 0.33 time, value of 2 * 0.66, 2.6, // At 0.66 time, value of 2.6 * 1, 3 // At 1 time, value of 3 * ]); */ constructor(data) { /** * The keys that define the curve. Each key is an array of two numbers with the time first and * the value second. * * @type {number[][]} */ __publicField(this, "keys", []); /** * The curve interpolation scheme. Can be: * * - {@link CURVE_LINEAR} * - {@link CURVE_SMOOTHSTEP} * - {@link CURVE_SPLINE} * - {@link CURVE_STEP} * * Defaults to {@link CURVE_SMOOTHSTEP}. * * @type {number} */ __publicField(this, "type", CURVE_SMOOTHSTEP); /** * Controls how {@link CURVE_SPLINE} tangents are calculated. Valid range is between 0 and 1 * where 0 results in a non-smooth curve (equivalent to linear interpolation) and 1 results in * a very smooth curve. Use 0.5 for a Catmull-Rom spline. */ __publicField(this, "tension", 0.5); /** * @type {CurveEvaluator} * @private */ __publicField(this, "_eval", new CurveEvaluator(this)); if (data) { for (let i = 0; i < data.length - 1; i += 2) { this.keys.push([data[i], data[i + 1]]); } } this.sort(); } /** * Gets the number of keys in the curve. * * @type {number} */ get length() { return this.keys.length; } /** * Adds a new key to the curve. * * @param {number} time - Time to add new key. * @param {number} value - Value of new key. * @returns {number[]} The newly created `[time, value]` pair. * @example * const curve = new pc.Curve(); * curve.add(0, 1); // add key at time 0 with value 1 * curve.add(1, 2); // add key at time 1 with value 2 */ add(time, value) { const keys = this.keys; const len = keys.length; let i = 0; for (; i < len; i++) { if (keys[i][0] > time) { break; } } const key = [time, value]; this.keys.splice(i, 0, key); return key; } /** * Gets the `[time, value]` pair at the specified index. * * @param {number} index - The index of key to return. * @returns {number[]} The `[time, value]` pair at the specified index. * @example * const curve = new pc.Curve([0, 1, 1, 2]); * const key = curve.get(0); // returns [0, 1] */ get(index) { return this.keys[index]; } /** * Sorts keys by time. */ sort() { this.keys.sort((a, b) => a[0] - b[0]); } /** * Returns the interpolated value of the curve at specified time. * * @param {number} time - The time at which to calculate the value. * @returns {number} The interpolated value. * @example * const curve = new pc.Curve([0, 0, 1, 10]); * const value = curve.value(0.5); // returns interpolated value at time 0.5 */ value(time) { return this._eval.evaluate(time, true); } /** * Returns the key closest to the specified time. * * @param {number} time - The time to find the closest key to. * @returns {number[]|null} The `[time, value]` pair closest to the specified time, or null if * no keys exist. * @example * const curve = new pc.Curve([0, 1, 0.5, 2, 1, 3]); * const key = curve.closest(0.6); // returns [0.5, 2] */ closest(time) { const keys = this.keys; const length = keys.length; let min = 2; let result = null; for (let i = 0; i < length; i++) { const diff = Math.abs(time - keys[i][0]); if (min >= diff) { min = diff; result = keys[i]; } else { break; } } return result; } /** * Returns a clone of the specified curve object. * * @returns {this} A clone of the specified curve. * @example * const curve = new pc.Curve([0, 0, 1, 10]); * const clonedCurve = curve.clone(); */ clone() { const result = new this.constructor(); result.keys = this.keys.map((key) => [...key]); result.type = this.type; result.tension = this.tension; return result; } /** * Sample the curve at regular intervals over the range [0..1]. * * @param {number} precision - The number of samples to return. * @returns {Float32Array} The set of quantized values. * @ignore */ quantize(precision) { precision = Math.max(precision, 2); const values = new Float32Array(precision); const step = 1 / (precision - 1); values[0] = this._eval.evaluate(0, true); for (let i = 1; i < precision; i++) { values[i] = this._eval.evaluate(step * i); } return values; } /** * Sample the curve at regular intervals over the range [0..1] and clamp the resulting samples * to [min..max]. * * @param {number} precision - The number of samples to return. * @param {number} min - The minimum output value. * @param {number} max - The maximum output value. * @returns {Float32Array} The set of quantized values. * @ignore */ quantizeClamped(precision, min, max) { const result = this.quantize(precision); for (let i = 0; i < result.length; ++i) { result[i] = Math.min(max, Math.max(min, result[i])); } return result; } } export { Curve };