{"version":3,"sources":["liquid-look.mjs"],"sourcesContent":["// THE ONE LOOK OF A LIQUID (the owner, Oct 3: \"Let's use deep glow for the inventory item textures and try to use the top\n// of that inventory item texture in game\", with \"that pulsing effect\" and \"consistent for all liquids so only the hex color\n// is changing\"; picked as Deep glow on the Liquid Flow review page). Every liquid kube's icon, a pool or sea's surface,\n// and lava wherever it lies, are this one function of position, time and a colour:\n//   * a body darker in its depths and lighter at its surface, with a slow current through it (fbm of value noise);\n//   * on top, soft rings spreading from the middle of each kube;\n//   * a slow pulse, its phase drifting across the surface in broad waves, between the colour and the colour squared,\n//     which deepens any hue without changing it: lava's orange to orange-red, water's blue to a deeper blue.\n// GLSL only, guarded so a shader that pulls it in twice (a lava sea is a fluid AND a melt) compiles once.\nexport const LIQUID_LOOK_GLSL = `\n#ifndef LIQUID_LOOK\n#define LIQUID_LOOK\nfloat llHash(vec3 p) { p = fract(p * 0.3183099 + 0.1); p *= 17.0; return fract(p.x * p.y * p.z * (p.x + p.y + p.z)); }\nfloat llNoise(vec3 x) { vec3 i = floor(x), f = fract(x); f = f * f * (3.0 - 2.0 * f);\n  return mix(mix(mix(llHash(i + vec3(0, 0, 0)), llHash(i + vec3(1, 0, 0)), f.x), mix(llHash(i + vec3(0, 1, 0)), llHash(i + vec3(1, 1, 0)), f.x), f.y),\n             mix(mix(llHash(i + vec3(0, 0, 1)), llHash(i + vec3(1, 0, 1)), f.x), mix(llHash(i + vec3(0, 1, 1)), llHash(i + vec3(1, 1, 1)), f.x), f.y), f.z); }\nfloat llFbm(vec3 p) { float a = 0.5, s = 0.0; for (int i = 0; i < 4; i++) { s += a * llNoise(p); p = p * 2.03 + 11.7; a *= 0.5; } return s; }\n// p: position in kubes · r: distance from the middle of its kube's top (0 to about 0.7) · depth: 0 at the surface, 1 a kube\n// down · top: 1 on a top face, 0 elsewhere · c: the liquid's colour · t: seconds.\nvec3 liquidLook(vec3 p, float r, float depth, float top, vec3 c, float t) {\n  float cur = llFbm(p * 2.5 + vec3(t * 0.12, -t * 0.05, t * 0.08));\n  float v = 0.85 - depth * 0.7 + (cur - 0.5) * 0.5;\n  vec3 dk = c * 0.42, lt = mix(c, vec3(1.0), 0.6);\n  vec3 col = mix(dk, mix(c, lt, smoothstep(0.55, 1.0, v)), smoothstep(0.0, 0.6, v));\n  col = mix(col, lt, top * (0.25 + 0.2 * sin(r * 18.0 - t * 1.5)));\n  float pulse = 0.5 + 0.5 * sin(t * 1.25 + 6.2832 * llNoise(p * 0.15 + 3.0));\n  return mix(col, col * col, pulse * 0.55);\n}\n// THE SAME, FOR A LINEAR-LIGHT SHADER (the world's). The look is worked out in display colour, where its icon is drawn,\n// and turned back into linear light: done in linear light, its mix toward white came out as pale pink lava.\nvec3 liquidLookLinear(vec3 p, float r, float depth, float top, vec3 cLinear, float t) {\n  vec3 c = pow(max(cLinear, vec3(0.0)), vec3(1.0 / 2.2));\n  return pow(max(liquidLook(p, r, depth, top, c, t), vec3(0.0)), vec3(2.2));\n}\n#endif\n`;\n\n// ---- FRESNEL WATER AND COOLING LAVA (the owner's play review, Oct 23, v9, the primary: \"water reflects the sky at grazing\n// angles and shows depth colour; lava lights its surroundings and crusts as it cools\") --------------------------------------\n// Neither changes LIQUID_LOOK_GLSL, so a liquid's icon is as it was.\n// WATER. Schlick's Fresnel with water's F0 (0.02): looking straight down a liquid is a window, along it a mirror. The\n// mirror shows the sky the walker sees over the water (system-view.js waterSkyInto, on the world underfoot only, so other\n// worlds look as they always have), and the reflection makes it opaque as it brightens. A sea's depth colour is read along\n// the view: the flat depth (SEA_FLAT_DEPTH) lengthened by how shallowly it is looked into, so the water near your feet shows\n// its shallow colour and the far water its deep one, smoothly, with no step anywhere on the sheet (seaColumn).\nexport const WATER_F0 = 0.02;\nexport const WATER_VIEW_MAX = 4;            // the most the view lengthens the column (a grazing look into a sea)\nexport function waterFresnel(cosV) { const c = Math.max(0, Math.min(1, cosV)); return WATER_F0 + (1 - WATER_F0) * Math.pow(1 - c, 5); }\nexport function waterViewDepth(depth, cosV) { return depth * Math.min(WATER_VIEW_MAX, 1 / Math.max(1e-3, Math.abs(cosV))); }\nexport const WATER_FRESNEL_GLSL = `\nfloat waterFresnel(float cosV) { float c = clamp(cosV, 0.0, 1.0); return ${WATER_F0.toFixed(3)} + ${(1 - WATER_F0).toFixed(3)} * pow(1.0 - c, 5.0); }\nfloat waterViewDepth(float depth, float cosV) { return depth * min(${WATER_VIEW_MAX.toFixed(1)}, 1.0 / max(1e-3, abs(cosV))); }\n`;\n// LAVA. A lava sea stays molten: its look is the owner's (still, pure glow). What is POURED cools: from LAVA_COOL_AFTER\n// seconds after it settles, over LAVA_COOL_S, its glow sinks to a deep, dull red under a dark basalt skin, never to black\n// and in soft patches (a slow noise), not plates with glowing seams (the owner's rule for lava). lavaCool is how far it has\n// gone. The light it throws (collectLightSources: a lava sea's open cells, and now poured lava's) comes from the melt.\nexport const LAVA_COOL_AFTER = 20, LAVA_COOL_S = 150;\nexport const LAVA_CRUST_GLOW = Object.freeze([0.5, 0.2, 0.12]);   // what is left of the melt's glow, per channel, once cooled\nexport function lavaCool(sinceSettled) { const t = Math.max(0, Math.min(1, (sinceSettled - LAVA_COOL_AFTER) / LAVA_COOL_S)); return t * t * (3 - 2 * t); }\n// GLSL (needs LIQUID_LOOK_GLSL's llNoise): the emitted light and the lit colour at P, cooled by `cool` (lavaCool).\nexport const LAVA_COOL_GLSL = `\nfloat lavaCool(float since) { float t = clamp((since - ${LAVA_COOL_AFTER.toFixed(1)}) / ${LAVA_COOL_S.toFixed(1)}, 0.0, 1.0); return t * t * (3.0 - 2.0 * t); }\nvoid lavaCrust(inout vec3 emit, inout vec3 albedo, vec3 P, float cool) {\n  if (cool <= 0.0) return;\n  float c = clamp(cool * 1.25 - 0.25 * llNoise(P * 1.7 + 5.0), 0.0, 1.0);\n  emit *= mix(vec3(1.0), vec3(${LAVA_CRUST_GLOW.map((v) => v.toFixed(2)).join(', ')}), c);\n  albedo = mix(albedo, vec3(0.045, 0.032, 0.028), c);\n}\n`;\n"],"mappings":"AASO,aAAM,iBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoCnB,SAAW,IACX,eAAiB,EACvB,gBAAS,aAAa,KAAM,CAAE,MAAM,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,IAAI,CAAC,EAAG,MAAO,MAAY,EAAI,KAAY,KAAK,IAAI,EAAI,EAAG,CAAC,CAAG,CAC/H,gBAAS,eAAe,MAAO,KAAM,CAAE,OAAO,MAAQ,KAAK,IAAI,EAAgB,EAAI,KAAK,IAAI,KAAM,KAAK,IAAI,IAAI,CAAC,CAAC,CAAG,CACpH,aAAM,mBAAqB;AAAA,2EACyC,IAAS,QAAQ,CAAC,CAAC,OAAO,EAAI,KAAU,QAAQ,CAAC,CAAC;AAAA,qEACxD,GAAe,QAAQ,CAAC,CAAC;AAAA,EAMjF,gBAAkB,GAAI,YAAc,IACpC,gBAAkB,OAAO,OAAO,CAAC,GAAK,GAAK,GAAI,CAAC,EACtD,gBAAS,SAAS,aAAc,CAAE,MAAM,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,GAAI,aAAe,iBAAmB,WAAW,CAAC,EAAG,OAAO,EAAI,GAAK,EAAI,EAAI,EAAI,CAElJ,aAAM,eAAiB;AAAA,yDAC2B,gBAAgB,QAAQ,CAAC,CAAC,OAAO,YAAY,QAAQ,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,gCAIhF,gBAAgB,IAAK,GAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA;","names":[],"file":"liquid-look.mjs"}