mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 03:14:00 +00:00
fix(time): latch the Cesium clock at creation; document the clock's limits
Review of Tasks 0–1: - The Cesium engine clock attaches its frame latch to viewer.clock.onTick when the engine is created, so it runs before onTick listeners added later (cameraVerbs installs its own after the engine exists). Before, it attached on first use and would have run after them. A viewer without a clock still latches lazily on the scene's preUpdate. - GlobeClock lists what is not on the app clock yet: Cesium's viewer clock (its lighting and property reads at currentTime), the launch replay timeline and the mission orbit's GMST frame (Task 15a), the satellite cloud's SGP4 and orbit bake (Task 14a), and wall-clock throttles. The plan's T14a/T15a now carry those moves. - freeze/offset/rate change now() at once and frameTime() from the next frame; QA helpers request a render after moving the clock.
This commit is contained in:
1 parent
7c7422e281
commit
f7f4e9a45c
5 files changed
+43
-10
No files matched your search
@@ -5,8 +5,15 @@
|
|||||||
// (including those the app added to the scene before the engine existed)
|
// (including those the app added to the scene before the engine existed)
|
||||||
// reads the same frame time. The viewer clock itself is never changed: the
|
// reads the same frame time. The viewer clock itself is never changed: the
|
||||||
// app does not animate it (shouldAnimate stays false), and its time still
|
// app does not animate it (shouldAnimate stays false), and its time still
|
||||||
// drives Cesium's own lighting as before. The tick subscription appears on
|
// drives Cesium's own lighting as before.
|
||||||
// first use (a ticked listener or a frameTime read) and destroy removes it.
|
//
|
||||||
|
// The latch is attached when the engine is created (the app creates it with
|
||||||
|
// the scene, before cameraVerbs and the layers add their own onTick
|
||||||
|
// listeners), so it runs first in each tick; an onTick listener added before
|
||||||
|
// the engine existed would read the previous frame's time. destroy removes
|
||||||
|
// it. A viewer without a clock (tests, a bare scene) latches on the scene's
|
||||||
|
// preUpdate instead, attached on first use so creating the engine adds no
|
||||||
|
// scene listener.
|
||||||
|
|
||||||
import { createEngineEvent } from '../contract.js';
|
import { createEngineEvent } from '../contract.js';
|
||||||
import { appClock as pageClock } from '../../time/clock.js';
|
import { appClock as pageClock } from '../../time/clock.js';
|
||||||
@@ -29,6 +36,7 @@ export function createCesiumClock(viewer, { appClock = pageClock } = {}) {
|
|||||||
if (!removeTick && !destroyed)
|
if (!removeTick && !destroyed)
|
||||||
removeTick = tickSource.addEventListener(onTick);
|
removeTick = tickSource.addEventListener(onTick);
|
||||||
};
|
};
|
||||||
|
if (viewer.clock?.onTick) attach();
|
||||||
const add = ticked.addEventListener;
|
const add = ticked.addEventListener;
|
||||||
ticked.addEventListener = (listener) => {
|
ticked.addEventListener = (listener) => {
|
||||||
const remove = add(listener);
|
const remove = add(listener);
|
||||||
|
|||||||
@@ -28,12 +28,19 @@ function cesiumFrame(viewer, { draw = true } = {}) {
|
|||||||
viewer.scene.postRender.raiseEvent(viewer.scene, time);
|
viewer.scene.postRender.raiseEvent(viewer.scene, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
test('the clock reads the app clock and subscribes to nothing at creation', () => {
|
test('the clock reads the app clock and latches on the viewer clock from creation', () => {
|
||||||
const viewer = createFakeViewer();
|
const viewer = createFakeViewer();
|
||||||
const wall = manualAppClock();
|
const wall = manualAppClock();
|
||||||
const { clock } = createCesiumClock(viewer, { appClock: wall.appClock });
|
const { clock } = createCesiumClock(viewer, { appClock: wall.appClock });
|
||||||
assert.ok(isEngineEvent(clock.ticked));
|
assert.ok(isEngineEvent(clock.ticked));
|
||||||
assert.equal(viewer.clock.onTick.numberOfListeners, 0);
|
// Attached at creation, so it runs before onTick listeners added later
|
||||||
|
// (cameraVerbs installs its own after the engine exists).
|
||||||
|
assert.equal(viewer.clock.onTick.numberOfListeners, 1);
|
||||||
|
const order = [];
|
||||||
|
viewer.clock.onTick.addEventListener(() => order.push(clock.frameTime()));
|
||||||
|
wall.advance(9);
|
||||||
|
viewer.clock.onTick.raiseEvent(viewer.clock);
|
||||||
|
assert.deepEqual(order, [wall.appClock.now()]);
|
||||||
assert.equal(clock.now(), wall.appClock.now());
|
assert.equal(clock.now(), wall.appClock.now());
|
||||||
wall.advance(5);
|
wall.advance(5);
|
||||||
assert.equal(clock.now(), wall.appClock.now());
|
assert.equal(clock.now(), wall.appClock.now());
|
||||||
@@ -67,7 +74,7 @@ test('frameTime is latched on the viewer clock tick, before preUpdate', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('frameTime alone starts the latch; destroy removes it', () => {
|
test('frameTime reads the latch; destroy removes it', () => {
|
||||||
const viewer = createFakeViewer();
|
const viewer = createFakeViewer();
|
||||||
const wall = manualAppClock();
|
const wall = manualAppClock();
|
||||||
const { clock, destroy } = createCesiumClock(viewer, {
|
const { clock, destroy } = createCesiumClock(viewer, {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
// The GlobeEngine on an existing Cesium Viewer. Creating it changes nothing
|
// The GlobeEngine on an existing Cesium Viewer. Creating it changes nothing
|
||||||
// in the viewer: Cesium subscriptions, the input handler and render holds
|
// in the scene: Cesium subscriptions, the input handler and render holds
|
||||||
// appear only when the shell uses them, and destroy() removes them again
|
// appear only when the shell uses them, and destroy() removes them again
|
||||||
// (the viewer itself stays owned by the app).
|
// (the viewer itself stays owned by the app). The one exception is the
|
||||||
|
// engine clock's frame latch on viewer.clock.onTick (clock.js), attached at
|
||||||
|
// creation so it runs before onTick listeners added later.
|
||||||
|
|
||||||
import { createCesiumCamera } from './camera.js';
|
import { createCesiumCamera } from './camera.js';
|
||||||
import { createCesiumClock } from './clock.js';
|
import { createCesiumClock } from './clock.js';
|
||||||
|
|||||||
+16
-2
@@ -214,8 +214,22 @@
|
|||||||
* The app's own time (src/time/clock.js), in milliseconds since the Unix
|
* The app's own time (src/time/clock.js), in milliseconds since the Unix
|
||||||
* epoch: the one time source for layers and the engine's own time-driven
|
* epoch: the one time source for layers and the engine's own time-driven
|
||||||
* drawing (Navara's sun). By default it is the wall clock (Date.now); QA
|
* drawing (Navara's sun). By default it is the wall clock (Date.now); QA
|
||||||
* and tests may freeze, offset or speed it up on the app clock. Cesium's
|
* and tests may freeze, offset or speed it up on the app clock: now()
|
||||||
* viewer.clock is not driven by it (the app never animates that clock).
|
* follows at once, frameTime() and ticked from the engine's next frame, and
|
||||||
|
* in request-render mode nothing draws until a render is requested, so a
|
||||||
|
* QA helper that moves the clock calls render.request() after it.
|
||||||
|
* Not on this clock yet (each moves when its layer or code moves):
|
||||||
|
* - Cesium's viewer.clock: the app never animates it (shouldAnimate false,
|
||||||
|
* its time frozen at boot); Cesium's sun and lighting and every entity
|
||||||
|
* property read at viewer.clock.currentTime stay on that time;
|
||||||
|
* - launches: the replay timeline (replay.js, Date.now/performance.now),
|
||||||
|
* the mission orbit's GMST frame (orbitRendering.js new Date()), launch
|
||||||
|
* pad and panel throttles (phase 3 Task 15a);
|
||||||
|
* - satellites: the point cloud's SGP4 propagation and orbit bake
|
||||||
|
* (rendering.js new Date()/Date.now) (Task 14a); only the tracked
|
||||||
|
* satellite reads the app clock;
|
||||||
|
* - wall-clock throttles and feed receipt stamps everywhere (they measure
|
||||||
|
* real elapsed time, not scene time).
|
||||||
* @property {() => number} now The current app time.
|
* @property {() => number} now The current app time.
|
||||||
* @property {() => number} frameTime The app time latched at the start of the
|
* @property {() => number} frameTime The app time latched at the start of the
|
||||||
* engine's current frame: every reader in one frame gets the same value; it
|
* engine's current frame: every reader in one frame gets the same value; it
|
||||||
|
|||||||
+3
-1
@@ -22,7 +22,9 @@ function finite(value, label) {
|
|||||||
* @property {() => number} beginFrame Latches and returns the frame time; the
|
* @property {() => number} beginFrame Latches and returns the frame time; the
|
||||||
* globe engine calls it once at the start of each of its frames.
|
* globe engine calls it once at the start of each of its frames.
|
||||||
* @property {(ms?: number) => void} freeze Holds the time at `ms` (default:
|
* @property {(ms?: number) => void} freeze Holds the time at `ms` (default:
|
||||||
* the current time). QA and tests only.
|
* the current time). QA and tests only. Like offset and rate, it changes
|
||||||
|
* now() at once and frameTime() from the next beginFrame (the engine's
|
||||||
|
* next frame); request a render after it in request-render mode.
|
||||||
* @property {() => void} resume Runs on from the frozen time.
|
* @property {() => void} resume Runs on from the frozen time.
|
||||||
* @property {(ms: number) => void} offset Sets the time to the wall clock
|
* @property {(ms: number) => void} offset Sets the time to the wall clock
|
||||||
* plus `ms`, running on from it at the current rate (it ends a freeze).
|
* plus `ms`, running on from it at the current rate (it ends a freeze).
|
||||||
|
|||||||
Reference in new issue
Block a user