fogón

← Ancient and prehistory3D assetfogon/market-fountain

Fuente del zoco

by fogonCC013336 blocks
Fuente del zocoDrag to turn it
// «Fuente del zoco» · propio
// An octagonal sandstone basin full of teal water with a pale rim, and in the middle a carved stone column that widens into a shallow bowl at the top.

// The market's fountain: an octagonal sandstone basin full of teal water with a pale rim, and a carved column in
// the middle that widens into a shallow bowl.
const stone = ["#a37c4b", "#b38c57", "#c19a64", "#cda870", "#d8b57e"];
const mortar = "#84653c";
const trim = ["#d4bd8c", "#e0cb9c", "#ebd8ad", "#f4e6c4"];
const water = ["#27626e", "#2f7482", "#3d8b98", "#63abb5"];
const clampi = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
const C = 23.5;
const oct = (x, y) => Math.max(Math.abs(x - C), Math.abs(y - C), (Math.abs(x - C) + Math.abs(y - C)) * 0.7071);
const hash = (a, b) => {
  const s = Math.sin(a * 12.9898 + b * 78.233) * 43758.5453;
  return s - Math.floor(s);
};
// The basin.
for (let x = 0; x < 48; x++)
  for (let y = 0; y < 48; y++) {
    const d = oct(x, y);
    if (d > 20.6) continue;
    for (let z = 0; z <= 10; z++) {
      if (z >= 9) {
        // The rim: pale, wider than the wall.
        if (d > 14.6) set(x, y, z, (Math.round(Math.atan2(y - C, x - C) * 40) % 9 === 0 ? "#bfa878" : trim[clampi((z === 10 ? 2 : 1) + (d < 16 && z === 10 ? 1 : 0) - (rand() < 0.14 ? 1 : 0), 0, 3)]));
        continue;
      }
      if (d > 19.4) continue;
      if (d > 16.2) {
        // The wall: courses of blocks.
        const u = Math.round((Math.atan2(y - C, x - C) + Math.PI) * 19);
        const row = Math.floor(z / 3);
        const k = Math.floor((u + row * 4) / 8);
        const line = z % 3 === 2 || (u + row * 4) % 8 === 0;
        set(x, y, z, line ? mortar : stone[clampi(1 + Math.floor(hash(k, row) * 3) + (z > 5 ? 1 : 0) - (rand() < 0.12 ? 1 : 0), 0, 4)]);
      } else if (z <= 1) set(x, y, z, stone[1]);
      else if (z <= 7) {
        // Water, with paler ripples around the column.
        const r = Math.hypot(x - C, y - C);
        const ripple = z === 7 && (Math.round(r) % 5 === 0 || rand() < 0.06);
        set(x, y, z, ripple ? water[3] : water[clampi(1 + (hash(x >> 1, y >> 1) > 0.6 ? 1 : 0), 0, 2)]);
      }
    }
  }
// The column: its radius at each height.
const profile = [[7, 5.2], [9, 5.2], [10, 4.2], [12, 3.4], [13, 2.7], [26, 2.5], [27, 3.2], [28, 4.3], [29, 5.8], [30, 7.4], [31, 8.8], [32, 9.4], [33, 9.4]];
function radiusAt(z) {
  for (let i = 0; i < profile.length - 1; i++) {
    const [z0, r0] = profile[i], [z1, r1] = profile[i + 1];
    if (z >= z0 && z <= z1) return r0 + ((r1 - r0) * (z - z0)) / (z1 - z0 || 1);
  }
  return 0;
}
for (let z = 7; z <= 33; z++) {
  const r = radiusAt(z);
  for (let x = Math.floor(C - r - 1); x <= Math.ceil(C + r + 1); x++)
    for (let y = Math.floor(C - r - 1); y <= Math.ceil(C + r + 1); y++) {
      const d = Math.hypot(x - C, y - C);
      if (d > r) continue;
      if (z >= 32 && d < r - 1.6) {
        // The bowl holds water.
        if (z === 32) set(x, y, z, Math.round(d) % 3 === 0 ? water[3] : water[2]);
        continue;
      }
      let tone = z >= 27 ? 2 : z < 13 ? 1 : 2;
      if (x < C && y < C) tone++;
      if (x > C + 1 && y > C + 1) tone--;
      if (z === 13 || z === 26 || z === 10) tone = 0;
      if (rand() < 0.1) tone--;
      set(x, y, z, trim[clampi(tone, 0, 3)]);
    }
}
// Flutes carved down the shaft, a knob on top, and four thin streams falling from the bowl.
for (let z = 15; z <= 24; z++) for (const [dx, dy] of [[-3, 0], [3, 0], [0, -3], [0, 3]]) set(Math.round(C + dx), Math.round(C + dy), z, "#bfa878");
box(23, 23, 33, 24, 24, 35, trim[2]);
box(23, 23, 36, 24, 24, 36, trim[3]);
for (const [dx, dy] of [[-10, 0], [10, 0], [0, -10], [0, 10]]) for (let z = 8; z <= 31; z++) if (z % 5 !== 0) set(Math.round(C + dx), Math.round(C + dy), z, z % 2 ? "#9fd6dc" : "#c6ecf0");