Screw conveyors join across the corner to diagonals (t62)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
// Screw casing geometry shared by both looks, ghosts and placement previews.
|
||||
// smooth-look class of a screw conveyor cell by direction: 9 up, 10 right, 11 down, 12 left
|
||||
const SCREW_CLASS = new Uint8Array(15); SCREW_CLASS[1] = 9; SCREW_CLASS[4] = 10; SCREW_CLASS[2] = 11; SCREW_CLASS[3] = 12;
|
||||
for (let p = P_SCREW_UR; p <= P_SCREW_UL; p++) SCREW_CLASS[p] = 19 + p - P_SCREW_UR;
|
||||
// Drawing only: the four transport lanes remain in the square block.
|
||||
let diagonalJoins = new Uint8Array(0);
|
||||
function diagonalScrewJoins(bx, by, v, planned = null) {
|
||||
// Three bits per end: 1..4 edge exits, 5/6 corner horizontal/vertical; bits 6/7 are collars.
|
||||
const dy = v === 4 || v === 6 ? -1 : 1;
|
||||
let joins = 0;
|
||||
for (let end = 0; end < 2; end++) {
|
||||
const side = end ? 1 : -1, nx = bx + side, ny = by + side * dy;
|
||||
const nb = ny * BW + nx, next = planned && planned.get(nb);
|
||||
const nc = next ? next[0] : blockP[nb], nv = next ? next[1] : blockV[nb];
|
||||
if (nx >= 0 && ny >= 0 && nx < BW && ny < BH &&
|
||||
nc === BP_SCREW && nv >= 4 && (nv === 4 || nv === 6) === (dy < 0)) continue;
|
||||
let join = 0;
|
||||
for (const dir of [side > 0 ? 1 : 3, side * dy > 0 ? 2 : 0]) {
|
||||
const x = bx + SCREW_DIRS[dir][0], y = by + SCREW_DIRS[dir][1];
|
||||
if (x < 0 || y < 0 || x >= BW || y >= BH) continue;
|
||||
const n = y * BW + x, next = planned && planned.get(n);
|
||||
const code = next ? next[0] : blockP[n], nv = next ? next[1] : blockV[n];
|
||||
if ((code === BP_SCREW && nv < 4 && (nv & 1) === (dir & 1)) ||
|
||||
((code === BP_BELT || code === BP_FILTER) && (dir & 1))) { join = dir + 1; break; }
|
||||
}
|
||||
if (!join && nx >= 0 && ny >= 0 && nx < BW && ny < BH && nc === BP_SCREW && nv < 4) join = nv & 1 ? 5 : 6;
|
||||
joins |= join << (end * 3);
|
||||
if (!join) joins |= 64 << end;
|
||||
}
|
||||
return joins;
|
||||
}
|
||||
// Scratch coordinates shared by the pixel shading; no allocations in the grain loop.
|
||||
let diagonalAcross = 0, diagonalAlong = 0, diagonalCap = 0;
|
||||
function diagonalScrewShape(x, y, b, v, joins) {
|
||||
const lx = x - (b % BW) * BS - 2, ly = y - ((b / BW) | 0) * BS - 2;
|
||||
let best = Infinity;
|
||||
for (let end = 0; end < 2; end++) {
|
||||
const join = (joins >> (end * 3)) & 7, side = end ? 1 : -1;
|
||||
const slope = v === 4 || v === 6 ? -1 : 1;
|
||||
const dx = join >= 5 ? (join === 5 ? side : 0) : join ? SCREW_DIRS[join - 1][0] : side * Math.SQRT1_2;
|
||||
const dy = join >= 5 ? (join === 6 ? side * slope : 0) : join ? SCREW_DIRS[join - 1][1] : side * slope * Math.SQRT1_2;
|
||||
const ox = join === 6 ? side * BS : 0, oy = join === 5 ? side * slope * BS : 0;
|
||||
const along = (lx - ox) * dx + (ly - oy) * dy, across = -(lx - ox) * dy + (ly - oy) * dx;
|
||||
let radius = Math.hypot(across, Math.min(0, along));
|
||||
if (join >= 5) {
|
||||
const t = Math.max(0, Math.min(1, (lx * ox + ly * oy) / (BS * BS)));
|
||||
radius = Math.min(radius, Math.hypot(lx - ox * t, ly - oy * t));
|
||||
}
|
||||
const cap = along - (join ? 2 : 2 * Math.SQRT2);
|
||||
const sd = Math.max(radius - 2, join || (joins & (64 << end)) ? cap : -10);
|
||||
if (sd < best) {
|
||||
best = sd; diagonalAcross = side * across < 0 ? -radius : radius;
|
||||
diagonalAlong = ((b % BW) * BS + 2 + (((b / BW) | 0) * BS + 2) * (v === 4 || v === 6 ? -1 : 1)) * Math.SQRT1_2 + side * along; diagonalCap = joins & (64 << end) ? cap : -10;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
function diagonalScrewBlock(x, y, smooth) {
|
||||
const i = y * W + x, own = (y >> 2) * BW + (x >> 2);
|
||||
if (part[i] >= P_SCREW_UR && part[i] <= P_SCREW_UL) return own;
|
||||
if (mat[i] !== EMPTY || part[i] || mach[i] || occ[i] || blockP[own]) return -1;
|
||||
let best = smooth ? 0.75 : 0, found = -1;
|
||||
for (let k = 0; k < 4; k++) {
|
||||
const bx = (x >> 2) + (k === 0 ? -1 : k === 1 ? 1 : 0);
|
||||
const by = (y >> 2) + (k === 2 ? -1 : k === 3 ? 1 : 0);
|
||||
if (bx < 0 || by < 0 || bx >= BW || by >= BH) continue;
|
||||
const b = by * BW + bx, v = blockV[b];
|
||||
if (blockP[b] !== BP_SCREW || v < 4) continue;
|
||||
const joins = diagonalJoins[b] === undefined ? diagonalScrewJoins(bx, by, v) : diagonalJoins[b];
|
||||
const sd = diagonalScrewShape(x + 0.5, y + 0.5, b, v, joins);
|
||||
if (sd <= best) { best = sd; found = b; }
|
||||
}
|
||||
return found;
|
||||
}
|
||||
@@ -265,10 +265,14 @@ ${SM_SLOPE_DRAW}
|
||||
int join = (joins >> (end * 3)) & 7;
|
||||
float side = end == 0 ? -1.0 : 1.0;
|
||||
vec2 ray = join == 0 ? vec2(side, side * (nc == 19 || nc == 21 ? -1.0 : 1.0)) * 0.70710678 :
|
||||
join == 5 ? vec2(side, 0) : join == 6 ? vec2(0, side * d.y) :
|
||||
join == 1 ? vec2(0, -1) : join == 2 ? vec2(1, 0) : join == 3 ? vec2(0, 1) : vec2(-1, 0);
|
||||
float t = dot(local, ray), cross2 = dot(local, vec2(-ray.y, ray.x));
|
||||
vec2 offset = join == 5 ? vec2(0, side * d.y * 4.0) : join == 6 ? vec2(side * 4.0, 0) : vec2(0);
|
||||
float t = dot(local - offset, ray), cross2 = dot(local - offset, vec2(-ray.y, ray.x));
|
||||
float radius = length(vec2(cross2, min(0.0, t))), cap = t - (join == 0 ? 2.82842712 : 2.0);
|
||||
float sd = max(radius - 2.0, join != 0 || (joins & (64 << end)) != 0 ? cap : -10.0);
|
||||
if (join >= 5) radius = min(radius, length(local - offset * clamp(dot(local, offset) / 16.0, 0.0, 1.0)));
|
||||
// A connected mouth meets another opaque pipe; fading its edge leaves a seam.
|
||||
float sd = max(radius - 2.0, (joins & (64 << end)) != 0 ? cap : -10.0);
|
||||
if (sd < screwSD) {
|
||||
screwSD = sd;
|
||||
a = 2.0 + (side * cross2 < 0.0 ? -radius : radius);
|
||||
|
||||
+12
-68
@@ -2,71 +2,6 @@
|
||||
function fogColor(c, k) { return (c & 0xff000000) | (((c >>> 16 & 255) * k) << 16) | (((c >>> 8 & 255) * k) << 8) | ((c & 255) * k); }
|
||||
// drawWorld: the per-grain pixel buffer (pixel look), also the input of the smooth look.
|
||||
// ---------- World pixels ----------
|
||||
// smooth-look class of a screw conveyor cell by direction: 9 up, 10 right, 11 down, 12 left
|
||||
const SCREW_CLASS = new Uint8Array(15); SCREW_CLASS[1] = 9; SCREW_CLASS[4] = 10; SCREW_CLASS[2] = 11; SCREW_CLASS[3] = 12;
|
||||
for (let p = P_SCREW_UR; p <= P_SCREW_UL; p++) SCREW_CLASS[p] = 19 + p - P_SCREW_UR;
|
||||
// Drawing only: the four transport lanes remain in the square block.
|
||||
let diagonalJoins = new Uint8Array(0);
|
||||
function diagonalScrewJoins(bx, by, v, planned = null) {
|
||||
// Low/high three bits select the two edge exits; bits 6/7 mark free-end collars.
|
||||
const dy = v === 4 || v === 6 ? -1 : 1;
|
||||
let joins = 0;
|
||||
for (let end = 0; end < 2; end++) {
|
||||
const side = end ? 1 : -1, nx = bx + side, ny = by + side * dy;
|
||||
const nb = ny * BW + nx, next = planned && planned.get(nb);
|
||||
const nc = next ? next[0] : blockP[nb], nv = next ? next[1] : blockV[nb];
|
||||
if (nx >= 0 && ny >= 0 && nx < BW && ny < BH &&
|
||||
nc === BP_SCREW && nv >= 4 && (nv === 4 || nv === 6) === (dy < 0)) continue;
|
||||
let join = 0;
|
||||
for (const dir of [side > 0 ? 1 : 3, side * dy > 0 ? 2 : 0]) {
|
||||
const x = bx + SCREW_DIRS[dir][0], y = by + SCREW_DIRS[dir][1];
|
||||
if (x < 0 || y < 0 || x >= BW || y >= BH) continue;
|
||||
const n = y * BW + x, next = planned && planned.get(n);
|
||||
const code = next ? next[0] : blockP[n], nv = next ? next[1] : blockV[n];
|
||||
if ((code === BP_SCREW && nv < 4 && (nv & 1) === (dir & 1)) ||
|
||||
((code === BP_BELT || code === BP_FILTER) && (dir & 1))) { join = dir + 1; break; }
|
||||
}
|
||||
joins |= join << (end * 3);
|
||||
if (!join) joins |= 64 << end;
|
||||
}
|
||||
return joins;
|
||||
}
|
||||
// Scratch coordinates shared by the pixel shading; no allocations in the grain loop.
|
||||
let diagonalAcross = 0, diagonalAlong = 0, diagonalCap = 0;
|
||||
function diagonalScrewShape(x, y, b, v, joins) {
|
||||
const lx = x - (b % BW) * BS - 2, ly = y - ((b / BW) | 0) * BS - 2;
|
||||
let best = Infinity;
|
||||
for (let end = 0; end < 2; end++) {
|
||||
const join = (joins >> (end * 3)) & 7, side = end ? 1 : -1;
|
||||
const dx = join ? SCREW_DIRS[join - 1][0] : side * Math.SQRT1_2;
|
||||
const dy = join ? SCREW_DIRS[join - 1][1] : side * (v === 4 || v === 6 ? -1 : 1) * Math.SQRT1_2;
|
||||
const along = lx * dx + ly * dy, across = -lx * dy + ly * dx;
|
||||
const radius = Math.hypot(across, Math.min(0, along)), cap = along - (join ? 2 : 2 * Math.SQRT2);
|
||||
const sd = Math.max(radius - 2, join || (joins & (64 << end)) ? cap : -10);
|
||||
if (sd < best) {
|
||||
best = sd; diagonalAcross = side * across < 0 ? -radius : radius;
|
||||
diagonalAlong = ((b % BW) * BS + 2 + (((b / BW) | 0) * BS + 2) * (v === 4 || v === 6 ? -1 : 1)) * Math.SQRT1_2 + side * along; diagonalCap = joins & (64 << end) ? cap : -10;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
function diagonalScrewBlock(x, y, smooth) {
|
||||
const i = y * W + x, own = (y >> 2) * BW + (x >> 2);
|
||||
if (part[i] >= P_SCREW_UR && part[i] <= P_SCREW_UL) return own;
|
||||
if (mat[i] !== EMPTY || part[i] || mach[i] || occ[i] || blockP[own]) return -1;
|
||||
let best = smooth ? 0.75 : 0, found = -1;
|
||||
for (let k = 0; k < 4; k++) {
|
||||
const bx = (x >> 2) + (k === 0 ? -1 : k === 1 ? 1 : 0);
|
||||
const by = (y >> 2) + (k === 2 ? -1 : k === 3 ? 1 : 0);
|
||||
if (bx < 0 || by < 0 || bx >= BW || by >= BH) continue;
|
||||
const b = by * BW + bx, v = blockV[b];
|
||||
if (blockP[b] !== BP_SCREW || v < 4) continue;
|
||||
const joins = diagonalJoins[b] === undefined ? diagonalScrewJoins(bx, by, v) : diagonalJoins[b];
|
||||
const sd = diagonalScrewShape(x + 0.5, y + 0.5, b, v, joins);
|
||||
if (sd <= best) { best = sd; found = b; }
|
||||
}
|
||||
return found;
|
||||
}
|
||||
function drawWorld() {
|
||||
const bw = R.bw, bh = R.bh, px = R.px;
|
||||
R.vx0 = Math.floor(R.camX); R.vy0 = Math.floor(R.camY);
|
||||
@@ -404,9 +339,18 @@ function drawWorld() {
|
||||
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), joins = slope ? slopeBeltConnections(gbx, gby, code, ghostBlocks) : 0;
|
||||
for (let dy = slope ? -9 : 0; dy < (slope ? 8 : BS); dy++) for (let dx = slope ? -5 : 0; dx < (slope ? 9 : BS); dx++) {
|
||||
const slope = isSlopeBelt(code), diagonal = code === BP_SCREW && v >= 4;
|
||||
const joins = slope ? slopeBeltConnections(gbx, gby, code, ghostBlocks) : diagonal ? diagonalScrewJoins(gbx, gby, v, ghostBlocks) : 0;
|
||||
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) {
|
||||
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;
|
||||
@@ -421,7 +365,7 @@ function drawWorld() {
|
||||
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, c = px[k];
|
||||
const edge = slope ? sd > -0.8 : dx === 0 || dy === 0 || dx === BS - 1 || dy === BS - 1;
|
||||
const edge = slope || diagonal ? sd > -0.8 : dx === 0 || dy === 0 || dx === BS - 1 || 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);
|
||||
|
||||
Reference in New Issue
Block a user