UNPKG

@polygonjs/polygonjs

Version:

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

296 lines (295 loc) 9.62 kB
"use strict"; import { CoreGraphNode } from "../../../core/graph/CoreGraphNode"; import { SceneEvent } from "../../poly/SceneEvent"; import { Clock } from "three"; import { SCENE_EVENT_PLAY_EVENT_CONTEXT, SCENE_EVENT_PAUSE_EVENT_CONTEXT } from "./events/SceneEventsController"; import { ref } from "../../../core/reactivity/CoreReactivity"; import { Poly } from "../../Poly"; const FPS = 60; export const DESIRED_FPS = 60; const MAX_DELTA = 0.1; export const TIME_CONTROLLER_UPDATE_TIME_OPTIONS_DEFAULT = { updateClockDelta: false }; const _TimeController = class { // private _delta: number = 0; // private _PLAY_EVENT_CONTEXT: EventContext<SceneEvent> | undefined; // private _PAUSE_EVENT_CONTEXT: EventContext<SceneEvent> | undefined; // private _TICK_EVENT_CONTEXT: EventContext<SceneEvent> | undefined; // get PLAY_EVENT_CONTEXT() { // return (this._PLAY_EVENT_CONTEXT = this._PLAY_EVENT_CONTEXT || {event: new SceneEvent(SceneEventType.PLAY)}); // } // get PAUSE_EVENT_CONTEXT() { // return (this._PAUSE_EVENT_CONTEXT = this._PAUSE_EVENT_CONTEXT || {event: new SceneEvent(SceneEventType.PAUSE)}); // } // get TICK_EVENT_CONTEXT() { // return (this._TICK_EVENT_CONTEXT = this._TICK_EVENT_CONTEXT || {event: new SceneEvent(SceneEventType.TICK)}); // } constructor(scene) { this.scene = scene; this._frame = 0; this._timeUniform = ref(0); this._timeDeltaUniform = ref(0); this._realtimeState = true; this._maxFrame = 600; this._maxFrameLocked = false; this._playing = false; this._clock = new Clock(); this._playAllowedWithoutAllNodesCooked = true; this._onBeforeTickCallbacks = []; this._onAfterTickCallbacks = []; this._onPlayingStateChangeCallbacks = []; this._graphNode = new CoreGraphNode(scene, "timeController"); } get graphNode() { return this._graphNode; } dispose() { this._graphNode.dispose(); } updateClockDelta() { const delta = this._clock.getDelta(); const clampedDelta = delta > MAX_DELTA ? MAX_DELTA : delta; return this.setDelta(clampedDelta); } delta() { return this._timeDeltaUniform.value; } setDelta(delta) { return this._timeDeltaUniform.value = delta; } frame() { return this._frame; } timeUniform() { return this._timeUniform; } timeDeltaUniform() { return this._timeDeltaUniform; } time() { return this._timeUniform.value; } // timeDelta() { // return this._timeDeltaUniform.value; // } maxFrame() { return this._maxFrame; } maxFrameLocked() { return this._maxFrameLocked; } realtimeState() { return this._realtimeState; } setMaxFrame(maxFrame) { this._maxFrame = Math.floor(maxFrame); this.scene.dispatchController.dispatch(this._graphNode, SceneEvent.MAX_FRAME_UPDATED); } setMaxFrameLocked(state) { this._maxFrameLocked = state; this.scene.dispatchController.dispatch(this._graphNode, SceneEvent.MAX_FRAME_UPDATED); } setRealtimeState(state) { this._realtimeState = state; this.scene.dispatchController.dispatch(this._graphNode, SceneEvent.REALTIME_STATUS_UPDATED); } setTime(time, updateFrame = true) { if (time == this._timeUniform.value) { return; } this._timeUniform.value = time; this.scene.cooker.block(); const delta = this.delta(); for (const callback of this._onBeforeTickCallbacks) { callback(delta); } if (this._playing == true && time > 0) { this.scene.actorsManager.tick(); } if (updateFrame) { const newFrame = Math.floor(this._timeUniform.value * FPS); const boundedFrame = this._ensureFrameWithinBounds(newFrame); if (newFrame != boundedFrame) { this.setFrame(boundedFrame, true); } else { this._frame = newFrame; } } this.scene.dispatchController.dispatch(this._graphNode, SceneEvent.FRAME_UPDATED); this.graphNode.setSuccessorsDirty(); this.scene.cooker.unblock(); for (const callback of this._onAfterTickCallbacks) { callback(delta); } } setFrame(frame, updateTime = true) { if (frame == this._frame) { return; } frame = this._ensureFrameWithinBounds(frame); if (frame == this._frame) { return; } this._frame = frame; if (this._frame == _TimeController.START_FRAME) { this.scene.actorsManager.runOnEventSceneReset(); } if (updateTime) { this.setTime(this._frame / FPS, false); } } setFrameToStart() { this.setFrame(_TimeController.START_FRAME, true); } incrementTimeIfPlaying(options) { if (this._playing) { if (!this.scene.root().areChildrenCooking()) { this.incrementTime(options); } } } incrementTime(options) { if (!((options == null ? void 0 : options.updateClockDelta) == false)) { this.updateClockDelta(); } if (this._realtimeState) { const newTime = this._timeUniform.value + this.delta(); this.setTime(newTime, false); this.setFrame(this._frame + 1, false); } else { this.setFrame(this.frame() + 1); } } _ensureFrameWithinBounds(frame) { if (this._playing) { if (this._maxFrameLocked && frame > this._maxFrame) { return _TimeController.START_FRAME; } } else { if (this._maxFrameLocked && frame > this._maxFrame) { return this._maxFrame; } if (frame < _TimeController.START_FRAME) { return _TimeController.START_FRAME; } } return frame; } playing() { return this._playing === true; } pause() { if (this._playing == false) { return; } this._playing = false; this.scene.dispatchController.dispatch(this._graphNode, SceneEvent.PLAY_STATE_UPDATED); this.scene.actorsManager.runOnEventScenePause(); this.scene.eventsDispatcher.sceneEventsController.dispatch(SCENE_EVENT_PAUSE_EVENT_CONTEXT); for (const callback of this._onPlayingStateChangeCallbacks) { callback(); } } play() { if (!this._playAllowedWithoutAllNodesCooked) { if (!this.scene.cookController.allNodesHaveCookedAtLeastOnce()) { Poly.warn("play not allowed, some nodes have not completed cooking"); return; } } if (this._playing == true) { return; } this._playing = true; this.scene.actorsManager.runOnEventScenePlay(); this.scene.dispatchController.dispatch(this._graphNode, SceneEvent.PLAY_STATE_UPDATED); this.scene.eventsDispatcher.sceneEventsController.dispatch(SCENE_EVENT_PLAY_EVENT_CONTEXT); for (const callback of this._onPlayingStateChangeCallbacks) { callback(); } } togglePlayPause() { if (this.playing()) { this.pause(); } else { this.play(); } } forbidPlayUntilAllNodesCooked() { this._playAllowedWithoutAllNodesCooked = false; } registerOnBeforeTick(callbackName, callback) { this._registerCallback(callbackName, callback, this.registeredBeforeTickCallbacks()); } unRegisterOnBeforeTick(callbackName) { this._unregisterCallback(callbackName, this._onBeforeTickCallbacksMap); } registeredBeforeTickCallbacks() { return this._onBeforeTickCallbacksMap = this._onBeforeTickCallbacksMap || /* @__PURE__ */ new Map(); } hasBeforeTickCallback(callbackName) { var _a; return ((_a = this._onBeforeTickCallbacksMap) == null ? void 0 : _a.has(callbackName)) || false; } registerOnAfterTick(callbackName, callback) { this._registerCallback(callbackName, callback, this.registeredAfterTickCallbacks()); } unRegisterOnAfterTick(callbackName) { this._unregisterCallback(callbackName, this._onAfterTickCallbacksMap); } registeredAfterTickCallbacks() { return this._onAfterTickCallbacksMap = this._onAfterTickCallbacksMap || /* @__PURE__ */ new Map(); } hasAfterTickCallback(callbackName) { var _a; return ((_a = this._onAfterTickCallbacksMap) == null ? void 0 : _a.has(callbackName)) || false; } onPlayingStateChange(callback) { this._onPlayingStateChangeCallbacksMap = this._onPlayingStateChangeCallbacksMap || /* @__PURE__ */ new Set(); this._onPlayingStateChangeCallbacksMap.add(callback); this._updateOnPlayingStateChangeCallbacks(); } removeOnPlayingStateChange(callback) { if (this._onPlayingStateChangeCallbacksMap) { this._onPlayingStateChangeCallbacksMap.delete(callback); this._updateOnPlayingStateChangeCallbacks(); } } _updateOnPlayingStateChangeCallbacks() { this._onPlayingStateChangeCallbacks = []; if (this._onPlayingStateChangeCallbacksMap) { this._onPlayingStateChangeCallbacksMap.forEach((callback) => { this._onPlayingStateChangeCallbacks.push(callback); }); } } _registerCallback(callbackName, callback, map) { if (map.has(callbackName)) { console.warn(`callback ${callbackName} already registered`); return; } map.set(callbackName, callback); this._updateCallbacks(); } _unregisterCallback(callbackName, map) { if (!map) { return; } map.delete(callbackName); this._updateCallbacks(); } _updateCallbacks() { var _a, _b; this._onBeforeTickCallbacks.length = 0; (_a = this._onBeforeTickCallbacksMap) == null ? void 0 : _a.forEach((callback) => { this._onBeforeTickCallbacks.push(callback); }); this._onAfterTickCallbacks.length = 0; (_b = this._onAfterTickCallbacksMap) == null ? void 0 : _b.forEach((callback) => { this._onAfterTickCallbacks.push(callback); }); } }; export let TimeController = _TimeController; TimeController.START_FRAME = 0;