fogón

← City3D assetfogon/crate-stack

Pila de cajones

by fogonCC010299 blocks
Pila de cajonesDrag to turn it
// «Pila de cajones» · propio
// Three wooden crates stacked in a small pile: two side by side and one on top, turned a little, each with plank faces and frames, slightly different wood tones.

// Three wooden crates in a pile: two side by side and one on top, turned a little. Each its own wood.
const WARM = {
  plank: ["#b9803f", "#c68d49", "#d29a55"], groove: "#8a5a28", frame: "#9c6730", frameLight: "#b98040", frameDark: "#744a20",
  brace: "#a87035", nail: "#2e2a26", inner: "#6b4520",
};
const PALE = {
  plank: ["#c9a56b", "#d6b47a", "#e0c28a"], groove: "#9b7a48", frame: "#b08c55", frameLight: "#cdaa72", frameDark: "#86683b",
  brace: "#bb975e", nail: "#3a332b", inner: "#7a5f37",
};
const RED = {
  plank: ["#a5633a", "#b37044", "#c07d4f"], groove: "#774224", frame: "#8a4f2b", frameLight: "#a66239", frameDark: "#65381d",
  brace: "#96582f", nail: "#2a2522", inner: "#5c341c",
};

// What is at a point of a crate S × D × H (null: nothing). F: how wide the frame is. P: how wide a board is.
// flush: the boards are level with the frame (a turned crate keeps its faces whole that way).
function crateAt(lx, ly, lz, S, D, H, F, P, T, flush) {
  if (lx < 0 || ly < 0 || lz < 0 || lx >= S || ly >= D || lz >= H) return null;
  const d = [lx, S - 1 - lx, ly, D - 1 - ly, lz, H - 1 - lz];
  let face = 0;
  for (let i = 1; i < 6; i++) if (d[i] < d[face]) face = i;
  const depth = d[face];
  if (depth > 2) return null; // hollow
  const [a, b, A, B] = face < 2 ? [ly, lz, D, H] : face < 4 ? [lx, lz, S, H] : [lx, ly, S, D];
  const top = face === 5;
  if (a < F || a >= A - F || b < F || b >= B - F) {
    if (depth > 0) return T.frameDark;
    if ((a === 1 || a === A - 2) && (b === 1 || b === B - 2)) return T.nail;
    return top ? T.frameLight : a === 0 || a === A - 1 || b === 0 ? T.frameDark : T.frame;
  }
  if (depth === 0) {
    const across = Math.abs(((a - F) * (B - 2 * F - 1)) / (A - 2 * F - 1) - (b - F));
    if (face !== 4 && across <= 1) return top ? T.frameLight : T.brace;
    if (!flush) return null;
    return a % P === 0 ? T.groove : T.plank[(Math.floor(a / P) * 7 + face * 3) % 3];
  }
  if (depth === 1) return a % P === 0 ? T.groove : T.plank[(Math.floor(a / P) * 7 + face * 3) % 3];
  return T.inner;
}

// A crate with its centre at (cx, cy), standing at z0, turned `angle` around the vertical.
function crate(cx, cy, z0, S, H, angle, T) {
  const ca = Math.cos(angle), sa = Math.sin(angle), r = Math.ceil(S * 0.75), half = (S - 1) / 2;
  for (let x = Math.floor(cx - r); x <= cx + r; x++)
    for (let y = Math.floor(cy - r); y <= cy + r; y++) {
      const dx = x - cx, dy = y - cy;
      const lx = Math.round(dx * ca + dy * sa + half), ly = Math.round(-dx * sa + dy * ca + half);
      for (let z = z0; z < z0 + H; z++) {
        const c = crateAt(lx, ly, z - z0, S, S, H, 3, 4, T, angle !== 0);
        if (c) set(x, y, z, c);
      }
    }
}

crate(13, 23, 0, 19, 18, 0, WARM);
crate(33.5, 24.5, 0, 18, 18, 0, RED);
crate(23, 23.5, 18, 17, 15, 0.3, PALE);