WebGPU pixel look: GPU colours the world, CPU only rare cells (t88 phase 2a)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 19:49:36 -04:00
co-authored by Claude Opus 5.5
parent b2c9ad9533
commit fc05146887
29 changed files with 949 additions and 386 deletions
+80
View File
@@ -0,0 +1,80 @@
// Loose bars, flying grains and queued blueprint blocks in the grain buffer.
function worldObjects() {
const { bw, bh, px, vx0, vy0, smoothOn: sm, lens } = R;
const useFog = SET.fog, incand = SET.incandescence;
// bars and other loose objects
if (!lens) for (const e of ents) {
if (useFog && fogSeen(e.ix, e.iy) < 64) continue;
const ex = e.ix - vx0, ey = e.iy - vy0;
if (ex + BAR_W < 0 || ey + BAR_H < 0 || ex >= bw || ey >= bh) continue;
const m = e.m;
for (let dy = 0; dy < BAR_H; dy++) for (let dx = 0; dx < BAR_W; dx++) {
const sx = ex + dx, sy = ey + dy;
if (sx < 0 || sy < 0 || sx >= bw || sy >= bh) continue;
let r = COLR[m], g = COLG[m], b = COLB[m];
const end = dx === 0 || dx === BAR_W - 1;
if (dy === 0) { r += end ? 10 : 34; g += end ? 8 : 28; b += end ? 6 : 24; } else { r -= end ? 34 : 18; g -= end ? 30 : 16; b -= end ? 26 : 14; }
if (e.T > 450 && incand) { const gi = glowIndex(e.T), w = GLOW_W[gi]; r = r * (1 - w) + GLOW_R[gi] * w; g = g * (1 - w) + GLOW_G[gi] * w; b = b * (1 - w) + GLOW_B[gi] * w; }
if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0;
if (R.gpuOn && !px[sy * bw + sx]) GPU.overrideCount++;
px[sy * bw + sx] = (sm ? 0x04000000 : 0xff000000) | ((b > 255 ? 255 : b | 0) << 16) | ((g > 255 ? 255 : g | 0) << 8) | (r > 255 ? 255 : r | 0);
}
}
// grains in flight from the vacuum nozzle, a screw or a belt (rain and snow are drawn over the top, see drawRain)
if (!lens) for (const f of flyers) {
if (f.rain || (useFog && fogSeen(f.x, f.y) < 64)) continue;
const sx = Math.floor(f.x) - vx0, sy = Math.floor(f.y) - vy0;
if (sx < 0 || sy < 0 || sx >= bw || sy >= bh) continue;
const m = f.m, v = ((sx * 7 + sy * 13) & 15) - 8;
if (R.gpuOn && !px[sy * bw + sx]) GPU.overrideCount++;
px[sy * bw + sx] = (sm ? 0x02000000 : 0xff000000) | (Math.max(0, Math.min(255, COLB[m] + v)) << 16) | (Math.max(0, Math.min(255, COLG[m] + v)) << 8) | Math.max(0, Math.min(255, COLR[m] + v));
}
// blueprint ghosts: blocks waiting to be built
if (ghostBlocks.size) {
const bx0 = vx0 >> 2, by0 = vy0 >> 2, bx1 = (vx0 + bw) >> 2, by1 = (vy0 + bh) >> 2;
const pulse = (R.frame >> 3) & 3;
for (const [b, gv] of ghostBlocks) {
const gbx = b % BW, gby = (b / BW) | 0;
if (gbx < bx0 || gbx > bx1 || gby < by0 || gby > by1) continue;
const blocked = ghostBlocked.has(b), code = gv[0], v = gv[1];
let tr = 90, tg = 190, tb = 230;
if (blocked) { tr = 230; tg = 70; tb = 60; }
else if (isWall(code) && WALL_OF[v]) { const wm = WALL_OF[v]; tr = (COLR[wm] + 90) / 2; tg = (COLG[wm] + 190) / 2; tb = (COLB[wm] + 230) / 2; }
const slope = isSlopeBelt(code), diagonal = code === BP_SCREW && (v >= 4 || straightScrewJoins(gbx, gby, v, ghostBlocks));
const joins = slope ? slopeBeltConnections(gbx, gby, code, ghostBlocks) : diagonal ? (v >= 4 ? diagonalScrewJoins(gbx, gby, v, ghostBlocks) : straightScrewJoins(gbx, gby, v, ghostBlocks)) : 0;
const caps = code === BP_BELT || code === BP_FILTER ? flatBeltCaps(b, ghostBlocks) : 3;
for (let dy = slope ? -9 : diagonal ? -4 : 0; dy < (slope || diagonal ? 8 : BS); dy++) for (let dx = slope ? -5 : diagonal ? -4 : 0; dx < (slope ? 9 : diagonal ? 8 : BS); dx++) {
let sd = 0;
if (diagonal) {
if (v < 4 && ((v & 1) ? dx < 0 || dx >= BS : dy < 0 || dy >= BS)) continue;
const x = gbx * BS + dx, y = gby * BS + dy;
if (x < 0 || y < 0 || x >= W || y >= H) continue;
const i = y * W + x, n = (y >> 2) * BW + (x >> 2);
if (n !== b && (mat[i] !== EMPTY || part[i] || mach[i] || occ[i] || blockP[n])) continue;
sd = diagonalScrewShape(x + 0.5, y + 0.5, b, v, joins);
if (sd > 0) continue;
}
if (slope) {
const x = gbx * BS + dx, y = gby * BS + dy;
if (x < 0 || y < 0 || x >= W || y >= H) continue;
const i = y * W + x, n = (y >> 2) * BW + (x >> 2);
if (n !== b && (mat[i] !== EMPTY || part[i] || mach[i] || occ[i] || blockP[n])) continue;
sd = slopeBeltShape(x + 0.5, y + 0.5, b, joins, code);
const up = !isFilter(code) && slopeUphill(code, v), rib = up && slopePreviewCleat(x, y, b, code);
if (sd > 0 && !rib && (!up || slopeWallShape(x + 0.5, y + 0.5, b, code) > 0)) continue;
if (rib) sd = -0.1;
}
if (isSlope(code) && !slopeCell(code, dx, dy)) continue;
const sx = gbx * BS + dx - vx0, sy = gby * BS + dy - vy0;
if (sx < 0 || sy < 0 || sx >= bw || sy >= bh) continue;
const k = sy * bw + sx;
if (R.gpuOn && !px[k]) cellPixel(sx + vx0, sy + vy0);
const c = px[k];
const edge = slope || diagonal ? sd > -0.8 : (dx === 0 && (caps & 1)) || dy === 0 || (dx === BS - 1 && (caps & 2)) || dy === BS - 1;
const a = edge ? (((dx + dy + pulse) & 3) === 0 ? 0.85 : 0.6) : 0.28;
const pr = c & 255, pg = (c >> 8) & 255, pb = (c >> 16) & 255;
px[k] = (sm ? 0x04000000 : 0xff000000) | ((pb + (tb - pb) * a) << 16) | ((pg + (tg - pg) * a) << 8) | (pr + (tr - pr) * a);
}
}
}
}