mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
Drive drawProjectionFrame with a fake runtime and a recording canvas: a 640x480 still draws at its fitted rectangle over the matte, the same pixels at the same size skip the redraw, and the same pixels at a new aspect redraw at the new fit. The last case fails on the pixel-only signature; the first fails if drawImage stretches to the canvas again. Expected rectangles now read the canvas size from policy.js. Co-Authored-By: Claude Opus 5.5 <[email protected]>
142 lines
4.0 KiB
JavaScript
142 lines
4.0 KiB
JavaScript
// src/layers/cctv/frames.test.mjs
|
|
// Still-frame fit (#1201): stills draw at their source aspect, centered on the
|
|
// 1920x1080 projection canvas, instead of being stretched to fill it.
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { createFrames, fitToProjection } from './frames.js';
|
|
import {
|
|
FRAME_SIGNATURE_W,
|
|
FRAME_SIGNATURE_H,
|
|
PROJECTION_CANVAS_WIDTH,
|
|
PROJECTION_CANVAS_HEIGHT,
|
|
PROJECTION_MATTE_COLOR,
|
|
} from './policy.js';
|
|
|
|
// The expected rectangles below are written for a 1920x1080 canvas.
|
|
assert.equal(PROJECTION_CANVAS_WIDTH, 1920);
|
|
assert.equal(PROJECTION_CANVAS_HEIGHT, 1080);
|
|
|
|
const FULL_CANVAS = {
|
|
x: 0,
|
|
y: 0,
|
|
w: PROJECTION_CANVAS_WIDTH,
|
|
h: PROJECTION_CANVAS_HEIGHT,
|
|
};
|
|
|
|
test('a 4:3 still is pillarboxed at full height', () => {
|
|
assert.deepEqual(fitToProjection(640, 480), {
|
|
x: 240,
|
|
y: 0,
|
|
w: 1440,
|
|
h: 1080,
|
|
});
|
|
});
|
|
|
|
test('a source wider than 16:9 is letterboxed at full width', () => {
|
|
assert.deepEqual(fitToProjection(3840, 1080), {
|
|
x: 0,
|
|
y: 270,
|
|
w: 1920,
|
|
h: 540,
|
|
});
|
|
});
|
|
|
|
test('a 16:9 still fills the canvas', () => {
|
|
assert.deepEqual(fitToProjection(1920, 1080), FULL_CANVAS);
|
|
});
|
|
|
|
test('a missing or zero dimension falls back to the full canvas', () => {
|
|
assert.deepEqual(fitToProjection(0, 480), FULL_CANVAS);
|
|
assert.deepEqual(fitToProjection(640, 0), FULL_CANVAS);
|
|
assert.deepEqual(fitToProjection(640, undefined), FULL_CANVAS);
|
|
assert.deepEqual(fitToProjection(undefined, undefined), FULL_CANVAS);
|
|
});
|
|
|
|
// Draw path: the fit reaches drawImage, and the unchanged-frame skip keys on the
|
|
// fitted size as well as the pixels (the 64x36 hash alone drops aspect).
|
|
function stillHarness() {
|
|
const calls = [];
|
|
const ctx = {
|
|
fillStyle: null,
|
|
fillRect: (...rect) => calls.push(['fillRect', ctx.fillStyle, ...rect]),
|
|
clearRect: () => {},
|
|
drawImage: (_image, ...rect) => calls.push(['drawImage', ...rect]),
|
|
};
|
|
// Every frame downsamples to the same pixels, so only the size differs.
|
|
const pixels = new Uint8ClampedArray(
|
|
FRAME_SIGNATURE_W * FRAME_SIGNATURE_H * 4,
|
|
).fill(7);
|
|
const runtime = {
|
|
mode: 'image',
|
|
ctx,
|
|
image: { naturalWidth: 0, naturalHeight: 0 },
|
|
imageReady: true,
|
|
// In flight, so refreshProjectionImage returns before touching image.src.
|
|
imageLoading: true,
|
|
imageStamp: 0,
|
|
drawnImageStamp: -1,
|
|
lastFrameSignature: null,
|
|
canvasStamp: 0,
|
|
signatureCtx: {
|
|
clearRect: () => {},
|
|
drawImage: () => {},
|
|
getImageData: () => ({ data: pixels }),
|
|
},
|
|
};
|
|
const record = { camera: { id: 'still' }, projection: runtime };
|
|
const { drawProjectionFrame } = createFrames({
|
|
state: { _healthById: new Map(), _activeCameraId: null },
|
|
services: {},
|
|
parts: {},
|
|
source: {},
|
|
});
|
|
const load = (width, height) => {
|
|
runtime.image = { naturalWidth: width, naturalHeight: height };
|
|
runtime.imageStamp += 1;
|
|
calls.length = 0;
|
|
drawProjectionFrame(record);
|
|
return calls.slice();
|
|
};
|
|
return { runtime, load };
|
|
}
|
|
|
|
test('a still is drawn into its fitted rectangle over a full matte', () => {
|
|
const { runtime, load } = stillHarness();
|
|
assert.deepEqual(load(640, 480), [
|
|
[
|
|
'fillRect',
|
|
PROJECTION_MATTE_COLOR,
|
|
0,
|
|
0,
|
|
PROJECTION_CANVAS_WIDTH,
|
|
PROJECTION_CANVAS_HEIGHT,
|
|
],
|
|
['drawImage', 240, 0, 1440, 1080],
|
|
]);
|
|
assert.equal(runtime.canvasStamp, 1);
|
|
});
|
|
|
|
test('same pixels at the same size skip the redraw', () => {
|
|
const { runtime, load } = stillHarness();
|
|
load(640, 480);
|
|
assert.deepEqual(load(640, 480), []);
|
|
assert.equal(runtime.canvasStamp, 1);
|
|
});
|
|
|
|
test('same pixels at a new aspect redraw at the new fit', () => {
|
|
const { runtime, load } = stillHarness();
|
|
load(640, 480);
|
|
assert.deepEqual(load(1920, 1080), [
|
|
[
|
|
'fillRect',
|
|
PROJECTION_MATTE_COLOR,
|
|
0,
|
|
0,
|
|
PROJECTION_CANVAS_WIDTH,
|
|
PROJECTION_CANVAS_HEIGHT,
|
|
],
|
|
['drawImage', 0, 0, 1920, 1080],
|
|
]);
|
|
assert.equal(runtime.canvasStamp, 2);
|
|
});
|