@adatechnology/game-fluids-three 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/index.d.ts +315 -4
- package/dist/index.global.js +9628 -241
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +827 -193
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/clip.ts","../src/liquid-body.ts","../src/util.ts","../src/materials.ts","../src/particles.ts","../src/quality.ts","../src/stains.ts","../src/streams.ts","../src/renderer.ts"],"sourcesContent":["/**\n * Convex solids (a cylinder or a box, in container space) clipped by the liquid surface plane `u · p <= d`.\n * This is robust for any tilt (upright, lying on its side, upside down): the result is exactly the part of the container the liquid fills,\n * with the surface cap lying on the plane. Written into preallocated buffers, no per-frame geometry is created.\n */\nexport type V3 = [number, number, number]\n\nexport interface SolidFace {\n p: V3[]\n n: V3[]\n}\n\nexport interface Solid {\n faces: SolidFace[]\n /** Upper bound of the vertices a clip can write (non-indexed triangles). */\n maxVertices: number\n}\n\nconst sub = (a: V3, b: V3): V3 => [a[0] - b[0], a[1] - b[1], a[2] - b[2]]\nconst cross = (a: V3, b: V3): V3 => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]\nconst dot = (a: V3, b: V3): number => a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\nconst norm = (a: V3): V3 => {\n const l = Math.hypot(a[0], a[1], a[2]) || 1\n return [a[0] / l, a[1] / l, a[2] / l]\n}\n\n/** Reverse the winding when the face does not look outward. */\nconst orient = (p: V3[], n: V3[], outward: V3): SolidFace => {\n if (dot(cross(sub(p[1], p[0]), sub(p[2], p[0])), outward) < 0) return { p: [...p].reverse(), n: [...n].reverse() }\n return { p, n }\n}\n\nconst finish = (faces: SolidFace[]): Solid => {\n let maxVertices = 0\n for (const f of faces) maxVertices += (f.p.length * 2 + 2) * 3\n // The surface cap: at most one point per face edge cut.\n maxVertices += faces.length * 3 * 2 + 64\n return { faces, maxVertices }\n}\n\nexport const cylinderSolid = (radius: number, height: number, segments: number): Solid => {\n const faces: SolidFace[] = []\n const ring = (y: number, i: number): V3 => {\n const a = (i / segments) * Math.PI * 2\n return [Math.cos(a) * radius, y, Math.sin(a) * radius]\n }\n const radial = (i: number): V3 => {\n const a = (i / segments) * Math.PI * 2\n return [Math.cos(a), 0, Math.sin(a)]\n }\n for (let i = 0; i < segments; i++) {\n const j = (i + 1) % segments\n const mid = norm([radial(i)[0] + radial(j)[0], 0, radial(i)[2] + radial(j)[2]])\n faces.push(orient([ring(0, i), ring(0, j), ring(height, j), ring(height, i)], [radial(i), radial(j), radial(j), radial(i)], mid))\n }\n const bottom: V3[] = []\n const top: V3[] = []\n for (let i = 0; i < segments; i++) {\n bottom.push(ring(0, i))\n top.push(ring(height, i))\n }\n faces.push(orient(bottom, bottom.map((): V3 => [0, -1, 0]), [0, -1, 0]))\n faces.push(orient(top, top.map((): V3 => [0, 1, 0]), [0, 1, 0]))\n return finish(faces)\n}\n\nexport const boxSolid = (size: V3): Solid => {\n const hx = size[0] / 2\n const hz = size[2] / 2\n const hy = size[1]\n const c = (x: number, y: number, z: number): V3 => [x * hx, y * hy, z * hz]\n const quad = (a: V3, b: V3, cc: V3, d: V3, n: V3): SolidFace => orient([a, b, cc, d], [n, n, n, n], n)\n return finish([\n quad(c(1, 0, -1), c(1, 1, -1), c(1, 1, 1), c(1, 0, 1), [1, 0, 0]),\n quad(c(-1, 0, -1), c(-1, 1, -1), c(-1, 1, 1), c(-1, 0, 1), [-1, 0, 0]),\n quad(c(-1, 1, -1), c(1, 1, -1), c(1, 1, 1), c(-1, 1, 1), [0, 1, 0]),\n quad(c(-1, 0, -1), c(1, 0, -1), c(1, 0, 1), c(-1, 0, 1), [0, -1, 0]),\n quad(c(-1, 0, 1), c(1, 0, 1), c(1, 1, 1), c(-1, 1, 1), [0, 0, 1]),\n quad(c(-1, 0, -1), c(1, 0, -1), c(1, 1, -1), c(-1, 1, -1), [0, 0, -1]),\n ])\n}\n\nconst polyP: number[] = []\nconst polyN: number[] = []\nconst cut: number[] = []\n\n/**\n * Writes the triangles of `solid ∩ { u · p <= d }` into `pos` / `nor` (non-indexed, 3 floats per vertex) and returns the vertex count.\n * The cap on the plane has normal `u`.\n */\nexport const clipSolid = (solid: Solid, u: V3, d: number, pos: Float32Array, nor: Float32Array): number => {\n let count = 0\n const capacity = Math.floor(pos.length / 3)\n cut.length = 0\n const put = (px: number, py: number, pz: number, nx: number, ny: number, nz: number): void => {\n if (count >= capacity) return\n pos[count * 3] = px\n pos[count * 3 + 1] = py\n pos[count * 3 + 2] = pz\n nor[count * 3] = nx\n nor[count * 3 + 1] = ny\n nor[count * 3 + 2] = nz\n count++\n }\n\n for (const face of solid.faces) {\n const m = face.p.length\n polyP.length = 0\n polyN.length = 0\n for (let i = 0; i < m; i++) {\n const a = face.p[i]\n const b = face.p[(i + 1) % m]\n const na = face.n[i]\n const nb = face.n[(i + 1) % m]\n const da = u[0] * a[0] + u[1] * a[1] + u[2] * a[2] - d\n const db = u[0] * b[0] + u[1] * b[1] + u[2] * b[2] - d\n const ina = da <= 0\n const inb = db <= 0\n if (ina) {\n polyP.push(a[0], a[1], a[2])\n polyN.push(na[0], na[1], na[2])\n if (da > -1e-7) cut.push(a[0], a[1], a[2])\n }\n if (ina !== inb) {\n const t = da / (da - db)\n const x = a[0] + (b[0] - a[0]) * t\n const y = a[1] + (b[1] - a[1]) * t\n const z = a[2] + (b[2] - a[2]) * t\n polyP.push(x, y, z)\n polyN.push(na[0] + (nb[0] - na[0]) * t, na[1] + (nb[1] - na[1]) * t, na[2] + (nb[2] - na[2]) * t)\n cut.push(x, y, z)\n }\n }\n const n = polyP.length / 3\n for (let i = 1; i < n - 1; i++) {\n for (const k of [0, i, i + 1]) put(polyP[k * 3], polyP[k * 3 + 1], polyP[k * 3 + 2], polyN[k * 3], polyN[k * 3 + 1], polyN[k * 3 + 2])\n }\n }\n\n // Cap on the plane: unique cut points sorted around their centre.\n const pts: V3[] = []\n for (let i = 0; i < cut.length; i += 3) {\n let dup = false\n for (const q of pts) {\n if (Math.abs(q[0] - cut[i]) + Math.abs(q[1] - cut[i + 1]) + Math.abs(q[2] - cut[i + 2]) < 1e-6) {\n dup = true\n break\n }\n }\n if (!dup) pts.push([cut[i], cut[i + 1], cut[i + 2]])\n }\n if (pts.length >= 3) {\n const c: V3 = [0, 0, 0]\n for (const q of pts) {\n c[0] += q[0] / pts.length\n c[1] += q[1] / pts.length\n c[2] += q[2] / pts.length\n }\n const e1 = norm(cross(u, Math.abs(u[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0]))\n const e2 = cross(u, e1)\n const keyed = pts.map((q) => ({ q, a: Math.atan2(dot(sub(q, c), e2), dot(sub(q, c), e1)) })).sort((p, r) => p.a - r.a)\n for (let i = 0; i < keyed.length; i++) {\n for (const q of [c, keyed[i].q, keyed[(i + 1) % keyed.length].q]) put(q[0], q[1], q[2], u[0], u[1], u[2])\n }\n }\n return count\n}\n","import type * as THREE_NS from 'three'\nimport type { ContainerState, FluidWorld, Vec3 } from '@adatechnology/game-fluids'\nimport { boxSolid, clipSolid, cylinderSolid } from './clip'\nimport type { Solid, V3 } from './clip'\nimport type { MaterialCache } from './materials'\nimport type { ParticlePool } from './particles'\nimport type { QualityProfile } from './quality'\nimport type { ThreeLib } from './types'\n\n/** How far the liquid is kept inside the container walls so it does not fight with them. */\nconst INSET = 0.985\n\n/**\n * The liquid inside one bound container: the container's inner shape clipped by the world surface plane, expressed in the bound object's space,\n * so the cap always lies on the plane whatever the tilt. Plus steam puffs above a hot surface.\n */\nexport class LiquidBody {\n readonly group: THREE_NS.Group\n private mesh: THREE_NS.Mesh | null = null\n private geometry: THREE_NS.BufferGeometry | null = null\n private pos: Float32Array = new Float32Array(0)\n private nor: Float32Array = new Float32Array(0)\n private solid: Solid | null = null\n private shapeKey = ''\n private steamAcc = 0\n private readonly inverse: THREE_NS.Matrix4\n private readonly tmpN: THREE_NS.Vector3\n private readonly tmpP: THREE_NS.Vector3\n vertices = 0\n\n constructor(\n private readonly THREE: ThreeLib,\n readonly containerId: string,\n readonly object: THREE_NS.Object3D,\n offset: Vec3,\n ) {\n this.group = new THREE.Group()\n this.group.name = 'fluid_liquid_body'\n this.group.position.set(offset[0], offset[1], offset[2])\n this.inverse = new THREE.Matrix4()\n this.tmpN = new THREE.Vector3()\n this.tmpP = new THREE.Vector3()\n object.add(this.group)\n }\n\n get visible(): boolean {\n return !!this.mesh && this.mesh.visible\n }\n\n private build(state: ContainerState, quality: QualityProfile): void {\n const shape = state.shape\n if (!shape) return\n const key = JSON.stringify(shape) + quality.bodySegments\n if (key === this.shapeKey) return\n this.shapeKey = key\n this.solid =\n shape.kind === 'cylinder'\n ? cylinderSolid(shape.radius * INSET, shape.height * INSET, quality.bodySegments)\n : boxSolid([shape.size[0] * INSET, shape.size[1] * INSET, shape.size[2] * INSET])\n const T = this.THREE\n this.geometry?.dispose()\n this.pos = new Float32Array(this.solid.maxVertices * 3)\n this.nor = new Float32Array(this.solid.maxVertices * 3)\n this.geometry = new T.BufferGeometry()\n const p = new T.BufferAttribute(this.pos, 3)\n const n = new T.BufferAttribute(this.nor, 3)\n p.setUsage(T.DynamicDrawUsage)\n n.setUsage(T.DynamicDrawUsage)\n this.geometry.setAttribute('position', p)\n this.geometry.setAttribute('normal', n)\n if (!this.mesh) {\n this.mesh = new T.Mesh(this.geometry)\n this.mesh.name = 'fluid_liquid'\n this.mesh.frustumCulled = false\n this.mesh.renderOrder = 3\n this.group.add(this.mesh)\n } else this.mesh.geometry = this.geometry\n }\n\n update(dt: number, world: FluidWorld, materials: MaterialCache, quality: QualityProfile, particles: ParticlePool): void {\n const state = world.container(this.containerId)\n const def = state?.liquid ? world.liquids.get(state.liquid) : undefined\n if (!state || !state.shape || !def || state.liters <= 1e-6) {\n if (this.mesh) this.mesh.visible = false\n this.vertices = 0\n return\n }\n this.build(state, quality)\n if (!this.mesh || !this.solid) return\n this.mesh.material = materials.liquidBody(def)\n\n // The surface plane in the group's space.\n this.object.updateWorldMatrix(true, false)\n this.group.updateWorldMatrix(true, false)\n this.inverse.copy(this.group.matrixWorld).invert()\n this.tmpN.set(state.surfaceNormal[0], state.surfaceNormal[1], state.surfaceNormal[2]).transformDirection(this.inverse)\n this.tmpP.set(state.surfacePoint[0], state.surfacePoint[1], state.surfacePoint[2]).applyMatrix4(this.inverse)\n const u: V3 = [this.tmpN.x, this.tmpN.y, this.tmpN.z]\n const d = u[0] * this.tmpP.x + u[1] * this.tmpP.y + u[2] * this.tmpP.z\n\n this.vertices = clipSolid(this.solid, u, d, this.pos, this.nor)\n const geometry = this.geometry as THREE_NS.BufferGeometry\n geometry.setDrawRange(0, this.vertices)\n ;(geometry.getAttribute('position') as THREE_NS.BufferAttribute).needsUpdate = true\n ;(geometry.getAttribute('normal') as THREE_NS.BufferAttribute).needsUpdate = true\n this.mesh.visible = this.vertices > 0\n\n // Steam above a hot open surface.\n if (state.steaming && this.vertices > 0) {\n this.steamAcc += dt * quality.steamRate\n while (this.steamAcc >= 1) {\n this.steamAcc -= 1\n const o = this.tmpP.set(state.surfacePoint[0], state.surfacePoint[1], state.surfacePoint[2])\n particles.steam([o.x, o.y + 0.01, o.z])\n }\n } else this.steamAcc = 0\n }\n\n get triangles(): number {\n return this.visible ? Math.floor(this.vertices / 3) : 0\n }\n\n dispose(): void {\n this.object.remove(this.group)\n this.geometry?.dispose()\n this.geometry = null\n this.mesh = null\n }\n}\n","export const clamp = (v: number, lo: number, hi: number): number => (v < lo ? lo : v > hi ? hi : v)\nexport const lerp = (a: number, b: number, t: number): number => a + (b - a) * t\n\n/** Small seeded generator for cosmetic randomness (droplet directions): the same input gives the same droplets. */\nexport class Rng {\n private state: number\n constructor(seed: number) {\n this.state = (seed >>> 0) || 1\n }\n next(): number {\n this.state = (this.state + 0x6d2b79f5) >>> 0\n let t = this.state\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** Integer hash of a point, to seed cosmetic randomness from world state. */\nexport const hashPoint = (x: number, y: number, z: number): number => {\n let h = 2166136261\n for (const v of [x, y, z]) h = Math.imul(h ^ Math.round(v * 1000), 16777619)\n return h >>> 0\n}\n","import type * as THREE_NS from 'three'\nimport type { LiquidDef } from '@adatechnology/game-fluids'\nimport { clamp } from './util'\nimport type { ThreeLib } from './types'\n\n/** Colour of a stain: the liquid's `stainColor`, else a darker `color`. */\nexport const stainColorOf = (def: LiquidDef): number => {\n if (def.stainColor !== undefined) return def.stainColor\n const r = ((def.color >> 16) & 255) * 0.65\n const g = ((def.color >> 8) & 255) * 0.65\n const b = (def.color & 255) * 0.65\n return (Math.round(r) << 16) | (Math.round(g) << 8) | Math.round(b)\n}\n\n/**\n * One material per liquid and role, created on demand and shared by every mesh: each liquid is its own material (colour, opacity, gloss).\n * Wet surfaces use a low roughness from `gloss` so they reflect the scene's environment.\n */\nexport class MaterialCache {\n private body = new Map<string, THREE_NS.MeshStandardMaterial>()\n private stream = new Map<string, THREE_NS.MeshStandardMaterial>()\n private film = new Map<string, THREE_NS.MeshStandardMaterial>()\n private wet = new Map<string, THREE_NS.MeshStandardMaterial>()\n\n constructor(\n private readonly THREE: ThreeLib,\n private readonly envMap: THREE_NS.Texture | null,\n ) {}\n\n private make(params: THREE_NS.MeshStandardMaterialParameters): THREE_NS.MeshStandardMaterial {\n const m = new this.THREE.MeshStandardMaterial({ metalness: 0, ...params })\n if (this.envMap) m.envMap = this.envMap\n return m\n }\n\n /** The volume of liquid inside a container. */\n liquidBody(def: LiquidDef): THREE_NS.MeshStandardMaterial {\n let m = this.body.get(def.id)\n if (!m) {\n m = this.make({\n color: def.color,\n opacity: def.opacity,\n transparent: def.opacity < 0.999,\n roughness: clamp(1 - def.gloss * 0.9, 0.04, 1),\n envMapIntensity: 0.5 + def.gloss * 0.9,\n depthWrite: def.opacity >= 0.999,\n })\n this.body.set(def.id, m)\n }\n return m\n }\n\n /** A jet or a drop in the air. */\n liquidStream(def: LiquidDef): THREE_NS.MeshStandardMaterial {\n let m = this.stream.get(def.id)\n if (!m) {\n m = this.make({\n color: def.color,\n opacity: clamp(def.opacity + 0.1, 0.35, 1),\n transparent: true,\n roughness: clamp(1 - def.gloss * 0.95, 0.03, 1),\n envMapIntensity: 0.8 + def.gloss,\n side: this.THREE.DoubleSide,\n depthWrite: false,\n })\n this.stream.set(def.id, m)\n }\n return m\n }\n\n /** The thin outer film of a stain (and the permanent mark): tinted by vertex colour, soft rim by vertex alpha, mostly matte. */\n stainFilm(def: LiquidDef): THREE_NS.MeshStandardMaterial {\n let m = this.film.get(def.id)\n if (!m) {\n m = this.make({\n color: 0xffffff,\n vertexColors: true,\n transparent: true,\n roughness: clamp(0.95 - def.gloss * 0.45, 0.3, 1),\n envMapIntensity: 0.4 + def.gloss * 0.4,\n depthWrite: false,\n polygonOffset: true,\n polygonOffsetFactor: -2,\n polygonOffsetUnits: -2,\n })\n this.film.set(def.id, m)\n }\n return m\n }\n\n /** The glossy wet part of a stain, which shrinks while it dries. */\n stainWet(def: LiquidDef): THREE_NS.MeshStandardMaterial {\n let m = this.wet.get(def.id)\n if (!m) {\n m = this.make({\n color: 0xffffff,\n vertexColors: true,\n transparent: true,\n roughness: clamp(1 - def.gloss, 0.02, 0.7),\n envMapIntensity: 0.9 + def.gloss * 1.4,\n depthWrite: false,\n polygonOffset: true,\n polygonOffsetFactor: -3,\n polygonOffsetUnits: -3,\n })\n this.wet.set(def.id, m)\n }\n return m\n }\n\n dispose(): void {\n for (const map of [this.body, this.stream, this.film, this.wet]) {\n for (const m of map.values()) m.dispose()\n map.clear()\n }\n }\n}\n","import type * as THREE_NS from 'three'\nimport { Rng, clamp, hashPoint } from './util'\nimport type { ThreeLib } from './types'\n\nconst VERTEX = /* glsl */ `\nattribute float aSize;\nattribute vec4 aColor;\nattribute float aSoft;\nuniform float uScale;\nvarying vec4 vColor;\nvarying float vSoft;\nvoid main() {\n vColor = aColor;\n vSoft = aSoft;\n vec4 mv = modelViewMatrix * vec4(position, 1.0);\n gl_PointSize = aSize * uScale / max(0.1, -mv.z);\n gl_Position = projectionMatrix * mv;\n}\n`\n\n// Round sprite drawn in the fragment shader: no textures.\nconst FRAGMENT = /* glsl */ `\nvarying vec4 vColor;\nvarying float vSoft;\nvoid main() {\n float d = length(gl_PointCoord - vec2(0.5)) * 2.0;\n if (d > 1.0 || vColor.a <= 0.001) discard;\n float edge = mix(smoothstep(1.0, 0.8, d), 1.0 - d, vSoft);\n gl_FragColor = vec4(vColor.rgb, vColor.a * edge);\n}\n`\n\n/**\n * A fixed pool of round point sprites: splash droplets (ballistic, they die on the floor they hit) and steam (soft, rising puffs).\n * One draw call. When the pool is full the oldest slot is reused.\n */\nexport class ParticlePool {\n readonly points: THREE_NS.Points\n private readonly geometry: THREE_NS.BufferGeometry\n private readonly material: THREE_NS.ShaderMaterial\n private readonly capacity: number\n private next = 0\n private readonly pos: Float32Array\n private readonly size: Float32Array\n private readonly color: Float32Array\n private readonly soft: Float32Array\n private readonly vel: Float32Array\n private readonly life: Float32Array\n private readonly maxLife: Float32Array\n private readonly size0: Float32Array\n private readonly size1: Float32Array\n private readonly alpha: Float32Array\n private readonly floorY: Float32Array\n private readonly kind: Uint8Array\n private readonly rgb: Float32Array\n private readonly rng = new Rng(1234567)\n private alive = 0\n\n constructor(\n private readonly THREE: ThreeLib,\n capacity: number,\n pointScale: number,\n ) {\n this.capacity = capacity\n this.pos = new Float32Array(capacity * 3)\n this.size = new Float32Array(capacity)\n this.color = new Float32Array(capacity * 4)\n this.soft = new Float32Array(capacity)\n this.vel = new Float32Array(capacity * 3)\n this.life = new Float32Array(capacity)\n this.maxLife = new Float32Array(capacity)\n this.size0 = new Float32Array(capacity)\n this.size1 = new Float32Array(capacity)\n this.alpha = new Float32Array(capacity)\n this.floorY = new Float32Array(capacity)\n this.kind = new Uint8Array(capacity)\n this.rgb = new Float32Array(capacity * 3)\n this.life.fill(0)\n const T = THREE\n this.geometry = new T.BufferGeometry()\n const attr = (array: Float32Array, n: number) => {\n const a = new T.BufferAttribute(array, n)\n a.setUsage(T.DynamicDrawUsage)\n return a\n }\n this.geometry.setAttribute('position', attr(this.pos, 3))\n this.geometry.setAttribute('aSize', attr(this.size, 1))\n this.geometry.setAttribute('aColor', attr(this.color, 4))\n this.geometry.setAttribute('aSoft', attr(this.soft, 1))\n this.material = new T.ShaderMaterial({\n vertexShader: VERTEX,\n fragmentShader: FRAGMENT,\n uniforms: { uScale: { value: pointScale } },\n transparent: true,\n depthWrite: false,\n })\n this.points = new T.Points(this.geometry, this.material)\n this.points.frustumCulled = false\n this.points.renderOrder = 4\n this.points.name = 'fluid_particles'\n }\n\n get count(): number {\n return this.alive\n }\n\n private slot(): number {\n const i = this.next\n this.next = (this.next + 1) % this.capacity\n return i\n }\n\n private setColor(i: number, hex: number): void {\n this.rgb[i * 3] = ((hex >> 16) & 255) / 255\n this.rgb[i * 3 + 1] = ((hex >> 8) & 255) / 255\n this.rgb[i * 3 + 2] = (hex & 255) / 255\n }\n\n /** Droplets thrown up by an impact; `floorY` is the height they stop at. */\n splash(point: [number, number, number], intensity: number, hex: number, opacity: number, count: number): void {\n const rng = new Rng(hashPoint(point[0], point[1], point[2]) ^ this.next)\n const n = Math.max(2, Math.round(count * (0.35 + 0.65 * clamp(intensity, 0, 1))))\n for (let k = 0; k < n; k++) {\n const i = this.slot()\n const a = rng.next() * Math.PI * 2\n const h = (0.25 + rng.next() * 0.9) * (0.4 + intensity)\n const up = (0.7 + rng.next() * 1.5) * (0.5 + intensity)\n this.pos.set([point[0], point[1] + 0.01, point[2]], i * 3)\n this.vel.set([Math.cos(a) * h, up, Math.sin(a) * h], i * 3)\n this.life[i] = this.maxLife[i] = 0.45 + rng.next() * 0.45\n this.size0[i] = 0.012 + rng.next() * 0.014\n this.size1[i] = this.size0[i] * 0.7\n this.alpha[i] = clamp(opacity + 0.2, 0.35, 1)\n this.soft[i] = 0\n this.kind[i] = 0\n this.floorY[i] = point[1]\n this.setColor(i, hex)\n }\n }\n\n /** One puff of steam rising from `point`. */\n steam(point: [number, number, number]): void {\n const i = this.slot()\n const r = this.rng\n this.pos.set([point[0] + (r.next() - 0.5) * 0.04, point[1], point[2] + (r.next() - 0.5) * 0.04], i * 3)\n this.vel.set([(r.next() - 0.5) * 0.06, 0.22 + r.next() * 0.12, (r.next() - 0.5) * 0.06], i * 3)\n this.life[i] = this.maxLife[i] = 1.2 + r.next() * 0.6\n this.size0[i] = 0.03\n this.size1[i] = 0.1\n this.alpha[i] = 0.24\n this.soft[i] = 1\n this.kind[i] = 1\n this.floorY[i] = -1e9\n this.setColor(i, 0xf4f8ff)\n }\n\n update(dt: number, gravity: number): void {\n let alive = 0\n for (let i = 0; i < this.capacity; i++) {\n if (this.life[i] <= 0) {\n this.size[i] = 0\n this.color[i * 4 + 3] = 0\n continue\n }\n this.life[i] -= dt\n const k = 1 - this.life[i] / this.maxLife[i]\n if (this.life[i] <= 0) {\n this.size[i] = 0\n this.color[i * 4 + 3] = 0\n continue\n }\n alive++\n if (this.kind[i] === 0) {\n this.vel[i * 3 + 1] -= gravity * dt\n } else {\n // Steam drifts sideways a little while rising.\n this.vel[i * 3] += Math.sin((k + i) * 7) * 0.02 * dt\n }\n this.pos[i * 3] += this.vel[i * 3] * dt\n this.pos[i * 3 + 1] += this.vel[i * 3 + 1] * dt\n this.pos[i * 3 + 2] += this.vel[i * 3 + 2] * dt\n if (this.kind[i] === 0 && this.pos[i * 3 + 1] < this.floorY[i]) {\n this.life[i] = 0\n alive--\n this.size[i] = 0\n this.color[i * 4 + 3] = 0\n continue\n }\n this.size[i] = this.size0[i] + (this.size1[i] - this.size0[i]) * k\n const fade = this.kind[i] === 1 ? Math.min(1, k * 4) * (1 - k) : 1 - k * k\n this.color[i * 4] = this.rgb[i * 3]\n this.color[i * 4 + 1] = this.rgb[i * 3 + 1]\n this.color[i * 4 + 2] = this.rgb[i * 3 + 2]\n this.color[i * 4 + 3] = this.alpha[i] * fade\n }\n this.alive = alive\n for (const name of ['position', 'aSize', 'aColor', 'aSoft']) (this.geometry.getAttribute(name) as THREE_NS.BufferAttribute).needsUpdate = true\n }\n\n clear(): void {\n this.life.fill(0)\n this.alive = 0\n this.update(0, 0)\n }\n\n dispose(): void {\n this.geometry.dispose()\n this.material.dispose()\n }\n}\n","import type { FluidQuality } from './types'\n\nexport interface QualityProfile {\n /** Radial segments of the container liquid volume. */\n bodySegments: number\n /** Samples along a stream and sides of its tube. */\n streamSamples: number\n streamSides: number\n /** Drops of a thin stream. */\n thinDrops: number\n /** Subdivisions per front sample of a stain outline (16 samples). */\n stainSubdiv: number\n maxStains: number\n maxStreams: number\n maxParticles: number\n /** Steam puffs per second of a steaming container. */\n steamRate: number\n /** Droplets of a full-intensity splash. */\n splashDroplets: number\n}\n\nexport const PROFILES: Record<FluidQuality, QualityProfile> = {\n low: { bodySegments: 10, streamSamples: 8, streamSides: 4, thinDrops: 4, stainSubdiv: 1, maxStains: 24, maxStreams: 12, maxParticles: 96, steamRate: 4, splashDroplets: 5 },\n medium: { bodySegments: 14, streamSamples: 12, streamSides: 5, thinDrops: 6, stainSubdiv: 2, maxStains: 48, maxStreams: 24, maxParticles: 256, steamRate: 8, splashDroplets: 9 },\n high: { bodySegments: 20, streamSamples: 20, streamSides: 8, thinDrops: 8, stainSubdiv: 4, maxStains: 96, maxStreams: 48, maxParticles: 512, steamRate: 14, splashDroplets: 14 },\n}\n\nexport const profileOf = (q: FluidQuality | undefined): QualityProfile => PROFILES[q ?? 'medium'] ?? PROFILES.medium\n","import type * as THREE_NS from 'three'\nimport { STAIN_SAMPLES } from '@adatechnology/game-fluids'\nimport type { LiquidDef, StainState, Vec3 } from '@adatechnology/game-fluids'\nimport type { MaterialCache } from './materials'\nimport { stainColorOf } from './materials'\nimport type { QualityProfile } from './quality'\nimport { clamp } from './util'\nimport type { ThreeLib } from './types'\n\n/** Periodic Catmull-Rom of the 16 front radii: a smooth outline with `subdiv` points per sample. */\nexport const smoothOutline = (front: number[], subdiv: number, out?: number[]): number[] => {\n const n = front.length\n const res = out ?? []\n res.length = n * subdiv\n for (let i = 0; i < n; i++) {\n const p0 = front[(i + n - 1) % n]\n const p1 = front[i]\n const p2 = front[(i + 1) % n]\n const p3 = front[(i + 2) % n]\n for (let j = 0; j < subdiv; j++) {\n const t = j / subdiv\n const r = 0.5 * (2 * p1 + (-p0 + p2) * t + (2 * p0 - 5 * p1 + 4 * p2 - p3) * t * t + (-p0 + 3 * p1 - 3 * p2 + p3) * t * t * t)\n res[i * subdiv + j] = Math.max(0.004, r)\n }\n }\n return res\n}\n\ninterface Fan {\n mesh: THREE_NS.Mesh\n position: Float32Array\n color: Float32Array\n}\n\n/**\n * One stain: an outer film (the whole flow-front polygon, soft at the rim) and an inner glossy fan at `wetRadius` that recedes while it dries.\n * Both are triangle fans with preallocated buffers, lying on the surface plane a hair above it.\n */\nexport class StainVisual {\n readonly group: THREE_NS.Group\n private readonly outer: Fan\n private readonly inner: Fan\n private readonly ring: number\n private readonly radii: number[] = []\n private readonly tint: THREE_NS.Color\n stainId = ''\n signature = Number.NaN\n triangles = 0\n\n constructor(\n private readonly THREE: ThreeLib,\n profile: QualityProfile,\n readonly slot: number,\n ) {\n this.ring = STAIN_SAMPLES * profile.stainSubdiv\n this.group = new THREE.Group()\n this.group.name = 'fluid_stain'\n this.tint = new THREE.Color()\n this.outer = this.makeFan('fluid_stain_film', 1)\n this.inner = this.makeFan('fluid_stain_wet', 2)\n this.group.add(this.outer.mesh, this.inner.mesh)\n this.group.visible = false\n }\n\n private makeFan(name: string, order: number): Fan {\n const T = this.THREE\n const count = 1 + this.ring\n const position = new Float32Array(count * 3)\n const color = new Float32Array(count * 4)\n const normal = new Float32Array(count * 3)\n const geometry = new T.BufferGeometry()\n const p = new T.BufferAttribute(position, 3)\n const c = new T.BufferAttribute(color, 4)\n p.setUsage(T.DynamicDrawUsage)\n c.setUsage(T.DynamicDrawUsage)\n geometry.setAttribute('position', p)\n geometry.setAttribute('normal', new T.BufferAttribute(normal, 3))\n geometry.setAttribute('color', c)\n const index: number[] = []\n for (let i = 0; i < this.ring; i++) index.push(0, 1 + i, 1 + ((i + 1) % this.ring))\n geometry.setIndex(index)\n const mesh = new T.Mesh(geometry)\n mesh.name = name\n mesh.frustumCulled = false\n mesh.renderOrder = order\n return { mesh, position, color }\n }\n\n assign(def: LiquidDef, materials: MaterialCache): void {\n this.outer.mesh.material = materials.stainFilm(def)\n this.inner.mesh.material = materials.stainWet(def)\n }\n\n hide(): void {\n this.group.visible = false\n this.stainId = ''\n this.signature = Number.NaN\n this.triangles = 0\n }\n\n /** Rebuild the vertices from the stain state (skipped when nothing changed). */\n update(stain: StainState, def: LiquidDef, profile: QualityProfile): void {\n const sig =\n stain.center[0] * 3 +\n stain.center[1] * 5 +\n stain.center[2] * 7 +\n stain.front.reduce((s, v, i) => s + v * (i + 1), 0) * 11 +\n stain.wetness * 13 +\n stain.wetRadius * 17 +\n (stain.soaked / (stain.soaked + stain.liters + 1e-6)) * 19\n if (sig === this.signature && this.group.visible) return\n this.signature = sig\n\n const n: Vec3 = stain.normal ?? [0, 1, 0]\n const t1: Vec3 = stain.tangent ?? [1, 0, 0]\n const t2: Vec3 = [n[1] * t1[2] - n[2] * t1[1], n[2] * t1[0] - n[0] * t1[2], n[0] * t1[1] - n[1] * t1[0]]\n smoothOutline(stain.front, profile.stainSubdiv, this.radii)\n const ring = this.ring\n const lift = 0.0015 + 0.0004 * (this.slot % 6)\n const mean = stain.front.reduce((s, v) => s + v, 0) / stain.front.length\n const wet = clamp(stain.wetness, 0, 1)\n const soakRatio = stain.soaked / (stain.soaked + stain.liters + 1e-6)\n\n // Outer film: tinted by the liquid, darker while wet and where it soaked in, fainter once only the mark is left.\n this.tint.setHex(stainColorOf(def))\n const dark = 1 - 0.3 * wet - 0.2 * soakRatio\n const markAlpha = def.leavesMark ? 0.34 : 0.1\n const aMid = (markAlpha + (0.62 - markAlpha) * wet) * (0.75 + 0.25 * Math.min(1, stain.liters * 20 + soakRatio))\n this.writeFan(this.outer, stain.center, n, t1, t2, lift, 1, this.tint.r * dark, this.tint.g * dark, this.tint.b * dark, aMid, aMid * 0.45)\n this.outer.mesh.visible = true\n\n // Inner glossy wet fan, centred where the liquid came in, shrinking as it dries.\n const wr = clamp(stain.wetRadius, 0, 1)\n const showInner = wr > 0.05 && wet > 0.03\n this.inner.mesh.visible = showInner\n if (showInner) {\n this.tint.setHex(def.color)\n const shift = stain.flow ? -mean * 0.1 * (1 - wr) : 0\n const centre: Vec3 = stain.flow\n ? [stain.center[0] + stain.flow[0] * shift, stain.center[1] + stain.flow[1] * shift, stain.center[2] + stain.flow[2] * shift]\n : stain.center\n const a = clamp(def.opacity, 0.2, 0.85) * wet * 0.8\n this.writeFan(this.inner, centre, n, t1, t2, lift + 0.0007, 0.9 * wr, this.tint.r, this.tint.g, this.tint.b, a, a * 0.5)\n }\n this.triangles = ring * (showInner ? 2 : 1)\n this.group.visible = true\n }\n\n private writeFan(\n fan: Fan,\n center: Vec3,\n n: Vec3,\n t1: Vec3,\n t2: Vec3,\n lift: number,\n scale: number,\n r: number,\n g: number,\n b: number,\n aCentre: number,\n aRim: number,\n ): void {\n const ring = this.ring\n const px = center[0] + n[0] * lift\n const py = center[1] + n[1] * lift\n const pz = center[2] + n[2] * lift\n fan.position[0] = px\n fan.position[1] = py\n fan.position[2] = pz\n fan.color[0] = r * 0.85\n fan.color[1] = g * 0.85\n fan.color[2] = b * 0.85\n fan.color[3] = aCentre\n const normalAttr = fan.mesh.geometry.getAttribute('normal') as THREE_NS.BufferAttribute\n for (let i = 0; i <= ring; i++) {\n normalAttr.setXYZ(i, n[0], n[1], n[2])\n }\n normalAttr.needsUpdate = true\n for (let i = 0; i < ring; i++) {\n const a = (i / ring) * Math.PI * 2\n const c = Math.cos(a) * this.radii[i] * scale\n const s = Math.sin(a) * this.radii[i] * scale\n const o = (1 + i) * 3\n fan.position[o] = px + t1[0] * c + t2[0] * s\n fan.position[o + 1] = py + t1[1] * c + t2[1] * s\n fan.position[o + 2] = pz + t1[2] * c + t2[2] * s\n const k = (1 + i) * 4\n fan.color[k] = r\n fan.color[k + 1] = g\n fan.color[k + 2] = b\n fan.color[k + 3] = aRim\n }\n const geometry = fan.mesh.geometry\n ;(geometry.getAttribute('position') as THREE_NS.BufferAttribute).needsUpdate = true\n ;(geometry.getAttribute('color') as THREE_NS.BufferAttribute).needsUpdate = true\n }\n\n dispose(): void {\n for (const fan of [this.outer, this.inner]) fan.mesh.geometry.dispose()\n }\n}\n","import type * as THREE_NS from 'three'\nimport { sampleStream } from '@adatechnology/game-fluids'\nimport type { StreamState } from '@adatechnology/game-fluids'\nimport type { QualityProfile } from './quality'\nimport { clamp } from './util'\nimport type { ThreeLib } from './types'\n\n/** Seconds a stream takes to break up into drops after the world ended it. */\nconst GHOST_TIME = 0.4\n\n/**\n * One stream: a thread along the ballistic path (a tube updated in place) with a growing drop at its leading tip, a trailing drop while it ends,\n * and for thin streams only a sequence of falling drops. The jet narrows as it accelerates.\n */\nexport class StreamVisual {\n readonly tube: THREE_NS.Mesh\n readonly drops: THREE_NS.InstancedMesh\n private readonly positions: Float32Array\n private readonly normals: Float32Array\n private readonly samples: number\n private readonly sides: number\n private readonly matrix: THREE_NS.Matrix4\n private readonly maxDrops: number\n id = ''\n age = 0\n ghostAge = -1\n /** Last known state, kept while the stream breaks into drops. */\n state: StreamState | null = null\n triangles = 0\n\n constructor(\n private readonly THREE: ThreeLib,\n profile: QualityProfile,\n dropGeometry: THREE_NS.SphereGeometry,\n ) {\n const T = THREE\n this.samples = profile.streamSamples\n this.sides = profile.streamSides\n this.maxDrops = Math.max(profile.thinDrops, 2) + 2\n this.positions = new Float32Array(this.samples * this.sides * 3)\n this.normals = new Float32Array(this.samples * this.sides * 3)\n const geometry = new T.BufferGeometry()\n const p = new T.BufferAttribute(this.positions, 3)\n const n = new T.BufferAttribute(this.normals, 3)\n p.setUsage(T.DynamicDrawUsage)\n n.setUsage(T.DynamicDrawUsage)\n geometry.setAttribute('position', p)\n geometry.setAttribute('normal', n)\n const index: number[] = []\n for (let i = 0; i < this.samples - 1; i++) {\n for (let j = 0; j < this.sides; j++) {\n const a = i * this.sides + j\n const b = i * this.sides + ((j + 1) % this.sides)\n const c = (i + 1) * this.sides + j\n const d = (i + 1) * this.sides + ((j + 1) % this.sides)\n index.push(a, c, b, b, c, d)\n }\n }\n geometry.setIndex(index)\n this.tube = new T.Mesh(geometry)\n this.tube.name = 'fluid_stream'\n this.tube.frustumCulled = false\n this.tube.renderOrder = 2\n this.drops = new T.InstancedMesh(dropGeometry, undefined as unknown as THREE_NS.Material, this.maxDrops)\n this.drops.name = 'fluid_stream_drops'\n this.drops.frustumCulled = false\n this.drops.renderOrder = 2\n this.drops.instanceMatrix.setUsage(T.DynamicDrawUsage)\n this.drops.count = 0\n this.matrix = new T.Matrix4()\n }\n\n setMaterial(material: THREE_NS.Material): void {\n this.tube.material = material\n this.drops.material = material\n }\n\n hide(): void {\n this.tube.visible = false\n this.drops.visible = false\n this.drops.count = 0\n this.triangles = 0\n }\n\n private dropAt(slot: number, x: number, y: number, z: number, radius: number): void {\n this.matrix.makeScale(radius, radius, radius).setPosition(x, y, z)\n this.drops.setMatrixAt(slot, this.matrix)\n }\n\n /**\n * Draw the stream. `state` is the world's stream while it lives, or the last known one while ghost (`ghostAge >= 0`).\n */\n update(state: StreamState, gravity: number, dt: number, profile: QualityProfile, time: number): void {\n this.state = state\n this.age += dt\n if (this.ghostAge >= 0) this.ghostAge += dt\n\n const flight = Math.max(0.02, state.flightTime ?? 1)\n const [vx, vy, vz] = state.velocity\n const speed0 = Math.max(0.3, Math.hypot(vx, vy, vz))\n const q = Math.max(state.rate, 0) / 1000\n const r0 = clamp(Math.sqrt(q / (Math.PI * speed0)), 0.0015, 0.03)\n\n const tB = Math.min(flight, this.age)\n // The tail leaves the origin at free fall once the world stopped the stream.\n const tA = this.ghostAge >= 0 ? Math.min(flight, this.ghostAge) : 0\n\n let drops = 0\n const thin = state.thin && this.ghostAge < 0\n\n if (thin) {\n this.tube.visible = false\n this.triangles = 0\n const n = profile.thinDrops\n const phase = time * 1.3\n for (let k = 0; k < n && drops < this.maxDrops; k++) {\n const tau = ((phase + k / n) % 1) * flight\n if (tau > tB) continue\n const p = sampleStream(state, gravity, tau)\n const grow = Math.min(1, tau / (0.12 * flight + 0.02))\n this.dropAt(drops++, p[0], p[1], p[2], Math.max(0.002, r0 * 1.8) * (0.4 + 0.6 * grow))\n }\n } else if (tB - tA > 0.015) {\n this.writeTube(state, gravity, tA, tB, r0, speed0)\n this.tube.visible = true\n this.triangles = (this.samples - 1) * this.sides * 2\n // Leading drop that grows and detaches while the jet is still advancing; trailing drop while it ends.\n if (tB < flight) {\n const p = sampleStream(state, gravity, tB)\n const w = this.radiusAt(state, gravity, tB, r0, speed0)\n this.dropAt(drops++, p[0], p[1], p[2], w * 1.35)\n }\n if (this.ghostAge >= 0) {\n const p = sampleStream(state, gravity, tA)\n const w = this.radiusAt(state, gravity, tA, r0, speed0)\n this.dropAt(drops++, p[0], p[1], p[2], w * 1.4 * (1 - this.ghostAge / GHOST_TIME * 0.4))\n }\n } else {\n this.tube.visible = false\n this.triangles = 0\n if (tA < flight) {\n // Only the drop is left.\n const p = sampleStream(state, gravity, this.ghostAge >= 0 ? tA : tB)\n this.dropAt(drops++, p[0], p[1], p[2], Math.max(0.003, r0 * 1.3))\n }\n }\n\n this.drops.count = drops\n this.drops.visible = drops > 0\n this.drops.instanceMatrix.needsUpdate = true\n this.triangles += drops * 24\n }\n\n /** The ghost is over once its tail reached the landing. */\n get finished(): boolean {\n return this.ghostAge >= 0 && (this.ghostAge >= GHOST_TIME || this.ghostAge >= (this.state?.flightTime ?? 0))\n }\n\n private radiusAt(state: StreamState, gravity: number, t: number, r0: number, speed0: number): number {\n const vy = state.velocity[1] - gravity * t\n const speed = Math.max(0.3, Math.hypot(state.velocity[0], vy, state.velocity[2]))\n const fade = this.ghostAge >= 0 ? clamp(1 - this.ghostAge / GHOST_TIME, 0.15, 1) : 1\n return r0 * Math.sqrt(speed0 / speed) * fade\n }\n\n private writeTube(state: StreamState, gravity: number, tA: number, tB: number, r0: number, speed0: number): void {\n const n = this.samples\n const sides = this.sides\n for (let i = 0; i < n; i++) {\n const k = i / (n - 1)\n const t = tA + (tB - tA) * k\n const p = sampleStream(state, gravity, t)\n const vx = state.velocity[0]\n const vy = state.velocity[1] - gravity * t\n const vz = state.velocity[2]\n const l = Math.hypot(vx, vy, vz) || 1\n const tx = vx / l\n const ty = vy / l\n const tz = vz / l\n // Any vector not parallel to the tangent gives the first side axis.\n const ax = Math.abs(tz) < 0.9 ? 0 : 1\n const az = Math.abs(tz) < 0.9 ? 1 : 0\n let b1x = ty * az - tz * 0\n let b1y = tz * ax - tx * az\n let b1z = tx * 0 - ty * ax\n const bl = Math.hypot(b1x, b1y, b1z) || 1\n b1x /= bl\n b1y /= bl\n b1z /= bl\n const b2x = ty * b1z - tz * b1y\n const b2y = tz * b1x - tx * b1z\n const b2z = tx * b1y - ty * b1x\n // Rounded ends: the radius tapers to a bead at both ends.\n const end = Math.min(1, 0.35 + Math.min(k, 1 - k) * 8)\n const r = this.radiusAt(state, gravity, t, r0, speed0) * end\n for (let j = 0; j < sides; j++) {\n const a = (j / sides) * Math.PI * 2\n const c = Math.cos(a)\n const s = Math.sin(a)\n const nx = b1x * c + b2x * s\n const ny = b1y * c + b2y * s\n const nz = b1z * c + b2z * s\n const o = (i * sides + j) * 3\n this.positions[o] = p[0] + nx * r\n this.positions[o + 1] = p[1] + ny * r\n this.positions[o + 2] = p[2] + nz * r\n this.normals[o] = nx\n this.normals[o + 1] = ny\n this.normals[o + 2] = nz\n }\n }\n const g = this.tube.geometry\n ;(g.getAttribute('position') as THREE_NS.BufferAttribute).needsUpdate = true\n ;(g.getAttribute('normal') as THREE_NS.BufferAttribute).needsUpdate = true\n }\n\n start(id: string): void {\n this.id = id\n this.age = 0\n this.ghostAge = -1\n this.state = null\n }\n\n dispose(): void {\n this.tube.geometry.dispose()\n this.drops.dispose()\n }\n}\n","import type * as THREE_NS from 'three'\nimport type { FluidEvent, StainState, StreamState } from '@adatechnology/game-fluids'\nimport { LiquidBody } from './liquid-body'\nimport { MaterialCache } from './materials'\nimport { ParticlePool } from './particles'\nimport { profileOf } from './quality'\nimport { StainVisual } from './stains'\nimport { StreamVisual } from './streams'\nimport type { BindOptions, FluidQuality, FluidRenderer, FluidRendererOptions, FluidRendererStats, ThreeLib } from './types'\n\n/**\n * Draws a `FluidWorld` with three.js. It only reads the world state (plus `splash` events for droplets), so a LAN client that receives the\n * same world state draws the same liquids.\n */\nexport function createFluidRenderer(THREE: ThreeLib, options: FluidRendererOptions): FluidRenderer {\n const { scene, fluids } = options\n const quality: FluidQuality = options.quality ?? 'medium'\n const profile = profileOf(quality)\n const materials = new MaterialCache(THREE, options.envMap ?? null)\n const root = new THREE.Group()\n root.name = 'fluid_renderer'\n scene.add(root)\n const particles = new ParticlePool(THREE, profile.maxParticles, options.pointScale ?? 600)\n root.add(particles.points)\n const dropGeometry = new THREE.SphereGeometry(1, 8, 6)\n\n const bodies = new Map<string, LiquidBody>()\n const streamsActive = new Map<string, StreamVisual>()\n const streamsFree: StreamVisual[] = []\n let streamsCreated = 0\n const stainsActive = new Map<string, StainVisual>()\n const stainsFree: StainVisual[] = []\n let stainsCreated = 0\n let time = 0\n let disposed = false\n\n const offSplash = fluids.on('splash', (e: FluidEvent) => {\n if (e.type !== 'splash' || disposed) return\n const def = fluids.liquids.get(e.liquid)\n if (!def) return\n particles.splash(e.point, e.intensity, def.color, def.opacity, profile.splashDroplets)\n })\n\n // ---- streams ----\n\n const acquireStream = (id: string): StreamVisual | null => {\n let v = streamsFree.pop() ?? null\n if (!v) {\n if (streamsCreated >= profile.maxStreams) return null\n streamsCreated++\n v = new StreamVisual(THREE, profile, dropGeometry)\n root.add(v.tube, v.drops)\n }\n v.start(id)\n return v\n }\n\n const releaseStream = (v: StreamVisual): void => {\n v.hide()\n streamsActive.delete(v.id)\n streamsFree.push(v)\n }\n\n const syncStreams = (dt: number): void => {\n const live = fluids.streams()\n const seen = new Set<string>()\n // Biggest first, so the budget keeps the visible ones.\n live.sort((a: StreamState, b: StreamState) => b.rate - a.rate)\n for (const s of live) {\n seen.add(s.id)\n let v = streamsActive.get(s.id)\n if (!v) {\n const fresh = acquireStream(s.id)\n if (!fresh) continue\n v = fresh\n streamsActive.set(s.id, v)\n }\n const def = fluids.liquids.get(s.liquid)\n if (!def) continue\n v.ghostAge = -1\n v.setMaterial(materials.liquidStream(def))\n v.update(s, fluids.gravity, dt, profile, time)\n }\n for (const v of [...streamsActive.values()]) {\n if (seen.has(v.id)) continue\n // The world ended it: let it break into drops.\n if (v.ghostAge < 0) v.ghostAge = 0\n if (!v.state || v.finished) {\n releaseStream(v)\n continue\n }\n v.update(v.state, fluids.gravity, dt, profile, time)\n if (v.finished) releaseStream(v)\n }\n }\n\n // ---- stains ----\n\n const syncStains = (): void => {\n const all = fluids.stains()\n // Keep the newest stains when the budget is smaller than the world.\n const wanted = all.length > profile.maxStains ? [...all].sort((a: StainState, b: StainState) => (a.age ?? 0) - (b.age ?? 0)).slice(0, profile.maxStains) : all\n const ids = new Set(wanted.map((s: StainState) => s.id))\n for (const [id, v] of [...stainsActive]) {\n if (ids.has(id)) continue\n v.hide()\n stainsActive.delete(id)\n stainsFree.push(v)\n }\n for (const s of wanted) {\n const def = fluids.liquids.get(s.liquid)\n if (!def) continue\n let v = stainsActive.get(s.id)\n if (!v) {\n v = stainsFree.pop()\n if (!v) {\n if (stainsCreated >= profile.maxStains) continue\n v = new StainVisual(THREE, profile, stainsCreated++)\n root.add(v.group)\n }\n v.stainId = s.id\n v.signature = Number.NaN\n v.assign(def, materials)\n stainsActive.set(s.id, v)\n }\n v.update(s, def, profile)\n }\n }\n\n // ---- public ----\n\n const renderer: FluidRenderer = {\n bindContainer(containerId: string, object: THREE_NS.Object3D, opts: BindOptions = {}) {\n renderer.unbindContainer(containerId)\n bodies.set(containerId, new LiquidBody(THREE, containerId, object, opts.innerOffset ?? [0, 0, 0]))\n },\n\n unbindContainer(containerId: string) {\n const body = bodies.get(containerId)\n if (!body) return\n body.dispose()\n bodies.delete(containerId)\n },\n\n update(dt: number) {\n if (disposed) return\n time += dt\n for (const body of bodies.values()) body.update(dt, fluids, materials, profile, particles)\n syncStreams(dt)\n syncStains()\n particles.update(dt, fluids.gravity)\n },\n\n clear() {\n for (const v of [...streamsActive.values()]) releaseStream(v)\n for (const [id, v] of [...stainsActive]) {\n v.hide()\n stainsActive.delete(id)\n stainsFree.push(v)\n }\n particles.clear()\n },\n\n dispose() {\n if (disposed) return\n disposed = true\n offSplash()\n for (const body of bodies.values()) body.dispose()\n bodies.clear()\n for (const v of [...streamsActive.values(), ...streamsFree]) v.dispose()\n for (const v of [...stainsActive.values(), ...stainsFree]) v.dispose()\n streamsActive.clear()\n stainsActive.clear()\n streamsFree.length = 0\n stainsFree.length = 0\n particles.dispose()\n dropGeometry.dispose()\n materials.dispose()\n scene.remove(root)\n root.clear()\n },\n\n stats(): FluidRendererStats {\n let triangles = 0\n let containers = 0\n for (const body of bodies.values()) {\n triangles += body.triangles\n if (body.visible) containers++\n }\n for (const v of streamsActive.values()) triangles += v.triangles\n for (const v of stainsActive.values()) triangles += v.triangles\n return {\n quality,\n containers,\n streams: streamsActive.size,\n stains: stainsActive.size,\n particles: particles.count,\n triangles,\n budget: { stains: profile.maxStains, streams: profile.maxStreams, particles: profile.maxParticles },\n }\n },\n }\n\n return renderer\n}\n\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/renderer.ts","../src/clip.ts","../src/liquid-body.ts","../src/util.ts","../src/materials.ts","../src/quality.ts","../src/sprites.ts","../src/stains.ts","../src/streams.ts","../src/film/manager.ts","../src/film/grid.ts","../src/film/drops.ts","../src/film/shader.ts","../src/film/material.ts","../src/film/strips.ts","../src/film/bridge.ts"],"sourcesContent":["import type * as THREE_NS from 'three'\nimport type { FluidEvent, StainState, StreamState } from '@adatechnology/game-fluids'\nimport { createVfx } from '@adatechnology/game-vfx'\nimport { createVfxRenderer } from '@adatechnology/game-vfx-three'\nimport { LiquidBody } from './liquid-body'\nimport { MaterialCache } from './materials'\nimport { profileOf } from './quality'\nimport { FluidSprites } from './sprites'\nimport { StainVisual } from './stains'\nimport { StreamVisual } from './streams'\nimport type { BindOptions, FluidQuality, FluidRenderer, FluidRendererOptions, FluidRendererStats, ThreeLib } from './types'\n\nlet rendererCount = 0\n\n/**\n * Draws a `FluidWorld` with three.js. It only reads the world state (plus `splash` events for droplets), so a LAN client that receives the\n * same world state draws the same liquids.\n */\nexport function createFluidRenderer(THREE: ThreeLib, options: FluidRendererOptions): FluidRenderer {\n const { scene, fluids } = options\n const quality: FluidQuality = options.quality ?? 'medium'\n const profile = profileOf(quality)\n const materials = new MaterialCache(THREE, options.envMap ?? null)\n const root = new THREE.Group()\n root.name = 'fluid_renderer'\n scene.add(root)\n // The droplets and steam are sprites of the effects world: the host's shared one, or one made here and stepped in `update`.\n const vfx = options.vfx ?? createVfx({ profile: quality, gravity: fluids.gravity, sprites: { capacity: profile.maxParticles } })\n const ownVfx = options.vfx ? undefined : createVfxRenderer(THREE, { scene, camera: options.camera ?? new THREE.PerspectiveCamera(), vfx, pointScale: options.pointScale ?? 600 })\n const particles = new FluidSprites(vfx, `fluids-${++rendererCount}`)\n const dropGeometry = new THREE.SphereGeometry(1, 8, 6)\n\n const bodies = new Map<string, LiquidBody>()\n const streamsActive = new Map<string, StreamVisual>()\n const streamsFree: StreamVisual[] = []\n let streamsCreated = 0\n const stainsActive = new Map<string, StainVisual>()\n const stainsFree: StainVisual[] = []\n let stainsCreated = 0\n let time = 0\n let disposed = false\n\n const offSplash = fluids.on('splash', (e: FluidEvent) => {\n if (e.type !== 'splash' || disposed) return\n const def = fluids.liquids.get(e.liquid)\n if (!def) return\n particles.splash(e.point, e.intensity, def.color, def.opacity, profile.splashDroplets)\n })\n\n // ---- streams ----\n\n const acquireStream = (id: string): StreamVisual | null => {\n let v = streamsFree.pop() ?? null\n if (!v) {\n if (streamsCreated >= profile.maxStreams) return null\n streamsCreated++\n v = new StreamVisual(THREE, profile, dropGeometry)\n root.add(v.tube, v.drops)\n }\n v.start(id)\n return v\n }\n\n const releaseStream = (v: StreamVisual): void => {\n v.hide()\n streamsActive.delete(v.id)\n streamsFree.push(v)\n }\n\n const syncStreams = (dt: number): void => {\n const live = fluids.streams()\n const seen = new Set<string>()\n // Biggest first, so the budget keeps the visible ones.\n live.sort((a: StreamState, b: StreamState) => b.rate - a.rate)\n for (const s of live) {\n seen.add(s.id)\n let v = streamsActive.get(s.id)\n if (!v) {\n const fresh = acquireStream(s.id)\n if (!fresh) continue\n v = fresh\n streamsActive.set(s.id, v)\n }\n const def = fluids.liquids.get(s.liquid)\n if (!def) continue\n v.ghostAge = -1\n v.setMaterial(materials.liquidStream(def))\n v.update(s, fluids.gravity, dt, profile, time)\n }\n for (const v of [...streamsActive.values()]) {\n if (seen.has(v.id)) continue\n // The world ended it: let it break into drops.\n if (v.ghostAge < 0) v.ghostAge = 0\n if (!v.state || v.finished) {\n releaseStream(v)\n continue\n }\n v.update(v.state, fluids.gravity, dt, profile, time)\n if (v.finished) releaseStream(v)\n }\n }\n\n // ---- stains ----\n\n const syncStains = (): void => {\n const all = fluids.stains()\n // Keep the newest stains when the budget is smaller than the world.\n const wanted = all.length > profile.maxStains ? [...all].sort((a: StainState, b: StainState) => (a.age ?? 0) - (b.age ?? 0)).slice(0, profile.maxStains) : all\n const ids = new Set(wanted.map((s: StainState) => s.id))\n for (const [id, v] of [...stainsActive]) {\n if (ids.has(id)) continue\n v.hide()\n stainsActive.delete(id)\n stainsFree.push(v)\n }\n for (const s of wanted) {\n const def = fluids.liquids.get(s.liquid)\n if (!def) continue\n let v = stainsActive.get(s.id)\n if (!v) {\n v = stainsFree.pop()\n if (!v) {\n if (stainsCreated >= profile.maxStains) continue\n v = new StainVisual(THREE, profile, stainsCreated++)\n root.add(v.group)\n }\n v.stainId = s.id\n v.signature = Number.NaN\n v.assign(def, materials)\n stainsActive.set(s.id, v)\n }\n v.update(s, def, profile)\n }\n }\n\n // ---- public ----\n\n const renderer: FluidRenderer = {\n bindContainer(containerId: string, object: THREE_NS.Object3D, opts: BindOptions = {}) {\n renderer.unbindContainer(containerId)\n bodies.set(containerId, new LiquidBody(THREE, containerId, object, opts.innerOffset ?? [0, 0, 0]))\n },\n\n unbindContainer(containerId: string) {\n const body = bodies.get(containerId)\n if (!body) return\n body.dispose()\n bodies.delete(containerId)\n },\n\n update(dt: number) {\n if (disposed) return\n time += dt\n for (const body of bodies.values()) body.update(dt, fluids, materials, profile, particles)\n syncStreams(dt)\n syncStains()\n ownVfx?.update(dt)\n },\n\n clear() {\n for (const v of [...streamsActive.values()]) releaseStream(v)\n for (const [id, v] of [...stainsActive]) {\n v.hide()\n stainsActive.delete(id)\n stainsFree.push(v)\n }\n if (ownVfx) vfx.clear()\n else vfx.sprites().clear()\n },\n\n dispose() {\n if (disposed) return\n disposed = true\n offSplash()\n for (const body of bodies.values()) body.dispose()\n bodies.clear()\n for (const v of [...streamsActive.values(), ...streamsFree]) v.dispose()\n for (const v of [...stainsActive.values(), ...stainsFree]) v.dispose()\n streamsActive.clear()\n stainsActive.clear()\n streamsFree.length = 0\n stainsFree.length = 0\n ownVfx?.dispose()\n dropGeometry.dispose()\n materials.dispose()\n scene.remove(root)\n root.clear()\n },\n\n stats(): FluidRendererStats {\n let triangles = 0\n let containers = 0\n for (const body of bodies.values()) {\n triangles += body.triangles\n if (body.visible) containers++\n }\n for (const v of streamsActive.values()) triangles += v.triangles\n for (const v of stainsActive.values()) triangles += v.triangles\n return {\n quality,\n containers,\n streams: streamsActive.size,\n stains: stainsActive.size,\n particles: particles.count,\n triangles,\n budget: { stains: profile.maxStains, streams: profile.maxStreams, particles: profile.maxParticles },\n }\n },\n }\n\n return renderer\n}\n\n","/**\n * Convex solids (a cylinder or a box, in container space) clipped by the liquid surface plane `u · p <= d`.\n * This is robust for any tilt (upright, lying on its side, upside down): the result is exactly the part of the container the liquid fills,\n * with the surface cap lying on the plane. Written into preallocated buffers, no per-frame geometry is created.\n */\nexport type V3 = [number, number, number]\n\nexport interface SolidFace {\n p: V3[]\n n: V3[]\n}\n\nexport interface Solid {\n faces: SolidFace[]\n /** Upper bound of the vertices a clip can write (non-indexed triangles). */\n maxVertices: number\n}\n\nconst sub = (a: V3, b: V3): V3 => [a[0] - b[0], a[1] - b[1], a[2] - b[2]]\nconst cross = (a: V3, b: V3): V3 => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]\nconst dot = (a: V3, b: V3): number => a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\nconst norm = (a: V3): V3 => {\n const l = Math.hypot(a[0], a[1], a[2]) || 1\n return [a[0] / l, a[1] / l, a[2] / l]\n}\n\n/** Reverse the winding when the face does not look outward. */\nconst orient = (p: V3[], n: V3[], outward: V3): SolidFace => {\n if (dot(cross(sub(p[1], p[0]), sub(p[2], p[0])), outward) < 0) return { p: [...p].reverse(), n: [...n].reverse() }\n return { p, n }\n}\n\nconst finish = (faces: SolidFace[]): Solid => {\n let maxVertices = 0\n for (const f of faces) maxVertices += (f.p.length * 2 + 2) * 3\n // The surface cap: at most one point per face edge cut.\n maxVertices += faces.length * 3 * 2 + 64\n return { faces, maxVertices }\n}\n\nexport const cylinderSolid = (radius: number, height: number, segments: number): Solid => {\n const faces: SolidFace[] = []\n const ring = (y: number, i: number): V3 => {\n const a = (i / segments) * Math.PI * 2\n return [Math.cos(a) * radius, y, Math.sin(a) * radius]\n }\n const radial = (i: number): V3 => {\n const a = (i / segments) * Math.PI * 2\n return [Math.cos(a), 0, Math.sin(a)]\n }\n for (let i = 0; i < segments; i++) {\n const j = (i + 1) % segments\n const mid = norm([radial(i)[0] + radial(j)[0], 0, radial(i)[2] + radial(j)[2]])\n faces.push(orient([ring(0, i), ring(0, j), ring(height, j), ring(height, i)], [radial(i), radial(j), radial(j), radial(i)], mid))\n }\n const bottom: V3[] = []\n const top: V3[] = []\n for (let i = 0; i < segments; i++) {\n bottom.push(ring(0, i))\n top.push(ring(height, i))\n }\n faces.push(orient(bottom, bottom.map((): V3 => [0, -1, 0]), [0, -1, 0]))\n faces.push(orient(top, top.map((): V3 => [0, 1, 0]), [0, 1, 0]))\n return finish(faces)\n}\n\nexport const boxSolid = (size: V3): Solid => {\n const hx = size[0] / 2\n const hz = size[2] / 2\n const hy = size[1]\n const c = (x: number, y: number, z: number): V3 => [x * hx, y * hy, z * hz]\n const quad = (a: V3, b: V3, cc: V3, d: V3, n: V3): SolidFace => orient([a, b, cc, d], [n, n, n, n], n)\n return finish([\n quad(c(1, 0, -1), c(1, 1, -1), c(1, 1, 1), c(1, 0, 1), [1, 0, 0]),\n quad(c(-1, 0, -1), c(-1, 1, -1), c(-1, 1, 1), c(-1, 0, 1), [-1, 0, 0]),\n quad(c(-1, 1, -1), c(1, 1, -1), c(1, 1, 1), c(-1, 1, 1), [0, 1, 0]),\n quad(c(-1, 0, -1), c(1, 0, -1), c(1, 0, 1), c(-1, 0, 1), [0, -1, 0]),\n quad(c(-1, 0, 1), c(1, 0, 1), c(1, 1, 1), c(-1, 1, 1), [0, 0, 1]),\n quad(c(-1, 0, -1), c(1, 0, -1), c(1, 1, -1), c(-1, 1, -1), [0, 0, -1]),\n ])\n}\n\nconst polyP: number[] = []\nconst polyN: number[] = []\nconst cut: number[] = []\n\n/**\n * Writes the triangles of `solid ∩ { u · p <= d }` into `pos` / `nor` (non-indexed, 3 floats per vertex) and returns the vertex count.\n * The cap on the plane has normal `u`.\n */\nexport const clipSolid = (solid: Solid, u: V3, d: number, pos: Float32Array, nor: Float32Array): number => {\n let count = 0\n const capacity = Math.floor(pos.length / 3)\n cut.length = 0\n const put = (px: number, py: number, pz: number, nx: number, ny: number, nz: number): void => {\n if (count >= capacity) return\n pos[count * 3] = px\n pos[count * 3 + 1] = py\n pos[count * 3 + 2] = pz\n nor[count * 3] = nx\n nor[count * 3 + 1] = ny\n nor[count * 3 + 2] = nz\n count++\n }\n\n for (const face of solid.faces) {\n const m = face.p.length\n polyP.length = 0\n polyN.length = 0\n for (let i = 0; i < m; i++) {\n const a = face.p[i]\n const b = face.p[(i + 1) % m]\n const na = face.n[i]\n const nb = face.n[(i + 1) % m]\n const da = u[0] * a[0] + u[1] * a[1] + u[2] * a[2] - d\n const db = u[0] * b[0] + u[1] * b[1] + u[2] * b[2] - d\n const ina = da <= 0\n const inb = db <= 0\n if (ina) {\n polyP.push(a[0], a[1], a[2])\n polyN.push(na[0], na[1], na[2])\n if (da > -1e-7) cut.push(a[0], a[1], a[2])\n }\n if (ina !== inb) {\n const t = da / (da - db)\n const x = a[0] + (b[0] - a[0]) * t\n const y = a[1] + (b[1] - a[1]) * t\n const z = a[2] + (b[2] - a[2]) * t\n polyP.push(x, y, z)\n polyN.push(na[0] + (nb[0] - na[0]) * t, na[1] + (nb[1] - na[1]) * t, na[2] + (nb[2] - na[2]) * t)\n cut.push(x, y, z)\n }\n }\n const n = polyP.length / 3\n for (let i = 1; i < n - 1; i++) {\n for (const k of [0, i, i + 1]) put(polyP[k * 3], polyP[k * 3 + 1], polyP[k * 3 + 2], polyN[k * 3], polyN[k * 3 + 1], polyN[k * 3 + 2])\n }\n }\n\n // Cap on the plane: unique cut points sorted around their centre.\n const pts: V3[] = []\n for (let i = 0; i < cut.length; i += 3) {\n let dup = false\n for (const q of pts) {\n if (Math.abs(q[0] - cut[i]) + Math.abs(q[1] - cut[i + 1]) + Math.abs(q[2] - cut[i + 2]) < 1e-6) {\n dup = true\n break\n }\n }\n if (!dup) pts.push([cut[i], cut[i + 1], cut[i + 2]])\n }\n if (pts.length >= 3) {\n const c: V3 = [0, 0, 0]\n for (const q of pts) {\n c[0] += q[0] / pts.length\n c[1] += q[1] / pts.length\n c[2] += q[2] / pts.length\n }\n const e1 = norm(cross(u, Math.abs(u[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0]))\n const e2 = cross(u, e1)\n const keyed = pts.map((q) => ({ q, a: Math.atan2(dot(sub(q, c), e2), dot(sub(q, c), e1)) })).sort((p, r) => p.a - r.a)\n for (let i = 0; i < keyed.length; i++) {\n for (const q of [c, keyed[i].q, keyed[(i + 1) % keyed.length].q]) put(q[0], q[1], q[2], u[0], u[1], u[2])\n }\n }\n return count\n}\n","import type * as THREE_NS from 'three'\nimport type { ContainerState, FluidWorld, Vec3 } from '@adatechnology/game-fluids'\nimport { boxSolid, clipSolid, cylinderSolid } from './clip'\nimport type { Solid, V3 } from './clip'\nimport type { MaterialCache } from './materials'\nimport type { FluidSprites } from './sprites'\nimport type { QualityProfile } from './quality'\nimport type { ThreeLib } from './types'\n\n/** How far the liquid is kept inside the container walls so it does not fight with them. */\nconst INSET = 0.985\n\n/**\n * The liquid inside one bound container: the container's inner shape clipped by the world surface plane, expressed in the bound object's space,\n * so the cap always lies on the plane whatever the tilt. Plus steam puffs above a hot surface.\n */\nexport class LiquidBody {\n readonly group: THREE_NS.Group\n private mesh: THREE_NS.Mesh | null = null\n private geometry: THREE_NS.BufferGeometry | null = null\n private pos: Float32Array = new Float32Array(0)\n private nor: Float32Array = new Float32Array(0)\n private solid: Solid | null = null\n private shapeKey = ''\n private steamAcc = 0\n private readonly inverse: THREE_NS.Matrix4\n private readonly tmpN: THREE_NS.Vector3\n private readonly tmpP: THREE_NS.Vector3\n vertices = 0\n\n constructor(\n private readonly THREE: ThreeLib,\n readonly containerId: string,\n readonly object: THREE_NS.Object3D,\n offset: Vec3,\n ) {\n this.group = new THREE.Group()\n this.group.name = 'fluid_liquid_body'\n this.group.position.set(offset[0], offset[1], offset[2])\n this.inverse = new THREE.Matrix4()\n this.tmpN = new THREE.Vector3()\n this.tmpP = new THREE.Vector3()\n object.add(this.group)\n }\n\n get visible(): boolean {\n return !!this.mesh && this.mesh.visible\n }\n\n private build(state: ContainerState, quality: QualityProfile): void {\n const shape = state.shape\n if (!shape) return\n const key = JSON.stringify(shape) + quality.bodySegments\n if (key === this.shapeKey) return\n this.shapeKey = key\n this.solid =\n shape.kind === 'cylinder'\n ? cylinderSolid(shape.radius * INSET, shape.height * INSET, quality.bodySegments)\n : boxSolid([shape.size[0] * INSET, shape.size[1] * INSET, shape.size[2] * INSET])\n const T = this.THREE\n this.geometry?.dispose()\n this.pos = new Float32Array(this.solid.maxVertices * 3)\n this.nor = new Float32Array(this.solid.maxVertices * 3)\n this.geometry = new T.BufferGeometry()\n const p = new T.BufferAttribute(this.pos, 3)\n const n = new T.BufferAttribute(this.nor, 3)\n p.setUsage(T.DynamicDrawUsage)\n n.setUsage(T.DynamicDrawUsage)\n this.geometry.setAttribute('position', p)\n this.geometry.setAttribute('normal', n)\n if (!this.mesh) {\n this.mesh = new T.Mesh(this.geometry)\n this.mesh.name = 'fluid_liquid'\n this.mesh.frustumCulled = false\n this.mesh.renderOrder = 3\n this.group.add(this.mesh)\n } else this.mesh.geometry = this.geometry\n }\n\n update(dt: number, world: FluidWorld, materials: MaterialCache, quality: QualityProfile, particles: FluidSprites): void {\n const state = world.container(this.containerId)\n const def = state?.liquid ? world.liquids.get(state.liquid) : undefined\n if (!state || !state.shape || !def || state.liters <= 1e-6) {\n if (this.mesh) this.mesh.visible = false\n this.vertices = 0\n return\n }\n this.build(state, quality)\n if (!this.mesh || !this.solid) return\n this.mesh.material = materials.liquidBody(def)\n\n // The surface plane in the group's space.\n this.object.updateWorldMatrix(true, false)\n this.group.updateWorldMatrix(true, false)\n this.inverse.copy(this.group.matrixWorld).invert()\n this.tmpN.set(state.surfaceNormal[0], state.surfaceNormal[1], state.surfaceNormal[2]).transformDirection(this.inverse)\n this.tmpP.set(state.surfacePoint[0], state.surfacePoint[1], state.surfacePoint[2]).applyMatrix4(this.inverse)\n const u: V3 = [this.tmpN.x, this.tmpN.y, this.tmpN.z]\n const d = u[0] * this.tmpP.x + u[1] * this.tmpP.y + u[2] * this.tmpP.z\n\n this.vertices = clipSolid(this.solid, u, d, this.pos, this.nor)\n const geometry = this.geometry as THREE_NS.BufferGeometry\n geometry.setDrawRange(0, this.vertices)\n ;(geometry.getAttribute('position') as THREE_NS.BufferAttribute).needsUpdate = true\n ;(geometry.getAttribute('normal') as THREE_NS.BufferAttribute).needsUpdate = true\n this.mesh.visible = this.vertices > 0\n\n // Steam above a hot open surface.\n if (state.steaming && this.vertices > 0) {\n this.steamAcc += dt * quality.steamRate\n while (this.steamAcc >= 1) {\n this.steamAcc -= 1\n const o = this.tmpP.set(state.surfacePoint[0], state.surfacePoint[1], state.surfacePoint[2])\n particles.steam([o.x, o.y + 0.01, o.z])\n }\n } else this.steamAcc = 0\n }\n\n get triangles(): number {\n return this.visible ? Math.floor(this.vertices / 3) : 0\n }\n\n dispose(): void {\n this.object.remove(this.group)\n this.geometry?.dispose()\n this.geometry = null\n this.mesh = null\n }\n}\n","export const clamp = (v: number, lo: number, hi: number): number => (v < lo ? lo : v > hi ? hi : v)\nexport const lerp = (a: number, b: number, t: number): number => a + (b - a) * t\n\n/** Small seeded generator for cosmetic randomness (droplet directions): the same input gives the same droplets. */\nexport class Rng {\n private state: number\n constructor(seed: number) {\n this.state = (seed >>> 0) || 1\n }\n next(): number {\n this.state = (this.state + 0x6d2b79f5) >>> 0\n let t = this.state\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** Integer hash of a point, to seed cosmetic randomness from world state. */\nexport const hashPoint = (x: number, y: number, z: number): number => {\n let h = 2166136261\n for (const v of [x, y, z]) h = Math.imul(h ^ Math.round(v * 1000), 16777619)\n return h >>> 0\n}\n","import type * as THREE_NS from 'three'\nimport type { LiquidDef } from '@adatechnology/game-fluids'\nimport { clamp } from './util'\nimport type { ThreeLib } from './types'\n\n/** Colour of a stain: the liquid's `stainColor`, else a darker `color`. */\nexport const stainColorOf = (def: LiquidDef): number => {\n if (def.stainColor !== undefined) return def.stainColor\n const r = ((def.color >> 16) & 255) * 0.65\n const g = ((def.color >> 8) & 255) * 0.65\n const b = (def.color & 255) * 0.65\n return (Math.round(r) << 16) | (Math.round(g) << 8) | Math.round(b)\n}\n\n/**\n * One material per liquid and role, created on demand and shared by every mesh: each liquid is its own material (colour, opacity, gloss).\n * Wet surfaces use a low roughness from `gloss` so they reflect the scene's environment.\n */\nexport class MaterialCache {\n private body = new Map<string, THREE_NS.MeshStandardMaterial>()\n private stream = new Map<string, THREE_NS.MeshStandardMaterial>()\n private film = new Map<string, THREE_NS.MeshStandardMaterial>()\n private wet = new Map<string, THREE_NS.MeshStandardMaterial>()\n\n constructor(\n private readonly THREE: ThreeLib,\n private readonly envMap: THREE_NS.Texture | null,\n ) {}\n\n private make(params: THREE_NS.MeshStandardMaterialParameters): THREE_NS.MeshStandardMaterial {\n const m = new this.THREE.MeshStandardMaterial({ metalness: 0, ...params })\n if (this.envMap) m.envMap = this.envMap\n return m\n }\n\n /** The volume of liquid inside a container. */\n liquidBody(def: LiquidDef): THREE_NS.MeshStandardMaterial {\n let m = this.body.get(def.id)\n if (!m) {\n m = this.make({\n color: def.color,\n opacity: def.opacity,\n transparent: def.opacity < 0.999,\n roughness: clamp(1 - def.gloss * 0.9, 0.04, 1),\n envMapIntensity: 0.5 + def.gloss * 0.9,\n depthWrite: def.opacity >= 0.999,\n })\n this.body.set(def.id, m)\n }\n return m\n }\n\n /** A jet or a drop in the air. */\n liquidStream(def: LiquidDef): THREE_NS.MeshStandardMaterial {\n let m = this.stream.get(def.id)\n if (!m) {\n m = this.make({\n color: def.color,\n opacity: clamp(def.opacity + 0.1, 0.35, 1),\n transparent: true,\n roughness: clamp(1 - def.gloss * 0.95, 0.03, 1),\n envMapIntensity: 0.8 + def.gloss,\n side: this.THREE.DoubleSide,\n depthWrite: false,\n })\n this.stream.set(def.id, m)\n }\n return m\n }\n\n /** The thin outer film of a stain (and the permanent mark): tinted by vertex colour, soft rim by vertex alpha, mostly matte. */\n stainFilm(def: LiquidDef): THREE_NS.MeshStandardMaterial {\n let m = this.film.get(def.id)\n if (!m) {\n m = this.make({\n color: 0xffffff,\n vertexColors: true,\n transparent: true,\n roughness: clamp(0.95 - def.gloss * 0.45, 0.3, 1),\n envMapIntensity: 0.4 + def.gloss * 0.4,\n depthWrite: false,\n polygonOffset: true,\n polygonOffsetFactor: -2,\n polygonOffsetUnits: -2,\n })\n this.film.set(def.id, m)\n }\n return m\n }\n\n /** The glossy wet part of a stain, which shrinks while it dries. */\n stainWet(def: LiquidDef): THREE_NS.MeshStandardMaterial {\n let m = this.wet.get(def.id)\n if (!m) {\n m = this.make({\n color: 0xffffff,\n vertexColors: true,\n transparent: true,\n roughness: clamp(1 - def.gloss, 0.02, 0.7),\n envMapIntensity: 0.9 + def.gloss * 1.4,\n depthWrite: false,\n polygonOffset: true,\n polygonOffsetFactor: -3,\n polygonOffsetUnits: -3,\n })\n this.wet.set(def.id, m)\n }\n return m\n }\n\n dispose(): void {\n for (const map of [this.body, this.stream, this.film, this.wet]) {\n for (const m of map.values()) m.dispose()\n map.clear()\n }\n }\n}\n","import type { FluidQuality } from './types'\n\nexport interface QualityProfile {\n /** Radial segments of the container liquid volume. */\n bodySegments: number\n /** Samples along a stream and sides of its tube. */\n streamSamples: number\n streamSides: number\n /** Drops of a thin stream. */\n thinDrops: number\n /** Subdivisions per front sample of a stain outline (16 samples). */\n stainSubdiv: number\n maxStains: number\n maxStreams: number\n maxParticles: number\n /** Steam puffs per second of a steaming container. */\n steamRate: number\n /** Droplets of a full-intensity splash. */\n splashDroplets: number\n}\n\nexport const PROFILES: Record<FluidQuality, QualityProfile> = {\n low: { bodySegments: 10, streamSamples: 8, streamSides: 4, thinDrops: 4, stainSubdiv: 1, maxStains: 24, maxStreams: 12, maxParticles: 96, steamRate: 4, splashDroplets: 5 },\n medium: { bodySegments: 14, streamSamples: 12, streamSides: 5, thinDrops: 6, stainSubdiv: 2, maxStains: 48, maxStreams: 24, maxParticles: 256, steamRate: 8, splashDroplets: 9 },\n high: { bodySegments: 20, streamSamples: 20, streamSides: 8, thinDrops: 8, stainSubdiv: 4, maxStains: 96, maxStreams: 48, maxParticles: 512, steamRate: 14, splashDroplets: 14 },\n}\n\nexport const profileOf = (q: FluidQuality | undefined): QualityProfile => PROFILES[q ?? 'medium'] ?? PROFILES.medium\n","import type { VfxWorld } from '@adatechnology/game-vfx'\nimport { Rng, clamp, hashPoint } from './util'\n\n/**\n * Splash droplets and steam, made of the shared sprite kinds of the effects world (`drips` and `steam`) instead of a pool of their own. The droplets are\n * ballistic and stop at the height they were thrown from; the steam rises slowly.\n */\nexport class FluidSprites {\n private readonly rng = new Rng(1234567)\n private thrown = 0\n\n constructor(\n private readonly vfx: VfxWorld,\n private readonly owner: string,\n ) {}\n\n /** Droplets thrown up by an impact; they stop at `point[1]`. */\n splash(point: [number, number, number], intensity: number, hex: number, opacity: number, count: number): void {\n const rng = new Rng(hashPoint(point[0], point[1], point[2]) ^ this.thrown)\n const n = Math.max(2, Math.round(count * (0.35 + 0.65 * clamp(intensity, 0, 1))))\n this.thrown += n\n for (let k = 0; k < n; k++) {\n const a = rng.next() * Math.PI * 2\n const h = (0.25 + rng.next() * 0.9) * (0.4 + intensity)\n const up = (0.7 + rng.next() * 1.5) * (0.5 + intensity)\n const life = 0.45 + rng.next() * 0.45\n const size = 0.012 + rng.next() * 0.014\n this.vfx.spawn('drips', [point[0], point[1] + 0.01, point[2]], [Math.cos(a) * h, up, Math.sin(a) * h], {\n color: hex,\n life: life / DRIP_LIFE,\n size: size / DRIP_SIZE,\n alpha: clamp(opacity + 0.2, 0.35, 1),\n floor: point[1],\n })\n }\n }\n\n /** One puff of steam rising from `point`. */\n steam(point: [number, number, number]): void {\n const r = this.rng\n this.vfx.spawn('steam', [point[0] + (r.next() - 0.5) * 0.04, point[1], point[2] + (r.next() - 0.5) * 0.04], [(r.next() - 0.5) * 0.06, 0.22 + r.next() * 0.12, (r.next() - 0.5) * 0.06], {\n color: STEAM_COLOR,\n life: (1.2 + r.next() * 0.6) / STEAM_LIFE,\n size: STEAM_SIZE_FACTOR,\n alpha: STEAM_ALPHA,\n rise: STEAM_RISE,\n })\n }\n\n /** The sprites alive in the world (a shared world counts everyone's). */\n get count(): number {\n return this.vfx.sprites().live\n }\n}\n\n// The `drips` kind lives 2 to 3 s at 0.025 to 0.035 m, the `steam` kind 1 to 2 s at 0.12 to 0.2 m with 0.35 alpha and a rise of 0.9 m/s²: the\n// fluids pool's old droplets (0.45 to 0.9 s, 0.012 to 0.026 m) and steam (1.2 to 1.8 s, 0.03 m growing to 0.1 m, 0.24 alpha) are those scaled.\nconst DRIP_LIFE = 2.5\nconst DRIP_SIZE = 0.03\nconst STEAM_LIFE = 1.5\nconst STEAM_COLOR = 0xf4f8ff\nconst STEAM_SIZE_FACTOR = 0.2\nconst STEAM_ALPHA = 0.24 / 0.35\nconst STEAM_RISE = 0.3\n","import type * as THREE_NS from 'three'\nimport { STAIN_SAMPLES } from '@adatechnology/game-fluids'\nimport type { LiquidDef, StainState, Vec3 } from '@adatechnology/game-fluids'\nimport type { MaterialCache } from './materials'\nimport { stainColorOf } from './materials'\nimport type { QualityProfile } from './quality'\nimport { clamp } from './util'\nimport type { ThreeLib } from './types'\n\n/** Periodic Catmull-Rom of the 16 front radii: a smooth outline with `subdiv` points per sample. */\nexport const smoothOutline = (front: number[], subdiv: number, out?: number[]): number[] => {\n const n = front.length\n const res = out ?? []\n res.length = n * subdiv\n for (let i = 0; i < n; i++) {\n const p0 = front[(i + n - 1) % n]\n const p1 = front[i]\n const p2 = front[(i + 1) % n]\n const p3 = front[(i + 2) % n]\n for (let j = 0; j < subdiv; j++) {\n const t = j / subdiv\n const r = 0.5 * (2 * p1 + (-p0 + p2) * t + (2 * p0 - 5 * p1 + 4 * p2 - p3) * t * t + (-p0 + 3 * p1 - 3 * p2 + p3) * t * t * t)\n res[i * subdiv + j] = Math.max(0.004, r)\n }\n }\n return res\n}\n\ninterface Fan {\n mesh: THREE_NS.Mesh\n position: Float32Array\n color: Float32Array\n}\n\n/**\n * One stain: an outer film (the whole flow-front polygon, soft at the rim) and an inner glossy fan at `wetRadius` that recedes while it dries.\n * Both are triangle fans with preallocated buffers, lying on the surface plane a hair above it.\n */\nexport class StainVisual {\n readonly group: THREE_NS.Group\n private readonly outer: Fan\n private readonly inner: Fan\n private readonly ring: number\n private readonly radii: number[] = []\n private readonly tint: THREE_NS.Color\n stainId = ''\n signature = Number.NaN\n triangles = 0\n\n constructor(\n private readonly THREE: ThreeLib,\n profile: QualityProfile,\n readonly slot: number,\n ) {\n this.ring = STAIN_SAMPLES * profile.stainSubdiv\n this.group = new THREE.Group()\n this.group.name = 'fluid_stain'\n this.tint = new THREE.Color()\n this.outer = this.makeFan('fluid_stain_film', 1)\n this.inner = this.makeFan('fluid_stain_wet', 2)\n this.group.add(this.outer.mesh, this.inner.mesh)\n this.group.visible = false\n }\n\n private makeFan(name: string, order: number): Fan {\n const T = this.THREE\n const count = 1 + this.ring\n const position = new Float32Array(count * 3)\n const color = new Float32Array(count * 4)\n const normal = new Float32Array(count * 3)\n const geometry = new T.BufferGeometry()\n const p = new T.BufferAttribute(position, 3)\n const c = new T.BufferAttribute(color, 4)\n p.setUsage(T.DynamicDrawUsage)\n c.setUsage(T.DynamicDrawUsage)\n geometry.setAttribute('position', p)\n geometry.setAttribute('normal', new T.BufferAttribute(normal, 3))\n geometry.setAttribute('color', c)\n const index: number[] = []\n for (let i = 0; i < this.ring; i++) index.push(0, 1 + i, 1 + ((i + 1) % this.ring))\n geometry.setIndex(index)\n const mesh = new T.Mesh(geometry)\n mesh.name = name\n mesh.frustumCulled = false\n mesh.renderOrder = order\n return { mesh, position, color }\n }\n\n assign(def: LiquidDef, materials: MaterialCache): void {\n this.outer.mesh.material = materials.stainFilm(def)\n this.inner.mesh.material = materials.stainWet(def)\n }\n\n hide(): void {\n this.group.visible = false\n this.stainId = ''\n this.signature = Number.NaN\n this.triangles = 0\n }\n\n /** Rebuild the vertices from the stain state (skipped when nothing changed). */\n update(stain: StainState, def: LiquidDef, profile: QualityProfile): void {\n const sig =\n stain.center[0] * 3 +\n stain.center[1] * 5 +\n stain.center[2] * 7 +\n stain.front.reduce((s, v, i) => s + v * (i + 1), 0) * 11 +\n stain.wetness * 13 +\n stain.wetRadius * 17 +\n (stain.soaked / (stain.soaked + stain.liters + 1e-6)) * 19\n if (sig === this.signature && this.group.visible) return\n this.signature = sig\n\n const n: Vec3 = stain.normal ?? [0, 1, 0]\n const t1: Vec3 = stain.tangent ?? [1, 0, 0]\n const t2: Vec3 = [n[1] * t1[2] - n[2] * t1[1], n[2] * t1[0] - n[0] * t1[2], n[0] * t1[1] - n[1] * t1[0]]\n smoothOutline(stain.front, profile.stainSubdiv, this.radii)\n const ring = this.ring\n const lift = 0.0015 + 0.0004 * (this.slot % 6)\n const mean = stain.front.reduce((s, v) => s + v, 0) / stain.front.length\n const wet = clamp(stain.wetness, 0, 1)\n const soakRatio = stain.soaked / (stain.soaked + stain.liters + 1e-6)\n\n // Outer film: tinted by the liquid, darker while wet and where it soaked in, fainter once only the mark is left.\n this.tint.setHex(stain.tint?.dry ?? stainColorOf(def))\n const dark = 1 - 0.3 * wet - 0.2 * soakRatio\n const markAlpha = def.leavesMark ? 0.34 : 0.1\n const aMid = (markAlpha + (0.62 - markAlpha) * wet) * (0.75 + 0.25 * Math.min(1, stain.liters * 20 + soakRatio))\n this.writeFan(this.outer, stain.center, n, t1, t2, lift, 1, this.tint.r * dark, this.tint.g * dark, this.tint.b * dark, aMid, aMid * 0.45)\n this.outer.mesh.visible = true\n\n // Inner glossy wet fan, centred where the liquid came in, shrinking as it dries.\n const wr = clamp(stain.wetRadius, 0, 1)\n const showInner = wr > 0.05 && wet > 0.03\n this.inner.mesh.visible = showInner\n if (showInner) {\n this.tint.setHex(stain.tint?.fresh ?? def.color)\n const shift = stain.flow ? -mean * 0.1 * (1 - wr) : 0\n const centre: Vec3 = stain.flow\n ? [stain.center[0] + stain.flow[0] * shift, stain.center[1] + stain.flow[1] * shift, stain.center[2] + stain.flow[2] * shift]\n : stain.center\n const a = clamp(def.opacity, 0.2, 0.85) * wet * 0.8\n this.writeFan(this.inner, centre, n, t1, t2, lift + 0.0007, 0.9 * wr, this.tint.r, this.tint.g, this.tint.b, a, a * 0.5)\n }\n this.triangles = ring * (showInner ? 2 : 1)\n this.group.visible = true\n }\n\n private writeFan(\n fan: Fan,\n center: Vec3,\n n: Vec3,\n t1: Vec3,\n t2: Vec3,\n lift: number,\n scale: number,\n r: number,\n g: number,\n b: number,\n aCentre: number,\n aRim: number,\n ): void {\n const ring = this.ring\n const px = center[0] + n[0] * lift\n const py = center[1] + n[1] * lift\n const pz = center[2] + n[2] * lift\n fan.position[0] = px\n fan.position[1] = py\n fan.position[2] = pz\n fan.color[0] = r * 0.85\n fan.color[1] = g * 0.85\n fan.color[2] = b * 0.85\n fan.color[3] = aCentre\n const normalAttr = fan.mesh.geometry.getAttribute('normal') as THREE_NS.BufferAttribute\n for (let i = 0; i <= ring; i++) {\n normalAttr.setXYZ(i, n[0], n[1], n[2])\n }\n normalAttr.needsUpdate = true\n for (let i = 0; i < ring; i++) {\n const a = (i / ring) * Math.PI * 2\n const c = Math.cos(a) * this.radii[i] * scale\n const s = Math.sin(a) * this.radii[i] * scale\n const o = (1 + i) * 3\n fan.position[o] = px + t1[0] * c + t2[0] * s\n fan.position[o + 1] = py + t1[1] * c + t2[1] * s\n fan.position[o + 2] = pz + t1[2] * c + t2[2] * s\n const k = (1 + i) * 4\n fan.color[k] = r\n fan.color[k + 1] = g\n fan.color[k + 2] = b\n fan.color[k + 3] = aRim\n }\n const geometry = fan.mesh.geometry\n ;(geometry.getAttribute('position') as THREE_NS.BufferAttribute).needsUpdate = true\n ;(geometry.getAttribute('color') as THREE_NS.BufferAttribute).needsUpdate = true\n }\n\n dispose(): void {\n for (const fan of [this.outer, this.inner]) fan.mesh.geometry.dispose()\n }\n}\n","import type * as THREE_NS from 'three'\nimport { sampleStream } from '@adatechnology/game-fluids'\nimport type { StreamState } from '@adatechnology/game-fluids'\nimport type { QualityProfile } from './quality'\nimport { clamp } from './util'\nimport type { ThreeLib } from './types'\n\n/** Seconds a stream takes to break up into drops after the world ended it. */\nconst GHOST_TIME = 0.4\n\n/**\n * One stream: a thread along the ballistic path (a tube updated in place) with a growing drop at its leading tip, a trailing drop while it ends,\n * and for thin streams only a sequence of falling drops. The jet narrows as it accelerates.\n */\nexport class StreamVisual {\n readonly tube: THREE_NS.Mesh\n readonly drops: THREE_NS.InstancedMesh\n private readonly positions: Float32Array\n private readonly normals: Float32Array\n private readonly samples: number\n private readonly sides: number\n private readonly matrix: THREE_NS.Matrix4\n private readonly maxDrops: number\n id = ''\n age = 0\n ghostAge = -1\n /** Last known state, kept while the stream breaks into drops. */\n state: StreamState | null = null\n triangles = 0\n\n constructor(\n private readonly THREE: ThreeLib,\n profile: QualityProfile,\n dropGeometry: THREE_NS.SphereGeometry,\n ) {\n const T = THREE\n this.samples = profile.streamSamples\n this.sides = profile.streamSides\n this.maxDrops = Math.max(profile.thinDrops, 2) + 2\n this.positions = new Float32Array(this.samples * this.sides * 3)\n this.normals = new Float32Array(this.samples * this.sides * 3)\n const geometry = new T.BufferGeometry()\n const p = new T.BufferAttribute(this.positions, 3)\n const n = new T.BufferAttribute(this.normals, 3)\n p.setUsage(T.DynamicDrawUsage)\n n.setUsage(T.DynamicDrawUsage)\n geometry.setAttribute('position', p)\n geometry.setAttribute('normal', n)\n const index: number[] = []\n for (let i = 0; i < this.samples - 1; i++) {\n for (let j = 0; j < this.sides; j++) {\n const a = i * this.sides + j\n const b = i * this.sides + ((j + 1) % this.sides)\n const c = (i + 1) * this.sides + j\n const d = (i + 1) * this.sides + ((j + 1) % this.sides)\n index.push(a, c, b, b, c, d)\n }\n }\n geometry.setIndex(index)\n this.tube = new T.Mesh(geometry)\n this.tube.name = 'fluid_stream'\n this.tube.frustumCulled = false\n this.tube.renderOrder = 2\n this.drops = new T.InstancedMesh(dropGeometry, undefined as unknown as THREE_NS.Material, this.maxDrops)\n this.drops.name = 'fluid_stream_drops'\n this.drops.frustumCulled = false\n this.drops.renderOrder = 2\n this.drops.instanceMatrix.setUsage(T.DynamicDrawUsage)\n this.drops.count = 0\n this.matrix = new T.Matrix4()\n }\n\n setMaterial(material: THREE_NS.Material): void {\n this.tube.material = material\n this.drops.material = material\n }\n\n hide(): void {\n this.tube.visible = false\n this.drops.visible = false\n this.drops.count = 0\n this.triangles = 0\n }\n\n private dropAt(slot: number, x: number, y: number, z: number, radius: number): void {\n this.matrix.makeScale(radius, radius, radius).setPosition(x, y, z)\n this.drops.setMatrixAt(slot, this.matrix)\n }\n\n /**\n * Draw the stream. `state` is the world's stream while it lives, or the last known one while ghost (`ghostAge >= 0`).\n */\n update(state: StreamState, gravity: number, dt: number, profile: QualityProfile, time: number): void {\n this.state = state\n this.age += dt\n if (this.ghostAge >= 0) this.ghostAge += dt\n\n const flight = Math.max(0.02, state.flightTime ?? 1)\n const [vx, vy, vz] = state.velocity\n const speed0 = Math.max(0.3, Math.hypot(vx, vy, vz))\n const q = Math.max(state.rate, 0) / 1000\n const r0 = clamp(Math.sqrt(q / (Math.PI * speed0)), 0.0015, 0.03)\n\n const tB = Math.min(flight, this.age)\n // The tail leaves the origin at free fall once the world stopped the stream.\n const tA = this.ghostAge >= 0 ? Math.min(flight, this.ghostAge) : 0\n\n let drops = 0\n const thin = state.thin && this.ghostAge < 0\n\n if (thin) {\n this.tube.visible = false\n this.triangles = 0\n const n = profile.thinDrops\n const phase = time * 1.3\n for (let k = 0; k < n && drops < this.maxDrops; k++) {\n const tau = ((phase + k / n) % 1) * flight\n if (tau > tB) continue\n const p = sampleStream(state, gravity, tau)\n const grow = Math.min(1, tau / (0.12 * flight + 0.02))\n this.dropAt(drops++, p[0], p[1], p[2], Math.max(0.002, r0 * 1.8) * (0.4 + 0.6 * grow))\n }\n } else if (tB - tA > 0.015) {\n this.writeTube(state, gravity, tA, tB, r0, speed0)\n this.tube.visible = true\n this.triangles = (this.samples - 1) * this.sides * 2\n // Leading drop that grows and detaches while the jet is still advancing; trailing drop while it ends.\n if (tB < flight) {\n const p = sampleStream(state, gravity, tB)\n const w = this.radiusAt(state, gravity, tB, r0, speed0)\n this.dropAt(drops++, p[0], p[1], p[2], w * 1.35)\n }\n if (this.ghostAge >= 0) {\n const p = sampleStream(state, gravity, tA)\n const w = this.radiusAt(state, gravity, tA, r0, speed0)\n this.dropAt(drops++, p[0], p[1], p[2], w * 1.4 * (1 - this.ghostAge / GHOST_TIME * 0.4))\n }\n } else {\n this.tube.visible = false\n this.triangles = 0\n if (tA < flight) {\n // Only the drop is left.\n const p = sampleStream(state, gravity, this.ghostAge >= 0 ? tA : tB)\n this.dropAt(drops++, p[0], p[1], p[2], Math.max(0.003, r0 * 1.3))\n }\n }\n\n this.drops.count = drops\n this.drops.visible = drops > 0\n this.drops.instanceMatrix.needsUpdate = true\n this.triangles += drops * 24\n }\n\n /** The ghost is over once its tail reached the landing. */\n get finished(): boolean {\n return this.ghostAge >= 0 && (this.ghostAge >= GHOST_TIME || this.ghostAge >= (this.state?.flightTime ?? 0))\n }\n\n private radiusAt(state: StreamState, gravity: number, t: number, r0: number, speed0: number): number {\n const vy = state.velocity[1] - gravity * t\n const speed = Math.max(0.3, Math.hypot(state.velocity[0], vy, state.velocity[2]))\n const fade = this.ghostAge >= 0 ? clamp(1 - this.ghostAge / GHOST_TIME, 0.15, 1) : 1\n return r0 * Math.sqrt(speed0 / speed) * fade\n }\n\n private writeTube(state: StreamState, gravity: number, tA: number, tB: number, r0: number, speed0: number): void {\n const n = this.samples\n const sides = this.sides\n for (let i = 0; i < n; i++) {\n const k = i / (n - 1)\n const t = tA + (tB - tA) * k\n const p = sampleStream(state, gravity, t)\n const vx = state.velocity[0]\n const vy = state.velocity[1] - gravity * t\n const vz = state.velocity[2]\n const l = Math.hypot(vx, vy, vz) || 1\n const tx = vx / l\n const ty = vy / l\n const tz = vz / l\n // Any vector not parallel to the tangent gives the first side axis.\n const ax = Math.abs(tz) < 0.9 ? 0 : 1\n const az = Math.abs(tz) < 0.9 ? 1 : 0\n let b1x = ty * az - tz * 0\n let b1y = tz * ax - tx * az\n let b1z = tx * 0 - ty * ax\n const bl = Math.hypot(b1x, b1y, b1z) || 1\n b1x /= bl\n b1y /= bl\n b1z /= bl\n const b2x = ty * b1z - tz * b1y\n const b2y = tz * b1x - tx * b1z\n const b2z = tx * b1y - ty * b1x\n // Rounded ends: the radius tapers to a bead at both ends.\n const end = Math.min(1, 0.35 + Math.min(k, 1 - k) * 8)\n const r = this.radiusAt(state, gravity, t, r0, speed0) * end\n for (let j = 0; j < sides; j++) {\n const a = (j / sides) * Math.PI * 2\n const c = Math.cos(a)\n const s = Math.sin(a)\n const nx = b1x * c + b2x * s\n const ny = b1y * c + b2y * s\n const nz = b1z * c + b2z * s\n const o = (i * sides + j) * 3\n this.positions[o] = p[0] + nx * r\n this.positions[o + 1] = p[1] + ny * r\n this.positions[o + 2] = p[2] + nz * r\n this.normals[o] = nx\n this.normals[o + 1] = ny\n this.normals[o + 2] = nz\n }\n }\n const g = this.tube.geometry\n ;(g.getAttribute('position') as THREE_NS.BufferAttribute).needsUpdate = true\n ;(g.getAttribute('normal') as THREE_NS.BufferAttribute).needsUpdate = true\n }\n\n start(id: string): void {\n this.id = id\n this.age = 0\n this.ghostAge = -1\n this.state = null\n }\n\n dispose(): void {\n this.tube.geometry.dispose()\n this.drops.dispose()\n }\n}\n","import type * as THREE_NS from 'three'\nimport { FILM_PROFILES, filmProfileOf, layoutFromSurfaces } from '@adatechnology/game-fluids'\nimport type { FilmLayout, FilmProfile, FilmRandom, FluidWorld, LiquidId, StainTint, SurfaceSpec, Vec3 } from '@adatechnology/game-fluids'\nimport type { ThreeLib } from '../types'\nimport { FilmGrid } from './grid'\nimport type { CellRect } from './grid'\n\n/** What the manager keeps from the page's budget text: up to 6 grids, only within 30 m, about 0.3 ms of simulation each (W711, W text \"a mais de 30 m não anima\"). */\nconst DEFAULT_MAX_GRIDS = 6\nconst DEFAULT_RANGE = 30\nconst DEFAULT_BUDGET_MS = 1.2\nconst DEFAULT_SETTLE_SECONDS = 20\nconst DEFAULT_MAX_STAGING = 16\nconst DEFAULT_GRID_METRES = 2\nconst DEFAULT_CELL = 0.0125\nconst BAKE_RANGE_FACTOR = 1.25\nconst EDGE_MARGIN = 0.35\nconst FLOOR_REACH = 0.3\n/** A drop thrown from higher than this above a strip is not counted as over it. */\nconst DROP_HEIGHT = 2.5\nconst DEFAULT_DROP_RADIUS = 3\nconst FALL_SPEED = 2\nconst VISIBLE_THICKNESS = 0.035\nconst DEFAULT_HALF = 50\nconst FREE_AFTER_EMPTY = 2\n/** How much darker the thick middle of a tinted film is than its thin edge. */\nconst THICK_FACTOR = 0.55\n\n/** The surfaces a grid is laid over: the floor, and optionally a wall the film folds up and a curb it folds down. */\nexport interface FilmSurfaces {\n floor: SurfaceSpec\n wall?: SurfaceSpec\n curb?: SurfaceSpec\n}\n\n/** The part of the renderer the manager uses to upload only the dirty rectangle of a texture (three 0.160 `copyTextureToTexture`). */\nexport interface FilmGpu {\n copyTextureToTexture(position: THREE_NS.Vector2, source: THREE_NS.Texture, destination: THREE_NS.Texture, level?: number): void\n}\n\nexport interface FilmViewer {\n position: Vec3\n forward: Vec3\n}\n\n/** What a baked grid leaves behind in the host's stain decals. */\nexport interface FilmBake {\n fluid: LiquidId\n /** Where the film was thickest (world), litres of it, and the colours of its wet and dry look. */\n point: Vec3\n liters: number\n tint: StainTint\n /** Radius in metres of the wet cells around `point`. */\n radius: number\n reason: 'range' | 'settled' | 'budget' | 'clear'\n}\n\nexport interface FilmManagerOptions {\n /** Where the grids are added (one group). */\n scene: THREE_NS.Object3D\n /** The host's random stream: the film never calls `Math.random`. */\n random: FilmRandom\n /** The player's eye: grids are simulated near it and drawn lit from it. A camera works; or give `viewer`. */\n camera?: THREE_NS.Camera\n viewer?: () => FilmViewer\n /** The surfaces under a world point (floor, wall, curb), or null for none. Default: the ground plane at `groundAt`. */\n surfaceAt?: (point: Vec3) => FilmSurfaces | null\n groundAt?: (x: number, z: number) => number\n /** The world whose stain decals take the film when a grid is baked (`fluids.splash`). Without it a bake only calls `onBake`. */\n fluids?: FluidWorld\n onBake?: (bake: FilmBake) => void\n /** Profiles by liquid id (default the film profiles of `game-fluids`); override one to tune it. */\n profiles?: Readonly<Record<string, FilmProfile>>\n /** Colour of the surface under the film (default the page's grey). */\n base?: number\n maxGrids?: number\n /** Metres from the player past which a grid is not simulated and is baked. */\n range?: number\n /** Milliseconds of film simulation per frame; the grids left out wait for the next frame. */\n budgetMs?: number\n /** Seconds without change after which a grid is baked and freed. */\n settleSeconds?: number\n /** Side of a grid in metres (cells are 1.25 cm) and the cell size. */\n gridMetres?: number\n cellSize?: number\n /** Seconds of drying clock that pass in one second of real time (the host scales it; default 1). */\n dryingSpeed?: number\n /** The renderer, for the partial texture uploads. Without it the whole texture goes up when it changes. */\n gpu?: FilmGpu\n /** A clock in milliseconds (default `performance.now`). */\n now?: () => number\n}\n\nexport interface FilmStats {\n grids: number\n drops: number\n wetCells: number\n /** Milliseconds the last update spent simulating. */\n simMs: number\n /** Grids left out of the last update by the budget. */\n starved: number\n baked: number\n /** Texels written by partial uploads in the last update. */\n uploadedTexels: number\n}\n\nexport interface FilmLaunch {\n fluid: LiquidId\n point: Vec3\n /** Default straight down at 2 m/s. */\n velocity?: Vec3\n /** Millimetres (default 3). */\n radius?: number\n surfaces?: FilmSurfaces\n /** The colours of this splash (an infection age: fresh red, dry brown): the film is drawn with them instead of the liquid's own. */\n tint?: StainTint\n}\n\nexport interface FilmDripSpec {\n fluid: LiquidId\n point: Vec3\n /** Average seconds between drops. */\n every: number\n radius?: number\n surfaces?: FilmSurfaces\n tint?: StainTint\n}\n\nconst sameTint = (a: StainTint | undefined, b: StainTint | undefined): boolean => a?.fresh === b?.fresh && a?.dry === b?.dry\n\nconst scaleColor = (hex: number, factor: number): number =>\n (Math.round(((hex >> 16) & 255) * factor) << 16) | (Math.round(((hex >> 8) & 255) * factor) << 8) | Math.round((hex & 255) * factor)\n\n/** A profile drawn in the colours of a splash: the thin film and the drops take the fresh colour, the thick middle a darker one, and the dried film the dry colour. */\nexport function tinted(profile: FilmProfile, tint: StainTint): FilmProfile {\n return { ...profile, thin: tint.fresh, thick: scaleColor(tint.fresh, THICK_FACTOR), dry: tint.dry, dryThin: tint.dry, dropColor: tint.fresh }\n}\n\nconst distance = (a: Vec3, b: Vec3): number => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2])\n\n/**\n * Keeps the running films near the player: at most `maxGrids` grids of 2 x 2 m, only within `range`, simulated inside a millisecond budget and uploaded by their\n * dirty rectangle. A grid that is out of range, still, or squeezed out by a newer one is baked: its film becomes a stain of the host's world with the same\n * colours and amount, and the grid is freed.\n */\nexport class FilmManager {\n readonly group: THREE_NS.Group\n private readonly grids: FilmGrid[] = []\n private readonly profiles: Readonly<Record<string, FilmProfile>>\n private readonly staging = new Map<string, THREE_NS.DataTexture>()\n private readonly now: () => number\n private rain = 0\n private time = 0\n private bakedCount = 0\n private last: FilmStats = { grids: 0, drops: 0, wetCells: 0, simMs: 0, starved: 0, baked: 0, uploadedTexels: 0 }\n private empties = new Map<FilmGrid, number>()\n\n constructor(\n private readonly THREE: ThreeLib,\n private readonly options: FilmManagerOptions,\n ) {\n this.group = new THREE.Group()\n this.group.name = 'film_manager'\n options.scene.add(this.group)\n this.profiles = options.profiles ?? Object.fromEntries(FILM_PROFILES.map((profile) => [profile.id, profile]))\n this.now = options.now ?? (() => (typeof performance === 'undefined' ? Date.now() : performance.now()))\n }\n\n get gridCount(): number {\n return this.grids.length\n }\n\n /** The grids, for a host that wants to look at them (a bench, a test). */\n list(): readonly FilmGrid[] {\n return this.grids\n }\n\n setWeather(weather: { rain: number }): void {\n this.rain = Math.min(1, Math.max(0, weather.rain))\n for (const grid of this.grids) grid.film.setWeather({ rain: this.rain })\n }\n\n /** Throws a drop of a liquid: it lands in the grid under it (made on the spot) and leaves the impact splash. Null when it is out of range or has no surface. */\n launch(request: FilmLaunch): FilmGrid | null {\n const grid = this.gridFor(request.fluid, request.point, request.surfaces, request.tint)\n if (!grid) return null\n const velocity = request.velocity ?? [0, -FALL_SPEED, 0]\n grid.film.launch(request.point, velocity, request.radius ?? DEFAULT_DROP_RADIUS)\n return grid\n }\n\n /** A drip: a bead swells at `point`, detaches and falls every `every` seconds on average. Replaces the grid's drip. */\n drip(spec: FilmDripSpec): FilmGrid | null {\n const grid = this.gridFor(spec.fluid, spec.point, spec.surfaces, spec.tint)\n if (!grid) return null\n grid.film.drip = { position: [spec.point[0], spec.point[1], spec.point[2]], every: spec.every, base: spec.every, elapsed: 0, radius: spec.radius ?? DEFAULT_DROP_RADIUS }\n return grid\n }\n\n /** The grid of a liquid that covers `point`, made when there is none. Null when `point` is out of range or has no surface under it. */\n gridFor(fluid: LiquidId, point: Vec3, surfaces?: FilmSurfaces, tint?: StainTint): FilmGrid | null {\n const viewer = this.viewer()\n if (viewer && distance(viewer.position, point) > (this.options.range ?? DEFAULT_RANGE)) return null\n const existing = this.grids.find((grid) => grid.profile.id === fluid && sameTint(grid.tint, tint) && this.covers(grid, point))\n if (existing) return existing\n const base = this.profiles[fluid] ?? filmProfileOf(fluid)\n if (!base) return null\n const profile = tint ? tinted(base, tint) : base\n const found = surfaces ?? this.surfacesAt(point)\n if (!found) return null\n const layout = layoutFromSurfaces({ ...found, center: point, columns: this.columns(), rows: this.columns(), cellSize: this.options.cellSize ?? DEFAULT_CELL })\n if (this.grids.length >= (this.options.maxGrids ?? DEFAULT_MAX_GRIDS)) this.evict(point)\n const grid = new FilmGrid(this.THREE, { layout, profile, random: this.options.random, center: point, ...(tint ? { tint } : {}), ...(this.options.base === undefined ? {} : { base: this.options.base }) })\n grid.film.setWeather({ rain: this.rain })\n this.grids.push(grid)\n this.group.add(grid.group)\n return grid\n }\n\n /** One frame: simulates the grids near the player inside the budget, uploads what changed, bakes the ones that are far or still. */\n update(dt: number): FilmStats {\n this.time += dt\n const viewer = this.viewer()\n const range = this.options.range ?? DEFAULT_RANGE\n const budget = this.options.budgetMs ?? DEFAULT_BUDGET_MS\n const drying = dt * (this.options.dryingSpeed ?? 1)\n const order = [...this.grids].sort((a, b) => (viewer ? distance(viewer.position, a.center) - distance(viewer.position, b.center) : 0))\n const start = this.now()\n let starved = 0\n let uploaded = 0\n for (const grid of order) {\n if (viewer && distance(viewer.position, grid.center) > range * BAKE_RANGE_FACTOR) {\n this.release(grid, 'range')\n continue\n }\n if (this.now() - start > budget) {\n starved++\n continue\n }\n if (viewer) grid.setView(viewer.position, viewer.forward, this.time)\n const rect = grid.update(dt, drying)\n grid.syncDrops()\n if (rect) uploaded += this.upload(grid, rect)\n if (this.emptyFor(grid, dt) || grid.idle > (this.options.settleSeconds ?? DEFAULT_SETTLE_SECONDS)) this.release(grid, 'settled')\n }\n let drops = 0\n let wet = 0\n for (const grid of this.grids) {\n const { active } = grid.film.drops\n for (let i = 0; i < active.length; i++) drops += active[i]!\n wet += grid.film.wetCells()\n }\n this.last = { grids: this.grids.length, drops, wetCells: wet, simMs: this.now() - start, starved, baked: this.bakedCount, uploadedTexels: uploaded }\n return this.last\n }\n\n stats(): FilmStats {\n return this.last\n }\n\n /** Frees every grid. `bake` leaves each one's film as a stain first. */\n clear(bake = false): void {\n for (const grid of [...this.grids]) {\n if (bake) this.release(grid, 'clear')\n else this.free(grid)\n }\n }\n\n dispose(): void {\n this.clear()\n for (const texture of this.staging.values()) texture.dispose()\n this.staging.clear()\n this.options.scene.remove(this.group)\n }\n\n // ---- internals ----\n\n private columns(): number {\n return Math.round((this.options.gridMetres ?? DEFAULT_GRID_METRES) / (this.options.cellSize ?? DEFAULT_CELL))\n }\n\n private viewer(): FilmViewer | null {\n if (this.options.viewer) return this.options.viewer()\n const camera = this.options.camera\n if (!camera) return null\n const forward = new this.THREE.Vector3()\n camera.getWorldDirection(forward)\n return { position: [camera.position.x, camera.position.y, camera.position.z], forward: [forward.x, forward.y, forward.z] }\n }\n\n private surfacesAt(point: Vec3): FilmSurfaces | null {\n if (this.options.surfaceAt) return this.options.surfaceAt(point)\n const y = this.options.groundAt?.(point[0], point[2]) ?? 0\n return { floor: { id: 'film_ground', point: [point[0], y, point[2]], normal: [0, 1, 0], halfSize: [DEFAULT_HALF, DEFAULT_HALF], porosity: 0 } }\n }\n\n /** Whether `point` is over the grid, away from its edge, so a splash there does not fall off the strip. */\n private covers(grid: FilmGrid, point: Vec3): boolean {\n const layout: FilmLayout = grid.film.layout\n const wide = layout.width * layout.cellSize\n for (const region of layout.regions) {\n const local: Vec3 = [point[0] - region.origin[0], point[1] - region.origin[1], point[2] - region.origin[2]]\n const above = local[0] * region.normal[0] + local[1] * region.normal[1] + local[2] * region.normal[2]\n if (above < -FLOOR_REACH || above > DROP_HEIGHT) continue\n const sideways = local[0] * region.columnAxis[0] + local[1] * region.columnAxis[1] + local[2] * region.columnAxis[2]\n const down = local[0] * region.rowAxis[0] + local[1] * region.rowAxis[1] + local[2] * region.rowAxis[2]\n const length = region.rowCount * layout.cellSize\n if (sideways > EDGE_MARGIN && sideways < wide - EDGE_MARGIN && down > EDGE_MARGIN && down < length - EDGE_MARGIN) return true\n }\n return false\n }\n\n /** The grid squeezed out for a new one at `point`: the one that has been still the longest, then the farthest from the player. */\n private evict(point: Vec3): void {\n const viewer = this.viewer()\n const score = (grid: FilmGrid): number => grid.idle * 10 + (viewer ? distance(viewer.position, grid.center) : distance(point, grid.center))\n const victim = [...this.grids].sort((a, b) => score(b) - score(a))[0]\n if (victim) this.release(victim, 'budget')\n }\n\n /** A grid that has nothing wet for two seconds goes without a trace. */\n private emptyFor(grid: FilmGrid, dt: number): boolean {\n if (grid.film.wetCells() > 0 || grid.dropsInFlight() || grid.film.drip || grid.film.sources.length > 0) {\n this.empties.delete(grid)\n return false\n }\n const seconds = (this.empties.get(grid) ?? 0) + dt\n this.empties.set(grid, seconds)\n return seconds > FREE_AFTER_EMPTY\n }\n\n private free(grid: FilmGrid): void {\n const at = this.grids.indexOf(grid)\n if (at < 0) return\n this.grids.splice(at, 1)\n this.empties.delete(grid)\n this.group.remove(grid.group)\n grid.dispose()\n }\n\n /** Bakes the film of a grid into the host's stain decals and frees the grid. */\n private release(grid: FilmGrid, reason: FilmBake['reason']): void {\n const bake = this.measure(grid, reason)\n this.free(grid)\n if (!bake) return\n this.bakedCount++\n this.options.fluids?.splash(bake.fluid, bake.point, bake.liters, undefined, { tint: bake.tint })\n this.options.onBake?.(bake)\n }\n\n /** The film's centre of volume, its litres (millimetres of film times cell area) and the radius of the wet cells. */\n private measure(grid: FilmGrid, reason: FilmBake['reason']): FilmBake | null {\n const { thickness } = grid.film.field\n const { width, cellSize } = grid.film.layout\n let volume = 0\n let x = 0\n let y = 0\n let z = 0\n const wet: number[] = []\n for (let i = 0; i < thickness.length; i++) {\n const h = thickness[i]!\n if (h <= VISIBLE_THICKNESS) continue\n const at = grid.film.layout.cellToWorld(Math.floor(i / width) + 0.5, (i % width) + 0.5)\n volume += h\n x += at[0] * h\n y += at[1] * h\n z += at[2] * h\n wet.push(i)\n }\n if (volume === 0) return null\n const point: Vec3 = [x / volume, y / volume, z / volume]\n let radius = 0\n for (const i of wet) radius = Math.max(radius, distance(grid.film.layout.cellToWorld(Math.floor(i / width) + 0.5, (i % width) + 0.5), point))\n const profile = grid.profile\n return { fluid: profile.id, point, liters: volume * cellSize * cellSize, tint: grid.tint ?? { fresh: profile.thin, dry: profile.dry }, radius, reason }\n }\n\n /** Copies the dirty rectangle to the GPU texture; answers the texels written. */\n private upload(grid: FilmGrid, rect: CellRect): number {\n const gpu = this.options.gpu\n const width = rect.lastColumn - rect.firstColumn + 1\n const height = rect.lastRow - rect.firstRow + 1\n const whole = grid.film.layout.width * grid.film.layout.height\n if (!gpu || !grid.uploaded || width * height >= whole * 0.6) {\n grid.texture.needsUpdate = true\n return whole\n }\n const staging = this.stagingFor(width, height)\n const target = staging.image.data as unknown as Uint8Array\n const stride = grid.film.layout.width * 4\n for (let row = 0; row < height; row++) {\n const from = (rect.firstRow + row) * stride + rect.firstColumn * 4\n target.set(grid.data.subarray(from, from + width * 4), row * width * 4)\n }\n staging.needsUpdate = true\n gpu.copyTextureToTexture(new this.THREE.Vector2(rect.firstColumn, rect.firstRow), staging, grid.texture)\n return width * height\n }\n\n private stagingFor(width: number, height: number): THREE_NS.DataTexture {\n const key = `${width}x${height}`\n let texture = this.staging.get(key)\n if (!texture) {\n if (this.staging.size >= DEFAULT_MAX_STAGING) {\n const oldest = this.staging.keys().next().value as string\n this.staging.get(oldest)?.dispose()\n this.staging.delete(oldest)\n }\n texture = new this.THREE.DataTexture(new Uint8Array(new ArrayBuffer(width * height * 4)), width, height, this.THREE.RGBAFormat)\n texture.magFilter = this.THREE.LinearFilter\n texture.minFilter = this.THREE.LinearFilter\n this.staging.set(key, texture)\n }\n return texture\n }\n}\n\nexport function createFilmManager(THREE: ThreeLib, options: FilmManagerOptions): FilmManager {\n return new FilmManager(THREE, options)\n}\n","import type * as THREE_NS from 'three'\nimport { createFilm } from '@adatechnology/game-fluids'\nimport type { Film, FilmBounds, FilmLayout, FilmProfile, FilmRandom, StainTint, Vec3 } from '@adatechnology/game-fluids'\nimport type { ThreeLib } from '../types'\nimport { createFilmDrops } from './drops'\nimport type { FilmDrops } from './drops'\nimport { createFilmMaterial } from './material'\nimport type { FilmMaterial } from './material'\nimport { createStripGeometry } from './strips'\n\nconst MAX_THICKNESS = 6\nconst CHANNEL = 255\nconst VISIBLE_THICKNESS = 0.035\nconst DEFAULT_BASE = 0x666661\nconst MIN_CHANGE = 2\nconst CHANGE_FRACTION = 0.005\nconst LAMP_OFFSET: Vec3 = [0.9, 2.9, 0.4]\n\nexport interface FilmGridOptions {\n layout: FilmLayout\n profile: FilmProfile\n random: FilmRandom\n /** The host's surface colour under the film, `0xRRGGBB` (the shader blends over it). Default the page's sidewalk grey. */\n base?: number\n /** World point the grid is about: the distance to the player is measured from it. */\n center: Vec3\n /** The splash colours the profile was tinted with, kept to tell a grid of another tint apart and to bake with them. */\n tint?: StainTint\n stepRate?: number\n maxSteps?: number\n}\n\n/** A rectangle of cells, inclusive. */\nexport interface CellRect {\n firstRow: number\n lastRow: number\n firstColumn: number\n lastColumn: number\n}\n\n/**\n * One film grid on screen: the running film, its texture (thickness, dryness, dampness per cell as the page's `upload` writes them), the strips of the\n * layout drawn with the film shader, and the drops in flight.\n */\nexport class FilmGrid {\n readonly film: Film\n readonly group: THREE_NS.Group\n readonly texture: THREE_NS.DataTexture\n readonly center: Vec3\n readonly tint: StainTint | undefined\n readonly data: Uint8Array<ArrayBuffer>\n /** Seconds the grid has been without anything landing, flowing or drying. */\n idle = 0\n /** Set once the whole texture went to the GPU (the partial uploads need it there first). */\n uploaded = false\n private readonly strips: THREE_NS.Mesh[] = []\n private readonly material: FilmMaterial\n private readonly dropsView: FilmDrops\n private previous: CellRect | null = null\n private pending: CellRect | null = null\n private launched = 0\n private lastWet = 0\n\n constructor(\n private readonly THREE: ThreeLib,\n options: FilmGridOptions,\n ) {\n const { layout, profile } = options\n this.center = options.center\n this.tint = options.tint\n this.film = createFilm({ layout, profile, random: options.random, ...(options.stepRate ? { stepRate: options.stepRate } : {}), ...(options.maxSteps ? { maxSteps: options.maxSteps } : {}) })\n this.data = new Uint8Array(new ArrayBuffer(layout.width * layout.height * 4))\n this.texture = new THREE.DataTexture(this.data, layout.width, layout.height, THREE.RGBAFormat)\n this.texture.magFilter = THREE.LinearFilter\n this.texture.minFilter = THREE.LinearFilter\n this.texture.needsUpdate = true\n // three calls this after the texture reached the GPU: from then on only the dirty rectangle has to go up\n this.texture.onUpdate = () => {\n this.uploaded = true\n }\n this.material = createFilmMaterial(THREE, this.texture, layout.width, layout.height, layout.height * layout.cellSize)\n this.material.setProfile(profile)\n this.group = new THREE.Group()\n this.group.name = 'film_grid'\n for (const region of layout.regions) {\n const mesh = new THREE.Mesh(createStripGeometry(THREE, layout, region), this.material.material)\n mesh.frustumCulled = false\n mesh.renderOrder = 3\n mesh.name = `film_${region.id}`\n this.strips.push(mesh)\n this.group.add(mesh)\n }\n this.dropsView = createFilmDrops(THREE, layout.rules.dropCapacity, profile)\n this.group.add(this.dropsView.drops, this.dropsView.bead)\n const uniforms = this.material.material.uniforms\n const base = options.base ?? DEFAULT_BASE\n uniforms.uBase!.value.set(((base >> 16) & 255) / 255, ((base >> 8) & 255) / 255, (base & 255) / 255)\n uniforms.lampP!.value.set(this.center[0] + LAMP_OFFSET[0], this.center[1] + LAMP_OFFSET[1], this.center[2] + LAMP_OFFSET[2])\n this.launched = this.film.drops.launched\n }\n\n get profile(): FilmProfile {\n return this.film.profile\n }\n\n setProfile(profile: FilmProfile): void {\n this.film.profile = profile\n this.material.setProfile(profile)\n this.dropsView.setProfile(profile)\n }\n\n /** Where the film's light and eye are (the page's `camP`, `flashP` and `flashD`). */\n setView(camera: Vec3, forward: Vec3, time: number): void {\n const uniforms = this.material.material.uniforms\n uniforms.camP!.value.set(camera[0], camera[1], camera[2])\n uniforms.flashP!.value.set(camera[0] + 0.12, camera[1] - 0.15, camera[2])\n uniforms.flashD!.value.set(forward[0], forward[1], forward[2])\n uniforms.uT!.value = time\n }\n\n /** Steps the film one frame and refreshes the texture cells that may have changed. Returns the rectangle to upload, or null. */\n update(dt: number, dryingSeconds: number): CellRect | null {\n this.film.update({ dt, dryingSeconds })\n const bounds: FilmBounds = this.film.simulator.bounds\n const launched = this.film.drops.launched\n const busy = launched !== this.launched || this.film.drip !== undefined || this.film.sources.length > 0 || this.film.drags.some((drag) => !drag.done) || this.dropsInFlight()\n this.launched = launched\n const current: CellRect | null = bounds.lastRow < 0 ? null : { firstRow: bounds.firstRow, lastRow: bounds.lastRow, firstColumn: bounds.firstColumn, lastColumn: bounds.lastColumn }\n const rect = this.union(this.previous, current)\n this.previous = current\n const wet = current ? this.film.wetCells() : 0\n // still = nothing arriving and the wet area changing by less than half a percent (a slow creep does not keep a grid alive)\n const moved = Math.abs(wet - this.lastWet) > Math.max(MIN_CHANGE, wet * CHANGE_FRACTION)\n this.idle = busy || moved ? 0 : this.idle + dt\n if (moved || busy) this.lastWet = wet\n if (!rect) return this.takePending()\n this.encode(rect)\n this.pending = this.union(this.pending, rect)\n return this.takePending()\n }\n\n private takePending(): CellRect | null {\n const rect = this.pending\n this.pending = null\n return rect\n }\n\n /** The mean dryness of the cells that are wet (1 when nothing is). */\n dryness(): number {\n const { thickness, dryness } = this.film.field\n let wet = 0\n let dry = 0\n for (let i = 0; i < thickness.length; i++) {\n if (thickness[i]! > VISIBLE_THICKNESS) {\n wet++\n dry += dryness[i]!\n }\n }\n return wet === 0 ? 1 : dry / wet\n }\n\n /** Draws the drops and the bead; answers how many drops are in flight. */\n syncDrops(): number {\n return this.dropsView.sync(this.film)\n }\n\n dropsInFlight(): boolean {\n const { active } = this.film.drops\n for (let i = 0; i < active.length; i++) if (active[i]) return true\n return false\n }\n\n /** Writes the cells of the texture from the field, as the page's `upload` does (F360). */\n encode(rect: CellRect): void {\n const { thickness, dryness, dampness, width } = this.film.field\n const data = this.data\n for (let row = rect.firstRow; row <= rect.lastRow; row++) {\n for (let column = rect.firstColumn; column <= rect.lastColumn; column++) {\n const cell = row * width + column\n const j = cell * 4\n const h = thickness[cell]!\n data[j] = h > 0 ? Math.min(CHANNEL, Math.sqrt(Math.min(MAX_THICKNESS, h) / MAX_THICKNESS) * CHANNEL + 0.5) : 0\n data[j + 1] = dryness[cell]! * CHANNEL\n data[j + 2] = dampness[cell]! * CHANNEL\n data[j + 3] = CHANNEL\n }\n }\n }\n\n /** Encodes the whole field (a grid made from a state, or after `clear`). */\n encodeAll(): void {\n this.encode({ firstRow: 0, lastRow: this.film.field.height - 1, firstColumn: 0, lastColumn: this.film.field.width - 1 })\n this.texture.needsUpdate = true\n this.uploaded = false\n }\n\n private union(a: CellRect | null, b: CellRect | null): CellRect | null {\n if (!a) return b ? { ...b } : null\n if (!b) return { ...a }\n return { firstRow: Math.min(a.firstRow, b.firstRow), lastRow: Math.max(a.lastRow, b.lastRow), firstColumn: Math.min(a.firstColumn, b.firstColumn), lastColumn: Math.max(a.lastColumn, b.lastColumn) }\n }\n\n dispose(): void {\n for (const mesh of this.strips) mesh.geometry.dispose()\n this.material.dispose()\n this.dropsView.dispose()\n this.texture.dispose()\n }\n}\n","import type * as THREE_NS from 'three'\nimport type { Film, FilmProfile } from '@adatechnology/game-fluids'\nimport type { ThreeLib } from '../types'\n\n/** The page's drop size: a radius in millimetres drawn as a sphere of `radius * 0.0013` m, stretched along its flight by its speed (F258-262). */\nconst METRES_PER_MM = 0.0013\nconst STRETCH_PER_SPEED = 0.35\nconst MAX_STRETCH = 3.5\nconst BEAD_HANG = 0.0012\nconst BEAD_SCALE = 0.0011\n\nexport interface FilmDrops {\n readonly drops: THREE_NS.InstancedMesh\n readonly bead: THREE_NS.Mesh\n setProfile(profile: FilmProfile): void\n /** Writes the film's drops in flight and the drip's bead into the meshes; answers how many drops are drawn. */\n sync(film: Film): number\n dispose(): void\n}\n\nexport function createFilmDrops(THREE: ThreeLib, capacity: number, profile: FilmProfile): FilmDrops {\n const material = new THREE.MeshStandardMaterial({ color: profile.dropColor, roughness: 0.12, metalness: 0.15, transparent: true, opacity: profile.dropOpacity })\n const geometry = new THREE.IcosahedronGeometry(1, 1)\n const drops = new THREE.InstancedMesh(geometry, material, capacity)\n drops.frustumCulled = false\n drops.instanceMatrix.setUsage(THREE.DynamicDrawUsage)\n drops.name = 'film_drops'\n const beadGeometry = new THREE.SphereGeometry(1, 10, 8)\n const bead = new THREE.Mesh(beadGeometry, material)\n bead.visible = false\n bead.name = 'film_bead'\n const hidden = new THREE.Matrix4().makeScale(0, 0, 0)\n for (let i = 0; i < capacity; i++) drops.setMatrixAt(i, hidden)\n const up = new THREE.Vector3(0, 1, 0)\n const direction = new THREE.Vector3()\n const location = new THREE.Vector3()\n const scale = new THREE.Vector3()\n const rotation = new THREE.Quaternion()\n const matrix = new THREE.Matrix4()\n return {\n drops,\n bead,\n setProfile(next) {\n material.color.setHex(next.dropColor)\n material.opacity = next.dropOpacity\n },\n sync(film) {\n const { active, position, velocity, radius } = film.drops\n let drawn = 0\n for (let i = 0; i < capacity; i++) {\n if (!active[i]) {\n drops.setMatrixAt(i, hidden)\n continue\n }\n const o = i * 3\n const speed = Math.hypot(velocity[o]!, velocity[o + 1]!, velocity[o + 2]!)\n direction.set(velocity[o]!, velocity[o + 1]!, velocity[o + 2]!).normalize()\n rotation.setFromUnitVectors(up, direction)\n const size = radius[i]! * METRES_PER_MM\n matrix.compose(location.set(position[o]!, position[o + 1]!, position[o + 2]!), rotation, scale.set(size, size * (1 + Math.min(MAX_STRETCH, speed * STRETCH_PER_SPEED)), size))\n drops.setMatrixAt(i, matrix)\n drawn++\n }\n drops.instanceMatrix.needsUpdate = true\n const state = film.bead\n bead.visible = state.visible\n if (state.visible) {\n const r = state.radius\n bead.position.set(state.position[0], state.position[1] - r * BEAD_HANG, state.position[2])\n bead.scale.set(r * BEAD_SCALE, r * BEAD_SCALE * (1 + state.swell * 0.7), r * BEAD_SCALE)\n }\n return drawn\n },\n dispose() {\n geometry.dispose()\n beadGeometry.dispose()\n material.dispose()\n },\n }\n}\n","/**\n * The film shader of the Fluid Standard page (F131-209), line by line. Where the page painted the whole surface itself (`baseCol`: wall, sidewalk, curb,\n * road), the film is drawn over the host's own surface, so `baseCol` is the flat colour `uBase` and the alpha is the film's coverage: the wet part and,\n * for fuel, the ground it darkened. Three more differences: the grid size and span are uniforms (`uGrid`, `uSpan`; the page hard-codes 256 x 396 and 4.95),\n * the strip tangent comes from the geometry (`aT`; the page's was the x axis), and the output goes through the r160 colour-space chunk after turning the page's\n * display-space colours linear. The two lines that mirror the page's own wall in the reflection (`R.z<-.02 ... env=vec3(.30,.32,.35)`, `R.y<-.02 ...`) are left out:\n * they describe the page's scene, not a surface of the host.\n */\nexport const FILM_VERTEX = `attribute vec3 aB;attribute vec3 aT;varying vec2 vUv;varying vec3 vPos;varying vec3 vN;varying vec3 vB;varying vec3 vT;\nvoid main(){vUv=uv;vPos=position;vN=normal;vB=aB;vT=aT;gl_Position=projectionMatrix*viewMatrix*vec4(position,1.);}`\n\nexport const FILM_FRAGMENT = `precision highp float;\nuniform sampler2D tF;uniform vec2 tx;uniform vec2 uGrid;uniform float uSpan;uniform float uT;uniform int uFl;uniform vec3 cThin,cThick,cDry,cDryThin,uBase;uniform float opK,F0,nrm,dbg;\nuniform vec3 camP,lampP,flashP,flashD;varying vec2 vUv;varying vec3 vPos;varying vec3 vN;varying vec3 vB;varying vec3 vT;\nfloat hsh(vec2 p){p=fract(p*vec2(123.34,456.21));p+=dot(p,p+45.32);return fract(p.x*p.y);}\nvec2 hsh2(vec2 p){return vec2(hsh(p),hsh(p+17.7));}\nfloat nz(vec2 p){vec2 i=floor(p),f=fract(p);f=f*f*(3.-2.*f);return mix(mix(hsh(i),hsh(i+vec2(1,0)),f.x),mix(hsh(i+vec2(0,1)),hsh(i+vec2(1,1)),f.x),f.y);}\nfloat vor(vec2 p){vec2 i=floor(p),f=fract(p);float d1=8.,d2=8.;for(int y=-1;y<=1;y++)for(int x=-1;x<=1;x++){vec2 o=vec2(float(x),float(y));vec2 r=o+hsh2(i+o)-f;float d=dot(r,r);if(d<d1){d2=d1;d1=d;}else if(d<d2)d2=d;}return sqrt(d2)-sqrt(d1);}\nfloat hs(vec2 u){float r=texture2D(tF,u).r;return r*r*6.;}\nvoid main(){\n vec4 S=texture2D(tF,vUv);vec2 q=tx*.5;float h=.25*(hs(vUv+q)+hs(vUv-q)+hs(vUv+vec2(q.x,-q.y))+hs(vUv+vec2(-q.x,q.y)));float dry=S.g;float wg=S.b;\n vec2 o1=vec2(tx.x*1.5,0.),o2=vec2(0.,tx.y*1.5);\n float hl=hs(vUv-o1),hr=hs(vUv+o1),hd=hs(vUv-o2),hu=hs(vUv+o2);\n vec2 g=vec2(hr-hl,hu-hd)/37.5;\n vec2 cellp=vUv*uGrid;\n float n1=nz(cellp*2.3),n2=nz(cellp*7.1);\n float hn=h+(n1-.5)*.045+(n2-.5)*.02;\n float m=smoothstep(.035,.08,hn);\n if(uFl==4){float wa=.25*(texture2D(tF,vUv+q).b+texture2D(tF,vUv-q).b+texture2D(tF,vUv+vec2(q.x,-q.y)).b+texture2D(tF,vUv+vec2(-q.x,q.y)).b);m=smoothstep(.35,.75,wa+(n1-.5)*.25)*smoothstep(.0,.012,h);wg=smoothstep(.2,.8,wa+(n1-.5)*.2);}\n vec2 p=vec2(dot(vPos,normalize(vT)),vUv.y*uSpan);\n vec3 base=uBase;\n vec3 T=normalize(vT),Bv=normalize(vB),N0=normalize(vN);\n vec3 nt=vec3(-g*nrm*m,1.);\n float dryM=smoothstep(.5,.95,dry);\n float wet=(1.-dryM)*m;\n // bile bubbles\n float bub=0.;\n if(uFl==2){vec2 bp=cellp/2.6;vec2 bi=floor(bp);vec2 bf=fract(bp)-.5;float rnd=hsh(bi);\n if(rnd>.5&&h>1.1){float t=fract(uT*(.18+.25*hsh(bi+3.1))+rnd*7.);float rad=.42*smoothstep(0.,.8,t);float d=length(bf-(hsh2(bi+9.)-.5)*.2);\n if(t<.86&&d<rad){float z=sqrt(max(0.,rad*rad-d*d));nt.xy+=(bf/max(rad,.01))*2.2*(1.-dryM);bub=z/rad;}\n else if(t>=.86){float rr=.42*1.15;float ring=1.-smoothstep(0.,.07,abs(d-rr*(.9+(t-.86)*.8)));nt.xy-=normalize(bf+.0001)*ring*.8*(1.-dryM);bub=-ring;}}}\n if(uFl==4){vec2 wp=p;nt.xy+=.05*m*vec2(nz(wp*9.+vec2(uT*1.7,0.))-.5,nz(wp*9.+vec2(0.,uT*1.4)+7.)-.5)*2.;}\n vec3 Nf=normalize(T*nt.x+Bv*nt.y+N0*nt.z);\n // albedo\n float th=smoothstep(.1,1.7,h);\n vec3 fc=mix(cThin,cThick,th);\n float op=clamp(1.-exp(-h*opK),0.,1.);\n vec3 alb;\n if(uFl==4){alb=base*mix(vec3(1.),cThin*1.15,clamp(h*.9,0.,1.));}\n else{alb=mix(base*mix(vec3(1.),fc*1.6,clamp(h*2.,0.,1.)),fc,op);}\n if(uFl==2&&bub>0.)alb=mix(alb,cThin*1.25,bub*.5);\n // dried look: matte, darker rim, cracks where it was thick\n float rim=smoothstep(.01,.05,length(g))*(1.-smoothstep(.4,1.,h));\n vec3 dc=mix(cDryThin,cDry,smoothstep(.06,.8,h))*(1.-.42*rim);\n float crk=(1.-smoothstep(.015,.05,vor(p*(uFl==2?34.:52.))))*smoothstep(.9,1.6,h);\n dc=mix(dc,base*.55,crk*.75);\n if(uFl!=3&&uFl!=4)alb=mix(alb,mix(base,dc,clamp(.4+h*1.4,0.,1.)),dryM);\n // gasoline darkens the ground while wet\n float gw=0.;if(uFl==4){gw=wg*(1.-m*.0);base*=mix(1.,.45,gw);alb=mix(base,alb,m);}\n vec3 col0=mix(base,alb*(uFl<2?mix(.62,1.,dryM):1.),m);\n // lighting\n vec3 V=normalize(camP-vPos);\n vec3 Lv=lampP-vPos;float dl=length(Lv);vec3 L=Lv/dl;float att=2.2/(1.+dl*dl*.12);\n vec3 lampC=vec3(1.,.88,.7);vec3 moonD=normalize(vec3(-3.,5.,4.));vec3 moonC=vec3(.11,.14,.19);vec3 amb=vec3(.14,.15,.17);\n vec3 Fv=flashP-vPos;float fd=length(Fv);vec3 FL=Fv/fd;float cone=smoothstep(.86,.97,dot(-FL,flashD));float fatt=cone*1.1/(1.+fd*fd*.6);\n vec3 dif=col0*(amb+lampC*att*max(dot(Nf,L),0.)+moonC*max(dot(Nf,moonD),0.)+vec3(.95,.97,1.)*fatt*max(dot(Nf,FL),0.));\n float wv=max(wet,gw*.7);\n float shin=mix(30.,320.,wv);\n vec3 Hh=normalize(L+V);vec3 Hf=normalize(FL+V);\n float sp=pow(max(dot(Nf,Hh),0.),shin)*shin*.011*att;float spf=pow(max(dot(Nf,Hf),0.),shin)*shin*.008*fatt;\n vec3 R=reflect(-V,Nf);\n vec3 env=mix(vec3(.03,.035,.04),vec3(.15,.17,.21),clamp(R.y*1.4,0.,1.));\n env+=lampC*(pow(max(dot(R,L),0.),500.)*7.+pow(max(dot(R,L),0.),40.)*.6)*att;\n float fr=F0+(1.-F0)*pow(1.-max(dot(Nf,V),0.),5.);\n vec3 col=dif*(1.-fr*wv*.7)+(env*min(1.,fr*(uFl==4?1.6:3.4))+min(lampC*sp+vec3(.9,.95,1.)*spf,vec3(.85)))*wv;\n if(uFl==3){float film=(1.-smoothstep(.04,.55,h))*m;vec3 ir=.5+.5*cos(6.283*(h*7.+n1*.5+uT*.03+vec3(0.,.33,.67)));col+=ir*film*(.10+.5*fr)*(.6+att*.4);}\n if(uFl==4){vec2 wp=p;float film=m*(.4+.6*(1.-smoothstep(.02,.2,h)));vec3 ir=.5+.5*cos(6.283*(nz(wp*6.)*1.4+uT*.02+vec3(0.,.33,.67)));col+=ir*film*.05*(.3+fr*3.);}\n if(dbg>.5){float k=clamp(h/3.,0.,1.);vec3 hc=mix(vec3(.05,.1,.5),vec3(1.,.9,.2),k);hc=mix(hc,vec3(1.,.2,.1),step(.66,k));col=mix(base*.25,mix(hc,vec3(.6),dryM*.7),step(.004,h));}\n float cover=max(m,gw*.55);\n gl_FragColor=vec4(pow(max(col,vec3(0.)),vec3(2.2)),clamp(cover,0.,1.));\n #include <colorspace_fragment>\n}`\n","import type * as THREE_NS from 'three'\nimport type { FilmLook, FilmProfile } from '@adatechnology/game-fluids'\nimport type { ThreeLib } from '../types'\nimport { FILM_FRAGMENT, FILM_VERTEX } from './shader'\n\n/** The page's `uFl` of each look (blood 0, bile 2, oil 3, fuel 4). */\nexport const LOOK_INDEX: Readonly<Record<FilmLook, number>> = { blood: 0, bile: 2, oil: 3, fuel: 4 }\nconst DEFAULT_SPAN = 4.95\n\nexport interface FilmMaterial {\n readonly material: THREE_NS.ShaderMaterial\n /** Sets the page's liquid uniforms from a profile (`setFluid`, F119-130). */\n setProfile(profile: FilmProfile): void\n dispose(): void\n}\n\nconst rgb = (THREE: ThreeLib, target: THREE_NS.Vector3, hex: number): void => {\n target.set(((hex >> 16) & 255) / 255, ((hex >> 8) & 255) / 255, (hex & 255) / 255)\n}\n\n/**\n * The film's material: the Fluid Standard's shader with the grid texture `tF` (r: thickness, g: dryness, b: dampness) and the liquid's colours.\n * It is transparent over the host's surface: the alpha is the film's coverage.\n */\nexport function createFilmMaterial(THREE: ThreeLib, texture: THREE_NS.Texture, width: number, height: number, span: number = DEFAULT_SPAN): FilmMaterial {\n const V3 = THREE.Vector3\n const uniforms = {\n tF: { value: texture },\n tx: { value: new THREE.Vector2(1 / width, 1 / height) },\n uGrid: { value: new THREE.Vector2(width, height) },\n uSpan: { value: span },\n uT: { value: 0 },\n uFl: { value: 0 },\n cThin: { value: new V3() },\n cThick: { value: new V3() },\n cDry: { value: new V3() },\n cDryThin: { value: new V3() },\n uBase: { value: new V3(0.4, 0.4, 0.38) },\n opK: { value: 3 },\n F0: { value: 0.03 },\n nrm: { value: 16 },\n camP: { value: new V3() },\n lampP: { value: new V3() },\n flashP: { value: new V3() },\n flashD: { value: new V3(0, 0, -1) },\n dbg: { value: 0 },\n }\n const material = new THREE.ShaderMaterial({\n uniforms,\n vertexShader: FILM_VERTEX,\n fragmentShader: FILM_FRAGMENT,\n transparent: true,\n depthWrite: false,\n // the layout's axes may be either handed (the page's strips were all built facing out)\n side: THREE.DoubleSide,\n polygonOffset: true,\n polygonOffsetFactor: -2,\n polygonOffsetUnits: -2,\n })\n return {\n material,\n setProfile(profile) {\n uniforms.uFl.value = LOOK_INDEX[profile.look]\n rgb(THREE, uniforms.cThin.value, profile.thin)\n rgb(THREE, uniforms.cThick.value, profile.thick)\n rgb(THREE, uniforms.cDry.value, profile.dry)\n rgb(THREE, uniforms.cDryThin.value, profile.dryThin)\n uniforms.opK.value = profile.opacityRate\n uniforms.F0.value = profile.reflectance\n uniforms.nrm.value = profile.normalScale\n },\n dispose() {\n material.dispose()\n },\n }\n}\n","import type * as THREE_NS from 'three'\nimport type { FilmLayout, FilmRegion } from '@adatechnology/game-fluids'\nimport type { ThreeLib } from '../types'\n\nconst SEGMENTS_ACROSS = 8\nconst SEGMENTS_ALONG = 8\n\n/**\n * One strip of the folded grid as a plane of the surface: `uv` runs over the region's rows and the grid's columns, so the shader reads its own cells.\n * `aB` is the way the film runs down the strip (rows) and `aT` its columns.\n */\nexport function createStripGeometry(THREE: ThreeLib, layout: FilmLayout, region: FilmRegion): THREE_NS.BufferGeometry {\n const { width, height, cellSize } = layout\n const alongSegments = region.rowCount <= 2 ? 1 : SEGMENTS_ALONG\n const position: number[] = []\n const normal: number[] = []\n const uv: number[] = []\n const down: number[] = []\n const across: number[] = []\n const index: number[] = []\n for (let j = 0; j <= alongSegments; j++) {\n const t = j / alongSegments\n for (let i = 0; i <= SEGMENTS_ACROSS; i++) {\n const u = i / SEGMENTS_ACROSS\n for (let k = 0; k < 3; k++) position.push(region.origin[k] + region.columnAxis[k] * u * width * cellSize + region.rowAxis[k] * t * region.rowCount * cellSize)\n normal.push(region.normal[0], region.normal[1], region.normal[2])\n down.push(region.rowAxis[0], region.rowAxis[1], region.rowAxis[2])\n across.push(region.columnAxis[0], region.columnAxis[1], region.columnAxis[2])\n uv.push(u, (region.firstRow + t * region.rowCount) / height)\n }\n }\n for (let j = 0; j < alongSegments; j++) {\n for (let i = 0; i < SEGMENTS_ACROSS; i++) {\n const a = j * (SEGMENTS_ACROSS + 1) + i\n const b = a + 1\n const c = a + SEGMENTS_ACROSS + 1\n index.push(a, c, b, b, c, c + 1)\n }\n }\n const geometry = new THREE.BufferGeometry()\n geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3))\n geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normal, 3))\n geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2))\n geometry.setAttribute('aB', new THREE.Float32BufferAttribute(down, 3))\n geometry.setAttribute('aT', new THREE.Float32BufferAttribute(across, 3))\n geometry.setIndex(index)\n return geometry\n}\n","import type { FilmProfile, FluidEvent, FluidWorld, LiquidId, StainTint, Vec3 } from '@adatechnology/game-fluids'\nimport { FILM_PROFILES } from '@adatechnology/game-fluids'\nimport type { FilmSurfaces, FilmManager } from './manager'\n\nconst DEFAULT_DROP_LITERS = 0.00015\nconst DEFAULT_DROP_RADIUS = 3.2\nconst MAX_DROPS_PER_FRAME = 6\nconst RADIUS_SPREAD = 0.3\nconst RADIUS_BASE = 0.85\nconst DEFAULT_SPLAT_SPEED = 2.5\n\n/** A splash on the ground or a wall (a wound, a body falling): the film draws it as a drop landing, in the colours of `tint` when given. */\nexport interface FilmSplat {\n fluid: LiquidId\n point: Vec3\n /** The way the liquid travels (default straight down). */\n direction?: Vec3\n /** Metres per second (default 2.5). */\n speed?: number\n /** Drop radius in millimetres (default 3.2). */\n radius?: number\n /** Drops thrown (default 1). */\n count?: number\n surfaces?: FilmSurfaces\n tint?: StainTint\n}\n\nexport interface FilmBridgeOptions {\n fluids: FluidWorld\n manager: FilmManager\n /** The seeded stream that spreads the drops (the film never calls `Math.random`). */\n random: () => number\n /** Which film profile a world liquid runs as: by default the liquids that have one (`blood`, `old_blood`, `bile`, `motor_oil`, `fuel`). Map `diesel` to `fuel`, say. */\n liquids?: Readonly<Record<string, LiquidId>>\n /** Litres of one drop of a leak (default 0.00015). */\n dropLiters?: number\n surfaceAt?: (point: Vec3) => FilmSurfaces | null\n}\n\nexport interface FilmBridge {\n /** Throws drops of a splash into the film. Returns how many found a grid. */\n splat(splat: FilmSplat): number\n /** Weather of the film (the Phase 6 hook): while it rains the film does not dry and spreads 1.5 times faster. */\n setWeather(weather: { rain: number }): void\n /** Streams of the world that feed the film right now. */\n readonly leaks: number\n /** Feeds the leaks: call it each frame with the frame's seconds, before or after `manager.update`. */\n update(dt: number): void\n dispose(): void\n}\n\nconst filmLiquids = (): Record<string, LiquidId> => Object.fromEntries(FILM_PROFILES.map((profile: FilmProfile) => [profile.id, profile.id]))\n\n/**\n * Joins a fluid world to the film: a `leak` of a liquid that has a film (blood, fuel, oil) drips onto the ground or wall below as drops thrown from the\n * hole, at the rate the world gives, until the stream ends. `splat` is what the characters use for a wound (with the colours of the infection age as\n * `tint`), and `setWeather` is the rain hook.\n */\nexport function createFilmBridge(options: FilmBridgeOptions): FilmBridge {\n const { fluids, manager, random } = options\n const liquids = options.liquids ?? filmLiquids()\n const dropLiters = options.dropLiters ?? DEFAULT_DROP_LITERS\n const leaks = new Map<string, { fluid: LiquidId; owed: number }>()\n\n const offLeak = fluids.on('leak', (event: FluidEvent) => {\n if (event.type !== 'leak') return\n const fluid = liquids[event.liquid]\n if (fluid) leaks.set(event.stream, { fluid, owed: 0 })\n })\n const offEnd = fluids.on('stream_end', (event: FluidEvent) => {\n if (event.type === 'stream_end') leaks.delete(event.stream)\n })\n\n const surfaces = (point: Vec3): FilmSurfaces | undefined => options.surfaceAt?.(point) ?? undefined\n\n return {\n get leaks() {\n return leaks.size\n },\n splat(splat) {\n const count = splat.count ?? 1\n const speed = splat.speed ?? DEFAULT_SPLAT_SPEED\n const direction = splat.direction ?? [0, -1, 0]\n const length = Math.hypot(direction[0], direction[1], direction[2]) || 1\n const velocity: Vec3 = [(direction[0] / length) * speed, (direction[1] / length) * speed, (direction[2] / length) * speed]\n let landed = 0\n for (let i = 0; i < count; i++) {\n const grid = manager.launch({\n fluid: splat.fluid,\n point: splat.point,\n velocity,\n radius: (splat.radius ?? DEFAULT_DROP_RADIUS) * (RADIUS_BASE + random() * RADIUS_SPREAD),\n ...(splat.surfaces ? { surfaces: splat.surfaces } : {}),\n ...(splat.tint ? { tint: splat.tint } : {}),\n })\n if (grid) landed++\n }\n return landed\n },\n setWeather: (weather) => manager.setWeather(weather),\n update(dt) {\n if (leaks.size === 0) return\n const streams = new Map(fluids.streams().map((stream) => [stream.id, stream]))\n for (const [id, leak] of leaks) {\n const stream = streams.get(id)\n if (!stream) continue\n leak.owed += (stream.rate * dt) / dropLiters\n let thrown = 0\n while (leak.owed >= 1 && thrown < MAX_DROPS_PER_FRAME) {\n leak.owed -= 1\n thrown++\n manager.launch({\n fluid: leak.fluid,\n point: stream.origin,\n velocity: stream.velocity,\n radius: DEFAULT_DROP_RADIUS * (RADIUS_BASE + random() * RADIUS_SPREAD),\n ...(surfaces(stream.origin) ? { surfaces: surfaces(stream.origin)! } : {}),\n })\n }\n if (thrown === MAX_DROPS_PER_FRAME) leak.owed = 0\n }\n },\n dispose() {\n offLeak()\n offEnd()\n leaks.clear()\n },\n }\n}\n"],"mappings":"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","names":["VISIBLE_THICKNESS","grid","FILM_PROFILES","DEFAULT_DROP_RADIUS"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adatechnology/game-fluids-three",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "three.js renderer for @adatechnology/game-fluids: liquid surfaces inside containers, streams with a drop at the tip, puddles that grow from a flow front, wet surfaces that reflect and dry from the edge.",
|
|
6
6
|
"keywords": [
|
|
@@ -38,7 +38,9 @@
|
|
|
38
38
|
"dist"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@adatechnology/game-fluids": "0.
|
|
41
|
+
"@adatechnology/game-fluids": "0.2.0",
|
|
42
|
+
"@adatechnology/game-vfx": "0.1.0",
|
|
43
|
+
"@adatechnology/game-vfx-three": "0.1.0"
|
|
42
44
|
},
|
|
43
45
|
"peerDependencies": {
|
|
44
46
|
"three": "^0.160.0"
|