Buildings cast no shadows: daylight passes player-built pieces (t37)
The lighting finds its own roof per column, skipping walls, belts, tubes, machines and molds, and lets light through them like air, in both looks. Natural rock still shades; the simulation's roof (steam condensing under a built roof) is unchanged. New test/t_light.js. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
// Run the renderer's lighting against real simulation data, with only canvas storage stubbed.
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { load, suite, flatWorld } = require('./harness');
|
||||
const { run } = load();
|
||||
const { check, done } = suite();
|
||||
for (const f of ['setup.js', 'light.js']) run(fs.readFileSync(path.join(__dirname, '../src/render', f), 'utf8'));
|
||||
run(`
|
||||
const SET = { lighting: 'full', daylight: 1, ambient: 0.12 };
|
||||
R.lightC = {};
|
||||
R.lightX = { createImageData: (w, h) => ({ data: new Uint8ClampedArray(w * h * 4) }), putImageData() {} };
|
||||
R.vx0 = 0; R.vy0 = 100; R.bw = 320; R.bh = 80;
|
||||
function lightAt(a, x, y) { return a[(Math.floor(y / R.lres) - R.ly0) * R.lw + Math.floor(x / R.lres) - R.lx0]; }
|
||||
`);
|
||||
flatWorld(run, 320, 200, 160);
|
||||
run(`
|
||||
bot.lamp = false;
|
||||
for (let bx = 8; bx < 30; bx++) placeBlock(BP_WALL, RSTONE, bx, 20, true);
|
||||
for (let by = 21; by < 39; by++) {
|
||||
placeBlock(BP_WALL, RSTONE, 8, by, true);
|
||||
placeBlock(BP_WALL, RSTONE, 29, by, true);
|
||||
}
|
||||
placeBlock(BP_BELT, 1, 12, 30, true);
|
||||
placeBlock(BP_TUBE, 0, 14, 30, true);
|
||||
addMachine('silo', 18, 30, 0);
|
||||
addMold('bit', 24, 30, RSTONE, true);
|
||||
for (let y = 80; y < 88; y++) for (let x = 180; x < 280; x++) setCell(y * W + x, STONE, AMB[y], F_NAT);
|
||||
updateRoof();
|
||||
const simRoof = Array.from(roofY);
|
||||
`);
|
||||
for (const mode of ['full', 'fast']) {
|
||||
run(`SET.lighting = '${mode}'; computeLight();`);
|
||||
for (const channel of ['lr', 'lg']) {
|
||||
const [inside, open, rock, ground, openGround] = run(`[lightAt(R.${channel}, 80, 144), lightAt(R.${channel}, 152, 144), lightAt(R.${channel}, 232, 144), lightAt(R.${channel}, 80, 160), lightAt(R.${channel}, 152, 160)]`);
|
||||
check(`${mode} ${channel}: under a built roof matches open daylight`, Math.abs(inside / open - 1) < 0.03, `${inside} / ${open}`);
|
||||
check(`${mode} ${channel}: ground under the base matches outside`, Math.abs(ground / openGround - 1) < 0.03, `${ground} / ${openGround}`);
|
||||
check(`${mode} ${channel}: natural overhang still shades`, rock < open * 0.95, `${rock} / ${open}`);
|
||||
}
|
||||
// Directly check transmission as daylight can hide an opaque piece in the open.
|
||||
for (const [name, x, y] of [['wall', 32, 120], ['belt', 48, 120], ['tube', 56, 120], ['machine', 72, 120], ['mold', 96, 120]]) {
|
||||
const a = run(`lightAt(R.latt, ${x}, ${y})`);
|
||||
check(`${mode}: ${name} transmits like air`, Math.abs(a - Math.pow(0.978, mode === 'fast' ? 4 : 2)) < 1e-6, a);
|
||||
}
|
||||
}
|
||||
check('lighting leaves the simulation roof unchanged', run('simRoof.every((y, x) => roofY[x] === y) && roofY[80] === 80'));
|
||||
for (const material of ['STONE', 'SAND', 'WATER']) {
|
||||
run(`setCell(96 * W + 80, ${material}, AMB[96], F_NAT); updateRoof(); computeLight();`);
|
||||
check(`${material} above the view still blocks daylight`, run('lightAt(R.lr, 80, 144) < 0.95'));
|
||||
run('setCell(96 * W + 80, EMPTY, AMB[96], 0);');
|
||||
}
|
||||
run('updateRoof(); computeLight();');
|
||||
check('removing an obstruction restores daylight', run('lightAt(R.lr, 80, 144) === 1'));
|
||||
for (const field of ['blockP[24 * BW + 20]', 'mach[96 * W + 80]', 'part[96 * W + 80]']) {
|
||||
run(`setCell(96 * W + 80, STONE, AMB[96], F_NAT); ${field} = 1; updateRoof(); computeLight();`);
|
||||
check(`${field}: built contents do not shade or absorb light`, run('lightAt(R.lr, 80, 144) === 1 && Math.abs(lightAt(R.latt, 80, 96) - Math.pow(0.978, 4)) < 1e-6'));
|
||||
run(`${field} = 0; setCell(96 * W + 80, EMPTY, AMB[96], 0);`);
|
||||
}
|
||||
run('updateRoof();');
|
||||
run(`SET.daylight = 0; temp[140 * W + 80] = 1500; computeLight();`);
|
||||
check('hot material inside the base lights its surroundings', run('lightAt(R.lr, 88, 140) > 0.2'));
|
||||
run(`temp[140 * W + 80] = AMB[140]; bot.x = 72; bot.y = 130; bot.lamp = true; computeLight();`);
|
||||
check('the bot lamp still lights the base', run('lightAt(R.lr, 80, 140) > 0.2'));
|
||||
done();
|
||||
Reference in New Issue
Block a user