diff --git a/src/render/cesium/appRenderer.js b/src/render/cesium/appRenderer.js index 2e87091b1..df11714bd 100644 --- a/src/render/cesium/appRenderer.js +++ b/src/render/cesium/appRenderer.js @@ -7,11 +7,10 @@ * The renderer it makes is transitional. Its ports are the shared Cesium * ports (`ports.js`), the ones the conformance renderer is checked with, * less the members that would not be true of the application yet: the - * globe (it draws photoreal tiles the port does not know), `whenSettled` - * (it would not wait for them), `frame.setTime` (it would stop the - * application's clock). Those arrive with the layer families that need - * them (phase 2 of the renderer plan); `checkRendererShape` lists what is - * still missing. + * globe (it draws photoreal tiles the port does not know) and + * `whenSettled` (it would not wait for them). Those arrive with the layer + * families that need them (phase 2 of the renderer plan); + * `checkRendererShape` lists what is still missing. * Until a family is ported, its code reaches the Cesium viewer through * `cesiumViewerOf`, never through a renderer member, so no engine type * crosses the contract and each call marks code still to port. Ported code diff --git a/src/render/cesium/appRenderer.test.mjs b/src/render/cesium/appRenderer.test.mjs index eb0cf71a0..b351b8d70 100644 --- a/src/render/cesium/appRenderer.test.mjs +++ b/src/render/cesium/appRenderer.test.mjs @@ -318,7 +318,6 @@ test('the application refuses a renderer it cannot run on, and destroys it', asy }); const EXPECTED_MISSING = [ - 'frame.setTime', 'renderer.globe', 'renderer.readPixels', 'renderer.releaseUnused', diff --git a/src/render/cesium/ports.js b/src/render/cesium/ports.js index 3a18938c4..4fd652a1b 100644 --- a/src/render/cesium/ports.js +++ b/src/render/cesium/ports.js @@ -347,6 +347,16 @@ export function createCesiumPorts(widget, { capabilities }) { targetFps = fps > 0 ? fps : 0; widget.targetFrameRate = targetFps || undefined; }, + /** + * Moves the clock to `ms` and draws it. Whether the clock then runs on + * is its owner's: the application's clock keeps running if it was (a + * clock on Cesium's real-time step moves to its multiplier step, as + * setting its time does in Cesium). + */ + setTime(ms) { + widget.clock.currentTime = Cesium.JulianDate.fromDate(new Date(ms)); + frame.requestRender('time'); + }, time: () => Cesium.JulianDate.toDate(widget.clock.currentTime).getTime(), }; diff --git a/src/render/cesium/ports.test.mjs b/src/render/cesium/ports.test.mjs index edd276e23..f2d4c571b 100644 --- a/src/render/cesium/ports.test.mjs +++ b/src/render/cesium/ports.test.mjs @@ -697,3 +697,18 @@ test('an icon draws its atlas slot once the atlas has it, and again when it chan ); ports.dispose(); }); + +test('setTime moves scene time and draws it, leaving the clock running or not', () => { + const { widget, scene } = tickingWidget(); + let requested = 0; + scene.requestRender = () => (requested += 1); + widget.clock.shouldAnimate = true; + const ports = createCesiumPorts(widget, { capabilities: all }); + const t = Date.UTC(2026, 5, 21, 12); + ports.frame.setTime(t); + assert.equal(ports.frame.time(), t); + assert.equal(widget.clock.shouldAnimate, true, 'still running'); + assert.equal(requested, 1, 'one frame asked for'); + assert.deepEqual(ports.frame.diagnostics().pendingReasons, ['time']); + ports.dispose(); +}); diff --git a/src/render/cesium/sceneRenderer.js b/src/render/cesium/sceneRenderer.js index 68514b986..1fa54cb4a 100644 --- a/src/render/cesium/sceneRenderer.js +++ b/src/render/cesium/sceneRenderer.js @@ -66,7 +66,8 @@ export async function createCesiumSceneRenderer({ contextOptions: { webgl: { preserveDrawingBuffer: true } }, }); const scene = widget.scene; - // A fixed time, so lighting is the same in every capture. + // A fixed time, so lighting is the same in every capture; `setTime` + // moves it and it stays there. widget.clock.shouldAnimate = false; widget.clock.currentTime = Cesium.JulianDate.fromIso8601( '2026-06-21T18:00:00Z', @@ -95,14 +96,6 @@ export async function createCesiumSceneRenderer({ query: ports.query, report: ports.report, }); - const frame = { - ...ports.frame, - setTime(ms) { - widget.clock.currentTime = Cesium.JulianDate.fromDate(new Date(ms)); - widget.clock.shouldAnimate = false; - scene.requestRender(); - }, - }; // --- Globe ----------------------------------------------------------------- @@ -269,7 +262,7 @@ export async function createCesiumSceneRenderer({ contractVersion: '0', capabilities, canvas: scene.canvas, - frame, + frame: ports.frame, globe, // A member of a capability left out is absent, not stubbed. draw: capabilities.has('models')