import assert from 'node:assert/strict'; import test from 'node:test'; import { applySbsTextureWindow, hideContentMeshes, isLeftEyeCamera, positionPlaneForPresentation, showActiveContentMesh } from '../vr180player/rendering/projection.js'; function createMaterial() { return { map: { offset: { x: 99, y: 99 }, repeat: { x: 99, y: 99 } } }; } function createRenderer({ isPresenting = false, xrCamera = null } = {}) { return { xr: { getCamera: () => xrCamera, isPresenting } }; } function createCamera(x, projectionOffset = 0) { return { matrixWorldInverse: { elements: new Array(16).fill(0).with(12, x) }, projectionMatrix: { elements: new Array(16).fill(0).with(8, projectionOffset) } }; } test('applySbsTextureWindow uses left eye only in non-XR 2D fallback', () => { const material = createMaterial(); applySbsTextureWindow(createRenderer(), createCamera(0), material, true); assert.equal(material.map.offset.x, 0); assert.equal(material.map.repeat.x, 0.5); assert.equal(material.map.offset.y, 0); assert.equal(material.map.repeat.y, 1); }); test('applySbsTextureWindow keeps the full texture outside XR when not in 2D fallback', () => { const material = createMaterial(); applySbsTextureWindow(createRenderer(), createCamera(0), material, false); assert.equal(material.map.offset.x, 0); assert.equal(material.map.repeat.x, 1); assert.equal(material.map.offset.y, 0); assert.equal(material.map.repeat.y, 1); }); test('applySbsTextureWindow selects the right SBS half for the right XR eye', () => { const leftCamera = createCamera(-0.03); const rightCamera = createCamera(0.03); const renderer = createRenderer({ isPresenting: true, xrCamera: { cameras: [leftCamera, rightCamera] } }); const material = createMaterial(); applySbsTextureWindow(renderer, rightCamera, material, false); assert.equal(material.map.offset.x, 0.5); assert.equal(material.map.repeat.x, 0.5); }); test('isLeftEyeCamera falls back to projection matrix offset when XR cameras are unavailable', () => { assert.equal(isLeftEyeCamera(createRenderer({ isPresenting: true }), createCamera(0, -0.1)), true); assert.equal(isLeftEyeCamera(createRenderer({ isPresenting: true }), createCamera(0, 0.1)), false); }); test('showActiveContentMesh hides inactive meshes before showing the active mesh', () => { const vr180Mesh = { visible: true }; const planeMesh = { visible: true }; showActiveContentMesh(vr180Mesh, planeMesh, planeMesh); assert.equal(vr180Mesh.visible, false); assert.equal(planeMesh.visible, true); hideContentMeshes(vr180Mesh, planeMesh); assert.equal(vr180Mesh.visible, false); assert.equal(planeMesh.visible, false); }); test('positionPlaneForPresentation uses the fallback camera depth in 2D plane mode', () => { const calls = []; const planeMesh = { position: { set: (...args) => calls.push(args) } }; positionPlaneForPresentation(planeMesh, { position: { z: 0.1 } }, true, 3, 1.2); positionPlaneForPresentation(planeMesh, { position: { z: 0.1 } }, false, 3, 1.2); assert.deepEqual(calls[0], [0, 1.6, -1.0999999999999999]); assert.deepEqual(calls[1], [0, 1.6, -3]); });