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