From c81924b385f01206659264ddff06362dddc17881 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Jun 2024 14:53:59 +0200 Subject: [PATCH] refactor(loop): use explicit variables for stop/pause states --- src/core/loop.ts | 55 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/src/core/loop.ts b/src/core/loop.ts index f6aab535c..9eb10f149 100644 --- a/src/core/loop.ts +++ b/src/core/loop.ts @@ -44,8 +44,11 @@ export interface RendererLoop { } export function createRenderLoop(): RendererLoop { + let isReady = true + let isStopped = true + let isPaused = false const clock = new Clock(false) - const isActive = ref(false) + const isActive = ref(clock.running) const isRenderPaused = ref(false) let animationFrameId: number const loopId = MathUtils.generateUUID() @@ -53,7 +56,8 @@ export function createRenderLoop(): RendererLoop { const subscribersBefore = createPriorityEventHook() const subscriberRender = createPriorityEventHook() const subscribersAfter = createPriorityEventHook() - let isReady = true + + _syncState() // Context to be passed to callbacks let context: Record = {} @@ -78,29 +82,31 @@ export function createRenderLoop(): RendererLoop { } function start() { - if (!isActive.value) { - clock.start() - isActive.value = true - loop() - } + // NOTE: `loop()` produces side effects on each call. + // Those side effects are only desired if `isStopped` goes + // from `true` to `false` below. So while we don't need + // a guard in `stop`, `resume`, and `pause`, we do need + // a guard here. + if (!isStopped) { return } + isStopped = false + _syncState() + loop() } function stop() { - if (isActive.value) { - clock.stop() - cancelAnimationFrame(animationFrameId) - isActive.value = false - } + isStopped = true + _syncState() + cancelAnimationFrame(animationFrameId) } - function pause() { - clock.stop() - isActive.value = false + function resume() { + isPaused = false + _syncState() } - function resume() { - clock.start() - isActive.value = true + function pause() { + isPaused = true + _syncState() } function pauseRender() { @@ -151,6 +157,19 @@ export function createRenderLoop(): RendererLoop { animationFrameId = requestAnimationFrame(loop) } + function _syncState() { + const shouldClockBeRunning = !isStopped && !isPaused + if (clock.running !== shouldClockBeRunning) { + if (!clock.running) { + clock.start() + } + else { + clock.stop() + } + } + isActive.value = clock.running + } + return { loopId, register: (callback: LoopCallbackFn, stage: 'before' | 'render' | 'after', index) => registerCallback(callback, stage, index),