From 40ec050a7578e443ac2fbe594b95268d9e03b9b8 Mon Sep 17 00:00:00 2001 From: yyc-git <395976266@qq.com> Date: Sat, 9 Mar 2024 20:00:58 +0800 Subject: [PATCH] feat(editor): add tween animation interact extension add tween animation; pass "cube keyframe animation" run test; pass "camera keyframe animation" run test; (fix(action): run action: now script->onStop's meta3dState is the one after onInit) --- contributes/meta3d-action-run/src/Main.ts | 4 +- doc/jiehuo.org | 103 +++ .../extensions/meta3d-interact/src/Main.ts | 125 ++- .../src/animation/tween.module.d.ts | 219 +++++ .../src/animation/tween.module.js | 858 ++++++++++++++++++ .../meta3d-interact/webpack.config.js | 2 +- .../src/service/ServiceType.d.ts | 45 +- .../src/state/StateType.d.ts | 13 +- .../meta3d-interact-protocol/tsconfig.json | 2 +- 9 files changed, 1360 insertions(+), 11 deletions(-) create mode 100755 packages/interact/extensions/meta3d-interact/src/animation/tween.module.d.ts create mode 100755 packages/interact/extensions/meta3d-interact/src/animation/tween.module.js diff --git a/contributes/meta3d-action-run/src/Main.ts b/contributes/meta3d-action-run/src/Main.ts index eb071235a..b17e1c28e 100755 --- a/contributes/meta3d-action-run/src/Main.ts +++ b/contributes/meta3d-action-run/src/Main.ts @@ -90,10 +90,10 @@ export let getContribute: getContributeMeta3D> = meta3dState = _markIsRun(meta3dState, api, false) meta3dState = _stopGameViewRender(meta3dState, api) - meta3dState = api.restore(meta3dState, api.nullable.getExn(api.action.getActionState(meta3dState, actionName)).meta3dStateBeforeRun) - return execEventHandle(meta3dState, api, "onStop", getViewServiceForEditor(meta3dState, api)).then(meta3dState => { + meta3dState = api.restore(meta3dState, api.nullable.getExn(api.action.getActionState(meta3dState, actionName)).meta3dStateBeforeRun) + return runGameViewRenderOnlyOnce(meta3dState, api, api.nullable.getExn(api.getPackageService(meta3dState, "meta3d-editor-whole-protocol"))) }) })) diff --git a/doc/jiehuo.org b/doc/jiehuo.org index f91ee1bef..4cc742d64 100755 --- a/doc/jiehuo.org +++ b/doc/jiehuo.org @@ -134,10 +134,96 @@ gameview c run +* DONE learn three.js with keyframe animation + +TODO demo + + +* DONE implement cube keyframe animation + +# ** TODO build data + + +# ** TODO implement + +TODO use Tween to move cube + +TODO provide animation api + + + +* DONE implement camera keyframe animation to focus cube + + + +TODO compute new target, new distance + TODO use fake distance + +TODO use Tween to these new ones + +TODO provide animation api + + +* TODO fix: if onStop error, recurse throw! + + +* TODO fix: change action->immdiatlly run: action not work + + + + +* TODO update engine + +* TODO publish and update + +TODO : +interact e, p + +run + + +* TODO add 2d ui(page) + +TODO page box + +TODO text + +TODO link + + + +* TODO add data binding + +TODO scene data: +parent-child cubes +ids +description + + + +* TODO add 3d ui(billboard or face to one direction) + + + + + + + + + + + + + + * TODO future +** TODO picking should return gameObjects instead of objects +** TODO setSelectedObjects should use gameObjects instead of objects +** TODO refactor: rename setSelectedObjects to setSelectedGameObjects + ** TODO add Collider component @@ -146,6 +232,9 @@ maintain boundingSphere, boundingBox TODO computeBounding in update job +TODO update camera focus->new distance + + ** TODO add Picking component maintain ray, camera @@ -166,6 +255,14 @@ TODO remove RayCaster +** TODO sceneview add focus when press "f" + +*** TODO add hotkey + +*** TODO implement focus + + + @@ -180,6 +277,12 @@ TODO share allocate ECS ArrayBuffers when each run(visual, run) show log, error(e.g. error by script->handler) +** TODO GameObjectAPI: add findGameObjectByName + + +** TODO refactor: move "animation" out of interact package to be animation package + + ** TODO add MeshRender component diff --git a/packages/interact/extensions/meta3d-interact/src/Main.ts b/packages/interact/extensions/meta3d-interact/src/Main.ts index 804dfda2e..3ec191512 100755 --- a/packages/interact/extensions/meta3d-interact/src/Main.ts +++ b/packages/interact/extensions/meta3d-interact/src/Main.ts @@ -1,11 +1,12 @@ import { getExtensionService as getExtensionServiceMeta3D, createExtensionState as createExtensionStateMeta3D, getExtensionLife as getLifeMeta3D, state as meta3dState, api } from "meta3d-type" import { state } from "meta3d-interact-protocol/src/state/StateType" -import { service } from "meta3d-interact-protocol/src/service/ServiceType" +import { service, tweenId } from "meta3d-interact-protocol/src/service/ServiceType" import { service as eventService } from "meta3d-event-protocol/src/service/ServiceType" import { service as threeService } from "meta3d-three-protocol/src/service/ServiceType" import { state as converterState } from "meta3d-scenegraph-converter-three-protocol/src/state/StateType" import { getExn } from "meta3d-commonlib-ts/src/NullableUtils" import { getVertexPosition } from "./PositionUtils" +import TWEEN from "./animation/tween.module" let _checkIntersection = ( threeAPIService, @@ -348,6 +349,31 @@ let _ascSort = (a, b) => { } + +let _getMeta3dStateForAnimation = (api: api) => { + return api.nullable.getExn(globalThis["meta3d_animation_meta3dState"]) +} + +let _setMeta3dStateForAnimation = (meta3dState: meta3dState) => { + globalThis["meta3d_animation_meta3dState"] = meta3dState +} + +let _getTween = (meta3dState: meta3dState, api: api, id: tweenId) => { + return api.nullable.getExn(api.getExtensionState(meta3dState, "meta3d-interact-protocol").animation.tweens.get(id)) +} + +let _setTween = (meta3dState: meta3dState, api: api, id: tweenId, tween: any) => { + let state = api.getExtensionState(meta3dState, "meta3d-interact-protocol") + + return api.setExtensionState(meta3dState, + "meta3d-interact-protocol", { + ...state, + animation: { + tweens: state.animation.tweens.set(id, tween) + } + }) +} + export let getExtensionService: getExtensionServiceMeta3D< service > = (api) => { @@ -439,6 +465,97 @@ export let getExtensionService: getExtensionServiceMeta3D< return intersects; }, + }, + animation: { + add: (meta3dState, id, object, { + onStart = (meta3dState, object) => meta3dState, + onUpdate = (meta3dState, object, elapsed) => meta3dState, + onRepeat = (meta3dState, object) => meta3dState, + onComplete = (meta3dState, object) => meta3dState, + onStop = (meta3dState, object) => meta3dState + }) => { + let state = api.getExtensionState(meta3dState, + "meta3d-interact-protocol") + + return api.setExtensionState(meta3dState, + "meta3d-interact-protocol", { + ...state, + animation: { + // tweens: state.animation.tweens.set(id, new TWEEN.Tween(object).onStart(onStart).onUpdate(onUpdate).onRepeat(onRepeat).onComplete(onComplete).onStop(onStop) + tweens: state.animation.tweens.set(id, new TWEEN.Tween(object).onStart((object) => { + _setMeta3dStateForAnimation(onStart(_getMeta3dStateForAnimation(api), object)) + }).onUpdate((object, elapsed) => { + _setMeta3dStateForAnimation(onUpdate(_getMeta3dStateForAnimation(api), object, elapsed)) + }).onRepeat((object) => { + _setMeta3dStateForAnimation(onRepeat(_getMeta3dStateForAnimation(api), object)) + }).onComplete((object) => { + _setMeta3dStateForAnimation(onComplete(_getMeta3dStateForAnimation(api), object)) + }).onStop((object) => { + _setMeta3dStateForAnimation(onStop(_getMeta3dStateForAnimation(api), object)) + }) + ) + } + }) + }, + remove: (meta3dState, id) => { + TWEEN.remove(_getTween(meta3dState, api, id)) + + return meta3dState + }, + to: (meta3dState, id, target, duration) => { + return _setTween(meta3dState, api, id, _getTween(meta3dState, api, id).to(target, duration)) + }, + start: (meta3dState, id, time) => { + _setMeta3dStateForAnimation(meta3dState) + + return _setTween(meta3dState, api, id, _getTween(meta3dState, api, id).start(time)) + }, + stop: (meta3dState, id) => { + _setMeta3dStateForAnimation(meta3dState) + + return _setTween(meta3dState, api, id, _getTween(meta3dState, api, id).stop()) + }, + end: (meta3dState, id) => { + _setMeta3dStateForAnimation(meta3dState) + + return _setTween(meta3dState, api, id, _getTween(meta3dState, api, id).end()) + }, + pause: (meta3dState, id, time) => { + return _setTween(meta3dState, api, id, _getTween(meta3dState, api, id).pause(time)) + }, + resume: (meta3dState, id, time) => { + return _setTween(meta3dState, api, id, _getTween(meta3dState, api, id).resume(time)) + }, + repeat: (meta3dState, id, times) => { + _setMeta3dStateForAnimation(meta3dState) + + return _setTween(meta3dState, api, id, _getTween(meta3dState, api, id).repeat(times)) + }, + isPlaying: (meta3dState, id) => { + return _getTween(meta3dState, api, id).isPlaying() + }, + isPaused: (meta3dState, id) => { + return _getTween(meta3dState, api, id).isPaused() + }, + update: (meta3dState, id, time) => { + let tween = _getTween(meta3dState, api, id) + + _setMeta3dStateForAnimation(meta3dState) + + let result = tween.update(time) + + return [_setTween(meta3dState, api, id, tween), result] + }, + updateAll: (meta3dState, time) => { + _setMeta3dStateForAnimation(meta3dState) + + return [meta3dState, TWEEN.update(time)] + }, + removeAll: (meta3dState) => { + TWEEN.removeAll() + + return meta3dState + }, } } } @@ -446,7 +563,11 @@ export let getExtensionService: getExtensionServiceMeta3D< export let createExtensionState: createExtensionStateMeta3D< state > = (meta3dState, api) => { - return null + return { + animation: { + tweens: api.immutable.createMap() + } + } } export let getExtensionLife: getLifeMeta3D = (api, extensionProtocolName) => { diff --git a/packages/interact/extensions/meta3d-interact/src/animation/tween.module.d.ts b/packages/interact/extensions/meta3d-interact/src/animation/tween.module.d.ts new file mode 100755 index 000000000..4cdba4ba5 --- /dev/null +++ b/packages/interact/extensions/meta3d-interact/src/animation/tween.module.d.ts @@ -0,0 +1,219 @@ +type EasingFunction = (amount: number) => number; +interface EasingFunctionGroup { + In: EasingFunction; + Out: EasingFunction; + InOut: EasingFunction; +} +/** + * The Ease class provides a collection of easing functions for use with tween.js. + */ +declare const Easing: Readonly<{ + Linear: Readonly< + EasingFunctionGroup & { + None: EasingFunction; + } + >; + Quadratic: Readonly; + Cubic: Readonly; + Quartic: Readonly; + Quintic: Readonly; + Sinusoidal: Readonly; + Exponential: Readonly; + Circular: Readonly; + Elastic: Readonly; + Back: Readonly; + Bounce: Readonly; + generatePow(power?: number): EasingFunctionGroup; +}>; + +type InterpolationFunction = (v: number[], k: number) => number; +declare const Interpolation: { + Linear: (v: number[], k: number) => number; + Bezier: (v: number[], k: number) => number; + CatmullRom: (v: number[], k: number) => number; + Utils: { + Linear: (p0: number, p1: number, t: number) => number; + Bernstein: (n: number, i: number) => number; + Factorial: (n: number) => number; + CatmullRom: (p0: number, p1: number, p2: number, p3: number, t: number) => number; + }; +}; + +/** + * Controlling groups of tweens + * + * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components. + * In these cases, you may want to create your own smaller groups of tween + */ +declare class Group { + private _tweens; + private _tweensAddedDuringUpdate; + getAll(): Array>; + removeAll(): void; + add(tween: Tween): void; + remove(tween: Tween): void; + update(time?: number, preserve?: boolean): boolean; +} + +/** + * Tween.js - Licensed under the MIT license + * https://github.com/tweenjs/tween.js + * ---------------------------------------------- + * + * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors. + * Thank you all, you're awesome! + */ + +declare class Tween { + private _object; + private _group; + private _isPaused; + private _pauseStart; + private _valuesStart; + private _valuesEnd; + private _valuesStartRepeat; + private _duration; + private _isDynamic; + private _initialRepeat; + private _repeat; + private _repeatDelayTime?; + private _yoyo; + private _isPlaying; + private _reversed; + private _delayTime; + private _startTime; + private _easingFunction; + private _interpolationFunction; + private _chainedTweens; + private _onStartCallback?; + private _onStartCallbackFired; + private _onEveryStartCallback?; + private _onEveryStartCallbackFired; + private _onUpdateCallback?; + private _onRepeatCallback?; + private _onCompleteCallback?; + private _onStopCallback?; + private _id; + private _isChainStopped; + private _propertiesAreSetUp; + constructor(_object: T, _group?: Group | false); + getId(): number; + isPlaying(): boolean; + isPaused(): boolean; + to(target: UnknownProps, duration?: number): this; + duration(duration?: number): this; + dynamic(dynamic?: boolean): this; + start(time?: number, overrideStartingValues?: boolean): this; + startFromCurrentValues(time?: number): this; + private _setupProperties; + stop(): this; + end(): this; + pause(time?: number): this; + resume(time?: number): this; + stopChainedTweens(): this; + group(group?: Group): this; + delay(amount?: number): this; + repeat(times?: number): this; + repeatDelay(amount?: number): this; + yoyo(yoyo?: boolean): this; + easing(easingFunction?: EasingFunction): this; + interpolation(interpolationFunction?: InterpolationFunction): this; + chain(...tweens: Array>): this; + onStart(callback?: (object: T) => void): this; + onEveryStart(callback?: (object: T) => void): this; + onUpdate(callback?: (object: T, elapsed: number) => void): this; + onRepeat(callback?: (object: T) => void): this; + onComplete(callback?: (object: T) => void): this; + onStop(callback?: (object: T) => void): this; + private _goToEnd; + /** + * @returns true if the tween is still playing after the update, false + * otherwise (calling update on a paused tween still returns true because + * it is still playing, just paused). + */ + update(time?: number, autoStart?: boolean): boolean; + private _updateProperties; + private _handleRelativeValue; + private _swapEndStartRepeatValues; +} +type UnknownProps = Record; + +declare function now(): number; + +/** + * Utils + */ +// tslint:disable-next-line:no-unnecessary-class +declare class Sequence { + private static _nextId; + static nextId(): number; +} + +declare const VERSION = '21.0.0'; + +declare const nextId: typeof Sequence.nextId; +declare function getAll(): Array>; +declare function removeAll(): void; +declare function add(tween: Tween): void; +declare function remove(tween: Tween): void; +declare function update(time?: number, preserve?: boolean): boolean; + +declare const exports: { + Easing: Readonly<{ + Linear: Readonly< + EasingFunctionGroup & { + None: EasingFunction; + } + >; + Quadratic: Readonly; + Cubic: Readonly; + Quartic: Readonly; + Quintic: Readonly; + Sinusoidal: Readonly; + Exponential: Readonly; + Circular: Readonly; + Elastic: Readonly; + Back: Readonly; + Bounce: Readonly; + generatePow(power?: number): EasingFunctionGroup; + }>; + Group: typeof Group; + Interpolation: { + Linear: (v: number[], k: number) => number; + Bezier: (v: number[], k: number) => number; + CatmullRom: (v: number[], k: number) => number; + Utils: { + Linear: (p0: number, p1: number, t: number) => number; + Bernstein: (n: number, i: number) => number; + Factorial: (n: number) => number; + CatmullRom: (p0: number, p1: number, p2: number, p3: number, t: number) => number; + }; + }; + now: () => number; + Sequence: typeof Sequence; + nextId: typeof Sequence.nextId; + Tween: typeof Tween; + VERSION: string; + getAll: () => Array>; + removeAll: () => void; + add: (tween: Tween) => void; + remove: (tween: Tween) => void; + update: (time?: number, preserve?: boolean) => boolean; +}; + +export { + Easing, + Group, + Interpolation, + Sequence, + Tween, + VERSION, + add, + exports as default, + getAll, + nextId, + now, + remove, + removeAll, + update, +}; diff --git a/packages/interact/extensions/meta3d-interact/src/animation/tween.module.js b/packages/interact/extensions/meta3d-interact/src/animation/tween.module.js new file mode 100755 index 000000000..094ec3a86 --- /dev/null +++ b/packages/interact/extensions/meta3d-interact/src/animation/tween.module.js @@ -0,0 +1,858 @@ +/** + * The Ease class provides a collection of easing functions for use with tween.js. + */ +var Easing = Object.freeze({ + Linear: Object.freeze({ + None: function (amount) { + return amount; + }, + In: function (amount) { + return this.None(amount); + }, + Out: function (amount) { + return this.None(amount); + }, + InOut: function (amount) { + return this.None(amount); + }, + }), + Quadratic: Object.freeze({ + In: function (amount) { + return amount * amount; + }, + Out: function (amount) { + return amount * (2 - amount); + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return 0.5 * amount * amount; + } + return -0.5 * (--amount * (amount - 2) - 1); + }, + }), + Cubic: Object.freeze({ + In: function (amount) { + return amount * amount * amount; + }, + Out: function (amount) { + return --amount * amount * amount + 1; + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return 0.5 * amount * amount * amount; + } + return 0.5 * ((amount -= 2) * amount * amount + 2); + }, + }), + Quartic: Object.freeze({ + In: function (amount) { + return amount * amount * amount * amount; + }, + Out: function (amount) { + return 1 - --amount * amount * amount * amount; + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return 0.5 * amount * amount * amount * amount; + } + return -0.5 * ((amount -= 2) * amount * amount * amount - 2); + }, + }), + Quintic: Object.freeze({ + In: function (amount) { + return amount * amount * amount * amount * amount; + }, + Out: function (amount) { + return --amount * amount * amount * amount * amount + 1; + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return 0.5 * amount * amount * amount * amount * amount; + } + return 0.5 * ((amount -= 2) * amount * amount * amount * amount + 2); + }, + }), + Sinusoidal: Object.freeze({ + In: function (amount) { + return 1 - Math.sin(((1.0 - amount) * Math.PI) / 2); + }, + Out: function (amount) { + return Math.sin((amount * Math.PI) / 2); + }, + InOut: function (amount) { + return 0.5 * (1 - Math.sin(Math.PI * (0.5 - amount))); + }, + }), + Exponential: Object.freeze({ + In: function (amount) { + return amount === 0 ? 0 : Math.pow(1024, amount - 1); + }, + Out: function (amount) { + return amount === 1 ? 1 : 1 - Math.pow(2, -10 * amount); + }, + InOut: function (amount) { + if (amount === 0) { + return 0; + } + if (amount === 1) { + return 1; + } + if ((amount *= 2) < 1) { + return 0.5 * Math.pow(1024, amount - 1); + } + return 0.5 * (-Math.pow(2, -10 * (amount - 1)) + 2); + }, + }), + Circular: Object.freeze({ + In: function (amount) { + return 1 - Math.sqrt(1 - amount * amount); + }, + Out: function (amount) { + return Math.sqrt(1 - --amount * amount); + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return -0.5 * (Math.sqrt(1 - amount * amount) - 1); + } + return 0.5 * (Math.sqrt(1 - (amount -= 2) * amount) + 1); + }, + }), + Elastic: Object.freeze({ + In: function (amount) { + if (amount === 0) { + return 0; + } + if (amount === 1) { + return 1; + } + return -Math.pow(2, 10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI); + }, + Out: function (amount) { + if (amount === 0) { + return 0; + } + if (amount === 1) { + return 1; + } + return Math.pow(2, -10 * amount) * Math.sin((amount - 0.1) * 5 * Math.PI) + 1; + }, + InOut: function (amount) { + if (amount === 0) { + return 0; + } + if (amount === 1) { + return 1; + } + amount *= 2; + if (amount < 1) { + return -0.5 * Math.pow(2, 10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI); + } + return 0.5 * Math.pow(2, -10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI) + 1; + }, + }), + Back: Object.freeze({ + In: function (amount) { + var s = 1.70158; + return amount === 1 ? 1 : amount * amount * ((s + 1) * amount - s); + }, + Out: function (amount) { + var s = 1.70158; + return amount === 0 ? 0 : --amount * amount * ((s + 1) * amount + s) + 1; + }, + InOut: function (amount) { + var s = 1.70158 * 1.525; + if ((amount *= 2) < 1) { + return 0.5 * (amount * amount * ((s + 1) * amount - s)); + } + return 0.5 * ((amount -= 2) * amount * ((s + 1) * amount + s) + 2); + }, + }), + Bounce: Object.freeze({ + In: function (amount) { + return 1 - Easing.Bounce.Out(1 - amount); + }, + Out: function (amount) { + if (amount < 1 / 2.75) { + return 7.5625 * amount * amount; + } + else if (amount < 2 / 2.75) { + return 7.5625 * (amount -= 1.5 / 2.75) * amount + 0.75; + } + else if (amount < 2.5 / 2.75) { + return 7.5625 * (amount -= 2.25 / 2.75) * amount + 0.9375; + } + else { + return 7.5625 * (amount -= 2.625 / 2.75) * amount + 0.984375; + } + }, + InOut: function (amount) { + if (amount < 0.5) { + return Easing.Bounce.In(amount * 2) * 0.5; + } + return Easing.Bounce.Out(amount * 2 - 1) * 0.5 + 0.5; + }, + }), + generatePow: function (power) { + if (power === void 0) { power = 4; } + power = power < Number.EPSILON ? Number.EPSILON : power; + power = power > 10000 ? 10000 : power; + return { + In: function (amount) { + return Math.pow(amount, power); + }, + Out: function (amount) { + return 1 - Math.pow((1 - amount), power); + }, + InOut: function (amount) { + if (amount < 0.5) { + return Math.pow((amount * 2), power) / 2; + } + return (1 - Math.pow((2 - amount * 2), power)) / 2 + 0.5; + }, + }; + }, +}); + +var now = function () { return performance.now(); }; + +/** + * Controlling groups of tweens + * + * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components. + * In these cases, you may want to create your own smaller groups of tween + */ +var Group = /** @class */ (function () { + function Group() { + this._tweens = {}; + this._tweensAddedDuringUpdate = {}; + } + Group.prototype.getAll = function () { + var _this = this; + return Object.keys(this._tweens).map(function (tweenId) { + return _this._tweens[tweenId]; + }); + }; + Group.prototype.removeAll = function () { + this._tweens = {}; + }; + Group.prototype.add = function (tween) { + this._tweens[tween.getId()] = tween; + this._tweensAddedDuringUpdate[tween.getId()] = tween; + }; + Group.prototype.remove = function (tween) { + delete this._tweens[tween.getId()]; + delete this._tweensAddedDuringUpdate[tween.getId()]; + }; + Group.prototype.update = function (time, preserve) { + if (time === void 0) { time = now(); } + if (preserve === void 0) { preserve = false; } + var tweenIds = Object.keys(this._tweens); + if (tweenIds.length === 0) { + return false; + } + // Tweens are updated in "batches". If you add a new tween during an + // update, then the new tween will be updated in the next batch. + // If you remove a tween during an update, it may or may not be updated. + // However, if the removed tween was added during the current batch, + // then it will not be updated. + while (tweenIds.length > 0) { + this._tweensAddedDuringUpdate = {}; + for (var i = 0; i < tweenIds.length; i++) { + var tween = this._tweens[tweenIds[i]]; + var autoStart = !preserve; + if (tween && tween.update(time, autoStart) === false && !preserve) { + delete this._tweens[tweenIds[i]]; + } + } + tweenIds = Object.keys(this._tweensAddedDuringUpdate); + } + return true; + }; + return Group; +}()); + +/** + * + */ +var Interpolation = { + Linear: function (v, k) { + var m = v.length - 1; + var f = m * k; + var i = Math.floor(f); + var fn = Interpolation.Utils.Linear; + if (k < 0) { + return fn(v[0], v[1], f); + } + if (k > 1) { + return fn(v[m], v[m - 1], m - f); + } + return fn(v[i], v[i + 1 > m ? m : i + 1], f - i); + }, + Bezier: function (v, k) { + var b = 0; + var n = v.length - 1; + var pw = Math.pow; + var bn = Interpolation.Utils.Bernstein; + for (var i = 0; i <= n; i++) { + b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i); + } + return b; + }, + CatmullRom: function (v, k) { + var m = v.length - 1; + var f = m * k; + var i = Math.floor(f); + var fn = Interpolation.Utils.CatmullRom; + if (v[0] === v[m]) { + if (k < 0) { + i = Math.floor((f = m * (1 + k))); + } + return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i); + } + else { + if (k < 0) { + return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]); + } + if (k > 1) { + return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]); + } + return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i); + } + }, + Utils: { + Linear: function (p0, p1, t) { + return (p1 - p0) * t + p0; + }, + Bernstein: function (n, i) { + var fc = Interpolation.Utils.Factorial; + return fc(n) / fc(i) / fc(n - i); + }, + Factorial: (function () { + var a = [1]; + return function (n) { + var s = 1; + if (a[n]) { + return a[n]; + } + for (var i = n; i > 1; i--) { + s *= i; + } + a[n] = s; + return s; + }; + })(), + CatmullRom: function (p0, p1, p2, p3, t) { + var v0 = (p2 - p0) * 0.5; + var v1 = (p3 - p1) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1; + }, + }, +}; + +/** + * Utils + */ +var Sequence = /** @class */ (function () { + function Sequence() { + } + Sequence.nextId = function () { + return Sequence._nextId++; + }; + Sequence._nextId = 0; + return Sequence; +}()); + +var mainGroup = new Group(); + +/** + * Tween.js - Licensed under the MIT license + * https://github.com/tweenjs/tween.js + * ---------------------------------------------- + * + * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors. + * Thank you all, you're awesome! + */ +var Tween = /** @class */ (function () { + function Tween(_object, _group) { + if (_group === void 0) { _group = mainGroup; } + this._object = _object; + this._group = _group; + this._isPaused = false; + this._pauseStart = 0; + this._valuesStart = {}; + this._valuesEnd = {}; + this._valuesStartRepeat = {}; + this._duration = 1000; + this._isDynamic = false; + this._initialRepeat = 0; + this._repeat = 0; + this._yoyo = false; + this._isPlaying = false; + this._reversed = false; + this._delayTime = 0; + this._startTime = 0; + this._easingFunction = Easing.Linear.None; + this._interpolationFunction = Interpolation.Linear; + // eslint-disable-next-line + this._chainedTweens = []; + this._onStartCallbackFired = false; + this._onEveryStartCallbackFired = false; + this._id = Sequence.nextId(); + this._isChainStopped = false; + this._propertiesAreSetUp = false; + this._goToEnd = false; + } + Tween.prototype.getId = function () { + return this._id; + }; + Tween.prototype.isPlaying = function () { + return this._isPlaying; + }; + Tween.prototype.isPaused = function () { + return this._isPaused; + }; + Tween.prototype.to = function (target, duration) { + if (duration === void 0) { duration = 1000; } + if (this._isPlaying) + throw new Error('Can not call Tween.to() while Tween is already started or paused. Stop the Tween first.'); + this._valuesEnd = target; + this._propertiesAreSetUp = false; + this._duration = duration; + return this; + }; + Tween.prototype.duration = function (duration) { + if (duration === void 0) { duration = 1000; } + this._duration = duration; + return this; + }; + Tween.prototype.dynamic = function (dynamic) { + if (dynamic === void 0) { dynamic = false; } + this._isDynamic = dynamic; + return this; + }; + Tween.prototype.start = function (time, overrideStartingValues) { + if (time === void 0) { time = now(); } + if (overrideStartingValues === void 0) { overrideStartingValues = false; } + if (this._isPlaying) { + return this; + } + // eslint-disable-next-line + this._group && this._group.add(this); + this._repeat = this._initialRepeat; + if (this._reversed) { + // If we were reversed (f.e. using the yoyo feature) then we need to + // flip the tween direction back to forward. + this._reversed = false; + for (var property in this._valuesStartRepeat) { + this._swapEndStartRepeatValues(property); + this._valuesStart[property] = this._valuesStartRepeat[property]; + } + } + this._isPlaying = true; + this._isPaused = false; + this._onStartCallbackFired = false; + this._onEveryStartCallbackFired = false; + this._isChainStopped = false; + this._startTime = time; + this._startTime += this._delayTime; + if (!this._propertiesAreSetUp || overrideStartingValues) { + this._propertiesAreSetUp = true; + // If dynamic is not enabled, clone the end values instead of using the passed-in end values. + if (!this._isDynamic) { + var tmp = {}; + for (var prop in this._valuesEnd) + tmp[prop] = this._valuesEnd[prop]; + this._valuesEnd = tmp; + } + this._setupProperties(this._object, this._valuesStart, this._valuesEnd, this._valuesStartRepeat, overrideStartingValues); + } + return this; + }; + Tween.prototype.startFromCurrentValues = function (time) { + return this.start(time, true); + }; + Tween.prototype._setupProperties = function (_object, _valuesStart, _valuesEnd, _valuesStartRepeat, overrideStartingValues) { + for (var property in _valuesEnd) { + var startValue = _object[property]; + var startValueIsArray = Array.isArray(startValue); + var propType = startValueIsArray ? 'array' : typeof startValue; + var isInterpolationList = !startValueIsArray && Array.isArray(_valuesEnd[property]); + // If `to()` specifies a property that doesn't exist in the source object, + // we should not set that property in the object + if (propType === 'undefined' || propType === 'function') { + continue; + } + // Check if an Array was provided as property value + if (isInterpolationList) { + var endValues = _valuesEnd[property]; + if (endValues.length === 0) { + continue; + } + // Handle an array of relative values. + // Creates a local copy of the Array with the start value at the front + var temp = [startValue]; + for (var i = 0, l = endValues.length; i < l; i += 1) { + var value = this._handleRelativeValue(startValue, endValues[i]); + if (isNaN(value)) { + isInterpolationList = false; + console.warn('Found invalid interpolation list. Skipping.'); + break; + } + temp.push(value); + } + if (isInterpolationList) { + // if (_valuesStart[property] === undefined) { // handle end values only the first time. NOT NEEDED? setupProperties is now guarded by _propertiesAreSetUp. + _valuesEnd[property] = temp; + // } + } + } + // handle the deepness of the values + if ((propType === 'object' || startValueIsArray) && startValue && !isInterpolationList) { + _valuesStart[property] = startValueIsArray ? [] : {}; + var nestedObject = startValue; + for (var prop in nestedObject) { + _valuesStart[property][prop] = nestedObject[prop]; + } + // TODO? repeat nested values? And yoyo? And array values? + _valuesStartRepeat[property] = startValueIsArray ? [] : {}; + var endValues = _valuesEnd[property]; + // If dynamic is not enabled, clone the end values instead of using the passed-in end values. + if (!this._isDynamic) { + var tmp = {}; + for (var prop in endValues) + tmp[prop] = endValues[prop]; + _valuesEnd[property] = endValues = tmp; + } + this._setupProperties(nestedObject, _valuesStart[property], endValues, _valuesStartRepeat[property], overrideStartingValues); + } + else { + // Save the starting value, but only once unless override is requested. + if (typeof _valuesStart[property] === 'undefined' || overrideStartingValues) { + _valuesStart[property] = startValue; + } + if (!startValueIsArray) { + // eslint-disable-next-line + // @ts-ignore FIXME? + _valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings + } + if (isInterpolationList) { + // eslint-disable-next-line + // @ts-ignore FIXME? + _valuesStartRepeat[property] = _valuesEnd[property].slice().reverse(); + } + else { + _valuesStartRepeat[property] = _valuesStart[property] || 0; + } + } + } + }; + Tween.prototype.stop = function () { + if (!this._isChainStopped) { + this._isChainStopped = true; + this.stopChainedTweens(); + } + if (!this._isPlaying) { + return this; + } + // eslint-disable-next-line + this._group && this._group.remove(this); + this._isPlaying = false; + this._isPaused = false; + if (this._onStopCallback) { + this._onStopCallback(this._object); + } + return this; + }; + Tween.prototype.end = function () { + this._goToEnd = true; + this.update(Infinity); + return this; + }; + Tween.prototype.pause = function (time) { + if (time === void 0) { time = now(); } + if (this._isPaused || !this._isPlaying) { + return this; + } + this._isPaused = true; + this._pauseStart = time; + // eslint-disable-next-line + this._group && this._group.remove(this); + return this; + }; + Tween.prototype.resume = function (time) { + if (time === void 0) { time = now(); } + if (!this._isPaused || !this._isPlaying) { + return this; + } + this._isPaused = false; + this._startTime += time - this._pauseStart; + this._pauseStart = 0; + // eslint-disable-next-line + this._group && this._group.add(this); + return this; + }; + Tween.prototype.stopChainedTweens = function () { + for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) { + this._chainedTweens[i].stop(); + } + return this; + }; + Tween.prototype.group = function (group) { + if (group === void 0) { group = mainGroup; } + this._group = group; + return this; + }; + Tween.prototype.delay = function (amount) { + if (amount === void 0) { amount = 0; } + this._delayTime = amount; + return this; + }; + Tween.prototype.repeat = function (times) { + if (times === void 0) { times = 0; } + this._initialRepeat = times; + this._repeat = times; + return this; + }; + Tween.prototype.repeatDelay = function (amount) { + this._repeatDelayTime = amount; + return this; + }; + Tween.prototype.yoyo = function (yoyo) { + if (yoyo === void 0) { yoyo = false; } + this._yoyo = yoyo; + return this; + }; + Tween.prototype.easing = function (easingFunction) { + if (easingFunction === void 0) { easingFunction = Easing.Linear.None; } + this._easingFunction = easingFunction; + return this; + }; + Tween.prototype.interpolation = function (interpolationFunction) { + if (interpolationFunction === void 0) { interpolationFunction = Interpolation.Linear; } + this._interpolationFunction = interpolationFunction; + return this; + }; + // eslint-disable-next-line + Tween.prototype.chain = function () { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + this._chainedTweens = tweens; + return this; + }; + Tween.prototype.onStart = function (callback) { + this._onStartCallback = callback; + return this; + }; + Tween.prototype.onEveryStart = function (callback) { + this._onEveryStartCallback = callback; + return this; + }; + Tween.prototype.onUpdate = function (callback) { + this._onUpdateCallback = callback; + return this; + }; + Tween.prototype.onRepeat = function (callback) { + this._onRepeatCallback = callback; + return this; + }; + Tween.prototype.onComplete = function (callback) { + this._onCompleteCallback = callback; + return this; + }; + Tween.prototype.onStop = function (callback) { + this._onStopCallback = callback; + return this; + }; + /** + * @returns true if the tween is still playing after the update, false + * otherwise (calling update on a paused tween still returns true because + * it is still playing, just paused). + */ + Tween.prototype.update = function (time, autoStart) { + if (time === void 0) { time = now(); } + if (autoStart === void 0) { autoStart = true; } + if (this._isPaused) + return true; + var property; + var elapsed; + var endTime = this._startTime + this._duration; + if (!this._goToEnd && !this._isPlaying) { + if (time > endTime) + return false; + if (autoStart) + this.start(time, true); + } + this._goToEnd = false; + if (time < this._startTime) { + return true; + } + if (this._onStartCallbackFired === false) { + if (this._onStartCallback) { + this._onStartCallback(this._object); + } + this._onStartCallbackFired = true; + } + if (this._onEveryStartCallbackFired === false) { + if (this._onEveryStartCallback) { + this._onEveryStartCallback(this._object); + } + this._onEveryStartCallbackFired = true; + } + elapsed = (time - this._startTime) / this._duration; + elapsed = this._duration === 0 || elapsed > 1 ? 1 : elapsed; + var value = this._easingFunction(elapsed); + // properties transformations + this._updateProperties(this._object, this._valuesStart, this._valuesEnd, value); + if (this._onUpdateCallback) { + this._onUpdateCallback(this._object, elapsed); + } + if (elapsed === 1) { + if (this._repeat > 0) { + if (isFinite(this._repeat)) { + this._repeat--; + } + // Reassign starting values, restart by making startTime = now + for (property in this._valuesStartRepeat) { + if (!this._yoyo && typeof this._valuesEnd[property] === 'string') { + this._valuesStartRepeat[property] = + // eslint-disable-next-line + // @ts-ignore FIXME? + this._valuesStartRepeat[property] + parseFloat(this._valuesEnd[property]); + } + if (this._yoyo) { + this._swapEndStartRepeatValues(property); + } + this._valuesStart[property] = this._valuesStartRepeat[property]; + } + if (this._yoyo) { + this._reversed = !this._reversed; + } + if (this._repeatDelayTime !== undefined) { + this._startTime = time + this._repeatDelayTime; + } + else { + this._startTime = time + this._delayTime; + } + if (this._onRepeatCallback) { + this._onRepeatCallback(this._object); + } + this._onEveryStartCallbackFired = false; + return true; + } + else { + if (this._onCompleteCallback) { + this._onCompleteCallback(this._object); + } + for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) { + // Make the chained tweens start exactly at the time they should, + // even if the `update()` method was called way past the duration of the tween + this._chainedTweens[i].start(this._startTime + this._duration, false); + } + this._isPlaying = false; + return false; + } + } + return true; + }; + Tween.prototype._updateProperties = function (_object, _valuesStart, _valuesEnd, value) { + for (var property in _valuesEnd) { + // Don't update properties that do not exist in the source object + if (_valuesStart[property] === undefined) { + continue; + } + var start = _valuesStart[property] || 0; + var end = _valuesEnd[property]; + var startIsArray = Array.isArray(_object[property]); + var endIsArray = Array.isArray(end); + var isInterpolationList = !startIsArray && endIsArray; + if (isInterpolationList) { + _object[property] = this._interpolationFunction(end, value); + } + else if (typeof end === 'object' && end) { + // eslint-disable-next-line + // @ts-ignore FIXME? + this._updateProperties(_object[property], start, end, value); + } + else { + // Parses relative end values with start as base (e.g.: +10, -3) + end = this._handleRelativeValue(start, end); + // Protect against non numeric properties. + if (typeof end === 'number') { + // eslint-disable-next-line + // @ts-ignore FIXME? + _object[property] = start + (end - start) * value; + } + } + } + }; + Tween.prototype._handleRelativeValue = function (start, end) { + if (typeof end !== 'string') { + return end; + } + if (end.charAt(0) === '+' || end.charAt(0) === '-') { + return start + parseFloat(end); + } + return parseFloat(end); + }; + Tween.prototype._swapEndStartRepeatValues = function (property) { + var tmp = this._valuesStartRepeat[property]; + var endValue = this._valuesEnd[property]; + if (typeof endValue === 'string') { + this._valuesStartRepeat[property] = this._valuesStartRepeat[property] + parseFloat(endValue); + } + else { + this._valuesStartRepeat[property] = this._valuesEnd[property]; + } + this._valuesEnd[property] = tmp; + }; + return Tween; +}()); + +var VERSION = '21.0.0'; + +/** + * Tween.js - Licensed under the MIT license + * https://github.com/tweenjs/tween.js + * ---------------------------------------------- + * + * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors. + * Thank you all, you're awesome! + */ +var nextId = Sequence.nextId; +/** + * Controlling groups of tweens + * + * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components. + * In these cases, you may want to create your own smaller groups of tweens. + */ +var TWEEN = mainGroup; +// This is the best way to export things in a way that's compatible with both ES +// Modules and CommonJS, without build hacks, and so as not to break the +// existing API. +// https://github.com/rollup/rollup/issues/1961#issuecomment-423037881 +var getAll = TWEEN.getAll.bind(TWEEN); +var removeAll = TWEEN.removeAll.bind(TWEEN); +var add = TWEEN.add.bind(TWEEN); +var remove = TWEEN.remove.bind(TWEEN); +var update = TWEEN.update.bind(TWEEN); +var exports = { + Easing: Easing, + Group: Group, + Interpolation: Interpolation, + now: now, + Sequence: Sequence, + nextId: nextId, + Tween: Tween, + VERSION: VERSION, + getAll: getAll, + removeAll: removeAll, + add: add, + remove: remove, + update: update, +}; + +export { Easing, Group, Interpolation, Sequence, Tween, VERSION, add, exports as default, getAll, nextId, now, remove, removeAll, update }; diff --git a/packages/interact/extensions/meta3d-interact/webpack.config.js b/packages/interact/extensions/meta3d-interact/webpack.config.js index 2d861b4c6..870602028 100755 --- a/packages/interact/extensions/meta3d-interact/webpack.config.js +++ b/packages/interact/extensions/meta3d-interact/webpack.config.js @@ -17,7 +17,7 @@ module.exports = { // devtool: "source-map", resolve: { - extensions: ['.ts', '.tsx', '.Extensionjs', '.jsx', '.scss'], + extensions: ['.ts', '.tsx', '.js', '.jsx', '.scss'], modules: ['node_modules'] }, diff --git a/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/src/service/ServiceType.d.ts b/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/src/service/ServiceType.d.ts index c1fadc358..632bf94eb 100755 --- a/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/src/service/ServiceType.d.ts +++ b/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/src/service/ServiceType.d.ts @@ -1,6 +1,7 @@ -import { state as meta3dState } from "meta3d-type" +import { state as meta3dState, nullableAPI } from "meta3d-type" import { pointEventName, priority, handleFunc } from "meta3d-event-protocol/src/service/ServiceType" import type { Vector2, Camera, Object3D, Intersection } from "three" +import { nullable } from "meta3d-commonlib-ts/src/nullable" type point = { onPointEvent: (meta3dState: meta3dState, pointEventName: pointEventName, priority: priority, handleFunc: handleFunc) => meta3dState, @@ -26,17 +27,53 @@ type picking = { setFromCurrentCamera: (meta3dState: meta3dState, mousePos: mousePos) => meta3dState, // intersectObject: ( // meta3dState: meta3dState, - // object: Object3D, + // object: any, // recursive: boolean, // ) => Array> intersectScene: ( meta3dState: meta3dState, - // object: Object3D, + // object: valueObject, // recursive: boolean, ) => Array> } +type valueObject = any + +export type tweenId = string + +type tween = { + add: (meta3dState: meta3dState, id: tweenId, object: valueObject, { + onStart, + onUpdate, + onRepeat, + onComplete, + onStop + }: { + onStart: nullable<(meta3dState: meta3dState, object: valueObject) => meta3dState>, + onUpdate: nullable<(meta3dState: meta3dState, object: valueObject, elapsed: number) => meta3dState>, + onRepeat: nullable<(meta3dState: meta3dState, object: valueObject) => meta3dState>, + onComplete: nullable<(meta3dState: meta3dState, object: valueObject) => meta3dState>, + onStop: nullable<(meta3dState: meta3dState, object: valueObject) => meta3dState>, + }) => meta3dState, + remove: (meta3dState: meta3dState, id: tweenId) => meta3dState, + to: (meta3dState: meta3dState, id: tweenId, target: valueObject, duration: number) => meta3dState, + start: (meta3dState: meta3dState, id: tweenId, time: nullable) => meta3dState, + stop: (meta3dState: meta3dState, id: tweenId) => meta3dState, + end: (meta3dState: meta3dState, id: tweenId) => meta3dState, + pause: (meta3dState: meta3dState, id: tweenId, time: nullable) => meta3dState, + resume: (meta3dState: meta3dState, id: tweenId, time: nullable) => meta3dState, + repeat: (meta3dState: meta3dState, id: tweenId, times: number) => meta3dState, + isPlaying: (meta3dState: meta3dState, id: tweenId) => boolean, + isPaused: (meta3dState: meta3dState, id: tweenId) => boolean, + update: (meta3dState: meta3dState, id: tweenId, time: nullable) => [meta3dState, boolean], + updateAll: (meta3dState: meta3dState, time: nullable) => [meta3dState, boolean], + removeAll: (meta3dState: meta3dState) => meta3dState, +} + +type animation = tween + export type service = { input: input, - picking: picking + picking: picking, + animation: animation } diff --git a/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/src/state/StateType.d.ts b/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/src/state/StateType.d.ts index e830d73b3..3ed281353 100755 --- a/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/src/state/StateType.d.ts +++ b/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/src/state/StateType.d.ts @@ -1 +1,12 @@ -export type state = null \ No newline at end of file +import type { Map } from "immutable" +import { tweenId } from "../service/ServiceType" + +type tween = any + +type animation = { + tweens: Map +} + +export type state = { + animation: animation +} \ No newline at end of file diff --git a/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/tsconfig.json b/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/tsconfig.json index 9f1c23b81..dcb375aa2 100755 --- a/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/tsconfig.json +++ b/packages/interact/protocols/extension_protocols/meta3d-interact-protocol/tsconfig.json @@ -20,5 +20,5 @@ }, "include": [ "./src" - ] +, "../../../extensions/meta3d-interact/src/animation/tween.module.d.ts" ] } \ No newline at end of file