fogón

← Ancient and prehistory3D assetfogon/town-gate

Arco de entrada

by fogonCC012096 blocks
Arco de entradaDrag to turn it
// «Arco de entrada» · propio
// A sandstone town gateway: two thick wall stubs joined by a round arch you can walk through, with a pale band and square merlons along the top.

// A sandstone town gateway: two thick wall stubs joined by a round arch to walk through, a pale band and merlons.
const stone = ["#a37c4b", "#b38c57", "#c19a64", "#cda870", "#d8b57e"];
const footStone = ["#806038", "#8f6d42", "#9c794c"];
const mortar = "#84653c";
const trim = ["#d4bd8c", "#e0cb9c", "#ebd8ad", "#f2e2bd"];
const clampi = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
const X0 = 2, X1 = 45, Y0 = 18, Y1 = 29, TOP = 30;
const CX = 23.5, SPRING = 13, R = 11;
const hash = (a, b) => {
  const s = Math.sin(a * 12.9898 + b * 78.233) * 43758.5453;
  return s - Math.floor(s);
};
function blockAt(u, z, tones, base) {
  const row = Math.floor(z / 4);
  const len = 8 + (row % 3);
  const shift = (row % 2) * 4 + ((row * 5) % 3);
  const k = Math.floor((u + shift) / len);
  if (z % 4 === 3 || (u + shift) % len === 0) return mortar;
  let tone = base + Math.floor(hash(k, row) * 3);
  if (rand() < 0.12) tone--;
  return tones[clampi(tone, 0, tones.length - 1)];
}
// Inside the opening?
const open = (x, z) => (z <= SPRING ? Math.abs(x - CX) < R : Math.hypot(x - CX, z - SPRING) < R);
// How far from the opening's edge (for the ring of pale stones around it).
const ring = (x, z) => (z <= SPRING ? Math.abs(x - CX) - R : Math.hypot(x - CX, z - SPRING) - R);

for (let x = X0; x <= X1; x++)
  for (let y = Y0; y <= Y1; y++)
    for (let z = 0; z <= TOP; z++) {
      if (open(x, z)) continue;
      const e = ring(x, z);
      const face = y === Y0 || y === Y1;
      if (e < 2.6 && z > 5) {
        // The arch stones: pale, cut like wedges above the spring.
        const a = z <= SPRING ? Math.floor(z / 4) : Math.floor((Math.atan2(z - SPRING, x - CX) / Math.PI) * 9);
        const joint = z <= SPRING ? z % 4 === 3 : Math.abs((Math.atan2(z - SPRING, x - CX) / Math.PI) * 9 - Math.round((Math.atan2(z - SPRING, x - CX) / Math.PI) * 9)) < 0.12;
        set(x, y, z, joint && face ? "#bfa878" : trim[clampi(1 + (a % 2) + (e < 1 ? 0 : 1) - (rand() < 0.12 ? 1 : 0), 0, 3)]);
        continue;
      }
      const u = x === X0 || x === X1 ? y + 2 : x;
      set(x, y, z, blockAt(u, z, stone, z > 18 ? 2 : 1));
    }
// The foot of each stub: darker, a block wider.
for (let x = X0 - 1; x <= X1 + 1; x++)
  for (let y = Y0 - 1; y <= Y1 + 1; y++)
    for (let z = 0; z <= 5; z++) {
      if (Math.abs(x - CX) < R + 0.6) continue;
      const u = x < X0 || x > X1 ? y + 2 : x + 3;
      set(x, y, z, z === 5 ? footStone[2] : blockAt(u, z, footStone, 0));
    }
// The pale band.
for (let x = X0 - 1; x <= X1 + 1; x++)
  for (let y = Y0 - 1; y <= Y1 + 1; y++)
    for (let z = TOP - 3; z <= TOP - 2; z++) set(x, y, z, (x + 5) % 11 === 0 ? "#bfa878" : trim[clampi((z === TOP - 2 ? 2 : 1) - (rand() < 0.15 ? 1 : 0), 0, 3)]);
// The top and its merlons, front and back.
for (let x = X0; x <= X1; x++) for (let y = Y0; y <= Y1; y++) set(x, y, TOP, stone[clampi(3 - (rand() < 0.2 ? 1 : 0), 0, 4)]);
for (let x = X0; x <= X1; x++) {
  const m = (x - X0) % 8;
  if (m > 4) continue;
  for (const y of [Y0, Y0 + 1, Y1 - 1, Y1])
    for (let z = TOP + 1; z <= TOP + 5; z++) {
      let tone = z >= TOP + 4 ? 3 : 2;
      if (m === 0 || m === 4) tone--;
      if (rand() < 0.12) tone--;
      set(x, y, z, z === TOP + 5 ? trim[clampi(tone - 1, 0, 3)] : stone[clampi(tone + 1, 0, 4)]);
    }
}
// The keystone, and the paving inside the passage.
for (const y of [Y0 - 1, Y1 + 1]) box(22, y, SPRING + 10, 25, y, SPRING + 13, trim[3]);
for (const y of [Y0 - 1, Y1 + 1]) box(23, y, SPRING + 11, 24, y, SPRING + 12, "#cdb787");
for (let x = 13; x <= 34; x++) for (let y = Y0 - 1; y <= Y1 + 1; y++) set(x, y, 0, (x + (Math.floor(y / 3) % 2) * 2) % 4 === 0 || y % 3 === 0 ? "#9c7d50" : hash(Math.floor(x / 4), Math.floor(y / 3)) > 0.5 ? "#c9a56c" : "#b99660");