[
  {
    "path": ".gitignore",
    "content": "\n# Generated by Cargo\n# will have compiled files and executables\n/target/\n\n# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries\n# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html\nCargo.lock\n\n# These are backup files generated by rustfmt\n**/*.rs.bk\n\n.cargo/config.toml"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"bevy_shadertoy_wgsl\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Eliot Bolduc\"]\n\n[dependencies]\nbytemuck = \"1.5\"\nrand = \"0.8\"\nrand_pcg = \"0.3\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nanyhow = \"1.0\"\nron = \"0.7\"\nbitflags = \"1.3\"\nbevy = \"0.8\"\ncrevice = \"0.11\"\n\n\n\n[[bin]]\nedition = \"2021\"\nname = \"bevy_shadertoy_wgsl\"\npath = \"src/main.rs\"\n\n# cargo build --release --target wasm32-unknown-unknown \n# wasm-bindgen --out-name wasm_shadertoy --out-dir wasm --target web target/wasm32-unknown-unknown/release/bevy_shadertoy_wgsl.wasm\n[[example]]\nname = \"simpler_particles\"\npath = \"examples/simpler_particles/simpler_particles.rs\"\n\n[[example]]\nname = \"liquid_toy\"\npath = \"examples/liquid_toy/liquid_toy.rs\"\n\n[[example]]\nname = \"soul\"\npath = \"examples/soul/soul.rs\"\n\n\n[[example]]\nname = \"paint_streams\"\npath = \"examples/paint_streams/paint_streams.rs\"\n\n[[example]]\nname = \"minimal\"\npath = \"examples/minimal/minimal.rs\"\n\n[[example]]\nname = \"paint\"\npath = \"examples/paint/paint.rs\"\n\n[[example]]\nname = \"protean_clouds\"\npath = \"examples/protean_clouds/protean_clouds.rs\"\n\n[[example]]\nname = \"seascape\"\npath = \"examples/seascape/seascape.rs\"\n\n[[example]]\nname = \"fluid\"\npath = \"examples/fluid/fluid.rs\"\n\n[[example]]\nname = \"fire2\"\npath = \"examples/fire2/fire2.rs\"\n\n[[example]]\nname = \"fire\"\npath = \"examples/fire/fire.rs\"\n\n[[example]]\nname = \"dry_ice\"\npath = \"examples/dry_ice/dry_ice.rs\"\n\n[[example]]\nname = \"sunset\"\npath = \"examples/sunset/sunset.rs\""
  },
  {
    "path": "LICENSES",
    "content": "bevy_shadertoy_wgsl is dual-licensed under either\n\n* MIT License (docs/LICENSE-MIT or <http://opensource.org/licenses/MIT>)\n* Apache License, Version 2.0 (docs/LICENSE-APACHE or <http://www.apache.org/licenses/LICENSE-2.0>)\n\nat your option.\n//\n//\n//\n//\n\nThe licenses for the examples taken from shadertoy.com are the following:\n\nseascape ->         Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\nfire2 ->            MIT License\nprotean_clouds ->   License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\nsunset ->           MIT License\nfluid ->            License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\npaint_streams ->    License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\ndry_ice ->          License Creative Commons Attribution-NonCommercial-ShareAlike 3.0\nsoul ->             Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0)\nliquid_toy ->       Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0)\n\nauthors (full name or Shadertoy username):\nseascape ->         TDM\nfire2 ->            Ian McEwan, Ashima Arts\nprotean_clouds ->   nimitz\nsunset ->           Dimas Leenman\nfluid ->            Wyatt Flanders\npaint_streams ->    michael0884\ndry_ice ->          David Gallardo\nsoul ->             leon\nliquid_toy ->       leon\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nlink to licenses:\n<https://creativecommons.org/licenses/by-nc/2.0/>\n<https://creativecommons.org/licenses/by-nc-sa/3.0/>\n"
  },
  {
    "path": "README.md",
    "content": "# bevy_shadertoy_wgsl\n\nA Shadertoy clone for the Bevy game engine, where the glsl language is replaced by wgsl.\n\n\nClone the repo, and for example run the following command:\n```\ncargo run --release --features bevy/dynamic --example paint_streams\n```\n![](showcase.gif)\n\nHere is a GLSL to WGLSL converter that might be helpful: [https://eliotbo.github.io/glsl2wgsl/](https://eliotbo.github.io/glsl2wgsl/)\n\nTODO: make compatible with WASM\n\nSee the LICENSES file for the individual examples.\n"
  },
  {
    "path": "assets/shaders/clouds/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/clouds/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/clouds/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/clouds/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/clouds/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// [[group(0), binding(1)]]\n// var buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(2)]]\n// var buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(3)]]\n// var buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(4)]]\n// var buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n[[group(0), binding(8)]]\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n[[group(0), binding(9)]]\nvar rgba_noise_256_texture_sampler: sampler;\n\n\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n\n\n\n// Sample Pinning\n// https://www.shadertoy.com/view/XdfXzn\n// MIT License\n\nvar<private> STRUCTURED: bool;\nvar<private> sundir: vec3<f32>;\nfn noise(x: vec3<f32>) -> f32 {\n\tvar p: vec3<f32> = floor(x);\n\tvar f: vec3<f32> = fract(x);\n\tf = f * f * (3. - 2. * f);\n\tlet uv: vec2<f32> = p.xy + vec2<f32>(37., 17.) * p.z + f.xy;\n\t// let rg: vec2<f32> = textureLod(iChannel0, (uv + 0.5) / 256., 0.).yx;\n    // let rg: vec2<f32> = textureLoad(rgba_noise_256_texture, vec2<i32>((uv + 0.5) ), 0).yx;\n\n    let rg: vec2<f32> = textureSampleLevel(\n        rgba_noise_256_texture,\n        rgba_noise_256_texture_sampler,\n        (uv + 0.5) / 256.,\n        0.\n    ).yx ;\n\n\treturn mix(rg.x, rg.y, f.z);\n} \n\nfn map(p: vec3<f32>) -> vec4<f32> {\n\tvar d: f32 = 0.1 + 0.8 * sin(0.6 * p.z) * sin(0.5 * p.x) - p.y;\n\tvar q: vec3<f32> = p;\n\tvar f: f32;\n\tf = 0.5 * noise(q);\n\tq = q * 2.02;\n\tf = f + (0.25 * noise(q));\n\tq = q * 2.03;\n\tf = f + (0.125 * noise(q));\n\tq = q * 2.01;\n\tf = f + (0.0625 * noise(q));\n\td = d + (2.75 * f);\n\td = clamp(d, 0., 1.);\n\tvar res: vec4<f32> = vec4<f32>(d);\n\tvar col: vec3<f32> = 1.15 * vec3<f32>(1., 0.95, 0.8);\n\tcol = col + (vec3<f32>(1., 0., 0.) * exp2(res.x * 10. - 10.));\n\tvar resxyz = res.xyz;\n\tresxyz = mix(col, vec3<f32>(0.7, 0.7, 0.7), res.x);\n\tres.x = resxyz.x;\n\tres.y = resxyz.y;\n\tres.z = resxyz.z;\n\treturn res;\n} \n\nfn mysign(x: f32) -> f32 {\n\n\tif (x < 0.) { return -1.; } else { return 1.; };\n} \n\nfn mysign2(x: vec2<f32>) -> vec2<f32> {\n    var x2: vec2<f32>;\n    if (x.x < 0.) { x2.x = -1.; } else { x2.x =1.; };\n    if (x.y < 0.) { x2.y = -1.; } else { x2.y = 1.; }\n\treturn x2;\n} \n\nfn SetupSampling(t: ptr<function, vec2<f32>>, dt: ptr<function, vec2<f32>>, wt: ptr<function, vec2<f32>>, ro: vec3<f32>, rd: vec3<f32>)  {\n\tvar rd_var = rd;\n\tif (!STRUCTURED) {\n\t\t(*dt) = vec2<f32>(1., 1.);\n\t\t(*t) = (*dt);\n\t\t(*wt) = vec2<f32>(0.5, 0.5);\n\t\treturn ;\n\t}\n\tvar n0: vec3<f32>; \n    if (abs(rd_var.x) > abs(rd_var.z)) { n0 = vec3<f32>(1., 0., 0.); } else { n0 = vec3<f32>(0., 0., 1.); };\n\n\tvar n1: vec3<f32> = vec3<f32>(mysign(rd_var.x * rd_var.z), 0., 1.);\n\tlet ln: vec2<f32> = vec2<f32>(length(n0), length(n1));\n\tn0 = n0 / (ln.x);\n\tn1 = n1 / (ln.y);\n\tlet ndotro: vec2<f32> = vec2<f32>(dot(ro, n0), dot(ro, n1));\n\tvar ndotrd: vec2<f32> = vec2<f32>(dot(rd_var, n0), dot(rd_var, n1));\n\tlet period: vec2<f32> = ln * 1.;\n\t(*dt) = period / abs(ndotrd);\n\tlet dist: vec2<f32> = abs(ndotro / ndotrd);\n\t(*t) = -mysign2(ndotrd) * (ndotro % period) / abs(ndotrd);\n\n\tif (ndotrd.x > 0.) { (*t).x = (*t).x + ((*dt).x); }\n\tif (ndotrd.y > 0.) { (*t).y = (*t).y + ((*dt).y); }\n\tlet minperiod: f32 = 1.;\n\tlet maxperiod: f32 = sqrt(2.) * 1.;\n\t(*wt) = smoothStep(vec2<f32>(maxperiod), vec2<f32>(minperiod), (*dt) / ln);\n\t(*wt) = (*wt) / ((*wt).x + (*wt).y);\n} \n\nfn raymarch(ro: vec3<f32>, rd: vec3<f32>) -> vec4<f32> {\n\tvar sum: vec4<f32> = vec4<f32>(0., 0., 0., 0.);\n\tvar t: vec2<f32>;\n\tvar dt: vec2<f32>;\n\tvar wt: vec2<f32>;\n\tSetupSampling(&t, &dt, &wt, ro, rd);\n\tlet f: f32 = 0.6;\n\tlet endFade: f32 = f * f32(40.) * 1.;\n\tlet startFade: f32 = 0.8 * endFade;\n\n\tfor (var i: i32 = 0; i < 40; i = i + 1) {\n\t\tif (sum.a > 0.99) {\t\tcontinue;\n }\n\t\tvar data: vec4<f32>;\n        if (t.x < t.y) { data = vec4<f32>(t.x, wt.x, dt.x, 0.); } else { data = vec4<f32>(t.y, wt.y, 0., dt.y); };\n\n\t\tlet pos: vec3<f32> = ro + data.x * rd;\n\t\tvar w: f32 = data.y;\n\t\tt = t + (data.zw);\n\t\tw = w * (smoothStep(endFade, startFade, data.x));\n\t\tvar col: vec4<f32> = map(pos);\n\t\tlet dif: f32 = clamp((col.w - map(pos + 0.6 * sundir).w) / 0.6, 0., 1.);\n\t\tlet lin: vec3<f32> = vec3<f32>(0.51, 0.53, 0.63) * 1.35 + 0.55 * vec3<f32>(0.85, 0.57, 0.3) * dif;\n\t\tvar colxyz = col.xyz;\n\tcolxyz = col.xyz * (lin);\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\t\tvar colxyz = col.xyz;\n\tcolxyz = col.xyz * (col.xyz);\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\t\tcol.a = col.a * (0.75);\n\t\tvar colrgb = col.rgb;\n\tcolrgb = col.rgb * (col.a);\n\tcol.r = colrgb.r;\n\tcol.g = colrgb.g;\n\tcol.b = colrgb.b;\n\t\tsum = sum + (col * (1. - sum.a) * w);\n\t}\n\n\tvar sumxyz = sum.xyz;\n\tsumxyz = sum.xyz / (0.001 + sum.w);\n\tsum.x = sumxyz.x;\n\tsum.y = sumxyz.y;\n\tsum.z = sumxyz.z;\n\treturn clamp(sum, vec4<f32>(0.), vec4<f32>(1.));\n} \n\nfn sky(rd: vec3<f32>) -> vec3<f32> {\n\tvar col: vec3<f32> = vec3<f32>(0.);\n\tlet hort: f32 = 1. - clamp(abs(rd.y), 0., 1.);\n\tcol = col + (0.5 * vec3<f32>(0.99, 0.5, 0.) * exp2(hort * 8. - 8.));\n\tcol = col + (0.1 * vec3<f32>(0.5, 0.9, 1.) * exp2(hort * 3. - 3.));\n\tcol = col + (0.55 * vec3<f32>(0.6, 0.6, 0.9));\n\tlet sun: f32 = clamp(dot(sundir, rd), 0., 1.);\n\tcol = col + (0.2 * vec3<f32>(1., 0.3, 0.2) * pow(sun, 2.));\n\tcol = col + (0.5 * vec3<f32>(1., 0.9, 0.9) * exp2(sun * 650. - 650.));\n\tcol = col + (0.1 * vec3<f32>(1., 1., 0.1) * exp2(sun * 100. - 100.));\n\tcol = col + (0.3 * vec3<f32>(1., 0.7, 0.) * exp2(sun * 50. - 50.));\n\tcol = col + (0.5 * vec3<f32>(1., 0.3, 0.05) * exp2(sun * 10. - 10.));\n\tlet ax: f32 = atan2(rd.y, length(rd.xz)) / 1.;\n\tlet ay: f32 = atan2(rd.z, rd.x) / 2.;\n    \n\tvar st: f32 = textureLoad(rgba_noise_256_texture, vec2<i32>(vec2<f32>(ax, ay) * 255.), 0 ).x;\n\n\tlet st2: f32 = textureLoad(rgba_noise_256_texture, vec2<i32>(0.25 * vec2<f32>(ax, ay) * 255.), 0 ).x;\n\tst = st * (st2);\n\tst = smoothStep(0.65, 0.9, st);\n\tcol = mix(col, col + 1.8 * st, clamp(1. - 1.1 * length(col), 0., 1.));\n\treturn col;\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tSTRUCTURED = uni.iMouse.z <= 0.;\n\tsundir = normalize(vec3<f32>(-1., 0., -1.));\n\tlet q: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\tvar p: vec2<f32> = -1. + 2. * q;\n\tp.x = p.x * (uni.iResolution.x / uni.iResolution.y);\n\tlet mo: vec2<f32> = -1. + 2. * uni.iMouse.xy / uni.iResolution.xy;\n\tlet lookDir: vec3<f32> = vec3<f32>(cos(0.53 * uni.iTime), 0., sin(uni.iTime));\n\tlet camVel: vec3<f32> = vec3<f32>(-20., 0., 0.);\n\tlet ro: vec3<f32> = vec3<f32>(0., 1.5, 0.) + uni.iTime * camVel;\n\tlet ta: vec3<f32> = ro + lookDir;\n\tlet ww: vec3<f32> = normalize(ta - ro);\n\tlet uu: vec3<f32> = normalize(cross(vec3<f32>(0., 1., 0.), ww));\n\tlet vv: vec3<f32> = normalize(cross(ww, uu));\n\tlet fov: f32 = 1.;\n\tlet rd: vec3<f32> = normalize(fov * p.x * uu + fov * 1.2 * p.y * vv + 1.5 * ww);\n\tvar clouds: vec4<f32> = raymarch(ro, rd);\n\tvar col: vec3<f32> = clouds.xyz;\n\tif (clouds.w <= 0.99) { col = mix(sky(rd), col, clouds.w); }\n\tcol = clamp(col, vec3<f32>(0.), vec3<f32>(1.));\n\tcol = smoothStep(vec3<f32>(0.), vec3<f32>(1.), col);\n\tcol = col * (pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), 0.12));\n\t// (*fragColor) = vec4<f32>(col, 1.);\n    textureStore(texture, y_inverted_location, vec4<f32>(col, 1.));\n\n    let test: vec4<f32> = textureSampleLevel(\n        rgba_noise_256_texture,\n        rgba_noise_256_texture_sampler,\n        vec2<f32>(location) / R * 2.0,\n        0.\n    ) ;\n\n    // textureStore(texture, y_inverted_location, test);\n\n\n} \n\n\n\n\n    \n\n\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n//     let R: vec2<f32> = uni.iResolution.xy;\n//     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n// \tif (uni.iMouse.z > 0.) { useNewApproach = false; }\n// \tlet q: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n// \tvar p: vec2<f32> = -1. + 2. * q;\n// \tp.x = p.x * (uni.iResolution.x / uni.iResolution.y);\n// \tlet mo: vec2<f32> = -1. + 2. * uni.iMouse.xy / uni.iResolution.xy;\n// \tlet ro: vec3<f32> = vec3<f32>(0., 1.9, 0.) + uni.iTime * camVel;\n// \tlet ta: vec3<f32> = ro + lookDir;\n// \tlet ww: vec3<f32> = normalize(ta - ro);\n// \tlet uu: vec3<f32> = normalize(cross(vec3<f32>(0., 1., 0.), ww));\n// \tlet vv: vec3<f32> = normalize(cross(ww, uu));\n// \tlet rd: vec3<f32> = normalize(p.x * uu + 1.2 * p.y * vv + 1.5 * ww);\n// \tvar col: vec3<f32> = sky(rd);\n// \tlet rd_layout: vec3<f32> = rd / mix(dot(rd, ww), 1., samplesCurvature);\n// \tlet clouds: vec4<f32> = raymarch(ro, rd_layout);\n// \tcol = mix(col, clouds.xyz, clouds.w);\n// \tcol = clamp(col, 0., 1.);\n// \tcol = smoothStep(0., 1., col);\n// \tcol = col * (pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), 0.12));\n// \t// (*fragColor) = vec4<f32>(col, 1.);\n//     textureStore(texture, y_inverted_location, vec4<f32>(col, 1.));\n\n    \n// } \n\n"
  },
  {
    "path": "assets/shaders/dancing_tree/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/dancing_tree/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/dancing_tree/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/dancing_tree/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/dancing_tree/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n[[group(0), binding(8)]]\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n[[group(0), binding(9)]]\nvar rgba_noise_256_texture_sampler: sampler;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n// Why are the characters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\nlet backColorDebug: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n\nvar<private> uv_debug: vec2<f32> ;\nvar<private> tp_debug: vec2<f32> ;\nvar<private> align_debug: vec4<f32>; // north, east, south, west\nvar<private> font_size_debug: f32;\nvar<private> dotColor_debug: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\nvar<private> drawColorDebug: vec3<f32> = vec3<f32>(1., 1., 0.);\nvar<private> vColor: vec3<f32> = backColorDebug;\nvar<private> aspect_debug: f32 = 1.;\nvar<private> pixelPosDebug: vec2<f32> = vec2<f32>(0., 0.);\n\nlet FONT_SPACE_DEBUG: f32 = 0.5;\nlet headColorDebug: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\nlet mpColorDebug: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\nlet mxColorDebug: vec3<f32> = vec3<f32>(1., 0., 0.);\nlet myColorDebug: vec3<f32> = vec3<f32>(0., 1., 0.);\nlet font_png_size_debug: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\nfn char(ch: i32) -> f32 {\n\n    let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n\tlet q = clamp(tp_debug, vec2<f32>(0.), vec2<f32>(1.)) / 16. + fr ;\n\tlet inverted_q = vec2<f32>(q.x, 1. - q.y);\n\n\t// // There is aliasing on the characters\n\t// let f = textureSampleGrad(font_texture,\n    //                  font_texture_sampler,\n    //                  inverted_q,\n    //                   vec2<f32>(1.0, 0.0),\n    //                  vec2<f32>(0.0, 1.0));\n\n\t// using textureLoad without sampler\n    let q1 = vec2<i32>(font_png_size_debug  * q );\n\tlet y_inverted_q1 = vec2<i32>(q1.x, i32(font_png_size_debug.y) - q1.y);\n\n\tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n\t// smoothing out the aliasing\n\tlet dx = vec2<i32>(1, 0);\n\tlet dy = vec2<i32>(0, 1);\n\n\tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n\tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n\tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n\tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n\tlet rp = 0.25;\n\tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n\treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n} \n\nfn SetTextPosition(x: f32, y: f32)  {\n\ttp_debug =  10. * uv_debug;\n\ttp_debug.x = tp_debug.x + 17. - x;\n\ttp_debug.y = tp_debug.y - 9.4 + y;\n} \n\nfn SetTextPositionAbs(x: f32, y: f32)  {\n\ttp_debug.x = 10. * uv_debug.x - x;\n\ttp_debug.y = 10. * uv_debug.y - y;\n} \n\nfn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\t*value = fract(*value) * 10.;\n\n\tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n\t\tc = c + (char(48 + i32(*value)));\n\t\ttp_debug.x = tp_debug.x - (0.5);\n\t\t*digits = *digits - (1);\n\t\t*value = fract(*value) * 10.;\n\n\t\tif (*digits <= 0 || *value == 0.) {\t\t\n            break;\n        }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(*digits));\n\treturn c;\n} \n\nfn maxInt(a: i32, b: i32) -> i32 {\n    var ret: i32;\n    if (a > b) { ret = a; } else { ret = b; };\n\treturn ret;\n} \n\nfn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\tc = c + (char(45));\n\t\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni >= digits) {\t\tbreak; }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\treturn c;\n} \n\nfn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tlet original_value: i32 = *value;\n\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\t// tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\t// c = c + (char(45));\n\t\t\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\t// tp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni == 0) {\t\tbreak; }\n\t}\n\n\tif (original_value < 0) {\n\t\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\tc = c + (char(45));\n\t}\n\n\t// tp_debug.x = tp_debug.x + (0.5 * f32(digits));\n\treturn c;\n} \n\n// fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\nfn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n\t// in case of 0.099999..., round up to 0.1000000\n\tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n\tlet tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits);\n\tvar c: f32 = 0.;\n\tif (value < 0.) {\n\t\tc = char(45);\n\t\tvalue = -value;\n\t}\n\ttp_debug.x = tp_debug.x - (0.5);\n    var ival = i32(value);\n\n    var one: i32 = 1;\n\n\tc = c + (drawInt(&ival, &one));\n\tc = c + (char(46));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n    var frac_val = fract(value);\n\tc = c + (drawFract(&frac_val, prec));\n\ttp_debug.x = min(tp_debug.x, tp_debugx);\n\n\treturn c;\n}\n\nfn drawFloat_f32(value:  f32) -> f32 {\n    var two: i32 = 2;\n\treturn drawFloat(value, &two, 5);\n} \n\nfn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n\treturn drawFloat(value, prec, 2);\n} \n\nfn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawIntBackwards(value, &one);\n} \n\nfn drawInt_i32(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawInt(value, &one);\n} \n\n\n\n\n\nfn SetColor(red: f32, green: f32, blue: f32)  {\n\tdrawColorDebug = vec3<f32>(red, green, blue);\n} \n\nfn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n\t// vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces));\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteFloatBox(\n\tfValue: f32, \n\tmaxDigits: i32, \n\tdecimalPlaces: i32, \n\talpha: f32\n)  {\n\tvar decs = decimalPlaces;\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha);\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteInteger(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32(iValue));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n} \n\nfn WriteIntegerBack(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue));\n\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\n} \n\n\n\nfn WriteFPS()  {\n\tvar fps: f32 = f32(uni.iSampleRate);\n\tSetColor(0.8, 0.6, 0.3);\n\tvar max_digits_one = 1;\n\tWriteFloat(fps, 5, &max_digits_one);\n\tvar c: f32 = 0.;\n\tc = c + (char(102));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(112));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(115));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\t// let c2 = smoothStep(0.0, 1.0, c );\n\n\tvColor = mix(vColor, drawColorDebug, c);\n} \n\nfn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n\tlet digits: i32 = 3;\n\tlet radius: f32 =  uni.iResolution.x / 400.;\n\tif (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; }\n\tlet r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius;\n\t// vColor = vColor + (mix(vec3<f32>(0.), dotColor_debug, 1. - clamp(r, 0., 1.)));\n\n\tvar max_digits_three: i32 = 3;\n\tvar mposxi: i32 = i32(mPos.x);\n\tvar mposyi: i32 = i32(mPos.y);\n\n\tvar mposx: f32 = (mPos.x);\n\tvar mposy: f32 = (mPos.y);\n\n\n\tlet x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG;\n\t\t\n\tSetTextPositionAbs(\n\t\t x_pos,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = myColorDebug;\n\tWriteIntegerBack(&mposyi);\n\n\tSetTextPositionAbs(\n\t\t x_pos - 7. *  FONT_SPACE_DEBUG,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = mxColorDebug;\n\n\tWriteIntegerBack(&mposxi);\n\n} \n\n\nfn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n  var x = r.x;\n  var y = r.y;\n  x = select(r.z, r.x, p.x > 0.);\n  y = select(r.w, r.y, p.x > 0.);\n  x  = select(y, x, p.y > 0.);\n  let q = abs(p) - b + x;\n  return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n}\n\n\n\nfn WriteRGBAValues(\n\tlocation: vec2<i32>, \n\tvalue: vec4<f32>, \n\tscreen_poz: vec2<f32>,\n\talpha: f32,\n )  {\n\tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect_debug, 1.0);\n\tlet window_ajusted = uni.iResolution / vec2<f32>(960., 600.);\n\n\tlet box_pos = vec2<f32>(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.;\n\t// let box_pos = mp;\n\n\t// // box location follows mouse position\n\t// let box_location = vec2<f32>(\n\t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t// \tuni.iMouse.y - 48. * window_ajusted.y\n\t// );\n\n\n\tlet box_location  = vec2<f32>(\n\t\t100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t\tuni.iResolution.y - 60. * window_ajusted.y,\n\t);\n\t\n\tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect_debug, 1.) ;\n\n\tlet d_box = sdRoundedBox(\n\t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n\t\t vec2<f32>(73. /  ( aspect_debug / 1.6 ), 75.) * window_ajusted, \n\t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n\t);\n\n\t// let alpha = 0.225;\n\tlet decimal_places = 3;\n\tSetColor(1., 1., 1.);\n\tvar c: f32 = 0.;\n\tlet lspace = 0.8;\n\n\tlet bg_color = vec3<f32>(.8, .7, .9);\n\tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n\t// red\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n\t) ;\n\tc = c + (char(114)); // r\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n\t// green\n\tSetTextPosition(\n\t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n\t) ;\n\tc = c + (char(103)); // g\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n\t// blue\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n\t\t) ;\n\tc = c + (char(98)); // b\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n\t// alpha\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n\t) ;\n\tc = c + (char(97)); // a\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n\tvColor = mix(vColor, drawColorDebug, c * alpha);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n\treturn mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius)));\n} \n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\nfn draw_ring(location: vec2<i32>) {\n\tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n\tlet alpha = 0.75;\n\tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n\tlet d = smoothStep(0.5, 1.5, abs(ring_dist - 1.));\n\tvColor = mix(vColor, headColorDebug,   (1. - d) * alpha );\n}\n\nfn draw_crossair(location: vec2<i32>)  {\n\n\tlet start = 5.0;\n\tlet end = 20.;\n\tlet segment1 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(start, 0.), \n\t\tvec2<f32>(end, 0.)\n\t);\n\n\tlet segment2 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(-start, 0.), \n\t\tvec2<f32>(-end, 0.)\n\t);\n\n\tlet segment3 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., start), \n\t\tvec2<f32>(0., end)\n\t);\n\n\tlet segment4 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., -start), \n\t\tvec2<f32>(0., -end)\n\t);\n\n\tvar alpha = 0.75;\n\tif (uni.iMouse.z > 0.) {\n\t\talpha = 1.0;\n\t}\n\n\tlet d = smoothStep(0.5, 1.5, segment1);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment2);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment3);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment4);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n}\n\nfn show_debug_info(location: vec2<i32>, color: vec3<f32>) -> vec4<f32> {    \n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    vColor = color;\n\n\n\taspect_debug =  uni.iResolution.x /  uni.iResolution.y;\n\n\tlet ratio: vec2<f32> = vec2<f32>(aspect_debug, 1.);\n\tpixelPosDebug = fragCoord.xy;\n\t// mousePosDebug = uni.iMouse.xy;\n\tuv_debug = (2. * fragCoord.xy /  uni.iResolution.xy - 1.) * ratio;\n\n\talign_debug = 10. * vec4<f32>(\n\t\t1.,      // North\n\t\taspect_debug,  // East\n\t\t-1.,     // South\n\t\t-aspect_debug, // West\n\t);\n\n\n\tWriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position\n\tWriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position\n\n\tvar c: f32 = 0.;\n\n\tSetTextPositionAbs(\n\t\t align_debug.y -      FONT_SPACE_DEBUG,\n\t\t align_debug.x - 2. * FONT_SPACE_DEBUG,\n\t);\n\n\tSetColor(0.8, 0.8, 0.8);\n\tvar resx = i32(uni.iResolution.x);\n\tvar resy = i32(uni.iResolution.y);\n\n\n\tWriteIntegerBack(&resx);\n\tc = c + (char(28));\n\ttp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG);\n\tWriteIntegerBack(&resy);\n\n\n\tSetTextPositionAbs(\n\t\t align_debug.w - 1. * FONT_SPACE_DEBUG,\n\t\t align_debug.z - 0. * FONT_SPACE_DEBUG,\n\t);\n\n\tWriteFPS();\n\tSetColor(0.9, 0.7, 0.8);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n\t// // RGBA probe labels follow mouse\n\t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n\tlet inverted_y_mouse_location = vec2<i32>(vec2<f32>(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n\tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n\tWriteRGBAValues(location, value, poz, 0.85);\n\n\tlet inverted_y_mouseclick_location = vec2<i32>(vec2<f32>(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n\tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n\tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.65);\n\n\tdraw_crossair(location);\n\n\tdraw_ring(location);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\t\n\n\treturn fragColor;\n} \n\n\n\n\n// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n// TODO: \n//\n// 1. ar<private> light: vec3<f32>; for global variables\n//\n// 2. p.xy = ...\n// pattern -> \n//  var pxy = p.xy;\n//  pxy = pxy * matrix;\n//  p.x = pxy.x;\n//  p.y = pxy.y ;\n\nlet pi = 3.1415926;\ntype v2 = vec2<f32>;\n\nvar<private> light: vec3<f32>;\n\nfn ln(p2: vec3<f32>, a: vec3<f32>, b: vec3<f32>, R: f32) -> f32 {\n\tvar r: f32 = dot(p2 - a, b - a) / dot(b - a, b - a);\n\tr = clamp(r, 0., 1.);\n    var p = p2;\n\tp.x = p.x + (0.2 * sqrt(R) * smoothStep(1., 0., abs(r * 2. - 1.)) * cos(pi * (2. * uni.iTime)));\n\treturn length(p - a - (b - a) * r) - R * (1.5 - 0.4 * r);\n\n} \n\nfn ro(a: f32) -> mat2x2<f32> {\n\tlet s: f32 = sin(a);\n\tlet c: f32 = cos(a);\n\treturn mat2x2<f32>(c, -s, s, c);\n\n} \n\nfn map(p2: vec3<f32>) -> f32 {\n    var p = p2;\n\tvar l: f32 = length(p - light) - 0.01;\n\tl = min(l, abs(p.y + 0.4) - 0.01);\n\tl = min(l, abs(p.z - 0.4) - 0.01);\n\tl = min(l, abs(p.x - 0.7) - 0.01);\n\tp.y = p.y + (0.4);\n\tp.z = p.z + (0.1);\n    var pzx = p.zx;\n    pzx = pzx * ro(0.1 * uni.iTime);\n\n\tp.z = pzx.x;\n    p.x = pzx.y;\n\n\tvar rl: vec2<f32> = vec2<f32>(0.02, 0.25 + 0.01 * sin(pi * 4. * uni.iTime));\n\tfor (var i: i32 = 1; i < 11; i = i + 1) {\n\t\tl = min(l, ln(p, vec3<f32>(0.), vec3<f32>(0., rl.y, 0.), rl.x));\n\t\tp.y = p.y - (rl.y);\n\n        var pxy = p.xy;\n        pxy = pxy * (ro(0.2 * sin(3.1 * uni.iTime + f32(i)) + sin(0.222 * uni.iTime) * (-0.1 * sin(0.4 * pi * uni.iTime) + sin(0.543 * uni.iTime) / max(f32(i), 2.))));\n\t\tp.x = pxy.x;\n        p.y = pxy.y ;\n\t\tp.x = abs(p.x);\n\n        var pxy = p.xy;\n        pxy = pxy *(ro(0.6 + 0.4 * sin(uni.iTime) * sin(0.871 * uni.iTime) + 0.05 * f32(i) * sin(2. * uni.iTime)));\n\t\tp.x = pxy.x ; \n\t\tp.y = pxy.y ;\n\t\t\n        var pzx = p.zx;\n        pzx = pzx * (ro(0.5 * pi + 0.2 * sin(0.5278 * uni.iTime) + 0.8 * f32(i) * (sin(0.1 * uni.iTime) * (sin(0.1 * pi * uni.iTime) + sin(0.333 * uni.iTime) + 0.2 * sin(1.292 * uni.iTime)))));\n        p.z = pzx.x;  \n\t\tp.x = pzx.y; \n\t\t\n        rl = rl * (0.7 + 0.015 * f32(i) * (sin(uni.iTime) + 0.1 * sin(4. * pi * uni.iTime)));\n\t\tl = min(l, length(p) - 0.15 * sqrt(rl.x));\n\t\n\t}\treturn l;\n\n} \n\nfn march(p2: vec3<f32>, d: vec3<f32>) -> vec3<f32> {\n\tlet o: f32 = 1000.;\n    var p = p2;\n\tfor (var i: i32 = 0; i < 24; i = i + 1) {\n\t\tlet l: f32 = map(p);\n\t\tp = p + (l * d);\n\t\tif (l < 0.001) {\t\tbreak;\n\t\t}\n\t\n\t}\treturn p;\n\n} \n\nfn norm(p: vec3<f32>) -> vec3<f32> {\n\tlet e: vec2<f32> = vec2<f32>(0.001, 0.);\n\treturn normalize(vec3<f32>(map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx)));\n\n} \n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\tlet y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n\n\tlight = vec3<f32>(0.2 * sin(uni.iTime), 0.5, -0.5);\n\tif (uni.iMouse.z > 0.) {\t\n        light = vec3<f32>(vec2<f32>(-0.5, 0.5) * 0. + 0.7 * (uni.iMouse.xy - 0.5 * R) / R.y, -0.3);\n\t}\n\t\n    var U = (vec2<f32>(location) - 0.5 * R) / R.y;\n    // U = vec2<f32>(U.x, -U.y);\n\n\tvar p: vec3<f32> = vec3<f32>(0., 0., -1.);\n\tvar d: vec3<f32> = normalize(vec3<f32>(U, 1.));\n\tp = march(p, d);\n\tlet n: vec3<f32> = norm(p);\n\tvar C = 0.6 + 0.4 * sin(1.1 * vec4<f32>(1., 2., 3., 4.) * dot(d, n));\n\tlet D: vec3<f32> = light - p;\n\td = normalize(D);\n\tlet lp: vec3<f32> = march(p + d * 0.01, d);\n\tC = C * (2.5 * dot(d, n) * (0.3 + 0.7 * length(lp - p) / length(light - p)));\n\tC = atan(C) / pi * 2.;\n\n\n\ttextureStore(texture, y_inverted_location, C);\n\n\n} \n\n"
  },
  {
    "path": "assets/shaders/debugger/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/debugger/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/debugger/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/debugger/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/debugger/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n// Why are the characters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\nlet backColorDebug: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n\nvar<private> uv_debug: vec2<f32> ;\nvar<private> tp_debug: vec2<f32> ;\nvar<private> align_debug: vec4<f32>; // north, east, south, west\nvar<private> font_size_debug: f32;\nvar<private> dotColor_debug: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\nvar<private> drawColorDebug: vec3<f32> = vec3<f32>(1., 1., 0.);\nvar<private> vColor: vec3<f32> = backColorDebug;\nvar<private> aspect_debug: f32 = 1.;\nvar<private> pixelPosDebug: vec2<f32> = vec2<f32>(0., 0.);\n\nlet FONT_SPACE_DEBUG: f32 = 0.5;\nlet headColorDebug: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\nlet mpColorDebug: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\nlet mxColorDebug: vec3<f32> = vec3<f32>(1., 0., 0.);\nlet myColorDebug: vec3<f32> = vec3<f32>(0., 1., 0.);\nlet font_png_size_debug: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\nfn char(ch: i32) -> f32 {\n\n    let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n\tlet q = clamp(tp_debug, vec2<f32>(0.), vec2<f32>(1.)) / 16. + fr ;\n\tlet inverted_q = vec2<f32>(q.x, 1. - q.y);\n\n\t// // There is aliasing on the characters\n\t// let f = textureSampleGrad(font_texture,\n    //                  font_texture_sampler,\n    //                  inverted_q,\n    //                   vec2<f32>(1.0, 0.0),\n    //                  vec2<f32>(0.0, 1.0));\n\n\t// using textureLoad without sampler\n    let q1 = vec2<i32>(font_png_size_debug  * q );\n\tlet y_inverted_q1 = vec2<i32>(q1.x, i32(font_png_size_debug.y) - q1.y);\n\n\tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n\t// smoothing out the aliasing\n\tlet dx = vec2<i32>(1, 0);\n\tlet dy = vec2<i32>(0, 1);\n\n\tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n\tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n\tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n\tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n\tlet rp = 0.25;\n\tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n\treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n} \n\nfn SetTextPosition(x: f32, y: f32)  {\n\ttp_debug =  10. * uv_debug;\n\ttp_debug.x = tp_debug.x + 17. - x;\n\ttp_debug.y = tp_debug.y - 9.4 + y;\n} \n\nfn SetTextPositionAbs(x: f32, y: f32)  {\n\ttp_debug.x = 10. * uv_debug.x - x;\n\ttp_debug.y = 10. * uv_debug.y - y;\n} \n\nfn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\t*value = fract(*value) * 10.;\n\n\tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n\t\tc = c + (char(48 + i32(*value)));\n\t\ttp_debug.x = tp_debug.x - (0.5);\n\t\t*digits = *digits - (1);\n\t\t*value = fract(*value) * 10.;\n\n\t\tif (*digits <= 0 || *value == 0.) {\t\t\n            break;\n        }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(*digits));\n\treturn c;\n} \n\nfn maxInt(a: i32, b: i32) -> i32 {\n    var ret: i32;\n    if (a > b) { ret = a; } else { ret = b; };\n\treturn ret;\n} \n\nfn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\tc = c + (char(45));\n\t\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni >= digits) {\t\tbreak; }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\treturn c;\n} \n\nfn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tlet original_value: i32 = *value;\n\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\t// tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\t// c = c + (char(45));\n\t\t\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\t// tp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni == 0) {\t\tbreak; }\n\t}\n\n\tif (original_value < 0) {\n\t\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\tc = c + (char(45));\n\t}\n\n\t// tp_debug.x = tp_debug.x + (0.5 * f32(digits));\n\treturn c;\n} \n\n// fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\nfn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n\t// in case of 0.099999..., round up to 0.1000000\n\tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n\tlet tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits);\n\tvar c: f32 = 0.;\n\tif (value < 0.) {\n\t\tc = char(45);\n\t\tvalue = -value;\n\t}\n\ttp_debug.x = tp_debug.x - (0.5);\n    var ival = i32(value);\n\n    var one: i32 = 1;\n\n\tc = c + (drawInt(&ival, &one));\n\tc = c + (char(46));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n    var frac_val = fract(value);\n\tc = c + (drawFract(&frac_val, prec));\n\ttp_debug.x = min(tp_debug.x, tp_debugx);\n\n\treturn c;\n}\n\nfn drawFloat_f32(value:  f32) -> f32 {\n    var two: i32 = 2;\n\treturn drawFloat(value, &two, 5);\n} \n\nfn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n\treturn drawFloat(value, prec, 2);\n} \n\nfn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawIntBackwards(value, &one);\n} \n\nfn drawInt_i32(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawInt(value, &one);\n} \n\n\n\n\n\nfn SetColor(red: f32, green: f32, blue: f32)  {\n\tdrawColorDebug = vec3<f32>(red, green, blue);\n} \n\nfn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n\t// vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces));\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteFloatBox(\n\tfValue: f32, \n\tmaxDigits: i32, \n\tdecimalPlaces: i32, \n\talpha: f32\n)  {\n\tvar decs = decimalPlaces;\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha);\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteInteger(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32(iValue));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n} \n\nfn WriteIntegerBack(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue));\n\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\n} \n\n\n\nfn WriteFPS()  {\n\tvar fps: f32 = f32(uni.iSampleRate);\n\tSetColor(0.8, 0.6, 0.3);\n\tvar max_digits_one = 1;\n\tWriteFloat(fps, 5, &max_digits_one);\n\tvar c: f32 = 0.;\n\tc = c + (char(102));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(112));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(115));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\t// let c2 = smoothStep(0.0, 1.0, c );\n\n\tvColor = mix(vColor, drawColorDebug, c);\n} \n\nfn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n\tlet digits: i32 = 3;\n\tlet radius: f32 =  uni.iResolution.x / 400.;\n\tif (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; }\n\tlet r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius;\n\t// vColor = vColor + (mix(vec3<f32>(0.), dotColor_debug, 1. - clamp(r, 0., 1.)));\n\n\tvar max_digits_three: i32 = 3;\n\tvar mposxi: i32 = i32(mPos.x);\n\tvar mposyi: i32 = i32(mPos.y);\n\n\tvar mposx: f32 = (mPos.x);\n\tvar mposy: f32 = (mPos.y);\n\n\n\tlet x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG;\n\t\t\n\tSetTextPositionAbs(\n\t\t x_pos,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = myColorDebug;\n\tWriteIntegerBack(&mposyi);\n\n\tSetTextPositionAbs(\n\t\t x_pos - 7. *  FONT_SPACE_DEBUG,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = mxColorDebug;\n\n\tWriteIntegerBack(&mposxi);\n\n} \n\n\nfn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n  var x = r.x;\n  var y = r.y;\n  x = select(r.z, r.x, p.x > 0.);\n  y = select(r.w, r.y, p.x > 0.);\n  x  = select(y, x, p.y > 0.);\n  let q = abs(p) - b + x;\n  return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n}\n\n\n\nfn WriteRGBAValues(\n\tlocation: vec2<i32>, \n\tvalue: vec4<f32>, \n\tscreen_poz: vec2<f32>,\n\talpha: f32,\n )  {\n\tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect_debug, 1.0);\n\tlet window_ajusted = uni.iResolution / vec2<f32>(960., 600.);\n\n\tlet box_pos = vec2<f32>(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.;\n\t// let box_pos = mp;\n\n\t// // box location follows mouse position\n\t// let box_location = vec2<f32>(\n\t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t// \tuni.iMouse.y - 48. * window_ajusted.y\n\t// );\n\n\n\tlet box_location  = vec2<f32>(\n\t\t100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t\tuni.iResolution.y - 60. * window_ajusted.y,\n\t);\n\t\n\tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect_debug, 1.) ;\n\n\tlet d_box = sdRoundedBox(\n\t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n\t\t vec2<f32>(73. /  ( aspect_debug / 1.6 ), 75.) * window_ajusted, \n\t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n\t);\n\n\t// let alpha = 0.225;\n\tlet decimal_places = 3;\n\tSetColor(1., 1., 1.);\n\tvar c: f32 = 0.;\n\tlet lspace = 0.8;\n\n\tlet bg_color = vec3<f32>(.8, .7, .9);\n\tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n\t// red\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n\t) ;\n\tc = c + (char(114)); // r\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n\t// green\n\tSetTextPosition(\n\t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n\t) ;\n\tc = c + (char(103)); // g\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n\t// blue\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n\t\t) ;\n\tc = c + (char(98)); // b\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n\t// alpha\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n\t) ;\n\tc = c + (char(97)); // a\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n\tvColor = mix(vColor, drawColorDebug, c * alpha);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n\treturn mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius)));\n} \n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\nfn draw_ring(location: vec2<i32>) {\n\tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n\tlet alpha = 0.75;\n\tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n\tlet d = smoothStep(0.5, 1.5, abs(ring_dist - 1.));\n\tvColor = mix(vColor, headColorDebug,   (1. - d) * alpha );\n}\n\nfn draw_crossair(location: vec2<i32>)  {\n\n\tlet start = 5.0;\n\tlet end = 20.;\n\tlet segment1 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(start, 0.), \n\t\tvec2<f32>(end, 0.)\n\t);\n\n\tlet segment2 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(-start, 0.), \n\t\tvec2<f32>(-end, 0.)\n\t);\n\n\tlet segment3 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., start), \n\t\tvec2<f32>(0., end)\n\t);\n\n\tlet segment4 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., -start), \n\t\tvec2<f32>(0., -end)\n\t);\n\n\tvar alpha = 0.75;\n\tif (uni.iMouse.z > 0.) {\n\t\talpha = 1.0;\n\t}\n\n\tlet d = smoothStep(0.5, 1.5, segment1);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment2);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment3);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment4);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n}\n\nfn show_debug_info(location: vec2<i32>, color: vec3<f32>) -> vec4<f32> {    \n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    vColor = color;\n\n\n\taspect_debug =  uni.iResolution.x /  uni.iResolution.y;\n\n\tlet ratio: vec2<f32> = vec2<f32>(aspect_debug, 1.);\n\tpixelPosDebug = fragCoord.xy;\n\t// mousePosDebug = uni.iMouse.xy;\n\tuv_debug = (2. * fragCoord.xy /  uni.iResolution.xy - 1.) * ratio;\n\n\talign_debug = 10. * vec4<f32>(\n\t\t1.,      // North\n\t\taspect_debug,  // East\n\t\t-1.,     // South\n\t\t-aspect_debug, // West\n\t);\n\n\n\tWriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position\n\tWriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position\n\n\tvar c: f32 = 0.;\n\n\tSetTextPositionAbs(\n\t\t align_debug.y -      FONT_SPACE_DEBUG,\n\t\t align_debug.x - 2. * FONT_SPACE_DEBUG,\n\t);\n\n\tSetColor(0.8, 0.8, 0.8);\n\tvar resx = i32(uni.iResolution.x);\n\tvar resy = i32(uni.iResolution.y);\n\n\n\tWriteIntegerBack(&resx);\n\tc = c + (char(28));\n\ttp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG);\n\tWriteIntegerBack(&resy);\n\n\n\tSetTextPositionAbs(\n\t\t align_debug.w - 1. * FONT_SPACE_DEBUG,\n\t\t align_debug.z - 0. * FONT_SPACE_DEBUG,\n\t);\n\n\tWriteFPS();\n\tSetColor(0.9, 0.7, 0.8);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n\t// // RGBA probe labels follow mouse\n\t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n\tlet inverted_y_mouse_location = vec2<i32>(vec2<f32>(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n\tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n\tWriteRGBAValues(location, value, poz, 0.5);\n\n\tlet inverted_y_mouseclick_location = vec2<i32>(vec2<f32>(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n\tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n\tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.25);\n\n\tdraw_crossair(location);\n\n\tdraw_ring(location);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\treturn fragColor;\n} \n\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n// Why are the characters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\n// type ivec2 = vec2<i32>;\n// type v2 = vec2<f32>;\n\n// let backColor: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n// var<private> R: vec2<f32>;\n// var<private> uv: vec2<f32> ;\n// var<private> tp: vec2<f32> ;\n// var<private> alignment: vec4<f32>; // north, east, south, west\n// var<private> font_size: f32;\n// var<private> dotColor: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\n// var<private> drawColor: vec3<f32> = vec3<f32>(1., 1., 0.);\n// var<private> vColor: vec3<f32> = backColor;\n// var<private> aspect: f32 = 1.;\n// var<private> pixelPos: vec2<f32> = vec2<f32>(0., 0.);\n// var<private> mousePos: vec2<f32> = vec2<f32>(200., 200.);\n// var<private> lp: vec2<f32> = vec2<f32>(0.5, 0.5);\n// var<private> mp: vec2<f32> = vec2<f32>(0.5, 0.5);\n// var<private> resolution: vec2<f32>;\n\n\n// let FONT_SPACE: f32 = 0.5;\n// let headColor: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\n// let mpColor: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\n// let mxColor: vec3<f32> = vec3<f32>(1., 0., 0.);\n// let myColor: vec3<f32> = vec3<f32>(0., 1., 0.);\n// let font_png_size: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\n\n// fn char(ch: i32) -> f32 {\n\n//     let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n// \tlet q = clamp(tp, v2(0.), v2(1.)) / 16. + fr ;\n// \tlet inverted_q = v2(q.x, 1. - q.y);\n\n// \t// // There is aliasing on the characters\n// \t// let f = textureSampleGrad(font_texture,\n//     //                  font_texture_sampler,\n//     //                  inverted_q,\n//     //                   vec2<f32>(1.0, 0.0),\n//     //                  vec2<f32>(0.0, 1.0));\n\n// \t// using textureLoad without sampler\n//     let q1 = ivec2(font_png_size  * q );\n// \tlet y_inverted_q1 = ivec2(q1.x, i32(font_png_size.y) - q1.y);\n\n// \tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n// \t// smoothing out the aliasing\n// \tlet dx = vec2<i32>(1, 0);\n// \tlet dy = vec2<i32>(0, 1);\n\n// \tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n// \tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n// \tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n// \tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n// \tlet rp = 0.25;\n// \tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n// \treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n// } \n\n// fn SetTextPosition(x: f32, y: f32)  {\n// \ttp =  10. * uv;\n// \ttp.x = tp.x + 17. - x;\n// \ttp.y = tp.y - 9.4 + y;\n// } \n\n// fn SetTextPositionAbs(x: f32, y: f32)  {\n// \ttp.x = 10. * uv.x - x;\n// \ttp.y = 10. * uv.y - y;\n// } \n\n// fn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n// \tvar c: f32 = 0.;\n// \t*value = fract(*value) * 10.;\n\n// \tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n// \t\tc = c + (char(48 + i32(*value)));\n// \t\ttp.x = tp.x - (0.5);\n// \t\t*digits = *digits - (1);\n// \t\t*value = fract(*value) * 10.;\n\n// \t\tif (*digits <= 0 || *value == 0.) {\t\t\n//             break;\n//         }\n// \t}\n\n// \ttp.x = tp.x - (0.5 * f32(*digits));\n// \treturn c;\n// } \n\n// fn maxInt(a: i32, b: i32) -> i32 {\n//     var ret: i32;\n//     if (a > b) { ret = a; } else { ret = b; };\n// \treturn ret;\n// } \n\n// fn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n// \tvar c: f32 = 0.;\n// \tif (*value < 0) {\n// \t\t*value = -*value;\n// \t\tif (*minDigits < 1) {\t\t\n// \t\t\t*minDigits = 1;\n// \t\t} else { \n// \t\t\t*minDigits = *minDigits - 1;\n// \t\t}\n// \t\tc = c + (char(45));\n// \t\ttp.x = tp.x - (FONT_SPACE);\n\n// \t}\n// \tvar fn2: i32 = *value;\n// \tvar digits: i32 = 1;\n\n// \tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n// \t\tfn2 = fn2 / (10);\n// \t\tif (fn2 == 0) {\t\tbreak; }\n// \t\tdigits = digits + 1;\n// \t}\n\n// \tdigits = maxInt(*minDigits, digits);\n// \ttp.x = tp.x - (0.5 * f32(digits));\n\n// \tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n// \t\ttp.x = tp.x + (0.5);\n// \t\tc = c + (char(48 + *value % 10));\n// \t\t*value = *value / (10);\n// \t\tif (ni >= digits) {\t\tbreak; }\n// \t}\n\n// \ttp.x = tp.x - (0.5 * f32(digits));\n// \treturn c;\n// } \n\n// fn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n// \tvar c: f32 = 0.;\n// \tlet original_value: i32 = *value;\n\n// \tif (*value < 0) {\n// \t\t*value = -*value;\n// \t\tif (*minDigits < 1) {\t\t\n// \t\t\t*minDigits = 1;\n// \t\t} else { \n// \t\t\t*minDigits = *minDigits - 1;\n// \t\t}\n// \t\t// tp.x = tp.x + (FONT_SPACE);\n// \t\t// c = c + (char(45));\n\t\t\n\n// \t}\n// \tvar fn2: i32 = *value;\n// \tvar digits: i32 = 1;\n\n// \tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n// \t\tfn2 = fn2 / (10);\n// \t\tif (fn2 == 0) {\t\tbreak; }\n// \t\tdigits = digits + 1;\n// \t}\n\n// \tdigits = maxInt(*minDigits, digits);\n// \t// tp.x = tp.x - (0.5 * f32(digits));\n\n// \tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n// \t\ttp.x = tp.x + (0.5);\n// \t\tc = c + (char(48 + *value % 10));\n// \t\t*value = *value / (10);\n// \t\tif (ni == 0) {\t\tbreak; }\n// \t}\n\n// \tif (original_value < 0) {\n// \t\ttp.x = tp.x + (FONT_SPACE);\n// \t\tc = c + (char(45));\n// \t}\n\n// \t// tp.x = tp.x + (0.5 * f32(digits));\n// \treturn c;\n// } \n\n// // fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n// fn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n// \t// in case of 0.099999..., round up to 0.1000000\n// \tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n// \tlet tpx: f32 = tp.x - 0.5 * f32(maxDigits);\n// \tvar c: f32 = 0.;\n// \tif (value < 0.) {\n// \t\tc = char(45);\n// \t\tvalue = -value;\n// \t}\n// \ttp.x = tp.x - (0.5);\n//     var ival = i32(value);\n\n//     var one: i32 = 1;\n\n// \tc = c + (drawInt(&ival, &one));\n// \tc = c + (char(46));\n// \ttp.x = tp.x - (FONT_SPACE);\n\n//     var frac_val = fract(value);\n// \tc = c + (drawFract(&frac_val, prec));\n// \ttp.x = min(tp.x, tpx);\n\n// \treturn c;\n// }\n\n// fn drawFloat_f32(value:  f32) -> f32 {\n//     var two: i32 = 2;\n// \treturn drawFloat(value, &two, 5);\n// } \n\n// fn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n// \treturn drawFloat(value, prec, 2);\n// } \n\n// fn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n//     var one: i32 = 1;\n// \treturn drawIntBackwards(value, &one);\n// } \n\n// fn drawInt_i32(value: ptr<function, i32>) -> f32 {\n//     var one: i32 = 1;\n// \treturn drawInt(value, &one);\n// } \n\n\n\n\n\n// fn SetColor(red: f32, green: f32, blue: f32)  {\n// \tdrawColor = vec3<f32>(red, green, blue);\n// } \n\n// fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n// \t// vColor = mix(vColor, drawColor, drawFloat_f32_prec(fValue, decimalPlaces));\n// \tvColor = mix(vColor, drawColor, drawFloat(fValue, decimalPlaces, maxDigits));\n// \ttp.x = tp.x - (FONT_SPACE);\n// ;\n// } \n\n// fn WriteFloatBox(\n// \tfValue: f32, \n// \tmaxDigits: i32, \n// \tdecimalPlaces: i32, \n// \talpha: f32\n// )  {\n// \tvar decs = decimalPlaces;\n// \tvColor = mix(vColor, drawColor, drawFloat(fValue, &decs, maxDigits) * alpha);\n// \ttp.x = tp.x - (FONT_SPACE);\n// ;\n// } \n\n// fn WriteInteger(iValue: ptr<function, i32>)  {\n// \tvColor = mix(vColor, drawColor, drawInt_i32(iValue));\n// \ttp.x = tp.x - (FONT_SPACE);\n\n// } \n\n// fn WriteIntegerBack(iValue: ptr<function, i32>)  {\n// \tvColor = mix(vColor, drawColor, drawInt_i32_back(iValue));\n// \ttp.x = tp.x + (FONT_SPACE);\n\n// } \n\n\n\n// fn WriteFPS()  {\n// \tvar fps: f32 = f32(uni.iSampleRate);\n// \tSetColor(0.8, 0.6, 0.3);\n// \tvar max_digits_one = 1;\n// \tWriteFloat(fps, 5, &max_digits_one);\n// \tvar c: f32 = 0.;\n// \tc = c + (char(102));\n// \ttp.x = tp.x - (FONT_SPACE);\n\n// \tc = c + (char(112));\n// \ttp.x = tp.x - (FONT_SPACE);\n\n// \tc = c + (char(115));\n// \ttp.x = tp.x - (FONT_SPACE);\n// \t// let c2 = smoothStep(0.0, 1.0, c );\n\n// \tvColor = mix(vColor, drawColor, c);\n// } \n\n// fn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n// \tlet digits: i32 = 3;\n// \tlet radius: f32 = resolution.x / 400.;\n// \tif (uni.iMouse.z > 0.) { dotColor = mpColor; }\n// \tlet r: f32 = length(abs(mPos.xy) - pixelPos) - radius;\n// \t// vColor = vColor + (mix(vec3<f32>(0.), dotColor, 1. - clamp(r, 0., 1.)));\n\n// \tvar max_digits_three: i32 = 3;\n// \tvar mposxi: i32 = i32(mPos.x);\n// \tvar mposyi: i32 = i32(mPos.y);\n\n// \tvar mposx: f32 = (mPos.x);\n// \tvar mposy: f32 = (mPos.y);\n\n\n// \tlet x_pos = alignment.y - 1. * FONT_SPACE;\n\t\t\n// \tSetTextPositionAbs(\n// \t\t x_pos,\n// \t\t y_pos,\n// \t);\n\n// \tdrawColor = myColor;\n// \tWriteIntegerBack(&mposyi);\n\n// \tSetTextPositionAbs(\n// \t\t x_pos - 7. *  FONT_SPACE,\n// \t\t y_pos,\n// \t);\n\n// \tdrawColor = mxColor;\n\n// \tWriteIntegerBack(&mposxi);\n\n// } \n\n\n// fn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n//   var x = r.x;\n//   var y = r.y;\n//   x = select(r.z, r.x, p.x > 0.);\n//   y = select(r.w, r.y, p.x > 0.);\n//   x  = select(y, x, p.y > 0.);\n//   let q = abs(p) - b + x;\n//   return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n// }\n\n\n\n// fn WriteRGBAValues(\n// \tlocation: vec2<i32>, \n// \tvalue: vec4<f32>, \n// \tscreen_poz: vec2<f32>,\n// \talpha: f32,\n//  )  {\n// \tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect, 1.0);\n// \tlet window_ajusted = uni.iResolution / v2(960., 600.);\n\n// \tlet box_pos = vec2<f32>(alignment.w, alignment.x - FONT_SPACE ) / 10.;\n// \t// let box_pos = mp;\n\n// \t// // box location follows mouse position\n// \t// let box_location = v2(\n// \t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect / 1.6 ) , \n// \t// \tuni.iMouse.y - 48. * window_ajusted.y\n// \t// );\n\n\n// \tlet box_location  = v2(\n// \t\t100. * window_ajusted.x /  ( aspect / 1.6 ) , \n// \t\tuni.iResolution.y - 60. * window_ajusted.y,\n// \t);\n\t\n// \tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect, 1.) ;\n\n// \tlet d_box = sdRoundedBox(\n// \t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n// \t\t vec2<f32>(73. /  ( aspect / 1.6 ), 75.) * window_ajusted, \n// \t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n// \t);\n\n// \t// let alpha = 0.225;\n// \tlet decimal_places = 3;\n// \tSetColor(1., 1., 1.);\n// \tvar c: f32 = 0.;\n// \tlet lspace = 0.8;\n\n// \tlet bg_color = vec3<f32>(.8, .7, .9);\n// \tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n// \t// red\n// \tSetTextPosition(\n// \t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n// \t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n// \t) ;\n// \tc = c + (char(114)); // r\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tc = c + (char(58)); // colon\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n// \t// green\n// \tSetTextPosition(\n// \t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n// \t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n// \t) ;\n// \tc = c + (char(103)); // g\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tc = c + (char(58)); // colon\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n// \t// blue\n// \tSetTextPosition(\n// \t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n// \t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n// \t\t) ;\n// \tc = c + (char(98)); // b\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tc = c + (char(58)); // colon\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n// \t// alpha\n// \tSetTextPosition(\n// \t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n// \t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n// \t) ;\n// \tc = c + (char(97)); // a\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tc = c + (char(58)); // colon\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n// \tvColor = mix(vColor, drawColor, c * alpha);\n// }\n\n// fn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n//     let pa = p - a;\n//     let ba = b - a;\n//     let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n//     return length(pa - ba * h);\n// }\n\n// fn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n// \treturn mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv - pos) - radius)));\n// } \n\n// fn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n//     let d = length(p - c);\n//     return d - r;\n// }\n\n// fn draw_ring(location: vec2<i32>) {\n// \tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n// \tlet alpha = 0.75;\n// \tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n// \tlet d = smoothStep(0.5, 1.5, abs(ring_dist - 1.));\n// \tvColor = mix(vColor, headColor,   (1. - d) * alpha );\n// }\n\n// fn draw_crossair(location: vec2<i32>)  {\n\n// \tlet start = 5.0;\n// \tlet end = 20.;\n// \tlet segment1 = sdSegment(\n// \t\tvec2<f32>(location) - uni.iMouse.xy, \n// \t\tvec2<f32>(start, 0.), \n// \t\tvec2<f32>(end, 0.)\n// \t);\n\n// \tlet segment2 = sdSegment(\n// \t\tvec2<f32>(location) - uni.iMouse.xy, \n// \t\tvec2<f32>(-start, 0.), \n// \t\tvec2<f32>(-end, 0.)\n// \t);\n\n// \tlet segment3 = sdSegment(\n// \t\tvec2<f32>(location) - uni.iMouse.xy, \n// \t\tvec2<f32>(0., start), \n// \t\tvec2<f32>(0., end)\n// \t);\n\n// \tlet segment4 = sdSegment(\n// \t\tvec2<f32>(location) - uni.iMouse.xy, \n// \t\tvec2<f32>(0., -start), \n// \t\tvec2<f32>(0., -end)\n// \t);\n\n// \tvar alpha = 0.75;\n// \tif (uni.iMouse.z > 0.) {\n// \t\talpha = 1.0;\n// \t}\n\n// \tlet d = smoothStep(0.5, 1.5, segment1);\n// \tvColor = mix(vColor, headColor, (1.0 -  d) * alpha );\n\n// \tlet d = smoothStep(0.5, 1.5, segment2);\n// \tvColor = mix(vColor, headColor, (1.0 -  d) * alpha );\n\n// \tlet d = smoothStep(0.5, 1.5, segment3);\n// \tvColor = mix(vColor, headColor, (1.0 -  d) * alpha );\n\n// \tlet d = smoothStep(0.5, 1.5, segment4);\n// \tvColor = mix(vColor, headColor, (1.0 -  d) * alpha );\n// }\n\n// fn show_debug_info(location: vec2<i32>) -> vec4<f32> {    \n\n\n// \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// \tresolution = uni.iResolution.xy;\n// \taspect = resolution.x / resolution.y;\n\n// \tlet ratio: vec2<f32> = vec2<f32>(aspect, 1.);\n// \tpixelPos = fragCoord.xy;\n// \tmousePos = uni.iMouse.xy;\n// \tuv = (2. * fragCoord.xy / resolution.xy - 1.) * ratio;\n\n// \talignment = 10. * vec4<f32>(\n// \t\t1.,      // North\n// \t\taspect,  // East\n// \t\t-1.,     // South\n// \t\t-aspect, // West\n// \t);\n\n// \tmp = (2. * abs(uni.iMouse.xy) / resolution.xy - 1.) * ratio; // Mouse position in uv coordinates\n\n// \tWriteMousePos(uni.iMouse.zw, alignment.z + 2.0 * FONT_SPACE); // Click position\n// \tWriteMousePos(uni.iMouse.xy, alignment.z + 0.2 * FONT_SPACE); // Current mouse position\n\n// \tvar c: f32 = 0.;\n\n// \tSetTextPositionAbs(\n// \t\t alignment.y -      FONT_SPACE,\n// \t\t alignment.x - 2. * FONT_SPACE,\n// \t);\n\n// \tSetColor(0.8, 0.8, 0.8);\n// \tvar resx = i32(uni.iResolution.x);\n// \tvar resy = i32(uni.iResolution.y);\n\n\n// \tWriteIntegerBack(&resx);\n// \tc = c + (char(28));\n// \ttp.x = tp.x + 0. * (FONT_SPACE);\n// \tWriteIntegerBack(&resy);\n\n\n// \tSetTextPositionAbs(\n// \t\t alignment.w - 1. * FONT_SPACE,\n// \t\t alignment.z - 0. * FONT_SPACE,\n// \t);\n\n// \tWriteFPS();\n// \tSetColor(0.9, 0.7, 0.8);\n\n// \tlet fragColor = vec4<f32>(vColor, 1.);\n\n// \tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n// \t// // RGBA probe labels follow mouse\n// \t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n// \tlet inverted_y_mouse_location = vec2<i32>(v2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n// \tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n// \tWriteRGBAValues(location, value, poz, 0.5);\n\n// \tlet inverted_y_mouseclick_location = vec2<i32>(v2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n// \tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n// \tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.25);\n\n// \tdraw_crossair(location);\n\n// \tdraw_ring(location);\n\n// \tlet fragColor = vec4<f32>(vColor, 1.);\n\n// \treturn fragColor;\n// } \n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\t\n\tlet y_inverted_location = vec2<i32>((location.x), i32(uni.iResolution.y) - (location.y));\n\n\n\tlet fragColor = show_debug_info(location, vec3<f32>(0.5, 0.2, 0.1));\n\ttextureStore(texture, y_inverted_location, toLinear(fragColor));\n}\n\n"
  },
  {
    "path": "assets/shaders/dry_ice/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\nlet dissipation: f32 = 0.95;\nlet ballRadius: f32 = 0.06;\nlet fogHeigth: f32 = 0.24;\nlet nbSlice: i32 = 24;\nlet fogSlice: f32 = 0.01;\nlet nbSphere: i32 = 3;\nlet shadowDensity: f32 = 25.;\nlet fogDensity: f32 = 20.;\nlet lightHeight: f32 = 1.;\nlet tau: f32 = 6.28318530718;\n\nfn hash12(p: vec2<f32>) -> f32 {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * 0.1031);\n\tp3 = p3 + (dot(p3, p3.yzx + 33.33));\n\treturn fract((p3.x + p3.y) * p3.z);\n} \n\nfn hash41(p: f32) -> vec4<f32> {\n\tvar p4: vec4<f32> = fract(vec4<f32>(p) * vec4<f32>(0.1031, 0.103, 0.0973, 0.1099));\n\tp4 = p4 + (dot(p4, p4.wzxy + 33.33));\n\treturn fract((p4.xxyz + p4.yzzw) * p4.zywx);\n} \n\nfn rotate(angle: f32, radius: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(angle), -sin(angle)) * radius;\n} \n\nfn floorIntersect(ro: vec3<f32>, rd: vec3<f32>, floorHeight: f32, t: ptr<function, f32>) -> bool {\n\tvar ro_var = ro;\n\tro_var.y = ro_var.y - (floorHeight);\n\tif (rd.y < -0.01) {\n\t\t(*t) = ro_var.y / -rd.y;\n\t\treturn true;\n\t}\n\treturn false;\n} \n\nfn sphIntersect(ro: vec3<f32>, rd: vec3<f32>, ce: vec3<f32>, ra: f32) -> vec2<f32> {\n\tlet oc: vec3<f32> = ro - ce;\n\tlet b: f32 = dot(oc, rd);\n\tlet c: f32 = dot(oc, oc) - ra * ra;\n\tvar h: f32 = b * b - c;\n\tif (h < 0.) {\treturn vec2<f32>(-1.);\n }\n\th = sqrt(h);\n\treturn vec2<f32>(-b - h, -b + h);\n} \n\nfn boxIntersection(ro: vec3<f32>, rd: vec3<f32>, rad: vec3<f32>, center: vec3<f32>, oN: ptr<function, vec3<f32>>) -> vec2<f32> {\n\tvar ro_var = ro;\n\tro_var = ro_var - (center);\n\tlet m: vec3<f32> = 1. / rd;\n\tlet n: vec3<f32> = m * ro_var;\n\tlet k: vec3<f32> = abs(m) * rad;\n\tlet t1: vec3<f32> = -n - k;\n\tlet t2: vec3<f32> = -n + k;\n\tlet tN: f32 = max(max(t1.x, t1.y), t1.z);\n\tlet tF: f32 = min(min(t2.x, t2.y), t2.z);\n\tif (tN > tF || tF < 0.) {\treturn vec2<f32>(-1.);\n }\n\t(*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz);\n\treturn vec2<f32>(tN, tF);\n} \n\nfn spherePosition(id: i32, frame: i32) -> vec2<f32> {\n\tlet offset: vec4<f32> = hash41(f32(id)) * tau;\n\tlet fframe: f32 = f32(frame);\n\treturn vec2<f32>(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2<f32>(1., 0.5) * 0.9;\n} \n\nfn dist2(v: vec3<f32>) -> f32 {\n\treturn dot(v, v);\n} \n\n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n\nfn noise(p_in: vec3<f32>) -> f32 {\n    var p = p_in;\n\tlet ip: vec3<f32> = floor(p);\n\tp = p - (ip);\n\tlet s: vec3<f32> = vec3<f32>(7., 157., 113.);\n\tvar h: vec4<f32> = vec4<f32>(0., s.yz, s.y + s.z) + dot(ip, s);\n\tp = p * p * (3. - 2. * p);\n\th = mix(fract(sin(h) * 43758.5), fract(sin(h + s.x) * 43758.5), p.x);\n\tvar hxy = h.xy;\n\thxy = mix(h.xz, h.yw, p.y);\n\th.x = hxy.x;\n\th.y = hxy.y;\n\treturn mix(h.x, h.y, p.z);\n} \n\nfn fbm(p_in: vec3<f32>, octaveNum: i32) -> vec2<f32> {\n    var p = p_in;\n\tvar octaveNum_var = octaveNum;\n\tvar acc: vec2<f32> = vec2<f32>(0.);\n\tlet freq: f32 = 1.;\n\tvar amp: f32 = 0.5;\n\tlet shift: vec3<f32> = vec3<f32>(100.);\n\n\tfor (var i: i32 = 0; i < octaveNum_var; i = i + 1) {\n\t\tacc = acc + (vec2<f32>(noise(p), noise(p + vec3<f32>(0., 0., 10.))) * amp);\n\t\tp = p * 2. + shift;\n\t\tamp = amp * (0.5);\n\t}\n\n\treturn acc;\n} \n\nfn sampleMinusGradient(coord: vec2<f32>) -> vec3<f32> {\n\tvar veld: vec3<f32> = sample_texture(buffer_a, (coord / uni.iResolution.xy)).xyz;\n\tlet left: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(-1., 0.)) / uni.iResolution.xy)).x;\n\tlet right: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(1., 0.)) / uni.iResolution.xy)).x;\n\tlet bottom: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(0., -1.)) / uni.iResolution.xy)).x;\n\tlet top: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(0., 1.)) / uni.iResolution.xy)).x;\n\tlet grad: vec2<f32> = vec2<f32>(right - left, top - bottom) * 0.5;\n\treturn vec3<f32>(veld.xy - grad, veld.z);\n} \n\nfn vignette(color: vec3<f32>, q: vec2<f32>, v: f32) -> vec3<f32> {\n\tvar color_var = color;\n\tcolor_var = color_var * (mix(1., pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v), 0.02));\n\treturn color_var;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar velocity: vec2<f32> = sampleMinusGradient(fragCoord).xy;\n\tvar veld: vec3<f32> = sampleMinusGradient(fragCoord - dissipation * velocity).xyz;\n\tvar density: f32 = veld.z;\n\tvelocity = veld.xy;\n\tlet uv: vec2<f32> = (2. * fragCoord - uni.iResolution.xy) / uni.iResolution.y;\n\tlet detailNoise: vec2<f32> = fbm(vec3<f32>(uv * 40., uni.iTime * 0.5 + 30.), 7) - 0.5;\n\tvelocity = velocity + (detailNoise * 0.2);\n\tdensity = density + (length(detailNoise) * 0.01);\n\tlet injectionNoise: vec2<f32> = fbm(vec3<f32>(uv * 1.5, uni.iTime * 0.1 + 30.), 7) - 0.5;\n\tvelocity = velocity + (injectionNoise * 0.1);\n\tdensity = density + (max(length(injectionNoise) * 0.04, 0.));\n\tlet influenceRadius: f32 = ballRadius * 2.;\n\n\tfor (var i: i32 = 0; i < nbSphere; i = i + 1) {\n\t\tlet p: vec2<f32> = spherePosition(i, i32(uni.iFrame));\n\t\tlet dist: f32 = distance(uv, p);\n\t\tif (dist < influenceRadius) {\n\t\t\tlet op: vec2<f32> = spherePosition(i, i32(uni.iFrame) + 1);\n\t\t\tlet ballVelocity: vec2<f32> = p - op;\n\t\t\tdensity = density - ((influenceRadius - dist) / influenceRadius * 0.15);\n\t\t\tdensity = max(0., density);\n\t\t\tvelocity = velocity - (ballVelocity * 5.);\n\t\t}\n\t}\n\n\tdensity = min(1., density);\n\tdensity = density * (0.99);\n\tveld = vec3<f32>(vec3<f32>(velocity, density));\n\tveld = vignette(veld, fragCoord / uni.iResolution.xy, 1.);\n\tfragColor = vec4<f32>(veld, 1.);\n\n    textureStore(buffer_a, location, fragColor);\n} \n\n\n\n// fn noise(p_in: vec3<f32>) -> f32 {\n//     var p = p_in;\n// \tlet ip: vec3<f32> = floor(p);\n// \tp = p - (ip);\n// \tlet s: vec3<f32> = vec3<f32>(7., 157., 113.);\n// \tvar h: vec4<f32> = vec4<f32>(0., s.yz, s.y + s.z) + dot(ip, s);\n// \tp = p * p * (3. - 2. * p);\n// \th = mix(fract(sin(h) * 43758.5), fract(sin(h + s.x) * 43758.5), p.x);\n// \tvar hxy = h.xy;\n// \thxy = mix(h.xz, h.yw, p.y);\n// \th.x = hxy.x;\n// \th.y = hxy.y;\n// \treturn mix(h.x, h.y, p.z);\n// } \n\n// fn fbm(p_in: vec3<f32>, octaveNum: i32) -> vec2<f32> {\n//     var p = p_in;\n// \tvar octaveNum_var = octaveNum;\n// \tvar acc: vec2<f32> = vec2<f32>(0.);\n// \tlet freq: f32 = 1.;\n// \tvar amp: f32 = 0.5;\n// \tlet shift: vec3<f32> = vec3<f32>(100.);\n\n// \tfor (var i: i32 = 0; i < octaveNum_var; i = i + 1) {\n// \t\tacc = acc + (vec2<f32>(noise(p), noise(p + vec3<f32>(0., 0., 10.))) * amp);\n// \t\tp = p * 2. + shift;\n// \t\tamp = amp * (0.5);\n// \t}\n\n// \treturn acc;\n// } \n\n// fn sampleMinusGradient(coord: vec2<f32>) -> vec3<f32> {\n// \tvar veld: vec3<f32> = sample_texture(buffer_a,(coord / uni.iResolution.xy)).xyz;\n// \tlet left: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(-1., 0.)) / uni.iResolution.xy)).x;\n// \tlet right: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(1., 0.)) / uni.iResolution.xy)).x;\n// \tlet bottom: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(0., -1.)) / uni.iResolution.xy)).x;\n// \tlet top: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(0., 1.)) / uni.iResolution.xy)).x;\n// \tlet grad: vec2<f32> = vec2<f32>(right - left, top - bottom) * 0.5;\n// \treturn vec3<f32>(veld.xy - grad, veld.z);\n// } \n\n// fn vignette(color: vec3<f32>, q: vec2<f32>, v: f32) -> vec3<f32> {\n// \tvar color_var = color;\n// \tcolor_var = color_var * (mix(1., pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v), 0.02));\n// \treturn color_var;\n// } \n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n//     let R: vec2<f32> = uni.iResolution.xy;\n//     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n// \tvar fragColor: vec4<f32> = vec4<f32>(0.);\n// \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// \tvar velocity: vec2<f32> = sampleMinusGradient(fragCoord).xy;\n// \tvar veld: vec3<f32> = sampleMinusGradient(fragCoord - dissipation * velocity).xyz;\n// \tvar density: f32 = veld.z;\n// \tvelocity = veld.xy;\n// \tlet uv: vec2<f32> = (2. * fragCoord - uni.iResolution.xy) / uni.iResolution.y;\n\n\n// \tlet detailNoise: vec2<f32> = fbm(vec3<f32>(uv * 40., uni.iTime * 0.5 + 30.), 7) - 0.5;\n// \tvelocity = velocity + (detailNoise * 0.2);\n// \tdensity = density + (length(detailNoise) * 0.01);\n\n// \tlet injectionNoise: vec2<f32> = fbm(vec3<f32>(uv * 1.5, uni.iTime * 0.1 + 30.), 7) - 0.5;\n// \tvelocity = velocity + (injectionNoise * 0.1);\n// \tdensity = density + (max(length(injectionNoise) * 0.04, 0.));\n\n// \tlet influenceRadius: f32 = ballRadius * 2.;\n\n// \tfor (var i: i32 = 0; i < nbSphere; i = i + 1) {\n// \t\tlet p: vec2<f32> = spherePosition(i, i32(uni.iFrame));\n// \t\tlet dist: f32 = distance(uv, p);\n// \t\tif (dist < influenceRadius) {\n// \t\t\tlet op: vec2<f32> = spherePosition(i, i32(uni.iFrame) + 1);\n// \t\t\tlet ballVelocity: vec2<f32> = p - op;\n// \t\t\tdensity = density - ((influenceRadius - dist) / influenceRadius * 0.15);\n// \t\t\tdensity = max(0., density);\n// \t\t\tvelocity = velocity - (ballVelocity * 5.);\n// \t\t}\n// \t}\n\n// \tdensity = min(1., density);\n// \tdensity = density * (0.99);\n// \tveld = vec3<f32>(vec3<f32>(velocity, density));\n// \t// veld = vignette(veld, fragCoord / uni.iResolution.xy, 1.);\n// \tfragColor = vec4<f32>(veld, 1.);\n\n//     textureStore(buffer_a, location, fragColor);\n\n// } \n\n"
  },
  {
    "path": "assets/shaders/dry_ice/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\nlet dissipation: f32 = 0.95;\nlet ballRadius: f32 = 0.06;\nlet fogHeigth: f32 = 0.24;\nlet nbSlice: i32 = 24;\nlet fogSlice: f32 = 0.01;\nlet nbSphere: i32 = 3;\nlet shadowDensity: f32 = 25.;\nlet fogDensity: f32 = 20.;\nlet lightHeight: f32 = 1.;\nlet tau: f32 = 6.28318530718;\n\nfn hash12(p: vec2<f32>) -> f32 {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * 0.1031);\n\tp3 = p3 + (dot(p3, p3.yzx + 33.33));\n\treturn fract((p3.x + p3.y) * p3.z);\n} \n\nfn hash41(p: f32) -> vec4<f32> {\n\tvar p4: vec4<f32> = fract(vec4<f32>(p) * vec4<f32>(0.1031, 0.103, 0.0973, 0.1099));\n\tp4 = p4 + (dot(p4, p4.wzxy + 33.33));\n\treturn fract((p4.xxyz + p4.yzzw) * p4.zywx);\n} \n\nfn rotate(angle: f32, radius: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(angle), -sin(angle)) * radius;\n} \n\nfn floorIntersect(ro: vec3<f32>, rd: vec3<f32>, floorHeight: f32, t: ptr<function, f32>) -> bool {\n\tvar ro_var = ro;\n\tro_var.y = ro_var.y - (floorHeight);\n\tif (rd.y < -0.01) {\n\t\t(*t) = ro_var.y / -rd.y;\n\t\treturn true;\n\t}\n\treturn false;\n} \n\nfn sphIntersect(ro: vec3<f32>, rd: vec3<f32>, ce: vec3<f32>, ra: f32) -> vec2<f32> {\n\tlet oc: vec3<f32> = ro - ce;\n\tlet b: f32 = dot(oc, rd);\n\tlet c: f32 = dot(oc, oc) - ra * ra;\n\tvar h: f32 = b * b - c;\n\tif (h < 0.) {\treturn vec2<f32>(-1.);\n }\n\th = sqrt(h);\n\treturn vec2<f32>(-b - h, -b + h);\n} \n\nfn boxIntersection(ro: vec3<f32>, rd: vec3<f32>, rad: vec3<f32>, center: vec3<f32>, oN: ptr<function, vec3<f32>>) -> vec2<f32> {\n\tvar ro_var = ro;\n\tro_var = ro_var - (center);\n\tlet m: vec3<f32> = 1. / rd;\n\tlet n: vec3<f32> = m * ro_var;\n\tlet k: vec3<f32> = abs(m) * rad;\n\tlet t1: vec3<f32> = -n - k;\n\tlet t2: vec3<f32> = -n + k;\n\tlet tN: f32 = max(max(t1.x, t1.y), t1.z);\n\tlet tF: f32 = min(min(t2.x, t2.y), t2.z);\n\tif (tN > tF || tF < 0.) {\treturn vec2<f32>(-1.);\n }\n\t(*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz);\n\treturn vec2<f32>(tN, tF);\n} \n\nfn spherePosition(id: i32, frame: i32) -> vec2<f32> {\n\tlet offset: vec4<f32> = hash41(f32(id)) * tau;\n\tlet fframe: f32 = f32(frame);\n\treturn vec2<f32>(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2<f32>(1., 0.5) * 0.9;\n} \n\nfn dist2(v: vec3<f32>) -> f32 {\n\treturn dot(v, v);\n} \n\n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet icoord: vec2<i32> = vec2<i32>(fragCoord);\n\tlet vel_x_left: f32 = textureLoad(buffer_a, vec2<i32>(icoord + vec2<i32>(-1, 0))).x;\n\tlet vel_x_right: f32 = textureLoad(buffer_a, vec2<i32>(icoord + vec2<i32>(1, 0))).x;\n\tlet vel_y_bottom: f32 = textureLoad(buffer_a, vec2<i32>(icoord + vec2<i32>(0, -1))).y;\n\tlet vel_y_top: f32 = textureLoad(buffer_a, vec2<i32>(icoord + vec2<i32>(0, 1))).y;\n\tlet divergence: f32 = (vel_x_right - vel_x_left + vel_y_top - vel_y_bottom) * 0.5;\n\tfragColor = vec4<f32>(divergence, vec3<f32>(1.));\n    textureStore(buffer_b, location, fragColor);\n} \n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n//     let R: vec2<f32> = uni.iResolution.xy;\n//     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n// \tvar fragColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n// \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// \tlet icoord: vec2<i32> = vec2<i32>(fragCoord);\n// \tlet vel_x_left: f32 = sample_texture(buffer_a, vec2<f32>(icoord + vec2<i32>(-1, 0))).x;\n// \tlet vel_x_right: f32 = sample_texture(buffer_a, vec2<f32>(icoord + vec2<i32>(1, 0))).x;\n// \tlet vel_y_bottom: f32 = sample_texture(buffer_a, vec2<f32>(icoord + vec2<i32>(0, -1))).y;\n// \tlet vel_y_top: f32 = sample_texture(buffer_a, vec2<f32>(icoord + vec2<i32>(0, 1))).y;\n// \tlet divergence: f32 = (vel_x_right - vel_x_left + vel_y_top - vel_y_bottom) * 0.5;\n// \tfragColor = vec4<f32>(divergence, vec3<f32>(1.));\n//     textureStore(buffer_b, location, fragColor);\n\n\n// } \n\n"
  },
  {
    "path": "assets/shaders/dry_ice/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\nlet dissipation: f32 = 0.95;\nlet ballRadius: f32 = 0.06;\nlet fogHeigth: f32 = 0.24;\nlet nbSlice: i32 = 24;\nlet fogSlice: f32 = 0.01;\nlet nbSphere: i32 = 3;\nlet shadowDensity: f32 = 25.;\nlet fogDensity: f32 = 20.;\nlet lightHeight: f32 = 1.;\nlet tau: f32 = 6.28318530718;\n\nfn hash12(p: vec2<f32>) -> f32 {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * 0.1031);\n\tp3 = p3 + (dot(p3, p3.yzx + 33.33));\n\treturn fract((p3.x + p3.y) * p3.z);\n} \n\nfn hash41(p: f32) -> vec4<f32> {\n\tvar p4: vec4<f32> = fract(vec4<f32>(p) * vec4<f32>(0.1031, 0.103, 0.0973, 0.1099));\n\tp4 = p4 + (dot(p4, p4.wzxy + 33.33));\n\treturn fract((p4.xxyz + p4.yzzw) * p4.zywx);\n} \n\nfn rotate(angle: f32, radius: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(angle), -sin(angle)) * radius;\n} \n\nfn floorIntersect(ro: vec3<f32>, rd: vec3<f32>, floorHeight: f32, t: ptr<function, f32>) -> bool {\n\tvar ro_var = ro;\n\tro_var.y = ro_var.y - (floorHeight);\n\tif (rd.y < -0.01) {\n\t\t(*t) = ro_var.y / -rd.y;\n\t\treturn true;\n\t}\n\treturn false;\n} \n\nfn sphIntersect(ro: vec3<f32>, rd: vec3<f32>, ce: vec3<f32>, ra: f32) -> vec2<f32> {\n\tlet oc: vec3<f32> = ro - ce;\n\tlet b: f32 = dot(oc, rd);\n\tlet c: f32 = dot(oc, oc) - ra * ra;\n\tvar h: f32 = b * b - c;\n\tif (h < 0.) {\treturn vec2<f32>(-1.);\n }\n\th = sqrt(h);\n\treturn vec2<f32>(-b - h, -b + h);\n} \n\nfn boxIntersection(ro: vec3<f32>, rd: vec3<f32>, rad: vec3<f32>, center: vec3<f32>, oN: ptr<function, vec3<f32>>) -> vec2<f32> {\n\tvar ro_var = ro;\n\tro_var = ro_var - (center);\n\tlet m: vec3<f32> = 1. / rd;\n\tlet n: vec3<f32> = m * ro_var;\n\tlet k: vec3<f32> = abs(m) * rad;\n\tlet t1: vec3<f32> = -n - k;\n\tlet t2: vec3<f32> = -n + k;\n\tlet tN: f32 = max(max(t1.x, t1.y), t1.z);\n\tlet tF: f32 = min(min(t2.x, t2.y), t2.z);\n\tif (tN > tF || tF < 0.) {\treturn vec2<f32>(-1.);\n }\n\t(*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz);\n\treturn vec2<f32>(tN, tF);\n} \n\nfn spherePosition(id: i32, frame: i32) -> vec2<f32> {\n\tlet offset: vec4<f32> = hash41(f32(id)) * tau;\n\tlet fframe: f32 = f32(frame);\n\treturn vec2<f32>(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2<f32>(1., 0.5) * 0.9;\n} \n\nfn dist2(v: vec3<f32>) -> f32 {\n\treturn dot(v, v);\n} \n\n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n\nvar<private> location: vec2<i32>;\n\nfn div(x: i32, y: i32) -> f32 {\n\treturn textureLoad(buffer_b, vec2<i32>(location + vec2<i32>(x, y))).x;\n} \n\nfn getDiv() -> f32 {\n\tvar p: f32 = 0.;\n\tp = p + (1. * div(-9, 0));\n\tp = p + (9. * div(-8, -1));\n\tp = p + (4. * div(-8, 0));\n\tp = p + (9. * div(-8, 1));\n\tp = p + (36. * div(-7, -2));\n\tp = p + (32. * div(-7, -1));\n\tp = p + (97. * div(-7, 0));\n\tp = p + (32. * div(-7, 1));\n\tp = p + (36. * div(-7, 2));\n\tp = p + (84. * div(-6, -3));\n\tp = p + (112. * div(-6, -2));\n\tp = p + (436. * div(-6, -1));\n\tp = p + (320. * div(-6, 0));\n\tp = p + (436. * div(-6, 1));\n\tp = p + (112. * div(-6, 2));\n\tp = p + (84. * div(-6, 3));\n\tp = p + (126. * div(-5, -4));\n\tp = p + (224. * div(-5, -3));\n\tp = p + (1092. * div(-5, -2));\n\tp = p + (1280. * div(-5, -1));\n\tp = p + (2336. * div(-5, 0));\n\tp = p + (1280. * div(-5, 1));\n\tp = p + (1092. * div(-5, 2));\n\tp = p + (224. * div(-5, 3));\n\tp = p + (126. * div(-5, 4));\n\tp = p + (126. * div(-4, -5));\n\tp = p + (280. * div(-4, -4));\n\tp = p + (1694. * div(-4, -3));\n\tp = p + (2752. * div(-4, -2));\n\tp = p + (6656. * div(-4, -1));\n\tp = p + (6464. * div(-4, 0));\n\tp = p + (6656. * div(-4, 1));\n\tp = p + (2752. * div(-4, 2));\n\tp = p + (1694. * div(-4, 3));\n\tp = p + (280. * div(-4, 4));\n\tp = p + (126. * div(-4, 5));\n\tp = p + (84. * div(-3, -6));\n\tp = p + (224. * div(-3, -5));\n\tp = p + (1694. * div(-3, -4));\n\tp = p + (3520. * div(-3, -3));\n\tp = p + (11016. * div(-3, -2));\n\tp = p + (16128. * div(-3, -1));\n\tp = p + (24608. * div(-3, 0));\n\tp = p + (16128. * div(-3, 1));\n\tp = p + (11016. * div(-3, 2));\n\tp = p + (3520. * div(-3, 3));\n\tp = p + (1694. * div(-3, 4));\n\tp = p + (224. * div(-3, 5));\n\tp = p + (84. * div(-3, 6));\n\tp = p + (36. * div(-2, -7));\n\tp = p + (112. * div(-2, -6));\n\tp = p + (1092. * div(-2, -5));\n\tp = p + (2752. * div(-2, -4));\n\tp = p + (11016. * div(-2, -3));\n\tp = p + (21664. * div(-2, -2));\n\tp = p + (47432. * div(-2, -1));\n\tp = p + (59712. * div(-2, 0));\n\tp = p + (47432. * div(-2, 1));\n\tp = p + (21664. * div(-2, 2));\n\tp = p + (11016. * div(-2, 3));\n\tp = p + (2752. * div(-2, 4));\n\tp = p + (1092. * div(-2, 5));\n\tp = p + (112. * div(-2, 6));\n\tp = p + (36. * div(-2, 7));\n\tp = p + (9. * div(-1, -8));\n\tp = p + (32. * div(-1, -7));\n\tp = p + (436. * div(-1, -6));\n\tp = p + (1280. * div(-1, -5));\n\tp = p + (6656. * div(-1, -4));\n\tp = p + (16128. * div(-1, -3));\n\tp = p + (47432. * div(-1, -2));\n\tp = p + (92224. * div(-1, -1));\n\tp = p + (163476. * div(-1, 0));\n\tp = p + (92224. * div(-1, 1));\n\tp = p + (47432. * div(-1, 2));\n\tp = p + (16128. * div(-1, 3));\n\tp = p + (6656. * div(-1, 4));\n\tp = p + (1280. * div(-1, 5));\n\tp = p + (436. * div(-1, 6));\n\tp = p + (32. * div(-1, 7));\n\tp = p + (9. * div(-1, 8));\n\tp = p + (1. * div(0, -9));\n\tp = p + (4. * div(0, -8));\n\tp = p + (97. * div(0, -7));\n\tp = p + (320. * div(0, -6));\n\tp = p + (2336. * div(0, -5));\n\tp = p + (6464. * div(0, -4));\n\tp = p + (24608. * div(0, -3));\n\tp = p + (59712. * div(0, -2));\n\tp = p + (163476. * div(0, -1));\n\tp = p + (409744. * div(0, 0));\n\tp = p + (163476. * div(0, 1));\n\tp = p + (59712. * div(0, 2));\n\tp = p + (24608. * div(0, 3));\n\tp = p + (6464. * div(0, 4));\n\tp = p + (2336. * div(0, 5));\n\tp = p + (320. * div(0, 6));\n\tp = p + (97. * div(0, 7));\n\tp = p + (4. * div(0, 8));\n\tp = p + (1. * div(0, 9));\n\tp = p + (9. * div(1, -8));\n\tp = p + (32. * div(1, -7));\n\tp = p + (436. * div(1, -6));\n\tp = p + (1280. * div(1, -5));\n\tp = p + (6656. * div(1, -4));\n\tp = p + (16128. * div(1, -3));\n\tp = p + (47432. * div(1, -2));\n\tp = p + (92224. * div(1, -1));\n\tp = p + (163476. * div(1, 0));\n\tp = p + (92224. * div(1, 1));\n\tp = p + (47432. * div(1, 2));\n\tp = p + (16128. * div(1, 3));\n\tp = p + (6656. * div(1, 4));\n\tp = p + (1280. * div(1, 5));\n\tp = p + (436. * div(1, 6));\n\tp = p + (32. * div(1, 7));\n\tp = p + (9. * div(1, 8));\n\tp = p + (36. * div(2, -7));\n\tp = p + (112. * div(2, -6));\n\tp = p + (1092. * div(2, -5));\n\tp = p + (2752. * div(2, -4));\n\tp = p + (11016. * div(2, -3));\n\tp = p + (21664. * div(2, -2));\n\tp = p + (47432. * div(2, -1));\n\tp = p + (59712. * div(2, 0));\n\tp = p + (47432. * div(2, 1));\n\tp = p + (21664. * div(2, 2));\n\tp = p + (11016. * div(2, 3));\n\tp = p + (2752. * div(2, 4));\n\tp = p + (1092. * div(2, 5));\n\tp = p + (112. * div(2, 6));\n\tp = p + (36. * div(2, 7));\n\tp = p + (84. * div(3, -6));\n\tp = p + (224. * div(3, -5));\n\tp = p + (1694. * div(3, -4));\n\tp = p + (3520. * div(3, -3));\n\tp = p + (11016. * div(3, -2));\n\tp = p + (16128. * div(3, -1));\n\tp = p + (24608. * div(3, 0));\n\tp = p + (16128. * div(3, 1));\n\tp = p + (11016. * div(3, 2));\n\tp = p + (3520. * div(3, 3));\n\tp = p + (1694. * div(3, 4));\n\tp = p + (224. * div(3, 5));\n\tp = p + (84. * div(3, 6));\n\tp = p + (126. * div(4, -5));\n\tp = p + (280. * div(4, -4));\n\tp = p + (1694. * div(4, -3));\n\tp = p + (2752. * div(4, -2));\n\tp = p + (6656. * div(4, -1));\n\tp = p + (6464. * div(4, 0));\n\tp = p + (6656. * div(4, 1));\n\tp = p + (2752. * div(4, 2));\n\tp = p + (1694. * div(4, 3));\n\tp = p + (280. * div(4, 4));\n\tp = p + (126. * div(4, 5));\n\tp = p + (126. * div(5, -4));\n\tp = p + (224. * div(5, -3));\n\tp = p + (1092. * div(5, -2));\n\tp = p + (1280. * div(5, -1));\n\tp = p + (2336. * div(5, 0));\n\tp = p + (1280. * div(5, 1));\n\tp = p + (1092. * div(5, 2));\n\tp = p + (224. * div(5, 3));\n\tp = p + (126. * div(5, 4));\n\tp = p + (84. * div(6, -3));\n\tp = p + (112. * div(6, -2));\n\tp = p + (436. * div(6, -1));\n\tp = p + (320. * div(6, 0));\n\tp = p + (436. * div(6, 1));\n\tp = p + (112. * div(6, 2));\n\tp = p + (84. * div(6, 3));\n\tp = p + (36. * div(7, -2));\n\tp = p + (32. * div(7, -1));\n\tp = p + (97. * div(7, 0));\n\tp = p + (32. * div(7, 1));\n\tp = p + (36. * div(7, 2));\n\tp = p + (9. * div(8, -1));\n\tp = p + (4. * div(8, 0));\n\tp = p + (9. * div(8, 1));\n\tp = p + (1. * div(9, 0));\n\treturn p / 1048576.;\n} \n\nfn pre(x: i32, y: i32) -> f32 {\n\treturn textureLoad(buffer_d, vec2<i32>(location + vec2<i32>(x, y))).x;\n} \n\nfn getPre() -> f32 {\n\tvar p: f32 = 0.;\n\tp = p + (1. * pre(-10, 0));\n\tp = p + (10. * pre(-9, -1));\n\tp = p + (10. * pre(-9, 1));\n\tp = p + (45. * pre(-8, -2));\n\tp = p + (100. * pre(-8, 0));\n\tp = p + (45. * pre(-8, 2));\n\tp = p + (120. * pre(-7, -3));\n\tp = p + (450. * pre(-7, -1));\n\tp = p + (450. * pre(-7, 1));\n\tp = p + (120. * pre(-7, 3));\n\tp = p + (210. * pre(-6, -4));\n\tp = p + (1200. * pre(-6, -2));\n\tp = p + (2025. * pre(-6, 0));\n\tp = p + (1200. * pre(-6, 2));\n\tp = p + (210. * pre(-6, 4));\n\tp = p + (252. * pre(-5, -5));\n\tp = p + (2100. * pre(-5, -3));\n\tp = p + (5400. * pre(-5, -1));\n\tp = p + (5400. * pre(-5, 1));\n\tp = p + (2100. * pre(-5, 3));\n\tp = p + (252. * pre(-5, 5));\n\tp = p + (210. * pre(-4, -6));\n\tp = p + (2520. * pre(-4, -4));\n\tp = p + (9450. * pre(-4, -2));\n\tp = p + (14400. * pre(-4, 0));\n\tp = p + (9450. * pre(-4, 2));\n\tp = p + (2520. * pre(-4, 4));\n\tp = p + (210. * pre(-4, 6));\n\tp = p + (120. * pre(-3, -7));\n\tp = p + (2100. * pre(-3, -5));\n\tp = p + (11340. * pre(-3, -3));\n\tp = p + (25200. * pre(-3, -1));\n\tp = p + (25200. * pre(-3, 1));\n\tp = p + (11340. * pre(-3, 3));\n\tp = p + (2100. * pre(-3, 5));\n\tp = p + (120. * pre(-3, 7));\n\tp = p + (45. * pre(-2, -8));\n\tp = p + (1200. * pre(-2, -6));\n\tp = p + (9450. * pre(-2, -4));\n\tp = p + (30240. * pre(-2, -2));\n\tp = p + (44100. * pre(-2, 0));\n\tp = p + (30240. * pre(-2, 2));\n\tp = p + (9450. * pre(-2, 4));\n\tp = p + (1200. * pre(-2, 6));\n\tp = p + (45. * pre(-2, 8));\n\tp = p + (10. * pre(-1, -9));\n\tp = p + (450. * pre(-1, -7));\n\tp = p + (5400. * pre(-1, -5));\n\tp = p + (25200. * pre(-1, -3));\n\tp = p + (52920. * pre(-1, -1));\n\tp = p + (52920. * pre(-1, 1));\n\tp = p + (25200. * pre(-1, 3));\n\tp = p + (5400. * pre(-1, 5));\n\tp = p + (450. * pre(-1, 7));\n\tp = p + (10. * pre(-1, 9));\n\tp = p + (1. * pre(0, -10));\n\tp = p + (100. * pre(0, -8));\n\tp = p + (2025. * pre(0, -6));\n\tp = p + (14400. * pre(0, -4));\n\tp = p + (44100. * pre(0, -2));\n\tp = p + (63504. * pre(0, 0));\n\tp = p + (44100. * pre(0, 2));\n\tp = p + (14400. * pre(0, 4));\n\tp = p + (2025. * pre(0, 6));\n\tp = p + (100. * pre(0, 8));\n\tp = p + (1. * pre(0, 10));\n\tp = p + (10. * pre(1, -9));\n\tp = p + (450. * pre(1, -7));\n\tp = p + (5400. * pre(1, -5));\n\tp = p + (25200. * pre(1, -3));\n\tp = p + (52920. * pre(1, -1));\n\tp = p + (52920. * pre(1, 1));\n\tp = p + (25200. * pre(1, 3));\n\tp = p + (5400. * pre(1, 5));\n\tp = p + (450. * pre(1, 7));\n\tp = p + (10. * pre(1, 9));\n\tp = p + (45. * pre(2, -8));\n\tp = p + (1200. * pre(2, -6));\n\tp = p + (9450. * pre(2, -4));\n\tp = p + (30240. * pre(2, -2));\n\tp = p + (44100. * pre(2, 0));\n\tp = p + (30240. * pre(2, 2));\n\tp = p + (9450. * pre(2, 4));\n\tp = p + (1200. * pre(2, 6));\n\tp = p + (45. * pre(2, 8));\n\tp = p + (120. * pre(3, -7));\n\tp = p + (2100. * pre(3, -5));\n\tp = p + (11340. * pre(3, -3));\n\tp = p + (25200. * pre(3, -1));\n\tp = p + (25200. * pre(3, 1));\n\tp = p + (11340. * pre(3, 3));\n\tp = p + (2100. * pre(3, 5));\n\tp = p + (120. * pre(3, 7));\n\tp = p + (210. * pre(4, -6));\n\tp = p + (2520. * pre(4, -4));\n\tp = p + (9450. * pre(4, -2));\n\tp = p + (14400. * pre(4, 0));\n\tp = p + (9450. * pre(4, 2));\n\tp = p + (2520. * pre(4, 4));\n\tp = p + (210. * pre(4, 6));\n\tp = p + (252. * pre(5, -5));\n\tp = p + (2100. * pre(5, -3));\n\tp = p + (5400. * pre(5, -1));\n\tp = p + (5400. * pre(5, 1));\n\tp = p + (2100. * pre(5, 3));\n\tp = p + (252. * pre(5, 5));\n\tp = p + (210. * pre(6, -4));\n\tp = p + (1200. * pre(6, -2));\n\tp = p + (2025. * pre(6, 0));\n\tp = p + (1200. * pre(6, 2));\n\tp = p + (210. * pre(6, 4));\n\tp = p + (120. * pre(7, -3));\n\tp = p + (450. * pre(7, -1));\n\tp = p + (450. * pre(7, 1));\n\tp = p + (120. * pre(7, 3));\n\tp = p + (45. * pre(8, -2));\n\tp = p + (100. * pre(8, 0));\n\tp = p + (45. * pre(8, 2));\n\tp = p + (10. * pre(9, -1));\n\tp = p + (10. * pre(9, 1));\n\tp = p + (1. * pre(10, 0));\n\treturn p / 1048576.;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\tvar C = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet div: f32 = getDiv();\n\tlet p: f32 = getPre() - div;\n\tfragColor = vec4<f32>(p, div, vec2<f32>(1.));\n\n    textureStore(buffer_c, location, fragColor);\n} \n\n"
  },
  {
    "path": "assets/shaders/dry_ice/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\nlet dissipation: f32 = 0.95;\nlet ballRadius: f32 = 0.06;\nlet fogHeigth: f32 = 0.24;\nlet nbSlice: i32 = 24;\nlet fogSlice: f32 = 0.01;\nlet nbSphere: i32 = 3;\nlet shadowDensity: f32 = 25.;\nlet fogDensity: f32 = 20.;\nlet lightHeight: f32 = 1.;\nlet tau: f32 = 6.28318530718;\n\nfn hash12(p: vec2<f32>) -> f32 {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * 0.1031);\n\tp3 = p3 + (dot(p3, p3.yzx + 33.33));\n\treturn fract((p3.x + p3.y) * p3.z);\n} \n\nfn hash41(p: f32) -> vec4<f32> {\n\tvar p4: vec4<f32> = fract(vec4<f32>(p) * vec4<f32>(0.1031, 0.103, 0.0973, 0.1099));\n\tp4 = p4 + (dot(p4, p4.wzxy + 33.33));\n\treturn fract((p4.xxyz + p4.yzzw) * p4.zywx);\n} \n\nfn rotate(angle: f32, radius: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(angle), -sin(angle)) * radius;\n} \n\nfn floorIntersect(ro: vec3<f32>, rd: vec3<f32>, floorHeight: f32, t: ptr<function, f32>) -> bool {\n\tvar ro_var = ro;\n\tro_var.y = ro_var.y - (floorHeight);\n\tif (rd.y < -0.01) {\n\t\t(*t) = ro_var.y / -rd.y;\n\t\treturn true;\n\t}\n\treturn false;\n} \n\nfn sphIntersect(ro: vec3<f32>, rd: vec3<f32>, ce: vec3<f32>, ra: f32) -> vec2<f32> {\n\tlet oc: vec3<f32> = ro - ce;\n\tlet b: f32 = dot(oc, rd);\n\tlet c: f32 = dot(oc, oc) - ra * ra;\n\tvar h: f32 = b * b - c;\n\tif (h < 0.) {\treturn vec2<f32>(-1.);\n }\n\th = sqrt(h);\n\treturn vec2<f32>(-b - h, -b + h);\n} \n\nfn boxIntersection(ro: vec3<f32>, rd: vec3<f32>, rad: vec3<f32>, center: vec3<f32>, oN: ptr<function, vec3<f32>>) -> vec2<f32> {\n\tvar ro_var = ro;\n\tro_var = ro_var - (center);\n\tlet m: vec3<f32> = 1. / rd;\n\tlet n: vec3<f32> = m * ro_var;\n\tlet k: vec3<f32> = abs(m) * rad;\n\tlet t1: vec3<f32> = -n - k;\n\tlet t2: vec3<f32> = -n + k;\n\tlet tN: f32 = max(max(t1.x, t1.y), t1.z);\n\tlet tF: f32 = min(min(t2.x, t2.y), t2.z);\n\tif (tN > tF || tF < 0.) {\treturn vec2<f32>(-1.);\n }\n\t(*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz);\n\treturn vec2<f32>(tN, tF);\n} \n\nfn spherePosition(id: i32, frame: i32) -> vec2<f32> {\n\tlet offset: vec4<f32> = hash41(f32(id)) * tau;\n\tlet fframe: f32 = f32(frame);\n\treturn vec2<f32>(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2<f32>(1., 0.5) * 0.9;\n} \n\nfn dist2(v: vec3<f32>) -> f32 {\n\treturn dot(v, v);\n} \n\n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n\n\nvar<private> location: vec2<i32>;\n\nfn div(x: i32, y: i32) -> f32 {\n\treturn textureLoad(buffer_c, vec2<i32>(location + vec2<i32>(x, y))).y;\n} \n\nfn pre(x: i32, y: i32) -> f32 {\n\treturn textureLoad(buffer_c, vec2<i32>(location + vec2<i32>(x, y))).x;\n} \n\nfn getPre() -> f32 {\n\tvar p: f32 = 0.;\n\tp = p + (1. * pre(-10, 0));\n\tp = p + (10. * pre(-9, -1));\n\tp = p + (10. * pre(-9, 1));\n\tp = p + (45. * pre(-8, -2));\n\tp = p + (100. * pre(-8, 0));\n\tp = p + (45. * pre(-8, 2));\n\tp = p + (120. * pre(-7, -3));\n\tp = p + (450. * pre(-7, -1));\n\tp = p + (450. * pre(-7, 1));\n\tp = p + (120. * pre(-7, 3));\n\tp = p + (210. * pre(-6, -4));\n\tp = p + (1200. * pre(-6, -2));\n\tp = p + (2025. * pre(-6, 0));\n\tp = p + (1200. * pre(-6, 2));\n\tp = p + (210. * pre(-6, 4));\n\tp = p + (252. * pre(-5, -5));\n\tp = p + (2100. * pre(-5, -3));\n\tp = p + (5400. * pre(-5, -1));\n\tp = p + (5400. * pre(-5, 1));\n\tp = p + (2100. * pre(-5, 3));\n\tp = p + (252. * pre(-5, 5));\n\tp = p + (210. * pre(-4, -6));\n\tp = p + (2520. * pre(-4, -4));\n\tp = p + (9450. * pre(-4, -2));\n\tp = p + (14400. * pre(-4, 0));\n\tp = p + (9450. * pre(-4, 2));\n\tp = p + (2520. * pre(-4, 4));\n\tp = p + (210. * pre(-4, 6));\n\tp = p + (120. * pre(-3, -7));\n\tp = p + (2100. * pre(-3, -5));\n\tp = p + (11340. * pre(-3, -3));\n\tp = p + (25200. * pre(-3, -1));\n\tp = p + (25200. * pre(-3, 1));\n\tp = p + (11340. * pre(-3, 3));\n\tp = p + (2100. * pre(-3, 5));\n\tp = p + (120. * pre(-3, 7));\n\tp = p + (45. * pre(-2, -8));\n\tp = p + (1200. * pre(-2, -6));\n\tp = p + (9450. * pre(-2, -4));\n\tp = p + (30240. * pre(-2, -2));\n\tp = p + (44100. * pre(-2, 0));\n\tp = p + (30240. * pre(-2, 2));\n\tp = p + (9450. * pre(-2, 4));\n\tp = p + (1200. * pre(-2, 6));\n\tp = p + (45. * pre(-2, 8));\n\tp = p + (10. * pre(-1, -9));\n\tp = p + (450. * pre(-1, -7));\n\tp = p + (5400. * pre(-1, -5));\n\tp = p + (25200. * pre(-1, -3));\n\tp = p + (52920. * pre(-1, -1));\n\tp = p + (52920. * pre(-1, 1));\n\tp = p + (25200. * pre(-1, 3));\n\tp = p + (5400. * pre(-1, 5));\n\tp = p + (450. * pre(-1, 7));\n\tp = p + (10. * pre(-1, 9));\n\tp = p + (1. * pre(0, -10));\n\tp = p + (100. * pre(0, -8));\n\tp = p + (2025. * pre(0, -6));\n\tp = p + (14400. * pre(0, -4));\n\tp = p + (44100. * pre(0, -2));\n\tp = p + (63504. * pre(0, 0));\n\tp = p + (44100. * pre(0, 2));\n\tp = p + (14400. * pre(0, 4));\n\tp = p + (2025. * pre(0, 6));\n\tp = p + (100. * pre(0, 8));\n\tp = p + (1. * pre(0, 10));\n\tp = p + (10. * pre(1, -9));\n\tp = p + (450. * pre(1, -7));\n\tp = p + (5400. * pre(1, -5));\n\tp = p + (25200. * pre(1, -3));\n\tp = p + (52920. * pre(1, -1));\n\tp = p + (52920. * pre(1, 1));\n\tp = p + (25200. * pre(1, 3));\n\tp = p + (5400. * pre(1, 5));\n\tp = p + (450. * pre(1, 7));\n\tp = p + (10. * pre(1, 9));\n\tp = p + (45. * pre(2, -8));\n\tp = p + (1200. * pre(2, -6));\n\tp = p + (9450. * pre(2, -4));\n\tp = p + (30240. * pre(2, -2));\n\tp = p + (44100. * pre(2, 0));\n\tp = p + (30240. * pre(2, 2));\n\tp = p + (9450. * pre(2, 4));\n\tp = p + (1200. * pre(2, 6));\n\tp = p + (45. * pre(2, 8));\n\tp = p + (120. * pre(3, -7));\n\tp = p + (2100. * pre(3, -5));\n\tp = p + (11340. * pre(3, -3));\n\tp = p + (25200. * pre(3, -1));\n\tp = p + (25200. * pre(3, 1));\n\tp = p + (11340. * pre(3, 3));\n\tp = p + (2100. * pre(3, 5));\n\tp = p + (120. * pre(3, 7));\n\tp = p + (210. * pre(4, -6));\n\tp = p + (2520. * pre(4, -4));\n\tp = p + (9450. * pre(4, -2));\n\tp = p + (14400. * pre(4, 0));\n\tp = p + (9450. * pre(4, 2));\n\tp = p + (2520. * pre(4, 4));\n\tp = p + (210. * pre(4, 6));\n\tp = p + (252. * pre(5, -5));\n\tp = p + (2100. * pre(5, -3));\n\tp = p + (5400. * pre(5, -1));\n\tp = p + (5400. * pre(5, 1));\n\tp = p + (2100. * pre(5, 3));\n\tp = p + (252. * pre(5, 5));\n\tp = p + (210. * pre(6, -4));\n\tp = p + (1200. * pre(6, -2));\n\tp = p + (2025. * pre(6, 0));\n\tp = p + (1200. * pre(6, 2));\n\tp = p + (210. * pre(6, 4));\n\tp = p + (120. * pre(7, -3));\n\tp = p + (450. * pre(7, -1));\n\tp = p + (450. * pre(7, 1));\n\tp = p + (120. * pre(7, 3));\n\tp = p + (45. * pre(8, -2));\n\tp = p + (100. * pre(8, 0));\n\tp = p + (45. * pre(8, 2));\n\tp = p + (10. * pre(9, -1));\n\tp = p + (10. * pre(9, 1));\n\tp = p + (1. * pre(10, 0));\n\treturn p / 1048576.;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\tvar C = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet p: f32 = getPre() - div(0, 0);\n\tfragColor = vec4<f32>(p, vec3<f32>(1.));\n    textureStore(buffer_d, location, fragColor);\n} \n\n\n"
  },
  {
    "path": "assets/shaders/dry_ice/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\nlet dissipation: f32 = 0.95;\nlet ballRadius: f32 = 0.06;\nlet fogHeigth: f32 = 0.24;\nlet nbSlice: i32 = 24;\nlet fogSlice: f32 = 0.01;\nlet nbSphere: i32 = 3;\nlet shadowDensity: f32 = 25.;\nlet fogDensity: f32 = 20.;\nlet lightHeight: f32 = 1.;\nlet tau: f32 = 6.28318530718;\n\nfn hash12(p: vec2<f32>) -> f32 {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * 0.1031);\n\tp3 = p3 + (dot(p3, p3.yzx + 33.33));\n\treturn fract((p3.x + p3.y) * p3.z);\n} \n\nfn hash41(p: f32) -> vec4<f32> {\n\tvar p4: vec4<f32> = fract(vec4<f32>(p) * vec4<f32>(0.1031, 0.103, 0.0973, 0.1099));\n\tp4 = p4 + (dot(p4, p4.wzxy + 33.33));\n\treturn fract((p4.xxyz + p4.yzzw) * p4.zywx);\n} \n\nfn rotate(angle: f32, radius: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(angle), -sin(angle)) * radius;\n} \n\nfn floorIntersect(ro: vec3<f32>, rd: vec3<f32>, floorHeight: f32, t: ptr<function, f32>) -> bool {\n\tvar ro_var = ro;\n\tro_var.y = ro_var.y - (floorHeight);\n\tif (rd.y < -0.01) {\n\t\t(*t) = ro_var.y / -rd.y;\n\t\treturn true;\n\t}\n\treturn false;\n} \n\nfn sphIntersect(ro: vec3<f32>, rd: vec3<f32>, ce: vec3<f32>, ra: f32) -> vec2<f32> {\n\tlet oc: vec3<f32> = ro - ce;\n\tlet b: f32 = dot(oc, rd);\n\tlet c: f32 = dot(oc, oc) - ra * ra;\n\tvar h: f32 = b * b - c;\n\tif (h < 0.) {\treturn vec2<f32>(-1.);\n }\n\th = sqrt(h);\n\treturn vec2<f32>(-b - h, -b + h);\n} \n\nfn boxIntersection(ro: vec3<f32>, rd: vec3<f32>, rad: vec3<f32>, center: vec3<f32>, oN: ptr<function, vec3<f32>>) -> vec2<f32> {\n\tvar ro_var = ro;\n\tro_var = ro_var - (center);\n\tlet m: vec3<f32> = 1. / rd;\n\tlet n: vec3<f32> = m * ro_var;\n\tlet k: vec3<f32> = abs(m) * rad;\n\tlet t1: vec3<f32> = -n - k;\n\tlet t2: vec3<f32> = -n + k;\n\tlet tN: f32 = max(max(t1.x, t1.y), t1.z);\n\tlet tF: f32 = min(min(t2.x, t2.y), t2.z);\n\tif (tN > tF || tF < 0.) {\treturn vec2<f32>(-1.);\n }\n\t(*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz);\n\treturn vec2<f32>(tN, tF);\n} \n\nfn spherePosition(id: i32, frame: i32) -> vec2<f32> {\n\tlet offset: vec4<f32> = hash41(f32(id)) * tau;\n\tlet fframe: f32 = f32(frame);\n\treturn vec2<f32>(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2<f32>(1., 0.5) * 0.9;\n} \n\nfn dist2(v: vec3<f32>) -> f32 {\n\treturn dot(v, v);\n} \n\n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n\n// https://www.shadertoy.com/view/WlVyRV\n// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0\n\nfn sceneIntersection(ro: vec3<f32>, rd: vec3<f32>, inter: ptr<function, vec3<f32>>, normal: ptr<function, vec3<f32>>, color: ptr<function, vec3<f32>>, dist: f32, lightPos: ptr<function, vec3<f32>>) -> f32 {\n\tvar mint: f32 = dist;\n\t(*inter) = vec3<f32>(0.);\n\t(*normal) = vec3<f32>(0.);\n\t(*color) = vec3<f32>(0.);\n\n\tfor (var i: i32 = 0; i < nbSphere; i = i + 1) {\n\t\tlet p2d: vec2<f32> = spherePosition(i, i32(uni.iFrame));\n\t\tlet pos: vec3<f32> = vec3<f32>(p2d.x, ballRadius, p2d.y);\n\t\tvar ballColor: vec3<f32> = vec3<f32>(1., 0., 0.);\n\t\tif (i == 0) {\n\t\t\tballColor = vec3<f32>(1.);\n\t\t\t(*lightPos) = pos + vec3<f32>(0., lightHeight, 0.);\n\t\t}\n\t\tvar t: f32 = sphIntersect(ro, rd, pos, ballRadius).x;\n\t\tif (t > 0. && t < mint) {\n\t\t\tmint = t;\n\t\t\t(*inter) = ro + mint * rd;\n\t\t\t(*normal) = normalize((*inter) - pos);\n\t\t\t(*color) = ballColor;\n\t\t}\n\t}\n\n\n\t\tlet aspecRatio: f32 = uni.iResolution.x / uni.iResolution.y;\n\t\tvar boxNormal: vec3<f32>;\n\t\tlet t: f32 = boxIntersection(ro, rd, vec3<f32>(aspecRatio, 0.1, 1.), vec3<f32>(0., -0.1, 0.), &boxNormal).x;\n\t\tif (t > 0. && t < mint) {\n\t\t\tmint = t;\n\t\t\t(*inter) = ro + mint * rd;\n\t\t\t(*normal) = boxNormal;\n\t\t\tlet tileId: vec2<i32> = vec2<i32>(vec2<f32>((*inter).x, (*inter).z) * 3. + 100.);\n\t\t\t if ((tileId.x & 1 ^ tileId.y & 1) == 0) { (*color) =vec3<f32>(0.3); } else { (*color) =vec3<f32>(0.15); };\n\t\t}\n\treturn mint;\n} \n\nfn sampleFog(pos: vec3<f32>) -> f32 {\n\tvar uv: vec2<f32> = pos.xz;\n\tuv.x = uv.x * (uni.iResolution.y / uni.iResolution.x);\n\tuv = uv * 0.5 + 0.5;\n\tif (max(uv.x, uv.y) > 1. || min(uv.x, uv.y) < 0.) {\n\t\treturn 0.;\n\t}\n\treturn sample_texture(buffer_a, uv).z;\n} \n\nfn Render(ro: vec3<f32>, rd: vec3<f32>, dist: f32, fudge: f32) -> vec3<f32> {\n\tvar inter: vec3<f32>;\n\tvar normal: vec3<f32>;\n\tvar baseColor: vec3<f32>;\n\tvar lightPos: vec3<f32>;\n\tlet mint: f32 = sceneIntersection(ro, rd, &inter, &normal, &baseColor, dist, &lightPos);\n\tvar color: vec3<f32> = vec3<f32>(0.);\n\tif (mint < dist) {\n\t\tvar lightDir: vec3<f32> = normalize(lightPos - inter);\n\t\tvar lightDist2: f32 = dist2(lightPos - inter);\n\t\tvar shadowStep: vec3<f32> = fogHeigth / f32(nbSlice) * lightDir / lightDir.y;\n\t\tvar shadowDist: f32 = 0.;\n\n\t\tfor (var i: i32 = 0; i < nbSlice; i = i + 1) {\n\t\t\tvar shadowPos: vec3<f32> = inter + shadowStep * f32(i);\n\t\t\tlet v: f32 = sampleFog(shadowPos) * fogHeigth;\n\t\t\tshadowDist = shadowDist + (min(max(0., v - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice);\n\t\t}\n\n\t\tvar shadowFactor: f32 = exp(-shadowDist * shadowDensity * 0.25);\n\t\tcolor = baseColor * (max(0., dot(normal, lightDir) * shadowFactor) + 0.2) / lightDist2;\n\t} else { \n\t\tcolor = vec3<f32>(0.);\n\t}\n\tvar t: f32;\n\tif (floorIntersect(ro, rd, fogHeigth, &t)) {\n\t\tvar curPos: vec3<f32> = ro + rd * t;\n\t\tlet fogStep: vec3<f32> = fogHeigth / f32(nbSlice) * rd / abs(rd.y);\n\t\tcurPos = curPos + (fudge * fogStep);\n\t\tlet stepLen: f32 = length(fogStep);\n\t\tvar curDensity: f32 = 0.;\n\t\tvar transmittance: f32 = 1.;\n\t\tvar lightEnergy: f32 = 0.;\n\n\t\tfor (var i: i32 = 0; i < nbSlice; i = i + 1) {\n\t\t\tif (dot(curPos - ro, rd) > mint) {\t\t\tbreak;\n }\n\t\t\tlet curHeigth: f32 = sampleFog(curPos) * fogHeigth;\n\t\t\tlet curSample: f32 = min(max(0., curHeigth - curPos.y), fogSlice) * stepLen / fogSlice;\n\t\t\tif (curSample > 0.001) {\n\t\t\t\tlet lightDir: vec3<f32> = normalize(lightPos - curPos);\n\t\t\t\tlet shadowStep: vec3<f32> = fogHeigth / f32(nbSlice) * lightDir / lightDir.y;\n\t\t\t\tlet lightDist2: f32 = dist2(lightPos - curPos);\n\t\t\t\tvar shadowPos: vec3<f32> = curPos + shadowStep * fudge;\n\t\t\t\tvar shadowDist: f32 = 0.;\n\n\t\t\t\tfor (var j: i32 = 0; j < nbSlice; j = j + 1) {\n\t\t\t\t\tshadowPos = shadowPos + (shadowStep);\n\t\t\t\t\tif (shadowPos.y > fogHeigth) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tlet curHeight: f32 = sampleFog(shadowPos) * fogHeigth;\n\t\t\t\t\tshadowDist = shadowDist + (min(max(0., curHeight - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice);\n\t\t\t\t}\n\n\t\t\t\tlet shadowFactor: f32 = exp(-shadowDist * shadowDensity) / lightDist2;\n\t\t\t\tcurDensity = curSample * fogDensity;\n\t\t\t\tlet absorbedlight: f32 = shadowFactor * (1. * curDensity);\n\t\t\t\tlightEnergy = lightEnergy + (absorbedlight * transmittance);\n\t\t\t\ttransmittance = transmittance * (1. - curDensity);\n\t\t\t}\n\t\t\tcurPos = curPos + (fogStep);\n\t\t}\n\n\t\tcolor = mix(color, vec3<f32>(lightEnergy), 1. - transmittance);\n\t}\n\treturn color;\n} \n\nfn vignette(color: vec3<f32>, q: vec2<f32>, v: f32) -> vec3<f32> {\n\tvar color_var = color;\n\tcolor_var = color_var * (0.3 + 0.8 * pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v));\n\treturn color_var;\n} \n\nfn setCamera(ro: vec3<f32>, ta: vec3<f32>) -> mat3x3<f32> {\n\tlet cw: vec3<f32> = normalize(ta - ro);\n\tlet up: vec3<f32> = vec3<f32>(0., 1., 0.);\n\tlet cu: vec3<f32> = normalize(cross(cw, up));\n\tlet cv: vec3<f32> = normalize(cross(cu, cw));\n\treturn mat3x3<f32>(cu, cv, cw);\n} \n\nfn radians (degrees: f32) -> f32 {\n    return degrees * ( 3.1416 / 180.);\n}\n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar tot: vec3<f32> = vec3<f32>(0.);\n\tlet p: vec2<f32> = (-uni.iResolution.xy + 2. * fragCoord) / uni.iResolution.y;\n\tlet theta: f32 = radians(360.) * (uni.iMouse.x / uni.iResolution.x - 0.5) - radians(90.);\n\tlet phi: f32 = -radians(30.);\n\tlet ro: vec3<f32> = 2. * vec3<f32>(sin(phi) * cos(theta), cos(phi), sin(phi) * sin(theta));\n\tlet ta: vec3<f32> = vec3<f32>(0.);\n\tlet ca: mat3x3<f32> = setCamera(ro, ta);\n\tlet rd: vec3<f32> = ca * normalize(vec3<f32>(p, 1.5));\n\tlet col: vec3<f32> = Render(ro, rd, 6., hash12(fragCoord + uni.iTime));\n\ttot = tot + (col);\n\ttot = vignette(tot, fragCoord / uni.iResolution.xy, 0.6);\n\tfragColor = vec4<f32>(sqrt(tot), 1.);\n\n    textureStore(texture, y_inverted_location, toLinear(fragColor));\n} \n\n\n\n\n// fn sceneIntersection(\n//     ro: vec3<f32>, \n//     rd: vec3<f32>, \n//     inter: ptr<function, vec3<f32>>, \n//     normal: ptr<function, vec3<f32>>, \n//     color: ptr<function, vec3<f32>>, \n//     dist: f32, \n//     lightPos: ptr<function, vec3<f32>>\n// ) -> f32 {\n// \tvar mint: f32 = dist;\n// \t(*inter) = vec3<f32>(0.);\n// \t(*normal) = vec3<f32>(0.);\n// \t(*color) = vec3<f32>(0.);\n\n// \tfor (var i: i32 = 0; i < nbSphere; i = i + 1) {\n// \t\tlet p2d: vec2<f32> = spherePosition(i, i32(uni.iFrame));\n// \t\tlet pos: vec3<f32> = vec3<f32>(p2d.x, ballRadius, p2d.y);\n// \t\tvar ballColor: vec3<f32> = vec3<f32>(1., 0., 0.);\n// \t\tif (i == 0) {\n// \t\t\tballColor = vec3<f32>(1.);\n// \t\t\t(*lightPos) = pos + vec3<f32>(0., lightHeight, 0.);\n// \t\t}\n// \t\tvar t: f32 = sphIntersect(ro, rd, pos, ballRadius).x;\n// \t\tif (t > 0. && t < mint) {\n// \t\t\tmint = t;\n// \t\t\t(*inter) = ro + mint * rd;\n// \t\t\t(*normal) = normalize((*inter) - pos);\n// \t\t\t(*color) = ballColor;\n// \t\t}\n// \t}\n\n\n// \t\tlet aspecRatio: f32 = uni.iResolution.x / uni.iResolution.y;\n// \t\tvar boxNormal: vec3<f32> = vec3<f32>(0. );\n// \t\tlet t: f32 = boxIntersection(ro, rd, vec3<f32>(aspecRatio, 0.1, 1.), vec3<f32>(0., -0.1, 0.), &boxNormal).x;\n\n// \t\tif (t > 0. && t < mint) {\n// \t\t\tmint = t;\n// \t\t\t(*inter) = ro + mint * rd;\n// \t\t\t(*normal) = boxNormal;\n// \t\t\tlet tileId: vec2<i32> = vec2<i32>(vec2<f32>((*inter).x, (*inter).z) * 3. + 100.);\n// \t\t\t if ((tileId.x & 1 ^ tileId.y & 1) == 0) {(*color) = vec3<f32>(0.3); } else { (*color) = vec3<f32>(0.15); };\n// \t\t}\n\n// \treturn mint;\n// } \n\n// fn sampleFog(pos: vec3<f32>) -> f32 {\n// \tvar uv: vec2<f32> = pos.xz;\n// \tuv.x = uv.x * (uni.iResolution.y / uni.iResolution.x);\n// \tuv = uv * 0.5 + 0.5;\n// \tif (max(uv.x, uv.y) > 1. || min(uv.x, uv.y) < 0.) {\n// \t\treturn 0.;\n// \t}\n// \treturn sample_texture(buffer_a, uv).z;\n// } \n\n// fn Render(ro: vec3<f32>, rd: vec3<f32>, dist: f32, fudge: f32) -> vec3<f32> {\n// \tvar inter: vec3<f32> = vec3<f32>(0.);\n// \tvar normal: vec3<f32> = vec3<f32>(0.);\n// \tvar baseColor: vec3<f32> = vec3<f32>(0.);\n// \tvar lightPos: vec3<f32> = vec3<f32>(0.);\n// \tlet mint: f32 = sceneIntersection(ro, rd, &inter, &normal, &baseColor, dist, &lightPos);\n// \tvar color: vec3<f32> = vec3<f32>(0.);\n// \tif (mint < dist) {\n// \t\tvar lightDir: vec3<f32> = normalize(lightPos - inter);\n// \t\tvar lightDist2: f32 = dist2(lightPos - inter);\n// \t\tvar shadowStep: vec3<f32> = fogHeigth / f32(nbSlice) * lightDir / lightDir.y;\n// \t\tvar shadowDist: f32 = 0.;\n\n// \t\tfor (var i: i32 = 0; i < nbSlice; i = i + 1) {\n// \t\t\tvar shadowPos: vec3<f32> = inter + shadowStep * f32(i);\n// \t\t\tlet v: f32 = sampleFog(shadowPos) * fogHeigth;\n// \t\t\tshadowDist = shadowDist + (min(max(0., v - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice);\n// \t\t}\n\n// \t\tvar shadowFactor: f32 = exp(-shadowDist * shadowDensity * 0.25);\n// \t\tcolor = baseColor * (max(0., dot(normal, lightDir) * shadowFactor) + 0.2) / lightDist2;\n// \t} else { \n// \t\tcolor = vec3<f32>(0.);\n// \t}\n// \tvar t: f32 = 0.;\n// \tif (floorIntersect(ro, rd, fogHeigth, &t)) {\n// \t\tvar curPos: vec3<f32> = ro + rd * t;\n// \t\tlet fogStep: vec3<f32> = fogHeigth / f32(nbSlice) * rd / abs(rd.y);\n// \t\tcurPos = curPos + (fudge * fogStep);\n// \t\tlet stepLen: f32 = length(fogStep);\n// \t\tvar curDensity: f32 = 0.;\n// \t\tvar transmittance: f32 = 1.;\n// \t\tvar lightEnergy: f32 = 0.;\n\n// \t\tfor (var i: i32 = 0; i < nbSlice; i = i + 1) {\n// \t\t\tif (dot(curPos - ro, rd) > mint) {\t\t\tbreak;\n//  }\n// \t\t\tlet curHeigth: f32 = sampleFog(curPos) * fogHeigth;\n// \t\t\tlet curSample: f32 = min(max(0., curHeigth - curPos.y), fogSlice) * stepLen / fogSlice;\n// \t\t\tif (curSample > 0.001) {\n// \t\t\t\tlet lightDir: vec3<f32> = normalize(lightPos - curPos);\n// \t\t\t\tlet shadowStep: vec3<f32> = fogHeigth / f32(nbSlice) * lightDir / lightDir.y;\n// \t\t\t\tlet lightDist2: f32 = dist2(lightPos - curPos);\n// \t\t\t\tvar shadowPos: vec3<f32> = curPos + shadowStep * fudge;\n// \t\t\t\tvar shadowDist: f32 = 0.;\n\n// \t\t\t\tfor (var j: i32 = 0; j < nbSlice; j = j + 1) {\n// \t\t\t\t\tshadowPos = shadowPos + (shadowStep);\n// \t\t\t\t\tif (shadowPos.y > fogHeigth) {\n// \t\t\t\t\t\tbreak;\n// \t\t\t\t\t}\n// \t\t\t\t\tlet curHeight: f32 = sampleFog(shadowPos) * fogHeigth;\n// \t\t\t\t\tshadowDist = shadowDist + (min(max(0., curHeight - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice);\n// \t\t\t\t}\n\n// \t\t\t\tlet shadowFactor: f32 = exp(-shadowDist * shadowDensity) / lightDist2;\n// \t\t\t\tcurDensity = curSample * fogDensity;\n// \t\t\t\tlet absorbedlight: f32 = shadowFactor * (1. * curDensity);\n// \t\t\t\tlightEnergy = lightEnergy + (absorbedlight * transmittance);\n// \t\t\t\ttransmittance = transmittance * (1. - curDensity);\n// \t\t\t}\n// \t\t\tcurPos = curPos + (fogStep);\n// \t\t}\n\n// \t\tcolor = mix(color, vec3<f32>(lightEnergy), 1. - transmittance);\n// \t}\n// \treturn color;\n// } \n\n// fn vignette(color: vec3<f32>, q: vec2<f32>, v: f32) -> vec3<f32> {\n// \tvar color_var = color;\n// \tcolor_var = color_var * (0.3 + 0.8 * pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v));\n// \treturn color_var;\n// } \n\n// fn setCamera(ro: vec3<f32>, ta: vec3<f32>) -> mat3x3<f32> {\n// \tlet cw: vec3<f32> = normalize(ta - ro);\n// \tlet up: vec3<f32> = vec3<f32>(0., 1., 0.);\n// \tlet cu: vec3<f32> = normalize(cross(cw, up));\n// \tlet cv: vec3<f32> = normalize(cross(cu, cw));\n// \treturn mat3x3<f32>(cu, cv, cw);\n// } \n\n// fn radians(in: f32) -> f32 {\n//     return in * (3.141592653589793 / 180.);\n// }\n\n// fn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n//     let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n//     let lower = sRGB / vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n//     let R: vec2<f32> = uni.iResolution.xy;\n//     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n// \tvar fragColor: vec4<f32>;\n// \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// \tvar tot: vec3<f32> = vec3<f32>(0.);\n// \tvar rook: array<vec2<f32>,4>;\n// \trook[0] = vec2<f32>(1. / 8., 3. / 8.);\n// \trook[1] = vec2<f32>(3. / 8., -1. / 8.);\n// \trook[2] = vec2<f32>(-1. / 8., -3. / 8.);\n// \trook[3] = vec2<f32>(-3. / 8., 1. / 8.);\n\n// \tfor (var n: i32 = 0; n < 4; n  = n + 1) {\n// \t\tlet o: vec2<f32> = rook[n];\n// \t\tlet p: vec2<f32> = (-uni.iResolution.xy + 2. * (fragCoord + o)) / uni.iResolution.y;\n// \t\tlet theta: f32 = radians(360.) * (uni.iMouse.x / uni.iResolution.x - 0.5) - radians(90.);\n// \t\tlet phi: f32 = -radians(30.);\n// \t\tlet ro: vec3<f32> = 2. * vec3<f32>(sin(phi) * cos(theta), cos(phi), sin(phi) * sin(theta));\n// \t\tlet ta: vec3<f32> = vec3<f32>(0.);\n// \t\tlet ca: mat3x3<f32> = setCamera(ro, ta);\n// \t\tlet rd: vec3<f32> = ca * normalize(vec3<f32>(p, 1.5));\n// \t\tlet col: vec3<f32> = Render(ro, rd, 6., hash12(fragCoord + uni.iTime));\n// \t\ttot = tot + (col);\n// \t}\n\n// \ttot = tot / (4.);\n// \ttot = vignette(tot, fragCoord / uni.iResolution.xy, 0.6);\n// \tfragColor = vec4<f32>(sqrt(tot), 1.);\n\n//     textureStore(texture, y_inverted_location, toLinear(fragColor));\n// } \n\n\n// // fn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n// //     let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n// //     let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n// //     let lower = sRGB / vec4<f32>(12.92);\n\n// //     return mix(higher, lower, cutoff);\n// // }\n\n// // [[stage(compute), workgroup_size(8, 8, 1)]]\n// // fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n// //     let R: vec2<f32> = uni.iResolution.xy;\n// //     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n// //     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n// // \tvar fragColor: vec4<f32>;\n// // \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// // \tfragColor = vec4<f32>(vec3<f32>(sample_texture(buffer_a, fragCoord / uni.iResolution).z), 1.);\n// //     textureStore(texture, y_inverted_location, toLinear(fragColor));\n// // } \n\n"
  },
  {
    "path": "assets/shaders/fire/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/fire/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/fire/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/fire/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/fire/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// [[group(0), binding(1)]]\n// var buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(2)]]\n// var buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(3)]]\n// var buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(4)]]\n// var buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n[[group(0), binding(8)]]\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n[[group(0), binding(9)]]\nvar rgba_noise_256_texture_sampler: sampler;\n\n\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n\n\n\n// https://www.shadertoy.com/view/XsXSWS\n// no licence\n\nfn hash(p: vec2<f32>) -> vec2<f32> {\n\tvar p_var = p;\n\tp_var = vec2<f32>(dot(p_var, vec2<f32>(127.1, 311.7)), dot(p_var, vec2<f32>(269.5, 183.3)));\n\treturn -1. + 2. * fract(sin(p_var) * 43758.547);\n} \n\nfn noise(p: vec2<f32>) -> f32 {\n\tlet K1: f32 = 0.36602542;\n\tlet K2: f32 = 0.21132487;\n\tlet i: vec2<f32> = floor(p + (p.x + p.y) * K1);\n\tvar a: vec2<f32> = p - i + (i.x + i.y) * K2;\n\tvar o: vec2<f32>; \n    if (a.x > a.y) { o = vec2<f32>(1., 0.); } else { o = vec2<f32>(0., 1.); };\n\tlet b: vec2<f32> = a - o + K2;\n\tvar c: vec2<f32> = a - 1. + 2. * K2;\n\tlet h: vec3<f32> = max(0.5 - vec3<f32>(dot(a, a), dot(b, b), dot(c, c)), vec3<f32>(0.));\n\tvar n: vec3<f32> = h * h * h * h * vec3<f32>(dot(a, hash(i + 0.)), dot(b, hash(i + o)), dot(c, hash(i + 1.)));\n\treturn dot(n, vec3<f32>(70.));\n} \n\nfn fbm(uv_in: vec2<f32>) -> f32 {\n\tvar f: f32;\n    var uv = uv_in;\n\tlet m: mat2x2<f32> = mat2x2<f32>(1.6, 1.2, -1.2, 1.6);\n\tf = 0.5 * noise(uv);\n\tuv = m * uv;\n\tf = f + (0.25 * noise(uv));\n\tuv = m * uv;\n\tf = f + (0.125 * noise(uv));\n\tuv = m * uv;\n\tf = f + (0.0625 * noise(uv));\n\tuv = m * uv;\n\tf = 0.5 + 0.5 * f;\n\treturn f;\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\tlet uv: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\tvar q: vec2<f32> = uv;\n\tq.x = q.x * (5.);\n\tq.y = q.y * (2.);\n\tlet strength: f32 = floor(q.x + 1.);\n\tlet T3: f32 = max(3., 1.25 * strength) * uni.iTime;\n\tq.x = (q.x % 1.) - 0.5;\n\tq.y = q.y - (0.25);\n\tlet n: f32 = fbm(strength * q - vec2<f32>(0., T3));\n\tlet c: f32 = 1. - 16. * pow(max(0., length(q * vec2<f32>(1.8 + q.y * 1.5, 0.75)) - n * max(0., q.y + 0.25)), 1.2);\n\tvar c1: f32 = n * c * (1.5 - pow(2.5 * uv.y, 4.));\n\tc1 = clamp(c1, 0., 1.);\n\tlet col: vec3<f32> = vec3<f32>(1.5 * c1, 1.5 * c1 * c1 * c1, c1 * c1 * c1 * c1 * c1 * c1);\n\tlet a: f32 = c * (1. - pow(uv.y, 3.));\n\tfragColor = vec4<f32>(mix(vec3<f32>(0.), col, a), 1.);\n\n    textureStore(texture, y_inverted_location, fragColor);\n} \n\n\n\n"
  },
  {
    "path": "assets/shaders/fire2/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/fire2/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/fire2/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/fire2/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/fire2/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\n\n\n// original code: https://www.shadertoy.com/view/MlKSWm\n// MIT licence\n\nfn mod289(x: vec3<f32>) -> vec3<f32> {\n\treturn x - floor(x * (1. / 289.)) * 289.;\n} \n\nfn mod289_4(x: vec4<f32>) -> vec4<f32> {\n\treturn x - floor(x * (1. / 289.)) * 289.;\n} \n\nfn permute(x: vec4<f32>) -> vec4<f32> {\n\treturn mod289_4((x * 34. + 1.) * x);\n} \n\nfn taylorInvSqrt(r: vec4<f32>) -> vec4<f32> {\n\treturn 1.7928429 - 0.85373473 * r;\n} \n\nfn snoise(v: vec3<f32>) -> f32 {\n\tlet C: vec2<f32> = vec2<f32>(1. / 6., 1. / 3.);\n\tlet D: vec4<f32> = vec4<f32>(0., 0.5, 1., 2.);\n\n\t// First corner\n\tvar i: vec3<f32> = floor(v + dot(v, C.yyy));\n\tlet x0: vec3<f32> = v - i + dot(i, C.xxx);\n\n\t// Other corners\n\tlet g: vec3<f32> = step(x0.yzx, x0.xyz);\n\tlet l: vec3<f32> = 1. - g;\n\tlet i1: vec3<f32> = min(g.xyz, l.zxy);\n\tlet i2: vec3<f32> = max(g.xyz, l.zxy);\n\tlet x1: vec3<f32> = x0 - i1 + C.xxx;\n\tlet x2: vec3<f32> = x0 - i2 + C.yyy;\n\tlet x3: vec3<f32> = x0 - D.yyy;\n\n\t// Permutations\n\ti = mod289(i);\n\tlet p: vec4<f32> = permute(permute(permute(i.z + vec4<f32>(0., i1.z, i2.z, 1.)) + i.y + vec4<f32>(0., i1.y, i2.y, 1.)) + i.x + vec4<f32>(0., i1.x, i2.x, 1.));\n\t\n\t// Gradients: 7x7 points over a square, mapped onto an octahedron.\n\t// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)\n\tlet n_: f32 = 0.14285715;\n\tlet ns: vec3<f32> = n_ * D.wyz - D.xzx;\n\tlet j: vec4<f32> = p - 49. * floor(p * ns.z * ns.z);\n\tlet x_: vec4<f32> = floor(j * ns.z);\n\tlet y_: vec4<f32> = floor(j - 7. * x_);\n\tvar x: vec4<f32> = x_ * ns.x + ns.yyyy;\n\tvar y: vec4<f32> = y_ * ns.x + ns.yyyy;\n\tlet h: vec4<f32> = 1. - abs(x) - abs(y);\n\tlet b0: vec4<f32> = vec4<f32>(x.xy, y.xy);\n\tlet b1: vec4<f32> = vec4<f32>(x.zw, y.zw);\n\tlet s0: vec4<f32> = floor(b0) * 2. + 1.;\n\tlet s1: vec4<f32> = floor(b1) * 2. + 1.;\n\tlet sh: vec4<f32> = -step(h, vec4<f32>(0.));\n\tlet a0: vec4<f32> = b0.xzyw + s0.xzyw * sh.xxyy;\n\tlet a1: vec4<f32> = b1.xzyw + s1.xzyw * sh.zzww;\n\n\t//Normalise gradients\n\tvar p0: vec3<f32> = vec3<f32>(a0.xy, h.x);\n\tvar p1: vec3<f32> = vec3<f32>(a0.zw, h.y);\n\tvar p2: vec3<f32> = vec3<f32>(a1.xy, h.z);\n\tvar p3: vec3<f32> = vec3<f32>(a1.zw, h.w);\n\tlet norm: vec4<f32> = inverseSqrt(vec4<f32>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));\n\tp0 = p0 * (norm.x);\n\tp1 = p1 * (norm.y);\n\tp2 = p2 * (norm.z);\n\tp3 = p3 * (norm.w);\n\n\t// Mix final noise value\n\tvar m: vec4<f32> = max(0.6 - vec4<f32>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec4<f32>(0.));\n\tm = m * m;\n\treturn 42. * dot(m * m, vec4<f32>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));\n} \n\n// PRNG\n// From https://www.shadertoy.com/view/4djSRW\nfn prng(seed: vec2<f32>) -> f32 {\n\tvar seed_var = seed;\n\tseed_var = fract(seed_var * vec2<f32>(5.3983, 5.4427));\n\tseed_var = seed_var + (dot(seed_var.yx, seed_var.xy + vec2<f32>(21.5351, 14.3137)));\n\treturn fract(seed_var.x * seed_var.y * 95.4337);\n} \n\nlet PI: f32 = 3.1415927;\nfn noiseStack(pos_in: vec3<f32>, octaves: i32, falloff: f32) -> f32 {\n\tvar pos = pos_in;\n\tvar noise: f32 = snoise(vec3<f32>(pos));\n\tvar off: f32 = 1.;\n\tif (octaves > 1) {\n\t\tpos = pos * (2.);\n\t\toff = off * (falloff);\n\t\tnoise = (1. - off) * noise + off * snoise(vec3<f32>(pos));\n\t}\n\tif (octaves > 2) {\n\t\tpos = pos * (2.);\n\t\toff = off * (falloff);\n\t\tnoise = (1. - off) * noise + off * snoise(vec3<f32>(pos));\n\t}\n\tif (octaves > 3) {\n\t\tpos = pos * (2.);\n\t\toff = off * (falloff);\n\t\tnoise = (1. - off) * noise + off * snoise(vec3<f32>(pos));\n\t}\n\treturn (1. + noise) / 2.;\n} \n\nfn noiseStackUV(pos: vec3<f32>, octaves: i32, falloff: f32, diff: f32) -> vec2<f32> {\n\tlet displaceA: f32 = noiseStack(pos, octaves, falloff);\n\tlet displaceB: f32 = noiseStack(pos + vec3<f32>(3984.293, 423.21, 5235.19), octaves, falloff);\n\treturn vec2<f32>(displaceA, displaceB);\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\tlet time: f32 = uni.iTime;\n\tlet resolution: vec2<f32> = uni.iResolution.xy;\n\tlet drag: vec2<f32> = uni.iMouse.xy;\n\tlet offset: vec2<f32> = uni.iMouse.xy;\n\n\tlet xpart: f32 = fragCoord.x / resolution.x;\n\tlet ypart: f32 = fragCoord.y / resolution.y;\n\n\tlet clip: f32 = 210.;\n\tlet ypartClip: f32 = fragCoord.y / clip;\n\tlet ypartClippedFalloff: f32 = clamp(2. - ypartClip, 0., 1.);\n\tlet ypartClipped: f32 = min(ypartClip, 1.);\n\tlet ypartClippedn: f32 = 1. - ypartClipped;\n\n\tlet xfuel: f32 = 1. - abs(2. * xpart - 1.);\n\n\tlet timeSpeed: f32 = 0.5;\n\tlet realTime: f32 = timeSpeed * time;\n\n\tlet coordScaled: vec2<f32> = 0.01 * fragCoord - 0.02 * vec2<f32>(offset.x, 0.);\n\tlet position: vec3<f32> = vec3<f32>(coordScaled, 0.) + vec3<f32>(1223., 6434., 8425.);\n\tlet flow: vec3<f32> = vec3<f32>(4.1 * (0.5 - xpart) * pow(ypartClippedn, 4.), -2. * xfuel * pow(ypartClippedn, 64.), 0.);\n\tlet timing: vec3<f32> = realTime * vec3<f32>(0., -1.7, 1.1) + flow;\n\n\tlet displacePos: vec3<f32> = vec3<f32>(1., 0.5, 1.) * 2.4 * position + realTime * vec3<f32>(0.01, -0.7, 1.3);\n\tlet displace3: vec3<f32> = vec3<f32>(noiseStackUV(displacePos, 2, 0.4, 0.1), 0.);\n\n\tlet noiseCoord: vec3<f32> = (vec3<f32>(2., 1., 1.) * position + timing + 0.4 * displace3) / 1.;\n\tlet noise: f32 = noiseStack(noiseCoord, 3, 0.4);\n\n\tlet flames: f32 = pow(ypartClipped, 0.3 * xfuel) * pow(noise, 0.3 * xfuel);\n\n\tlet f: f32 = ypartClippedFalloff * pow(1. - flames * flames * flames, 8.);\n\tlet fff: f32 = f * f * f;\n\tlet fire: vec3<f32> = 1.5 * vec3<f32>(f, fff, fff * fff);\n\n\t// smoke\n\tlet smokeNoise: f32 = 0.5 + snoise(0.4 * position + timing * vec3<f32>(1., 1., 0.2)) / 2.;\n\tlet smoke: vec3<f32> = vec3<f32>(0.3 * pow(xfuel, 3.) * pow(ypart, 2.) * (smokeNoise + 0.4 * (1. - noise)));\n\n\t// sparks\n\tvar sparkGridSize: f32 = 30.;\n\tvar sparkCoord: vec2<f32> = fragCoord - vec2<f32>(2. * offset.x, 190. * realTime);\n\tsparkCoord = sparkCoord - (30. * noiseStackUV(0.01 * vec3<f32>(sparkCoord, 30. * time), 1, 0.4, 0.1));\n\tsparkCoord = sparkCoord + (100. * flow.xy);\n\n\tif (((sparkCoord.y / sparkGridSize) % 2.) < 1.) { sparkCoord.x = sparkCoord.x + (0.5 * sparkGridSize); }\n\tlet sparkGridIndex: vec2<f32> = vec2<f32>(floor(sparkCoord / sparkGridSize));\n\tlet sparkRandom: f32 = prng(sparkGridIndex);\n\tlet sparkLife: f32 = min(10. * (1. - min((sparkGridIndex.y + 190. * realTime / sparkGridSize) / (24. - 20. * sparkRandom), 1.)), 1.);\n\tvar sparks: vec3<f32> = vec3<f32>(0.);\n\tif (sparkLife > 0.) {\n\t\tlet sparkSize: f32 = xfuel * xfuel * sparkRandom * 0.08;\n\t\tlet sparkRadians: f32 = 999. * sparkRandom * 2. * PI + 2. * time;\n\t\tlet sparkCircular: vec2<f32> = vec2<f32>(sin(sparkRadians), cos(sparkRadians));\n\t\tlet sparkOffset: vec2<f32> = (0.5 - sparkSize) * sparkGridSize * sparkCircular;\n\t\tlet sparkModulus: vec2<f32> = ((sparkCoord + sparkOffset) % sparkGridSize) - 0.5 * vec2<f32>(sparkGridSize);\n\t\tlet sparkLength: f32 = length(sparkModulus);\n\t\tlet sparksGray: f32 = max(0., 1. - sparkLength / (sparkSize * sparkGridSize));\n\t\tsparks = sparkLife * sparksGray * vec3<f32>(1., 0.3, 0.);\n\t}\n\n\tfragColor = vec4<f32>(max(fire, sparks) + smoke, 1.);\n\ttextureStore(texture, y_inverted_location, toLinear(fragColor));\n} \n\n\n\n"
  },
  {
    "path": "assets/shaders/fluid/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n// var<private> R: vec2<f32>;\n\nfn lnln(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n\treturn length(p - a - (b - a) * clamp(dot(p - a, b - a) / dot(b - a, b - a), 0., 1.));\n} \n\nfn T(U: vec2<f32>) -> vec4<f32> {\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(buffer_a, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(buffer_a, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(buffer_a, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(buffer_a, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar Q: vec4<f32>;\n\tvar U = vec2<f32>(f32(location.x), f32(location.y) );\n\n\t// let R = uni.iResolution.xy;\n\tlet O: vec2<f32> = U;\n\tvar A: vec2<f32> = U + vec2<f32>(1., 0.);\n\tvar B: vec2<f32> = U + vec2<f32>(0., 1.);\n\tvar C: vec2<f32> = U + vec2<f32>(-1., 0.);\n\tvar D: vec2<f32> = U + vec2<f32>(0., -1.);\n\tvar u: vec4<f32> = T(U);\n\tvar a: vec4<f32> = T(A);\n\tvar b: vec4<f32> = T(B);\n\tvar c: vec4<f32> = T(C);\n\tvar d: vec4<f32> = T(D);\n\tvar p: vec4<f32> = vec4<f32>(0.);\n\tvar g: vec2<f32> = vec2<f32>(0.);\n\n\tfor (var i: i32 = 0; i < 2; i = i + 1) {\n\t\tU = U - (u.xy);\n\t\tA = A - (a.xy);\n\t\tB = B - (b.xy);\n\t\tC = C - (c.xy);\n\t\tD = D - (d.xy);\n\n\t\tp = p + (vec4<f32>(length(U - A), length(U - B), length(U - C), length(U - D)) - 1.);\n\n\t\tg = g + (vec2<f32>(a.z - c.z, b.z - d.z));\n\t\tu = T(U);\n\t\ta = T(A);\n\t\tb = T(B);\n\t\tc = T(C);\n\t\td = T(D);\n\t}\n\n\tQ = u;\n\tlet N: vec4<f32> = 0.25 * (a + b + c + d);\n\tQ = mix(Q, N, vec4<f32>(0., 0., 1., 0.));\n\tvar Qxy = Q.xy;\n\tQxy = Q.xy - (g / 10. / f32(2.));\n\tQ.x = Qxy.x;\n\tQ.y = Qxy.y;\n\tQ.z = Q.z + ((p.x + p.y + p.z + p.w) / 10.);\n\tQ.z = Q.z * (0.95);\n\n\tlet mouse: vec4<f32> = textureLoad(buffer_d, vec2<i32>(vec2<f32>(0.5) * R));\n\tlet q: f32 = lnln(U, mouse.xy, mouse.zw);\n\tlet m: vec2<f32> = mouse.xy - mouse.zw;\n\tlet l: f32 = length(m);\n\n\tif (mouse.z > 0. && l > 0.) {\n\t\tvar Qxyw = Q.xyw;\n        Qxyw = mix(Q.xyw, vec3<f32>(-normalize(m) * min(l, 20.) / 25., 1.), max(0., 5. - q) / 25.);\n        Q.x = Qxyw.x;\n        Q.y = Qxyw.y;\n        Q.w = Qxyw.z;\n\t}\n\t// ifuni.iFrame < 1) { \n        \n    #ifdef INIT\n        Q = vec4<f32>(0.); \n    #endif\n        \n        \n\tif (uni.iFrame < 140. && length(U - 0.5 * R) < 20.) {\n        var Qxyw = Q.xyw;\n        Qxyw = vec3<f32>(0., 0.1, 1.);\n        Q.x = Qxyw.x;\n        Q.y = Qxyw.y;\n        Q.w = Qxyw.z; \n    }\n\tif (U.x < 1. || U.y < 1. || R.x - U.x < 1. || R.y - U.y < 1.) { \n        var Qxyw = Q.xyw;\n        Qxyw = Q.xyw * (0.);\n        Q.x = Qxyw.x;\n        Q.y = Qxyw.y;\n        Q.w = Qxyw.z; \n    }\n\n    textureStore(buffer_a, location, Q);\n} \n\n"
  },
  {
    "path": "assets/shaders/fluid/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    \n} \n\n"
  },
  {
    "path": "assets/shaders/fluid/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n   \n} \n\n"
  },
  {
    "path": "assets/shaders/fluid/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar p: vec4<f32> = textureLoad(buffer_d, vec2<i32>(fragCoord));\n\tif (uni.iMouse.z > 0.) {\n\t\tif (p.z > 0.) {\t\t\n            fragColor = vec4<f32>(uni.iMouse.xy, p.xy);\n\t\t} else { \t\t\n            fragColor = vec4<f32>(uni.iMouse.xy, uni.iMouse.xy);\n\t\t}\n\t} else { \t\n        fragColor = vec4<f32>(-uni.iResolution.xy, -uni.iResolution.xy);\n\t}\n\n    textureStore(buffer_d, location, fragColor);\n} \n\n\n"
  },
  {
    "path": "assets/shaders/fluid/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n\n\n\n\n\nfn t(v: vec2<f32>) -> vec4<f32> {\n\treturn textureLoad(buffer_a, vec2<i32>(v ));\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar C: vec4<f32>;\n\tlet U = vec2<f32>( f32(location.x), f32(location.y) );\n\n\tvar me: vec4<f32> = t(U);\n\tme.z = me.z - (1.);\n\tC = 1. - 3. * me.wwww;\n\n\tlet d: vec3<f32> = vec3<f32>(\n        t(U + vec2<f32>(1., 0.)).w - t(U - vec2<f32>(1., 0.)).w, \n        t(U + vec2<f32>(0., 1.)).w - t(U - vec2<f32>(0., 1.)).w, \n        2.\n    );\n\n\tvar Cxyz = C.xyz;\n\tCxyz = C.xyz - (\n        max(\n            vec3<f32>(0.), \n            sin(vec3<f32>(\n                100. * length(me.xy), \n                -5. * me.z, \n                368. * d.y\n            ) * me.w)\n        ));\n\n\tC.x = Cxyz.x;\n\tC.y = Cxyz.y;\n\tC.z = Cxyz.z;\n    C.a = 1.;\n\n    // let col_debug_info = show_debug_info(location, C.xyz);\n\n    // textureStore(texture, y_inverted_location, toLinear(col_debug_info));\n\n    textureStore(texture, y_inverted_location, (C));\n    // textureStore(texture, y_inverted_location, t(U));\n}"
  },
  {
    "path": "assets/shaders/image_load.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: i32;\n    iSampleRate: i32;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n    \n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x);\n    let alive = randomNumber > 0.9;\n    let color = vec4<f32>(f32(alive));\n\n    textureStore(texture, location, color);\n}\n\n\n// fn get(location: vec2<i32>, offset_x: i32, offset_y: i32) -> i32 {\n//     let value: vec4<f32> = textureLoad(texture, location + vec2<i32>(offset_x, offset_y));\n//     return i32(value.x);\n// }\n\n// fn count_alive(location: vec2<i32>) -> i32 {\n//     return get(location, -1, -1) +\n//            get(location, -1,  0) +\n//            get(location, -1,  1) +\n//            get(location,  0, -1) +\n//            get(location,  0,  1) +\n//            get(location,  1, -1) +\n//            get(location,  1,  0) +\n//            get(location,  1,  1);\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let n_alive = count_alive(location);\n    // let color = vec4<f32>(f32(n_alive) / 8.0);\n\n    // var alive: bool;\n    // if (n_alive == 3) {\n    //     alive = true;\n    // } else if (n_alive == 2) {\n    //     let currently_alive = get(location, 0, 0);\n    //     alive = bool(currently_alive);\n    // } else {\n    //     alive = false;\n    // }\n\n    var alive = true;\n\n    // let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    // if (value.x > 0.51) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_b, vec2<i32>(0,1));\n    // if (value.x > 0.74) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_c, vec2<i32>(0,1));\n    // if (value.x > 0.61) {\n    //     alive = false;\n    // }\n\n    let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    if (value.x > 0.79) {\n        alive = false;\n    }\n\n    // if (ga > 2) {\n    //     alive = true;\n    // }\n\n    // if (uni.iTime > 1.0) {\n    //     alive = false;\n    // }\n\n    // alive = false;\n\n    storageBarrier();\n\n    textureStore(texture, location, vec4<f32>(f32(alive)));\n}\n\n\n"
  },
  {
    "path": "assets/shaders/interactive_fluid_simulation/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_a, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_a, location, vec4<f32>(0.094));\n\n    if (uni.iTime > 1.0) {\n        textureStore(buffer_a, location, vec4<f32>(0.95));\n    }\n}"
  },
  {
    "path": "assets/shaders/interactive_fluid_simulation/buffer_b.wgsl",
    "content": "\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: i32;\n    iSampleRate: i32;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n    \n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_b, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_b, location, vec4<f32>(0.85));\n\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_b, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "assets/shaders/interactive_fluid_simulation/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_c, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_c, location, vec4<f32>(0.95));\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_c, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "assets/shaders/interactive_fluid_simulation/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let color = vec4<f32>(0.60);\n\n    textureStore(buffer_d, location, color);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_d, location, vec4<f32>(0.7));\n\n\t// let p: vec4<f32> = texture(iChannel0, fragCoord/iResolution.xy);\n\t// if (uni.iMouse.z>0.) {\n\t// \tif (p.z>0.) {\t\tfragColor = vec4<f32>(uni.iMouse.xy, p.xy);\n\t// \t} else {\t\tfragColor = vec4<f32>(uni.iMouse.xy, uni.iMouse.xy);\n\t// \t}\n\t\n\t// } else {\tfragColor = vec4<f32>(-uni.iResolution.xy, -uni.iResolution.xy);\n\t// }\n\n\n    if (uni.iTime > 1.0) {\n        storageBarrier();\n        textureStore(buffer_d, location, vec4<f32>(0.95));\n    }\n\n    // storageBarrier();\n}\n\n// fn mainImage( fragColor: vec4<f32>,  fragCoord: vec2<f32>) -> () {\n// \tlet p: vec4<f32> = texture(iChannel0, fragCoord/iResolution.xy);\n// \tif (iMouse.z>0.) {\n// \t\tif (p.z>0.) {\t\tfragColor = vec4<f32>(iMouse.xy, p.xy);\n// \t\t} else {\t\tfragColor = vec4<f32>(iMouse.xy, iMouse.xy);\n// \t\t}\n\t\n// \t} else {\tfragColor = vec4<f32>(-iResolution.xy, -iResolution.xy);\n// \t}\n\n// }"
  },
  {
    "path": "assets/shaders/interactive_fluid_simulation/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x);\n    let alive = randomNumber > 0.9;\n    let color = vec4<f32>(f32(alive));\n\n    textureStore(texture, location, color);\n}\n\nfn t(v: vec2<i32>) -> vec4<f32> {\n\treturn textureLoad(buffer_a, v );\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\n    var me: vec4<f32> = t(location) ;\n    let U = location;\n\n\tme.z = me.z - (1.);\n\tvar C = 1. - 3.*me.www;\n\tlet d: vec3<f32> = vec3<f32>(t(U+vec2<i32>(1, 0)).w-t(U-vec2<i32>(1, 0)).w, t(U+vec2<i32>(0, 1)).w-t(U-vec2<i32>(0, 1)).w, 2.);\n\tC = C - (max(vec3<f32>(0.), sin(vec3<f32>(100.*length(me.xy), -5.*me.z, 368.*d.y)*me.w)));\n\n\n    storageBarrier();\n\n    textureStore(texture, location, vec4<f32>(C.x, C.y, C.z, me.w));\n}\n\n\n\n// fn mainImage( C: vec4<f32>,  U: vec2<f32>) -> () {\n// \tlet me: vec4<f32> = t(U);\n// \tme.z = me.z - (1.);\n// \tC = 1.-3.*me.wwww;\n// \tlet d: vec3<f32> = vec3<f32>(t(U+vec2<f32>(1, 0)).w-t(U-vec2<f32>(1, 0)).w, t(U+vec2<f32>(0, 1)).w-t(U-vec2<f32>(0, 1)).w, 2.);\n// \tC.xyz = C.xyz - (max(vec3<f32>(0), sin(vec3<f32>(100.*length(me.xy), -5.*me.z, 368.*d.y)*me.w)));\n\n// }\n\n"
  },
  {
    "path": "assets/shaders/liquid/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\nstruct Particle {\n    position: vec2<f32>;\n    velocity: vec2<f32>;\n    mass: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\nlet fluid_rho: f32 = 0.5;\nlet dt: f32 = 1.5;\nlet border_h = 5.0;\nlet h: f32 = 1.;\n\nfn Pf(rho: vec2<f32>) -> f32\n{\n    //return 0.2*rho.x; //gas\n    let GF: f32 = 1.;//smoothstep(0.49, 0.5, 1. - rho.y);\n    return mix(0.5*rho.x, 0.04*rho.x*(rho.x/fluid_rho - 1.), GF); //water pressure\n}\n\nfn Rot(ang: f32) -> mat2x2<f32>\n{\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang)); \n}\n\nfn Dir(ang: f32) -> vec2<f32>\n{\n    return vec2<f32>(cos(ang), sin(ang));\n}\n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  let d = (abs(p) - b) ;\n  return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n}\n\nfn border(p: vec2<f32>, uni: CommonUniform) -> f32\n{\n    let R: vec2<f32> = uni.iResolution;\n    \n    let bound: f32 = -sdBox(p - R*0.5, R*vec2<f32>(0.5, 0.5)); \n    let box: f32 = sdBox(Rot(0.*uni.iTime)*(p - R*vec2<f32>(0.5, 0.6)) , R*vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R*vec2<f32>(0.5, 0.7), R*vec2<f32>(1.5, 0.5));\n    return max(drain,min(bound, box));\n}\n\n\nfn bN( p: vec2<f32>, uni: CommonUniform ) -> vec3<f32>\n{\n    let dx: vec3<f32> = vec3<f32>(-h, 0.0 , h);\n\n    let idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n    let r: vec3<f32> = idx.zyw*border(p + dx.zy, uni)\n           + idx.xyw*border(p + dx.xy, uni)\n           + idx.yzw*border(p + dx.yz, uni)\n           + idx.yxw*border(p + dx.yx, uni);\n\n    return vec3<f32>(normalize(r.xy), r.z + 1e-4);\n\n}\n\n\nfn pack(x: vec2<f32>) -> u32 \n{\n    var q: vec2<f32>;\n    q.x = 65534.0*clamp(0.5*x.x+0.5, 0., 1.);\n    q.y = 65534.0*clamp(0.5*x.y+0.5, 0., 1.);\n    return u32(round(q.x)) + 65535u*u32(round(q.y));\n}\n\nfn unpack(a: u32) -> vec2<f32>\n{\n    let q = vec2<u32>(a % 65535u, a / 65535u);\n    let p = vec2<f32>(\n        clamp(f32(q.x) / 65534.0, 0.,1.)*2.0 - 1.0,\n        clamp(f32(q.y) / 65534.0, 0.,1.)*2.0 - 1.0\n    );\n    return p;\n}\n\nfn decode(x: f32) -> vec2<f32>\n{\n    let X: u32 = bitcast<u32>(x);\n    return unpack(X); \n}\n\nfn encode(x: vec2<f32>) -> f32\n{\n    let X: u32 = pack(x);\n    let casted: f32 = bitcast<f32>(X);\n    return casted;\n}\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> Particle\n{\n    var P: Particle;\n    P.position = decode(data.x) + pos;\n    P.velocity = decode(data.y);\n    P.mass = data.zw;\n    return P;\n}\n\n\nfn saveParticle(in_p: Particle, pos: vec2<f32>) -> vec4<f32>\n{\n    var P: Particle = in_p;\n    // P.position = clamp(P.position - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    P.position.x = clamp(P.position.x - pos.x, -0.5, 0.5);\n    P.position.y = clamp(P.position.y - pos.y, -0.5, 0.5);\n    return vec4<f32>(encode(P.position), encode(P.velocity), P.mass.x, P.mass.y);\n}\n\nfn hash32(p: vec2<f32>) -> vec3<f32>\n{\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n    p3 = p3 + dot(p3, p3.yxz+33.33);\n    return fract((p3.xxy+p3.yzz)*p3.zyx);\n}\n\nfn G(x: vec2<f32>) -> f32\n{\n    return exp(-dot(x,x));\n}\n\nfn G0(x: vec2<f32>) -> f32\n{\n    return exp(-length(x));\n}\n\nfn distribution(x: vec2<f32>,  p: vec2<f32>, K: f32) -> vec3<f32>\n{\n    let omin: vec2<f32> = clamp(x - K*0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K*0.5, p - 0.5, p + 0.5); \n    return vec3<f32>(0.5*(omin + omax), (omax.x - omin.x)*(omax.y - omin.y)/(K*K));\n}\n\n\n//diffusion and advection basically\nfn Reintegration(buffer: texture_storage_2d<rgba8unorm, read_write>, P: Particle, pos: vec2<f32>) -> Particle\n{\n    var particle: Particle = P;\n\n\n    \n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    var i: i32 = -2;\n    loop  {\n        if (i > 2) { break; }\n\n        var j: i32 = -2;\n        loop {\n            if (j > 2) { break; }\n\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i),f32(j));\n\n            let data: vec4<f32> = textureLoad(buffer, vec2<i32>(tpos));\n        \n            var P0: Particle = getParticle(data, tpos);\n        \n            P0.position = P0.position + P0.velocity*dt; //integrate position\n\n            let difR: f32 = 0.9 + 0.21*smoothStep(fluid_rho*0., fluid_rho*0.333, P0.mass.x);\n            let D: vec3<f32> = distribution(P0.position, pos, difR);\n            //the deposited mass into this cell\n            let m: f32 = P0.mass.x*D.z;\n            \n            //add weighted by mass\n            particle.position = particle.position + D.xy*m;\n            particle.velocity =  particle.velocity + P0.velocity*m;\n            particle.mass.y = particle.mass.y  +  P0.mass.y*m;\n            \n            //add mass\n            particle.mass.x = particle.mass.x + m;\n\n        }\n    }\n    // range(i, -2, 2) range(j, -2, 2)\n\n    //normalization\n    if(particle.mass.x != 0.)\n    {\n        particle.position = particle.position / particle.mass.x;\n        particle.velocity= particle.velocity / particle.mass.x;\n        particle.mass.y = particle.mass.y / particle.mass.x;\n    }\n\n    return particle;\n}\n\n//force calculation and integration\nfn Simulation(\n    buffer: texture_storage_2d<rgba8unorm, read_write>,   \n    P: Particle,  \n    pos: vec2<f32>, \n    Mouse: vec4<f32>,\n    uni: CommonUniform\n    ) -> Particle\n{\n    var particle: Particle = P;\n    \n    \n    //Compute the SPH force\n    var F: vec2<f32> = vec2<f32>(0.);\n    var  avgV: vec3<f32> = vec3<f32>(0.);\n\n    var i: i32 = -2;\n    loop  {\n        if (i > 2) { break; }\n\n        var j: i32 = -2;\n        loop {\n            if (j > 2) { break; }\n\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n            // let  data: vec4<f32> = texel(ch, tpos);\n            let data: vec4<f32> = textureLoad(buffer, vec2<i32>(tpos));\n\n            let  P0: Particle = getParticle(data, tpos);\n            let  dx: vec2<f32> = P0.position - particle.position;\n            let  avgP: f32 = 0.5*P0.mass.x*(Pf(particle.mass) + Pf(P0.mass)); \n            F = F - 0.5*G(1.*dx)*avgP*dx;\n            avgV = avgV + P0.mass.x*G(1.*dx)*vec3<f32>(P0.velocity,1.);\n        }\n    }\n\n    avgV.x = avgV.x / avgV.z;\n    avgV.y = avgV.y / avgV.z;\n\n    //viscosity\n    F = F + 0.*particle.mass.x*(avgV.xy - particle.velocity);\n    \n    //gravity\n    F = F + particle.mass.x*vec2<f32>(0., -0.0004);\n\n    if(Mouse.z > 0.)\n    {\n        let dm: vec2<f32> =(Mouse.xy - Mouse.zw)/10.; \n        let d: f32 = distance(Mouse.xy, particle.position)/20.;\n        F = F + 0.001*dm*exp(-d*d);\n       // particle.mass.y += 0.1*exp(-40.*d*d);\n    }\n    \n    //integrate\n    particle.velocity = particle.velocity + F*dt/particle.mass.x;\n\n    //border \n    let N: vec3<f32> = bN(particle.position, uni);\n    let vdotN : f32 = step(N.z, border_h) * dot(-N.xy, particle.velocity);\n    particle.velocity = particle.velocity + 0.5*(N.xy*vdotN + N.xy*abs(vdotN));\n    particle.velocity = particle.velocity + 0.*particle.mass.x*N.xy*step(abs(N.z), border_h)*exp(-N.z);\n    \n    if (N.z < 0.) { particle.velocity = vec2<f32>(0.); }\n    \n    \n    //velocity limit\n    let v: f32 = length(particle.velocity);\n    if (v > 1.0) { \n        particle.velocity = particle.velocity / v; \n    } \n\n    // particle.velocity = particle.velocity / (v > 1.) ? v : 1.;\n\n    return particle;\n}\n\n\n// // /*\n// // vec3 distribution(vec2 x, vec2 p, float K)\n// // {\n// //     vec4 aabb0 = vec4(p - 0.5, p + 0.5);\n// //     vec4 aabb1 = vec4(x - K*0.5, x + K*0.5);\n// //     vec4 aabbX = vec4(max(aabb0.xy, aabb1.xy), min(aabb0.zw, aabb1.zw));\n// //     vec2 center = 0.5*(aabbX.xy + aabbX.zw); //center of mass\n// //     vec2 size = max(aabbX.zw - aabbX.xy, 0.); //only positive\n// //     float m = size.x*size.y/(K*K); //relative amount\n// //     //if any of the dimensions are 0 then the mass is 0\n// //     return vec3(center, m);\n// // }*/\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_a, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_a, location, vec4<f32>(0.094));\n\n    if (uni.iTime > 1.0) {\n        textureStore(buffer_a, location, vec4<f32>(0.95));\n    }\n}\n\n"
  },
  {
    "path": "assets/shaders/liquid/buffer_b.wgsl",
    "content": "\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: i32;\n    iSampleRate: i32;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n    \n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_b, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_b, location, vec4<f32>(0.85));\n\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_b, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "assets/shaders/liquid/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_c, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_c, location, vec4<f32>(0.95));\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_c, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "assets/shaders/liquid/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let color = vec4<f32>(0.60);\n\n    textureStore(buffer_d, location, color);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_d, location, vec4<f32>(0.7));\n\n    if (uni.iTime > 1.0) {\n        storageBarrier();\n        textureStore(buffer_d, location, vec4<f32>(0.95));\n    }\n\n    // storageBarrier();\n}"
  },
  {
    "path": "assets/shaders/liquid/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x);\n    let alive = randomNumber > 0.9;\n    let color = vec4<f32>(f32(alive));\n\n    textureStore(texture, location, color);\n}\n\n\n// fn get(location: vec2<i32>, offset_x: i32, offset_y: i32) -> i32 {\n//     let value: vec4<f32> = textureLoad(texture, location + vec2<i32>(offset_x, offset_y));\n//     return i32(value.x);\n// }\n\n// fn count_alive(location: vec2<i32>) -> i32 {\n//     return get(location, -1, -1) +\n//            get(location, -1,  0) +\n//            get(location, -1,  1) +\n//            get(location,  0, -1) +\n//            get(location,  0,  1) +\n//            get(location,  1, -1) +\n//            get(location,  1,  0) +\n//            get(location,  1,  1);\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let n_alive = count_alive(location);\n    // let color = vec4<f32>(f32(n_alive) / 8.0);\n\n    // var alive: bool;\n    // if (n_alive == 3) {\n    //     alive = true;\n    // } else if (n_alive == 2) {\n    //     let currently_alive = get(location, 0, 0);\n    //     alive = bool(currently_alive);\n    // } else {\n    //     alive = false;\n    // }\n\n    var alive = true;\n\n    // let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    // if (value.x > 0.51) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_b, vec2<i32>(0,1));\n    // if (value.x > 0.74) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_c, vec2<i32>(0,1));\n    // if (value.x > 0.61) {\n    //     alive = false;\n    // }\n\n    let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    if (value.x > 0.79) {\n        alive = false;\n    }\n\n    // if (ga > 2) {\n    //     alive = true;\n    // }\n\n    // if (uni.iTime > 1.0) {\n    //     alive = false;\n    // }\n\n    // alive = false;\n\n    storageBarrier();\n\n    textureStore(texture, location, vec4<f32>(f32(alive)));\n}\n\n\n"
  },
  {
    "path": "assets/shaders/liquid_toy/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\nlet speed: f32 = 0.01;\nlet scale: f32 = 0.1;\nlet falloff: f32 = 3.;\nlet fade: f32 = 0.4;\nlet strength: f32 = 1.;\nlet range: f32 = 5.;\nfn random3(c: vec3<f32>) -> vec3<f32> {\n\tvar j: f32 = 4096. * sin(dot(c, vec3<f32>(17., 59.4, 15.)));\n\tvar r: vec3<f32>;\n\tr.z = fract(512. * j);\n\tj = j * (0.125);\n\tr.x = fract(512. * j);\n\tj = j * (0.125);\n\tr.y = fract(512. * j);\n\treturn r - 0.5;\n} \n\nlet F3: f32 = 0.3333333;\nlet G3: f32 = 0.1666667;\nfn simplex3d(p: vec3<f32>) -> f32 {\n\tlet s: vec3<f32> = floor(p + dot(p, vec3<f32>(F3)));\n\tvar x: vec3<f32> = p - s + dot(s, vec3<f32>(G3));\n\tlet e: vec3<f32> = step(vec3<f32>(0.), x - x.yzx);\n\tlet i1: vec3<f32> = e * (1. - e.zxy);\n\tlet i2: vec3<f32> = 1. - e.zxy * (1. - e);\n\tlet x1: vec3<f32> = x - i1 + G3;\n\tlet x2: vec3<f32> = x - i2 + 2. * G3;\n\tlet x3: vec3<f32> = x - 1. + 3. * G3;\n\tvar w: vec4<f32>;\n\tvar d: vec4<f32>;\n\tw.x = dot(x, x);\n\tw.y = dot(x1, x1);\n\tw.z = dot(x2, x2);\n\tw.w = dot(x3, x3);\n\tw = max(0.6 - w, vec4<f32>(0.));\n\td.x = dot(random3(s), x);\n\td.y = dot(random3(s + i1), x1);\n\td.z = dot(random3(s + i2), x2);\n\td.w = dot(random3(s + 1.), x3);\n\tw = w * (w);\n\tw = w * (w);\n\td = d * (w);\n\treturn dot(d, vec4<f32>(52.));\n} \n\nlet rot1: mat3x3<f32> = mat3x3<f32>(\n    vec3<f32>(-0.37, 0.36, 0.85), \n    vec3<f32>(-0.14, -0.93, 0.34), \n    vec3<f32>(0.92, 0.01, 0.4));\n\nlet rot2: mat3x3<f32> = mat3x3<f32>(\n     vec3<f32>(-0.55, -0.39, 0.74), \n     vec3<f32>(0.33, -0.91, -0.24), \n     vec3<f32>(0.77, 0.12, 0.63));\n\nlet rot3: mat3x3<f32> = mat3x3<f32>(\n     vec3<f32>(-0.71, 0.52, -0.47), \n     vec3<f32>(-0.08, -0.72, -0.68), \n     vec3<f32>(-0.7, -0.45, 0.56));\n\nfn simplex3d_fractal(m: vec3<f32>) -> f32 {\n\treturn 0.5333333 * simplex3d(m * rot1) + 0.2666667 * simplex3d(2. * m * rot2) + 0.1333333 * simplex3d(4. * m * rot3) + 0.0666667 * simplex3d(8. * m);\n} \n\nfn dummy(p3: vec3<f32>) -> vec3<f32> {\n\tvar value: f32 = simplex3d(p3 * 16.);\n\tvalue = 0.5 + 0.5 * value;\n\treturn vec3<f32>(value);\n} \n\nfn fbm(p: vec3<f32>) -> vec3<f32> {\n\tvar result: vec3<f32> = vec3<f32>(0.);\n\tvar amplitude: f32 = 0.5;\n\n\tfor (var index: f32 = 0.; index < 3.; index  = index + 1.) {\n\t\tlet what: vec3<f32> = dummy(p / amplitude);\n\t\tresult = result + (what * amplitude);\n\t\tamplitude = amplitude / (falloff);\n\t}\n\n\treturn result;\n} \n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar uv: vec2<f32> = (fragCoord.xy - uni.iResolution.xy / 2.) / uni.iResolution.y;\n\tvar spice: vec3<f32> = fbm(vec3<f32>(uv * scale, uni.iTime * speed));\n\tlet t: f32 = uni.iTime * 2.;\n\tlet mouse: vec2<f32> = (uni.iMouse.xy - uni.iResolution.xy / 2.) / uni.iResolution.y;\n\tif (uni.iMouse.z > 0.5) {\tuv = uv - (mouse);\n\t} else { \tuv = uv - (vec2<f32>(cos(t), sin(t)) * 0.3);\n\t}\n\tvar paint: f32 = smoothstep(0.1, 0., length(uv));\n\tvar offset: vec2<f32> = vec2<f32>(0.);\n\tuv = fragCoord.xy / uni.iResolution.xy;\n\n\tlet data: vec4<f32> = sample_texture(buffer_a, uv);\n\tlet unit: vec3<f32> = vec3<f32>(range / uni.iResolution.xy, 0.);\n\n\tlet normal: vec3<f32> = normalize(vec3<f32>(\n        sample_texture(buffer_a, uv - unit.xz).r \n        - sample_texture(buffer_a, uv + unit.xz).r, sample_texture(buffer_a, uv - unit.zy).r \n        - sample_texture(buffer_a, uv + unit.zy).r, data.x * data.x) + 0.001);\n\n\toffset = offset - (normal.xy);\n\tspice.x = spice.x * (6.28 * 2.);\n\tspice.x = spice.x + (uni.iTime);\n\toffset = offset + (vec2<f32>(cos(spice.x), sin(spice.x)));\n\tlet frame: vec4<f32> = sample_texture(buffer_a, uv + strength * offset / uni.iResolution.xy);\n\tpaint = max(paint, frame.x - uni.iTimeDelta * fade);\n\tfragColor = vec4<f32>(clamp(paint, 0., 1.));\n\n    textureStore(buffer_a, location, fragColor);\n} \n\n\n\n"
  },
  {
    "path": "assets/shaders/liquid_toy/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/liquid_toy/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/liquid_toy/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/liquid_toy/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\n\n\n// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar uv: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\t// let dither: vec3<f32> = textureSample(blue_noise_texture, \n    //     blue_noise_texture_sampler, fragCoord.xy / 1024.).rgb;\n    // let dither: vec3<f32> = textureSample(rgba_noise_256_texture, \n    //     rgba_noise_256_texture_sampler, fragCoord.xy / 256.).rgb;\n\n    let dither: vec3<f32> =  textureSampleGrad(blue_noise_texture,\n                     blue_noise_texture_sampler,\n                      fragCoord.xy / 1024.,\n                      vec2<f32>(0.),\n                      vec2<f32>(0.)).rbg;\n\n\tlet data: vec4<f32> = sample_texture(buffer_a, uv);\n\tlet gray: f32 = data.x;\n\tlet range: f32 = 3.;\n\tlet unit: vec3<f32> = vec3<f32>(range / uni.iResolution.xy, 0.);\n\tlet normal: vec3<f32> = normalize(vec3<f32>(sample_texture(buffer_a, uv + unit.xz).r \n        - sample_texture(buffer_a, uv - unit.xz).r, \n        sample_texture(buffer_a, uv - unit.zy).r \n        - sample_texture(buffer_a, uv + unit.zy).r, gray * gray * gray));\n\n\tvar color: vec3<f32> = vec3<f32>(0.3) * (1. - abs(dot(normal, vec3<f32>(0., 0., 1.))));\n\tlet dir: vec3<f32> = normalize(vec3<f32>(0., 1., 2.));\n\tlet specular: f32 = pow(dot(normal, dir) * 0.5 + 0.5, 20.);\n\tcolor = color + (vec3<f32>(0.5) * smoothstep(0.2, 1., specular));\n\tlet tint: vec3<f32> = 0.5 + 0.5 * cos(vec3<f32>(1., 2., 3.) * 1. + dot(normal, dir) * 4. - uv.y * 3. - 3.);\n\tcolor = color + (tint * smoothstep(0.15, 0., gray));\n\tcolor = color - (dither.x * 0.1);\n\tvar background: vec3<f32> = vec3<f32>(1.);\n\tbackground = background * (smoothstep(1.5, -0.5, length(uv - 0.5)));\n\tcolor = mix(background, clamp(color, vec3<f32>(0.), vec3<f32>(1.)), smoothstep(0.01, 0.1, gray));\n\tif (uni.iMouse.z > 0.5 && uni.iMouse.x / uni.iResolution.x < 0.1) {\n\t\tif (uv.x < 0.33) {\t\tcolor = vec3<f32>(gray);\n\t\t} else { \t\tif (uv.x < 0.66) {\t\tcolor = normal * 0.5 + 0.5;\n\t\t} else { \t\tcolor = vec3<f32>(tint);\n\t\t}\n\t\t}\n\t}\n\tfragColor = vec4<f32>(color, 1.);\n    textureStore(texture, y_inverted_location, toLinear(fragColor));\n} \n\n\n\n\n"
  },
  {
    "path": "assets/shaders/love_and_domination/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\nlet s2 = 30.;\n\nlet BLUR_DEPTH = 25.;\n\nlet SPEED = 2.;\n\nlet MOUSE_SIZE = 60.;\n\nlet texture_const = 255.;\n\n\n\nvar<private>  R: vec2<f32>;\n\nfn A(location: vec2<f32>) -> vec4<f32> {\n\treturn textureLoad(buffer_a, vec2<i32>(location)) * texture_const;\n} \n\n// fn B(location: vec2<f32>)-> vec4<f32> {\n// \treturn textureLoad(buffer_b, vec2<i32>(location));\n// } \n\nfn C(location: vec2<f32>) -> vec4<f32> {\n\treturn textureLoad(buffer_c, vec2<i32>(location)) * texture_const;\n} \n\nfn X(U: vec2<f32>, Q2: vec4<f32>, u: vec2<f32>) -> vec4<f32> {\n    var Q = Q2;\n\tlet p: vec4<f32> = A(U + u);\n\tif (length(p.xy - U) < length(Q.xy - U)) {\t\n        Q = p;\n\t}\n    return Q;\n\n} \n\nfn mod2(x: f32, d: f32) -> f32 {\n\tlet y: f32 = (x / d - floor(x / d)) * d;\n\treturn y;\n\n} \n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\n\n// fn mainImage( Q: vec4<f32>,  U: vec2<f32>) -> () {\n\n    var U = vec2<f32>(f32(location.x), f32(location.y));\n\tR = uni.iResolution.xy;\n\n    var Q: vec4<f32> = A(U);\n    Q = X(U, Q, vec2<f32>(1., 0.));\n    Q = X(U, Q, vec2<f32>(0., 1.));\n    Q = X(U, Q, vec2<f32>(0., -1.));\n    Q = X(U, Q, vec2<f32>(-1., 0.));\n    Q = X(U, Q, vec2<f32>(1., 1.));\n    Q = X(U, Q, vec2<f32>(-1., 1.));\n    Q = X(U, Q, vec2<f32>(1., -1.));\n    Q = X(U, Q, vec2<f32>(-1., -1.));\n    let n: vec4<f32> = C(U + vec2<f32>(0., 1.));\n    let e: vec4<f32> = C(U + vec2<f32>(1., 0.));\n    let s: vec4<f32> = C(U + vec2<f32>(0., -1.));\n    let w: vec4<f32> = C(U + vec2<f32>(-1., 0.));\n    let dx: vec3<f32> = e.xyz - w.xyz;\n    let dy: vec3<f32> = n.xyz - s.xyz;\n    var v: vec2<f32> = vec2<f32>(0.);\n    if (Q.w == 0.) {\tv = vec2<f32>(dx.z - dx.y + 0.3 * dx.x, dy.z - dy.y + 0.3 * dy.x);\n    }\n    if (Q.w == 1.) {\tv = vec2<f32>(dx.x - dx.z + 0.1 * dx.y, dy.x - dy.z + 0.1 * dy.y);\n    }\n    if (Q.w == 2.) {\tv = vec2<f32>(dx.y - dx.x + 0.2 * dx.z, dy.y - dy.x + 0.2 * dy.z);\n    }\n    if (length(v) > 0.) {\t\n        let qxy = Q.xy + (normalize(v) * min(1., SPEED * length(v)));\n        Q.x = qxy.x ;\n        Q.y = qxy.y ;\n    }\n\n    #ifdef INIT\n\t\tU = floor(U / 8.) * 8. + 5.;\n\t\tvar Q = vec4<f32>(U, 1., floor( mod2(-U.x / R.x * 5., 3.)));\n    #endif\n\t\n\n\n\tif (uni.iMouse.z > 0. && length(uni.iMouse.xy - Q.xy) < MOUSE_SIZE) {\t\n        Q = vec4<f32>(-100., -100., 0., 0.);\n\t}\n\n    textureStore(buffer_a, location, Q / texture_const );\n    // textureStore(buffer_a, location, vec4<f32>(0.2, 0.7, 0.9, 1.) / texture_const);\n} \n\n"
  },
  {
    "path": "assets/shaders/love_and_domination/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\nlet s2 = 30.;\n\nlet BLUR_DEPTH = 25.;\n\nlet SPEED = 2.;\n\nlet MOUSE_SIZE = 60.;\n\nlet texture_const = 255.;\n\n\n\nvar<private>  R: vec2<f32>;\nfn A(location: vec2<f32>) -> vec4<f32> {\n\treturn textureLoad(buffer_a, vec2<i32>(location)) * texture_const;\n} \n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let U = vec2<f32>(f32(location.x), f32(location.y));\n\n\n// fn mainImage( Q: vec4<f32>,  U: vec2<f32>) -> () {\n\tR = uni.iResolution.xy;\n\tvar Q = vec4<f32>(0.);\n\n\tfor (var i: f32 = -BLUR_DEPTH; i <= BLUR_DEPTH; i = i + 1.) {\n\t\tlet a: vec4<f32> = A(U + vec2<f32>(i, 0.));\n\t\tlet c: vec4<f32> = a.z * smoothStep(1., 0.5, length(U + vec2<f32>(i, 0.) - a.xy)) \n            * vec4<f32>(f32(a.w == 0.), f32(a.w == 1.), f32(a.w == 2.), 0.);\n\t\tQ = Q + (c * sqrt(s2) / s2 * exp(-i * i * 0.5 / s2));\n\t\n\t}\n\n    textureStore(buffer_b, location, Q / texture_const);\n\n    // Q = textureLoad(buffer_a, vec2<i32>(location));\n    // textureStore(buffer_b, location, Q);\n} \n\n"
  },
  {
    "path": "assets/shaders/love_and_domination/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\nlet s2 = 30.;\n\nlet BLUR_DEPTH = 25.;\n\nlet SPEED = 2.;\n\nlet MOUSE_SIZE = 60.;\n\nlet texture_const = 255.;\n\n\n\nvar<private>  R: vec2<f32>;\n// fn A(location: vec2<f32>) -> vec4<f32> {\n// \treturn textureLoad(buffer_a, vec2<i32>(location)) * texture_const;\n// } \n\nfn B(location: vec2<f32>)-> vec4<f32> {\n\treturn textureLoad(buffer_b, vec2<i32>(location)) * texture_const;\n} \n\nfn C(location: vec2<f32>) -> vec4<f32> {\n\treturn textureLoad(buffer_c, vec2<i32>(location)) * texture_const;\n} \n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n// }\n\n// fn mainImage( Q: vec4<f32>,  U: vec2<f32>) -> () {\n\n    let U = vec2<f32>(f32(location.x), f32(location.y));\n\tR = uni.iResolution.xy;\n\tvar Q = vec4<f32>(0.);\n\tfor (var i: f32 = -BLUR_DEPTH; i <= BLUR_DEPTH; i = i + 1.) {\n\t\tlet c: vec4<f32> = B(U + vec2<f32>(0., i));\n\t\tQ = Q + (2. * c * sqrt(s2) / s2 * exp(-i * i * 0.5 / s2));\n\t\n\t}\t\n    Q = mix(Q, C(U), 0.1);\n    textureStore(buffer_c, location, Q / texture_const);\n\n\n    // Q = textureLoad(buffer_b, vec2<i32>(location));\n    // textureStore(buffer_c, location, Q);\n\n\n} \n\n"
  },
  {
    "path": "assets/shaders/love_and_domination/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\nlet s2 = 30.;\n\nlet BLUR_DEPTH = 25.;\n\nlet SPEED = 2.;\n\nlet MOUSE_SIZE = 60.;\n\nlet texture_const = 255.;\n\n\n\nvar<private>  R: vec2<f32>;\nfn A(location: vec2<f32>) -> vec4<f32> {\n\treturn textureLoad(buffer_a, vec2<i32>(location)) * texture_const;\n} \n\n// fn B(location: vec2<f32>)-> vec4<f32> {\n// \treturn textureLoad(buffer_b, vec2<i32>(location)) * texture_const;\n// } \n\nfn C(location: vec2<f32>) -> vec4<f32> {\n\treturn textureLoad(buffer_c, vec2<i32>(location)) * texture_const;\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n     let U = vec2<f32>(f32(location.x), f32(location.y));\n// }\n\n// fn mainImage( Q: vec4<f32>,  U: vec2<f32>) -> () {\n\tR = uni.iResolution.xy;\n\tlet c: vec4<f32> = C(U);\n\tlet n: vec4<f32> = C(U + vec2<f32>(0., 1.));\n\tlet e: vec4<f32> = C(U + vec2<f32>(1., 0.));\n\tlet s: vec4<f32> = C(U + vec2<f32>(0., -1.));\n\tlet w: vec4<f32> = C(U + vec2<f32>(-1., 0.));\n\tlet a: vec4<f32> = A(U);\n\tlet r: f32 = smoothStep(1., 0.5, length(U - a.xy));\n\n\tlet f: vec4<f32> = \n          r * f32(a.w == 0.) * vec4<f32>(0.8, 0.6, 0.3, 1.) \n        + r * f32(a.w == 1.) * vec4<f32>(0.9, 0.2, 0.4, 1.) \n        + r * f32(a.w == 2.) * vec4<f32>(0.2, 0.7, 0.9, 1.);\n\n\tvar Q = 2. * f * (0.5 + 0.5 * (n - s + e - w));\n\n\n    textureStore(buffer_d, location, Q / texture_const);\n\n    // Q = textureLoad(buffer_c, vec2<i32>(location));\n    // textureStore(buffer_d, location, Q);\n} \n\n\n\n\n"
  },
  {
    "path": "assets/shaders/love_and_domination/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\nlet s2 = 30.;\n\nlet BLUR_DEPTH = 25.;\n\nlet SPEED = 2.;\n\nlet MOUSE_SIZE = 60.;\n\nlet texture_const = 255.;\n\n\n\n\nvar<private> R: vec2<f32>;\n\nfn D(location: vec2<f32>) -> vec4<f32> {\n\t// return texture(iChannel0, U / R);\n    return textureLoad(buffer_d, vec2<i32>(location)) * texture_const;\n} \n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let U = vec2<f32>(f32(location.x), f32(location.y));\n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n// fn mainImage( Q: vec4<f32>,  U: vec2<f32>) -> () {\n\n\tR = uni.iResolution.xy;\n\tlet n: vec4<f32> = D(U + vec2<f32>(0., 1.));\n\tlet e: vec4<f32> = D(U + vec2<f32>(1., 0.));\n\tlet s: vec4<f32> = D(U + vec2<f32>(0., -1.));\n\tlet w: vec4<f32> = D(U + vec2<f32>(-1., 0.));\n\tlet dx: vec4<f32> = e - w;\n\tlet dy: vec4<f32> = n - s;\n\tvar Q = (D(U) + abs(dx) + abs(dy)) / 3.;\n\n    textureStore(texture, location, Q);\n\n    // Q = textureLoad(buffer_b, vec2<i32>(location));\n    // textureStore(texture, location, Q * texture_const );\n\n} "
  },
  {
    "path": "assets/shaders/minimal/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/minimal/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/minimal/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/minimal/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/minimal/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\n\n\n// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "assets/shaders/mip_fluid/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\nlet RECALCULATE_OFFSET: bool = true;\nlet BLUR_TURBULENCE: bool = false;\nlet BLUR_CONFINEMENT: bool = false;\nlet BLUR_VELOCITY: bool = false;\nlet USE_PRESSURE_ADVECTION: bool = false;\nlet PREMULTIPLY_CURL: bool = true;\nlet VIEW_VELOCITY: bool = true;\nlet CENTER_PUMP: bool = false;\nfn normz(x: vec4<f32>) -> vec4<f32> {\n\treturn if (x.xyz == vec3<f32>(0.)) { vec4<f32>(0., 0., 0., x.w); } else { vec4<f32>(normalize(x.xyz), 0.); };\n} \n\nfn normz(x: vec3<f32>) -> vec3<f32> {\n\treturn if (x == vec3<f32>(0.)) { vec3<f32>(0.); } else { normalize(x); };\n} \n\nfn normz(x: vec2<f32>) -> vec2<f32> {\n\treturn if (x == vec2<f32>(0.)) { vec2<f32>(0.); } else { normalize(x); };\n} \n\nfn softmax(a: f32, b: f32, k: f32) -> f32 {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: f32, b: f32, k: f32) -> f32 {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softmax(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: vec4<f32>, b: vec4<f32>, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: f32, b: f32, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(vec4<f32>(b), softmax(vec4<f32>(a), x, k), k) + softmax(vec4<f32>(a), softmin(vec4<f32>(b), x, k), k)) / 2.;\n} \n\nfn G1V(dnv: f32, k: f32) -> f32 {\n\treturn 1. / (dnv * (1. - k) + k);\n} \n\nfn ggx(n: vec3<f32>, v: vec3<f32>, l: vec3<f32>, rough: f32, f0: f32) -> f32 {\n\tlet alpha: f32 = rough * rough;\n\tlet h: vec3<f32> = normalize(v + l);\n\tlet dnl: f32 = clamp(dot(n, l), 0., 1.);\n\tlet dnv: f32 = clamp(dot(n, v), 0., 1.);\n\tlet dnh: f32 = clamp(dot(n, h), 0., 1.);\n\tvar dlh: f32 = clamp(dot(l, h), 0., 1.);\n\tvar f: f32;\n\tlet d: f32;\n\tlet vis: f32;\n\tlet asqr: f32 = alpha * alpha;\n\tlet pi: f32 = 3.14159;\n\tlet den: f32 = dnh * dnh * (asqr - 1.) + 1.;\n\td = asqr / (pi * den * den);\n\tdlh = pow(1. - dlh, 5.);\n\tf = f0 + (1. - f0) * dlh;\n\tvar k: f32 = alpha / 1.;\n\tvis = G1V(dnl, k) * G1V(dnv, k);\n\tlet spec: f32 = dnl * d * f * vis;\n\treturn spec;\n} \n\nfn light(uv: vec2<f32>, BUMP: f32, SRC_DIST: f32, dxy: vec2<f32>, uni.iTime: f32, avd: ptr<function, vec3<f32>>) -> vec3<f32> {\n\tlet sp: vec3<f32> = vec3<f32>(uv - 0.5, 0.);\n\tlet light: vec3<f32> = vec3<f32>(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST);\n\tvar ld: vec3<f32> = light - sp;\n\tlet lDist: f32 = max(length(ld), 0.001);\n\tld = ld / (lDist);\n\t(*avd) = reflect(normalize(vec3<f32>(BUMP * dxy, -1.)), vec3<f32>(0., 1., 0.));\n\treturn ld;\n} \n\nfn hash1(n: u32) -> f32 {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\treturn f32(n_var & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn hash3(n: u32) -> vec3<f32> {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\tlet k: vec3<u32> = n_var * vec3<u32>(n_var, n_var * 16807u, n_var * 48271u);\n\treturn vec3<f32>(k & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn rand4(fragCoord: vec2<f32>, uni.iResolution: vec2<f32>, uni.iFrame: i32) -> vec4<f32> {\n\tlet p: vec2<u32> = vec2<u32>(fragCoord);\n\tlet r: vec2<u32> = vec2<u32>(uni.iResolution);\n\tlet c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame);\n\treturn vec4<f32>(hash3(c), hash1(c + 75132900.));\n} \n\n\n\nfn gaussian_turbulence(uv: vec2<f32>) -> vec2<f32> {\n\tvar texel: vec2<f32> = 1. / uni.iResolution.xy;\n\tvar t: vec4<f32> = vec4<f32>(texel, -texel.y, 0.);\n\tvar d: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (t.ww + 0.)))).xy;\n\tvar d_n: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (t.wy + 0.)))).xy;\n\tvar d_e: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (t.xw + 0.)))).xy;\n\tvar d_s: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (t.wz + 0.)))).xy;\n\tvar d_w: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (-t.xw + 0.)))).xy;\n\tvar d_nw: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (-t.xz + 0.)))).xy;\n\tvar d_sw: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (-t.xy + 0.)))).xy;\n\tvar d_ne: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (t.xy + 0.)))).xy;\n\tvar d_se: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (t.xz + 0.)))).xy;\n\treturn 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw);\n} \n\nfn gaussian_confinement(uv: vec2<f32>) -> vec2<f32> {\n\tvar texel: vec2<f32> = 1. / uni.iResolution.xy;\n\tvar t: vec4<f32> = vec4<f32>(texel, -texel.y, 0.);\n\tvar d: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (t.ww + 0.)))).xy;\n\tvar d_n: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (t.wy + 0.)))).xy;\n\tvar d_e: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (t.xw + 0.)))).xy;\n\tvar d_s: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (t.wz + 0.)))).xy;\n\tvar d_w: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (-t.xw + 0.)))).xy;\n\tvar d_nw: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (-t.xz + 0.)))).xy;\n\tvar d_sw: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (-t.xy + 0.)))).xy;\n\tvar d_ne: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (t.xy + 0.)))).xy;\n\tvar d_se: vec2<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (t.xz + 0.)))).xy;\n\treturn 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw);\n} \n\nfn diff(uv: vec2<f32>) -> vec2<f32> {\n\tvar texel: vec2<f32> = 1. / uni.iResolution.xy;\n\tvar t: vec4<f32> = vec4<f32>(texel, -texel.y, 0.);\n\tvar d: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + t.ww))).x;\n\tvar d_n: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + t.wy))).x;\n\tvar d_e: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + t.xw))).x;\n\tvar d_s: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + t.wz))).x;\n\tvar d_w: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + -t.xw))).x;\n\tvar d_nw: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + -t.xz))).x;\n\tvar d_sw: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + -t.xy))).x;\n\tvar d_ne: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + t.xy))).x;\n\tvar d_se: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2<i32>(fract(uv + t.xz))).x;\n\treturn vec2<f32>(0.5 * (d_e - d_w) + 0.25 * (d_ne - d_nw + d_se - d_sw), 0.5 * (d_n - d_s) + 0.25 * (d_ne + d_nw - d_se - d_sw));\n} \n\nfn gaussian_velocity(uv: vec2<f32>) -> vec4<f32> {\n\tvar texel: vec2<f32> = 1. / uni.iResolution.xy;\n\tvar t: vec4<f32> = vec4<f32>(texel, -texel.y, 0.);\n\tvar d: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.ww + 0.))));\n\tvar d_n: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.wy + 0.))));\n\tvar d_e: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.xw + 0.))));\n\tvar d_s: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.wz + 0.))));\n\tvar d_w: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (-t.xw + 0.))));\n\tvar d_nw: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (-t.xz + 0.))));\n\tvar d_sw: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (-t.xy + 0.))));\n\tvar d_ne: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.xy + 0.))));\n\tvar d_se: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.xz + 0.))));\n\treturn 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw);\n} \n\nfn vector_laplacian(uv: vec2<f32>) -> vec2<f32> {\n\tlet _K0: f32 = -20. / 6.;\nlet _K1: f32 = 4. / 6.;\nlet _K2: f32 = 1. / 6.;\n\tlet texel: vec2<f32> = 1. / uni.iResolution.xy;\n\tlet t: vec4<f32> = vec4<f32>(texel, -texel.y, 0.);\n\tlet d: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.ww + 0.))));\n\tlet d_n: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.wy + 0.))));\n\tlet d_e: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.xw + 0.))));\n\tlet d_s: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.wz + 0.))));\n\tlet d_w: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (-t.xw + 0.))));\n\tlet d_nw: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (-t.xz + 0.))));\n\tlet d_sw: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (-t.xy + 0.))));\n\tlet d_ne: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.xy + 0.))));\n\tlet d_se: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (t.xz + 0.))));\n\treturn (_K0 * d + _K1 * (d_e + d_w + d_n + d_s) + _K2 * (d_ne + d_nw + d_se + d_sw)).xy;\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet uv: vec2<f32> = fragCoord / uni.iResolution.xy;\n\tlet tx: vec2<f32> = 1. / uni.iResolution.xy;\n\tvar turb: vec2<f32> = vec2<f32>(0.);\n\tvar confine: vec2<f32> = vec2<f32>(0.);\n\tvar div: vec2<f32> = vec2<f32>(0.);\n\tvar delta_v: vec2<f32> = vec2<f32>(0.);\n\tvar offset: vec2<f32> = vec2<f32>(0.);\n\tvar lapl: vec2<f32> = vec2<f32>(0.);\n\tvar vel: vec4<f32> = vec4<f32>(0.);\n\tvar adv: vec4<f32> = vec4<f32>(0.);\n\tlet init: vec4<f32> = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + +0.)));\n\tif (RECALCULATE_OFFSET) {\n\n\t\tfor (var i: i32 = 0; i < 3; i = i + 1) {\n\t\t\tif (BLUR_TURBULENCE) {\n\t\t\t\tturb = gaussian_turbulence(uv + tx * offset);\n\t\t\t} else { \n\n\t\t\t\tturb = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + (tx * offset + 0.)))).xy;\n\t\t\t}\n\t\t\tif (BLUR_CONFINEMENT) {\n\t\t\t\tconfine = gaussian_confinement(uv + tx * offset);\n\t\t\t} else { \n\n\t\t\t\tconfine = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + (tx * offset + 0.)))).xy;\n\t\t\t}\n\t\t\tif (BLUR_VELOCITY) {\n\t\t\t\tvel = gaussian_velocity(uv + tx * offset);\n\t\t\t} else { \n\n\t\t\t\tvel = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (tx * offset + 0.))));\n\t\t\t}\n\t\t\toffset = f32(i + 1.) / f32(3.) * -40. * (-0.05 * vel.xy + 1. * turb - 0.6 * confine + 0. * div);\n\t\t\tdiv = diff(uv + tx * 1. * offset);\n\t\t\tlapl = vector_laplacian(uv + tx * 1. * offset);\n\t\t\tadv = adv + (textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (tx * offset + 0.)))));\n\t\t\tdelta_v = delta_v + (0.02 * lapl + 0. * turb + 0.01 * confine - 0.0001 * vel.xy - 0.1 * div);\n\t\t}\n\n\t\tadv = adv / (f32(3.));\n\t\tdelta_v = delta_v / (f32(3.));\n\t} else { \n\n\t\tif (BLUR_TURBULENCE) {\n\t\t\tturb = gaussian_turbulence(uv);\n\t\t} else { \n\n\t\t\tturb = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2<i32>(fract(uv + +0.))).xy;\n\t\t}\n\t\tif (BLUR_CONFINEMENT) {\n\t\t\tconfine = gaussian_confinement(uv);\n\t\t} else { \n\n\t\t\tconfine = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2<i32>(fract(uv + +0.))).xy;\n\t\t}\n\t\tif (BLUR_VELOCITY) {\n\t\t\tvel = gaussian_velocity(uv);\n\t\t} else { \n\n\t\t\tvel = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + +0.)));\n\t\t}\n\t\toffset = -40. * (-0.05 * vel.xy + 1. * turb - 0.6 * confine + 0. * div);\n\t\tdiv = diff(uv + tx * 1. * offset);\n\t\tlapl = vector_laplacian(uv + tx * 1. * offset);\n\t\tdelta_v = delta_v + (0.02 * lapl + 0. * turb + 0.01 * confine - 0.0001 * vel.xy - 0.1 * div);\n\n\t\tfor (var i: i32 = 0; i < 3; i = i + 1) {\n\t\t\tadv = adv + (textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2<i32>(fract(uv + (f32(i + 1.) / f32(3.) * tx * offset + 0.)))));\n\t\t}\n\n\t\tadv = adv / (f32(3.));\n\t}\n\tlet pq: vec2<f32> = 2. * (uv * 2. - 1.) * vec2<f32>(1., tx.x / tx.y);\n\tif (CENTER_PUMP) {\n\t\tvar pump: vec2<f32> = sin(0.2 * uni.iTime) * 0.001 * pq.xy / (dot(pq, pq) + 0.01);\n\t} else { \n\n\t\tvar pump: vec2<f32> = vec2<f32>(0.);\n\t\tlet uvy0: f32 = exp(-50. * pow(pq.y, 2.));\n\t\tlet uvx0: f32 = exp(-50. * pow(uv.x, 2.));\n\t\tpump = pump + (-15. * vec2<f32>(max(0., cos(0.2 * uni.iTime)) * 0.001 * uvx0 * uvy0, 0.));\n\t\tlet uvy1: f32 = exp(-50. * pow(pq.y, 2.));\n\t\tlet uvx1: f32 = exp(-50. * pow(1. - uv.x, 2.));\n\t\tpump = pump + (15. * vec2<f32>(max(0., cos(0.2 * uni.iTime + 3.1416)) * 0.001 * uvx1 * uvy1, 0.));\n\t\tlet uvy2: f32 = exp(-50. * pow(pq.x, 2.));\n\t\tlet uvx2: f32 = exp(-50. * pow(uv.y, 2.));\n\t\tpump = pump + (-15. * vec2<f32>(0., max(0., sin(0.2 * uni.iTime)) * 0.001 * uvx2 * uvy2));\n\t\tlet uvy3: f32 = exp(-50. * pow(pq.x, 2.));\n\t\tlet uvx3: f32 = exp(-50. * pow(1. - uv.y, 2.));\n\t\tpump = pump + (15. * vec2<f32>(0., max(0., sin(0.2 * uni.iTime + 3.1416)) * 0.001 * uvx3 * uvy3));\n\t}\n\tfragColor = mix(adv + vec4<f32>(1. * (delta_v + pump), offset), init, 0.);\n\tif (uni.iMouse.z > 0.) {\n\t\tlet mouseUV: vec4<f32> = uni.iMouse / uni.iResolution.xyxy;\n\t\tlet delta: vec2<f32> = normz(mouseUV.zw - mouseUV.xy);\n\t\tlet md: vec2<f32> = (mouseUV.xy - uv) * vec2<f32>(1., tx.x / tx.y);\n\t\tlet amp: f32 = exp(max(-12., -dot(md, md) / 0.001));\n\t\tvar fragColorxy = fragColor.xy;\n\tfragColorxy = fragColor.xy + (1. * 0.05 * clamp(amp * delta, -1., 1.));\n\tfragColor.x = fragColorxy.x;\n\tfragColor.y = fragColorxy.y;\n\t}\n\tif (uni.iFrame == 0) { fragColor = 0.000001 * rand4(fragCoord, uni.iResolution.xy, uni.iFrame); }\n} \n\n"
  },
  {
    "path": "assets/shaders/mip_fluid/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\nlet RECALCULATE_OFFSET: bool = true;\nlet BLUR_TURBULENCE: bool = false;\nlet BLUR_CONFINEMENT: bool = false;\nlet BLUR_VELOCITY: bool = false;\nlet USE_PRESSURE_ADVECTION: bool = false;\nlet PREMULTIPLY_CURL: bool = true;\nlet VIEW_VELOCITY: bool = true;\nlet CENTER_PUMP: bool = false;\nfn normz(x: vec4<f32>) -> vec4<f32> {\n\treturn if (x.xyz == vec3<f32>(0.)) { vec4<f32>(0., 0., 0., x.w); } else { vec4<f32>(normalize(x.xyz), 0.); };\n} \n\nfn normz(x: vec3<f32>) -> vec3<f32> {\n\treturn if (x == vec3<f32>(0.)) { vec3<f32>(0.); } else { normalize(x); };\n} \n\nfn normz(x: vec2<f32>) -> vec2<f32> {\n\treturn if (x == vec2<f32>(0.)) { vec2<f32>(0.); } else { normalize(x); };\n} \n\nfn softmax(a: f32, b: f32, k: f32) -> f32 {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: f32, b: f32, k: f32) -> f32 {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softmax(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: vec4<f32>, b: vec4<f32>, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: f32, b: f32, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(vec4<f32>(b), softmax(vec4<f32>(a), x, k), k) + softmax(vec4<f32>(a), softmin(vec4<f32>(b), x, k), k)) / 2.;\n} \n\nfn G1V(dnv: f32, k: f32) -> f32 {\n\treturn 1. / (dnv * (1. - k) + k);\n} \n\nfn ggx(n: vec3<f32>, v: vec3<f32>, l: vec3<f32>, rough: f32, f0: f32) -> f32 {\n\tlet alpha: f32 = rough * rough;\n\tlet h: vec3<f32> = normalize(v + l);\n\tlet dnl: f32 = clamp(dot(n, l), 0., 1.);\n\tlet dnv: f32 = clamp(dot(n, v), 0., 1.);\n\tlet dnh: f32 = clamp(dot(n, h), 0., 1.);\n\tvar dlh: f32 = clamp(dot(l, h), 0., 1.);\n\tvar f: f32;\n\tlet d: f32;\n\tlet vis: f32;\n\tlet asqr: f32 = alpha * alpha;\n\tlet pi: f32 = 3.14159;\n\tlet den: f32 = dnh * dnh * (asqr - 1.) + 1.;\n\td = asqr / (pi * den * den);\n\tdlh = pow(1. - dlh, 5.);\n\tf = f0 + (1. - f0) * dlh;\n\tvar k: f32 = alpha / 1.;\n\tvis = G1V(dnl, k) * G1V(dnv, k);\n\tlet spec: f32 = dnl * d * f * vis;\n\treturn spec;\n} \n\nfn light(uv: vec2<f32>, BUMP: f32, SRC_DIST: f32, dxy: vec2<f32>, uni.iTime: f32, avd: ptr<function, vec3<f32>>) -> vec3<f32> {\n\tlet sp: vec3<f32> = vec3<f32>(uv - 0.5, 0.);\n\tlet light: vec3<f32> = vec3<f32>(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST);\n\tvar ld: vec3<f32> = light - sp;\n\tlet lDist: f32 = max(length(ld), 0.001);\n\tld = ld / (lDist);\n\t(*avd) = reflect(normalize(vec3<f32>(BUMP * dxy, -1.)), vec3<f32>(0., 1., 0.));\n\treturn ld;\n} \n\nfn hash1(n: u32) -> f32 {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\treturn f32(n_var & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn hash3(n: u32) -> vec3<f32> {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\tlet k: vec3<u32> = n_var * vec3<u32>(n_var, n_var * 16807u, n_var * 48271u);\n\treturn vec3<f32>(k & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn rand4(fragCoord: vec2<f32>, uni.iResolution: vec2<f32>, uni.iFrame: i32) -> vec4<f32> {\n\tlet p: vec2<u32> = vec2<u32>(fragCoord);\n\tlet r: vec2<u32> = vec2<u32>(uni.iResolution);\n\tlet c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame);\n\treturn vec4<f32>(hash3(c), hash1(c + 75132900.));\n} \n\n\n\nfn tex(uv: vec2<f32>, mx: ptr<function, mat3x3<f32>>, my: ptr<function, mat3x3<f32>>, degree: i32)  {\n\tlet texel: vec2<f32> = 1. / uni.iResolution.xy;\n\tlet stride: f32 = f32(1 << degree);\n\tlet mip: f32 = f32(degree);\n\tlet t: vec4<f32> = stride * vec4<f32>(texel, -texel.y, 0.);\n\tlet d: vec2<f32> = textureLod(iChannel0, fract(uv + t.ww), mip).xy;\n\tlet d_n: vec2<f32> = textureLod(iChannel0, fract(uv + t.wy), mip).xy;\n\tlet d_e: vec2<f32> = textureLod(iChannel0, fract(uv + t.xw), mip).xy;\n\tlet d_s: vec2<f32> = textureLod(iChannel0, fract(uv + t.wz), mip).xy;\n\tlet d_w: vec2<f32> = textureLod(iChannel0, fract(uv + -t.xw), mip).xy;\n\tlet d_nw: vec2<f32> = textureLod(iChannel0, fract(uv + -t.xz), mip).xy;\n\tlet d_sw: vec2<f32> = textureLod(iChannel0, fract(uv + -t.xy), mip).xy;\n\tlet d_ne: vec2<f32> = textureLod(iChannel0, fract(uv + t.xy), mip).xy;\n\tlet d_se: vec2<f32> = textureLod(iChannel0, fract(uv + t.xz), mip).xy;\n\t(*mx) = mat3x3<f32>(d_nw.x, d_n.x, d_ne.x, d_w.x, d.x, d_e.x, d_sw.x, d_s.x, d_se.x);\n\t(*my) = mat3x3<f32>(d_nw.y, d_n.y, d_ne.y, d_w.y, d.y, d_e.y, d_sw.y, d_s.y, d_se.y);\n} \n\nfn reduce(a: mat3x3<f32>, b: mat3x3<f32>) -> f32 {\n\tlet p: mat3x3<f32> = matrixCompMult(a, b);\n\treturn array<p,0>array<p,0> + array<p,0>array<p,1> + array<p,0>array<p,2> + array<p,1>array<p,0> + array<p,1>array<p,1> + array<p,1>array<p,2> + array<p,2>array<p,0> + array<p,2>array<p,1> + array<p,2>array<p,2>;\n} \n\nfn turbulence(fragCoord: vec2<f32>, turb: ptr<function, vec2<f32>>, curl: ptr<function, f32>)  {\n\tlet uv: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\tlet turb_xx: mat3x3<f32> = (2. - 0.9) * mat3x3<f32>(0.125, 0.25, 0.125, -0.25, -0.5, -0.25, 0.125, 0.25, 0.125);\n\tlet turb_yy: mat3x3<f32> = (2. - 0.9) * mat3x3<f32>(0.125, -0.25, 0.125, 0.25, -0.5, 0.25, 0.125, -0.25, 0.125);\n\tlet turb_xy: mat3x3<f32> = 0.9 * mat3x3<f32>(0.25, 0., -0.25, 0., 0., 0., -0.25, 0., 0.25);\n\tlet norm: f32 = 8.8 / (4. + 8. * 0.6);\n\tlet c0: f32 = 0.6;\n\tlet curl_x: mat3x3<f32> = mat3x3<f32>(c0, 1., c0, 0., 0., 0., -c0, -1., -c0);\n\tlet curl_y: mat3x3<f32> = mat3x3<f32>(c0, 0., -c0, 1., 0., -1., c0, 0., -c0);\n\tvar mx: mat3x3<f32>;\n\tlet my: mat3x3<f32>;\n\tvar v: vec2<f32> = vec2<f32>(0.);\n\tvar turb_wc: f32 = 0.;\n\tvar curl_wc: f32 = 0.;\n\t(*curl) = 0.;\n\n\tfor (var i: i32 = 0; i < TURBULENCE_SCALES; i = i + 1) {\n\t\ttex(uv, mx, my, i);\n\t\tlet turb_w: f32 = 1.;\n\t\tlet curl_w: f32 = 1. / f32(i + 1.);\n\t\tv = v + (turb_w * vec2<f32>(reduce(turb_xx, mx) + reduce(turb_xy, my), reduce(turb_yy, my) + reduce(turb_xy, mx)));\n\t\t(*curl) = (*curl) + (curl_w * (reduce(curl_x, mx) + reduce(curl_y, my)));\n\t\tturb_wc = turb_wc + (turb_w);\n\t\tcurl_wc = curl_wc + (curl_w);\n\t}\n\n\t(*turb) = f32(TURBULENCE_SCALES) * v / turb_wc;\n\t(*curl) = norm * (*curl) / curl_wc;\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar turb: vec2<f32>;\n\tvar curl: f32;\n\tturbulence(fragCoord, turb, curl);\n\tfragColor = vec4<f32>(turb, 0., curl);\n\tif (uni.iFrame == 0) { fragColor = 0.000001 * rand4(fragCoord, uni.iResolution.xy, uni.iFrame); }\n} \n\n"
  },
  {
    "path": "assets/shaders/mip_fluid/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\nlet RECALCULATE_OFFSET: bool = true;\nlet BLUR_TURBULENCE: bool = false;\nlet BLUR_CONFINEMENT: bool = false;\nlet BLUR_VELOCITY: bool = false;\nlet USE_PRESSURE_ADVECTION: bool = false;\nlet PREMULTIPLY_CURL: bool = true;\nlet VIEW_VELOCITY: bool = true;\nlet CENTER_PUMP: bool = false;\nfn normz(x: vec4<f32>) -> vec4<f32> {\n\treturn if (x.xyz == vec3<f32>(0.)) { vec4<f32>(0., 0., 0., x.w); } else { vec4<f32>(normalize(x.xyz), 0.); };\n} \n\nfn normz(x: vec3<f32>) -> vec3<f32> {\n\treturn if (x == vec3<f32>(0.)) { vec3<f32>(0.); } else { normalize(x); };\n} \n\nfn normz(x: vec2<f32>) -> vec2<f32> {\n\treturn if (x == vec2<f32>(0.)) { vec2<f32>(0.); } else { normalize(x); };\n} \n\nfn softmax(a: f32, b: f32, k: f32) -> f32 {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: f32, b: f32, k: f32) -> f32 {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softmax(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: vec4<f32>, b: vec4<f32>, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: f32, b: f32, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(vec4<f32>(b), softmax(vec4<f32>(a), x, k), k) + softmax(vec4<f32>(a), softmin(vec4<f32>(b), x, k), k)) / 2.;\n} \n\nfn G1V(dnv: f32, k: f32) -> f32 {\n\treturn 1. / (dnv * (1. - k) + k);\n} \n\nfn ggx(n: vec3<f32>, v: vec3<f32>, l: vec3<f32>, rough: f32, f0: f32) -> f32 {\n\tlet alpha: f32 = rough * rough;\n\tlet h: vec3<f32> = normalize(v + l);\n\tlet dnl: f32 = clamp(dot(n, l), 0., 1.);\n\tlet dnv: f32 = clamp(dot(n, v), 0., 1.);\n\tlet dnh: f32 = clamp(dot(n, h), 0., 1.);\n\tvar dlh: f32 = clamp(dot(l, h), 0., 1.);\n\tvar f: f32;\n\tlet d: f32;\n\tlet vis: f32;\n\tlet asqr: f32 = alpha * alpha;\n\tlet pi: f32 = 3.14159;\n\tlet den: f32 = dnh * dnh * (asqr - 1.) + 1.;\n\td = asqr / (pi * den * den);\n\tdlh = pow(1. - dlh, 5.);\n\tf = f0 + (1. - f0) * dlh;\n\tvar k: f32 = alpha / 1.;\n\tvis = G1V(dnl, k) * G1V(dnv, k);\n\tlet spec: f32 = dnl * d * f * vis;\n\treturn spec;\n} \n\nfn light(uv: vec2<f32>, BUMP: f32, SRC_DIST: f32, dxy: vec2<f32>, uni.iTime: f32, avd: ptr<function, vec3<f32>>) -> vec3<f32> {\n\tlet sp: vec3<f32> = vec3<f32>(uv - 0.5, 0.);\n\tlet light: vec3<f32> = vec3<f32>(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST);\n\tvar ld: vec3<f32> = light - sp;\n\tlet lDist: f32 = max(length(ld), 0.001);\n\tld = ld / (lDist);\n\t(*avd) = reflect(normalize(vec3<f32>(BUMP * dxy, -1.)), vec3<f32>(0., 1., 0.));\n\treturn ld;\n} \n\nfn hash1(n: u32) -> f32 {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\treturn f32(n_var & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn hash3(n: u32) -> vec3<f32> {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\tlet k: vec3<u32> = n_var * vec3<u32>(n_var, n_var * 16807u, n_var * 48271u);\n\treturn vec3<f32>(k & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn rand4(fragCoord: vec2<f32>, uni.iResolution: vec2<f32>, uni.iFrame: i32) -> vec4<f32> {\n\tlet p: vec2<u32> = vec2<u32>(fragCoord);\n\tlet r: vec2<u32> = vec2<u32>(uni.iResolution);\n\tlet c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame);\n\treturn vec4<f32>(hash3(c), hash1(c + 75132900.));\n} \n\n\n\nfn tex(uv: vec2<f32>, mc: ptr<function, mat3x3<f32>>, curl: ptr<function, f32>, degree: i32)  {\n\tlet texel: vec2<f32> = 1. / uni.iResolution.xy;\n\tlet stride: f32 = f32(1 << degree);\n\tlet mip: f32 = f32(degree);\n\tlet t: vec4<f32> = stride * vec4<f32>(texel, -texel.y, 0.);\n\tlet d: f32 = abs(textureLod(iChannel0, fract(uv + t.ww), mip).w);\n\tlet d_n: f32 = abs(textureLod(iChannel0, fract(uv + t.wy), mip).w);\n\tlet d_e: f32 = abs(textureLod(iChannel0, fract(uv + t.xw), mip).w);\n\tlet d_s: f32 = abs(textureLod(iChannel0, fract(uv + t.wz), mip).w);\n\tlet d_w: f32 = abs(textureLod(iChannel0, fract(uv + -t.xw), mip).w);\n\tlet d_nw: f32 = abs(textureLod(iChannel0, fract(uv + -t.xz), mip).w);\n\tlet d_sw: f32 = abs(textureLod(iChannel0, fract(uv + -t.xy), mip).w);\n\tlet d_ne: f32 = abs(textureLod(iChannel0, fract(uv + t.xy), mip).w);\n\tlet d_se: f32 = abs(textureLod(iChannel0, fract(uv + t.xz), mip).w);\n\t(*mc) = mat3x3<f32>(d_nw, d_n, d_ne, d_w, d, d_e, d_sw, d_s, d_se);\n\t(*curl) = textureLod(iChannel0, fract(uv + +0.), mip).w;\n} \n\nfn reduce(a: mat3x3<f32>, b: mat3x3<f32>) -> f32 {\n\tlet p: mat3x3<f32> = matrixCompMult(a, b);\n\treturn array<p,0>array<p,0> + array<p,0>array<p,1> + array<p,0>array<p,2> + array<p,1>array<p,0> + array<p,1>array<p,1> + array<p,1>array<p,2> + array<p,2>array<p,0> + array<p,2>array<p,1> + array<p,2>array<p,2>;\n} \n\nfn confinement(fragCoord: vec2<f32>) -> vec2<f32> {\n\tlet uv: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\tlet k0: f32 = 0.25;\n\tlet k1: f32 = 1. - 2. * 0.25;\n\tlet conf_x: mat3x3<f32> = mat3x3<f32>(-k0, -k1, -k0, 0., 0., 0., k0, k1, k0);\n\tlet conf_y: mat3x3<f32> = mat3x3<f32>(-k0, 0., k0, -k1, 0., k1, -k0, 0., k0);\n\tvar mc: mat3x3<f32>;\n\tvar v: vec2<f32> = vec2<f32>(0.);\n\tvar curl: f32;\n\tvar cacc: f32 = 0.;\n\tvar nacc: vec2<f32> = vec2<f32>(0.);\n\tvar wc: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < VORTICITY_SCALES; i = i + 1) {\n\t\ttex(uv, mc, curl, i);\n\t\tlet w: f32 = 1.;\n\t\tlet n: vec2<f32> = w * normz(vec2<f32>(reduce(conf_x, mc), reduce(conf_y, mc)));\n\t\tv = v + (curl * n);\n\t\tcacc = cacc + (curl);\n\t\tnacc = nacc + (n);\n\t\twc = wc + (w);\n\t}\n\n\tif (PREMULTIPLY_CURL) {\n\t\treturn v / wc;\n\t} else { \n\n\t\treturn nacc * cacc / wc;\n\t}\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tfragColor = vec4<f32>(confinement(fragCoord), 0., 0.);\n\tif (uni.iFrame == 0) { fragColor = 0.000001 * rand4(fragCoord, uni.iResolution.xy, uni.iFrame); }\n} \n\n"
  },
  {
    "path": "assets/shaders/mip_fluid/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\nlet RECALCULATE_OFFSET: bool = true;\nlet BLUR_TURBULENCE: bool = false;\nlet BLUR_CONFINEMENT: bool = false;\nlet BLUR_VELOCITY: bool = false;\nlet USE_PRESSURE_ADVECTION: bool = false;\nlet PREMULTIPLY_CURL: bool = true;\nlet VIEW_VELOCITY: bool = true;\nlet CENTER_PUMP: bool = false;\nfn normz(x: vec4<f32>) -> vec4<f32> {\n\treturn if (x.xyz == vec3<f32>(0.)) { vec4<f32>(0., 0., 0., x.w); } else { vec4<f32>(normalize(x.xyz), 0.); };\n} \n\nfn normz(x: vec3<f32>) -> vec3<f32> {\n\treturn if (x == vec3<f32>(0.)) { vec3<f32>(0.); } else { normalize(x); };\n} \n\nfn normz(x: vec2<f32>) -> vec2<f32> {\n\treturn if (x == vec2<f32>(0.)) { vec2<f32>(0.); } else { normalize(x); };\n} \n\nfn softmax(a: f32, b: f32, k: f32) -> f32 {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: f32, b: f32, k: f32) -> f32 {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softmax(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: vec4<f32>, b: vec4<f32>, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: f32, b: f32, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(vec4<f32>(b), softmax(vec4<f32>(a), x, k), k) + softmax(vec4<f32>(a), softmin(vec4<f32>(b), x, k), k)) / 2.;\n} \n\nfn G1V(dnv: f32, k: f32) -> f32 {\n\treturn 1. / (dnv * (1. - k) + k);\n} \n\nfn ggx(n: vec3<f32>, v: vec3<f32>, l: vec3<f32>, rough: f32, f0: f32) -> f32 {\n\tlet alpha: f32 = rough * rough;\n\tlet h: vec3<f32> = normalize(v + l);\n\tlet dnl: f32 = clamp(dot(n, l), 0., 1.);\n\tlet dnv: f32 = clamp(dot(n, v), 0., 1.);\n\tlet dnh: f32 = clamp(dot(n, h), 0., 1.);\n\tvar dlh: f32 = clamp(dot(l, h), 0., 1.);\n\tvar f: f32;\n\tlet d: f32;\n\tlet vis: f32;\n\tlet asqr: f32 = alpha * alpha;\n\tlet pi: f32 = 3.14159;\n\tlet den: f32 = dnh * dnh * (asqr - 1.) + 1.;\n\td = asqr / (pi * den * den);\n\tdlh = pow(1. - dlh, 5.);\n\tf = f0 + (1. - f0) * dlh;\n\tvar k: f32 = alpha / 1.;\n\tvis = G1V(dnl, k) * G1V(dnv, k);\n\tlet spec: f32 = dnl * d * f * vis;\n\treturn spec;\n} \n\nfn light(uv: vec2<f32>, BUMP: f32, SRC_DIST: f32, dxy: vec2<f32>, uni.iTime: f32, avd: ptr<function, vec3<f32>>) -> vec3<f32> {\n\tlet sp: vec3<f32> = vec3<f32>(uv - 0.5, 0.);\n\tlet light: vec3<f32> = vec3<f32>(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST);\n\tvar ld: vec3<f32> = light - sp;\n\tlet lDist: f32 = max(length(ld), 0.001);\n\tld = ld / (lDist);\n\t(*avd) = reflect(normalize(vec3<f32>(BUMP * dxy, -1.)), vec3<f32>(0., 1., 0.));\n\treturn ld;\n} \n\nfn hash1(n: u32) -> f32 {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\treturn f32(n_var & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn hash3(n: u32) -> vec3<f32> {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\tlet k: vec3<u32> = n_var * vec3<u32>(n_var, n_var * 16807u, n_var * 48271u);\n\treturn vec3<f32>(k & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn rand4(fragCoord: vec2<f32>, uni.iResolution: vec2<f32>, uni.iFrame: i32) -> vec4<f32> {\n\tlet p: vec2<u32> = vec2<u32>(fragCoord);\n\tlet r: vec2<u32> = vec2<u32>(uni.iResolution);\n\tlet c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame);\n\treturn vec4<f32>(hash3(c), hash1(c + 75132900.));\n} \n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/mip_fluid/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n[[group(0), binding(8)]]\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n[[group(0), binding(9)]]\nvar rgba_noise_256_texture_sampler: sampler;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n// Why are the characters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\nlet backColorDebug: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n\nvar<private> uv_debug: vec2<f32> ;\nvar<private> tp_debug: vec2<f32> ;\nvar<private> align_debug: vec4<f32>; // north, east, south, west\nvar<private> font_size_debug: f32;\nvar<private> dotColor_debug: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\nvar<private> drawColorDebug: vec3<f32> = vec3<f32>(1., 1., 0.);\nvar<private> vColor: vec3<f32> = backColorDebug;\nvar<private> aspect_debug: f32 = 1.;\nvar<private> pixelPosDebug: vec2<f32> = vec2<f32>(0., 0.);\n\nlet FONT_SPACE_DEBUG: f32 = 0.5;\nlet headColorDebug: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\nlet mpColorDebug: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\nlet mxColorDebug: vec3<f32> = vec3<f32>(1., 0., 0.);\nlet myColorDebug: vec3<f32> = vec3<f32>(0., 1., 0.);\nlet font_png_size_debug: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\nfn char(ch: i32) -> f32 {\n\n    let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n\tlet q = clamp(tp_debug, vec2<f32>(0.), vec2<f32>(1.)) / 16. + fr ;\n\tlet inverted_q = vec2<f32>(q.x, 1. - q.y);\n\n\t// // There is aliasing on the characters\n\t// let f = textureSampleGrad(font_texture,\n    //                  font_texture_sampler,\n    //                  inverted_q,\n    //                   vec2<f32>(1.0, 0.0),\n    //                  vec2<f32>(0.0, 1.0));\n\n\t// using textureLoad without sampler\n    let q1 = vec2<i32>(font_png_size_debug  * q );\n\tlet y_inverted_q1 = vec2<i32>(q1.x, i32(font_png_size_debug.y) - q1.y);\n\n\tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n\t// smoothing out the aliasing\n\tlet dx = vec2<i32>(1, 0);\n\tlet dy = vec2<i32>(0, 1);\n\n\tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n\tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n\tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n\tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n\tlet rp = 0.25;\n\tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n\treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n} \n\nfn SetTextPosition(x: f32, y: f32)  {\n\ttp_debug =  10. * uv_debug;\n\ttp_debug.x = tp_debug.x + 17. - x;\n\ttp_debug.y = tp_debug.y - 9.4 + y;\n} \n\nfn SetTextPositionAbs(x: f32, y: f32)  {\n\ttp_debug.x = 10. * uv_debug.x - x;\n\ttp_debug.y = 10. * uv_debug.y - y;\n} \n\nfn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\t*value = fract(*value) * 10.;\n\n\tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n\t\tc = c + (char(48 + i32(*value)));\n\t\ttp_debug.x = tp_debug.x - (0.5);\n\t\t*digits = *digits - (1);\n\t\t*value = fract(*value) * 10.;\n\n\t\tif (*digits <= 0 || *value == 0.) {\t\t\n            break;\n        }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(*digits));\n\treturn c;\n} \n\nfn maxInt(a: i32, b: i32) -> i32 {\n    var ret: i32;\n    if (a > b) { ret = a; } else { ret = b; };\n\treturn ret;\n} \n\nfn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\tc = c + (char(45));\n\t\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni >= digits) {\t\tbreak; }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\treturn c;\n} \n\nfn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tlet original_value: i32 = *value;\n\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\t// tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\t// c = c + (char(45));\n\t\t\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\t// tp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni == 0) {\t\tbreak; }\n\t}\n\n\tif (original_value < 0) {\n\t\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\tc = c + (char(45));\n\t}\n\n\t// tp_debug.x = tp_debug.x + (0.5 * f32(digits));\n\treturn c;\n} \n\n// fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\nfn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n\t// in case of 0.099999..., round up to 0.1000000\n\tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n\tlet tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits);\n\tvar c: f32 = 0.;\n\tif (value < 0.) {\n\t\tc = char(45);\n\t\tvalue = -value;\n\t}\n\ttp_debug.x = tp_debug.x - (0.5);\n    var ival = i32(value);\n\n    var one: i32 = 1;\n\n\tc = c + (drawInt(&ival, &one));\n\tc = c + (char(46));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n    var frac_val = fract(value);\n\tc = c + (drawFract(&frac_val, prec));\n\ttp_debug.x = min(tp_debug.x, tp_debugx);\n\n\treturn c;\n}\n\nfn drawFloat_f32(value:  f32) -> f32 {\n    var two: i32 = 2;\n\treturn drawFloat(value, &two, 5);\n} \n\nfn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n\treturn drawFloat(value, prec, 2);\n} \n\nfn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawIntBackwards(value, &one);\n} \n\nfn drawInt_i32(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawInt(value, &one);\n} \n\n\n\n\n\nfn SetColor(red: f32, green: f32, blue: f32)  {\n\tdrawColorDebug = vec3<f32>(red, green, blue);\n} \n\nfn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n\t// vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces));\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteFloatBox(\n\tfValue: f32, \n\tmaxDigits: i32, \n\tdecimalPlaces: i32, \n\talpha: f32\n)  {\n\tvar decs = decimalPlaces;\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha);\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteInteger(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32(iValue));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n} \n\nfn WriteIntegerBack(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue));\n\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\n} \n\n\n\nfn WriteFPS()  {\n\tvar fps: f32 = f32(uni.iSampleRate);\n\tSetColor(0.8, 0.6, 0.3);\n\tvar max_digits_one = 1;\n\tWriteFloat(fps, 5, &max_digits_one);\n\tvar c: f32 = 0.;\n\tc = c + (char(102));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(112));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(115));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\t// let c2 = smoothStep(0.0, 1.0, c );\n\n\tvColor = mix(vColor, drawColorDebug, c);\n} \n\nfn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n\tlet digits: i32 = 3;\n\tlet radius: f32 =  uni.iResolution.x / 400.;\n\tif (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; }\n\tlet r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius;\n\t// vColor = vColor + (mix(vec3<f32>(0.), dotColor_debug, 1. - clamp(r, 0., 1.)));\n\n\tvar max_digits_three: i32 = 3;\n\tvar mposxi: i32 = i32(mPos.x);\n\tvar mposyi: i32 = i32(mPos.y);\n\n\tvar mposx: f32 = (mPos.x);\n\tvar mposy: f32 = (mPos.y);\n\n\n\tlet x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG;\n\t\t\n\tSetTextPositionAbs(\n\t\t x_pos,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = myColorDebug;\n\tWriteIntegerBack(&mposyi);\n\n\tSetTextPositionAbs(\n\t\t x_pos - 7. *  FONT_SPACE_DEBUG,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = mxColorDebug;\n\n\tWriteIntegerBack(&mposxi);\n\n} \n\n\nfn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n  var x = r.x;\n  var y = r.y;\n  x = select(r.z, r.x, p.x > 0.);\n  y = select(r.w, r.y, p.x > 0.);\n  x  = select(y, x, p.y > 0.);\n  let q = abs(p) - b + x;\n  return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n}\n\n\n\nfn WriteRGBAValues(\n\tlocation: vec2<i32>, \n\tvalue: vec4<f32>, \n\tscreen_poz: vec2<f32>,\n\talpha: f32,\n )  {\n\tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect_debug, 1.0);\n\tlet window_ajusted = uni.iResolution / vec2<f32>(960., 600.);\n\n\tlet box_pos = vec2<f32>(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.;\n\t// let box_pos = mp;\n\n\t// // box location follows mouse position\n\t// let box_location = vec2<f32>(\n\t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t// \tuni.iMouse.y - 48. * window_ajusted.y\n\t// );\n\n\n\tlet box_location  = vec2<f32>(\n\t\t100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t\tuni.iResolution.y - 60. * window_ajusted.y,\n\t);\n\t\n\tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect_debug, 1.) ;\n\n\tlet d_box = sdRoundedBox(\n\t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n\t\t vec2<f32>(73. /  ( aspect_debug / 1.6 ), 75.) * window_ajusted, \n\t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n\t);\n\n\t// let alpha = 0.225;\n\tlet decimal_places = 3;\n\tSetColor(1., 1., 1.);\n\tvar c: f32 = 0.;\n\tlet lspace = 0.8;\n\n\tlet bg_color = vec3<f32>(.8, .7, .9);\n\tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n\t// red\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n\t) ;\n\tc = c + (char(114)); // r\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n\t// green\n\tSetTextPosition(\n\t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n\t) ;\n\tc = c + (char(103)); // g\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n\t// blue\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n\t\t) ;\n\tc = c + (char(98)); // b\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n\t// alpha\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n\t) ;\n\tc = c + (char(97)); // a\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n\tvColor = mix(vColor, drawColorDebug, c * alpha);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n\treturn mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius)));\n} \n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\nfn draw_ring(location: vec2<i32>) {\n\tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n\tlet alpha = 0.75;\n\tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n\tlet d = smoothStep(0.5, 1.5, abs(ring_dist - 1.));\n\tvColor = mix(vColor, headColorDebug,   (1. - d) * alpha );\n}\n\nfn draw_crossair(location: vec2<i32>)  {\n\n\tlet start = 5.0;\n\tlet end = 20.;\n\tlet segment1 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(start, 0.), \n\t\tvec2<f32>(end, 0.)\n\t);\n\n\tlet segment2 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(-start, 0.), \n\t\tvec2<f32>(-end, 0.)\n\t);\n\n\tlet segment3 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., start), \n\t\tvec2<f32>(0., end)\n\t);\n\n\tlet segment4 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., -start), \n\t\tvec2<f32>(0., -end)\n\t);\n\n\tvar alpha = 0.75;\n\tif (uni.iMouse.z > 0.) {\n\t\talpha = 1.0;\n\t}\n\n\tlet d = smoothStep(0.5, 1.5, segment1);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment2);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment3);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment4);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n}\n\nfn show_debug_info(location: vec2<i32>, color: vec3<f32>) -> vec4<f32> {    \n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    vColor = color;\n\n\n\taspect_debug =  uni.iResolution.x /  uni.iResolution.y;\n\n\tlet ratio: vec2<f32> = vec2<f32>(aspect_debug, 1.);\n\tpixelPosDebug = fragCoord.xy;\n\t// mousePosDebug = uni.iMouse.xy;\n\tuv_debug = (2. * fragCoord.xy /  uni.iResolution.xy - 1.) * ratio;\n\n\talign_debug = 10. * vec4<f32>(\n\t\t1.,      // North\n\t\taspect_debug,  // East\n\t\t-1.,     // South\n\t\t-aspect_debug, // West\n\t);\n\n\n\tWriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position\n\tWriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position\n\n\tvar c: f32 = 0.;\n\n\tSetTextPositionAbs(\n\t\t align_debug.y -      FONT_SPACE_DEBUG,\n\t\t align_debug.x - 2. * FONT_SPACE_DEBUG,\n\t);\n\n\tSetColor(0.8, 0.8, 0.8);\n\tvar resx = i32(uni.iResolution.x);\n\tvar resy = i32(uni.iResolution.y);\n\n\n\tWriteIntegerBack(&resx);\n\tc = c + (char(28));\n\ttp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG);\n\tWriteIntegerBack(&resy);\n\n\n\tSetTextPositionAbs(\n\t\t align_debug.w - 1. * FONT_SPACE_DEBUG,\n\t\t align_debug.z - 0. * FONT_SPACE_DEBUG,\n\t);\n\n\tWriteFPS();\n\tSetColor(0.9, 0.7, 0.8);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n\t// // RGBA probe labels follow mouse\n\t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n\tlet inverted_y_mouse_location = vec2<i32>(vec2<f32>(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n\tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n\tWriteRGBAValues(location, value, poz, 0.85);\n\n\tlet inverted_y_mouseclick_location = vec2<i32>(vec2<f32>(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n\tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n\tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.65);\n\n\tdraw_crossair(location);\n\n\tdraw_ring(location);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\t\n\n\treturn fragColor;\n} \n\n\nlet RECALCULATE_OFFSET: bool = true;\nlet BLUR_TURBULENCE: bool = false;\nlet BLUR_CONFINEMENT: bool = false;\nlet BLUR_VELOCITY: bool = false;\nlet USE_PRESSURE_ADVECTION: bool = false;\nlet PREMULTIPLY_CURL: bool = true;\nlet VIEW_VELOCITY: bool = true;\nlet CENTER_PUMP: bool = false;\nfn normz(x: vec4<f32>) -> vec4<f32> {\n\treturn if (x.xyz == vec3<f32>(0.)) { vec4<f32>(0., 0., 0., x.w); } else { vec4<f32>(normalize(x.xyz), 0.); };\n} \n\nfn normz(x: vec3<f32>) -> vec3<f32> {\n\treturn if (x == vec3<f32>(0.)) { vec3<f32>(0.); } else { normalize(x); };\n} \n\nfn normz(x: vec2<f32>) -> vec2<f32> {\n\treturn if (x == vec2<f32>(0.)) { vec2<f32>(0.); } else { normalize(x); };\n} \n\nfn softmax(a: f32, b: f32, k: f32) -> f32 {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: f32, b: f32, k: f32) -> f32 {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softmax(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn log(exp(k * a) + exp(k * b)) / k;\n} \n\nfn softmin(a: vec4<f32>, b: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn -log(exp(-k * a) + exp(-k * b)) / k;\n} \n\nfn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: vec4<f32>, b: vec4<f32>, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.;\n} \n\nfn softclamp(a: f32, b: f32, x: vec4<f32>, k: f32) -> vec4<f32> {\n\treturn (softmin(vec4<f32>(b), softmax(vec4<f32>(a), x, k), k) + softmax(vec4<f32>(a), softmin(vec4<f32>(b), x, k), k)) / 2.;\n} \n\nfn G1V(dnv: f32, k: f32) -> f32 {\n\treturn 1. / (dnv * (1. - k) + k);\n} \n\nfn ggx(n: vec3<f32>, v: vec3<f32>, l: vec3<f32>, rough: f32, f0: f32) -> f32 {\n\tlet alpha: f32 = rough * rough;\n\tlet h: vec3<f32> = normalize(v + l);\n\tlet dnl: f32 = clamp(dot(n, l), 0., 1.);\n\tlet dnv: f32 = clamp(dot(n, v), 0., 1.);\n\tlet dnh: f32 = clamp(dot(n, h), 0., 1.);\n\tvar dlh: f32 = clamp(dot(l, h), 0., 1.);\n\tvar f: f32;\n\tlet d: f32;\n\tlet vis: f32;\n\tlet asqr: f32 = alpha * alpha;\n\tlet pi: f32 = 3.14159;\n\tlet den: f32 = dnh * dnh * (asqr - 1.) + 1.;\n\td = asqr / (pi * den * den);\n\tdlh = pow(1. - dlh, 5.);\n\tf = f0 + (1. - f0) * dlh;\n\tvar k: f32 = alpha / 1.;\n\tvis = G1V(dnl, k) * G1V(dnv, k);\n\tlet spec: f32 = dnl * d * f * vis;\n\treturn spec;\n} \n\nfn light(uv: vec2<f32>, BUMP: f32, SRC_DIST: f32, dxy: vec2<f32>, uni.iTime: f32, avd: ptr<function, vec3<f32>>) -> vec3<f32> {\n\tlet sp: vec3<f32> = vec3<f32>(uv - 0.5, 0.);\n\tlet light: vec3<f32> = vec3<f32>(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST);\n\tvar ld: vec3<f32> = light - sp;\n\tlet lDist: f32 = max(length(ld), 0.001);\n\tld = ld / (lDist);\n\t(*avd) = reflect(normalize(vec3<f32>(BUMP * dxy, -1.)), vec3<f32>(0., 1., 0.));\n\treturn ld;\n} \n\nfn hash1(n: u32) -> f32 {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\treturn f32(n_var & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn hash3(n: u32) -> vec3<f32> {\n\tvar n_var = n;\n\tn_var = n_var << 13u ^ n_var;\n\tn_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u;\n\tlet k: vec3<u32> = n_var * vec3<u32>(n_var, n_var * 16807u, n_var * 48271u);\n\treturn vec3<f32>(k & vec3<u32>(2147483600.)) / f32(2147483600.);\n} \n\nfn rand4(fragCoord: vec2<f32>, uni.iResolution: vec2<f32>, uni.iFrame: i32) -> vec4<f32> {\n\tlet p: vec2<u32> = vec2<u32>(fragCoord);\n\tlet r: vec2<u32> = vec2<u32>(uni.iResolution);\n\tlet c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame);\n\treturn vec4<f32>(hash3(c), hash1(c + 75132900.));\n} \n\n\n\n// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "assets/shaders/mixing_liquid/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n    return vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.000000001), vec2<f32 >(0.999999999));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n    return P;\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = P;\n    P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n\n\n\n\n\n\n\n\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba32float, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n        }\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n        P1.X = P1.X / (P1.M.x);\n        P1.V = P1.V / (P1.M.x);\n        P1.M.y = P1.M.y / (P1.M.x);\n    }\n\n    return P1;\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let color = vec4<f32>(0.5);\n//     textureStore(buffer_a, location, color);\n// }\n\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>) -> () {\n    let pos: vec2<f32> = vec2<f32>(location);\n\n    R = uni.iResolution.xy;\n    time = uni.iTime;\n    Mouse = uni.iMouse;\n    let p: vec2<i32> = location;\n\n\t// let data: vec4<f32> = texel(ch0, pos);\n\n    // buffer_b is set as the channel 0 in Buffer A of the paint\n    // streams inside shadertoy \n    // let data: vec4<f32> =  textureLoad(buffer_b, location);\n\n    var P: particle = Reintegration(buffer_b, pos);\n\n\t// if (uni.iFrame < 4.0) {\n    # ifdef INIT\n    let rand: vec3<f32> = hash32(pos);\n    if (rand.z < 0.) {\n        P.X = pos;\n        P.V = 0.5 * (rand.xy - 0.5) + vec2<f32>(0., 0.);\n        P.M = vec2<f32>(mass, 0.);\n    } else {\n        P.X = pos;\n        P.V = vec2<f32>(0.);\n        P.M = vec2<f32>(0.000001);\n    }\n    # endif\n\t// }\n\n    textureStore(buffer_a, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "assets/shaders/mixing_liquid/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n    return vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.000000001), vec2<f32 >(0.999999999));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n    return P;\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = P;\n    P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n\n\n\n\n\n\n\nfn Simulation(ch: texture_storage_2d<rgba32float, read_write>, P: particle, pos: vec2<f32>) -> particle {\n    var F: vec2<f32> = vec2<f32>(0.);\n    var avgV: vec3<f32> = vec3<f32>(0.);\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n        }\n    }\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n    F = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n    F = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n    if (Mouse.z > 0.) {\n        let dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n        let d: f32 = distance(Mouse.xy, P.X) / 20.;\n        F = F + (0.001 * dm * exp(-d * d));\n    }\n\n    var P1: particle = P;\n\n    //integrate\n    P1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n    let N: vec3<f32> = bN(P1.X);\n    let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n    P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n    P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\n    if (N.z < 0.) {\n        P1.V = vec2<f32>(0.);\n    }\n\n    //velocity limit\n    let v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v;\n    } else {\n        vv = 1.;\n    };\n    P1.V = P1.V / vv;\n\n    return P1;\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// }\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>) -> () {\n\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let pos: vec2<f32> = vec2<f32>(location);\n\n    R = uni.iResolution.xy;\n    time = uni.iTime;\n    Mouse = uni.iMouse;\n    let p: vec2<i32> = location;\n\n\n\t// let data: vec4<f32> = texel(buffer_a, pos);\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n\n    if (P.M.x != 0.) {\n        P = Simulation(buffer_a, P, pos);\n    }\n\n    if (length(P.X - R * vec2<f32>(0.8, 0.9)) < 10.) {\n        P.X = pos;\n        P.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time));\n        P.M = mix(P.M, vec2<f32>(fluid_rho, 1.), 0.4);\n    }\n\n    if (length(P.X - R * vec2<f32>(0.2, 0.9)) < 10.) {\n        P.X = pos;\n        P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time));\n        P.M = mix(P.M, vec2<f32>(fluid_rho, 0.), 0.4);\n    }\n\n\t// U = saveParticle(P, pos);\n    textureStore(buffer_b, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "assets/shaders/mixing_liquid/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n    return vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.000000001), vec2<f32 >(0.999999999));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n    return P;\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = P;\n    P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n\n\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// fn mainImage( fragColor: vec4<f32>,  pos: vec2<f32>) -> () {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    R = uni.iResolution.xy;\n    time = uni.iTime;\n    Mouse = uni.iMouse;\n    let pos = vec2<f32>(location);\n    let p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n\n\t// let data: vec4<f32> = texel(ch0, pos);\n\t// let P: particle = getParticle(data, pos);\n\n    var rho: vec4<f32> = vec4<f32>(0.);\n    for (var i: i32 = -1; i <= 1; i = i + 1) {\n        for (var j: i32 = -1; j <= 1; j = j + 1) {\n            let ij: vec2<i32> = vec2<i32>(i, j);\n\n\t\t\t// let data: vec4<f32> = texel(ch0, pos + ij);\n            let data: vec4<f32> = textureLoad(buffer_a, location + ij);\n\n            var P0: particle = getParticle(data, pos + vec2<f32>(ij));\n            let x0: vec2<f32> = P0.X;\n            rho = rho + (1. * vec4<f32>(P.V, P.M) * G((pos - x0) / 0.75));\n        }\n    }\n\n    textureStore(buffer_c, location, rho);\n} \n\n"
  },
  {
    "path": "assets/shaders/mixing_liquid/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n    return vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.000000001), vec2<f32 >(0.999999999));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n    return P;\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = P;\n    P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n\n\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/mixing_liquid/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n[[group(0), binding(8)]]\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n[[group(0), binding(9)]]\nvar rgba_noise_256_texture_sampler: sampler;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n// Why are the characters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\nlet backColorDebug: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n\nvar<private> uv_debug: vec2<f32> ;\nvar<private> tp_debug: vec2<f32> ;\nvar<private> align_debug: vec4<f32>; // north, east, south, west\nvar<private> font_size_debug: f32;\nvar<private> dotColor_debug: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\nvar<private> drawColorDebug: vec3<f32> = vec3<f32>(1., 1., 0.);\nvar<private> vColor: vec3<f32> = backColorDebug;\nvar<private> aspect_debug: f32 = 1.;\nvar<private> pixelPosDebug: vec2<f32> = vec2<f32>(0., 0.);\n\nlet FONT_SPACE_DEBUG: f32 = 0.5;\nlet headColorDebug: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\nlet mpColorDebug: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\nlet mxColorDebug: vec3<f32> = vec3<f32>(1., 0., 0.);\nlet myColorDebug: vec3<f32> = vec3<f32>(0., 1., 0.);\nlet font_png_size_debug: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\nfn char(ch: i32) -> f32 {\n\n    let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n\tlet q = clamp(tp_debug, vec2<f32>(0.), vec2<f32>(1.)) / 16. + fr ;\n\tlet inverted_q = vec2<f32>(q.x, 1. - q.y);\n\n\t// // There is aliasing on the characters\n\t// let f = textureSampleGrad(font_texture,\n    //                  font_texture_sampler,\n    //                  inverted_q,\n    //                   vec2<f32>(1.0, 0.0),\n    //                  vec2<f32>(0.0, 1.0));\n\n\t// using textureLoad without sampler\n    let q1 = vec2<i32>(font_png_size_debug  * q );\n\tlet y_inverted_q1 = vec2<i32>(q1.x, i32(font_png_size_debug.y) - q1.y);\n\n\tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n\t// smoothing out the aliasing\n\tlet dx = vec2<i32>(1, 0);\n\tlet dy = vec2<i32>(0, 1);\n\n\tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n\tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n\tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n\tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n\tlet rp = 0.25;\n\tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n\treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n} \n\nfn SetTextPosition(x: f32, y: f32)  {\n\ttp_debug =  10. * uv_debug;\n\ttp_debug.x = tp_debug.x + 17. - x;\n\ttp_debug.y = tp_debug.y - 9.4 + y;\n} \n\nfn SetTextPositionAbs(x: f32, y: f32)  {\n\ttp_debug.x = 10. * uv_debug.x - x;\n\ttp_debug.y = 10. * uv_debug.y - y;\n} \n\nfn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\t*value = fract(*value) * 10.;\n\n\tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n\t\tc = c + (char(48 + i32(*value)));\n\t\ttp_debug.x = tp_debug.x - (0.5);\n\t\t*digits = *digits - (1);\n\t\t*value = fract(*value) * 10.;\n\n\t\tif (*digits <= 0 || *value == 0.) {\t\t\n            break;\n        }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(*digits));\n\treturn c;\n} \n\nfn maxInt(a: i32, b: i32) -> i32 {\n    var ret: i32;\n    if (a > b) { ret = a; } else { ret = b; };\n\treturn ret;\n} \n\nfn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\tc = c + (char(45));\n\t\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni >= digits) {\t\tbreak; }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\treturn c;\n} \n\nfn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tlet original_value: i32 = *value;\n\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\t// tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\t// c = c + (char(45));\n\t\t\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\t// tp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni == 0) {\t\tbreak; }\n\t}\n\n\tif (original_value < 0) {\n\t\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\tc = c + (char(45));\n\t}\n\n\t// tp_debug.x = tp_debug.x + (0.5 * f32(digits));\n\treturn c;\n} \n\n// fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\nfn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n\t// in case of 0.099999..., round up to 0.1000000\n\tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n\tlet tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits);\n\tvar c: f32 = 0.;\n\tif (value < 0.) {\n\t\tc = char(45);\n\t\tvalue = -value;\n\t}\n\ttp_debug.x = tp_debug.x - (0.5);\n    var ival = i32(value);\n\n    var one: i32 = 1;\n\n\tc = c + (drawInt(&ival, &one));\n\tc = c + (char(46));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n    var frac_val = fract(value);\n\tc = c + (drawFract(&frac_val, prec));\n\ttp_debug.x = min(tp_debug.x, tp_debugx);\n\n\treturn c;\n}\n\nfn drawFloat_f32(value:  f32) -> f32 {\n    var two: i32 = 2;\n\treturn drawFloat(value, &two, 5);\n} \n\nfn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n\treturn drawFloat(value, prec, 2);\n} \n\nfn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawIntBackwards(value, &one);\n} \n\nfn drawInt_i32(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawInt(value, &one);\n} \n\n\n\n\n\nfn SetColor(red: f32, green: f32, blue: f32)  {\n\tdrawColorDebug = vec3<f32>(red, green, blue);\n} \n\nfn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n\t// vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces));\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteFloatBox(\n\tfValue: f32, \n\tmaxDigits: i32, \n\tdecimalPlaces: i32, \n\talpha: f32\n)  {\n\tvar decs = decimalPlaces;\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha);\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteInteger(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32(iValue));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n} \n\nfn WriteIntegerBack(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue));\n\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\n} \n\n\n\nfn WriteFPS()  {\n\tvar fps: f32 = f32(uni.iSampleRate);\n\tSetColor(0.8, 0.6, 0.3);\n\tvar max_digits_one = 1;\n\tWriteFloat(fps, 5, &max_digits_one);\n\tvar c: f32 = 0.;\n\tc = c + (char(102));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(112));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(115));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\t// let c2 = smoothStep(0.0, 1.0, c );\n\n\tvColor = mix(vColor, drawColorDebug, c);\n} \n\nfn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n\tlet digits: i32 = 3;\n\tlet radius: f32 =  uni.iResolution.x / 400.;\n\tif (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; }\n\tlet r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius;\n\t// vColor = vColor + (mix(vec3<f32>(0.), dotColor_debug, 1. - clamp(r, 0., 1.)));\n\n\tvar max_digits_three: i32 = 3;\n\tvar mposxi: i32 = i32(mPos.x);\n\tvar mposyi: i32 = i32(mPos.y);\n\n\tvar mposx: f32 = (mPos.x);\n\tvar mposy: f32 = (mPos.y);\n\n\n\tlet x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG;\n\t\t\n\tSetTextPositionAbs(\n\t\t x_pos,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = myColorDebug;\n\tWriteIntegerBack(&mposyi);\n\n\tSetTextPositionAbs(\n\t\t x_pos - 7. *  FONT_SPACE_DEBUG,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = mxColorDebug;\n\n\tWriteIntegerBack(&mposxi);\n\n} \n\n\nfn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n  var x = r.x;\n  var y = r.y;\n  x = select(r.z, r.x, p.x > 0.);\n  y = select(r.w, r.y, p.x > 0.);\n  x  = select(y, x, p.y > 0.);\n  let q = abs(p) - b + x;\n  return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n}\n\n\n\nfn WriteRGBAValues(\n\tlocation: vec2<i32>, \n\tvalue: vec4<f32>, \n\tscreen_poz: vec2<f32>,\n\talpha: f32,\n )  {\n\tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect_debug, 1.0);\n\tlet window_ajusted = uni.iResolution / vec2<f32>(960., 600.);\n\n\tlet box_pos = vec2<f32>(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.;\n\t// let box_pos = mp;\n\n\t// // box location follows mouse position\n\t// let box_location = vec2<f32>(\n\t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t// \tuni.iMouse.y - 48. * window_ajusted.y\n\t// );\n\n\n\tlet box_location  = vec2<f32>(\n\t\t100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t\tuni.iResolution.y - 60. * window_ajusted.y,\n\t);\n\t\n\tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect_debug, 1.) ;\n\n\tlet d_box = sdRoundedBox(\n\t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n\t\t vec2<f32>(73. /  ( aspect_debug / 1.6 ), 75.) * window_ajusted, \n\t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n\t);\n\n\t// let alpha = 0.225;\n\tlet decimal_places = 3;\n\tSetColor(1., 1., 1.);\n\tvar c: f32 = 0.;\n\tlet lspace = 0.8;\n\n\tlet bg_color = vec3<f32>(.8, .7, .9);\n\tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n\t// red\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n\t) ;\n\tc = c + (char(114)); // r\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n\t// green\n\tSetTextPosition(\n\t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n\t) ;\n\tc = c + (char(103)); // g\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n\t// blue\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n\t\t) ;\n\tc = c + (char(98)); // b\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n\t// alpha\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n\t) ;\n\tc = c + (char(97)); // a\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n\tvColor = mix(vColor, drawColorDebug, c * alpha);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n\treturn mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius)));\n} \n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\nfn draw_ring(location: vec2<i32>) {\n\tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n\tlet alpha = 0.75;\n\tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n\tlet d = smoothStep(0.5, 1.5, abs(ring_dist - 1.));\n\tvColor = mix(vColor, headColorDebug,   (1. - d) * alpha );\n}\n\nfn draw_crossair(location: vec2<i32>)  {\n\n\tlet start = 5.0;\n\tlet end = 20.;\n\tlet segment1 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(start, 0.), \n\t\tvec2<f32>(end, 0.)\n\t);\n\n\tlet segment2 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(-start, 0.), \n\t\tvec2<f32>(-end, 0.)\n\t);\n\n\tlet segment3 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., start), \n\t\tvec2<f32>(0., end)\n\t);\n\n\tlet segment4 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., -start), \n\t\tvec2<f32>(0., -end)\n\t);\n\n\tvar alpha = 0.75;\n\tif (uni.iMouse.z > 0.) {\n\t\talpha = 1.0;\n\t}\n\n\tlet d = smoothStep(0.5, 1.5, segment1);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment2);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment3);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment4);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n}\n\nfn show_debug_info(location: vec2<i32>, color: vec3<f32>) -> vec4<f32> {    \n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    vColor = color;\n\n\n\taspect_debug =  uni.iResolution.x /  uni.iResolution.y;\n\n\tlet ratio: vec2<f32> = vec2<f32>(aspect_debug, 1.);\n\tpixelPosDebug = fragCoord.xy;\n\t// mousePosDebug = uni.iMouse.xy;\n\tuv_debug = (2. * fragCoord.xy /  uni.iResolution.xy - 1.) * ratio;\n\n\talign_debug = 10. * vec4<f32>(\n\t\t1.,      // North\n\t\taspect_debug,  // East\n\t\t-1.,     // South\n\t\t-aspect_debug, // West\n\t);\n\n\n\tWriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position\n\tWriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position\n\n\tvar c: f32 = 0.;\n\n\tSetTextPositionAbs(\n\t\t align_debug.y -      FONT_SPACE_DEBUG,\n\t\t align_debug.x - 2. * FONT_SPACE_DEBUG,\n\t);\n\n\tSetColor(0.8, 0.8, 0.8);\n\tvar resx = i32(uni.iResolution.x);\n\tvar resy = i32(uni.iResolution.y);\n\n\n\tWriteIntegerBack(&resx);\n\tc = c + (char(28));\n\ttp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG);\n\tWriteIntegerBack(&resy);\n\n\n\tSetTextPositionAbs(\n\t\t align_debug.w - 1. * FONT_SPACE_DEBUG,\n\t\t align_debug.z - 0. * FONT_SPACE_DEBUG,\n\t);\n\n\tWriteFPS();\n\tSetColor(0.9, 0.7, 0.8);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n\t// // RGBA probe labels follow mouse\n\t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n\tlet inverted_y_mouse_location = vec2<i32>(vec2<f32>(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n\tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n\tWriteRGBAValues(location, value, poz, 0.85);\n\n\tlet inverted_y_mouseclick_location = vec2<i32>(vec2<f32>(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n\tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n\tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.65);\n\n\tdraw_crossair(location);\n\n\tdraw_ring(location);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\t\n\n\treturn fragColor;\n} \n\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba32float, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n    return vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.000000001), vec2<f32 >(0.999999999));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n    return P;\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = P;\n    P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n\n\n\n\n\n\n\n\n\nfn mixN(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {\n    return sqrt(mix(a * a, b * b, clamp(k, 0., 1.)));\n} \n\nfn V(p: vec2<f32>) -> vec4<f32> {\n\t// return pixel(ch1, p);\n    return textureLoad(buffer_c, vec2<i32>(p));\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    R = uni.iResolution.xy;\n    time = uni.iTime;\n    Mouse = uni.iMouse;\n\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n\t\n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n// fn mainImage( col: vec4<f32>,  pos: vec2<f32>) -> () {\n\n\n    \n\n\t// let p: vec2<i32> = vec2<i32>(pos);\n\t// let data: vec4<f32> = texel(ch0, pos);\n\n    let p: vec2<i32> = location;\n\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    let pos = vec2<f32>(location);\n\n    var P: particle = getParticle(data, pos);\n\n    let Nb: vec3<f32> = bN(P.X);\n    let bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos));\n    let rho: vec4<f32> = V(pos);\n    let dx: vec3<f32> = vec3<f32>(-2., 0., 2.);\n\n    let grad: vec4<f32> = -0.5 * vec4<f32>(V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw);\n    let N: vec2<f32> = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001);\n\n    let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5);\n    let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.);\n\n\n    let a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1);\n    let b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z));\n    let col0: vec3<f32> = vec3<f32>(1., 0.5, 0.);\n    let col1: vec3<f32> = vec3<f32>(0.1, 0.4, 1.);\n\n\n    let fcol: vec3<f32> = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5);\n    // var col: vec4<f32>;\n\n    var col: vec3<f32> = vec3<f32>(3.);\n    col = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a);\n\n\n    col = mixN(col, 0. * vec3<f32>(0.5, 0.5, 1.), bord);\n    col = tanh(col);\n    let col4 = vec4<f32>(col, 3.0);\n\n    textureStore(texture, y_inverted_location, col4);\n} \n"
  },
  {
    "path": "assets/shaders/molecular_dynamics/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0)\n\n// #define P(p) texture(iChannel0, mod(p,R)/R)\n\n// #define C(p) texture(iChannel1, mod(p,R)/R)\n\n// #define GS(x) exp(-dot(x,x))\n\n// #define GS0(x) exp(-length(x))\n\n// #define CI(x) smoothstep(1.0, 0.9, length(x))\n\n// #define Dir(ang) vec2(cos(ang), sin(ang))\n\n// #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang))\n\n\n// #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \\\n//            65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) )   \n\n// #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0)              \n\n// #define DECODE(X) UNPACK(floatBitsToUint(X))\n\n// #define ENCODE(X) uintBitsToFloat(PACK(X))\n\nlet PI = 3.14159265;\n\nlet dt = 0.4;\n\n// let R = uni.iResolution.xy;\n\nlet cooling = 1.5;\n\nfn GS(x1: vec2<f32>) -> f32 {\n    return exp(-dot(x1, x1));\n}\n\nfn MF(dx: vec2<f32>) -> f32 {\n\treturn -GS(0.75 * dx) + 0.15 * GS(0.4 * dx);\n\n} \n\nfn Ha(x: vec2<f32>) -> f32 {\n    var x2: f32;\n    if (x.x >= 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y >= 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\t// return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.);\n    return x2;\n\n} \n\nfn Hb(x: vec2<f32>) -> f32 {\n\t// return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.);\n    var x2: f32;\n    if (x.x > 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y > 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\n    return x2;\n\n} \n\nfn unpack(X: u32) -> vec2<f32> {\n    return (clamp(\n            vec2<f32>(f32(X % 65535u), f32(X / 65535u)) / 65534.0, \n            vec2<f32>(0.), \n            vec2<f32>(1.)\n        ) * 2.0 - 1.0\n    ) ;\n}\n\nfn pack(v: vec2<f32>) -> u32 {\n    return  (     u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + \n           65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) )   ;\n}\n\n\n\n\n\n\n\nfn PD(x: vec2<f32>, pos: vec2<f32>) -> vec3<f32> {\n\treturn vec3<f32>(x, 1.) * Ha(x - (pos - 0.5)) * Hb(pos + 0.5 - x);\n\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let color = vec4<f32>(0.5);\n    // textureStore(buffer_a, location, color);\n// }\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>)  {\n\n    let pos = location;\n\tlet p: vec2<i32> = vec2<i32>(pos);\n\tvar X: vec2<f32> = vec2<f32>(0.);\n\tvar V: vec2<f32> = vec2<f32>(0.);\n\tvar M: f32 = 0.;\n\tfor (var i: i32 = -1; i <= 1; i = i + 1) {\n\t\tfor (var j: i32 = -1; j <= 1; j = j + 1) {\n\t\t\tlet tpos: vec2<i32> = pos + vec2<i32>(i, j);\n\t\t\t// let data: vec4<f32> = T(tpos);\n\n            let data: vec4<f32> = textureLoad(buffer_b, tpos % vec2<i32>( R));\n\n            var X0: vec2<f32> = unpack(u32(data.x)) + vec2<f32>(tpos);\n\t\t\tvar V0: vec2<f32> = unpack(u32(data.y));\n\n\t\t\t// var X0: vec2<f32> = DECODE(data.x) + tpos;\n\t\t\t// let V0: vec2<f32> = DECODE(data.y);\n\n\t\t\tlet M0: i32 = i32(data.z);\n\t\t\tlet M0H: i32 = M0 / 2;\n\t\t\tX0 = X0 + (V0 * dt);\n\t\t\tvar m: vec3<f32>;\n\n            if  (M0 >= 2) {\n                 m =  f32(M0H) *      PD(X0 + vec2<f32>(0.5, 0.), vec3<f32>(pos)) \n                    + f32(M0 - M0H) * PD(X0 - vec2<f32>(0.5, 0.), vec3<f32>(pos)) ;\n             } else {\n                  m = f32(M0) * PD(X0, vec3<f32>(pos));\n            }\n\t\t\tX = X + (m.xy);\n\t\t\tV = V + (V0 * m.z);\n\t\t\tM = M + (m.z);\n\t\t\n\t\t}\t\n\t}\t\n    \n    if (M != 0.) {\n\t\tX = X / (M);\n\t\tV = V / (M);\n\t}\n\n\t#ifdef INIT\n\t\tX = vec2<f32>(pos);\n\t\tV = vec2<f32>(0.);\n\t\tM = Ha(vec2<f32>(pos) - (R * 0.5 - R.x * 0.1)) * Hb(R * 0.5 + R.x * 0.1 - vec2<f32>(pos));\n\t#endif\n\n\tX = X - vec2<f32>(pos);\n\n    let eX = f32(pack(X));\n    let eV = f32(pack(V));\n\n\tlet U = vec4<f32>(eX, eV, M, 0.);\n\n    textureStore(buffer_a, location, U);\n\n} \n\n"
  },
  {
    "path": "assets/shaders/molecular_dynamics/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0)\n\n// #define P(p) texture(iChannel0, mod(p,R)/R)\n\n// #define C(p) texture(iChannel1, mod(p,R)/R)\n\n// #define GS(x) exp(-dot(x,x))\n\n// #define GS0(x) exp(-length(x))\n\n// #define CI(x) smoothstep(1.0, 0.9, length(x))\n\n// #define Dir(ang) vec2(cos(ang), sin(ang))\n\n// #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang))\n\n\n// #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \\\n//            65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) )   \n\n// #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0)              \n\n// #define DECODE(X) UNPACK(floatBitsToUint(X))\n\n// #define ENCODE(X) uintBitsToFloat(PACK(X))\n\nlet PI = 3.14159265;\n\nlet dt = 0.4;\n\n// let R = uni.iResolution.xy;\n\nlet cooling = 1.5;\n\nfn GS(x1: vec2<f32>) -> f32 {\n    return exp(-dot(x1, x1));\n}\n\nfn MF(dx: vec2<f32>) -> f32 {\n\treturn -GS(0.75 * dx) + 0.15 * GS(0.4 * dx);\n\n} \n\nfn Ha(x: vec2<f32>) -> f32 {\n    var x2: f32;\n    if (x.x >= 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y >= 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\t// return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.);\n    return x2;\n\n} \n\nfn Hb(x: vec2<f32>) -> f32 {\n\t// return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.);\n    var x2: f32;\n    if (x.x > 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y > 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\n    return x2;\n\n} \n\nfn unpack(X: u32) -> vec2<f32> {\n    return (clamp(\n            vec2<f32>(f32(X % 65535u), f32(X / 65535u)) / 65534.0, \n            vec2<f32>(0.), \n            vec2<f32>(1.)\n        ) * 2.0 - 1.0\n    ) ;\n}\n\nfn pack(v: vec2<f32>) -> u32 {\n    return  (     u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + \n           65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) )   ;\n}\n\n\n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\nfn border(p: vec2<f32>, R: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.49, 0.49));\n\tlet box: f32 = sdBox(p - R * vec2<f32>(0.5, 0.6), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(0., 0.));\n\treturn bound;\n\n} \n\nlet h = 1.;\n\nfn bN(p: vec2<f32>, R: vec2<f32>) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0., h);\n\tlet idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy, R) \n        + idx.xyw * border(p + dx.xy, R) \n        + idx.yzw * border(p + dx.yz, R) \n        + idx.yxw * border(p + dx.yx, R);\n\treturn vec3<f32>(normalize(r.xy), r.z + 0.0001);\n\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// }\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>)  {\n    let R = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let pos = location;\n\n\n\tlet p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> = textureLoad(buffer_a, pos % vec2<i32>( R));\n\t// let data: vec4<f32> = textureLoad(buffer_a, pos );\n\n\n\t// var X: vec2<f32> = DECODE(data.x) + pos;\n\t// var V: vec2<f32> = DECODE(data.y);\n\n    var X: vec2<f32> = unpack(u32(data.x)) + vec2<f32>(pos);\n    var V: vec2<f32> = unpack(u32(data.y));\n\n\n\tlet M: f32 = data.z;\n\tif (M != 0.) {\n\t\tvar Fa: vec2<f32> = vec2<f32>(0.);\n\t\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\n\t\t\tfor (var j: i32 = -2; j <= 2; j = j + 1) {\n\t\t\t\tlet tpos: vec2<i32> = pos + vec2<i32>(i, j);\n\t\t\t\t// let data: vec4<f32> = T(tpos);\n\n                let data: vec4<f32> = textureLoad(buffer_a, (tpos % vec2<i32>( R)));\n\t\t\t\t// let data: vec4<f32> = textureLoad(buffer_a, (tpos ));\n\n                //  texelFetch(iChannel0, ivec2(mod(p,R)), 0)\n\n\t\t\t\t// let X0: vec2<f32> = DECODE(data.x) + tpos;\n\t\t\t\t// let V0: vec2<f32> = DECODE(data.y);\n\n                var X0: vec2<f32> = unpack(u32(data.x)) + vec2<f32>(tpos);\n                var V0: vec2<f32> = unpack(u32(data.y));\n\n\t\t\t\tlet M0: f32 = data.z;\n\t\t\t\tlet dx: vec2<f32> = X0 - X;\n\n\t\t\t\tFa = Fa + (M0 * MF(dx) * dx);\n\t\t\t\n\t\t\t}\t\n\t\t}\t\t\n            \n\t\tvar F: vec2<f32> = vec2<f32>(0.);\n\t\tif (uni.iMouse.z > 0.) {\n\t\t\tlet dx: vec2<f32> = vec2<f32>(pos) - uni.iMouse.xy;\n\t\t\tF = F - (0.003 * dx * GS(dx / 30.));\n\t\t}\n\n\t\tF = F + (0.001 * vec2<f32>(0., -1.0));\n\n\t\tV = V + ((F + Fa) * dt / M);\n\t\tX = X + (cooling * Fa * dt / M);\n\t\tlet BORD: vec3<f32> = bN(X, R);\n\n\t\tV = V + (0.5 * smoothStep(0., 5., -BORD.z) * BORD.xy);\n\t\tlet v: f32 = length(V);\n\n\t\tvar denom: f32 = 1.0;\n\t\tif (v > 1.) {\n\t\t\tdenom = 1. * v;\n\t\t} \n\t\tV = V / denom;\n\t\t// V = V / (v > 1. ? 1. * v : 1.);\n\t\t\n\t\t\t\n\t}\n\tX = X - vec2<f32>(pos);\n\t// U = vec4<f32>(ENCODE(X), ENCODE(V), M, 0.);\n\n    let eX = f32(pack(X));\n    let eV = f32(pack(V));\n\n\tlet U = vec4<f32>(eX, eV, M, 0.);\n\n    textureStore(buffer_b, location, U);\n\n} \n\n"
  },
  {
    "path": "assets/shaders/molecular_dynamics/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0)\n\n// #define P(p) texture(iChannel0, mod(p,R)/R)\n\n// #define C(p) texture(iChannel1, mod(p,R)/R)\n\n// #define GS(x) exp(-dot(x,x))\n\n// #define GS0(x) exp(-length(x))\n\n// #define CI(x) smoothstep(1.0, 0.9, length(x))\n\n// #define Dir(ang) vec2(cos(ang), sin(ang))\n\n// #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang))\n\n\n// #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \\\n//            65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) )   \n\n// #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0)              \n\n// #define DECODE(X) UNPACK(floatBitsToUint(X))\n\n// #define ENCODE(X) uintBitsToFloat(PACK(X))\n\nlet PI = 3.14159265;\n\nlet dt = 0.4;\n\n// let R = uni.iResolution.xy;\n\nlet cooling = 1.5;\n\nfn GS(x1: vec2<f32>) -> f32 {\n    return exp(-dot(x1, x1));\n}\n\nfn MF(dx: vec2<f32>) -> f32 {\n\treturn -GS(0.75 * dx) + 0.15 * GS(0.4 * dx);\n\n} \n\nfn Ha(x: vec2<f32>) -> f32 {\n    var x2: f32;\n    if (x.x >= 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y >= 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\t// return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.);\n    return x2;\n\n} \n\nfn Hb(x: vec2<f32>) -> f32 {\n\t// return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.);\n    var x2: f32;\n    if (x.x > 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y > 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\n    return x2;\n\n} \n\nfn unpack(X: u32) -> vec2<f32> {\n    return (clamp(\n            vec2<f32>(f32(X % 65535u), f32(X / 65535u)) / 65534.0, \n            vec2<f32>(0.), \n            vec2<f32>(1.)\n        ) * 2.0 - 1.0\n    ) ;\n}\n\nfn pack(v: vec2<f32>) -> u32 {\n    return  (     u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + \n           65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) )   ;\n}\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/molecular_dynamics/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0)\n\n// #define P(p) texture(iChannel0, mod(p,R)/R)\n\n// #define C(p) texture(iChannel1, mod(p,R)/R)\n\n// #define GS(x) exp(-dot(x,x))\n\n// #define GS0(x) exp(-length(x))\n\n// #define CI(x) smoothstep(1.0, 0.9, length(x))\n\n// #define Dir(ang) vec2(cos(ang), sin(ang))\n\n// #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang))\n\n\n// #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \\\n//            65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) )   \n\n// #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0)              \n\n// #define DECODE(X) UNPACK(floatBitsToUint(X))\n\n// #define ENCODE(X) uintBitsToFloat(PACK(X))\n\nlet PI = 3.14159265;\n\nlet dt = 0.4;\n\n// let R = uni.iResolution.xy;\n\nlet cooling = 1.5;\n\nfn GS(x1: vec2<f32>) -> f32 {\n    return exp(-dot(x1, x1));\n}\n\nfn MF(dx: vec2<f32>) -> f32 {\n\treturn -GS(0.75 * dx) + 0.15 * GS(0.4 * dx);\n\n} \n\nfn Ha(x: vec2<f32>) -> f32 {\n    var x2: f32;\n    if (x.x >= 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y >= 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\t// return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.);\n    return x2;\n\n} \n\nfn Hb(x: vec2<f32>) -> f32 {\n\t// return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.);\n    var x2: f32;\n    if (x.x > 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y > 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\n    return x2;\n\n} \n\nfn unpack(X: u32) -> vec2<f32> {\n    return (clamp(\n            vec2<f32>(f32(X % 65535u), f32(X / 65535u)) / 65534.0, \n            vec2<f32>(0.), \n            vec2<f32>(1.)\n        ) * 2.0 - 1.0\n    ) ;\n}\n\nfn pack(v: vec2<f32>) -> u32 {\n    return  (     u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + \n           65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) )   ;\n}\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/molecular_dynamics/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// [[group(0), binding(1)]]\n// var buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(2)]]\n// var buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(3)]]\n// var buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(4)]]\n// var buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n[[group(0), binding(8)]]\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n[[group(0), binding(9)]]\nvar rgba_noise_256_texture_sampler: sampler;\n\n\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n\n// #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0)\n\n// #define P(p) texture(iChannel0, mod(p,R)/R)\n\n// #define C(p) texture(iChannel1, mod(p,R)/R)\n\n// #define GS(x) exp(-dot(x,x))\n\n// #define GS0(x) exp(-length(x))\n\n// #define CI(x) smoothstep(1.0, 0.9, length(x))\n\n// #define Dir(ang) vec2(cos(ang), sin(ang))\n\n// #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang))\n\n\n// #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \\\n//            65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) )   \n\n// #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0)              \n\n// #define DECODE(X) UNPACK(floatBitsToUint(X))\n\n// #define ENCODE(X) uintBitsToFloat(PACK(X))\n\nlet PI = 3.14159265;\n\nlet dt = 0.4;\n\n// let R = uni.iResolution.xy;\n\nlet cooling = 1.5;\n\nfn GS(x1: vec2<f32>) -> f32 {\n    return exp(-dot(x1, x1));\n}\n\nfn MF(dx: vec2<f32>) -> f32 {\n\treturn -GS(0.75 * dx) + 0.15 * GS(0.4 * dx);\n\n} \n\nfn Ha(x: vec2<f32>) -> f32 {\n    var x2: f32;\n    if (x.x >= 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y >= 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\t// return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.);\n    return x2;\n\n} \n\nfn Hb(x: vec2<f32>) -> f32 {\n\t// return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.);\n    var x2: f32;\n    if (x.x > 0.) {\n        x2 = 1.;\n    } else {\n        x2 = 0.0;\n    }\n\n    if (x.y > 0.) {\n        x2 = x2;\n    } else {\n        x2 = 0.0;\n    }\n\n    return x2;\n\n} \n\nfn unpack(X: u32) -> vec2<f32> {\n    return (clamp(\n            vec2<f32>(f32(X % 65535u), f32(X / 65535u)) / 65534.0, \n            vec2<f32>(0.), \n            vec2<f32>(1.)\n        ) * 2.0 - 1.0\n    ) ;\n}\n\nfn pack(v: vec2<f32>) -> u32 {\n    return  (     u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + \n           65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) )   ;\n}\n\n\n\n// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n\n\n// fn hsv2rgb( c: vec3<f32>) -> vec3<f32> {\n\n// \tvar rgb: vec3<f32> = clamp(abs(mod(c.x * 6. + vec3<f32>(0., 4., 2.), 6.) - 3.) - 1., 0., 1.);\n// \trgb = rgb * rgb * (3. - 2. * rgb);\n// \treturn c.z * mix(vec3<f32>(1.), rgb, c.y);\n\n// } \n\nfn hsv2rgb( c: vec3<f32>) -> vec3<f32> {\n    var fractional: vec3<f32> = vec3<f32>( 0.0);\n    let m = modf(c.x * 6. + vec3<f32>(0., 4., 2.) / 6., &fractional);\n\n    // let v = vec3<f32>(0., 4., 2.);\n    // let fractional: vec3<f32> = vec3<f32>(vec3<i32>( (c.x * 6. +  v) / 6.0)) ;\n        \n    // let whatever = modf(uv + 1.0, &tempo);\n    // var temp2 = 0.;\n    // let frac = modf(tempo / 2.0, &temp2);\n\n    let af: vec3<f32>  = abs(fractional - 3.) - 1.;\n\tvar rgb: vec3<f32> = clamp(af, vec3<f32>(0.), vec3<f32>(1.));\n\n\trgb = rgb * rgb * (3. - 2. * rgb);\n\treturn c.z * mix(vec3<f32>(1.), rgb, c.y);\n} \n\n\n\nlet radius = 1.0;\n\nlet zoom = 0.3;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R = uni.iResolution.xy;\n    // let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let pos = location;\n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n// fn mainImage( col: vec4<f32>,  pos: vec2<f32>) -> () {\n\n\n\n\n\tvar rho: f32 = 0.001;\n\tvar vel: vec2<f32> = vec2<f32>(0., 0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\n\t\tfor (var j: i32 = -2; j <= 2; j = j + 1) {\n\t\t\tlet tpos: vec2<i32> = pos + vec2<i32>(i, j);\n\n\t\t\t// let data: vec4<f32> = texelFetch(buffer_b, ivec2(mod(tpos,R)), 0)\n            let data: vec4<f32> = textureLoad(buffer_b, (tpos % vec2<i32>( R)));\n\n\t\t\tvar X0: vec2<f32> = unpack(u32(data.x)) + vec2<f32>(tpos);\n\t\t\tvar V0: vec2<f32> = unpack(u32(data.y));\n\t\t\tlet M0: f32 = data.z;\n\t\t\tlet dx: vec2<f32> = X0 - vec2<f32>(pos);\n\n\t\t\tlet K: f32 = GS ((dx / radius)) / (radius * radius);\n\n\t\t\trho = rho + (M0 * K);\n\t\t\tvel = vel + (M0 * K * V0);\n\t\t\n\t\t}\t\n\t}\tvel = vel / (rho);\n\n\tlet vc: vec3<f32> = hsv2rgb(\n        vec3<f32>(\n            6. * atan2(vel.x, vel.y) / (2. * PI), \n            1.,\n            rho * length(vel.xy)\n        )\n    );\n\n\tlet col: vec3<f32> = cos(0.9 * vec3<f32>(3., 2., 1.) * rho) + 0. * vc;\n    let U = vec4<f32>(col, 1.);\n\n    textureStore(texture, y_inverted_location, U);\n\n} \n\n"
  },
  {
    "path": "assets/shaders/paint/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\nfn hue(v: f32) -> vec4<f32> {\n    return (vec4<f32>(.6) + vec4<f32>(.6) * cos(vec4<f32>(6.3 * v) + vec4<f32>(0.0, 23.0, 21.0, 0.0)));\n}\n\nfn smoothit(v: f32) -> f32 {\n    return smoothstep(1.5, 0., v);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn sdRhombus(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let q = abs(p);\n    let qb = dot(q, vec2<f32>(b.x, -b.y));\n    let bb = dot(b, vec2<f32>(b.x, -b.y));\n    let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.);\n    let d = length(q - 0.5 * b * vec2<f32>(1. - h, 1. + h));\n    return d * sign(q.x * b.y + q.y * b.x - b.x * b.y);\n}\n\nfn sdTriangleIsosceles(p: vec2<f32>, c: vec2<f32>) -> f32 {\n    let q = vec2<f32>(abs(p.x), p.y);\n    let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.);\n    let b = q - c * vec2<f32>(clamp(q.x / c.x, 0., 1.), 1.);\n    let s = -sign(c.y);\n    let d = min(vec2<f32>(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2<f32>(dot(b, b), s * (q.y - c.y)));\n    return -sqrt(d.x) * sign(d.y);\n}\n\nfn sdStar(p: vec2<f32>, r: f32, n: u32, m: f32) -> f32 {\n    let an = 3.141593 / f32(n);\n    let en = 3.141593 / m;\n    let acs = vec2<f32>(cos(an), sin(an));\n    let ecs = vec2<f32>(cos(en), sin(en));\n    let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an;\n    var q: vec2<f32> = length(p) * vec2<f32>(cos(bn), abs(sin(bn)));\n    q = q - r * acs;\n    q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y);\n    return length(q) * sign(q.x);\n}\n\nfn sdHeart(p: vec2<f32>) -> f32 {\n    let q = vec2<f32>(abs(p.x), p.y);\n    let w = q - vec2<f32>(0.25, 0.75);\n    if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; }\n    let u = q - vec2<f32>(0., 1.0);\n    let v = q - 0.5 * max(q.x + q.y, 0.);\n    return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y);\n}\n\nfn sdMoon(p: vec2<f32>, d: f32, ra: f32, rb: f32) -> f32 {\n    let q = vec2<f32>(p.x, abs(p.y));\n    let a = (ra * ra - rb * rb + d * d) / (2. * d);\n    let b = sqrt(max(ra * ra - a * a, 0.));\n    if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q - vec2<f32>(a, b)); }\n    return max((length(q) - ra), -(length(q - vec2<f32>(d, 0.)) - rb));\n}\n\nfn sdCross(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    var q: vec2<f32> = abs(p);\n    q = select(q.xy, q.yx, q.y > q.x);\n    let t = q - b;\n    let k = max(t.y, t.x);\n    let w = select(vec2<f32>(b.y - q.x, -k), t, k > 0.);\n    return sign(k) * length(max(w, vec2<f32>(0.)));\n}\n\nfn sdRoundedX(p: vec2<f32>, w: f32, r: f32) -> f32 {\n    let q = abs(p);\n    return length(q - min(q.x + q.y, w) * 0.5) - r;\n}\n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     # ifdef INIT\n//         if (location.x == 0 && location.y == 0 )  {\n//             textureStore(buffer_a, location, hue(4.0 / 8.0));\n//         } else {\n//             // set brush color to black\n//             let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n//             textureStore(buffer_a, location, black);\n//         }\n//     # endif\n// }\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    // let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    // let location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n\n    // on the very first frame, INIT is defined. Otherwise, it is not.\n    #ifdef INIT\n        if (location.x == 0 && location.y == 0) {\n            textureStore(buffer_a, location, hue(4.0 / 8.0));\n        } else {\n                // set brush color to black\n            let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n            textureStore(buffer_a, location, black);\n        }\n    #endif\n    // }\n\n    let U: vec2<f32> = vec2<f32>(location) / R;\n    let M: vec2<f32> = vec2<f32>(uni.iMouse.x, uni.iMouse.y) / R ;\n\n\n     var O: vec4<f32> = textureLoad(buffer_a, location);\n\n    if (location.x == 0 && location.y == 0) {\n        if (M.x < 0.1 && uni.iMouse.w > 0.0) { // just pressed left mouse button\n            let y: f32 = floor(9. * M.y);\n            O = hue(y / 8.);\n\n             textureStore(buffer_a, location, O);\n        }\n        return;\n    }\n\n\n    // display palette on left\n    if (U.x < 0.1) {\n        let y: f32 = floor(9. * U.y);\n        O = hue(y / 8.);\n        O.w = 1.;\n        textureStore(buffer_a, location, O);\n        return;\n    }\n\n    let brush_color = textureLoad(buffer_a, vec2<i32>(0, 0));\n\n    // apply paint\n    if (uni.iMouse.z > 1.0) {\n        let mouse_pix = vec2<f32>(uni.iMouse.x, uni.iMouse.y);\n\n        let brush_sdf = sdCircle(vec2<f32>(location), mouse_pix, 10.0);\n        let brush_d = smoothstep(0.0, 5.0, brush_sdf);\n        let brush_intensity = 0.1;\n        O = mix(O, brush_color, (1.0 - brush_d) * brush_intensity);\n    }\n\n    let inverted_y = vec2<i32>(location.x, location.y);\n\n\n    textureStore(buffer_a, location, O);\n}"
  },
  {
    "path": "assets/shaders/paint/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/paint/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/paint/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/paint/common.wgsl",
    "content": "// unused\n\n#define_import_path bevy_shadertoy_wgsl::assets::shaders::common\n\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};"
  },
  {
    "path": "assets/shaders/paint/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let location2 = vec2<i32>(i32(R.x) - i32(invocation_id.x), i32(invocation_id.y));\n\n    var alive = true;\n\n\tvar q: f32;\n\tif (true) { \n\t\tq = 1.;\n\t} else { \n\t\tq = 4.;\n\t};\n\n    var O: vec4<f32> =  mix(textureLoad(buffer_a, location),vec4<f32>(0.5), 0.1);\n\n    // var O: vec4<f32> = vec4<f32>(0.5);\n\n    textureStore(texture, y_inverted_location, O);\n}"
  },
  {
    "path": "assets/shaders/paint2/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\ntype float2 = vec2<f32>;\ntype float4 = vec4<f32>;\n\nfn hue(v: f32) -> vec4<f32> { \n    return (vec4<f32>(.6) + vec4<f32>(.6) * cos( vec4<f32>(6.3 * v) + vec4<f32>(0.0,23.0,21.0,0.0 ) ));\n}\n\nfn smoothit(v: f32) -> f32{ \n    return smoothStep( 1.5, 0., v );\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n  let pa = p - a;\n  let ba = b - a;\n  let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n  return length(pa - ba * h);\n}\n\nfn sdRhombus(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  let q = abs(p);\n  let qb = dot(q, vec2<f32>(b.x, -b.y));\n  let bb = dot(b, vec2<f32>(b.x, -b.y));\n  let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.);\n  let d = length(q - 0.5 * b * vec2<f32>(1. - h, 1. + h));\n  return d * sign(q.x * b.y + q.y * b.x - b.x * b.y);\n}\n\nfn sdTriangleIsosceles(p: vec2<f32>, c: vec2<f32>) -> f32 {\n  let q = vec2<f32>(abs(p.x), p.y);\n  let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.);\n  let b = q - c * vec2<f32>(clamp(q.x / c.x, 0., 1.), 1.);\n  let s = -sign(c.y);\n  let d = min(vec2<f32>(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2<f32>(dot(b, b), s * (q.y - c.y)));\n  return -sqrt(d.x) * sign(d.y);\n}\n\nfn sdStar(p: vec2<f32>, r: f32, n: u32, m: f32) ->f32 {\n  let an = 3.141593 / f32(n);\n  let en = 3.141593 / m;\n  let acs = vec2<f32>(cos(an), sin(an));\n  let ecs = vec2<f32>(cos(en), sin(en));\n  let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an;\n  var q: vec2<f32> = length(p) * vec2<f32>(cos(bn), abs(sin(bn)));\n  q = q - r * acs;\n  q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y);\n  return length(q) * sign(q.x);\n}\n\nfn sdHeart(p: vec2<f32>) -> f32 {\n  let q = vec2<f32>(abs(p.x), p.y);\n  let w = q - vec2<f32>(0.25, 0.75);\n  if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; }\n  let u = q - vec2<f32>(0., 1.0);\n  let v = q - 0.5 * max(q.x + q.y, 0.);\n  return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y);\n}\n\nfn sdMoon(p: vec2<f32>, d: f32, ra: f32, rb: f32) -> f32 {\n  let q = vec2<f32>(p.x, abs(p.y));\n  let a = (ra * ra - rb * rb + d * d) / (2. * d);\n  let b = sqrt(max(ra * ra - a * a, 0.));\n  if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q-vec2<f32>(a, b)); }\n  return max((length(q) - ra), -(length(q - vec2<f32>(d, 0.)) - rb));\n}\n\nfn sdCross(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  var q: vec2<f32> = abs(p);\n  q = select(q.xy, q.yx, q.y > q.x);\n  let t = q - b;\n  let k = max(t.y, t.x);\n  let w = select(vec2<f32>(b.y - q.x, -k), t, k > 0.);\n  return sign(k) * length(max(w, vec2<f32>(0.)));\n}\n\nfn sdRoundedX(p: vec2<f32>, w: f32, r: f32) -> f32 {\n  let q = abs(p);\n  return length(q - min(q.x + q.y, w) * 0.5) - r;\n}\n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n  let d = length(p - c);\n  return d - r;\n}\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     # ifdef INIT\n//         if (location.x == 0 && location.y == 0 )  {\n//             textureStore(buffer_a, location, hue(4.0 / 8.0));\n//         } else {\n//             // set brush color to black\n//             let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n//             textureStore(buffer_a, location, black);\n//         }\n//     # endif\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // the first three frames are not directed inside the update function.\n    // The first time this function is called is on frame 4.\n    if (i32(uni.iFrame) == 3) { \n    // # ifdef INIT\n        if (location.x == 0 && location.y == 0 )  {\n            textureStore(buffer_a, location, hue(4.0 / 8.0));\n        } else {\n            // set brush color to black\n            let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n            textureStore(buffer_a, location, black);\n        }\n    // # endif\n    }\n\n    let R: float2 = uni.iResolution.xy;\n    let U: vec2<f32> = vec2<f32>(location) / R;\n    let M: float2 = vec2<f32>(uni.iMouse.x, 1.0-uni.iMouse.y);\n\n    var O: float4 =  textureLoad(buffer_a, location);\n\n    if (location.x == 0 && location.y == 0 )  {\n        if ( uni.iMouse.x < 0.1 && uni.iMouse.w == 1.0) { // just pressed left mouse button\n            let y: f32 = floor(9.*M.y);\n            O = hue( y/8. ); \n            textureStore(buffer_a, location, O);\n        }\n        return;\n    }\n\n    // display palette on left\n    if ( U.x < 0.1  ) {  \n        let y: f32 = floor(9.*U.y);\n        O = hue( y/8. ); \n        O.w = 1.;\n        textureStore(buffer_a, location, O);\n        return;\n    }\n\n    // let brush_color = float4(1., 0., 0., 1.);\n    let brush_color = textureLoad(buffer_a, vec2<i32>(0,0));\n\n    // apply paint\n    if (uni.iMouse.z == 1.0) {\n        let mouse_pix = vec2<f32>(uni.iMouse.x *  R.x, (1.0 - uni.iMouse.y) * R.y );\n\n        let brush_sdf = sdCircle(vec2<f32>(location), mouse_pix, 10.0);\n        let brush_d = smoothStep(0.0, 5.0, brush_sdf);\n        O = mix(O, brush_color, (1.0-brush_d) * 0.01);\n    }\n    \n\n\n    textureStore(buffer_a, location, O);\n\n}"
  },
  {
    "path": "assets/shaders/paint2/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/paint2/buffer_c.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/paint2/buffer_d.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/paint2/common.wgsl",
    "content": "// unused\n\n#define_import_path bevy_shadertoy_wgsl::assets::shaders::common\n\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};"
  },
  {
    "path": "assets/shaders/paint2/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var alive = true;\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "assets/shaders/paint2/image2.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: i32;\n    iSampleRate: i32;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n    \n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(f32(0));\n    textureStore(texture, location, color);\n}\n\n\n\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var alive = true;\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n    // let color = vec4<f32>(O.x, 0.1, 0.12, 1.0);\n\n    // storageBarrier();\n\n    // textureStore(texture, location, vec4<f32>(color));\n    textureStore(texture, location, O);\n}\n\n\n\n"
  },
  {
    "path": "assets/shaders/paint_streams/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precis: u8) -> f32 {\n//     let value_u32 = self >> (place - precis);\n\n//     let mut mask = u32::MAX;\n//     if precis < 32 {\n//         mask = (1 << (precis)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>,\n\tV: vec2<f32>,\n\tM: vec2<f32>,\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n// struct particle {\n// \tX: vec2<f32>,\n// \tV: vec2<f32>,\n// \tM: vec2<f32>,\n// };\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\nfn Reintegration(ch: texture_storage_2d<rgba32float, read_write>, pos: vec2<f32>) -> particle {\n\n    var P: particle = particle(vec2<f32>(0.0), vec2<f32>(0.0), vec2<f32>(0.0));\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\n            let data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt); //integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothstep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n            let m: f32 = P0.M.x * D.z;\n            P.X = P.X + (D.xy * m);\n            P.V = P.V + (P0.V * m);\n            P.M.y = P.M.y + (P0.M.y * m);\n            P.M.x = P.M.x + (m);\n        }\n    }\n\n\n    if (P.M.x > 0.0000001) {\n        P.X = P.X / (P.M.x);\n        P.V = P.V / (P.M.x);\n        P.M.y = P.M.y / (P.M.x);\n    }\n\n    return P;\n} \n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var U: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n\t// R = uni.iResolution.xy;\n\t// time = uni.iTime;\n\t// Mouse = uni.iMouse;\n    // let p: vec2<i32> = vec2<i32>(pos);\n\t// let data: vec4<f32> = texel(ch0, pos);\n    // var P: particle;\n    var P: particle = Reintegration(buffer_b, pos);\n\n\t// if (uni.iFrame < 1) {\n    #ifdef INIT\n    let rand: vec3<f32> =  hash32(pos); \n\n    if (rand.z < 0.) {\n        P.X = pos;\n        P.V = 0.5 * (rand.xy - 0.5) + vec2<f32>(0., 0.);\n        P.M = vec2<f32>(mass, 0.);\n    } else {\n\n        P.X = pos;\n        P.V = vec2<f32>(0.);\n        P.M = vec2<f32>(0.000001);\n    }\n    #endif\n\t// }\n\n    U = saveParticle(P, pos);\n    // U = clamp(U, vec4<f32>(0.), vec4<f32>(1.));\n    textureStore(buffer_a, location, U);\n} \n"
  },
  {
    "path": "assets/shaders/paint_streams/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precis: u8) -> f32 {\n//     let value_u32 = self >> (place - precis);\n\n//     let mut mask = u32::MAX;\n//     if precis < 32 {\n//         mask = (1 << (precis)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>,\n\tV: vec2<f32>,\n\tM: vec2<f32>,\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n// struct particle {\n// \tX: vec2<f32>,\n// \tV: vec2<f32>,\n// \tM: vec2<f32>,\n// };\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\nfn border(p: vec2<f32>, R2: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\n\n\nfn bN(p: vec2<f32>, R2: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0., h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2);\n    return vec3<f32>(normalize(r.xy), r.z + 1.0e-4);\n} \n\nfn Simulation(\n    ch: texture_storage_2d<rgba32float, read_write>, \n    P: ptr<function, particle>,\n    pos: vec2<f32>)  \n{\n    var F: vec2<f32> = vec2<f32>(0.);\n    var avgV: vec3<f32> = vec3<f32>(0.,);\n\n    // var P = *PIn;\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n            // let data: vec4<f32> = texelFetch(ch, Bi(tpos), 0.);\n\n            let data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos)) ;\n\n            var P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - (*P).X;\n            let avgP: f32 = 0.5 * P0.M.x * (Pf((*P).M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V.x, P0.V.y, 1.));\n        }\n    }\n\n    var avgVxy = avgV.xy;\n    avgVxy = avgV.xy / (avgV.z);\n    avgV.x = avgVxy.x;\n    avgV.y = avgVxy.y;\n\n    F = F + (0. * (*P).M.x * (avgV.xy - (*P).V));\n    F = F + ((*P).M.x * vec2<f32>(0., -0.0004));\n\n    if (Mouse.z > 0.) {\n        let dm: vec2<f32> = (Mouse.xy - Mouse.zw ) / 10.;\n        let d: f32 = distance(Mouse.xy, (*P).X) / 20.;\n        F = F + (0.001 * dm * exp(-d * d));\n\n        // let Part = particle(vec2<f32>(0.), vec2<f32>(0.), vec2<f32>(0.));\n        // return Part;\n    }\n\n    (*P).V = (*P).V + (F * dt / (*P).M.x);\n\n    let N: vec3<f32> = bN((*P).X, R);\n\n    let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, (*P).V);\n    (*P).V = (*P).V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n    (*P).V = (*P).V + (0. * (*P).M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\n    if (N.z < 0.) {\n        (*P).V = vec2<f32>(0.);\n    }\n\n    let v: f32 = length((*P).V);\n    var dum: f32;\n    if (v > 1.) { dum = v; } else { dum = 1.; }\n    (*P).V = (*P).V / dum;\n\n    // return P;\n}\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var U: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n        // R = uni.iResolution.xy;\n    time = uni.iTime;\n    Mouse = uni.iMouse;\n    let p: vec2<i32> = vec2<i32>(pos);\n        // let data: vec4<f32> = texel(ch0, pos);\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n\n    if (P.M.x != 0.) {\n         Simulation(buffer_a, &P, pos);\n    }\n\n    let timeMult = 1.0;\n    if (length(P.X - R * vec2<f32>(0.55, 0.9)) < 20.) {\n        P.X = pos;\n        P.V = 0.5 * Dir(-PI * 0.75 + 0.3 * sin(0.4 * 2.0 * timeMult));\n        P.M = mix(P.M, vec2<f32>(fluid_rho, 1.), 0.4);\n    }\n\n    if (length(P.X - R * vec2<f32>(0.45, 0.9)) < 20.) {\n        // P.X = pos;\n        // P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * timeMult));\n        // P.M = mix(P.M, vec2<f32>(fluid_rho, 0.), 0.4);\n\n        P.X = pos;\n        P.V = 0.5 * Dir(PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * 2.0 * timeMult));\n        P.M = mix(P.M, vec2<f32>(fluid_rho, 0.5), 0.4);\n    }\n\n    U = saveParticle(P, pos);\n\n    // U = clamp(U, vec4<f32>(-1000000.), vec4<f32>(100000.));\n    // U.y = clamp(U.y, -1000000., 100000.);\n    textureStore(buffer_b, location, U);\n\n\n    // let b = vec4<f32>(.5, 0.2, 0.1, 1.0) * -10000.0;\n    // textureStore(buffer_b, location, b);\n} \n\n"
  },
  {
    "path": "assets/shaders/paint_streams/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precis: u8) -> f32 {\n//     let value_u32 = self >> (place - precis);\n\n//     let mut mask = u32::MAX;\n//     if precis < 32 {\n//         mask = (1 << (precis)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>,\n\tV: vec2<f32>,\n\tM: vec2<f32>,\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n// struct particle {\n// \tX: vec2<f32>,\n// \tV: vec2<f32>,\n// \tM: vec2<f32>,\n// };\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var fragColor: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n\t// R = uni.iResolution.xy;\n    time = uni.iTime;\n    let p: vec2<i32> = vec2<i32>(pos);\n    // let data: vec4<f32> = texel(ch0, pos);\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n    var rho: vec4<f32> = vec4<f32>(0.);\n\n    for (var i: i32 = -1; i <= 1; i = i + 1) {\n        for (var j: i32 = -1; j <= 1; j = j + 1) {\n            let ij: vec2<i32> = vec2<i32>(i, j);\n            // let data: vec4<f32> = texel(ch0, pos + ij);\n            let data: vec4<f32> = textureLoad(buffer_a, location + ij);\n\n            var P0: particle = getParticle(data, pos + vec2<f32>(ij));\n            let x0: vec2<f32> = P0.X;\n            rho = rho + (1. * vec4<f32>(P.V, P.M) * G((pos - x0) / 0.75));\n        }\n    }\n\n    // fragColor = rho;d\n    // rho = clamp(rho, vec4<f32>(0.), vec4<f32>(1.));\n    textureStore(buffer_c, location, rho);\n} \n\n"
  },
  {
    "path": "assets/shaders/paint_streams/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precis: u8) -> f32 {\n//     let value_u32 = self >> (place - precis);\n\n//     let mut mask = u32::MAX;\n//     if precis < 32 {\n//         mask = (1 << (precis)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>,\n\tV: vec2<f32>,\n\tM: vec2<f32>,\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n// struct particle {\n// \tX: vec2<f32>,\n// \tV: vec2<f32>,\n// \tM: vec2<f32>,\n// };\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/paint_streams/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n// Why are the charaacters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\nlet backColorDebug: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n\nvar<private> uv_debug: vec2<f32> ;\nvar<private> tp_debug: vec2<f32> ;\nvar<private> align_debug: vec4<f32>; // north, east, south, west\nvar<private> font_size_debug: f32;\nvar<private> dotColor_debug: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\nvar<private> drawColorDebug: vec3<f32> = vec3<f32>(1., 1., 0.);\nvar<private> vColor: vec3<f32> = backColorDebug;\nvar<private> aspect_debug: f32 = 1.;\nvar<private> pixelPosDebug: vec2<f32> = vec2<f32>(0., 0.);\n\nlet FONT_SPACE_DEBUG: f32 = 0.5;\nlet headColorDebug: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\nlet mpColorDebug: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\nlet mxColorDebug: vec3<f32> = vec3<f32>(1., 0., 0.);\nlet myColorDebug: vec3<f32> = vec3<f32>(0., 1., 0.);\nlet font_png_size_debug: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\nfn chara(ch: i32) -> f32 {\n\n    let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n\tlet q = clamp(tp_debug, vec2<f32>(0.), vec2<f32>(1.)) / 16. + fr ;\n\tlet inverted_q = vec2<f32>(q.x, 1. - q.y);\n\n\t// // There is aliasing on the charaacters\n\t// let f = textureSampleGrad(font_texture,\n    //                  font_texture_sampler,\n    //                  inverted_q,\n    //                   vec2<f32>(1.0, 0.0),\n    //                  vec2<f32>(0.0, 1.0));\n\n\t// using textureLoad without sampler\n    let q1 = vec2<i32>(font_png_size_debug  * q );\n\tlet y_inverted_q1 = vec2<i32>(q1.x, i32(font_png_size_debug.y) - q1.y);\n\n\tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n\t// smoothing out the aliasing\n\tlet dx = vec2<i32>(1, 0);\n\tlet dy = vec2<i32>(0, 1);\n\n\tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n\tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n\tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n\tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n\tlet rp = 0.25;\n\tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n\treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n} \n\nfn SetTextPosition(x: f32, y: f32)  {\n\ttp_debug =  10. * uv_debug;\n\ttp_debug.x = tp_debug.x + 17. - x;\n\ttp_debug.y = tp_debug.y - 9.4 + y;\n} \n\nfn SetTextPositionAbs(x: f32, y: f32)  {\n\ttp_debug.x = 10. * uv_debug.x - x;\n\ttp_debug.y = 10. * uv_debug.y - y;\n} \n\nfn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\t*value = fract(*value) * 10.;\n\n\tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n\t\tc = c + (chara(48 + i32(*value)));\n\t\ttp_debug.x = tp_debug.x - (0.5);\n\t\t*digits = *digits - (1);\n\t\t*value = fract(*value) * 10.;\n\n\t\tif (*digits <= 0 || *value == 0.) {\t\t\n            break;\n        }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(*digits));\n\treturn c;\n} \n\nfn maxInt(a: i32, b: i32) -> i32 {\n    var ret: i32;\n    if (a > b) { ret = a; } else { ret = b; };\n\treturn ret;\n} \n\nfn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\tc = c + (chara(45));\n\t\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (chara(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni >= digits) {\t\tbreak; }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\treturn c;\n} \n\nfn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tlet original_value: i32 = *value;\n\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\t// tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\t// c = c + (chara(45));\n\t\t\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\t// tp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (chara(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni == 0) {\t\tbreak; }\n\t}\n\n\tif (original_value < 0) {\n\t\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\tc = c + (chara(45));\n\t}\n\n\t// tp_debug.x = tp_debug.x + (0.5 * f32(digits));\n\treturn c;\n} \n\n// fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\nfn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n\t// in case of 0.099999..., round up to 0.1000000\n\tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n\tlet tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits);\n\tvar c: f32 = 0.;\n\tif (value < 0.) {\n\t\tc = chara(45);\n\t\tvalue = -value;\n\t}\n\ttp_debug.x = tp_debug.x - (0.5);\n    var ival = i32(value);\n\n    var one: i32 = 1;\n\n\tc = c + (drawInt(&ival, &one));\n\tc = c + (chara(46));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n    var frac_val = fract(value);\n\tc = c + (drawFract(&frac_val, prec));\n\ttp_debug.x = min(tp_debug.x, tp_debugx);\n\n\treturn c;\n}\n\nfn drawFloat_f32(value:  f32) -> f32 {\n    var two: i32 = 2;\n\treturn drawFloat(value, &two, 5);\n} \n\nfn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n\treturn drawFloat(value, prec, 2);\n} \n\nfn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawIntBackwards(value, &one);\n} \n\nfn drawInt_i32(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawInt(value, &one);\n} \n\n\n\n\n\nfn SetColor(red: f32, green: f32, blue: f32)  {\n\tdrawColorDebug = vec3<f32>(red, green, blue);\n} \n\nfn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n\t// vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces));\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteFloatBox(\n\tfValue: f32, \n\tmaxDigits: i32, \n\tdecimalPlaces: i32, \n\talpha: f32\n)  {\n\tvar decs = decimalPlaces;\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha);\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteInteger(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32(iValue));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n} \n\nfn WriteIntegerBack(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue));\n\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\n} \n\n\n\nfn WriteFPS()  {\n\tvar fps: f32 = f32(uni.iSampleRate);\n\tSetColor(0.8, 0.6, 0.3);\n\tvar max_digits_one = 1;\n\tWriteFloat(fps, 5, &max_digits_one);\n\tvar c: f32 = 0.;\n\tc = c + (chara(102));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (chara(112));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (chara(115));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\t// let c2 = smoothstep(0.0, 1.0, c );\n\n\tvColor = mix(vColor, drawColorDebug, c);\n} \n\nfn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n\tlet digits: i32 = 3;\n\tlet radius: f32 =  uni.iResolution.x / 400.;\n\tif (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; }\n\tlet r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius;\n\t// vColor = vColor + (mix(vec3<f32>(0.), dotColor_debug, 1. - clamp(r, 0., 1.)));\n\n\tvar max_digits_three: i32 = 3;\n\tvar mposxi: i32 = i32(mPos.x);\n\tvar mposyi: i32 = i32(mPos.y);\n\n\tvar mposx: f32 = (mPos.x);\n\tvar mposy: f32 = (mPos.y);\n\n\n\tlet x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG;\n\t\t\n\tSetTextPositionAbs(\n\t\t x_pos,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = myColorDebug;\n\tWriteIntegerBack(&mposyi);\n\n\tSetTextPositionAbs(\n\t\t x_pos - 7. *  FONT_SPACE_DEBUG,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = mxColorDebug;\n\n\tWriteIntegerBack(&mposxi);\n\n} \n\n\nfn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n  var x = r.x;\n  var y = r.y;\n  x = select(r.z, r.x, p.x > 0.);\n  y = select(r.w, r.y, p.x > 0.);\n  x  = select(y, x, p.y > 0.);\n  let q = abs(p) - b + x;\n  return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n}\n\n\n\nfn WriteRGBAValues(\n\tlocation: vec2<i32>, \n\tvalue: vec4<f32>, \n\tscreen_poz: vec2<f32>,\n\talpha: f32,\n )  {\n\tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect_debug, 1.0);\n\tlet window_ajusted = uni.iResolution / vec2<f32>(960., 600.);\n\n\tlet box_pos = vec2<f32>(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.;\n\t// let box_pos = mp;\n\n\t// // box location follows mouse position\n\t// let box_location = vec2<f32>(\n\t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t// \tuni.iMouse.y - 48. * window_ajusted.y\n\t// );\n\n\n\tlet box_location  = vec2<f32>(\n\t\t100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t\tuni.iResolution.y - 60. * window_ajusted.y,\n\t);\n\t\n\tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect_debug, 1.) ;\n\n\tlet d_box = sdRoundedBox(\n\t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n\t\t vec2<f32>(73. /  ( aspect_debug / 1.6 ), 75.) * window_ajusted, \n\t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n\t);\n\n\t// let alpha = 0.225;\n\tlet decimal_places = 3;\n\tSetColor(1., 1., 1.);\n\tvar c: f32 = 0.;\n\tlet lspace = 0.8;\n\n\tlet bg_color = vec3<f32>(.8, .7, .9);\n\tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n\t// red\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n\t) ;\n\tc = c + (chara(114)); // r\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (chara(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n\t// green\n\tSetTextPosition(\n\t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n\t) ;\n\tc = c + (chara(103)); // g\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (chara(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n\t// blue\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n\t\t) ;\n\tc = c + (chara(98)); // b\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (chara(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n\t// alpha\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n\t) ;\n\tc = c + (chara(97)); // a\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (chara(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n\tvColor = mix(vColor, drawColorDebug, c * alpha);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n\treturn mix(1., 0., smoothstep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius)));\n} \n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\nfn draw_ring(location: vec2<i32>) {\n\tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n\tlet alpha = 0.75;\n\tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n\tlet d = smoothstep(0.5, 1.5, abs(ring_dist - 1.));\n\tvColor = mix(vColor, headColorDebug,   (1. - d) * alpha );\n}\n\nfn draw_crossair(location: vec2<i32>)  {\n\n\tlet start = 5.0;\n\tlet end = 20.;\n\tlet segment1 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(start, 0.), \n\t\tvec2<f32>(end, 0.)\n\t);\n\n\tlet segment2 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(-start, 0.), \n\t\tvec2<f32>(-end, 0.)\n\t);\n\n\tlet segment3 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., start), \n\t\tvec2<f32>(0., end)\n\t);\n\n\tlet segment4 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., -start), \n\t\tvec2<f32>(0., -end)\n\t);\n\n\tvar alpha = 0.75;\n\tif (uni.iMouse.z > 0.) {\n\t\talpha = 1.0;\n\t}\n\n\tlet d = smoothstep(0.5, 1.5, segment1);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothstep(0.5, 1.5, segment2);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothstep(0.5, 1.5, segment3);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothstep(0.5, 1.5, segment4);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n}\n\nfn show_debug_info(location: vec2<i32>, color: vec3<f32>) -> vec4<f32> {    \n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    vColor = color;\n\n\n\taspect_debug =  uni.iResolution.x /  uni.iResolution.y;\n\n\tlet ratio: vec2<f32> = vec2<f32>(aspect_debug, 1.);\n\tpixelPosDebug = fragCoord.xy;\n\t// mousePosDebug = uni.iMouse.xy;\n\tuv_debug = (2. * fragCoord.xy /  uni.iResolution.xy - 1.) * ratio;\n\n\talign_debug = 10. * vec4<f32>(\n\t\t1.,      // North\n\t\taspect_debug,  // East\n\t\t-1.,     // South\n\t\t-aspect_debug, // West\n\t);\n\n\n\tWriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position\n\tWriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position\n\n\tvar c: f32 = 0.;\n\n\tSetTextPositionAbs(\n\t\t align_debug.y -      FONT_SPACE_DEBUG,\n\t\t align_debug.x - 2. * FONT_SPACE_DEBUG,\n\t);\n\n\tSetColor(0.8, 0.8, 0.8);\n\tvar resx = i32(uni.iResolution.x);\n\tvar resy = i32(uni.iResolution.y);\n\n\n\tWriteIntegerBack(&resx);\n\tc = c + (chara(28));\n\ttp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG);\n\tWriteIntegerBack(&resy);\n\n\n\tSetTextPositionAbs(\n\t\t align_debug.w - 1. * FONT_SPACE_DEBUG,\n\t\t align_debug.z - 0. * FONT_SPACE_DEBUG,\n\t);\n\n\tWriteFPS();\n\tSetColor(0.9, 0.7, 0.8);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n\t// // RGBA probe labels follow mouse\n\t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n\tlet inverted_y_mouse_location = vec2<i32>(vec2<f32>(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n\tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n\tWriteRGBAValues(location, value, poz, 0.85);\n\n\tlet inverted_y_mouseclick_location = vec2<i32>(vec2<f32>(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n\tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n\tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.65);\n\n\tdraw_crossair(location);\n\n\tdraw_ring(location);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\t\n\n\treturn fragColor;\n} \n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precis: u8) -> f32 {\n//     let value_u32 = self >> (place - precis);\n\n//     let mut mask = u32::MAX;\n//     if precis < 32 {\n//         mask = (1 << (precis)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>,\n\tV: vec2<f32>,\n\tM: vec2<f32>,\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n// struct particle {\n// \tX: vec2<f32>,\n// \tV: vec2<f32>,\n// \tM: vec2<f32>,\n// };\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n// https://www.shadertoy.com/view/WtfyDj\n// no license\n// https://michaelmoroz.github.io/Reintegration-Tracking/\n\nfn mixN(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {\n    return sqrt(mix(a * a, b * b, clamp(k, 0., 1.)));\n} \n\nfn V(p: vec2<f32>) -> vec4<f32> {\n    let data: vec4<f32> = textureLoad(buffer_c, vec2<i32>(p));\n    //  let data: vec4<f32> = textureSampleLevel(buffer_c, buffer_sampler, p / R, 0.0);\n    // let data: vec4<f32> = textureSampleGrad(buffer_c,\n    //                  buffer_sampler,\n    //                  p / R,\n    //                  vec2<f32>(0.0),\n    //                  vec2<f32>(0.0)) ;\n    return data;\n} \n\n\n\nfn border(p: vec2<f32>, R2: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\n\n\nfn bN(p: vec2<f32>, R2: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0., h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2);\n    return vec3<f32>(normalize(r.xy), r.z + 1.0e-4);\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var col: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y)) ;\n\n    // let Mouse = uni.iMouse;\n    time = uni.iTime;\n\n    let p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n    let Nb: vec3<f32> = bN(P.X, R);\n    let bord: f32 = smoothstep(2. * border_h, border_h * 0.5, border(pos, R));\n    let rho: vec4<f32> = V(pos);\n    let dx: vec3<f32> = vec3<f32>(-2., 0., 2.);\n    let grad: vec4<f32> = -0.5 * vec4<f32>(V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw);\n    let N: vec2<f32> = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001);\n    let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5);\n\n    let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.);\n\n    let a: f32 = pow(smoothstep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1);\n    let b: f32 = exp(-1.7 * smoothstep(fluid_rho * 1., fluid_rho * 7.5, rho.z));\n    let col0: vec3<f32> = vec3<f32>(1., 0.5, 0.);\n    let col1: vec3<f32> = vec3<f32>(0.1, 0.4, 1.);\n    let fcol: vec3<f32> = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5);\n    col = vec4<f32>(3.);\n    var colxyz = col.xyz;\n\n    colxyz = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    var colxyz = col.xyz;\n    colxyz = mixN(col.xyz, 0. * vec3<f32>(0.5, 0.5, 1.), bord);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    var colxyz = col.xyz;\n    colxyz = tanh(col.xyz);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    // let bufa: vec4<f32> = textureLoad(buffer_a, location);\n\n    // var col2 = vec4<f32>(0.2, 0.6, 0.9, 1.0);\n    // var col2 = vec4<f32>(0.3, 0.5, 0.29, 1.0);\n    // if (y_inverted_location.x > i32(R.x / 2.0)) {\n\n    //     let v = vec2<f32>(0.3, 0.5) * 2.0;\n\n    //     let u = f32(encodeVec2To1u(v));\n\n    //     let back = decode1uToVec2(u) / 2.0;\n\n    //     col2 = vec4<f32>(back.x, back.y, 0.29, 1.0);\n    // }\n\n    // let data2: vec4<f32> = (textureLoad(buffer_a, location)  ) ;\n    // var pb: particle = getParticle(data2, pos);\n    // let v2 = (pb.X - pos + 1.0) / 2.;\n    // let v2 = (pb.M ) / 1.;\n\n    // let debug = vec4<f32>(v2.x, 0.0, 0.0, 1.0);\n\n    // if (Mouse.z > 0.5) {\n    //     col = debug;\n    // }\n\n\n    let col_debug_info = show_debug_info(location, col.xyz);\n    \n    // textureStore(texture, y_inverted_location, toLinear(debug));\n    // textureStore(texture, y_inverted_location, toLinear(col));\n    textureStore(texture, y_inverted_location, toLinear(col_debug_info));\n} \n"
  },
  {
    "path": "assets/shaders/paint_streams2/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precision: u8) -> f32 {\n//     let value_u32 = self >> (place - precision);\n\n//     let mut mask = u32::MAX;\n//     if precision < 32 {\n//         mask = (1 << (precision)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precision: u32) -> f32 {\n    let value_u32 = input >> (place - precision);\n\n    var mask: u32 = 4294967295u;\n    if (precision < 32u) {\n        mask = (1u << precision) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precision - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precision - 1u)));\n    let delta_bits = u32(place - precision);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precision < 32u) {\n        mask = 4294967295u - (((1u << precision) - 1u) << (place - precision));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\nfn Reintegration(ch: texture_storage_2d<rgba32float, read_write>, pos: vec2<f32>) -> particle {\n\n    var P: particle = particle(vec2<f32>(0.0), vec2<f32>(0.0), vec2<f32>(0.0));\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\n            let data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt); //integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n            let m: f32 = P0.M.x * D.z;\n            P.X = P.X + (D.xy * m);\n            P.V = P.V + (P0.V * m);\n            P.M.y = P.M.y + (P0.M.y * m);\n            P.M.x = P.M.x + (m);\n        }\n    }\n\n\n    if (P.M.x > 0.0000001) {\n        P.X = P.X / (P.M.x);\n        P.V = P.V / (P.M.x);\n        P.M.y = P.M.y / (P.M.x);\n    }\n\n    return P;\n} \n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var U: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n\t// R = uni.iResolution.xy;\n\t// time = uni.iTime;\n\t// Mouse = uni.iMouse;\n    // let p: vec2<i32> = vec2<i32>(pos);\n\t// let data: vec4<f32> = texel(ch0, pos);\n    // var P: particle;\n    var P: particle = Reintegration(buffer_b, pos);\n\n\t// if (uni.iFrame < 1) {\n    #ifdef INIT\n    let rand: vec3<f32> =  hash32(pos); \n\n    if (rand.z < 0.) {\n        P.X = pos;\n        P.V = 0.5 * (rand.xy - 0.5) + vec2<f32>(0., 0.);\n        P.M = vec2<f32>(mass, 0.);\n    } else {\n\n        P.X = pos;\n        P.V = vec2<f32>(0.);\n        P.M = vec2<f32>(0.000001);\n    }\n    #endif\n\t// }\n\n    U = saveParticle(P, pos);\n    // U = clamp(U, vec4<f32>(0.), vec4<f32>(1.));\n    textureStore(buffer_a, location, U);\n} \n"
  },
  {
    "path": "assets/shaders/paint_streams2/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precision: u8) -> f32 {\n//     let value_u32 = self >> (place - precision);\n\n//     let mut mask = u32::MAX;\n//     if precision < 32 {\n//         mask = (1 << (precision)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precision: u32) -> f32 {\n    let value_u32 = input >> (place - precision);\n\n    var mask: u32 = 4294967295u;\n    if (precision < 32u) {\n        mask = (1u << precision) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precision - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precision - 1u)));\n    let delta_bits = u32(place - precision);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precision < 32u) {\n        mask = 4294967295u - (((1u << precision) - 1u) << (place - precision));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\nfn border(p: vec2<f32>, R2: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\n\n\nfn bN(p: vec2<f32>, R2: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0., h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2);\n    return vec3<f32>(normalize(r.xy), r.z + 1.0e-4);\n} \n\nfn Simulation(\n    ch: texture_storage_2d<rgba32float, read_write>, \n    P: ptr<function, particle>,\n    pos: vec2<f32>)  \n{\n    var F: vec2<f32> = vec2<f32>(0.);\n    var avgV: vec3<f32> = vec3<f32>(0.,);\n\n    // var P = *PIn;\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n            // let data: vec4<f32> = texelFetch(ch, Bi(tpos), 0.);\n\n            let data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos)) ;\n\n            var P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - (*P).X;\n            let avgP: f32 = 0.5 * P0.M.x * (Pf((*P).M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V.x, P0.V.y, 1.));\n        }\n    }\n\n    var avgVxy = avgV.xy;\n    avgVxy = avgV.xy / (avgV.z);\n    avgV.x = avgVxy.x;\n    avgV.y = avgVxy.y;\n\n    F = F + (0. * (*P).M.x * (avgV.xy - (*P).V));\n    F = F + ((*P).M.x * vec2<f32>(0., -0.0004));\n\n    if (Mouse.z > 0.) {\n        let dm: vec2<f32> = (Mouse.xy - Mouse.zw ) / 10.;\n        let d: f32 = distance(Mouse.xy, (*P).X) / 20.;\n        F = F + (0.001 * dm * exp(-d * d));\n\n        // let Part = particle(vec2<f32>(0.), vec2<f32>(0.), vec2<f32>(0.));\n        // return Part;\n    }\n\n    (*P).V = (*P).V + (F * dt / (*P).M.x);\n\n    let N: vec3<f32> = bN((*P).X, R);\n\n    let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, (*P).V);\n    (*P).V = (*P).V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n    (*P).V = (*P).V + (0. * (*P).M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\n    if (N.z < 0.) {\n        (*P).V = vec2<f32>(0.);\n    }\n\n    let v: f32 = length((*P).V);\n    var dum: f32;\n    if (v > 1.) { dum = v; } else { dum = 1.; }\n    (*P).V = (*P).V / dum;\n\n    // return P;\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var U: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n        // R = uni.iResolution.xy;\n    time = uni.iTime;\n    Mouse = uni.iMouse;\n    let p: vec2<i32> = vec2<i32>(pos);\n        // let data: vec4<f32> = texel(ch0, pos);\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n\n    if (P.M.x != 0.) {\n         Simulation(buffer_a, &P, pos);\n    }\n\n    let timeMult = 1.0;\n    if (length(P.X - R * vec2<f32>(0.55, 0.9)) < 20.) {\n        P.X = pos;\n        P.V = 0.5 * Dir(-PI * 0.75 + 0.3 * sin(0.4 * 2.0 * timeMult));\n        P.M = mix(P.M, vec2<f32>(fluid_rho, 1.), 0.4);\n    }\n\n    if (length(P.X - R * vec2<f32>(0.45, 0.9)) < 20.) {\n        // P.X = pos;\n        // P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * timeMult));\n        // P.M = mix(P.M, vec2<f32>(fluid_rho, 0.), 0.4);\n\n        P.X = pos;\n        P.V = 0.5 * Dir(PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * 2.0 * timeMult));\n        P.M = mix(P.M, vec2<f32>(fluid_rho, 0.5), 0.4);\n    }\n\n    U = saveParticle(P, pos);\n\n    // U = clamp(U, vec4<f32>(-1000000.), vec4<f32>(100000.));\n    // U.y = clamp(U.y, -1000000., 100000.);\n    textureStore(buffer_b, location, U);\n\n\n    // let b = vec4<f32>(.5, 0.2, 0.1, 1.0) * -10000.0;\n    // textureStore(buffer_b, location, b);\n} \n\n"
  },
  {
    "path": "assets/shaders/paint_streams2/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precision: u8) -> f32 {\n//     let value_u32 = self >> (place - precision);\n\n//     let mut mask = u32::MAX;\n//     if precision < 32 {\n//         mask = (1 << (precision)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precision: u32) -> f32 {\n    let value_u32 = input >> (place - precision);\n\n    var mask: u32 = 4294967295u;\n    if (precision < 32u) {\n        mask = (1u << precision) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precision - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precision - 1u)));\n    let delta_bits = u32(place - precision);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precision < 32u) {\n        mask = 4294967295u - (((1u << precision) - 1u) << (place - precision));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var fragColor: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n\t// R = uni.iResolution.xy;\n    time = uni.iTime;\n    let p: vec2<i32> = vec2<i32>(pos);\n    // let data: vec4<f32> = texel(ch0, pos);\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n    var rho: vec4<f32> = vec4<f32>(0.);\n\n    for (var i: i32 = -1; i <= 1; i = i + 1) {\n        for (var j: i32 = -1; j <= 1; j = j + 1) {\n            let ij: vec2<i32> = vec2<i32>(i, j);\n            // let data: vec4<f32> = texel(ch0, pos + ij);\n            let data: vec4<f32> = textureLoad(buffer_a, location + ij);\n\n            var P0: particle = getParticle(data, pos + vec2<f32>(ij));\n            let x0: vec2<f32> = P0.X;\n            rho = rho + (1. * vec4<f32>(P.V, P.M) * G((pos - x0) / 0.75));\n        }\n    }\n\n    // fragColor = rho;d\n    // rho = clamp(rho, vec4<f32>(0.), vec4<f32>(1.));\n    textureStore(buffer_c, location, rho);\n} \n\n"
  },
  {
    "path": "assets/shaders/paint_streams2/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precision: u8) -> f32 {\n//     let value_u32 = self >> (place - precision);\n\n//     let mut mask = u32::MAX;\n//     if precision < 32 {\n//         mask = (1 << (precision)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precision: u32) -> f32 {\n    let value_u32 = input >> (place - precision);\n\n    var mask: u32 = 4294967295u;\n    if (precision < 32u) {\n        mask = (1u << precision) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precision - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precision - 1u)));\n    let delta_bits = u32(place - precision);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precision < 32u) {\n        mask = 4294967295u - (((1u << precision) - 1u) << (place - precision));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/paint_streams2/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// [[group(0), binding(1)]]\n// var buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(2)]]\n// var buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(3)]]\n// var buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(4)]]\n// var buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n[[group(0), binding(8)]]\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n[[group(0), binding(9)]]\nvar rgba_noise_256_texture_sampler: sampler;\n\n\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n// Why are the characters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\nlet backColorDebug: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n\nvar<private> uv_debug: vec2<f32> ;\nvar<private> tp_debug: vec2<f32> ;\nvar<private> align_debug: vec4<f32>; // north, east, south, west\nvar<private> font_size_debug: f32;\nvar<private> dotColor_debug: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\nvar<private> drawColorDebug: vec3<f32> = vec3<f32>(1., 1., 0.);\nvar<private> vColor: vec3<f32> = backColorDebug;\nvar<private> aspect_debug: f32 = 1.;\nvar<private> pixelPosDebug: vec2<f32> = vec2<f32>(0., 0.);\n\nlet FONT_SPACE_DEBUG: f32 = 0.5;\nlet headColorDebug: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\nlet mpColorDebug: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\nlet mxColorDebug: vec3<f32> = vec3<f32>(1., 0., 0.);\nlet myColorDebug: vec3<f32> = vec3<f32>(0., 1., 0.);\nlet font_png_size_debug: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\nfn char(ch: i32) -> f32 {\n\n    let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n\tlet q = clamp(tp_debug, vec2<f32>(0.), vec2<f32>(1.)) / 16. + fr ;\n\tlet inverted_q = vec2<f32>(q.x, 1. - q.y);\n\n\t// // There is aliasing on the characters\n\t// let f = textureSampleGrad(font_texture,\n    //                  font_texture_sampler,\n    //                  inverted_q,\n    //                   vec2<f32>(1.0, 0.0),\n    //                  vec2<f32>(0.0, 1.0));\n\n\t// using textureLoad without sampler\n    let q1 = vec2<i32>(font_png_size_debug  * q );\n\tlet y_inverted_q1 = vec2<i32>(q1.x, i32(font_png_size_debug.y) - q1.y);\n\n\tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n\t// smoothing out the aliasing\n\tlet dx = vec2<i32>(1, 0);\n\tlet dy = vec2<i32>(0, 1);\n\n\tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n\tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n\tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n\tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n\tlet rp = 0.25;\n\tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n\treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n} \n\nfn SetTextPosition(x: f32, y: f32)  {\n\ttp_debug =  10. * uv_debug;\n\ttp_debug.x = tp_debug.x + 17. - x;\n\ttp_debug.y = tp_debug.y - 9.4 + y;\n} \n\nfn SetTextPositionAbs(x: f32, y: f32)  {\n\ttp_debug.x = 10. * uv_debug.x - x;\n\ttp_debug.y = 10. * uv_debug.y - y;\n} \n\nfn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\t*value = fract(*value) * 10.;\n\n\tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n\t\tc = c + (char(48 + i32(*value)));\n\t\ttp_debug.x = tp_debug.x - (0.5);\n\t\t*digits = *digits - (1);\n\t\t*value = fract(*value) * 10.;\n\n\t\tif (*digits <= 0 || *value == 0.) {\t\t\n            break;\n        }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(*digits));\n\treturn c;\n} \n\nfn maxInt(a: i32, b: i32) -> i32 {\n    var ret: i32;\n    if (a > b) { ret = a; } else { ret = b; };\n\treturn ret;\n} \n\nfn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\tc = c + (char(45));\n\t\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni >= digits) {\t\tbreak; }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\treturn c;\n} \n\nfn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tlet original_value: i32 = *value;\n\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\t// tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\t// c = c + (char(45));\n\t\t\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\t// tp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni == 0) {\t\tbreak; }\n\t}\n\n\tif (original_value < 0) {\n\t\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\tc = c + (char(45));\n\t}\n\n\t// tp_debug.x = tp_debug.x + (0.5 * f32(digits));\n\treturn c;\n} \n\n// fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\nfn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n\t// in case of 0.099999..., round up to 0.1000000\n\tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n\tlet tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits);\n\tvar c: f32 = 0.;\n\tif (value < 0.) {\n\t\tc = char(45);\n\t\tvalue = -value;\n\t}\n\ttp_debug.x = tp_debug.x - (0.5);\n    var ival = i32(value);\n\n    var one: i32 = 1;\n\n\tc = c + (drawInt(&ival, &one));\n\tc = c + (char(46));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n    var frac_val = fract(value);\n\tc = c + (drawFract(&frac_val, prec));\n\ttp_debug.x = min(tp_debug.x, tp_debugx);\n\n\treturn c;\n}\n\nfn drawFloat_f32(value:  f32) -> f32 {\n    var two: i32 = 2;\n\treturn drawFloat(value, &two, 5);\n} \n\nfn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n\treturn drawFloat(value, prec, 2);\n} \n\nfn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawIntBackwards(value, &one);\n} \n\nfn drawInt_i32(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawInt(value, &one);\n} \n\n\n\n\n\nfn SetColor(red: f32, green: f32, blue: f32)  {\n\tdrawColorDebug = vec3<f32>(red, green, blue);\n} \n\nfn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n\t// vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces));\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteFloatBox(\n\tfValue: f32, \n\tmaxDigits: i32, \n\tdecimalPlaces: i32, \n\talpha: f32\n)  {\n\tvar decs = decimalPlaces;\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha);\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteInteger(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32(iValue));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n} \n\nfn WriteIntegerBack(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue));\n\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\n} \n\n\n\nfn WriteFPS()  {\n\tvar fps: f32 = f32(uni.iSampleRate);\n\tSetColor(0.8, 0.6, 0.3);\n\tvar max_digits_one = 1;\n\tWriteFloat(fps, 5, &max_digits_one);\n\tvar c: f32 = 0.;\n\tc = c + (char(102));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(112));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(115));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\t// let c2 = smoothStep(0.0, 1.0, c );\n\n\tvColor = mix(vColor, drawColorDebug, c);\n} \n\nfn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n\tlet digits: i32 = 3;\n\tlet radius: f32 =  uni.iResolution.x / 400.;\n\tif (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; }\n\tlet r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius;\n\t// vColor = vColor + (mix(vec3<f32>(0.), dotColor_debug, 1. - clamp(r, 0., 1.)));\n\n\tvar max_digits_three: i32 = 3;\n\tvar mposxi: i32 = i32(mPos.x);\n\tvar mposyi: i32 = i32(mPos.y);\n\n\tvar mposx: f32 = (mPos.x);\n\tvar mposy: f32 = (mPos.y);\n\n\n\tlet x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG;\n\t\t\n\tSetTextPositionAbs(\n\t\t x_pos,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = myColorDebug;\n\tWriteIntegerBack(&mposyi);\n\n\tSetTextPositionAbs(\n\t\t x_pos - 7. *  FONT_SPACE_DEBUG,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = mxColorDebug;\n\n\tWriteIntegerBack(&mposxi);\n\n} \n\n\nfn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n  var x = r.x;\n  var y = r.y;\n  x = select(r.z, r.x, p.x > 0.);\n  y = select(r.w, r.y, p.x > 0.);\n  x  = select(y, x, p.y > 0.);\n  let q = abs(p) - b + x;\n  return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n}\n\n\n\nfn WriteRGBAValues(\n\tlocation: vec2<i32>, \n\tvalue: vec4<f32>, \n\tscreen_poz: vec2<f32>,\n\talpha: f32,\n )  {\n\tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect_debug, 1.0);\n\tlet window_ajusted = uni.iResolution / vec2<f32>(960., 600.);\n\n\tlet box_pos = vec2<f32>(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.;\n\t// let box_pos = mp;\n\n\t// // box location follows mouse position\n\t// let box_location = vec2<f32>(\n\t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t// \tuni.iMouse.y - 48. * window_ajusted.y\n\t// );\n\n\n\tlet box_location  = vec2<f32>(\n\t\t100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t\tuni.iResolution.y - 60. * window_ajusted.y,\n\t);\n\t\n\tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect_debug, 1.) ;\n\n\tlet d_box = sdRoundedBox(\n\t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n\t\t vec2<f32>(73. /  ( aspect_debug / 1.6 ), 75.) * window_ajusted, \n\t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n\t);\n\n\t// let alpha = 0.225;\n\tlet decimal_places = 3;\n\tSetColor(1., 1., 1.);\n\tvar c: f32 = 0.;\n\tlet lspace = 0.8;\n\n\tlet bg_color = vec3<f32>(.8, .7, .9);\n\tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n\t// red\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n\t) ;\n\tc = c + (char(114)); // r\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n\t// green\n\tSetTextPosition(\n\t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n\t) ;\n\tc = c + (char(103)); // g\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n\t// blue\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n\t\t) ;\n\tc = c + (char(98)); // b\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n\t// alpha\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n\t) ;\n\tc = c + (char(97)); // a\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n\tvColor = mix(vColor, drawColorDebug, c * alpha);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n\treturn mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius)));\n} \n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\nfn draw_ring(location: vec2<i32>) {\n\tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n\tlet alpha = 0.75;\n\tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n\tlet d = smoothStep(0.5, 1.5, abs(ring_dist - 1.));\n\tvColor = mix(vColor, headColorDebug,   (1. - d) * alpha );\n}\n\nfn draw_crossair(location: vec2<i32>)  {\n\n\tlet start = 5.0;\n\tlet end = 20.;\n\tlet segment1 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(start, 0.), \n\t\tvec2<f32>(end, 0.)\n\t);\n\n\tlet segment2 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(-start, 0.), \n\t\tvec2<f32>(-end, 0.)\n\t);\n\n\tlet segment3 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., start), \n\t\tvec2<f32>(0., end)\n\t);\n\n\tlet segment4 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., -start), \n\t\tvec2<f32>(0., -end)\n\t);\n\n\tvar alpha = 0.75;\n\tif (uni.iMouse.z > 0.) {\n\t\talpha = 1.0;\n\t}\n\n\tlet d = smoothStep(0.5, 1.5, segment1);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment2);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment3);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment4);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n}\n\nfn show_debug_info(location: vec2<i32>, color: vec3<f32>) -> vec4<f32> {    \n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    vColor = color;\n\n\n\taspect_debug =  uni.iResolution.x /  uni.iResolution.y;\n\n\tlet ratio: vec2<f32> = vec2<f32>(aspect_debug, 1.);\n\tpixelPosDebug = fragCoord.xy;\n\t// mousePosDebug = uni.iMouse.xy;\n\tuv_debug = (2. * fragCoord.xy /  uni.iResolution.xy - 1.) * ratio;\n\n\talign_debug = 10. * vec4<f32>(\n\t\t1.,      // North\n\t\taspect_debug,  // East\n\t\t-1.,     // South\n\t\t-aspect_debug, // West\n\t);\n\n\n\tWriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position\n\tWriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position\n\n\tvar c: f32 = 0.;\n\n\tSetTextPositionAbs(\n\t\t align_debug.y -      FONT_SPACE_DEBUG,\n\t\t align_debug.x - 2. * FONT_SPACE_DEBUG,\n\t);\n\n\tSetColor(0.8, 0.8, 0.8);\n\tvar resx = i32(uni.iResolution.x);\n\tvar resy = i32(uni.iResolution.y);\n\n\n\tWriteIntegerBack(&resx);\n\tc = c + (char(28));\n\ttp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG);\n\tWriteIntegerBack(&resy);\n\n\n\tSetTextPositionAbs(\n\t\t align_debug.w - 1. * FONT_SPACE_DEBUG,\n\t\t align_debug.z - 0. * FONT_SPACE_DEBUG,\n\t);\n\n\tWriteFPS();\n\tSetColor(0.9, 0.7, 0.8);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n\t// // RGBA probe labels follow mouse\n\t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n\tlet inverted_y_mouse_location = vec2<i32>(vec2<f32>(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n\tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n\tWriteRGBAValues(location, value, poz, 0.85);\n\n\tlet inverted_y_mouseclick_location = vec2<i32>(vec2<f32>(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n\tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n\tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.65);\n\n\tdraw_crossair(location);\n\n\tdraw_ring(location);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\t\n\n\treturn fragColor;\n} \n\n\n\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precision: u8) -> f32 {\n//     let value_u32 = self >> (place - precision);\n\n//     let mut mask = u32::MAX;\n//     if precision < 32 {\n//         mask = (1 << (precision)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precision: u32) -> f32 {\n    let value_u32 = input >> (place - precision);\n\n    var mask: u32 = 4294967295u;\n    if (precision < 32u) {\n        mask = (1u << precision) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precision - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precision - 1u)));\n    let delta_bits = u32(place - precision);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precision < 32u) {\n        mask = 4294967295u - (((1u << precision) - 1u) << (place - precision));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n// https://www.shadertoy.com/view/WtfyDj\n// no license\n// https://michaelmoroz.github.io/Reintegration-Tracking/\n\nfn mixN(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {\n    return sqrt(mix(a * a, b * b, clamp(k, 0., 1.)));\n} \n\nfn V(p: vec2<f32>) -> vec4<f32> {\n    let data: vec4<f32> = textureLoad(buffer_c, vec2<i32>(p));\n    //  let data: vec4<f32> = textureSampleLevel(buffer_c, buffer_sampler, p / R, 0.0);\n    // let data: vec4<f32> = textureSampleGrad(buffer_c,\n    //                  buffer_sampler,\n    //                  p / R,\n    //                  vec2<f32>(0.0),\n    //                  vec2<f32>(0.0)) ;\n    return data;\n} \n\n\n\nfn border(p: vec2<f32>, R2: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\n\n\nfn bN(p: vec2<f32>, R2: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0., h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2);\n    return vec3<f32>(normalize(r.xy), r.z + 1.0e-4);\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var col: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y)) ;\n\n    // let Mouse = uni.iMouse;\n    time = uni.iTime;\n\n    let p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n    let Nb: vec3<f32> = bN(P.X, R);\n    let bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos, R));\n    let rho: vec4<f32> = V(pos);\n    let dx: vec3<f32> = vec3<f32>(-2., 0., 2.);\n    let grad: vec4<f32> = -0.5 * vec4<f32>(V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw);\n    let N: vec2<f32> = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001);\n    let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5);\n\n    let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.);\n\n    let a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1);\n    let b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z));\n    let col0: vec3<f32> = vec3<f32>(1., 0.5, 0.);\n    let col1: vec3<f32> = vec3<f32>(0.1, 0.4, 1.);\n    let fcol: vec3<f32> = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5);\n    col = vec4<f32>(3.);\n    var colxyz = col.xyz;\n\n    colxyz = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    var colxyz = col.xyz;\n    colxyz = mixN(col.xyz, 0. * vec3<f32>(0.5, 0.5, 1.), bord);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    var colxyz = col.xyz;\n    colxyz = tanh(col.xyz);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    // let bufa: vec4<f32> = textureLoad(buffer_a, location);\n\n    // var col2 = vec4<f32>(0.2, 0.6, 0.9, 1.0);\n    // var col2 = vec4<f32>(0.3, 0.5, 0.29, 1.0);\n    // if (y_inverted_location.x > i32(R.x / 2.0)) {\n\n    //     let v = vec2<f32>(0.3, 0.5) * 2.0;\n\n    //     let u = f32(encodeVec2To1u(v));\n\n    //     let back = decode1uToVec2(u) / 2.0;\n\n    //     col2 = vec4<f32>(back.x, back.y, 0.29, 1.0);\n    // }\n\n    // let data2: vec4<f32> = (textureLoad(buffer_a, location)  ) ;\n    // var pb: particle = getParticle(data2, pos);\n    // let v2 = (pb.X - pos + 1.0) / 2.;\n    // let v2 = (pb.M ) / 1.;\n\n    // let debug = vec4<f32>(v2.x, 0.0, 0.0, 1.0);\n\n    // if (Mouse.z > 0.5) {\n    //     col = debug;\n    // }\n\n\n    let col_debug_info = show_debug_info(location, col.xyz);\n    \n    // textureStore(texture, y_inverted_location, toLinear(debug));\n    // textureStore(texture, y_inverted_location, toLinear(col));\n    textureStore(texture, y_inverted_location, toLinear(col_debug_info));\n} \n"
  },
  {
    "path": "assets/shaders/preludes/image_prelude",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>; // change to vec4<f32> when possible\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n{{IMAGE_CODE}}\n"
  },
  {
    "path": "assets/shaders/protean_clouds/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n}"
  },
  {
    "path": "assets/shaders/protean_clouds/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/protean_clouds/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/protean_clouds/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/protean_clouds/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\n\n\n// https://www.shadertoy.com/view/3l23Rh\n// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\n\n\nfn rot(a: f32) -> mat2x2<f32> {\n\tlet c: f32 = cos(a);\n\tlet s: f32 = sin(a);\n\treturn mat2x2<f32>(vec2<f32>(c, s), vec2<f32>(-s, c));\n} \n\nlet m3: mat3x3<f32> = mat3x3<f32>(\n    vec3<f32>(0.64342, 1.08146, -1.38607), \n    vec3<f32>(-1.696, 0.6302, -0.2957), \n    vec3<f32>(0.2926, 1.3432, 1.1838)\n);\n\nfn mag2(p: vec2<f32>) -> f32 {\n\treturn dot(p, p);\n} \n\nfn linstep(mn: f32, mx: f32, x: f32) -> f32 {\n\treturn clamp((x - mn) / (mx - mn), 0., 1.);\n} \n\nvar<private>  prm1: f32 = 0.;\nvar<private> bsMo: vec2<f32> = vec2<f32>(0., 0.);\nfn disp(t: f32) -> vec2<f32> {\n\treturn vec2<f32>(sin(t * 0.22) * 1., cos(t * 0.175) * 1.) * 2.;\n} \n\nfn map(p_in: vec3<f32>) -> vec2<f32> {\n    var p = p_in;\n\tvar p2: vec3<f32> = p;\n\tvar p2xy = p2.xy;\n\tp2xy = p2.xy - (disp(p.z).xy);\n\tp2.x = p2xy.x;\n\tp2.y = p2xy.y;\n\tvar pxy = p.xy;\n\tpxy = p.xy * (rot(sin(p.z + uni.iTime) * (0.1 + prm1 * 0.05) + uni.iTime * 0.09));\n\tp.x = pxy.x;\n\tp.y = pxy.y;\n\tlet cl: f32 = mag2(p2.xy);\n\tvar d: f32 = 0.;\n\tp = p * (0.61);\n\tvar z: f32 = 1.;\n\tvar trk: f32 = 1.;\n\tvar dspAmp: f32 = 0.1 + prm1 * 0.2;\n\n\tfor (var i: i32 = 0; i < 5; i = i + 1) {\n\t\tp = p + (sin(p.zxy * 0.75 * trk + uni.iTime * trk * 0.8) * dspAmp);\n\t\td = d - (abs(dot(cos(p), sin(p.yzx)) * z));\n\t\tz = z * (0.57);\n\t\ttrk = trk * (1.4);\n\t\tp = p * m3;\n\t}\n\n\td = abs(d + prm1 * 3.) + prm1 * 0.3 - 2.5 + bsMo.y;\n\treturn vec2<f32>(d + cl * 0.2 + 0.25, cl);\n} \n\nfn render(ro: vec3<f32>, rd: vec3<f32>, time: f32) -> vec4<f32> {\n\tvar rez: vec4<f32> = vec4<f32>(0.);\n\tlet ldst: f32 = 8.;\n\tlet lpos: vec3<f32> = vec3<f32>(disp(time + ldst) * 0.5, time + ldst);\n\tvar t: f32 = 1.5;\n\tvar fogT: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < 130; i = i + 1) {\n\t\tif (rez.a > 0.99) {\t\tbreak;\n }\n\t\tlet pos: vec3<f32> = ro + t * rd;\n\t\tlet mpv: vec2<f32> = map(pos);\n\t\tlet den: f32 = clamp(mpv.x - 0.3, 0., 1.) * 1.12;\n\t\tlet dn: f32 = clamp(mpv.x + 2., 0., 3.);\n\t\tvar col: vec4<f32> = vec4<f32>(0.);\n\t\tif (mpv.x > 0.6) {\n\t\t\tcol = vec4<f32>(sin(vec3<f32>(5., 0.4, 0.2) + mpv.y * 0.1 + sin(pos.z * 0.4) * 0.5 + 1.8) * 0.5 + 0.5, 0.08);\n\t\t\tcol = col * (den * den * den);\n\t\t\tvar colrgb = col.rgb;\n\tcolrgb = col.rgb * (linstep(4., -2.5, mpv.x) * 2.3);\n\tcol.r = colrgb.r;\n\tcol.g = colrgb.g;\n\tcol.b = colrgb.b;\n\t\t\tvar dif: f32 = clamp((den - map(pos + 0.8).x) / 9., 0.001, 1.);\n\t\t\tdif = dif + (clamp((den - map(pos + 0.35).x) / 2.5, 0.001, 1.));\n\t\t\tvar colxyz = col.xyz;\n\tcolxyz = col.xyz * (den * (vec3<f32>(0.005, 0.045, 0.075) + 1.5 * vec3<f32>(0.033, 0.07, 0.03) * dif));\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\t\t}\n\t\tlet fogC: f32 = exp(t * 0.2 - 2.2);\n\t\tvar colrgba = col.rgba;\n\tcolrgba = col.rgba + (vec4<f32>(0.06, 0.11, 0.11, 0.1) * clamp(fogC - fogT, 0., 1.));\n\tcol.r = colrgba.r;\n\tcol.g = colrgba.g;\n\tcol.b = colrgba.b;\n\tcol.a = colrgba.a;\n\t\tfogT = fogC;\n\t\trez = rez + col * (1. - rez.a);\n\t\tt = t + (clamp(0.5 - dn * dn * 0.05, 0.09, 0.3));\n\t}\n\n\treturn clamp(rez, vec4<f32>(0.), vec4<f32>(1.));\n} \n\nfn getsat(c: vec3<f32>) -> f32 {\n\tlet mi: f32 = min(min(c.x, c.y), c.z);\n\tlet ma: f32 = max(max(c.x, c.y), c.z);\n\treturn (ma - mi) / (ma + 0.0000001);\n} \n\nfn iLerp(a: vec3<f32>, b: vec3<f32>, x: f32) -> vec3<f32> {\n\tvar ic: vec3<f32> = mix(a, b, x) + vec3<f32>(0.000001, 0., 0.);\n\tlet sd: f32 = abs(getsat(ic) - mix(getsat(a), getsat(b), x));\n\tlet dir: vec3<f32> = normalize(vec3<f32>(2. * ic.x - ic.y - ic.z, 2. * ic.y - ic.x - ic.z, 2. * ic.z - ic.y - ic.x));\n\tlet lgt: f32 = dot(vec3<f32>(1.), ic);\n\tlet ff: f32 = dot(dir, normalize(ic));\n\tic = ic + (1.5 * dir * sd * ff * lgt);\n\treturn clamp(ic, vec3<f32>(0.), vec3<f32>(1.));\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet q: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\tlet p: vec2<f32> = (fragCoord - 0.5 * uni.iResolution.xy) / uni.iResolution.y;\n\tbsMo = (uni.iMouse.xy - 0.5 * uni.iResolution.xy) / uni.iResolution.y;\n\tlet time: f32 = uni.iTime * 3.;\n\tvar ro: vec3<f32> = vec3<f32>(0., 0., time);\n\tro = ro + (vec3<f32>(sin(uni.iTime) * 0.5, sin(uni.iTime * 1.) * 0., 0.));\n\tlet dspAmp: f32 = 0.85;\n\tvar roxy = ro.xy;\n\troxy = ro.xy + (disp(ro.z) * dspAmp);\n\tro.x = roxy.x;\n\tro.y = roxy.y;\n\tlet tgtDst: f32 = 3.5;\n\tlet targt: vec3<f32> = normalize(ro - vec3<f32>(disp(time + tgtDst) * dspAmp, time + tgtDst));\n\tro.x = ro.x - (bsMo.x * 2.);\n\tvar rightdir: vec3<f32> = normalize(cross(targt, vec3<f32>(0., 1., 0.)));\n\tlet updir: vec3<f32> = normalize(cross(rightdir, targt));\n\trightdir = normalize(cross(updir, targt));\n\tvar rd: vec3<f32> = normalize((p.x * rightdir + p.y * updir) * 1. - targt);\n\tvar rdxy = rd.xy;\n\trdxy = rd.xy * (rot(-disp(time + 3.5).x * 0.2 + bsMo.x));\n\trd.x = rdxy.x;\n\trd.y = rdxy.y;\n\tprm1 = smoothstep(-0.4, 0.4, sin(uni.iTime * 0.3));\n\tlet scn: vec4<f32> = render(ro, rd, time);\n\tvar col: vec3<f32> = scn.rgb;\n\tcol = iLerp(col.bgr, col.rgb, clamp(1. - prm1, 0.05, 1.));\n\tcol = pow(col, vec3<f32>(0.55, 0.65, 0.6)) * vec3<f32>(1., 0.97, 0.9);\n\tcol = col * (pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), 0.12) * 0.7 + 0.3);\n\tfragColor = vec4<f32>(col, 1.);\n    textureStore(texture, location, fragColor);\n} \n\n"
  },
  {
    "path": "assets/shaders/seascape/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/seascape/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/seascape/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/seascape/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/seascape/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\n\n\n// https://www.shadertoy.com/view/Ms2SD1\n// Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n\nlet NUM_STEPS: i32 = 8;\nlet PI: f32 = 3.141592;\nlet EPSILON: f32 = 0.001;\nlet ITER_GEOMETRY: i32 = 3;\nlet ITER_FRAGMENT: i32 = 5;\nlet SEA_HEIGHT: f32 = 0.6;\nlet SEA_CHOPPY: f32 = 4.;\nlet SEA_SPEED: f32 = 0.8;\nlet SEA_FREQ: f32 = 0.16;\nlet SEA_BASE: vec3<f32> = vec3<f32>(0., 0.09, 0.18);\nlet SEA_WATER_COLOR: vec3<f32> = vec3<f32>(0.48, 0.54, 0.36);\nlet octave_m: mat2x2<f32> = mat2x2<f32>(vec2<f32>(1.6, 1.2), vec2<f32>(-1.2, 1.6));\n\nfn fromEuler(ang: vec3<f32>) -> mat3x3<f32> {\n\tlet a1: vec2<f32> = vec2<f32>(sin(ang.x), cos(ang.x));\n\tlet a2: vec2<f32> = vec2<f32>(sin(ang.y), cos(ang.y));\n\tlet a3: vec2<f32> = vec2<f32>(sin(ang.z), cos(ang.z));\n\tvar m: mat3x3<f32>;\n    m[0] = vec3<f32>(a1.y * a3.y + a1.x * a2.x * a3.x, a1.y * a2.x * a3.x + a3.y * a1.x, -a2.y * a3.x);\n    m[1] =  vec3<f32>(-a2.y * a1.x, a1.y * a2.y, a2.x);\n    m[2] =  vec3<f32>(a3.y * a1.x * a2.x + a1.y * a3.x, a1.x * a3.x - a1.y * a3.y * a2.x, a2.y * a3.y);\n\treturn m;\n} \n\nfn hash(p: vec2<f32>) -> f32 {\n\tlet h: f32 = dot(p, vec2<f32>(127.1, 311.7));\n\treturn fract(sin(h) * 43758.547);\n} \n\nfn noise(p: vec2<f32>) -> f32 {\n\tlet i: vec2<f32> = floor(p);\n\tlet f: vec2<f32> = fract(p);\n\tlet u: vec2<f32> = f * f * (3. - 2. * f);\n\treturn -1. + 2. * mix(mix(hash(i + vec2<f32>(0., 0.)), hash(i + vec2<f32>(1., 0.)), u.x), mix(hash(i + vec2<f32>(0., 1.)), hash(i + vec2<f32>(1., 1.)), u.x), u.y);\n} \n\nfn diffuse(n: vec3<f32>, l: vec3<f32>, p: f32) -> f32 {\n\treturn pow(dot(n, l) * 0.4 + 0.6, p);\n} \n\nfn specular(n: vec3<f32>, l: vec3<f32>, e: vec3<f32>, s: f32) -> f32 {\n\tlet nrm: f32 = (s + 8.) / (PI * 8.);\n\treturn pow(max(dot(reflect(e, n), l), 0.), s) * nrm;\n} \n\nfn getSkyColor(e: vec3<f32>) -> vec3<f32> {\n\tvar e_var = e;\n\te_var.y = (max(e_var.y, 0.) * 0.8 + 0.2) * 0.8;\n\treturn vec3<f32>(pow(1. - e_var.y, 2.), 1. - e_var.y, 0.6 + (1. - e_var.y) * 0.4) * 1.1;\n} \n\nfn sea_octave(uv: vec2<f32>, choppy: f32) -> f32 {\n\tvar uv_var = uv;\n\tuv_var = uv_var + (noise(uv_var));\n\tvar wv: vec2<f32> = 1. - abs(sin(uv_var));\n\tlet swv: vec2<f32> = abs(cos(uv_var));\n\twv = mix(wv, swv, wv);\n\treturn pow(1. - pow(wv.x * wv.y, 0.65), choppy);\n} \n\nfn map(p: vec3<f32>) -> f32 {\n\tvar freq: f32 = SEA_FREQ;\n\tvar amp: f32 = SEA_HEIGHT;\n\tvar choppy: f32 = SEA_CHOPPY;\n\tvar uv: vec2<f32> = p.xz;\n\tuv.x = uv.x * (0.75);\n\tvar d: f32;\n\tvar h: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < ITER_GEOMETRY; i = i + 1) {\n\t\td = sea_octave((uv + (1. + uni.iTime * SEA_SPEED)) * freq, choppy);\n\t\td = d + (sea_octave((uv - (1. + uni.iTime * SEA_SPEED)) * freq, choppy));\n\t\th = h + (d * amp);\n\t\tuv = uv * (octave_m);\n\t\tfreq = freq * (1.9);\n\t\tamp = amp * (0.22);\n\t\tchoppy = mix(choppy, 1., 0.2);\n\t}\n\n\treturn p.y - h;\n} \n\nfn map_detailed(p: vec3<f32>) -> f32 {\n\tvar freq: f32 = SEA_FREQ;\n\tvar amp: f32 = SEA_HEIGHT;\n\tvar choppy: f32 = SEA_CHOPPY;\n\tvar uv: vec2<f32> = p.xz;\n\tuv.x = uv.x * (0.75);\n\tvar d: f32;\n\tvar h: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < ITER_FRAGMENT; i = i + 1) {\n\t\td = sea_octave((uv + (1. + uni.iTime * SEA_SPEED)) * freq, choppy);\n\t\td = d + (sea_octave((uv - (1. + uni.iTime * SEA_SPEED)) * freq, choppy));\n\t\th = h + (d * amp);\n\t\tuv = uv * (octave_m);\n\t\tfreq = freq * (1.9);\n\t\tamp = amp * (0.22);\n\t\tchoppy = mix(choppy, 1., 0.2);\n\t}\n\n\treturn p.y - h;\n} \n\nfn getSeaColor(p: vec3<f32>, n: vec3<f32>, l: vec3<f32>, eye: vec3<f32>, dist: vec3<f32>) -> vec3<f32> {\n\tvar fresnel: f32 = clamp(1. - dot(n, -eye), 0., 1.);\n\tfresnel = pow(fresnel, 3.) * 0.5;\n\tlet reflected: vec3<f32> = getSkyColor(reflect(eye, n));\n\tlet refracted: vec3<f32> = SEA_BASE + diffuse(n, l, 80.) * SEA_WATER_COLOR * 0.12;\n\tvar color: vec3<f32> = mix(refracted, reflected, fresnel);\n\tlet atten: f32 = max(1. - dot(dist, dist) * 0.001, 0.);\n\tcolor = color + (SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten);\n\tcolor = color + (vec3<f32>(specular(n, l, eye, 60.)));\n\treturn color;\n} \n\nfn getNormal(p: vec3<f32>, eps: f32) -> vec3<f32> {\n\tvar n: vec3<f32>;\n\tn.y = map_detailed(p);\n\tn.x = map_detailed(vec3<f32>(p.x + eps, p.y, p.z)) - n.y;\n\tn.z = map_detailed(vec3<f32>(p.x, p.y, p.z + eps)) - n.y;\n\tn.y = eps;\n\treturn normalize(n);\n} \n\nfn heightMapTracing(ori: vec3<f32>, dir: vec3<f32>,  p: ptr<function, vec3<f32>>) -> f32 {\n\tvar p_var: vec3<f32>;\n\tvar tm: f32 = 0.;\n\tvar tx: f32 = 1000.;\n\tvar hx: f32 = map(ori + dir * tx);\n\tif (hx > 0.) {\n\t\tp_var = ori + dir * tx;\n\t\treturn tx;\n\t}\n\tvar hm: f32 = map(ori + dir * tm);\n\tvar tmid: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < NUM_STEPS; i = i + 1) {\n\t\ttmid = mix(tm, tx, hm / (hm - hx));\n\t\tp_var = ori + dir * tmid;\n\t\tlet hmid: f32 = map(p_var);\n\t\tif (hmid < 0.) {\n\t\t\ttx = tmid;\n\t\t\thx = hmid;\n\t\t} else { \n\n\t\t\ttm = tmid;\n\t\t\thm = hmid;\n\t\t}\n\t}\n    *p = p_var;\n\n\treturn tmid;\n} \n\nfn getPixel(coord: vec2<f32>, time: f32) -> vec3<f32> {\n\tvar uv: vec2<f32> = coord / uni.iResolution.xy;\n\tuv = uv * 2. - 1.;\n\tuv.x = uv.x * (uni.iResolution.x / uni.iResolution.y);\n\tlet ang: vec3<f32> = vec3<f32>(sin(time * 3.) * 0.1, sin(time) * 0.2 + 0.3, time);\n\tlet ori: vec3<f32> = vec3<f32>(0., 3.5, time * 5.);\n\tvar dir: vec3<f32> = normalize(vec3<f32>(uv.xy, -2.));\n\tdir.z = dir.z + (length(uv) * 0.14);\n\tdir = normalize(dir) * fromEuler(ang);\n\tvar p: vec3<f32>;\n\theightMapTracing(ori, dir, &p);\n\tlet dist: vec3<f32> = p - ori;\n\tlet n: vec3<f32> = getNormal(p, dot(dist, dist) * (0.1 / uni.iResolution.x));\n\tlet light: vec3<f32> = normalize(vec3<f32>(0., 1., 0.8));\n\treturn mix(getSkyColor(dir), getSeaColor(p, n, light, dir, dist), pow(smoothstep(0., -0.02, dir.y), 0.2));\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet time: f32 = uni.iTime * 0.3 + uni.iMouse.x * 0.01;\n\n\t// var color: vec3<f32> = vec3<f32>(0.);\n\n\t// for (var i: i32 = -1; i <= 1; i = i + 1) {\n\n\t// \tfor (var j: i32 = -1; j <= 1; j = j + 1) {\n\t// \t\tlet uv2: vec2<f32> = fragCoord + vec2<f32>(f32(i), f32(j)) / 3.;\n\t// \t\tcolor = color + (getPixel(uv2, time));\n\t// \t}\n\n\t// }\n    // color = color / (9.);\n\n    var color: vec3<f32> = getPixel(fragCoord, time);\n\n\t\n\tfragColor = vec4<f32>(pow(color, vec3<f32>(0.65)), 1.);\n    // fragColor = vec4<f32>(1.);\n    // fragColor = getSkyColor(location);\n\n    // let col_debug_info = show_debug_info(location, fragColor.xyz);\n\n    textureStore(texture, y_inverted_location, toLinear(fragColor));\n} \n\n"
  },
  {
    "path": "assets/shaders/simpler_particles/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\nvar<private> s0: vec4<u32>;\n// let particle_size: f32 = 10.5;\nlet particle_size: f32 = 2.5;\nlet relax_value: f32 = 0.3;\n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n\tvar d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\t// return bound - 15.;\n\t// return min(bound, box);\n\treturn max(drain, min(bound, box));\n} \n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tvar dx: vec3<f32> = vec3<f32>(-1., 0., 1.);\n\tlet idx: vec4<f32> = vec4<f32>(-1. / 1., 0., 1. / 1., 0.25);\n\tvar r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpackHalf2x16(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = packHalf2x16(x);\n// \treturn uintBitsToFloat(X);\n// } \n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\n\nstruct particle {\n\tX: vec2<f32>,\n\tNX: vec2<f32>,\n\tR: f32,\n\tM: f32,\n};\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n\tvar P: particle;\n\tP.X = decode1uToVec2(data.x) + pos;\n\tP.NX = decode1uToVec2(data.y) + pos;\n\tP.R = data.z;\n\tP.M = data.w;\n\treturn P;\n} \n\nfn saveParticle(P_in: particle, pos: vec2<f32>) -> vec4<f32> {\n\tvar P = P_in;\n\tP.X = P.X - pos;\n\tP.NX = P.NX - pos;\n\treturn vec4<f32>(\n\t\tf32(encodeVec2To1u(P.X)), \n\t\tf32(encodeVec2To1u(P.NX)), \n\t\tP.R, \n\t\tP.M\n\t);\n} \n\n\nfn rng_initialize(p: vec2<f32>, frame: i32)  {\n\ts0 = vec4<u32>(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y));\n} \n\n// // https://www.pcg-random.org/\n// void pcg4d(inout uvec4 v)\n// {\n// \tv = v * 1664525u + 1013904223u;\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n//     v = v ^ (v>>16u);\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n// }\n\n\nfn pcg4d(v: ptr<private, vec4<u32>>)  {\n\n\t(*v) = (*v) * 1664525u + 1013904223u;\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n\n\n\tlet v2 = vec4<u32>((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u);\n\n\t(*v) = (*v) ^ v2;\n\t// (*v) = (*v) ^ ((*v) >> 16u);\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n} \n\nfn rand() -> f32 {\n\tpcg4d(&s0);\n\treturn f32(s0.x) / f32(4294967300.);\n} \n\nfn rand2() -> vec2<f32> {\n\tpcg4d(&s0);\n\treturn vec2<f32>(s0.xy) / f32(4294967300.);\n} \n\nfn rand3() -> vec3<f32> {\n\tpcg4d(&s0);\n\treturn vec3<f32>(s0.xyz) / f32(4294967300.);\n} \n\nfn rand4() -> vec4<f32> {\n\tpcg4d(&s0);\n\treturn vec4<f32>(s0) / f32(4294967300.);\n} \n\nfn Simulation(\n\tch: texture_storage_2d<rgba32float, read_write>,  \n\tP: ptr<function, particle>, \n\tpos: vec2<f32>\n)  {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar I: i32 = i32(ceil(particle_size));\n\t// var I: i32 = 4;\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\tif (i == 0 && j == 0) {\t\tcontinue;   }\n\n\n\t\tlet tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\t\tlet data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\t\tlet P0: particle = getParticle(data, tpos);\n\n\t\tif (P0.M == 0.) {\tcontinue;   }\n\n\t\tlet dx: vec2<f32> = P0.NX - (*P).NX;\n\t\tvar d: f32 = length(dx);\n\t\tvar r: f32 = (*P).R + P0.R;\n\n\t\tvar m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.;\n\t\tm = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M);\n\t\tm = P0.M / ((*P).M + P0.M);\n\n\t\tif (d < r) { F = F - (normalize(dx) * (r - d) * m); }\n\t}\n\t}\n\n\tlet dp: vec2<f32> = (*P).NX;\n\tvar d: f32 = border(dp);\n\tif (d < 0.) { F = F - (bN(dp).xy * d); }\n\t(*P).NX = (*P).NX + (F * 0.9 / 3.);\n} \n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\nfn Integrate(\n\tch: texture_storage_2d<rgba32float, read_write>, \n\tP: ptr<function, particle>, \n\tpos: vec2<f32>\n)  {\n\tvar I: i32 = 3;\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\t\tlet tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\t\tlet data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\n\t\tif (tpos.x < 0. || tpos.y < 0.) {\t\tcontinue; }\n\n\t\tvar P0: particle = getParticle(data, tpos);\n\n\t\tif (\n\t\t\t(P0.NX.x >= pos.x - 0.5 && P0.NX.x < pos.x + 0.5) \n\t\t\t&& (P0.NX.y >= pos.y - 0.5) \n\t\t\t&& (P0.NX.y < pos.y + 0.5) \n\t\t\t&& (P0.M > 0.5)\n\t\t) {\n\t\t\tvar P0V: vec2<f32> = (P0.NX - P0.X) / 2.;\n\n\t\t\tif (uni.iMouse.z > 0.) {\n\t\t\t\tlet dm: vec2<f32> = P0.NX - uni.iMouse.xy;\n\t\t\t\tlet d: f32 = length(dm / 50.);\n\t\t\t\tP0V = P0V + (normalize(dm) * exp(-d * d) * 0.3);\n\t\t\t}\n\n\t\t\tP0V = P0V + (vec2<f32>(0., -0.005));\n\t\t\tlet v: f32 = length(P0V);\n\t\t\tvar denom = 1.; \n\t\t\tif (v > 1.) { denom = v; }\n\t\t\tP0V = P0V / denom;\n\t\t\tP0.X = P0.NX;\n\t\t\tP0.NX = P0.NX + P0V * 2.;\n\t\t\t(*P) = P0;\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t}\n\n} \n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    // let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\t// var U: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\trng_initialize(pos, i32(uni.iFrame));\n\tvar P: particle;\n\n\tIntegrate(buffer_d, &P, pos);\n\n\t// if (uni.iFrame == 0) {\n\t#ifdef INIT\n\t\tif (rand() > 0.992) {\n\t\t\tP.X = pos;\n\t\t\tP.NX = pos + (rand2() - 0.5) * 0.;\n\t\t\tlet r: f32 = pow(rand(), 2.);\n\t\t\tP.M = mix(1., 4., r);\n\t\t\tP.R = mix(1., particle_size * 0.5, r);\n\t\t} else { \n\t\t\tP.X = pos;\n\t\t\tP.NX = pos;\n\t\t\tP.M = 0.;\n\t\t\tP.R = particle_size * 0.5;\n\t\t}\n\t// }\n\t#endif\n\n\tlet U = saveParticle(P, pos);\n\ttextureStore(buffer_a, location, U);\n    \n} \n\n\n"
  },
  {
    "path": "assets/shaders/simpler_particles/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\nvar<private> s0: vec4<u32>;\n// let particle_size: f32 = 10.5;\nlet particle_size: f32 = 2.5;\nlet relax_value: f32 = 0.3;\n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n\tvar d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\t// return bound - 15.;\n\t// return min(bound, box);\n\treturn max(drain, min(bound, box));\n} \n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tvar dx: vec3<f32> = vec3<f32>(-1., 0., 1.);\n\tlet idx: vec4<f32> = vec4<f32>(-1. / 1., 0., 1. / 1., 0.25);\n\tvar r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpackHalf2x16(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = packHalf2x16(x);\n// \treturn uintBitsToFloat(X);\n// } \n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\n\nstruct particle {\n\tX: vec2<f32>,\n\tNX: vec2<f32>,\n\tR: f32,\n\tM: f32,\n};\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n\tvar P: particle;\n\tP.X = decode1uToVec2(data.x) + pos;\n\tP.NX = decode1uToVec2(data.y) + pos;\n\tP.R = data.z;\n\tP.M = data.w;\n\treturn P;\n} \n\nfn saveParticle(P_in: particle, pos: vec2<f32>) -> vec4<f32> {\n\tvar P = P_in;\n\tP.X = P.X - pos;\n\tP.NX = P.NX - pos;\n\treturn vec4<f32>(\n\t\tf32(encodeVec2To1u(P.X)), \n\t\tf32(encodeVec2To1u(P.NX)), \n\t\tP.R, \n\t\tP.M\n\t);\n} \n\n\nfn rng_initialize(p: vec2<f32>, frame: i32)  {\n\ts0 = vec4<u32>(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y));\n} \n\n// // https://www.pcg-random.org/\n// void pcg4d(inout uvec4 v)\n// {\n// \tv = v * 1664525u + 1013904223u;\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n//     v = v ^ (v>>16u);\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n// }\n\n\nfn pcg4d(v: ptr<private, vec4<u32>>)  {\n\n\t(*v) = (*v) * 1664525u + 1013904223u;\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n\n\n\tlet v2 = vec4<u32>((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u);\n\n\t(*v) = (*v) ^ v2;\n\t// (*v) = (*v) ^ ((*v) >> 16u);\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n} \n\nfn rand() -> f32 {\n\tpcg4d(&s0);\n\treturn f32(s0.x) / f32(4294967300.);\n} \n\nfn rand2() -> vec2<f32> {\n\tpcg4d(&s0);\n\treturn vec2<f32>(s0.xy) / f32(4294967300.);\n} \n\nfn rand3() -> vec3<f32> {\n\tpcg4d(&s0);\n\treturn vec3<f32>(s0.xyz) / f32(4294967300.);\n} \n\nfn rand4() -> vec4<f32> {\n\tpcg4d(&s0);\n\treturn vec4<f32>(s0) / f32(4294967300.);\n} \n\nfn Simulation(\n\tch: texture_storage_2d<rgba32float, read_write>,  \n\tP: ptr<function, particle>, \n\tpos: vec2<f32>\n)  {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar I: i32 = i32(ceil(particle_size));\n\t// var I: i32 = 4;\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\tif (i == 0 && j == 0) {\t\tcontinue;   }\n\n\n\t\tlet tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\t\tlet data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\t\tlet P0: particle = getParticle(data, tpos);\n\n\t\tif (P0.M == 0.) {\tcontinue;   }\n\n\t\tlet dx: vec2<f32> = P0.NX - (*P).NX;\n\t\tvar d: f32 = length(dx);\n\t\tvar r: f32 = (*P).R + P0.R;\n\n\t\tvar m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.;\n\t\tm = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M);\n\t\tm = P0.M / ((*P).M + P0.M);\n\n\t\tif (d < r) { F = F - (normalize(dx) * (r - d) * m); }\n\t}\n\t}\n\n\tlet dp: vec2<f32> = (*P).NX;\n\tvar d: f32 = border(dp);\n\tif (d < 0.) { F = F - (bN(dp).xy * d); }\n\t(*P).NX = (*P).NX + (F * 0.9 / 3.);\n} \n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    // let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\t// var U: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet data: vec4<f32> = textureLoad(buffer_a, vec2<i32>(pos));\n\tvar P: particle = getParticle(data, pos);\n\n\tif (P.M > 0.) { Simulation(buffer_a, &P, pos); }\n\n\tlet U = saveParticle(P, pos);\n\ttextureStore(buffer_b, location, U);\n} \n\n"
  },
  {
    "path": "assets/shaders/simpler_particles/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\nvar<private> s0: vec4<u32>;\n// let particle_size: f32 = 10.5;\nlet particle_size: f32 = 2.5;\nlet relax_value: f32 = 0.3;\n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n\tvar d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\t// return bound - 15.;\n\t// return min(bound, box);\n\treturn max(drain, min(bound, box));\n} \n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tvar dx: vec3<f32> = vec3<f32>(-1., 0., 1.);\n\tlet idx: vec4<f32> = vec4<f32>(-1. / 1., 0., 1. / 1., 0.25);\n\tvar r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpackHalf2x16(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = packHalf2x16(x);\n// \treturn uintBitsToFloat(X);\n// } \n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\n\nstruct particle {\n\tX: vec2<f32>,\n\tNX: vec2<f32>,\n\tR: f32,\n\tM: f32,\n};\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n\tvar P: particle;\n\tP.X = decode1uToVec2(data.x) + pos;\n\tP.NX = decode1uToVec2(data.y) + pos;\n\tP.R = data.z;\n\tP.M = data.w;\n\treturn P;\n} \n\nfn saveParticle(P_in: particle, pos: vec2<f32>) -> vec4<f32> {\n\tvar P = P_in;\n\tP.X = P.X - pos;\n\tP.NX = P.NX - pos;\n\treturn vec4<f32>(\n\t\tf32(encodeVec2To1u(P.X)), \n\t\tf32(encodeVec2To1u(P.NX)), \n\t\tP.R, \n\t\tP.M\n\t);\n} \n\n\nfn rng_initialize(p: vec2<f32>, frame: i32)  {\n\ts0 = vec4<u32>(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y));\n} \n\n// // https://www.pcg-random.org/\n// void pcg4d(inout uvec4 v)\n// {\n// \tv = v * 1664525u + 1013904223u;\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n//     v = v ^ (v>>16u);\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n// }\n\n\nfn pcg4d(v: ptr<private, vec4<u32>>)  {\n\n\t(*v) = (*v) * 1664525u + 1013904223u;\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n\n\n\tlet v2 = vec4<u32>((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u);\n\n\t(*v) = (*v) ^ v2;\n\t// (*v) = (*v) ^ ((*v) >> 16u);\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n} \n\nfn rand() -> f32 {\n\tpcg4d(&s0);\n\treturn f32(s0.x) / f32(4294967300.);\n} \n\nfn rand2() -> vec2<f32> {\n\tpcg4d(&s0);\n\treturn vec2<f32>(s0.xy) / f32(4294967300.);\n} \n\nfn rand3() -> vec3<f32> {\n\tpcg4d(&s0);\n\treturn vec3<f32>(s0.xyz) / f32(4294967300.);\n} \n\nfn rand4() -> vec4<f32> {\n\tpcg4d(&s0);\n\treturn vec4<f32>(s0) / f32(4294967300.);\n} \n\nfn Simulation(\n\tch: texture_storage_2d<rgba32float, read_write>,  \n\tP: ptr<function, particle>, \n\tpos: vec2<f32>\n)  {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar I: i32 = i32(ceil(particle_size));\n\t// var I: i32 = 4;\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\tif (i == 0 && j == 0) {\t\tcontinue;   }\n\n\n\t\tlet tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\t\tlet data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\t\tlet P0: particle = getParticle(data, tpos);\n\n\t\tif (P0.M == 0.) {\tcontinue;   }\n\n\t\tlet dx: vec2<f32> = P0.NX - (*P).NX;\n\t\tvar d: f32 = length(dx);\n\t\tvar r: f32 = (*P).R + P0.R;\n\n\t\tvar m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.;\n\t\tm = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M);\n\t\tm = P0.M / ((*P).M + P0.M);\n\n\t\tif (d < r) { F = F - (normalize(dx) * (r - d) * m); }\n\t}\n\t}\n\n\tlet dp: vec2<f32> = (*P).NX;\n\tvar d: f32 = border(dp);\n\tif (d < 0.) { F = F - (bN(dp).xy * d); }\n\t(*P).NX = (*P).NX + (F * 0.9 / 3.);\n} \n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    // let R: vec2<f32> = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\t// var U: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet data: vec4<f32> = textureLoad(buffer_b, vec2<i32>(pos));\n\tvar P: particle = getParticle(data, pos);\n\tif (P.M > 0.) { Simulation(buffer_b, &P, pos); }\n\n\tlet U = saveParticle(P, pos);\n\ttextureStore(buffer_c, location, U);\n} \n\n"
  },
  {
    "path": "assets/shaders/simpler_particles/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\nvar<private> s0: vec4<u32>;\n// let particle_size: f32 = 10.5;\nlet particle_size: f32 = 2.5;\nlet relax_value: f32 = 0.3;\n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n\tvar d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\t// return bound - 15.;\n\t// return min(bound, box);\n\treturn max(drain, min(bound, box));\n} \n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tvar dx: vec3<f32> = vec3<f32>(-1., 0., 1.);\n\tlet idx: vec4<f32> = vec4<f32>(-1. / 1., 0., 1. / 1., 0.25);\n\tvar r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpackHalf2x16(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = packHalf2x16(x);\n// \treturn uintBitsToFloat(X);\n// } \n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\n\nstruct particle {\n\tX: vec2<f32>,\n\tNX: vec2<f32>,\n\tR: f32,\n\tM: f32,\n};\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n\tvar P: particle;\n\tP.X = decode1uToVec2(data.x) + pos;\n\tP.NX = decode1uToVec2(data.y) + pos;\n\tP.R = data.z;\n\tP.M = data.w;\n\treturn P;\n} \n\nfn saveParticle(P_in: particle, pos: vec2<f32>) -> vec4<f32> {\n\tvar P = P_in;\n\tP.X = P.X - pos;\n\tP.NX = P.NX - pos;\n\treturn vec4<f32>(\n\t\tf32(encodeVec2To1u(P.X)), \n\t\tf32(encodeVec2To1u(P.NX)), \n\t\tP.R, \n\t\tP.M\n\t);\n} \n\n\nfn rng_initialize(p: vec2<f32>, frame: i32)  {\n\ts0 = vec4<u32>(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y));\n} \n\n// // https://www.pcg-random.org/\n// void pcg4d(inout uvec4 v)\n// {\n// \tv = v * 1664525u + 1013904223u;\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n//     v = v ^ (v>>16u);\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n// }\n\n\nfn pcg4d(v: ptr<private, vec4<u32>>)  {\n\n\t(*v) = (*v) * 1664525u + 1013904223u;\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n\n\n\tlet v2 = vec4<u32>((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u);\n\n\t(*v) = (*v) ^ v2;\n\t// (*v) = (*v) ^ ((*v) >> 16u);\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n} \n\nfn rand() -> f32 {\n\tpcg4d(&s0);\n\treturn f32(s0.x) / f32(4294967300.);\n} \n\nfn rand2() -> vec2<f32> {\n\tpcg4d(&s0);\n\treturn vec2<f32>(s0.xy) / f32(4294967300.);\n} \n\nfn rand3() -> vec3<f32> {\n\tpcg4d(&s0);\n\treturn vec3<f32>(s0.xyz) / f32(4294967300.);\n} \n\nfn rand4() -> vec4<f32> {\n\tpcg4d(&s0);\n\treturn vec4<f32>(s0) / f32(4294967300.);\n} \n\nfn Simulation(\n\tch: texture_storage_2d<rgba32float, read_write>,  \n\tP: ptr<function, particle>, \n\tpos: vec2<f32>\n)  {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar I: i32 = i32(ceil(particle_size));\n\t// var I: i32 = 4;\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\tif (i == 0 && j == 0) {\t\tcontinue;   }\n\n\n\t\tlet tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\t\tlet data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\t\tlet P0: particle = getParticle(data, tpos);\n\n\t\tif (P0.M == 0.) {\tcontinue;   }\n\n\t\tlet dx: vec2<f32> = P0.NX - (*P).NX;\n\t\tvar d: f32 = length(dx);\n\t\tvar r: f32 = (*P).R + P0.R;\n\n\t\tvar m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.;\n\t\tm = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M);\n\t\tm = P0.M / ((*P).M + P0.M);\n\n\t\tif (d < r) { F = F - (normalize(dx) * (r - d) * m); }\n\t}\n\t}\n\n\tlet dp: vec2<f32> = (*P).NX;\n\tvar d: f32 = border(dp);\n\tif (d < 0.) { F = F - (bN(dp).xy * d); }\n\t(*P).NX = (*P).NX + (F * 0.9 / 3.);\n} \n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    // let R: vec2<f32> = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\t// var U: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet data: vec4<f32> = textureLoad(buffer_c, vec2<i32>(pos));\n\tvar P: particle = getParticle(data, pos);\n\n\tif (P.M > 0.) { Simulation(buffer_c, &P, pos); }\n\n\tlet U = saveParticle(P, pos);\n\ttextureStore(buffer_d, location, U);\n} \n\n\n"
  },
  {
    "path": "assets/shaders/simpler_particles/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\nvar<private> s0: vec4<u32>;\n// let particle_size: f32 = 10.5;\nlet particle_size: f32 = 2.5;\nlet relax_value: f32 = 0.3;\n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n\tvar d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\t// return bound - 15.;\n\t// return min(bound, box);\n\treturn max(drain, min(bound, box));\n} \n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tvar dx: vec3<f32> = vec3<f32>(-1., 0., 1.);\n\tlet idx: vec4<f32> = vec4<f32>(-1. / 1., 0., 1. / 1., 0.25);\n\tvar r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpackHalf2x16(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = packHalf2x16(x);\n// \treturn uintBitsToFloat(X);\n// } \n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\n\nstruct particle {\n\tX: vec2<f32>,\n\tNX: vec2<f32>,\n\tR: f32,\n\tM: f32,\n};\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n\tvar P: particle;\n\tP.X = decode1uToVec2(data.x) + pos;\n\tP.NX = decode1uToVec2(data.y) + pos;\n\tP.R = data.z;\n\tP.M = data.w;\n\treturn P;\n} \n\nfn saveParticle(P_in: particle, pos: vec2<f32>) -> vec4<f32> {\n\tvar P = P_in;\n\tP.X = P.X - pos;\n\tP.NX = P.NX - pos;\n\treturn vec4<f32>(\n\t\tf32(encodeVec2To1u(P.X)), \n\t\tf32(encodeVec2To1u(P.NX)), \n\t\tP.R, \n\t\tP.M\n\t);\n} \n\n\nfn rng_initialize(p: vec2<f32>, frame: i32)  {\n\ts0 = vec4<u32>(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y));\n} \n\n// // https://www.pcg-random.org/\n// void pcg4d(inout uvec4 v)\n// {\n// \tv = v * 1664525u + 1013904223u;\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n//     v = v ^ (v>>16u);\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n// }\n\n\nfn pcg4d(v: ptr<private, vec4<u32>>)  {\n\n\t(*v) = (*v) * 1664525u + 1013904223u;\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n\n\n\tlet v2 = vec4<u32>((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u);\n\n\t(*v) = (*v) ^ v2;\n\t// (*v) = (*v) ^ ((*v) >> 16u);\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n} \n\nfn rand() -> f32 {\n\tpcg4d(&s0);\n\treturn f32(s0.x) / f32(4294967300.);\n} \n\nfn rand2() -> vec2<f32> {\n\tpcg4d(&s0);\n\treturn vec2<f32>(s0.xy) / f32(4294967300.);\n} \n\nfn rand3() -> vec3<f32> {\n\tpcg4d(&s0);\n\treturn vec3<f32>(s0.xyz) / f32(4294967300.);\n} \n\nfn rand4() -> vec4<f32> {\n\tpcg4d(&s0);\n\treturn vec4<f32>(s0) / f32(4294967300.);\n} \n\nfn Simulation(\n\tch: texture_storage_2d<rgba32float, read_write>,  \n\tP: ptr<function, particle>, \n\tpos: vec2<f32>\n)  {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar I: i32 = i32(ceil(particle_size));\n\t// var I: i32 = 4;\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\tif (i == 0 && j == 0) {\t\tcontinue;   }\n\n\n\t\tlet tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\t\tlet data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\t\tlet P0: particle = getParticle(data, tpos);\n\n\t\tif (P0.M == 0.) {\tcontinue;   }\n\n\t\tlet dx: vec2<f32> = P0.NX - (*P).NX;\n\t\tvar d: f32 = length(dx);\n\t\tvar r: f32 = (*P).R + P0.R;\n\n\t\tvar m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.;\n\t\tm = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M);\n\t\tm = P0.M / ((*P).M + P0.M);\n\n\t\tif (d < r) { F = F - (normalize(dx) * (r - d) * m); }\n\t}\n\t}\n\n\tlet dp: vec2<f32> = (*P).NX;\n\tvar d: f32 = border(dp);\n\tif (d < 0.) { F = F - (bN(dp).xy * d); }\n\t(*P).NX = (*P).NX + (F * 0.9 / 3.);\n} \n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar col: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tvar colxyz = col.xyz;\n\tcolxyz = vec3<f32>(1.);\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\n\tvar d: f32 = 100.;\n\tvar c: vec3<f32> = vec3<f32>(1.);\n\tvar m: f32 = 1.;\n\tvar I: i32 = i32(ceil(particle_size * 0.5)) + 2;\n\t\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\tvar tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\t\tvar data: vec4<f32> = textureLoad(buffer_d, vec2<i32>(tpos));\n\t\tvar P0: particle = getParticle(data, tpos);\n\n\t\tif (P0.M == 0.) {\t\tcontinue; }\n\n\t\tvar nd: f32 = distance(pos, P0.NX) - P0.R;\n\n\t\tif (nd < d) {\n\t\t\tlet V: vec2<f32> = (P0.NX - P0.X) * 1. / 2.;\n\t\t\tc = vec3<f32>(V * 0.5 + 0.5, (P0.M - 1.) / 3.);\n\t\t\tc = mix(vec3<f32>(1.), c, length(V));\n\t\t\tm = P0.M;\n\t\t}\n\n\t\td = min(d, nd);\n\n\t\tif (d < 0.) {\t\tbreak;  }\n\t}\n\n\t}\n\n\tvar s: f32 = 100.;\n\tlet off: vec2<f32> = vec2<f32>(5., 5.);\n\tif (d > 0. && i32(pos.x) % 2 == 0 && i32(pos.y) % 2 == 0) {\n\n\t\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\t\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\t\tlet tpos: vec2<f32> = pos - off + vec2<f32>(f32(i), f32(j));\n\t\t\tlet data: vec4<f32> = textureLoad(buffer_d, vec2<i32>(tpos));\n\t\t\tlet P0: particle = getParticle(data, tpos);\n\t\t\tif (tpos.x < 0. || tpos.x > R.x || tpos.y < 0. || tpos.y > R.x) {\n\t\t\t\ts = 0.;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (P0.M == 0.) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet nd: f32 = distance(pos - off, P0.NX) - P0.R;\n\t\t\ts = min(s, nd);\n\t\t}\n\n\t\t}\n\n\t}\n\n\tif (d < 0.) { d = sin(d); }\n\n\tvar colxyz = col.xyz;\n\tcolxyz = vec3<f32>(abs(d));\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\n\tif (d < 0.) {\n\t\tvar colxyz = col.xyz;\n\t\tcolxyz = col.xyz * (c);\n\t\tcol.x = colxyz.x;\n\t\tcol.y = colxyz.y;\n\t\tcol.z = colxyz.z;\n\n\t\tvar colxyz = col.xyz;\n\t\tcolxyz = col.xyz / (0.4 + m * 0.25);\n\t\tcol.x = colxyz.x;\n\t\tcol.y = colxyz.y;\n\t\tcol.z = colxyz.z;\n\t}\n\n\tvar colxyz = col.xyz;\n\tcolxyz = clamp(col.xyz, vec3<f32>(0.), vec3<f32>(1.));\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\n\tif (d > 0.) {\n\t\t var colxyz = col.xyz;\n\t\tcolxyz = col.xyz * (mix(vec3<f32>(0.5), vec3<f32>(1.), clamp(s, 0., 1.)));\n\t\tcol.x = colxyz.x;\n\t\tcol.y = colxyz.y;\n\t\tcol.z = colxyz.z; \n\t}\n\n\tif (pos.x < 3.) || (pos.x > R.x - 3.) || (pos.y < 3.) || (pos.y > R.y - 3.) { \n\t\tvar colxyz = col.xyz;\n\t\tcolxyz = vec3<f32>(0.5);\n\t\tcol.x = colxyz.x;\n\t\tcol.y = colxyz.y;\n\t\tcol.z = colxyz.z; \n\t}\n\n\t// col = vec4<f32>(1.0, 0.0, 0.0, 1.0);\n\tcol.w = 1.0;\n\n\ttextureStore(texture, y_inverted_location, col);\n} \n\n"
  },
  {
    "path": "assets/shaders/simplest_detailed_fluid/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n\n    textureStore(buffer_a, location, color);\n}\n\n// https://www.shadertoy.com/view/7t3SDf\n\nfn t(i: vec2<i32>, location: vec2<i32>) -> vec4<f32> {\n    let O: vec4<f32> =  textureLoad(buffer_a, i + location );\n    return O;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    var location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    // location = location + vec2<i32>(10);\n    \n\n    var r: vec4<f32> = vec4<f32>(0.);\n\n\tfor (var i: vec2<i32> = vec2<i32>(-7); i.x < 7; i.x = i.x + 1  ) {\t\n\n        for (i.y = -7; i.y  < 7; i.y = i.y + 1  ) {\n            \n            let ii = i + 1;\n            let a = 0;\n\n            let v: vec2<f32> = t(ii , location + a ).xy;\n            let what = t(ii, location + a).z ;\n            let fi = vec2<f32>(ii);\n            \n            r = r + ( what \n                * exp(-dot(v+fi, v+fi)) / 3.14\n                * vec4<f32>(mix(v+v+fi , v, t(ii, location + a ).z), 1., 1.)  );\n        }\t\n    }\t\n\n    r.x = r.x / (r.z+0.000001);\n    r.y = r.y / (r.z+0.000001);\n\n\tif (i32(uni.iFrame) % 500 == 1) {\n            let u = vec2<f32>(location +0) ;\n\t\t\tlet m: vec2<f32> = 4.*u/vec2<f32>(uni.iResolution.xy) - 2.;\n\t\t\tr = r + (vec4<f32>(m, 1., 0.)*exp(-dot(m, m)));\n\t\t\n\t}\n\n    textureStore(buffer_a, location , r);\n}\n\n"
  },
  {
    "path": "assets/shaders/simplest_detailed_fluid/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_b, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_b, location, vec4<f32>(0.85));\n\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_b, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "assets/shaders/simplest_detailed_fluid/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_c, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_c, location, vec4<f32>(0.95));\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_c, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "assets/shaders/simplest_detailed_fluid/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let color = vec4<f32>(0.60);\n\n    textureStore(buffer_d, location, color);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_d, location, vec4<f32>(0.7));\n\n    if (uni.iTime > 1.0) {\n        storageBarrier();\n        textureStore(buffer_d, location, vec4<f32>(0.95));\n    }\n\n    // storageBarrier();\n}"
  },
  {
    "path": "assets/shaders/simplest_detailed_fluid/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x);\n    let alive = randomNumber > 0.9;\n    let color = vec4<f32>(f32(alive));\n\n    textureStore(texture, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\n\n    // var alive = true;\n\n\n    // let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    // if (value.x > 0.79) {\n    //     alive = false;\n    // }\n    let r = 1.- textureLoad(buffer_a, location ).zzzz;\n\n    storageBarrier();\n    textureStore(texture, location, r);\n   \n\n    // textureStore(texture, location, vec4<f32>(f32(alive)));\n}\n\n\n"
  },
  {
    "path": "assets/shaders/soul/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/soul/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/soul/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/soul/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/soul/image.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n\n\n\n\n// https://www.shadertoy.com/view/3ltyRB\n// by leon\n// License Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0)\n\nstruct Volume {\n\tdist: f32,\n\tmate: i32,\n\tdensity: f32,\n\tspace: f32,\n};\n\nfn select2(a: Volume, b: Volume) -> Volume {\n\tif (a.dist < b.dist) {\treturn a;\n }\n\treturn b;\n} \n\nlet mat_eye_globe: i32 = 1;\nlet mat_pupils: i32 = 2;\nlet mat_eyebrows: i32 = 3;\nlet mat_iris: i32 = 4;\nlet mat_glass: i32 = 5;\nfn rot(a: f32) -> mat2x2<f32> {\n\tlet c: f32 = cos(a);\n\tvar s: f32 = sin(a);\n\treturn mat2x2<f32>(c, -s, s, c);\n} \n\nfn hash12(p: vec2<f32>) -> f32 {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * 0.1031);\n\tp3 = p3 + (dot(p3, p3.yzx + 33.33));\n\treturn fract((p3.x + p3.y) * p3.z);\n} \n\nfn sdBox(p: vec3<f32>, b: vec3<f32>) -> f32 {\n\tvar q: vec3<f32> = abs(p) - b;\n\treturn length(max(q, vec3<f32>(0.))) + min(max(q.x, max(q.y, q.z)), 0.);\n} \n\nfn opSmoothUnion(d1: f32, d2: f32, k: f32) -> f32 {\n\tvar h: f32 = clamp(0.5 + 0.5 * (d2 - d1) / k, 0., 1.);\n\treturn mix(d2, d1, h) - k * h * (1. - h);\n} \n\nfn opSmoothSubtraction(d1: f32, d2: f32, k: f32) -> f32 {\n\tvar h: f32 = clamp(0.5 - 0.5 * (d2 + d1) / k, 0., 1.);\n\treturn mix(d2, -d1, h) + k * h * (1. - h);\n} \n\nfn opSmoothIntersection(d1: f32, d2: f32, k: f32) -> f32 {\n\tlet h: f32 = clamp(0.5 - 0.5 * (d2 - d1) / k, 0., 1.);\n\treturn mix(d2, d1, h) + k * h * (1. - h);\n} \n\nfn sdCappedTorus(p2: vec3<f32>, sc: vec2<f32>, ra: f32, rb: f32) -> f32 {\n    var p = p2;\n\tp.x = abs(p.x);\n\tvar k: f32 = 0.; \n    if (sc.y * p.x > sc.x * p.y) { \n        k = dot(p.xy, sc); }\n    else { \n        k = length(p.xy); \n    };\n\treturn sqrt(dot(p, p) + ra * ra - 2. * ra * k) - rb;\n} \n\nfn sdVerticalCapsule(p2: vec3<f32>, h: f32, r: f32) -> f32 {\n    var p = p2;\n\tp.y = p.y - (clamp(p.y, 0., h));\n\treturn length(p) - r;\n} \n\nfn sdCappedCone(p: vec3<f32>, a: vec3<f32>, b: vec3<f32>, ra: f32, rb: f32) -> f32 {\n\tlet rba: f32 = rb - ra;\n\tlet baba: f32 = dot(b - a, b - a);\n\tlet papa: f32 = dot(p - a, p - a);\n\tlet paba: f32 = dot(p - a, b - a) / baba;\n\tlet x: f32 = sqrt(papa - paba * paba * baba);\n    var rab: f32;\n    if (paba < 0.5) { rab = ra; } else { rab = rb; }\n\tlet cax: f32 = max(0., x - rab);\n\tvar cay: f32 = abs(paba - 0.5) - 0.5;\n\tlet k: f32 = rba * rba + baba;\n\tlet f: f32 = clamp((rba * (x - ra) + paba * baba) / k, 0., 1.);\n\tvar cbx: f32 = x - ra - f * rba;\n\tlet cby: f32 = paba - f;\n\tvar s: f32; \n    if (cbx < 0. && cay < 0.) { s = -1.; } else { s = 1.; };\n\treturn s * sqrt(min(cax * cax + cay * cay * baba, cbx * cbx + cby * cby * baba));\n} \n\nfn sdRoundedCylinder(p: vec3<f32>, ra: f32, rb: f32, h: f32) -> f32 {\n\tlet d: vec2<f32> = vec2<f32>(length(p.xz) - 2. * ra + rb, abs(p.y) - h);\n\treturn min(max(d.x, d.y), 0.) + length(max(d, vec2<f32>(0.))) - rb;\n} \n\nfn sdRoundBox(p: vec3<f32>, b: vec3<f32>, r: f32) -> f32 {\n\tlet q: vec3<f32> = abs(p) - b;\n\treturn length(max(q, vec3<f32>(0.))) + min(max(q.x, max(q.y, q.z)), 0.) - r;\n} \n\nvar<private> ao_pass: bool = false;\nfn map2(pos_in: vec3<f32>) -> Volume {\n    var pos = pos_in;\n\tvar shape: f32 = 100.;\n\tvar poszy = pos.zy;\n\tposzy = pos.zy * (rot(sin(pos.y * 0.2 + uni.iTime) * 0.1 + 0.2));\n\tpos.z = poszy.x;\n\tpos.y = poszy.y;\n\tvar posyx = pos.yx;\n\tposyx = pos.yx * (rot(0.1 * sin(pos.y * 0.3 + uni.iTime)));\n\tpos.y = posyx.x;\n\tpos.x = posyx.y;\n\tvar p: vec3<f32> = pos;\n\n\tvar ghost: Volume;\n\tghost.mate = 0;\n\tghost.density = 0.05;\n\tghost.space = 0.12;\n    \n\tvar opaque: Volume;\n\topaque.mate = 0;\n\topaque.density = 1.;\n\topaque.space = 0.;\n\n\tvar hair: Volume;\n\thair.mate = mat_eyebrows;\n\thair.density = 0.2;\n\thair.space = 0.1;\n\n\tvar glass: Volume;\n\tglass.mate = mat_glass;\n\tglass.density = 0.15;\n\tglass.space = 0.1;\n    glass.dist = 0.;\n\n\tghost.dist = length(p * vec3<f32>(1., 0.9, 1.)) - 1.;\n\tghost.dist = opSmoothUnion(ghost.dist, length(p - vec3<f32>(0., 1.2, 0.)) - 0.55, 0.35);\n\n\tp.z = p.z + (1.3);\n\tvar pyz = p.yz;\n\tpyz = p.yz * (rot(p.z * 0.5 + 0.1 * sin(uni.iTime + p.z * 4.)));\n\tp.y = pyz.x;\n\tp.z = pyz.y;\n\tshape = sdBox(p, vec3<f32>(1., 0.01, 1.));\n\tshape = max(shape, -length(pos.xz) + 0.99);\n\tghost.dist = opSmoothSubtraction(shape, ghost.dist, 0.1);\n\tp = pos - vec3<f32>(0., 1.6, 0.);\n\tshape = sdRoundedCylinder(p + sin(p.z * 4.) * 0.03, 0.4, 0.01, 0.01);\n\tshape = min(shape, sdCappedCone(p + 0.05 * sin(p.z * 8.), vec3<f32>(0., 0.5, 0.), vec3<f32>(0.), 0.3, 0.445));\n\tghost.dist = min(ghost.dist, shape);\n\tp = pos - vec3<f32>(0., 1., -0.55);\n\tlet s: f32 = sign(p.x);\n\n\tvar pxz = p.xz;\n\tpxz = p.xz * (rot(-pos.x * 1.));\n\tp.x = pxz.x;\n\tp.z = pxz.y;\n\n\tp.x = abs(p.x) - 0.15;\n\n\topaque.dist = max(length(p * vec3<f32>(1., 1., 1.3)) - 0.18, -ghost.dist);\n\topaque.mate = mat_eye_globe;\n\n\tp = p - (vec3<f32>(0.05, 0.3, -0.03));\n\tp.y = p.y - (0.01 * sin(uni.iTime * 3.));\n\n\tvar pxy = p.xy;\n\tpxy = p.xy * (rot(0.2 + sin(pos.x * 2. + uni.iTime) * 0.5));\n\tp.x = pxy.x;\n\tp.y = pxy.y;\n\n\tshape = sdBox(p, vec3<f32>(0.15, 0.02 - p.x * 0.1, 0.03));\n\thair.dist = shape;\n\tp = pos;\n\tghost.dist = opSmoothUnion(ghost.dist, length(p + vec3<f32>(0., 1.8, 0.)) - 0.5, 0.6);\n\tp.x = abs(p.x) - 0.2;\n\tp.z = p.z + (0.1 * sin(p.x * 4. + uni.iTime));\n\tghost.dist = opSmoothUnion(ghost.dist, sdVerticalCapsule(p + vec3<f32>(0., 2.8, 0.), 0.6, 0.01 + max(0., p.y + 3.) * 0.3), 0.2);\n\tp = pos;\n\tp.x = abs(p.x) - 0.4;\n\n\tvar pxy = p.xy;\n\tpxy = p.xy * (rot(3.14 / 2.));\n\tp.x = pxy.x;\n\tp.y = pxy.y;\n\n\tp.x = p.x + (pos.x * 0.2 * sin(pos.x + uni.iTime));\n\tghost.dist = opSmoothUnion(ghost.dist, sdVerticalCapsule(p + vec3<f32>(-1.5, 0., 0.), 0.6, 0.2), 0.2);\n\t\n    let vvv = select2(ghost, opaque);\n    var volume: Volume = select2(vvv, hair);\n\tif (!ao_pass) {\n\t\tp = pos - vec3<f32>(0., 1., -0.65);\n\t\tp.x = abs(p.x) - 0.18;\n\t\tglass.dist = sdRoundBox(p + vec3<f32>(-0.1, 0., 0.1), vec3<f32>(0.2 + p.y * 0.1, 0.15 + p.x * 0.05, 0.001), 0.05);\n\t\tglass.dist = max(glass.dist, -sdRoundBox(p + vec3<f32>(-0.1, 0., 0.1), vec3<f32>(0.18 + p.y * 0.1, 0.14 + p.x * 0.05, 0.1), 0.05));\n\t\tglass.dist = max(glass.dist, abs(p.z) - 0.1);\n\t\tvolume = select2(volume, glass);\n\t}\n\treturn volume;\n} \n\nfn getNormal(p: vec3<f32>) -> vec3<f32> {\n\tlet off: vec2<f32> = vec2<f32>(0.001, 0.);\n\treturn normalize(map2(p).dist - vec3<f32>(map2(p - off.xyy).dist, map2(p - off.yxy).dist, map2(p - off.yyx).dist));\n} \n\nfn getAO(pos: vec3<f32>, nor: vec3<f32>) -> f32 {\n\tvar occ: f32 = 0.;\n\tvar sca: f32 = 1.;\n\n\tfor (var i: i32 = 0; i < 5; i = i + 1) {\n\t\tlet h: f32 = 0.01 + 0.12 * f32(i) / 4.;\n\t\tvar volume: Volume = map2(pos + h * nor);\n\t\tlet d: f32 = volume.dist;\n\t\tocc = occ + ((h - d) * sca);\n\t\tsca = sca * (0.95);\n\t\tif (occ > 0.35) { break; }\n\t}\n\n\treturn clamp(1. - 3. * occ, 0., 1.) * (0.5 + 0.5 * nor.y);\n} \n\n\n// @compute @workgroup_size(8, 8, 1)\n// fn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar color: vec4<f32>;\n\tvar coordinate = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tcolor = vec4<f32>(0., 0., 0., 0.);\n\tlet uv: vec2<f32> = coordinate / uni.iResolution.xy;\n\tlet p: vec2<f32> = 2. * (coordinate - 0.5 * uni.iResolution.xy) / uni.iResolution.y;\n\tvar pos: vec3<f32> = vec3<f32>(-5., 0., -8.);\n\tvar z: vec3<f32> = normalize(vec3<f32>(0., -0.3, 0.) - pos);\n\tvar x: vec3<f32> = normalize(cross(z, vec3<f32>(0., 1., 0.)));\n\tvar y: vec3<f32> = normalize(cross(x, z));\n\tlet ray: vec3<f32> = normalize(z * 3. + x * p.x + y * p.y);\n\tvar colorrgb = color.rgb;\n\tcolorrgb = color.rgb + (vec3<f32>(0.2235, 0.3804, 0.5882) * uv.y);\n\tcolor.r = colorrgb.x;\n\tcolor.g = colorrgb.y;\n\tcolor.b = colorrgb.z;\n    color.a = 1.;\n\tvar shade: f32 = 0.;\n\tvar normal: vec3<f32> = vec3<f32>(0., 1., 0.);\n\tvar ao: f32 = 1.;\n\tlet rng: f32 = hash12(coordinate + uni.iTime);\n\tvar count: i32 = 30;\n\n\tfor (var index: i32 = 0; index < count; index += 1) {\n\t\tvar volume: Volume = map2(pos);\n\t\tif (volume.dist < 0.01) {\n        \n\t\t\tif (shade < 0.001) {\n\t\t\t\tao_pass = true;\n\t\t\t\tao = getAO(pos, normal);\n\t\t\t\tao_pass = false;\n\t\t\t}\n\t\t\tshade = shade + (volume.density);\n\t\t\tnormal = getNormal(pos);\n\t\t\tlet fresnel: f32 = pow(dot(ray, normal) * 0.5 + 0.5, 1.2);\n\t\t\tvolume.dist = volume.space * fresnel;\n\t\t\tvar col: vec3<f32> = vec3<f32>(0.);\n\t\t\tif (volume.mate == mat_eye_globe) {\n\n                let globe: f32 = dot(normal, vec3<f32>(0., 1., 0.)) * 0.5 + 0.5;\n                var look: vec3<f32> = vec3<f32>(0., 0., -1.);\n                var lookxz = look.xz;\n                lookxz = look.xz * (rot(sin(uni.iTime) * 0.2 - 0.2));\n                look.x = lookxz.x;\n                look.z = lookxz.y;\n                var lookyz = look.yz;\n                lookyz = look.yz * (rot(sin(uni.iTime * 2.) * 0.1 + 0.5));\n                look.y = lookyz.x;\n                look.z = lookyz.y;\n                let pupils: f32 = smoothstep(0.01, 0., dot(normal, look) - 0.95);\n                col = col + (vec3<f32>(1.) * globe * pupils);\n                // break;\n            }\n            else if (volume.mate == mat_eyebrows) {\n                col = col + (vec3<f32>(0.3451, 0.2314, 0.5255));\n                // break;\n            }\n            else if (volume.mate == mat_glass) {\n                col = col + (vec3<f32>(0.2));\n                // break;\n            }\n            else {\n                let leftlight: vec3<f32> = normalize(vec3<f32>(6., -5., 1.));\n                let rightlight: vec3<f32> = normalize(vec3<f32>(-3., 1., 1.));\n                let frontlight: vec3<f32> = normalize(vec3<f32>(-1., 1., -2.));\n                let blue: vec3<f32> = vec3<f32>(0., 0., 1.) * pow(dot(normal, leftlight) * 0.5 + 0.5, 0.2);\n                let green: vec3<f32> = vec3<f32>(0., 1., 0.) * pow(dot(normal, frontlight) * 0.5 + 0.5, 2.);\n                let red: vec3<f32> = vec3<f32>(0.8941, 0.2039, 0.0824) * pow(dot(normal, rightlight) * 0.5 + 0.5, 0.5);\n                col = col + (blue + green + red);\n                col = col * (ao * 0.5 + 0.3);\n                // break;\n            }\n        \n            var colorrgb = color.rgb;\n            colorrgb = color.rgb + (col * volume.density);\n            color.r = colorrgb.x;\n            color.g = colorrgb.y;\n            color.b = colorrgb.z;\n\n            // color = vec4<f32>(1.0, 0.0, 0.0, 1.0);\n            \n        }\n\t\tif (shade >= 1.) {\n\t\t\tbreak;\n\t\t}\n        \n\t\tvolume.dist = volume.dist * (0.9 + 0.1 * rng);\n\t\tpos = pos + (ray * volume.dist);\n\t}\n\n\n    // color = vec4<f32>(1.0, 0.0, 0.0, 1.0);\n    // color.a = 1.0;\n    textureStore(texture, y_inverted_location, color);\n\n} \n\n\n"
  },
  {
    "path": "assets/shaders/sunset/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "assets/shaders/sunset/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/sunset/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "assets/shaders/sunset/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "assets/shaders/sunset/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    \n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(1)]]\n// var buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(2)]]\n// var buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(3)]]\n// var buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(4)]]\n// var buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n[[group(0), binding(6)]]\nvar font_texture: texture_2d<f32>;\n\n[[group(0), binding(7)]]\nvar font_texture_sampler: sampler;\n\n[[group(0), binding(8)]]\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n[[group(0), binding(9)]]\nvar rgba_noise_256_texture_sampler: sampler;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n// Why are the characters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\nlet backColorDebug: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n\nvar<private> uv_debug: vec2<f32> ;\nvar<private> tp_debug: vec2<f32> ;\nvar<private> align_debug: vec4<f32>; // north, east, south, west\nvar<private> font_size_debug: f32;\nvar<private> dotColor_debug: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\nvar<private> drawColorDebug: vec3<f32> = vec3<f32>(1., 1., 0.);\nvar<private> vColor: vec3<f32> = backColorDebug;\nvar<private> aspect_debug: f32 = 1.;\nvar<private> pixelPosDebug: vec2<f32> = vec2<f32>(0., 0.);\n\nlet FONT_SPACE_DEBUG: f32 = 0.5;\nlet headColorDebug: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\nlet mpColorDebug: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\nlet mxColorDebug: vec3<f32> = vec3<f32>(1., 0., 0.);\nlet myColorDebug: vec3<f32> = vec3<f32>(0., 1., 0.);\nlet font_png_size_debug: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\nfn char(ch: i32) -> f32 {\n\n    let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n\tlet q = clamp(tp_debug, vec2<f32>(0.), vec2<f32>(1.)) / 16. + fr ;\n\tlet inverted_q = vec2<f32>(q.x, 1. - q.y);\n\n\t// // There is aliasing on the characters\n\t// let f = textureSampleGrad(font_texture,\n    //                  font_texture_sampler,\n    //                  inverted_q,\n    //                   vec2<f32>(1.0, 0.0),\n    //                  vec2<f32>(0.0, 1.0));\n\n\t// using textureLoad without sampler\n    let q1 = vec2<i32>(font_png_size_debug  * q );\n\tlet y_inverted_q1 = vec2<i32>(q1.x, i32(font_png_size_debug.y) - q1.y);\n\n\tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n\t// smoothing out the aliasing\n\tlet dx = vec2<i32>(1, 0);\n\tlet dy = vec2<i32>(0, 1);\n\n\tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n\tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n\tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n\tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n\tlet rp = 0.25;\n\tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n\treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n} \n\nfn SetTextPosition(x: f32, y: f32)  {\n\ttp_debug =  10. * uv_debug;\n\ttp_debug.x = tp_debug.x + 17. - x;\n\ttp_debug.y = tp_debug.y - 9.4 + y;\n} \n\nfn SetTextPositionAbs(x: f32, y: f32)  {\n\ttp_debug.x = 10. * uv_debug.x - x;\n\ttp_debug.y = 10. * uv_debug.y - y;\n} \n\nfn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\t*value = fract(*value) * 10.;\n\n\tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n\t\tc = c + (char(48 + i32(*value)));\n\t\ttp_debug.x = tp_debug.x - (0.5);\n\t\t*digits = *digits - (1);\n\t\t*value = fract(*value) * 10.;\n\n\t\tif (*digits <= 0 || *value == 0.) {\t\t\n            break;\n        }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(*digits));\n\treturn c;\n} \n\nfn maxInt(a: i32, b: i32) -> i32 {\n    var ret: i32;\n    if (a > b) { ret = a; } else { ret = b; };\n\treturn ret;\n} \n\nfn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\tc = c + (char(45));\n\t\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni >= digits) {\t\tbreak; }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\treturn c;\n} \n\nfn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tlet original_value: i32 = *value;\n\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\t// tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\t// c = c + (char(45));\n\t\t\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\t// tp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (char(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni == 0) {\t\tbreak; }\n\t}\n\n\tif (original_value < 0) {\n\t\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\tc = c + (char(45));\n\t}\n\n\t// tp_debug.x = tp_debug.x + (0.5 * f32(digits));\n\treturn c;\n} \n\n// fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\nfn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n\t// in case of 0.099999..., round up to 0.1000000\n\tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n\tlet tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits);\n\tvar c: f32 = 0.;\n\tif (value < 0.) {\n\t\tc = char(45);\n\t\tvalue = -value;\n\t}\n\ttp_debug.x = tp_debug.x - (0.5);\n    var ival = i32(value);\n\n    var one: i32 = 1;\n\n\tc = c + (drawInt(&ival, &one));\n\tc = c + (char(46));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n    var frac_val = fract(value);\n\tc = c + (drawFract(&frac_val, prec));\n\ttp_debug.x = min(tp_debug.x, tp_debugx);\n\n\treturn c;\n}\n\nfn drawFloat_f32(value:  f32) -> f32 {\n    var two: i32 = 2;\n\treturn drawFloat(value, &two, 5);\n} \n\nfn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n\treturn drawFloat(value, prec, 2);\n} \n\nfn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawIntBackwards(value, &one);\n} \n\nfn drawInt_i32(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawInt(value, &one);\n} \n\n\n\n\n\nfn SetColor(red: f32, green: f32, blue: f32)  {\n\tdrawColorDebug = vec3<f32>(red, green, blue);\n} \n\nfn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n\t// vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces));\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteFloatBox(\n\tfValue: f32, \n\tmaxDigits: i32, \n\tdecimalPlaces: i32, \n\talpha: f32\n)  {\n\tvar decs = decimalPlaces;\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha);\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteInteger(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32(iValue));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n} \n\nfn WriteIntegerBack(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue));\n\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\n} \n\n\n\nfn WriteFPS()  {\n\tvar fps: f32 = f32(uni.iSampleRate);\n\tSetColor(0.8, 0.6, 0.3);\n\tvar max_digits_one = 1;\n\tWriteFloat(fps, 5, &max_digits_one);\n\tvar c: f32 = 0.;\n\tc = c + (char(102));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(112));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (char(115));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\t// let c2 = smoothStep(0.0, 1.0, c );\n\n\tvColor = mix(vColor, drawColorDebug, c);\n} \n\nfn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n\tlet digits: i32 = 3;\n\tlet radius: f32 =  uni.iResolution.x / 400.;\n\tif (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; }\n\tlet r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius;\n\t// vColor = vColor + (mix(vec3<f32>(0.), dotColor_debug, 1. - clamp(r, 0., 1.)));\n\n\tvar max_digits_three: i32 = 3;\n\tvar mposxi: i32 = i32(mPos.x);\n\tvar mposyi: i32 = i32(mPos.y);\n\n\tvar mposx: f32 = (mPos.x);\n\tvar mposy: f32 = (mPos.y);\n\n\n\tlet x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG;\n\t\t\n\tSetTextPositionAbs(\n\t\t x_pos,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = myColorDebug;\n\tWriteIntegerBack(&mposyi);\n\n\tSetTextPositionAbs(\n\t\t x_pos - 7. *  FONT_SPACE_DEBUG,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = mxColorDebug;\n\n\tWriteIntegerBack(&mposxi);\n\n} \n\n\nfn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n  var x = r.x;\n  var y = r.y;\n  x = select(r.z, r.x, p.x > 0.);\n  y = select(r.w, r.y, p.x > 0.);\n  x  = select(y, x, p.y > 0.);\n  let q = abs(p) - b + x;\n  return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n}\n\n\n\nfn WriteRGBAValues(\n\tlocation: vec2<i32>, \n\tvalue: vec4<f32>, \n\tscreen_poz: vec2<f32>,\n\talpha: f32,\n )  {\n\tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect_debug, 1.0);\n\tlet window_ajusted = uni.iResolution / vec2<f32>(960., 600.);\n\n\tlet box_pos = vec2<f32>(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.;\n\t// let box_pos = mp;\n\n\t// // box location follows mouse position\n\t// let box_location = vec2<f32>(\n\t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t// \tuni.iMouse.y - 48. * window_ajusted.y\n\t// );\n\n\n\tlet box_location  = vec2<f32>(\n\t\t100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t\tuni.iResolution.y - 60. * window_ajusted.y,\n\t);\n\t\n\tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect_debug, 1.) ;\n\n\tlet d_box = sdRoundedBox(\n\t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n\t\t vec2<f32>(73. /  ( aspect_debug / 1.6 ), 75.) * window_ajusted, \n\t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n\t);\n\n\t// let alpha = 0.225;\n\tlet decimal_places = 3;\n\tSetColor(1., 1., 1.);\n\tvar c: f32 = 0.;\n\tlet lspace = 0.8;\n\n\tlet bg_color = vec3<f32>(.8, .7, .9);\n\tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n\t// red\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n\t) ;\n\tc = c + (char(114)); // r\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n\t// green\n\tSetTextPosition(\n\t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n\t) ;\n\tc = c + (char(103)); // g\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n\t// blue\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n\t\t) ;\n\tc = c + (char(98)); // b\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n\t// alpha\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n\t) ;\n\tc = c + (char(97)); // a\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (char(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n\tvColor = mix(vColor, drawColorDebug, c * alpha);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n\treturn mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius)));\n} \n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\nfn draw_ring(location: vec2<i32>) {\n\tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n\tlet alpha = 0.75;\n\tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n\tlet d = smoothStep(0.5, 1.5, abs(ring_dist - 1.));\n\tvColor = mix(vColor, headColorDebug,   (1. - d) * alpha );\n}\n\nfn draw_crossair(location: vec2<i32>)  {\n\n\tlet start = 5.0;\n\tlet end = 20.;\n\tlet segment1 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(start, 0.), \n\t\tvec2<f32>(end, 0.)\n\t);\n\n\tlet segment2 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(-start, 0.), \n\t\tvec2<f32>(-end, 0.)\n\t);\n\n\tlet segment3 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., start), \n\t\tvec2<f32>(0., end)\n\t);\n\n\tlet segment4 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., -start), \n\t\tvec2<f32>(0., -end)\n\t);\n\n\tvar alpha = 0.75;\n\tif (uni.iMouse.z > 0.) {\n\t\talpha = 1.0;\n\t}\n\n\tlet d = smoothStep(0.5, 1.5, segment1);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment2);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment3);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothStep(0.5, 1.5, segment4);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n}\n\nfn show_debug_info(location: vec2<i32>, color: vec3<f32>) -> vec4<f32> {    \n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    vColor = color;\n\n\n\taspect_debug =  uni.iResolution.x /  uni.iResolution.y;\n\n\tlet ratio: vec2<f32> = vec2<f32>(aspect_debug, 1.);\n\tpixelPosDebug = fragCoord.xy;\n\t// mousePosDebug = uni.iMouse.xy;\n\tuv_debug = (2. * fragCoord.xy /  uni.iResolution.xy - 1.) * ratio;\n\n\talign_debug = 10. * vec4<f32>(\n\t\t1.,      // North\n\t\taspect_debug,  // East\n\t\t-1.,     // South\n\t\t-aspect_debug, // West\n\t);\n\n\n\tWriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position\n\tWriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position\n\n\tvar c: f32 = 0.;\n\n\tSetTextPositionAbs(\n\t\t align_debug.y -      FONT_SPACE_DEBUG,\n\t\t align_debug.x - 2. * FONT_SPACE_DEBUG,\n\t);\n\n\tSetColor(0.8, 0.8, 0.8);\n\tvar resx = i32(uni.iResolution.x);\n\tvar resy = i32(uni.iResolution.y);\n\n\n\tWriteIntegerBack(&resx);\n\tc = c + (char(28));\n\ttp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG);\n\tWriteIntegerBack(&resy);\n\n\n\tSetTextPositionAbs(\n\t\t align_debug.w - 1. * FONT_SPACE_DEBUG,\n\t\t align_debug.z - 0. * FONT_SPACE_DEBUG,\n\t);\n\n\tWriteFPS();\n\tSetColor(0.9, 0.7, 0.8);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n\t// // RGBA probe labels follow mouse\n\t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n\tlet inverted_y_mouse_location = vec2<i32>(vec2<f32>(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n\tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n\tWriteRGBAValues(location, value, poz, 0.85);\n\n\tlet inverted_y_mouseclick_location = vec2<i32>(vec2<f32>(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n\tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n\tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.65);\n\n\tdraw_crossair(location);\n\n\tdraw_ring(location);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\t\n\n\treturn fragColor;\n} \n\n\n\n\nfn calculate_scattering(start: vec3<f32>, dir: vec3<f32>, max_dist: f32, scene_color: vec3<f32>, light_dir: vec3<f32>, light_intensity: vec3<f32>, planet_position: vec3<f32>, planet_radius: f32, atmo_radius: f32, beta_ray: vec3<f32>, beta_mie: vec3<f32>, beta_absorption: vec3<f32>, beta_ambient: vec3<f32>, g: f32, height_ray: f32, height_mie: f32, height_absorption: f32, absorption_falloff: f32, steps_i: i32, steps_l: i32) -> vec3<f32> {\n\tvar start_var = start;\n\tstart_var = start_var - (planet_position);\n\tvar a: f32 = dot(dir, dir);\n\tvar b: f32 = 2. * dot(dir, start_var);\n\tvar c: f32 = dot(start_var, start_var) - atmo_radius * atmo_radius;\n\tvar d: f32 = b * b - 4. * a * c;\n\tif (d < 0.) {\treturn scene_color;\n }\n\tvar ray_length: vec2<f32> = vec2<f32>(max((-b - sqrt(d)) / (2. * a), 0.), min((-b + sqrt(d)) / (2. * a), max_dist));\n\tif (ray_length.x > ray_length.y) {\treturn scene_color;\n }\n\tvar allow_mie: bool = max_dist > ray_length.y;\n\tray_length.y = min(ray_length.y, max_dist);\n\tray_length.x = max(ray_length.x, 0.);\n\tlet step_size_i: f32 = (ray_length.y - ray_length.x) / f32(steps_i);\n\tvar ray_pos_i: f32 = ray_length.x + step_size_i * 0.5;\n\tvar total_ray: vec3<f32> = vec3<f32>(0.);\n\tvar total_mie: vec3<f32> = vec3<f32>(0.);\n\tvar opt_i: vec3<f32> = vec3<f32>(0.);\n\tlet scale_height: vec2<f32> = vec2<f32>(height_ray, height_mie);\n\tvar mu: f32 = dot(dir, light_dir);\n\tvar mumu: f32 = mu * mu;\n\tvar gg: f32 = g * g;\n\tlet phase_ray: f32 = 3. / 50.265484 * (1. + mumu);\n\tvar phase_mie: f32; \n    if (allow_mie) { \n        phase_mie = 3. / 25.132742 * ((1. - gg) * (mumu + 1.)) / (pow(1. + gg - 2. * mu * g, 1.5) * (2. + gg)); \n    } else { \n        phase_mie = 0.; \n        };\n\n\tfor (var i: i32 = 0; i < steps_i; i = i + 1) {\n\t\tlet pos_i: vec3<f32> = start_var + dir * ray_pos_i;\n\t\tlet height_i: f32 = length(pos_i) - planet_radius;\n\t\tvar density: vec3<f32> = vec3<f32>(exp(-height_i / scale_height), 0.);\n\t\tvar denom: f32 = (height_absorption - height_i) / absorption_falloff;\n\t\tdensity.z = 1. / (denom * denom + 1.) * density.x;\n\t\tdensity = density * (step_size_i);\n\t\topt_i = opt_i + (density);\n\t\ta = dot(light_dir, light_dir);\n\t\tb = 2. * dot(light_dir, pos_i);\n\t\tc = dot(pos_i, pos_i) - atmo_radius * atmo_radius;\n\t\td = b * b - 4. * a * c;\n\t\tlet step_size_l: f32 = (-b + sqrt(d)) / (2. * a * f32(steps_l));\n\t\tvar ray_pos_l: f32 = step_size_l * 0.5;\n\t\tvar opt_l: vec3<f32> = vec3<f32>(0.);\n\n\t\tfor (var l: i32 = 0; l < steps_l; l = l + 1) {\n\t\t\tlet pos_l: vec3<f32> = pos_i + light_dir * ray_pos_l;\n\t\t\tlet height_l: f32 = length(pos_l) - planet_radius;\n\t\t\tvar density_l: vec3<f32> = vec3<f32>(exp(-height_l / scale_height), 0.);\n\t\t\tlet denom: f32 = (height_absorption - height_l) / absorption_falloff;\n\t\t\tdensity_l.z = 1. / (denom * denom + 1.) * density_l.x;\n\t\t\tdensity_l = density_l * (step_size_l);\n\t\t\topt_l = opt_l + (density_l);\n\t\t\tray_pos_l = ray_pos_l + (step_size_l);\n\t\t}\n\n\t\tlet attn: vec3<f32> = exp(-beta_ray * (opt_i.x + opt_l.x) - beta_mie * (opt_i.y + opt_l.y) - beta_absorption * (opt_i.z + opt_l.z));\n\t\ttotal_ray = total_ray + (density.x * attn);\n\t\ttotal_mie = total_mie + (density.y * attn);\n\t\tray_pos_i = ray_pos_i + (step_size_i);\n\t}\n\n\tlet opacity: vec3<f32> = exp(-(beta_mie * opt_i.y + beta_ray * opt_i.x + beta_absorption * opt_i.z));\n\treturn (phase_ray * beta_ray * total_ray + phase_mie * beta_mie * total_mie + opt_i.x * beta_ambient) * light_intensity + scene_color * opacity;\n} \n\nfn ray_sphere_intersect(start: vec3<f32>, dir: vec3<f32>, radius: f32) -> vec2<f32> {\n\tlet a: f32 = dot(dir, dir);\n\tlet b: f32 = 2. * dot(dir, start);\n\tlet c: f32 = dot(start, start) - radius * radius;\n\tlet d: f32 = b * b - 4. * a * c;\n\tif (d < 0.) {\treturn vec2<f32>(100000., -100000.);\n }\n\treturn vec2<f32>((-b - sqrt(d)) / (2. * a), (-b + sqrt(d)) / (2. * a));\n} \n\nfn skylight(sample_pos: vec3<f32>, surface_normal: vec3<f32>, light_dir: vec3<f32>, background_col: vec3<f32>) -> vec3<f32> {\n\tvar surface_normal_var = surface_normal;\n\tsurface_normal_var = normalize(mix(surface_normal_var, light_dir, 0.6));\n\treturn calculate_scattering(sample_pos, surface_normal_var, 3. * 6471000., background_col, light_dir, vec3<f32>(40.), vec3<f32>(0.), 6371000., 6471000., vec3<f32>(0.0000055, 0.000013, 0.0000224), vec3<f32>(0.000021), vec3<f32>(0.0000204, 0.0000497, 0.00000195), vec3<f32>(0.), 0.7, 8000., 1200., 30000., 4000., 4, 4);\n} \n\nfn render_scene(pos: vec3<f32>, dir: vec3<f32>, light_dir: vec3<f32>) -> vec4<f32> {\n\tvar color: vec4<f32> = vec4<f32>(0., 0., 0., 1000000000000.);\n\tvar colorxyz = color.xyz;\n\t// colorxyz = vec3<f32>;\n    if (dot(dir, light_dir) > 0.9998) { \n        colorxyz = vec3<f32>(3.); \n    } else { \n        colorxyz =vec3<f32>( 0.); \n        };\n\tcolor.x = colorxyz.x;\n\tcolor.y = colorxyz.y;\n\tcolor.z = colorxyz.z;\n\tlet planet_intersect: vec2<f32> = ray_sphere_intersect(pos - vec3<f32>(0.), dir, 6371000.);\n\tif (0. < planet_intersect.y) {\n\t\tcolor.w = max(planet_intersect.x, 0.);\n\t\tlet sample_pos: vec3<f32> = pos + dir * planet_intersect.x - vec3<f32>(0.);\n\t\tlet surface_normal: vec3<f32> = normalize(sample_pos);\n\t\tvar colorxyz = color.xyz;\n\tcolorxyz = vec3<f32>(0., 0.25, 0.05);\n\tcolor.x = colorxyz.x;\n\tcolor.y = colorxyz.y;\n\tcolor.z = colorxyz.z;\n\t\tlet N: vec3<f32> = surface_normal;\n\t\tlet V: vec3<f32> = -dir;\n\t\tlet L: vec3<f32> = light_dir;\n\t\tlet dotNV: f32 = max(0.000001, dot(N, V));\n\t\tlet dotNL: f32 = max(0.000001, dot(N, L));\n\t\tlet shadow: f32 = dotNL / (dotNL + dotNV);\n\t\tvar colorxyz = color.xyz;\n\tcolorxyz = color.xyz * (shadow);\n\tcolor.x = colorxyz.x;\n\tcolor.y = colorxyz.y;\n\tcolor.z = colorxyz.z;\n\t\tvar colorxyz = color.xyz;\n\tcolorxyz = color.xyz + (clamp(skylight(sample_pos, surface_normal, light_dir, vec3<f32>(0.)) * vec3<f32>(0., 0.25, 0.05), vec3<f32>(0.), vec3<f32>(1.)));\n\tcolor.x = colorxyz.x;\n\tcolor.y = colorxyz.y;\n\tcolor.z = colorxyz.z;\n\t}\n\treturn color;\n} \n\nfn get_camera_vector(resolution: vec2<f32>, coord: vec2<f32>) -> vec3<f32> {\n\tvar uv: vec2<f32> = coord.xy / resolution.xy - vec2<f32>(0.5);\n\tuv.x = uv.x * (resolution.x / resolution.y);\n\treturn normalize(vec3<f32>(uv.x, uv.y, -1.));\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    let time = uni.iTime / 3.0;\n\n\tlet camera_vector: vec3<f32> = get_camera_vector(uni.iResolution, fragCoord);\n\tlet offset: f32 = (1. - cos(time / 2.)) * 6471000.;\n\tlet camera_position: vec3<f32> = vec3<f32>(0., 6371000. + 1., offset);\n\tvar light_dir: vec3<f32>; \n    if (uni.iMouse.y == 0.) { \n        light_dir = normalize(vec3<f32>(0., cos(-time / 8.), sin(-time / 8.))); \n    } else { \n        light_dir = normalize(vec3<f32>(0., cos(uni.iMouse.y * -5. / uni.iResolution.y), sin(uni.iMouse.y * -5. / uni.iResolution.y))); \n    };\n\tlet scene: vec4<f32> = render_scene(camera_position, camera_vector, light_dir);\n\tvar col: vec3<f32> = vec3<f32>(0.);\n\tcol = col + (calculate_scattering(camera_position, camera_vector, scene.w, scene.xyz, light_dir, vec3<f32>(40.), vec3<f32>(0.), 6371000., 6471000., vec3<f32>(0.0000055, 0.000013, 0.0000224), vec3<f32>(0.000021), vec3<f32>(0.0000204, 0.0000497, 0.00000195), vec3<f32>(0.), 0.7, 8000., 1200., 30000., 4000., 12, 4));\n\tcol = 1. - exp(-col);\n\t// fragColor = vec4<f32>(col, 1.);\n\n    textureStore(texture, y_inverted_location,  toLinear(vec4<f32>((col), 1.)));\n} \n\n"
  },
  {
    "path": "bin/assets/shaders/image_load.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: i32;\n    iSampleRate: i32;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n    \n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x);\n    let alive = randomNumber > 0.9;\n    let color = vec4<f32>(f32(alive));\n\n    textureStore(texture, location, color);\n}\n\n\n// fn get(location: vec2<i32>, offset_x: i32, offset_y: i32) -> i32 {\n//     let value: vec4<f32> = textureLoad(texture, location + vec2<i32>(offset_x, offset_y));\n//     return i32(value.x);\n// }\n\n// fn count_alive(location: vec2<i32>) -> i32 {\n//     return get(location, -1, -1) +\n//            get(location, -1,  0) +\n//            get(location, -1,  1) +\n//            get(location,  0, -1) +\n//            get(location,  0,  1) +\n//            get(location,  1, -1) +\n//            get(location,  1,  0) +\n//            get(location,  1,  1);\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let n_alive = count_alive(location);\n    // let color = vec4<f32>(f32(n_alive) / 8.0);\n\n    // var alive: bool;\n    // if (n_alive == 3) {\n    //     alive = true;\n    // } else if (n_alive == 2) {\n    //     let currently_alive = get(location, 0, 0);\n    //     alive = bool(currently_alive);\n    // } else {\n    //     alive = false;\n    // }\n\n    var alive = true;\n\n    // let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    // if (value.x > 0.51) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_b, vec2<i32>(0,1));\n    // if (value.x > 0.74) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_c, vec2<i32>(0,1));\n    // if (value.x > 0.61) {\n    //     alive = false;\n    // }\n\n    let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    if (value.x > 0.79) {\n        alive = false;\n    }\n\n    // if (ga > 2) {\n    //     alive = true;\n    // }\n\n    // if (uni.iTime > 1.0) {\n    //     alive = false;\n    // }\n\n    // alive = false;\n\n    storageBarrier();\n\n    textureStore(texture, location, vec4<f32>(f32(alive)));\n}\n\n\n"
  },
  {
    "path": "bin/assets/shaders/interactive_fluid_simulation/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_a, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_a, location, vec4<f32>(0.094));\n\n    if (uni.iTime > 1.0) {\n        textureStore(buffer_a, location, vec4<f32>(0.95));\n    }\n}"
  },
  {
    "path": "bin/assets/shaders/interactive_fluid_simulation/buffer_b.wgsl",
    "content": "\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: i32;\n    iSampleRate: i32;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n    \n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_b, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_b, location, vec4<f32>(0.85));\n\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_b, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "bin/assets/shaders/interactive_fluid_simulation/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_c, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_c, location, vec4<f32>(0.95));\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_c, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "bin/assets/shaders/interactive_fluid_simulation/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let color = vec4<f32>(0.60);\n\n    textureStore(buffer_d, location, color);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_d, location, vec4<f32>(0.7));\n\n\t// let p: vec4<f32> = texture(iChannel0, fragCoord/iResolution.xy);\n\t// if (uni.iMouse.z>0.) {\n\t// \tif (p.z>0.) {\t\tfragColor = vec4<f32>(uni.iMouse.xy, p.xy);\n\t// \t} else {\t\tfragColor = vec4<f32>(uni.iMouse.xy, uni.iMouse.xy);\n\t// \t}\n\t\n\t// } else {\tfragColor = vec4<f32>(-uni.iResolution.xy, -uni.iResolution.xy);\n\t// }\n\n\n    if (uni.iTime > 1.0) {\n        storageBarrier();\n        textureStore(buffer_d, location, vec4<f32>(0.95));\n    }\n\n    // storageBarrier();\n}\n\n// fn mainImage( fragColor: vec4<f32>,  fragCoord: vec2<f32>) -> () {\n// \tlet p: vec4<f32> = texture(iChannel0, fragCoord/iResolution.xy);\n// \tif (iMouse.z>0.) {\n// \t\tif (p.z>0.) {\t\tfragColor = vec4<f32>(iMouse.xy, p.xy);\n// \t\t} else {\t\tfragColor = vec4<f32>(iMouse.xy, iMouse.xy);\n// \t\t}\n\t\n// \t} else {\tfragColor = vec4<f32>(-iResolution.xy, -iResolution.xy);\n// \t}\n\n// }"
  },
  {
    "path": "bin/assets/shaders/interactive_fluid_simulation/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x);\n    let alive = randomNumber > 0.9;\n    let color = vec4<f32>(f32(alive));\n\n    textureStore(texture, location, color);\n}\n\nfn t(v: vec2<i32>) -> vec4<f32> {\n\treturn textureLoad(buffer_a, v );\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\n    var me: vec4<f32> = t(location) ;\n    let U = location;\n\n\tme.z = me.z - (1.);\n\tvar C = 1. - 3.*me.www;\n\tlet d: vec3<f32> = vec3<f32>(t(U+vec2<i32>(1, 0)).w-t(U-vec2<i32>(1, 0)).w, t(U+vec2<i32>(0, 1)).w-t(U-vec2<i32>(0, 1)).w, 2.);\n\tC = C - (max(vec3<f32>(0.), sin(vec3<f32>(100.*length(me.xy), -5.*me.z, 368.*d.y)*me.w)));\n\n\n    storageBarrier();\n\n    textureStore(texture, location, vec4<f32>(C.x, C.y, C.z, me.w));\n}\n\n\n\n// fn mainImage( C: vec4<f32>,  U: vec2<f32>) -> () {\n// \tlet me: vec4<f32> = t(U);\n// \tme.z = me.z - (1.);\n// \tC = 1.-3.*me.wwww;\n// \tlet d: vec3<f32> = vec3<f32>(t(U+vec2<f32>(1, 0)).w-t(U-vec2<f32>(1, 0)).w, t(U+vec2<f32>(0, 1)).w-t(U-vec2<f32>(0, 1)).w, 2.);\n// \tC.xyz = C.xyz - (max(vec3<f32>(0), sin(vec3<f32>(100.*length(me.xy), -5.*me.z, 368.*d.y)*me.w)));\n\n// }\n\n"
  },
  {
    "path": "bin/assets/shaders/liquid/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\nstruct Particle {\n    position: vec2<f32>;\n    velocity: vec2<f32>;\n    mass: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\nlet fluid_rho: f32 = 0.5;\nlet dt: f32 = 1.5;\nlet border_h = 5.0;\nlet h: f32 = 1.;\n\nfn Pf(rho: vec2<f32>) -> f32\n{\n    //return 0.2*rho.x; //gas\n    let GF: f32 = 1.;//smoothstep(0.49, 0.5, 1. - rho.y);\n    return mix(0.5*rho.x, 0.04*rho.x*(rho.x/fluid_rho - 1.), GF); //water pressure\n}\n\nfn Rot(ang: f32) -> mat2x2<f32>\n{\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang)); \n}\n\nfn Dir(ang: f32) -> vec2<f32>\n{\n    return vec2<f32>(cos(ang), sin(ang));\n}\n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  let d = (abs(p) - b) ;\n  return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n}\n\nfn border(p: vec2<f32>, uni: CommonUniform) -> f32\n{\n    let R: vec2<f32> = uni.iResolution;\n    \n    let bound: f32 = -sdBox(p - R*0.5, R*vec2<f32>(0.5, 0.5)); \n    let box: f32 = sdBox(Rot(0.*uni.iTime)*(p - R*vec2<f32>(0.5, 0.6)) , R*vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R*vec2<f32>(0.5, 0.7), R*vec2<f32>(1.5, 0.5));\n    return max(drain,min(bound, box));\n}\n\n\nfn bN( p: vec2<f32>, uni: CommonUniform ) -> vec3<f32>\n{\n    let dx: vec3<f32> = vec3<f32>(-h, 0.0 , h);\n\n    let idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n    let r: vec3<f32> = idx.zyw*border(p + dx.zy, uni)\n           + idx.xyw*border(p + dx.xy, uni)\n           + idx.yzw*border(p + dx.yz, uni)\n           + idx.yxw*border(p + dx.yx, uni);\n\n    return vec3<f32>(normalize(r.xy), r.z + 1e-4);\n\n}\n\n\nfn pack(x: vec2<f32>) -> u32 \n{\n    var q: vec2<f32>;\n    q.x = 65534.0*clamp(0.5*x.x+0.5, 0., 1.);\n    q.y = 65534.0*clamp(0.5*x.y+0.5, 0., 1.);\n    return u32(round(q.x)) + 65535u*u32(round(q.y));\n}\n\nfn unpack(a: u32) -> vec2<f32>\n{\n    let q = vec2<u32>(a % 65535u, a / 65535u);\n    let p = vec2<f32>(\n        clamp(f32(q.x) / 65534.0, 0.,1.)*2.0 - 1.0,\n        clamp(f32(q.y) / 65534.0, 0.,1.)*2.0 - 1.0\n    );\n    return p;\n}\n\nfn decode(x: f32) -> vec2<f32>\n{\n    let X: u32 = bitcast<u32>(x);\n    return unpack(X); \n}\n\nfn encode(x: vec2<f32>) -> f32\n{\n    let X: u32 = pack(x);\n    let casted: f32 = bitcast<f32>(X);\n    return casted;\n}\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> Particle\n{\n    var P: Particle;\n    P.position = decode(data.x) + pos;\n    P.velocity = decode(data.y);\n    P.mass = data.zw;\n    return P;\n}\n\n\nfn saveParticle(in_p: Particle, pos: vec2<f32>) -> vec4<f32>\n{\n    var P: Particle = in_p;\n    // P.position = clamp(P.position - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    P.position.x = clamp(P.position.x - pos.x, -0.5, 0.5);\n    P.position.y = clamp(P.position.y - pos.y, -0.5, 0.5);\n    return vec4<f32>(encode(P.position), encode(P.velocity), P.mass.x, P.mass.y);\n}\n\nfn hash32(p: vec2<f32>) -> vec3<f32>\n{\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n    p3 = p3 + dot(p3, p3.yxz+33.33);\n    return fract((p3.xxy+p3.yzz)*p3.zyx);\n}\n\nfn G(x: vec2<f32>) -> f32\n{\n    return exp(-dot(x,x));\n}\n\nfn G0(x: vec2<f32>) -> f32\n{\n    return exp(-length(x));\n}\n\nfn distribution(x: vec2<f32>,  p: vec2<f32>, K: f32) -> vec3<f32>\n{\n    let omin: vec2<f32> = clamp(x - K*0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K*0.5, p - 0.5, p + 0.5); \n    return vec3<f32>(0.5*(omin + omax), (omax.x - omin.x)*(omax.y - omin.y)/(K*K));\n}\n\n\n//diffusion and advection basically\nfn Reintegration(buffer: texture_storage_2d<rgba8unorm, read_write>, P: Particle, pos: vec2<f32>) -> Particle\n{\n    var particle: Particle = P;\n\n\n    \n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    var i: i32 = -2;\n    loop  {\n        if (i > 2) { break; }\n\n        var j: i32 = -2;\n        loop {\n            if (j > 2) { break; }\n\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i),f32(j));\n\n            let data: vec4<f32> = textureLoad(buffer, vec2<i32>(tpos));\n        \n            var P0: Particle = getParticle(data, tpos);\n        \n            P0.position = P0.position + P0.velocity*dt; //integrate position\n\n            let difR: f32 = 0.9 + 0.21*smoothStep(fluid_rho*0., fluid_rho*0.333, P0.mass.x);\n            let D: vec3<f32> = distribution(P0.position, pos, difR);\n            //the deposited mass into this cell\n            let m: f32 = P0.mass.x*D.z;\n            \n            //add weighted by mass\n            particle.position = particle.position + D.xy*m;\n            particle.velocity =  particle.velocity + P0.velocity*m;\n            particle.mass.y = particle.mass.y  +  P0.mass.y*m;\n            \n            //add mass\n            particle.mass.x = particle.mass.x + m;\n\n        }\n    }\n    // range(i, -2, 2) range(j, -2, 2)\n\n    //normalization\n    if(particle.mass.x != 0.)\n    {\n        particle.position = particle.position / particle.mass.x;\n        particle.velocity= particle.velocity / particle.mass.x;\n        particle.mass.y = particle.mass.y / particle.mass.x;\n    }\n\n    return particle;\n}\n\n//force calculation and integration\nfn Simulation(\n    buffer: texture_storage_2d<rgba8unorm, read_write>,   \n    P: Particle,  \n    pos: vec2<f32>, \n    Mouse: vec4<f32>,\n    uni: CommonUniform\n    ) -> Particle\n{\n    var particle: Particle = P;\n    \n    \n    //Compute the SPH force\n    var F: vec2<f32> = vec2<f32>(0.);\n    var  avgV: vec3<f32> = vec3<f32>(0.);\n\n    var i: i32 = -2;\n    loop  {\n        if (i > 2) { break; }\n\n        var j: i32 = -2;\n        loop {\n            if (j > 2) { break; }\n\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n            // let  data: vec4<f32> = texel(ch, tpos);\n            let data: vec4<f32> = textureLoad(buffer, vec2<i32>(tpos));\n\n            let  P0: Particle = getParticle(data, tpos);\n            let  dx: vec2<f32> = P0.position - particle.position;\n            let  avgP: f32 = 0.5*P0.mass.x*(Pf(particle.mass) + Pf(P0.mass)); \n            F = F - 0.5*G(1.*dx)*avgP*dx;\n            avgV = avgV + P0.mass.x*G(1.*dx)*vec3<f32>(P0.velocity,1.);\n        }\n    }\n\n    avgV.x = avgV.x / avgV.z;\n    avgV.y = avgV.y / avgV.z;\n\n    //viscosity\n    F = F + 0.*particle.mass.x*(avgV.xy - particle.velocity);\n    \n    //gravity\n    F = F + particle.mass.x*vec2<f32>(0., -0.0004);\n\n    if(Mouse.z > 0.)\n    {\n        let dm: vec2<f32> =(Mouse.xy - Mouse.zw)/10.; \n        let d: f32 = distance(Mouse.xy, particle.position)/20.;\n        F = F + 0.001*dm*exp(-d*d);\n       // particle.mass.y += 0.1*exp(-40.*d*d);\n    }\n    \n    //integrate\n    particle.velocity = particle.velocity + F*dt/particle.mass.x;\n\n    //border \n    let N: vec3<f32> = bN(particle.position, uni);\n    let vdotN : f32 = step(N.z, border_h) * dot(-N.xy, particle.velocity);\n    particle.velocity = particle.velocity + 0.5*(N.xy*vdotN + N.xy*abs(vdotN));\n    particle.velocity = particle.velocity + 0.*particle.mass.x*N.xy*step(abs(N.z), border_h)*exp(-N.z);\n    \n    if (N.z < 0.) { particle.velocity = vec2<f32>(0.); }\n    \n    \n    //velocity limit\n    let v: f32 = length(particle.velocity);\n    if (v > 1.0) { \n        particle.velocity = particle.velocity / v; \n    } \n\n    // particle.velocity = particle.velocity / (v > 1.) ? v : 1.;\n\n    return particle;\n}\n\n\n// // /*\n// // vec3 distribution(vec2 x, vec2 p, float K)\n// // {\n// //     vec4 aabb0 = vec4(p - 0.5, p + 0.5);\n// //     vec4 aabb1 = vec4(x - K*0.5, x + K*0.5);\n// //     vec4 aabbX = vec4(max(aabb0.xy, aabb1.xy), min(aabb0.zw, aabb1.zw));\n// //     vec2 center = 0.5*(aabbX.xy + aabbX.zw); //center of mass\n// //     vec2 size = max(aabbX.zw - aabbX.xy, 0.); //only positive\n// //     float m = size.x*size.y/(K*K); //relative amount\n// //     //if any of the dimensions are 0 then the mass is 0\n// //     return vec3(center, m);\n// // }*/\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_a, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_a, location, vec4<f32>(0.094));\n\n    if (uni.iTime > 1.0) {\n        textureStore(buffer_a, location, vec4<f32>(0.95));\n    }\n}\n\n"
  },
  {
    "path": "bin/assets/shaders/liquid/buffer_b.wgsl",
    "content": "\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: i32;\n    iSampleRate: i32;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n    \n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_b, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_b, location, vec4<f32>(0.85));\n\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_b, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "bin/assets/shaders/liquid/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_c, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_c, location, vec4<f32>(0.95));\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_c, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "bin/assets/shaders/liquid/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let color = vec4<f32>(0.60);\n\n    textureStore(buffer_d, location, color);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_d, location, vec4<f32>(0.7));\n\n    if (uni.iTime > 1.0) {\n        storageBarrier();\n        textureStore(buffer_d, location, vec4<f32>(0.95));\n    }\n\n    // storageBarrier();\n}"
  },
  {
    "path": "bin/assets/shaders/liquid/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x);\n    let alive = randomNumber > 0.9;\n    let color = vec4<f32>(f32(alive));\n\n    textureStore(texture, location, color);\n}\n\n\n// fn get(location: vec2<i32>, offset_x: i32, offset_y: i32) -> i32 {\n//     let value: vec4<f32> = textureLoad(texture, location + vec2<i32>(offset_x, offset_y));\n//     return i32(value.x);\n// }\n\n// fn count_alive(location: vec2<i32>) -> i32 {\n//     return get(location, -1, -1) +\n//            get(location, -1,  0) +\n//            get(location, -1,  1) +\n//            get(location,  0, -1) +\n//            get(location,  0,  1) +\n//            get(location,  1, -1) +\n//            get(location,  1,  0) +\n//            get(location,  1,  1);\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let n_alive = count_alive(location);\n    // let color = vec4<f32>(f32(n_alive) / 8.0);\n\n    // var alive: bool;\n    // if (n_alive == 3) {\n    //     alive = true;\n    // } else if (n_alive == 2) {\n    //     let currently_alive = get(location, 0, 0);\n    //     alive = bool(currently_alive);\n    // } else {\n    //     alive = false;\n    // }\n\n    var alive = true;\n\n    // let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    // if (value.x > 0.51) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_b, vec2<i32>(0,1));\n    // if (value.x > 0.74) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_c, vec2<i32>(0,1));\n    // if (value.x > 0.61) {\n    //     alive = false;\n    // }\n\n    let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    if (value.x > 0.79) {\n        alive = false;\n    }\n\n    // if (ga > 2) {\n    //     alive = true;\n    // }\n\n    // if (uni.iTime > 1.0) {\n    //     alive = false;\n    // }\n\n    // alive = false;\n\n    storageBarrier();\n\n    textureStore(texture, location, vec4<f32>(f32(alive)));\n}\n\n\n"
  },
  {
    "path": "bin/assets/shaders/minimal/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "bin/assets/shaders/minimal/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/assets/shaders/minimal/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_c, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_c, location, vec4<f32>(0.95));\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_c, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "bin/assets/shaders/minimal/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let color = vec4<f32>(0.60);\n\n    textureStore(buffer_d, location, color);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_d, location, vec4<f32>(0.7));\n\n    if (uni.iTime > 1.0) {\n        storageBarrier();\n        textureStore(buffer_d, location, vec4<f32>(0.95));\n    }\n\n    // storageBarrier();\n}"
  },
  {
    "path": "bin/assets/shaders/minimal/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "bin/assets/shaders/mixing_liquid/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy) \n                     + idx.xyw * border(p + dx.xy) \n                     + idx.yzw * border(p + dx.yz) \n                     + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x.x)) + 65535u * u32(round(x.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba8unorm, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n\t\n        }\t\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n\t\tP1.X = P1.X / (P1.M.x);\n\t\tP1.V = P1.V / (P1.M.x);\n\t\tP1.M.y = P1.M.y / (P1.M.x);\n\t}\n\n    return P1;\n} \n\nfn Simulation(ch: texture_storage_2d<rgba8unorm, read_write>, P: particle, pos: vec2<f32>) -> particle {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar avgV: vec3<f32> = vec3<f32>(0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n\t\n        }\t\n    }\t\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n\tF = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n\tF = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n\tif (Mouse.z > 0.) {\n\t\tlet dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n\t\tlet d: f32 = distance(Mouse.xy, P.X) / 20.;\n\t\tF = F + (0.001 * dm * exp(-d * d));\n\t\n\t}\n\n    var P1: particle = P;\n\n    //integrate\n\tP1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n\tlet N: vec3<f32> = bN(P1.X);\n\tlet vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n\tP1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n\tP1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\t\n    if (N.z < 0.) {\t\n        P1.V = vec2<f32>(0.);\n\t}\n\n    //velocity limit\n\tlet v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v; \n    } else {\n        vv = 1.;\n    };\n\tP1.V = P1.V / vv;\n\n    return P1;\n\n} \n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let color = vec4<f32>(0.5);\n//     textureStore(buffer_a, location, color);\n// }\n\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>) -> () {\n    let pos: vec2<f32> = vec2<f32>(location);\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet p: vec2<i32> = location;\n\n\t// let data: vec4<f32> = texel(ch0, pos);\n\n    // buffer_b is set as the channel 0 in Buffer A of the paint\n    // streams inside shadertoy \n    let data: vec4<f32> =  textureLoad(buffer_b, location);\n\n\tvar P: particle = Reintegration(buffer_b, pos);\n\n\tif (uni.iFrame < 4.0) {\n\t\tlet rand: vec3<f32> = hash32(pos);\n\t\tif (rand.z < 0.) {\n\t\t\tP.X = pos;\n\t\t\tP.V = 0.5 * (rand.xy - 0.5) + vec2<f32>(0., 0.);\n\t\t\tP.M = vec2<f32>(mass, 0.);\n\t\t\n\t\t} else {\n\t\t\tP.X = pos;\n\t\t\tP.V = vec2<f32>(0.);\n\t\t\tP.M = vec2<f32>(0.000001);\n\t\t\n\t\t}\n\t}\n\n    textureStore(buffer_a, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "bin/assets/shaders/mixing_liquid/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy) \n                     + idx.xyw * border(p + dx.xy) \n                     + idx.yzw * border(p + dx.yz) \n                     + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x.x)) + 65535u * u32(round(x.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba8unorm, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n\t\n        }\t\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n\t\tP1.X = P1.X / (P1.M.x);\n\t\tP1.V = P1.V / (P1.M.x);\n\t\tP1.M.y = P1.M.y / (P1.M.x);\n\t}\n\n    return P1;\n} \n\nfn Simulation(ch: texture_storage_2d<rgba8unorm, read_write>, P: particle, pos: vec2<f32>) -> particle {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar avgV: vec3<f32> = vec3<f32>(0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n\t\n        }\t\n    }\t\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n\tF = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n\tF = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n\tif (Mouse.z > 0.) {\n\t\tlet dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n\t\tlet d: f32 = distance(Mouse.xy, P.X) / 20.;\n\t\tF = F + (0.001 * dm * exp(-d * d));\n\t\n\t}\n\n    var P1: particle = P;\n\n    //integrate\n\tP1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n\tlet N: vec3<f32> = bN(P1.X);\n\tlet vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n\tP1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n\tP1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\t\n    if (N.z < 0.) {\t\n        P1.V = vec2<f32>(0.);\n\t}\n\n    //velocity limit\n\tlet v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v; \n    } else {\n        vv = 1.;\n    };\n\tP1.V = P1.V / vv;\n\n    return P1;\n\n} \n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// }\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>) -> () {\n\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let pos: vec2<f32> = vec2<f32>(location);\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet p: vec2<i32> = location;\n\n\n\t// let data: vec4<f32> = texel(buffer_a, pos);\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\tif (P.M.x != 0.) {\n\t\tP = Simulation(buffer_a, P, pos);\n\t}\n\n\tif (length(P.X - R * vec2<f32>(0.8, 0.9)) < 10.) {\n\t\tP.X = pos;\n\t\tP.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time));\n\t\tP.M = mix(P.M, vec2<f32>(fluid_rho, 1.), 0.4);\n\t}\n    \n\tif (length(P.X - R * vec2<f32>(0.2, 0.9)) < 10.) {\n\t\tP.X = pos;\n\t\tP.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time));\n\t\tP.M = mix(P.M, vec2<f32>(fluid_rho, 0.), 0.4);\n\t}\n\n\t// U = saveParticle(P, pos);\n    textureStore(buffer_b, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "bin/assets/shaders/mixing_liquid/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy) \n                     + idx.xyw * border(p + dx.xy) \n                     + idx.yzw * border(p + dx.yz) \n                     + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x.x)) + 65535u * u32(round(x.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba8unorm, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n\t\n        }\t\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n\t\tP1.X = P1.X / (P1.M.x);\n\t\tP1.V = P1.V / (P1.M.x);\n\t\tP1.M.y = P1.M.y / (P1.M.x);\n\t}\n\n    return P1;\n} \n\nfn Simulation(ch: texture_storage_2d<rgba8unorm, read_write>, P: particle, pos: vec2<f32>) -> particle {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar avgV: vec3<f32> = vec3<f32>(0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n\t\n        }\t\n    }\t\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n\tF = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n\tF = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n\tif (Mouse.z > 0.) {\n\t\tlet dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n\t\tlet d: f32 = distance(Mouse.xy, P.X) / 20.;\n\t\tF = F + (0.001 * dm * exp(-d * d));\n\t\n\t}\n\n    var P1: particle = P;\n\n    //integrate\n\tP1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n\tlet N: vec3<f32> = bN(P1.X);\n\tlet vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n\tP1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n\tP1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\t\n    if (N.z < 0.) {\t\n        P1.V = vec2<f32>(0.);\n\t}\n\n    //velocity limit\n\tlet v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v; \n    } else {\n        vv = 1.;\n    };\n\tP1.V = P1.V / vv;\n\n    return P1;\n\n} \n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// fn mainImage( fragColor: vec4<f32>,  pos: vec2<f32>) -> () {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n    let pos = vec2<f32>(location);\n\tlet p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\t// let data: vec4<f32> = texel(ch0, pos);\n\t// let P: particle = getParticle(data, pos);\n\n\tvar rho: vec4<f32> = vec4<f32>(0.);\n\tfor (var i: i32 = -1; i <= 1; i = i + 1) {\n\t\tfor (var j: i32 = -1; j <= 1; j = j + 1) {\n\t\t\tlet ij: vec2<i32> = vec2<i32>(i, j);\n\n\t\t\t// let data: vec4<f32> = texel(ch0, pos + ij);\n             let data: vec4<f32> =  textureLoad(buffer_a, location + ij);\n\n\t\t\tvar P0: particle = getParticle(data, pos + vec2<f32>(ij));\n\t\t\tlet x0: vec2<f32> = P0.X;\n\t\t\trho = rho + (1. * vec4<f32>(P.V, P.M) * G((pos - x0) / 0.75));\n\t\t\n\t\t}\t\n\t}\t\n\n    textureStore(buffer_c, location, rho);\n\n} \n\n"
  },
  {
    "path": "bin/assets/shaders/mixing_liquid/buffer_d.wgsl",
    "content": "\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy) \n                     + idx.xyw * border(p + dx.xy) \n                     + idx.yzw * border(p + dx.yz) \n                     + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x.x)) + 65535u * u32(round(x.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba8unorm, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n\t\n        }\t\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n\t\tP1.X = P1.X / (P1.M.x);\n\t\tP1.V = P1.V / (P1.M.x);\n\t\tP1.M.y = P1.M.y / (P1.M.x);\n\t}\n\n    return P1;\n} \n\nfn Simulation(ch: texture_storage_2d<rgba8unorm, read_write>, P: particle, pos: vec2<f32>) -> particle {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar avgV: vec3<f32> = vec3<f32>(0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n\t\n        }\t\n    }\t\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n\tF = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n\tF = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n\tif (Mouse.z > 0.) {\n\t\tlet dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n\t\tlet d: f32 = distance(Mouse.xy, P.X) / 20.;\n\t\tF = F + (0.001 * dm * exp(-d * d));\n\t\n\t}\n\n    var P1: particle = P;\n\n    //integrate\n\tP1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n\tlet N: vec3<f32> = bN(P1.X);\n\tlet vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n\tP1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n\tP1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\t\n    if (N.z < 0.) {\t\n        P1.V = vec2<f32>(0.);\n\t}\n\n    //velocity limit\n\tlet v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v; \n    } else {\n        vv = 1.;\n    };\n\tP1.V = P1.V / vv;\n\n    return P1;\n\n} \n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "bin/assets/shaders/mixing_liquid/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy) \n                     + idx.xyw * border(p + dx.xy) \n                     + idx.yzw * border(p + dx.yz) \n                     + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x.x)) + 65535u * u32(round(x.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba8unorm, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n\t\n        }\t\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n\t\tP1.X = P1.X / (P1.M.x);\n\t\tP1.V = P1.V / (P1.M.x);\n\t\tP1.M.y = P1.M.y / (P1.M.x);\n\t}\n\n    return P1;\n} \n\nfn Simulation(ch: texture_storage_2d<rgba8unorm, read_write>, P: particle, pos: vec2<f32>) -> particle {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar avgV: vec3<f32> = vec3<f32>(0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n\t\n        }\t\n    }\t\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n\tF = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n\tF = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n\tif (Mouse.z > 0.) {\n\t\tlet dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n\t\tlet d: f32 = distance(Mouse.xy, P.X) / 20.;\n\t\tF = F + (0.001 * dm * exp(-d * d));\n\t\n\t}\n\n    var P1: particle = P;\n\n    //integrate\n\tP1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n\tlet N: vec3<f32> = bN(P1.X);\n\tlet vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n\tP1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n\tP1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\t\n    if (N.z < 0.) {\t\n        P1.V = vec2<f32>(0.);\n\t}\n\n    //velocity limit\n\tlet v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v; \n    } else {\n        vv = 1.;\n    };\n\tP1.V = P1.V / vv;\n\n    return P1;\n\n} \n\n\n\n\n// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n// fn even(uv: f32) -> f32 {\n//     var tempo: f32 = 0.0;\n//     let whatever = modf(uv + 1.0, &tempo);\n//     var temp2 = 0.;\n//     let frac = modf(tempo / 2.0, &temp2);\n\n//     if (abs(frac) < 0.001) {\n//         return 1.0;\n//     } else {\n//         return 0.0;\n//     }\n// }\n\n\nfn hsv2rgb( c: vec3<f32>) -> vec3<f32> {\n    // var fractional: f32 = 0.0;\n    // let m = modf(c.x * 6. + vec3<f32>(0., 4., 2.) / 6., &fractional);\n\n    let v = vec3<f32>(0., 4., 2.);\n    let fractional: vec3<f32> = vec3<f32>(vec3<i32>( (c.x * 6. +  v) / 6.0)) ;\n        \n    // let whatever = modf(uv + 1.0, &tempo);\n    // var temp2 = 0.;\n    // let frac = modf(tempo / 2.0, &temp2);\n    let af: vec3<f32>  = abs(fractional - 3.) - 1.;\n\n\tvar rgb: vec3<f32> = clamp(af, vec3<f32>(0.), vec3<f32>(1.));\n\n\trgb = rgb * rgb * (3. - 2. * rgb);\n\treturn c.z * mix(vec3<f32>(1.), rgb, c.y);\n\n} \n\nfn mixN(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {\n\treturn sqrt(mix(a * a, b * b, clamp(k, 0., 1.)));\n\n} \n\nfn V(p: vec2<f32>) -> vec4<f32> {\n\t// return pixel(ch1, p);\n    return textureLoad(buffer_c, vec2<i32>(p ));\n\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n// fn mainImage( col: vec4<f32>,  pos: vec2<f32>) -> () {\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\n\t// let p: vec2<i32> = vec2<i32>(pos);\n\t// let data: vec4<f32> = texel(ch0, pos);\n\n    let p: vec2<i32> = location;\n\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n    let pos = vec2<f32>(location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\tlet Nb: vec3<f32> = bN(P.X);\n\tlet bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos));\n\tlet rho: vec4<f32> = V(pos);\n\tlet dx: vec3<f32> = vec3<f32>(-2., 0., 2.);\n\n\tlet grad: vec4<f32> = -0.5 * vec4<f32>( V(pos + dx.zy).zw - V(pos + dx.xy).zw, \n                                            V(pos + dx.yz).zw - V(pos + dx.yx).zw);\n\tlet N: vec2<f32> = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001);\n\n\tlet specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5);\n\tlet specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.);\n\n\n\tlet a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1);\n\tlet b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z));\n\tlet col0: vec3<f32> = vec3<f32>(1., 0.5, 0.);\n\tlet col1: vec3<f32> = vec3<f32>(0.1, 0.4, 1.);\n\n\n\tlet fcol: vec3<f32> = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5);\n    // var col: vec4<f32>;\n\n\tvar col: vec3<f32> = vec3<f32>(3.);\n\tcol = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a);\n\n\n\tcol = mixN(col, 0. * vec3<f32>(0.5, 0.5, 1.), bord);\n\tcol = tanh(col);\n    let col4 = vec4<f32>(col, 0.3);\n\n    textureStore(texture, location, rho);\n\n\n} \n"
  },
  {
    "path": "bin/assets/shaders/paint/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\ntype float2 = vec2<f32>;\ntype float4 = vec4<f32>;\n\nfn hue(v: f32) -> vec4<f32> { \n    return (vec4<f32>(.6) + vec4<f32>(.6) * cos( vec4<f32>(6.3 * v) + vec4<f32>(0.0,23.0,21.0,0.0 ) ));\n}\n\nfn smoothit(v: f32) -> f32{ \n    return smoothStep( 1.5, 0., v );\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n  let pa = p - a;\n  let ba = b - a;\n  let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n  return length(pa - ba * h);\n}\n\nfn sdRhombus(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  let q = abs(p);\n  let qb = dot(q, vec2<f32>(b.x, -b.y));\n  let bb = dot(b, vec2<f32>(b.x, -b.y));\n  let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.);\n  let d = length(q - 0.5 * b * vec2<f32>(1. - h, 1. + h));\n  return d * sign(q.x * b.y + q.y * b.x - b.x * b.y);\n}\n\nfn sdTriangleIsosceles(p: vec2<f32>, c: vec2<f32>) -> f32 {\n  let q = vec2<f32>(abs(p.x), p.y);\n  let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.);\n  let b = q - c * vec2<f32>(clamp(q.x / c.x, 0., 1.), 1.);\n  let s = -sign(c.y);\n  let d = min(vec2<f32>(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2<f32>(dot(b, b), s * (q.y - c.y)));\n  return -sqrt(d.x) * sign(d.y);\n}\n\nfn sdStar(p: vec2<f32>, r: f32, n: u32, m: f32) ->f32 {\n  let an = 3.141593 / f32(n);\n  let en = 3.141593 / m;\n  let acs = vec2<f32>(cos(an), sin(an));\n  let ecs = vec2<f32>(cos(en), sin(en));\n  let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an;\n  var q: vec2<f32> = length(p) * vec2<f32>(cos(bn), abs(sin(bn)));\n  q = q - r * acs;\n  q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y);\n  return length(q) * sign(q.x);\n}\n\nfn sdHeart(p: vec2<f32>) -> f32 {\n  let q = vec2<f32>(abs(p.x), p.y);\n  let w = q - vec2<f32>(0.25, 0.75);\n  if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; }\n  let u = q - vec2<f32>(0., 1.0);\n  let v = q - 0.5 * max(q.x + q.y, 0.);\n  return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y);\n}\n\nfn sdMoon(p: vec2<f32>, d: f32, ra: f32, rb: f32) -> f32 {\n  let q = vec2<f32>(p.x, abs(p.y));\n  let a = (ra * ra - rb * rb + d * d) / (2. * d);\n  let b = sqrt(max(ra * ra - a * a, 0.));\n  if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q-vec2<f32>(a, b)); }\n  return max((length(q) - ra), -(length(q - vec2<f32>(d, 0.)) - rb));\n}\n\nfn sdCross(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  var q: vec2<f32> = abs(p);\n  q = select(q.xy, q.yx, q.y > q.x);\n  let t = q - b;\n  let k = max(t.y, t.x);\n  let w = select(vec2<f32>(b.y - q.x, -k), t, k > 0.);\n  return sign(k) * length(max(w, vec2<f32>(0.)));\n}\n\nfn sdRoundedX(p: vec2<f32>, w: f32, r: f32) -> f32 {\n  let q = abs(p);\n  return length(q - min(q.x + q.y, w) * 0.5) - r;\n}\n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n  let d = length(p - c);\n  return d - r;\n}\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     # ifdef INIT\n//         if (location.x == 0 && location.y == 0 )  {\n//             textureStore(buffer_a, location, hue(4.0 / 8.0));\n//         } else {\n//             // set brush color to black\n//             let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n//             textureStore(buffer_a, location, black);\n//         }\n//     # endif\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // the first three frames are not directed inside the update function.\n    // The first time this function is called is on frame 4.\n    if (i32(uni.iFrame) == 3) { \n    // # ifdef INIT\n        if (location.x == 0 && location.y == 0 )  {\n            textureStore(buffer_a, location, hue(4.0 / 8.0));\n        } else {\n            // set brush color to black\n            let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n            textureStore(buffer_a, location, black);\n        }\n    // # endif\n    }\n\n    let R: float2 = uni.iResolution.xy;\n    let U: vec2<f32> = vec2<f32>(location) / R;\n    let M: float2 = vec2<f32>(uni.iMouse.x, 1.0-uni.iMouse.y);\n\n    var O: float4 =  textureLoad(buffer_a, location);\n\n    if (location.x == 0 && location.y == 0 )  {\n        if ( uni.iMouse.x < 0.1 && uni.iMouse.w == 1.0) { // just pressed left mouse button\n            let y: f32 = floor(9.*M.y);\n            O = hue( y/8. ); \n            textureStore(buffer_a, location, O);\n        }\n        return;\n    }\n\n    // display palette on left\n    if ( U.x < 0.1  ) {  \n        let y: f32 = floor(9.*U.y);\n        O = hue( y/8. ); \n        O.w = 1.;\n        textureStore(buffer_a, location, O);\n        return;\n    }\n\n    // let brush_color = float4(1., 0., 0., 1.);\n    let brush_color = textureLoad(buffer_a, vec2<i32>(0,0));\n\n    // apply paint\n    if (uni.iMouse.z == 1.0) {\n        let mouse_pix = vec2<f32>(uni.iMouse.x *  R.x, (1.0 - uni.iMouse.y) * R.y );\n\n        let brush_sdf = sdCircle(vec2<f32>(location), mouse_pix, 10.0);\n        let brush_d = smoothStep(0.0, 5.0, brush_sdf);\n        O = mix(O, brush_color, (1.0-brush_d) * 0.01);\n    }\n    \n\n\n    textureStore(buffer_a, location, O);\n\n}"
  },
  {
    "path": "bin/assets/shaders/paint/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/assets/shaders/paint/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_c, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_c, location, vec4<f32>(0.95));\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_c, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "bin/assets/shaders/paint/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let color = vec4<f32>(0.60);\n\n    textureStore(buffer_d, location, color);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_d, location, vec4<f32>(0.7));\n\n    if (uni.iTime > 1.0) {\n        storageBarrier();\n        textureStore(buffer_d, location, vec4<f32>(0.95));\n    }\n\n    // storageBarrier();\n}"
  },
  {
    "path": "bin/assets/shaders/paint/common.wgsl",
    "content": "// unused\n\n#define_import_path bevy_shadertoy_wgsl::assets::shaders::common\n\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};"
  },
  {
    "path": "bin/assets/shaders/paint/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var alive = true;\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "bin/assets/shaders/paint2/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\ntype float2 = vec2<f32>;\ntype float4 = vec4<f32>;\n\nfn hue(v: f32) -> vec4<f32> { \n    return (vec4<f32>(.6) + vec4<f32>(.6) * cos( vec4<f32>(6.3 * v) + vec4<f32>(0.0,23.0,21.0,0.0 ) ));\n}\n\nfn smoothit(v: f32) -> f32{ \n    return smoothStep( 1.5, 0., v );\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n  let pa = p - a;\n  let ba = b - a;\n  let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n  return length(pa - ba * h);\n}\n\nfn sdRhombus(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  let q = abs(p);\n  let qb = dot(q, vec2<f32>(b.x, -b.y));\n  let bb = dot(b, vec2<f32>(b.x, -b.y));\n  let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.);\n  let d = length(q - 0.5 * b * vec2<f32>(1. - h, 1. + h));\n  return d * sign(q.x * b.y + q.y * b.x - b.x * b.y);\n}\n\nfn sdTriangleIsosceles(p: vec2<f32>, c: vec2<f32>) -> f32 {\n  let q = vec2<f32>(abs(p.x), p.y);\n  let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.);\n  let b = q - c * vec2<f32>(clamp(q.x / c.x, 0., 1.), 1.);\n  let s = -sign(c.y);\n  let d = min(vec2<f32>(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2<f32>(dot(b, b), s * (q.y - c.y)));\n  return -sqrt(d.x) * sign(d.y);\n}\n\nfn sdStar(p: vec2<f32>, r: f32, n: u32, m: f32) ->f32 {\n  let an = 3.141593 / f32(n);\n  let en = 3.141593 / m;\n  let acs = vec2<f32>(cos(an), sin(an));\n  let ecs = vec2<f32>(cos(en), sin(en));\n  let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an;\n  var q: vec2<f32> = length(p) * vec2<f32>(cos(bn), abs(sin(bn)));\n  q = q - r * acs;\n  q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y);\n  return length(q) * sign(q.x);\n}\n\nfn sdHeart(p: vec2<f32>) -> f32 {\n  let q = vec2<f32>(abs(p.x), p.y);\n  let w = q - vec2<f32>(0.25, 0.75);\n  if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; }\n  let u = q - vec2<f32>(0., 1.0);\n  let v = q - 0.5 * max(q.x + q.y, 0.);\n  return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y);\n}\n\nfn sdMoon(p: vec2<f32>, d: f32, ra: f32, rb: f32) -> f32 {\n  let q = vec2<f32>(p.x, abs(p.y));\n  let a = (ra * ra - rb * rb + d * d) / (2. * d);\n  let b = sqrt(max(ra * ra - a * a, 0.));\n  if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q-vec2<f32>(a, b)); }\n  return max((length(q) - ra), -(length(q - vec2<f32>(d, 0.)) - rb));\n}\n\nfn sdCross(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  var q: vec2<f32> = abs(p);\n  q = select(q.xy, q.yx, q.y > q.x);\n  let t = q - b;\n  let k = max(t.y, t.x);\n  let w = select(vec2<f32>(b.y - q.x, -k), t, k > 0.);\n  return sign(k) * length(max(w, vec2<f32>(0.)));\n}\n\nfn sdRoundedX(p: vec2<f32>, w: f32, r: f32) -> f32 {\n  let q = abs(p);\n  return length(q - min(q.x + q.y, w) * 0.5) - r;\n}\n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n  let d = length(p - c);\n  return d - r;\n}\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     # ifdef INIT\n//         if (location.x == 0 && location.y == 0 )  {\n//             textureStore(buffer_a, location, hue(4.0 / 8.0));\n//         } else {\n//             // set brush color to black\n//             let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n//             textureStore(buffer_a, location, black);\n//         }\n//     # endif\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // the first three frames are not directed inside the update function.\n    // The first time this function is called is on frame 4.\n    if (i32(uni.iFrame) == 3) { \n    // # ifdef INIT\n        if (location.x == 0 && location.y == 0 )  {\n            textureStore(buffer_a, location, hue(4.0 / 8.0));\n        } else {\n            // set brush color to black\n            let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n            textureStore(buffer_a, location, black);\n        }\n    // # endif\n    }\n\n    let R: float2 = uni.iResolution.xy;\n    let U: vec2<f32> = vec2<f32>(location) / R;\n    let M: float2 = vec2<f32>(uni.iMouse.x, 1.0-uni.iMouse.y);\n\n    var O: float4 =  textureLoad(buffer_a, location);\n\n    if (location.x == 0 && location.y == 0 )  {\n        if ( uni.iMouse.x < 0.1 && uni.iMouse.w == 1.0) { // just pressed left mouse button\n            let y: f32 = floor(9.*M.y);\n            O = hue( y/8. ); \n            textureStore(buffer_a, location, O);\n        }\n        return;\n    }\n\n    // display palette on left\n    if ( U.x < 0.1  ) {  \n        let y: f32 = floor(9.*U.y);\n        O = hue( y/8. ); \n        O.w = 1.;\n        textureStore(buffer_a, location, O);\n        return;\n    }\n\n    // let brush_color = float4(1., 0., 0., 1.);\n    let brush_color = textureLoad(buffer_a, vec2<i32>(0,0));\n\n    // apply paint\n    if (uni.iMouse.z == 1.0) {\n        let mouse_pix = vec2<f32>(uni.iMouse.x *  R.x, (1.0 - uni.iMouse.y) * R.y );\n\n        let brush_sdf = sdCircle(vec2<f32>(location), mouse_pix, 10.0);\n        let brush_d = smoothStep(0.0, 5.0, brush_sdf);\n        O = mix(O, brush_color, (1.0-brush_d) * 0.01);\n    }\n    \n\n\n    textureStore(buffer_a, location, O);\n\n}"
  },
  {
    "path": "bin/assets/shaders/paint2/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/assets/shaders/paint2/buffer_c.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/assets/shaders/paint2/buffer_d.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/assets/shaders/paint2/common.wgsl",
    "content": "// unused\n\n#define_import_path bevy_shadertoy_wgsl::assets::shaders::common\n\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};"
  },
  {
    "path": "bin/assets/shaders/paint2/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var alive = true;\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "bin/assets/shaders/paint2/image2.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: i32;\n    iSampleRate: i32;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n    \n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(f32(0));\n    textureStore(texture, location, color);\n}\n\n\n\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var alive = true;\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n    // let color = vec4<f32>(O.x, 0.1, 0.12, 1.0);\n\n    // storageBarrier();\n\n    // textureStore(texture, location, vec4<f32>(color));\n    textureStore(texture, location, O);\n}\n\n\n\n"
  },
  {
    "path": "bin/assets/shaders/paint_streams/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\n// var<private> R: vec2<f32> ;\n// var<private> Mouse: vec4<f32> ;\n// var<private> time: f32;\nlet mass = 1.;\nlet h: f32 = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x2.x)) + 65535u * u32(round(x2.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(\n        decode(data.x) + pos, \n        decode(data.y), \n        data.zw\n    );\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n\n\n\n\n\n\n\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba8unorm, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n\t\n        }\t\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n\t\tP1.X = P1.X / (P1.M.x);\n\t\tP1.V = P1.V / (P1.M.x);\n\t\tP1.M.y = P1.M.y / (P1.M.x);\n\t}\n\n    return P1;\n} \n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n\tlet R2 = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(R2.y)  - i32(invocation_id.y));\n\n    let pos: vec2<f32> = vec2<f32>(location);\n\n\t\n\t// Mouse = uni.iMouse;\n\n\n\n\n\tvar P: particle;\n\n\t// if (uni.iFrame < 4.0) {\n\t// if (Mouse.z > 0.5) {\n\t\t\n\t#ifdef INIT\n\t\tlet rand: vec3<f32> = hash32(pos);\n\t\t// let rand = vec3<f32>(0.2, -0.2, -0.2);\n\t\tif (rand.z < 0.) {\n\t\t\tP.X = pos;\n\t\t\tP.V = 0.5 * (rand.xy - 0.5) + vec2<f32>(0., 0.);\n\t\t\tP.M = vec2<f32>(mass, 0.);\n\t\t\n\t\t} else {\n\t\t\tP.X = pos;\n\t\t\tP.V = vec2<f32>(0.);\n\t\t\tP.M = vec2<f32>(0.000001);\n\t\t\n\t\t}\n\t#else\n\t\tP = Reintegration(buffer_b, pos);\n\t#endif\n\n    textureStore(buffer_a, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "bin/assets/shaders/paint_streams/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\n// var<private> R: vec2<f32> ;\n// var<private> Mouse: vec4<f32> ;\n// var<private> time: f32;\nlet mass = 1.;\nlet h: f32 = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x2.x)) + 65535u * u32(round(x2.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(\n        decode(data.x) + pos, \n        decode(data.y), \n        data.zw\n    );\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n\n\n\n\n\n\nfn border(p: vec2<f32>, R2: vec2<f32>, time: f32) -> f32 {\n\tlet bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nfn bN(p: vec2<f32>, R2: vec2<f32>, time: f32) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy, R2, time) \n                     + idx.xyw * border(p + dx.xy, R2, time) \n                     + idx.yzw * border(p + dx.yz, R2, time) \n                     + idx.yxw * border(p + dx.yx, R2, time);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\nfn Simulation(\n\tch: texture_storage_2d<rgba8unorm, read_write>, \n\tP: particle, pos: vec2<f32>,  \n\tR2: vec2<f32>, \n\ttime: f32,\n\tMouse: vec4<f32>,\n) -> particle \n{\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar avgV: vec3<f32> = vec3<f32>(0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n\t\n        }\t\n    }\t\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n\tF = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n\tF = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n\tif (Mouse.z > 0.) {\n\t\tlet dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n\t\tlet d: f32 = distance(Mouse.xy, P.X) / 20.;\n\t\tF = F + (0.001 * dm * exp(-d * d));\n\t\n\t}\n\n    var P1: particle = P;\n\n    //integrate\n\tP1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n\tlet N: vec3<f32> = bN(P1.X, R2, time);\n\tlet vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n\tP1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n\tP1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\t\n    if (N.z < 0.) {\t\n        P1.V = vec2<f32>(0.);\n\t}\n\n    //velocity limit\n\tlet v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v; \n    } else {\n        vv = 1.;\n    };\n\tP1.V = P1.V / vv;\n\n    return P1;\n\n} \n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// }\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>) -> () {\n\n\tlet R2 = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(R2.y) - i32(invocation_id.y));\n\n    let pos: vec2<f32> = vec2<f32>(location);\n\n\t\n\tlet time = uni.iTime;\n\tlet Mouse = uni.iMouse;\n\tlet p: vec2<i32> = location;\n\n\n\t// let data: vec4<f32> = texel(buffer_a, pos);\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\tif (P.M.x != 0.) {\n\t\tP = Simulation(buffer_a, P, pos, R2, time, Mouse);\n\t}\n\n\tif (length(P.X - R2 * vec2<f32>(0.8, 0.9)) < 10.) {\n\t\tP.X = pos;\n\t\tP.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time));\n\t\tP.M = mix(P.M, vec2<f32>(fluid_rho, 1.), 0.4);\n\t}\n    \n\tif (length(P.X - R2 * vec2<f32>(0.2, 0.9)) < 10.) {\n\t\tP.X = pos;\n\t\tP.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time));\n\t\tP.M = mix(P.M, vec2<f32>(fluid_rho, 0.), 0.4);\n\t}\n\n\t// U = saveParticle(P, pos);\n    textureStore(buffer_b, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "bin/assets/shaders/paint_streams/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\n// var<private> R: vec2<f32> ;\n// var<private> Mouse: vec4<f32> ;\n// var<private> time: f32;\nlet mass = 1.;\nlet h: f32 = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x2.x)) + 65535u * u32(round(x2.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(\n        decode(data.x) + pos, \n        decode(data.y), \n        data.zw\n    );\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// fn mainImage( fragColor: vec4<f32>,  pos: vec2<f32>) -> () {\n\t// let R = uni.iResolution.xy;\n\n\tlet R2 = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(R2.y)  - i32(invocation_id.y));\n\t// R = uni.iResolution.xy;\n\t// time = uni.iTime;\n    let pos = vec2<f32>(location);\n\tlet p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\t// let data: vec4<f32> = texel(ch0, pos);\n\t// let P: particle = getParticle(data, pos);\n\n\tvar rho: vec4<f32> = vec4<f32>(0.);\n\tfor (var i: i32 = -1; i <= 1; i = i + 1) {\n\t\tfor (var j: i32 = -1; j <= 1; j = j + 1) {\n\t\t\tlet ij: vec2<i32> = vec2<i32>(i, j);\n\n\t\t\t// let data: vec4<f32> = texel(ch0, pos + ij);\n             let data: vec4<f32> =  textureLoad(buffer_a, location + ij);\n\n\t\t\tvar P0: particle = getParticle(data, pos + vec2<f32>(ij));\n\t\t\tlet x0: vec2<f32> = P0.X;\n\t\t\trho = rho + (1. * vec4<f32>(P.V, P.M) * G((pos - x0) / 0.75));\n\t\t\n\t\t}\t\n\t}\t\n\n    textureStore(buffer_c, location, rho);\n\n} \n\n"
  },
  {
    "path": "bin/assets/shaders/paint_streams/buffer_d.wgsl",
    "content": "\nstruct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\n// var<private> R: vec2<f32> ;\n// var<private> Mouse: vec4<f32> ;\n// var<private> time: f32;\nlet mass = 1.;\nlet h: f32 = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x2.x)) + 65535u * u32(round(x2.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(\n        decode(data.x) + pos, \n        decode(data.y), \n        data.zw\n    );\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n\n\n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}\n"
  },
  {
    "path": "bin/assets/shaders/paint_streams/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\n// var<private> R: vec2<f32> ;\n// var<private> Mouse: vec4<f32> ;\n// var<private> time: f32;\nlet mass = 1.;\nlet h: f32 = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x2.x)) + 65535u * u32(round(x2.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(\n        decode(data.x) + pos, \n        decode(data.y), \n        data.zw\n    );\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n\n\n\n\n\n\n\n\n// fn hsv2rgb( c: vec3<f32>) -> vec3<f32> {\n//     // var fractional: f32 = 0.0;\n//     // let m = modf(c.x * 6. + vec3<f32>(0., 4., 2.) / 6., &fractional);\n\n//     let v = vec3<f32>(0., 4., 2.);\n//     let fractional: vec3<f32> = vec3<f32>(vec3<i32>( (c.x * 6. +  v) / 6.0)) ;\n        \n//     // let whatever = modf(uv + 1.0, &tempo);\n//     // var temp2 = 0.;\n//     // let frac = modf(tempo / 2.0, &temp2);\n//     let af: vec3<f32>  = abs(fractional - 3.) - 1.;\n\n// \tvar rgb: vec3<f32> = clamp(af, vec3<f32>(0.), vec3<f32>(1.));\n\n// \trgb = rgb * rgb * (3. - 2. * rgb);\n// \treturn c.z * mix(vec3<f32>(1.), rgb, c.y);\n\n// } \n\nfn mixN(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {\n\treturn sqrt(mix(a * a, b * b, clamp(k, 0., 1.)));\n\n} \n\nfn V(p: vec2<f32>) -> vec4<f32> {\n\t// return pixel(ch1, p);\n    return textureLoad(buffer_c, vec2<i32>(p ));\n\n} \n\nfn border(p: vec2<f32>, R2: vec2<f32>, time: f32) -> f32 {\n\tlet bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nfn bN(p: vec2<f32>, R2: vec2<f32>, time: f32) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy, R2, time) \n                     + idx.xyw * border(p + dx.xy, R2, time) \n                     + idx.yzw * border(p + dx.yz, R2, time) \n                     + idx.yxw * border(p + dx.yx, R2, time);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    \n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n// fn mainImage( col: vec4<f32>,  pos: vec2<f32>) -> () {\n\n\tlet R2 = uni.iResolution.xy;\n\n\tlet location = vec2<i32>(i32(invocation_id.x),  i32(invocation_id.y));\n\tlet time = uni.iTime;\n\n\t// let p: vec2<i32> = vec2<i32>(pos);\n\t// let data: vec4<f32> = texel(ch0, pos);\n\n    // let p: vec2<i32> = vec2<i32>(location.x, i32(R2.y) - location.y);\n\n    let data: vec4<f32> =  textureLoad(buffer_a, i32(R2.y) - location);\n\n    let pos = vec2<f32>(f32(location.x), R2.y - f32(location.y));\n\n\tvar P: particle = getParticle(data, pos);\n\n\tlet Nb: vec3<f32> = bN(P.X, R2, time);\n\tlet bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos, R2, time));\n\tlet rho: vec4<f32> = V(pos);\n\tlet dx: vec3<f32> = vec3<f32>(-2., 0., 2.);\n\n\tlet grad: vec4<f32> = -0.5 * vec4<f32>( V(pos + dx.zy).zw - V(pos + dx.xy).zw, \n                                            V(pos + dx.yz).zw - V(pos + dx.yx).zw);\n\tlet N: vec2<f32> = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001);\n\n\tlet specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5);\n\tlet specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.);\n\n\n\tlet a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1);\n\tlet b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z));\n\tlet col0: vec3<f32> = vec3<f32>(1., 0.5, 0.);\n\tlet col1: vec3<f32> = vec3<f32>(0.1, 0.4, 1.);\n\n\n\tlet fcol: vec3<f32> = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5);\n    // var col: vec4<f32>;\n\n\tvar col: vec3<f32> = vec3<f32>(3.);\n\tcol = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a);\n\n\n\tcol = mixN(col, 0. * vec3<f32>(0.5, 0.5, 1.), bord);\n\tcol = tanh(col);\n    let col4 = vec4<f32>(col, 1.0);\n\n\t// let grey = vec4<f32>(0.8);\n\n    textureStore(texture, location, col4);\n\t// textureStore(texture, location, data);\n\n\n} \n"
  },
  {
    "path": "bin/assets/shaders/preludes/image_prelude",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iResolution: vec2<f32>;\n    iMouse: vec2<f32>;\n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>; // change to vec4<f32> when possible\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n{{IMAGE_CODE}}\n"
  },
  {
    "path": "bin/assets/shaders/simplest_detailed_fluid/buffer_a.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n\n    textureStore(buffer_a, location, color);\n}\n\n// https://www.shadertoy.com/view/7t3SDf\n\nfn t(i: vec2<i32>, location: vec2<i32>) -> vec4<f32> {\n    let O: vec4<f32> =  textureLoad(buffer_a, i + location );\n    return O;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    var location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    // location = location + vec2<i32>(10);\n    \n\n    var r: vec4<f32> = vec4<f32>(0.);\n\n\tfor (var i: vec2<i32> = vec2<i32>(-7); i.x < 7; i.x = i.x + 1  ) {\t\n\n        for (i.y = -7; i.y  < 7; i.y = i.y + 1  ) {\n            \n            let ii = i + 1;\n            let a = 0;\n\n            let v: vec2<f32> = t(ii , location + a ).xy;\n            let what = t(ii, location + a).z ;\n            let fi = vec2<f32>(ii);\n            \n            r = r + ( what \n                * exp(-dot(v+fi, v+fi)) / 3.14\n                * vec4<f32>(mix(v+v+fi , v, t(ii, location + a ).z), 1., 1.)  );\n        }\t\n    }\t\n\n    r.x = r.x / (r.z+0.000001);\n    r.y = r.y / (r.z+0.000001);\n\n\tif (i32(uni.iFrame) % 500 == 1) {\n            let u = vec2<f32>(location +0) ;\n\t\t\tlet m: vec2<f32> = 4.*u/vec2<f32>(uni.iResolution.xy) - 2.;\n\t\t\tr = r + (vec4<f32>(m, 1., 0.)*exp(-dot(m, m)));\n\t\t\n\t}\n\n    textureStore(buffer_a, location , r);\n}\n\n"
  },
  {
    "path": "bin/assets/shaders/simplest_detailed_fluid/buffer_b.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_b, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_b, location, vec4<f32>(0.85));\n\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_b, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "bin/assets/shaders/simplest_detailed_fluid/buffer_c.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let color = vec4<f32>(0.0);\n\n    textureStore(buffer_c, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_c, location, vec4<f32>(0.95));\n\n    // if (uni.iTime > 1.0) {\n    //     textureStore(buffer_c, location, vec4<f32>(0.95));\n    // }\n}"
  },
  {
    "path": "bin/assets/shaders/simplest_detailed_fluid/buffer_d.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let color = vec4<f32>(0.60);\n\n    textureStore(buffer_d, location, color);\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // textureStore(buffer_d, location, vec4<f32>(0.7));\n\n    if (uni.iTime > 1.0) {\n        storageBarrier();\n        textureStore(buffer_d, location, vec4<f32>(0.95));\n    }\n\n    // storageBarrier();\n}"
  },
  {
    "path": "bin/assets/shaders/simplest_detailed_fluid/image.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\nfn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n    let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x);\n    let alive = randomNumber > 0.9;\n    let color = vec4<f32>(f32(alive));\n\n    textureStore(texture, location, color);\n}\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\n\n    // var alive = true;\n\n\n    // let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    // if (value.x > 0.79) {\n    //     alive = false;\n    // }\n    let r = 1.- textureLoad(buffer_a, location ).zzzz;\n\n    storageBarrier();\n    textureStore(texture, location, r);\n   \n\n    // textureStore(texture, location, vec4<f32>(f32(alive)));\n}\n\n\n"
  },
  {
    "path": "bin/examples/minimal/buffer_a.wgsl",
    "content": "\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "bin/examples/minimal/buffer_b.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/examples/minimal/buffer_c.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/examples/minimal/buffer_d.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/examples/minimal/common.wgsl",
    "content": ""
  },
  {
    "path": "bin/examples/minimal/image.wgsl",
    "content": "// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "bin/examples/mixing_liquid/buffer_a.wgsl",
    "content": "\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let color = vec4<f32>(0.5);\n//     textureStore(buffer_a, location, color);\n// }\n\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>) -> () {\n    let pos: vec2<f32> = vec2<f32>(location);\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet p: vec2<i32> = location;\n\n\t// let data: vec4<f32> = texel(ch0, pos);\n\n    // buffer_b is set as the channel 0 in Buffer A of the paint\n    // streams inside shadertoy \n    let data: vec4<f32> =  textureLoad(buffer_b, location);\n\n\tvar P: particle = Reintegration(buffer_b, pos);\n\n\t// if (uni.iFrame < 4.0) {\n    # ifdef INIT \n\t\tlet rand: vec3<f32> = hash32(pos);\n\t\tif (rand.z < 0.) {\n\t\t\tP.X = pos;\n\t\t\tP.V = 0.5 * (rand.xy - 0.5) + vec2<f32>(0., 0.);\n\t\t\tP.M = vec2<f32>(mass, 0.);\n\t\t\n\t\t} else {\n\t\t\tP.X = pos;\n\t\t\tP.V = vec2<f32>(0.);\n\t\t\tP.M = vec2<f32>(0.000001);\n\t\t\n\t\t}\n    # endif\n\t// }\n\n    textureStore(buffer_a, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "bin/examples/mixing_liquid/buffer_b.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// }\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>) -> () {\n\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    let pos: vec2<f32> = vec2<f32>(location);\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet p: vec2<i32> = location;\n\n\n\t// let data: vec4<f32> = texel(buffer_a, pos);\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\tif (P.M.x != 0.) {\n\t\tP = Simulation(buffer_a, P, pos);\n\t}\n\n\tif (length(P.X - R * vec2<f32>(0.8, 0.9)) < 10.) {\n\t\tP.X = pos;\n\t\tP.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time));\n\t\tP.M = mix(P.M, vec2<f32>(fluid_rho, 1.), 0.4);\n\t}\n    \n\tif (length(P.X - R * vec2<f32>(0.2, 0.9)) < 10.) {\n\t\tP.X = pos;\n\t\tP.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time));\n\t\tP.M = mix(P.M, vec2<f32>(fluid_rho, 0.), 0.4);\n\t}\n\n\t// U = saveParticle(P, pos);\n    textureStore(buffer_b, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "bin/examples/mixing_liquid/buffer_c.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// fn mainImage( fragColor: vec4<f32>,  pos: vec2<f32>) -> () {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n    let pos = vec2<f32>(location);\n\tlet p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\t// let data: vec4<f32> = texel(ch0, pos);\n\t// let P: particle = getParticle(data, pos);\n\n\tvar rho: vec4<f32> = vec4<f32>(0.);\n\tfor (var i: i32 = -1; i <= 1; i = i + 1) {\n\t\tfor (var j: i32 = -1; j <= 1; j = j + 1) {\n\t\t\tlet ij: vec2<i32> = vec2<i32>(i, j);\n\n\t\t\t// let data: vec4<f32> = texel(ch0, pos + ij);\n             let data: vec4<f32> =  textureLoad(buffer_a, location + ij);\n\n\t\t\tvar P0: particle = getParticle(data, pos + vec2<f32>(ij));\n\t\t\tlet x0: vec2<f32> = P0.X;\n\t\t\trho = rho + (1. * vec4<f32>(P.V, P.M) * G((pos - x0) / 0.75));\n\t\t\n\t\t}\t\n\t}\t\n\n    textureStore(buffer_c, location, rho);\n\n} \n\n"
  },
  {
    "path": "bin/examples/mixing_liquid/buffer_d.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/examples/mixing_liquid/common.wgsl",
    "content": "\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\nvar<private> R: vec2<f32> ;\nvar<private> Mouse: vec4<f32> ;\nvar<private> time: f32;\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nlet h: f32 = 1.;\n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy) \n                     + idx.xyw * border(p + dx.xy) \n                     + idx.yzw * border(p + dx.yz) \n                     + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x.x)) + 65535u * u32(round(x.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw);\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba8unorm, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n\t\n        }\t\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n\t\tP1.X = P1.X / (P1.M.x);\n\t\tP1.V = P1.V / (P1.M.x);\n\t\tP1.M.y = P1.M.y / (P1.M.x);\n\t}\n\n    return P1;\n} \n\nfn Simulation(ch: texture_storage_2d<rgba8unorm, read_write>, P: particle, pos: vec2<f32>) -> particle {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar avgV: vec3<f32> = vec3<f32>(0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(i));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n\t\n        }\t\n    }\t\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n\tF = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n\tF = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n\tif (Mouse.z > 0.) {\n\t\tlet dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n\t\tlet d: f32 = distance(Mouse.xy, P.X) / 20.;\n\t\tF = F + (0.001 * dm * exp(-d * d));\n\t\n\t}\n\n    var P1: particle = P;\n\n    //integrate\n\tP1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n\tlet N: vec3<f32> = bN(P1.X);\n\tlet vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n\tP1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n\tP1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\t\n    if (N.z < 0.) {\t\n        P1.V = vec2<f32>(0.);\n\t}\n\n    //velocity limit\n\tlet v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v; \n    } else {\n        vv = 1.;\n    };\n\tP1.V = P1.V / vv;\n\n    return P1;\n\n} \n\n"
  },
  {
    "path": "bin/examples/mixing_liquid/image.wgsl",
    "content": "// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n// fn even(uv: f32) -> f32 {\n//     var tempo: f32 = 0.0;\n//     let whatever = modf(uv + 1.0, &tempo);\n//     var temp2 = 0.;\n//     let frac = modf(tempo / 2.0, &temp2);\n\n//     if (abs(frac) < 0.001) {\n//         return 1.0;\n//     } else {\n//         return 0.0;\n//     }\n// }\n\n\nfn hsv2rgb( c: vec3<f32>) -> vec3<f32> {\n    // var fractional: f32 = 0.0;\n    // let m = modf(c.x * 6. + vec3<f32>(0., 4., 2.) / 6., &fractional);\n\n    let v = vec3<f32>(0., 4., 2.);\n    let fractional: vec3<f32> = vec3<f32>(vec3<i32>( (c.x * 6. +  v) / 6.0)) ;\n        \n    // let whatever = modf(uv + 1.0, &tempo);\n    // var temp2 = 0.;\n    // let frac = modf(tempo / 2.0, &temp2);\n    let af: vec3<f32>  = abs(fractional - 3.) - 1.;\n\n\tvar rgb: vec3<f32> = clamp(af, vec3<f32>(0.), vec3<f32>(1.));\n\n\trgb = rgb * rgb * (3. - 2. * rgb);\n\treturn c.z * mix(vec3<f32>(1.), rgb, c.y);\n\n} \n\nfn mixN(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {\n\treturn sqrt(mix(a * a, b * b, clamp(k, 0., 1.)));\n\n} \n\nfn V(p: vec2<f32>) -> vec4<f32> {\n\t// return pixel(ch1, p);\n    return textureLoad(buffer_c, vec2<i32>(p ));\n\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n// fn mainImage( col: vec4<f32>,  pos: vec2<f32>) -> () {\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\n\t// let p: vec2<i32> = vec2<i32>(pos);\n\t// let data: vec4<f32> = texel(ch0, pos);\n\n    let p: vec2<i32> = location;\n\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n    let pos = vec2<f32>(location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\tlet Nb: vec3<f32> = bN(P.X);\n\tlet bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos));\n\tlet rho: vec4<f32> = V(pos);\n\tlet dx: vec3<f32> = vec3<f32>(-2., 0., 2.);\n\n\tlet grad: vec4<f32> = -0.5 * vec4<f32>( V(pos + dx.zy).zw - V(pos + dx.xy).zw, \n                                            V(pos + dx.yz).zw - V(pos + dx.yx).zw);\n\tlet N: vec2<f32> = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001);\n\n\tlet specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5);\n\tlet specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.);\n\n\n\tlet a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1);\n\tlet b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z));\n\tlet col0: vec3<f32> = vec3<f32>(1., 0.5, 0.);\n\tlet col1: vec3<f32> = vec3<f32>(0.1, 0.4, 1.);\n\n\n\tlet fcol: vec3<f32> = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5);\n    // var col: vec4<f32>;\n\n\tvar col: vec3<f32> = vec3<f32>(3.);\n\tcol = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a);\n\n\n\tcol = mixN(col, 0. * vec3<f32>(0.5, 0.5, 1.), bord);\n\tcol = tanh(col);\n    let col4 = vec4<f32>(col, 0.3);\n\n    textureStore(texture, location, rho);\n\n\n} \n"
  },
  {
    "path": "bin/examples/paint/buffer_a.wgsl",
    "content": "\ntype float2 = vec2<f32>;\ntype float4 = vec4<f32>;\n\nfn hue(v: f32) -> vec4<f32> { \n    return (vec4<f32>(.6) + vec4<f32>(.6) * cos( vec4<f32>(6.3 * v) + vec4<f32>(0.0,23.0,21.0,0.0 ) ));\n}\n\nfn smoothit(v: f32) -> f32{ \n    return smoothStep( 1.5, 0., v );\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n  let pa = p - a;\n  let ba = b - a;\n  let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n  return length(pa - ba * h);\n}\n\nfn sdRhombus(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  let q = abs(p);\n  let qb = dot(q, vec2<f32>(b.x, -b.y));\n  let bb = dot(b, vec2<f32>(b.x, -b.y));\n  let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.);\n  let d = length(q - 0.5 * b * vec2<f32>(1. - h, 1. + h));\n  return d * sign(q.x * b.y + q.y * b.x - b.x * b.y);\n}\n\nfn sdTriangleIsosceles(p: vec2<f32>, c: vec2<f32>) -> f32 {\n  let q = vec2<f32>(abs(p.x), p.y);\n  let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.);\n  let b = q - c * vec2<f32>(clamp(q.x / c.x, 0., 1.), 1.);\n  let s = -sign(c.y);\n  let d = min(vec2<f32>(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2<f32>(dot(b, b), s * (q.y - c.y)));\n  return -sqrt(d.x) * sign(d.y);\n}\n\nfn sdStar(p: vec2<f32>, r: f32, n: u32, m: f32) ->f32 {\n  let an = 3.141593 / f32(n);\n  let en = 3.141593 / m;\n  let acs = vec2<f32>(cos(an), sin(an));\n  let ecs = vec2<f32>(cos(en), sin(en));\n  let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an;\n  var q: vec2<f32> = length(p) * vec2<f32>(cos(bn), abs(sin(bn)));\n  q = q - r * acs;\n  q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y);\n  return length(q) * sign(q.x);\n}\n\nfn sdHeart(p: vec2<f32>) -> f32 {\n  let q = vec2<f32>(abs(p.x), p.y);\n  let w = q - vec2<f32>(0.25, 0.75);\n  if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; }\n  let u = q - vec2<f32>(0., 1.0);\n  let v = q - 0.5 * max(q.x + q.y, 0.);\n  return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y);\n}\n\nfn sdMoon(p: vec2<f32>, d: f32, ra: f32, rb: f32) -> f32 {\n  let q = vec2<f32>(p.x, abs(p.y));\n  let a = (ra * ra - rb * rb + d * d) / (2. * d);\n  let b = sqrt(max(ra * ra - a * a, 0.));\n  if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q-vec2<f32>(a, b)); }\n  return max((length(q) - ra), -(length(q - vec2<f32>(d, 0.)) - rb));\n}\n\nfn sdCross(p: vec2<f32>, b: vec2<f32>) -> f32 {\n  var q: vec2<f32> = abs(p);\n  q = select(q.xy, q.yx, q.y > q.x);\n  let t = q - b;\n  let k = max(t.y, t.x);\n  let w = select(vec2<f32>(b.y - q.x, -k), t, k > 0.);\n  return sign(k) * length(max(w, vec2<f32>(0.)));\n}\n\nfn sdRoundedX(p: vec2<f32>, w: f32, r: f32) -> f32 {\n  let q = abs(p);\n  return length(q - min(q.x + q.y, w) * 0.5) - r;\n}\n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n  let d = length(p - c);\n  return d - r;\n}\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     # ifdef INIT\n//         if (location.x == 0 && location.y == 0 )  {\n//             textureStore(buffer_a, location, hue(4.0 / 8.0));\n//         } else {\n//             // set brush color to black\n//             let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n//             textureStore(buffer_a, location, black);\n//         }\n//     # endif\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // the first three frames are not directed inside the update function.\n    // The first time this function is called is on frame 4.\n    if (i32(uni.iFrame) == 3) { \n    // # ifdef INIT\n        if (location.x == 0 && location.y == 0 )  {\n            textureStore(buffer_a, location, hue(4.0 / 8.0));\n        } else {\n            // set brush color to black\n            let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n            textureStore(buffer_a, location, black);\n        }\n    // # endif\n    }\n\n    let R: float2 = uni.iResolution.xy;\n    let U: vec2<f32> = vec2<f32>(location) / R;\n    let M: float2 = vec2<f32>(uni.iMouse.x, 1.0-uni.iMouse.y);\n\n    var O: float4 =  textureLoad(buffer_a, location);\n\n    if (location.x == 0 && location.y == 0 )  {\n        if ( uni.iMouse.x < 0.1 && uni.iMouse.w == 1.0) { // just pressed left mouse button\n            let y: f32 = floor(9.*M.y);\n            O = hue( y/8. ); \n            textureStore(buffer_a, location, O);\n        }\n        return;\n    }\n\n    // display palette on left\n    if ( U.x < 0.1  ) {  \n        let y: f32 = floor(9.*U.y);\n        O = hue( y/8. ); \n        O.w = 1.;\n        textureStore(buffer_a, location, O);\n        return;\n    }\n\n    // let brush_color = float4(1., 0., 0., 1.);\n    let brush_color = textureLoad(buffer_a, vec2<i32>(0,0));\n\n    // apply paint\n    if (uni.iMouse.z == 1.0) {\n        let mouse_pix = vec2<f32>(uni.iMouse.x *  R.x, (1.0 - uni.iMouse.y) * R.y );\n\n        let brush_sdf = sdCircle(vec2<f32>(location), mouse_pix, 10.0);\n        let brush_d = smoothStep(0.0, 5.0, brush_sdf);\n        O = mix(O, brush_color, (1.0-brush_d) * 0.01);\n    }\n    \n\n\n    textureStore(buffer_a, location, O);\n\n}"
  },
  {
    "path": "bin/examples/paint/buffer_b.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/examples/paint/buffer_c.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/examples/paint/buffer_d.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/examples/paint/common.wgsl",
    "content": ""
  },
  {
    "path": "bin/examples/paint/image.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var alive = true;\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "bin/examples/paint_streams/buffer_a.wgsl",
    "content": "\n// don't forget to use a return value when using Reintegration\nfn Reintegration(ch: texture_storage_2d<rgba8unorm, read_write>, pos: vec2<f32>) -> particle {\n\t\n    //basically integral over all updated neighbor distributions\n    //that fall inside of this pixel\n    //this makes the tracking conservative\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt);//integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n\n            //the deposited mass into this cell\n            let m: f32 = P0.M.x * D.z;\n\n            var P1: particle;\n            // TODO: change the input particle directly using (*P).X = ...\n            //add weighted by mass\n            P1.X = P1.X + (D.xy * m);\n            P1.V = P1.V + (P0.V * m);\n            P1.M.y = P1.M.y + (P0.M.y * m);\n\n            //add mass\n            P1.M.x = P1.M.x + (m);\n\t\n        }\t\n    }\n\n    //normalization\n    if (P1.M.x != 0.) {\n\t\tP1.X = P1.X / (P1.M.x);\n\t\tP1.V = P1.V / (P1.M.x);\n\t\tP1.M.y = P1.M.y / (P1.M.x);\n\t}\n\n    return P1;\n} \n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n\tlet R2 = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(R2.y)  - i32(invocation_id.y));\n\n    let pos: vec2<f32> = vec2<f32>(location);\n\n\t\n\t// Mouse = uni.iMouse;\n\n\n\n\n\tvar P: particle;\n\n\t// if (uni.iFrame < 4.0) {\n\t// if (Mouse.z > 0.5) {\n\t\t\n\t#ifdef INIT\n\t\tlet rand: vec3<f32> = hash32(pos);\n\t\t// let rand = vec3<f32>(0.2, -0.2, -0.2);\n\t\tif (rand.z < 0.) {\n\t\t\tP.X = pos;\n\t\t\tP.V = 0.5 * (rand.xy - 0.5) + vec2<f32>(0., 0.);\n\t\t\tP.M = vec2<f32>(mass, 0.);\n\t\t\n\t\t} else {\n\t\t\tP.X = pos;\n\t\t\tP.V = vec2<f32>(0.);\n\t\t\tP.M = vec2<f32>(0.000001);\n\t\t\n\t\t}\n\t#else\n\t\tP = Reintegration(buffer_b, pos);\n\t#endif\n\n    textureStore(buffer_a, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "bin/examples/paint_streams/buffer_b.wgsl",
    "content": "fn border(p: vec2<f32>, R2: vec2<f32>, time: f32) -> f32 {\n\tlet bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nfn bN(p: vec2<f32>, R2: vec2<f32>, time: f32) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy, R2, time) \n                     + idx.xyw * border(p + dx.xy, R2, time) \n                     + idx.yzw * border(p + dx.yz, R2, time) \n                     + idx.yxw * border(p + dx.yx, R2, time);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\nfn Simulation(\n\tch: texture_storage_2d<rgba8unorm, read_write>, \n\tP: particle, pos: vec2<f32>,  \n\tR2: vec2<f32>, \n\ttime: f32,\n\tMouse: vec4<f32>,\n) -> particle \n{\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar avgV: vec3<f32> = vec3<f32>(0.);\n\tfor (var i: i32 = -2; i <= 2; i = i + 1) {\t\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n            // let data: vec4<f32> = texel(ch, tpos);\n            // let data: vec4<f32> = texelFetch(ch, ivec2(tpos), 0);\n            let data: vec4<f32> =  textureLoad(ch, vec2<i32>(tpos));\n\n            let P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - P.X;\n\n            let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V, 1.));\n\t\n        }\t\n    }\t\n    avgV.y = avgV.y / (avgV.z);\n    avgV.x = avgV.x / (avgV.z);\n\n    //viscosity\n\tF = F + (0. * P.M.x * (avgV.xy - P.V));\n\n    //gravity\n\tF = F + (P.M.x * vec2<f32>(0., -0.0004));\n\n\tif (Mouse.z > 0.) {\n\t\tlet dm: vec2<f32> = (Mouse.xy - Mouse.zw) / 10.;\n\t\tlet d: f32 = distance(Mouse.xy, P.X) / 20.;\n\t\tF = F + (0.001 * dm * exp(-d * d));\n\t\n\t}\n\n    var P1: particle = P;\n\n    //integrate\n\tP1.V = P1.V + (F * dt / P1.M.x);\n\n    //border \n\tlet N: vec3<f32> = bN(P1.X, R2, time);\n\tlet vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V);\n\tP1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n\tP1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\t\n    if (N.z < 0.) {\t\n        P1.V = vec2<f32>(0.);\n\t}\n\n    //velocity limit\n\tlet v: f32 = length(P1.V);\n\n    var vv: f32;\n    if (v > 1.) {\n        vv = v; \n    } else {\n        vv = 1.;\n    };\n\tP1.V = P1.V / vv;\n\n    return P1;\n\n} \n\n\n\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// }\n\n// fn mainImage( U: vec4<f32>,  pos: vec2<f32>) -> () {\n\n\tlet R2 = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(R2.y) - i32(invocation_id.y));\n\n    let pos: vec2<f32> = vec2<f32>(location);\n\n\t\n\tlet time = uni.iTime;\n\tlet Mouse = uni.iMouse;\n\tlet p: vec2<i32> = location;\n\n\n\t// let data: vec4<f32> = texel(buffer_a, pos);\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\tif (P.M.x != 0.) {\n\t\tP = Simulation(buffer_a, P, pos, R2, time, Mouse);\n\t}\n\n\tif (length(P.X - R2 * vec2<f32>(0.8, 0.9)) < 10.) {\n\t\tP.X = pos;\n\t\tP.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time));\n\t\tP.M = mix(P.M, vec2<f32>(fluid_rho, 1.), 0.4);\n\t}\n    \n\tif (length(P.X - R2 * vec2<f32>(0.2, 0.9)) < 10.) {\n\t\tP.X = pos;\n\t\tP.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time));\n\t\tP.M = mix(P.M, vec2<f32>(fluid_rho, 0.), 0.4);\n\t}\n\n\t// U = saveParticle(P, pos);\n    textureStore(buffer_b, location, saveParticle(P, pos));\n} \n\n"
  },
  {
    "path": "bin/examples/paint_streams/buffer_c.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n// fn mainImage( fragColor: vec4<f32>,  pos: vec2<f32>) -> () {\n\t// let R = uni.iResolution.xy;\n\n\tlet R2 = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(R2.y)  - i32(invocation_id.y));\n\t// R = uni.iResolution.xy;\n\t// time = uni.iTime;\n    let pos = vec2<f32>(location);\n\tlet p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> =  textureLoad(buffer_a, location);\n\n\tvar P: particle = getParticle(data, pos);\n\n\t// let data: vec4<f32> = texel(ch0, pos);\n\t// let P: particle = getParticle(data, pos);\n\n\tvar rho: vec4<f32> = vec4<f32>(0.);\n\tfor (var i: i32 = -1; i <= 1; i = i + 1) {\n\t\tfor (var j: i32 = -1; j <= 1; j = j + 1) {\n\t\t\tlet ij: vec2<i32> = vec2<i32>(i, j);\n\n\t\t\t// let data: vec4<f32> = texel(ch0, pos + ij);\n             let data: vec4<f32> =  textureLoad(buffer_a, location + ij);\n\n\t\t\tvar P0: particle = getParticle(data, pos + vec2<f32>(ij));\n\t\t\tlet x0: vec2<f32> = P0.X;\n\t\t\trho = rho + (1. * vec4<f32>(P.V, P.M) * G((pos - x0) / 0.75));\n\t\t\n\t\t}\t\n\t}\t\n\n    textureStore(buffer_c, location, rho);\n\n} \n\n"
  },
  {
    "path": "bin/examples/paint_streams/buffer_d.wgsl",
    "content": "[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "bin/examples/paint_streams/common.wgsl",
    "content": "\n\n\n// struct Particle {\n//      a: vec4<f32>;\n//      b: vec4<f32>;\n// };\n\n\n// fn dum(x: Particle) {\n//     let x2 = Particle(x.a, x.b);\n//     let bah = x.a + 1.0;\n//     return;\n// }\n\n\n// fn miam() -> Particle {\n//     var out: Particle;\n//     out.a = vec4<f32>(0.0);\n//     out.b = vec4<f32>(1.0);\n//     return out;\n// }\n\n// let ch0: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch1: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch2: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// let ch3: texture_storage_2d<rgba8unorm, read_write> = buffer_a;\n\n// #define Bf(p) p\n// #define Bi(p) ivec2(p)\n// #define texel(a, p) texelFetch(a, Bi(p), 0)\n// #define pixel(a, p) texture(a, (p)/R)\n\nlet PI = 3.14159265;\n\n\n\nlet dt = 1.5;\n\nlet border_h = 5.;\n\n// var<private> R: vec2<f32> ;\n// var<private> Mouse: vec4<f32> ;\n// var<private> time: f32;\nlet mass = 1.;\nlet h: f32 = 1.;\n\nlet fluid_rho = 0.5;\n\nfn Pf(rho: vec2<f32>) -> f32 {\n\tlet GF: f32 = 1.;\n\treturn mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n\n\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n\n} \n\nfn sdBox( p: vec2<f32>,  b: vec2<f32>) -> f32 {\n\tlet d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n\n} \n\n\nfn pack(x: vec2<f32>) -> u32 {\n\tlet x2: vec2<f32> = 65534. * clamp(0.5 * x + 0.5, vec2<f32>(0.), vec2<f32>(1.));\n\treturn u32(round(x2.x)) + 65535u * u32(round(x2.y));\n\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n\tvar x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n\treturn clamp(x / 65534., vec2<f32>(0.), vec2<f32>(1.)) * 2. - 1.;\n\n} \n\nfn decode(x: f32) -> vec2<f32> {\n\tvar X: u32 = u32(x);\n\treturn unpack(X);\n\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n\tvar X: u32 = pack(x);\n\treturn f32(X);\n\n} \n\nstruct particle {\n\tX: vec2<f32>;\n\tV: vec2<f32>;\n\tM: vec2<f32>;\n};\n\n\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle = particle(\n        decode(data.x) + pos, \n        decode(data.y), \n        data.zw\n    );\n\treturn P;\n\n} \n\nfn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P2: particle = particle(P.X, P.V, P.M);\n\tP2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n\treturn vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n\n} \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(.1031, .1030, .0973));\n\tp3 = p3 + (dot(p3, p3.yxz + 33.33));\n\treturn fract((p3.xxy + p3.yzz) * p3.zyx);\n\n} \n\nfn G(x: vec2<f32>) -> f32 {\n\treturn exp(-dot(x, x));\n\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n\treturn exp(-length(x));\n\n} \n\nlet dif: f32 = 1.12;\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n\tlet omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n\tlet omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n\treturn vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n\n} \n\n\n\n\n\n\n"
  },
  {
    "path": "bin/examples/paint_streams/image.wgsl",
    "content": "\n// fn hsv2rgb( c: vec3<f32>) -> vec3<f32> {\n//     // var fractional: f32 = 0.0;\n//     // let m = modf(c.x * 6. + vec3<f32>(0., 4., 2.) / 6., &fractional);\n\n//     let v = vec3<f32>(0., 4., 2.);\n//     let fractional: vec3<f32> = vec3<f32>(vec3<i32>( (c.x * 6. +  v) / 6.0)) ;\n        \n//     // let whatever = modf(uv + 1.0, &tempo);\n//     // var temp2 = 0.;\n//     // let frac = modf(tempo / 2.0, &temp2);\n//     let af: vec3<f32>  = abs(fractional - 3.) - 1.;\n\n// \tvar rgb: vec3<f32> = clamp(af, vec3<f32>(0.), vec3<f32>(1.));\n\n// \trgb = rgb * rgb * (3. - 2. * rgb);\n// \treturn c.z * mix(vec3<f32>(1.), rgb, c.y);\n\n// } \n\nfn mixN(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {\n\treturn sqrt(mix(a * a, b * b, clamp(k, 0., 1.)));\n\n} \n\nfn V(p: vec2<f32>) -> vec4<f32> {\n\t// return pixel(ch1, p);\n    return textureLoad(buffer_c, vec2<i32>(p ));\n\n} \n\nfn border(p: vec2<f32>, R2: vec2<f32>, time: f32) -> f32 {\n\tlet bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n\treturn max(drain, min(bound, box));\n\n} \n\nfn bN(p: vec2<f32>, R2: vec2<f32>, time: f32) -> vec3<f32> {\n\tlet dx: vec3<f32> = vec3<f32>(-h, 0.0, h);\n\tlet idx: vec4<f32> = vec4<f32>(-1./h, 0., 1./h, 0.25);\n\tlet r: vec3<f32> = idx.zyw * border(p + dx.zy, R2, time) \n                     + idx.xyw * border(p + dx.xy, R2, time) \n                     + idx.yzw * border(p + dx.yz, R2, time) \n                     + idx.yxw * border(p + dx.yx, R2, time);\n\treturn vec3<f32>(normalize(r.xy),  r.z + 1e-4);\n\n} \n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    \n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n// fn mainImage( col: vec4<f32>,  pos: vec2<f32>) -> () {\n\n\tlet R2 = uni.iResolution.xy;\n\n\tlet location = vec2<i32>(i32(invocation_id.x),  i32(invocation_id.y));\n\tlet time = uni.iTime;\n\n\t// let p: vec2<i32> = vec2<i32>(pos);\n\t// let data: vec4<f32> = texel(ch0, pos);\n\n    // let p: vec2<i32> = vec2<i32>(location.x, i32(R2.y) - location.y);\n\n    let data: vec4<f32> =  textureLoad(buffer_a, i32(R2.y) - location);\n\n    let pos = vec2<f32>(f32(location.x), R2.y - f32(location.y));\n\n\tvar P: particle = getParticle(data, pos);\n\n\tlet Nb: vec3<f32> = bN(P.X, R2, time);\n\tlet bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos, R2, time));\n\tlet rho: vec4<f32> = V(pos);\n\tlet dx: vec3<f32> = vec3<f32>(-2., 0., 2.);\n\n\tlet grad: vec4<f32> = -0.5 * vec4<f32>( V(pos + dx.zy).zw - V(pos + dx.xy).zw, \n                                            V(pos + dx.yz).zw - V(pos + dx.yx).zw);\n\tlet N: vec2<f32> = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001);\n\n\tlet specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5);\n\tlet specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.);\n\n\n\tlet a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1);\n\tlet b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z));\n\tlet col0: vec3<f32> = vec3<f32>(1., 0.5, 0.);\n\tlet col1: vec3<f32> = vec3<f32>(0.1, 0.4, 1.);\n\n\n\tlet fcol: vec3<f32> = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5);\n    // var col: vec4<f32>;\n\n\tvar col: vec3<f32> = vec3<f32>(3.);\n\tcol = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a);\n\n\n\tcol = mixN(col, 0. * vec3<f32>(0.5, 0.5, 1.), bord);\n\tcol = tanh(col);\n    let col4 = vec4<f32>(col, 1.0);\n\n\t// let grey = vec4<f32>(0.8);\n\n    textureStore(texture, location, col4);\n\t// textureStore(texture, location, data);\n\n\n} \n"
  },
  {
    "path": "bin/main.rs",
    "content": "use bevy::{\n    core_pipeline::node::MAIN_PASS_DEPENDENCIES,\n    diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n    reflect::TypeUuid,\n    render::{\n        render_asset::RenderAssets,\n        render_graph::{self, RenderGraph},\n        // render_resource::*,\n        render_resource::{std140::AsStd140, *},\n        renderer::{RenderContext, RenderDevice, RenderQueue},\n        RenderApp,\n        RenderStage,\n    },\n    window::{PresentMode, WindowResized},\n};\n\nuse std::borrow::Cow;\nuse std::fs; // not compatible with WASM -->\n\nmod texture_a;\nuse texture_a::*;\n\nmod texture_b;\nuse texture_b::*;\n\nmod texture_c;\nuse texture_c::*;\n\nmod texture_d;\nuse texture_d::{extract_texture_d, queue_bind_group_d, TextureD, TextureDNode, TextureDPipeline};\n\npub const SIZE: (u32, u32) = (1280, 720);\npub const WORKGROUP_SIZE: u32 = 8;\npub const NUM_PARTICLES: u32 = 256;\n\n// const COMMON: &'static str = include_str!(\"common.wgsl\");\n\n// const IMAGE_SHADER: &'static str = include_str!(\"templates/image_template.wgsl\");\n// const IMAGE_CORE_SCRIPT: &'static str = include_str!(\"templates/image.wgsl\");\n// pub const IMAGE_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(\n//     bevy::render::render_resource::Shader::TYPE_UUID,\n//     192598017680025719,\n// );\n\n// const TEXTURE_A_SHADER: &'static str = include_str!(\"templates/texture_a_template.wgsl\");\n// const TEXTURE_A_CORE_SCRIPT: &'static str = include_str!(\"templates/texture_a.wgsl\");\n// pub const TEXTURE_A_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(\n//     bevy::render::render_resource::Shader::TYPE_UUID,\n//     986988749367675188,\n// );\n\n// const TEXTURE_B_SHADER: &'static str = include_str!(\"templates/texture_b_template.wgsl\");\n// const TEXTURE_B_CORE_SCRIPT: &'static str = include_str!(\"templates/texture_b.wgsl\");\n// pub const TEXTURE_B_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(\n//     bevy::render::render_resource::Shader::TYPE_UUID,\n//     808999425257967014,\n// );\n\n// const TEXTURE_C_SHADER: &'static str = include_str!(\"templates/texture_c_template.wgsl\");\n// const TEXTURE_C_CORE_SCRIPT: &'static str = include_str!(\"templates/texture_c.wgsl\");\n// pub const TEXTURE_C_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(\n//     bevy::render::render_resource::Shader::TYPE_UUID,\n//     819348234244712380,\n// );\n\n// const TEXTURE_D_SHADER: &'static str = include_str!(\"templates/texture_d_template.wgsl\");\n// const TEXTURE_D_CORE_SCRIPT: &'static str = include_str!(\"templates/texture_d.wgsl\");\n// pub const TEXTURE_D_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(\n//     bevy::render::render_resource::Shader::TYPE_UUID,\n//     193535259211504032,\n// );\n\nfn main() {\n    // // not sure this works on wasm\n    // let mut wgpu_options = WgpuLimits::default();\n    // wgpu_options.max_bind_groups = 5;\n    // wgpu_options.max_storage_buffers_per_shader_stage = 5;\n    // wgpu_options.max_storage_textures_per_shader_stage = 5;\n    // wgpu_options.max_inter_stage_shader_components = 5;\n\n    let mut app = App::new();\n    // app.insert_resource(wgpu_options)\n    app.insert_resource(ClearColor(Color::BLACK))\n        .insert_resource(WindowDescriptor {\n            present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .add_plugins(DefaultPlugins)\n        .add_system(bevy::input::system::exit_on_esc_system)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .add_system(update_common_uniform)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    mut images: ResMut<Assets<Image>>,\n    // mut shaders: ResMut<Assets<Shader>>,\n    asset_server: Res<AssetServer>,\n    windows: Res<Windows>,\n) {\n    commands.spawn_bundle(OrthographicCameraBundle::new_2d());\n\n    let mut image = Image::new_fill(\n        Extent3d {\n            width: SIZE.0,\n            height: SIZE.1,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba8Unorm,\n    );\n    image.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let image = images.add(image);\n\n    commands.insert_resource(MainImage(image.clone()));\n\n    commands.spawn_bundle(SpriteBundle {\n        sprite: Sprite {\n            custom_size: Some(Vec2::new(SIZE.0 as f32, SIZE.1 as f32)),\n            ..default()\n        },\n        texture: image.clone(),\n        ..default()\n    });\n\n    let window = windows.primary();\n    let mut common_uniform = CommonUniform::default();\n\n    common_uniform.i_resolution.x = window.width();\n    common_uniform.i_resolution.y = window.height();\n    commands.insert_resource(common_uniform);\n\n    //\n    //\n    //\n    // Texture A: equivalent of Buffer A in Shadertoy\n    let mut texture_a = Image::new_fill(\n        Extent3d {\n            width: SIZE.0,\n            height: SIZE.1,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        // &[255, 255, 255, 255],\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba8Unorm,\n    );\n    texture_a.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let texture_a = images.add(texture_a);\n\n    commands.insert_resource(TextureA(texture_a));\n\n    //\n    //\n    //\n    // Texture B: equivalent of Buffer B in Shadertoy\n    let mut texture_b = Image::new_fill(\n        Extent3d {\n            width: SIZE.0,\n            height: SIZE.1,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        // &[255, 255, 255, 255],\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba8Unorm,\n    );\n    texture_b.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let texture_b = images.add(texture_b);\n\n    commands.insert_resource(TextureB(texture_b));\n\n    //\n    //\n    //\n    // Texture C: equivalent of Buffer C in Shadertoy\n    let mut texture_c = Image::new_fill(\n        Extent3d {\n            width: SIZE.0,\n            height: SIZE.1,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        // &[255, 255, 255, 255],\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba8Unorm,\n    );\n    texture_c.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let texture_c = images.add(texture_c);\n\n    commands.insert_resource(TextureC(texture_c));\n\n    //\n    //\n    //\n    // Texture D: equivalent of Buffer D in Shadertoy\n    let mut texture_d = Image::new_fill(\n        Extent3d {\n            width: SIZE.0,\n            height: SIZE.1,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        // &[255, 255, 255, 255],\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba8Unorm,\n    );\n    texture_d.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let texture_d = images.add(texture_d);\n\n    commands.insert_resource(TextureD(texture_d));\n\n    //\n    //\n    //\n    // import shaders\n\n    //\n    // let image_shader_handle = import_shader(\n    //     IMAGE_SHADER,\n    //     IMAGE_SHADER_HANDLE,\n    //     &mut shaders,\n    //     IMAGE_CORE_SCRIPT,\n    //     \"{{IMAGE}}\",\n    // );\n\n    // // let image_shader = Shader::from_wgsl(Cow::from(IMAGE_SHADER));\n    // // shaders.set_untracked(IMAGE_SHADER_HANDLE.clone(), image_shader);\n    // // let image_handle: Handle<Shader> = IMAGE_SHADER_HANDLE.clone().typed();\n\n    // let texture_a_shader_handle = import_shader(\n    //     TEXTURE_A_SHADER,\n    //     TEXTURE_A_SHADER_HANDLE,\n    //     &mut shaders,\n    //     TEXTURE_A_CORE_SCRIPT,\n    //     \"{{TEXTURE_A}}\",\n    // );\n\n    // let texture_b_shader_handle = import_shader(\n    //     TEXTURE_B_SHADER,\n    //     TEXTURE_B_SHADER_HANDLE,\n    //     &mut shaders,\n    //     TEXTURE_B_CORE_SCRIPT,\n    //     \"{{TEXTURE_B}}\",\n    // );\n\n    // let texture_c_shader_handle = import_shader(\n    //     TEXTURE_C_SHADER,\n    //     TEXTURE_C_SHADER_HANDLE,\n    //     &mut shaders,\n    //     TEXTURE_C_CORE_SCRIPT,\n    //     \"{{TEXTURE_C}}\",\n    // );\n\n    // let texture_d_shader_handle = import_shader(\n    //     TEXTURE_D_SHADER,\n    //     TEXTURE_D_SHADER_HANDLE,\n    //     &mut shaders,\n    //     TEXTURE_D_CORE_SCRIPT,\n    //     \"{{TEXTURE_D}}\",\n    // );\n\n    // let example = \"minimal\";\n    // let example = \"paint\";\n    // let example = \"mixing_liquid\";\n    let example = \"paint_streams\";\n    // let example = \"simplest_detailed_fluid\";\n    // let example = \"interactive_fluid_simulation\";\n    // let example = \"liquid\"; https://www.shadertoy.com/view/WtfyDj\n\n    let all_shader_handles: ShaderHandles = make_and_load_shaders2(example, &asset_server);\n\n    commands.insert_resource(all_shader_handles);\n}\n\npub fn make_and_load_shaders(example: &str, asset_server: &Res<AssetServer>) -> ShaderHandles {\n    let image_shader_handle = asset_server.load(&format!(\"shaders/{}/image.wgsl\", example));\n    let texture_a_shader = asset_server.load(&format!(\"shaders/{}/buffer_a.wgsl\", example));\n    let texture_b_shader = asset_server.load(&format!(\"shaders/{}/buffer_b.wgsl\", example));\n    let texture_c_shader = asset_server.load(&format!(\"shaders/{}/buffer_c.wgsl\", example));\n    let texture_d_shader = asset_server.load(&format!(\"shaders/{}/buffer_d.wgsl\", example));\n\n    ShaderHandles {\n        image_shader: image_shader_handle,\n        texture_a_shader,\n        texture_b_shader,\n        texture_c_shader,\n        texture_d_shader,\n    }\n}\n\npub fn make_and_load_shaders2(example: &str, asset_server: &Res<AssetServer>) -> ShaderHandles {\n    // let image_shader_handle = asset_server.load(&format!(\"shaders/{}/image.wgsl\", example));\n    // let example_string = example.to_string();\n    //\n\n    format_and_save_shader(example, \"image\");\n    format_and_save_shader(example, \"buffer_a\");\n    format_and_save_shader(example, \"buffer_b\");\n    format_and_save_shader(example, \"buffer_c\");\n    format_and_save_shader(example, \"buffer_d\");\n\n    let image_shader_handle = asset_server.load(&format!(\"shaders/{}/image.wgsl\", example));\n    let texture_a_shader = asset_server.load(&format!(\"shaders/{}/buffer_a.wgsl\", example));\n    let texture_b_shader = asset_server.load(&format!(\"shaders/{}/buffer_b.wgsl\", example));\n    let texture_c_shader = asset_server.load(&format!(\"shaders/{}/buffer_c.wgsl\", example));\n    let texture_d_shader = asset_server.load(&format!(\"shaders/{}/buffer_d.wgsl\", example));\n\n    ShaderHandles {\n        image_shader: image_shader_handle,\n        texture_a_shader,\n        texture_b_shader,\n        texture_c_shader,\n        texture_d_shader,\n    }\n}\n\n// This function uses the std library and isn't compatible with wasm\nfn format_and_save_shader(example: &str, buffer_type: &str) {\n    let common_prelude = include_str!(\"templates/common_prelude.wgsl\");\n\n    let template = match buffer_type {\n        \"image\" => include_str!(\"templates/image_template.wgsl\"),\n        \"buffer_a\" => include_str!(\"templates/buffer_a_template.wgsl\"),\n        \"buffer_b\" => include_str!(\"templates/buffer_b_template.wgsl\"),\n        \"buffer_c\" => include_str!(\"templates/buffer_c_template.wgsl\"),\n        \"buffer_d\" => include_str!(\"templates/buffer_d_template.wgsl\"),\n        _ => include_str!(\"templates/buffer_d_template.wgsl\"),\n    };\n\n    let mut shader_content = template.replace(\"{{COMMON_PRELUDE}}\", common_prelude);\n\n    let path_to_code_block = format!(\"examples/{}/{}.wgsl\", example, buffer_type);\n    let path_to_common = format!(\"examples/{}/common.wgsl\", example);\n\n    let common = fs::read_to_string(path_to_common).expect(\"could not read file.\");\n    let image_main = fs::read_to_string(path_to_code_block).expect(\"could not read file.\");\n\n    let mut shader_content = shader_content.replace(\"{{COMMON}}\", &common);\n    shader_content = shader_content.replace(\"{{CODE_BLOCK}}\", &image_main);\n    let folder = format!(\"assets/shaders/{}\", example);\n    let path = format!(\"{}/{}.wgsl\", folder, buffer_type);\n    println!(\"{}\", path);\n    let _ = fs::create_dir(folder);\n    fs::write(path, shader_content).expect(\"Unable to write file\");\n}\n\n// fn import_shader(\n//     shader_skeleton: &str,\n//     shader_handle_untyped: HandleUntyped,\n//     shaders: &mut Assets<Shader>,\n//     shader_core_script: &str,\n//     signature: &str,\n// ) -> Handle<Shader> {\n//     //\n//     // insert common code in every shader\n//     let shader_prelude =\n//     let mut image_source = shader_skeleton.replace(\"{{COMMON}}\", &COMMON);\n//     image_source = image_source.replace(signature, shader_core_script);\n\n//     let image_shader = Shader::from_wgsl(Cow::from(image_source));\n//     shaders.set_untracked(shader_handle_untyped.clone(), image_shader.clone());\n//     shader_handle_untyped.typed()\n// }\n\n// Copied from Shadertoy.com :\n// uniform vec3      iResolution;           // viewport resolution (in pixels)\n// uniform float     iTime;                 // shader playback time (in seconds)\n// uniform float     iTimeDelta;            // render time (in seconds)\n// uniform int       iFrame;                // shader playback frame\n// uniform float     iChannelTime[4];       // channel playback time (in seconds)\n// uniform vec3      iChannelResolution[4]; // channel resolution (in pixels)\n// uniform vec4      iMouse;                // mouse pixel coords. xy: current (if MLB down), zw: click\n// uniform samplerXX iChannel0..3;          // input channel. XX = 2D/Cube\n// uniform vec4      iDate;                 // (year, month, day, time in seconds)\n// uniform float     iSampleRate;           // sound sample rate (i.e., 44100)\n\n#[derive(Component, Default, Clone, AsStd140)]\npub struct CommonUniform {\n    pub i_time: f32,\n    pub i_time_delta: f32,\n    pub i_frame: f32,\n    pub i_sample_rate: f32, // sound sample rate\n\n    pub i_mouse: Vec4,\n    pub i_resolution: Vec2,\n\n    pub i_channel_time: Vec4,\n    pub i_channel_resolution: Vec4,\n    pub i_date: [i32; 4],\n}\n\npub struct CommonUniformMeta {\n    buffer: Buffer,\n}\n\n// TODO: update date, channel time, channe l_resolution, sample_rate\nfn update_common_uniform(\n    mut common_uniform: ResMut<CommonUniform>,\n    mut window_resize_event: EventReader<WindowResized>,\n    windows: Res<Windows>,\n    time: Res<Time>,\n    mouse_button_input: Res<Input<MouseButton>>,\n) {\n    // update resolution\n    for window_resize in window_resize_event.iter() {\n        common_uniform.i_resolution.x = window_resize.width;\n        common_uniform.i_resolution.y = window_resize.height;\n    }\n\n    // update mouse position\n    let window = windows.primary();\n    if let Some(mouse_pos) = window.cursor_position() {\n        let mut mp = mouse_pos;\n        mp.x = mp.x / common_uniform.i_resolution.x;\n        mp.y = mp.y / common_uniform.i_resolution.y;\n\n        common_uniform.i_mouse.x = mp.x;\n        common_uniform.i_mouse.y = mp.y;\n        common_uniform.i_mouse.z = if mouse_button_input.pressed(MouseButton::Left) {\n            1.0\n        } else {\n            0.0\n        };\n        common_uniform.i_mouse.w = if mouse_button_input.just_pressed(MouseButton::Left) {\n            1.0\n        } else {\n            0.0\n        };\n\n        // println!(\"{:?}\", mp);\n    }\n\n    // update time\n    common_uniform.i_time = time.seconds_since_startup() as f32;\n    common_uniform.i_time_delta = time.delta_seconds() as f32;\n\n    common_uniform.i_frame += 1.0;\n}\n\npub struct ShadertoyPlugin;\n\n#[derive(Clone)]\npub struct ShaderHandles {\n    pub image_shader: Handle<Shader>,\n    pub texture_a_shader: Handle<Shader>,\n    pub texture_b_shader: Handle<Shader>,\n    pub texture_c_shader: Handle<Shader>,\n    pub texture_d_shader: Handle<Shader>,\n}\n\nimpl Plugin for ShadertoyPlugin {\n    fn build(&self, app: &mut App) {\n        // let mut common_uniform = app.world.resource_mut::<CommonUniform>();\n        // common_uniform.i_frame += 1.0;\n\n        let render_app = app.sub_app_mut(RenderApp);\n\n        let render_device = render_app.world.resource::<RenderDevice>();\n\n        let buffer = render_device.create_buffer(&BufferDescriptor {\n            label: Some(\"common uniform buffer\"),\n            size: CommonUniform::std140_size_static() as u64,\n            usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,\n            mapped_at_creation: false,\n        });\n\n        render_app\n            .insert_resource(CommonUniformMeta {\n                buffer: buffer.clone(),\n            })\n            .add_system_to_stage(RenderStage::Prepare, prepare_common_uniform)\n            .init_resource::<MainImagePipeline>()\n            .add_system_to_stage(RenderStage::Extract, extract_main_image)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group)\n            .init_resource::<TextureAPipeline>()\n            .add_system_to_stage(RenderStage::Extract, extract_texture_a)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group_a)\n            .init_resource::<TextureBPipeline>()\n            .add_system_to_stage(RenderStage::Extract, extract_texture_b)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group_b)\n            .init_resource::<TextureCPipeline>()\n            .add_system_to_stage(RenderStage::Extract, extract_texture_c)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group_c)\n            .init_resource::<TextureDPipeline>()\n            .add_system_to_stage(RenderStage::Extract, extract_texture_d)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group_d);\n\n        let mut render_graph = render_app.world.resource_mut::<RenderGraph>();\n\n        render_graph.add_node(\"main_image\", MainNode::default());\n        render_graph.add_node(\"texture_a\", TextureANode::default());\n        render_graph.add_node(\"texture_b\", TextureBNode::default());\n        render_graph.add_node(\"texture_c\", TextureCNode::default());\n        render_graph.add_node(\"texture_d\", TextureDNode::default());\n\n        render_graph\n            .add_node_edge(\"texture_a\", \"texture_b\")\n            .unwrap();\n\n        render_graph\n            .add_node_edge(\"texture_b\", \"texture_c\")\n            .unwrap();\n\n        render_graph\n            .add_node_edge(\"texture_c\", \"texture_d\")\n            .unwrap();\n\n        render_graph\n            .add_node_edge(\"texture_d\", \"main_image\")\n            .unwrap();\n\n        render_graph\n            .add_node_edge(\"main_image\", MAIN_PASS_DEPENDENCIES)\n            .unwrap();\n    }\n}\n\npub struct MainImagePipeline {\n    main_image_group_layout: BindGroupLayout,\n}\n\nimpl FromWorld for MainImagePipeline {\n    fn from_world(world: &mut World) -> Self {\n        let main_image_group_layout =\n            world\n                .resource::<RenderDevice>()\n                .create_bind_group_layout(&BindGroupLayoutDescriptor {\n                    label: Some(\"main_layout\"),\n                    entries: &[\n                        BindGroupLayoutEntry {\n                            binding: 0,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::Buffer {\n                                ty: BufferBindingType::Uniform,\n                                has_dynamic_offset: false,\n                                min_binding_size: BufferSize::new(\n                                    CommonUniform::std140_size_static() as u64,\n                                ),\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 1,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 2,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 3,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 4,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 5,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                    ],\n                });\n\n        MainImagePipeline {\n            main_image_group_layout,\n        }\n    }\n}\n\n#[derive(Deref)]\nstruct MainImage(Handle<Image>);\n\nstruct MainImageBindGroup {\n    main_image_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n// write the extracted common uniform into the corresponding uniform buffer\npub fn prepare_common_uniform(\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n    render_queue: Res<RenderQueue>,\n    common_uniform: Res<CommonUniform>,\n) {\n    use bevy::render::render_resource::std140::Std140;\n    let std140_common_uniform = common_uniform.as_std140();\n    let bytes = std140_common_uniform.as_bytes();\n\n    render_queue.write_buffer(\n        &common_uniform_meta.buffer,\n        0,\n        bevy::core::cast_slice(&bytes),\n    );\n}\n\nfn extract_main_image(\n    mut commands: Commands,\n    image: Res<MainImage>,\n    common_uniform: Res<CommonUniform>,\n    all_shader_handles: Res<ShaderHandles>,\n) {\n    // insert common uniform only once\n    commands.insert_resource(common_uniform.clone());\n\n    commands.insert_resource(MainImage(image.clone()));\n\n    commands.insert_resource(all_shader_handles.clone());\n}\n\nfn queue_bind_group(\n    mut commands: Commands,\n    pipeline: Res<MainImagePipeline>,\n\n    gpu_images: Res<RenderAssets<Image>>,\n    main_image: Res<MainImage>,\n    texture_a_image: Res<TextureA>,\n    texture_b_image: Res<TextureB>,\n    texture_c_image: Res<TextureC>,\n    texture_d_image: Res<TextureD>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    all_shader_handles: Res<ShaderHandles>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.main_image_group_layout.clone()]),\n        shader: all_shader_handles.image_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.main_image_group_layout.clone()]),\n        shader: all_shader_handles.image_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let main_view = &gpu_images[&main_image.0];\n    let texture_a_view = &gpu_images[&texture_a_image.0];\n    let texture_b_view = &gpu_images[&texture_b_image.0];\n    let texture_c_view = &gpu_images[&texture_c_image.0];\n    let texture_d_view = &gpu_images[&texture_d_image.0];\n\n    let main_image_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: Some(\"main_bind_group\"),\n        layout: &pipeline.main_image_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&texture_a_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&texture_b_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&texture_c_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 4,\n                resource: BindingResource::TextureView(&texture_d_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 5,\n                resource: BindingResource::TextureView(&main_view.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(MainImageBindGroup {\n        main_image_bind_group,\n        init_pipeline: init_pipeline.clone(),\n        update_pipeline: update_pipeline.clone(),\n    });\n}\n\npub enum ShadertoyState {\n    Loading,\n    Init,\n    Update,\n}\n\npub struct MainNode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for MainNode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for MainNode {\n    fn update(&mut self, world: &mut World) {\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let bind_group = world.resource::<MainImageBindGroup>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<MainImageBindGroup>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor {\n                label: Some(\"main_compute_pass\"),\n            });\n\n        pass.set_bind_group(0, &bind_group.main_image_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "bin/templates/buffer_a_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n{{COMMON}}\n\n{{CODE_BLOCK}}"
  },
  {
    "path": "bin/templates/buffer_b_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n{{COMMON}}\n\n{{CODE_BLOCK}}"
  },
  {
    "path": "bin/templates/buffer_c_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n{{COMMON}}\n\n{{CODE_BLOCK}}"
  },
  {
    "path": "bin/templates/buffer_d_template.wgsl",
    "content": "\n{{COMMON_PRELUDE}}\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n{{COMMON}}\n\n{{CODE_BLOCK}}\n"
  },
  {
    "path": "bin/templates/common.wgsl",
    "content": ""
  },
  {
    "path": "bin/templates/common_prelude.wgsl",
    "content": "struct CommonUniform {\n    iTime: f32;\n    iTimeDelta: f32;\n    iFrame: f32;\n    iSampleRate: f32;\n\n    iMouse: vec4<f32>;\n    iResolution: vec2<f32>;\n    \n\n    iChannelTime: vec4<f32>;\n    iChannelResolution: vec4<f32>;\n    iDate: vec4<i32>;\n};\n\n[[group(0), binding(0)]]\nvar<uniform> uni: CommonUniform;"
  },
  {
    "path": "bin/templates/image.wgsl",
    "content": "fn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n\n\n// fn get(location: vec2<i32>, offset_x: i32, offset_y: i32) -> i32 {\n//     let value: vec4<f32> = textureLoad(texture, location + vec2<i32>(offset_x, offset_y));\n//     return i32(value.x);\n// }\n\n// fn count_alive(location: vec2<i32>) -> i32 {\n//     return get(location, -1, -1) +\n//            get(location, -1,  0) +\n//            get(location, -1,  1) +\n//            get(location,  0, -1) +\n//            get(location,  0,  1) +\n//            get(location,  1, -1) +\n//            get(location,  1,  0) +\n//            get(location,  1,  1);\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let n_alive = count_alive(location);\n    // let color = vec4<f32>(f32(n_alive) / 8.0);\n\n    // var alive: bool;\n    // if (n_alive == 3) {\n    //     alive = true;\n    // } else if (n_alive == 2) {\n    //     let currently_alive = get(location, 0, 0);\n    //     alive = bool(currently_alive);\n    // } else {\n    //     alive = false;\n    // }\n\n    var alive = true;\n\n    // let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    // if (value.x > 0.51) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_b, vec2<i32>(0,1));\n    // if (value.x > 0.74) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_c, vec2<i32>(0,1));\n    // if (value.x > 0.61) {\n    //     alive = false;\n    // }\n\n    let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    if (value.x > 0.79) {\n        alive = false;\n    }\n\n    // if (ga > 2) {\n    //     alive = true;\n    // }\n\n    // if (uni.iTime > 1.0) {\n    //     alive = false;\n    // }\n\n    // alive = false;\n\n    storageBarrier();\n\n    textureStore(texture, location, vec4<f32>(f32(alive)));\n}"
  },
  {
    "path": "bin/templates/image_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n[[group(0), binding(1)]]\nvar buffer_a: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(2)]]\nvar buffer_b: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(3)]]\nvar buffer_c: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(4)]]\nvar buffer_d: texture_storage_2d<rgba8unorm, read_write>;\n\n[[group(0), binding(5)]]\nvar texture: texture_storage_2d<rgba8unorm, read_write>;\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     let color = vec4<f32>(f32(0));\n//     textureStore(texture, location, color);\n// }\n\n{{COMMON}}\n\n\n{{CODE_BLOCK}}"
  },
  {
    "path": "bin/test_renderdoc.d",
    "content": "/home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/target/release/test_renderdoc: /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/main.rs /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/templates/buffer_a_template.wgsl /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/templates/buffer_b_template.wgsl /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/templates/buffer_c_template.wgsl /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/templates/buffer_d_template.wgsl /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/templates/common_prelude.wgsl /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/templates/image_template.wgsl /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/texture_a.rs /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/texture_b.rs /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/texture_c.rs /home/eliotbolduc/Documents/rust/bevy_shadertoy_wgsl/src/texture_d.rs\n"
  },
  {
    "path": "bin/texture_a.rs",
    "content": "use bevy::{\n    prelude::*,\n    render::{\n        render_asset::RenderAssets,\n        render_graph::{self},\n        render_resource::{std140::AsStd140, *},\n        renderer::{RenderContext, RenderDevice},\n    },\n};\n\nuse std::borrow::Cow;\n\nuse crate::texture_b::TextureB;\nuse crate::texture_c::TextureC;\nuse crate::texture_d::TextureD;\nuse crate::{\n    CommonUniform, CommonUniformMeta, ShaderHandles, ShadertoyState, SIZE, WORKGROUP_SIZE,\n};\n\nstruct TextureABindGroup {\n    // texture_b_bind_group: BindGroup,\n    texture_a_bind_group: BindGroup,\n    // common_uniform_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n// pub struct CommonUniformMetaA {\n//     // buffer: UniformVec<CommonUniform>,\n//     pub buffer: Buffer,\n//     // bind_group: Option<BindGroup>,\n// }\n\n#[derive(Deref)]\npub struct TextureA(pub Handle<Image>);\n\npub struct TextureAPipeline {\n    texture_a_bind_group_layout: BindGroupLayout,\n}\n\nimpl FromWorld for TextureAPipeline {\n    fn from_world(world: &mut World) -> Self {\n        let texture_a_bind_group_layout = world\n            .resource::<RenderDevice>()\n            .create_bind_group_layout(&BindGroupLayoutDescriptor {\n                label: Some(\"layout_a\"),\n                entries: &[\n                    BindGroupLayoutEntry {\n                        binding: 0,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Buffer {\n                            ty: BufferBindingType::Uniform,\n                            has_dynamic_offset: false,\n                            min_binding_size: BufferSize::new(\n                                CommonUniform::std140_size_static() as u64\n                            ),\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 1,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 2,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 3,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 4,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                ],\n            });\n\n        TextureAPipeline {\n            texture_a_bind_group_layout,\n        }\n    }\n}\n\npub fn extract_texture_a(mut commands: Commands, image: Res<TextureA>) {\n    commands.insert_resource(TextureA(image.clone()));\n}\n\npub fn queue_bind_group_a(\n    mut commands: Commands,\n    pipeline: Res<TextureAPipeline>,\n    gpu_images: Res<RenderAssets<Image>>,\n\n    texture_a: Res<TextureA>,\n    texture_b: Res<TextureB>,\n    texture_c: Res<TextureC>,\n    texture_d: Res<TextureD>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    all_shader_handles: Res<ShaderHandles>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.texture_a_bind_group_layout.clone()]),\n        shader: all_shader_handles.texture_a_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.texture_a_bind_group_layout.clone()]),\n        shader: all_shader_handles.texture_a_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    // let texture_a_view = &gpu_images[&texture_a.0];\n    let view_a = &gpu_images[&texture_a.0];\n    let view_b = &gpu_images[&texture_b.0];\n    let view_c = &gpu_images[&texture_c.0];\n    let view_d = &gpu_images[&texture_d.0];\n\n    let texture_a_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: Some(\"texture_a_bind_group\"),\n        layout: &pipeline.texture_a_bind_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&view_a.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&view_b.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&view_c.texture_view),\n            },\n            BindGroupEntry {\n                binding: 4,\n                resource: BindingResource::TextureView(&view_d.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(TextureABindGroup {\n        texture_a_bind_group,\n        init_pipeline,\n        update_pipeline,\n    });\n}\n\npub struct TextureANode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for TextureANode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for TextureANode {\n    fn update(&mut self, world: &mut World) {\n        let bind_group = world.resource::<TextureABindGroup>();\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<TextureABindGroup>();\n\n        // let texture_b_bind_group = &bind_group.texture_b_bind_group;\n        let texture_a_bind_group = &bind_group.texture_a_bind_group;\n\n        // let common_uni_bind_group = bind_group.common_uniform_bind_group.clone();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor::default());\n\n        // pass.set_bind_group(0, &common_uni_bind_group, &[]);\n        pass.set_bind_group(0, texture_a_bind_group, &[]);\n\n        // pass.set_bind_group(1, texture_b_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "bin/texture_b.rs",
    "content": "use bevy::{\n    prelude::*,\n    render::{\n        render_asset::RenderAssets,\n        render_graph::{self},\n        // render_resource::*,\n        render_resource::{std140::AsStd140, *},\n        renderer::{RenderContext, RenderDevice},\n    },\n};\n\nuse crate::texture_a::*;\n\nuse std::borrow::Cow;\n\nuse crate::{\n    CommonUniform, CommonUniformMeta, ShaderHandles, ShadertoyState, SIZE, WORKGROUP_SIZE,\n};\n\nstruct TextureBBindGroup {\n    texture_b_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n#[derive(Deref)]\npub struct TextureB(pub Handle<Image>);\n\npub struct TextureBPipeline {\n    texture_b_bind_group_layout: BindGroupLayout,\n}\n\nimpl FromWorld for TextureBPipeline {\n    fn from_world(world: &mut World) -> Self {\n        let texture_b_bind_group_layout = world\n            .resource::<RenderDevice>()\n            .create_bind_group_layout(&BindGroupLayoutDescriptor {\n                label: Some(\"layout_b\"),\n                entries: &[\n                    BindGroupLayoutEntry {\n                        binding: 0,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Buffer {\n                            ty: BufferBindingType::Uniform,\n                            has_dynamic_offset: false,\n                            min_binding_size: BufferSize::new(\n                                CommonUniform::std140_size_static() as u64\n                            ),\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 1,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 2,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                ],\n            });\n\n        TextureBPipeline {\n            texture_b_bind_group_layout,\n        }\n    }\n}\n\npub fn extract_texture_b(mut commands: Commands, image: Res<TextureB>) {\n    commands.insert_resource(TextureB(image.clone()));\n}\n\npub fn queue_bind_group_b(\n    mut commands: Commands,\n    pipeline: Res<TextureBPipeline>,\n    gpu_images: Res<RenderAssets<Image>>,\n    texture_b: Res<TextureB>,\n    texture_a: Res<TextureA>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    all_shader_handles: Res<ShaderHandles>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.texture_b_bind_group_layout.clone()]),\n        shader: all_shader_handles.texture_b_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.texture_b_bind_group_layout.clone()]),\n        shader: all_shader_handles.texture_b_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let view_a = &gpu_images[&texture_a.0];\n    let view_b = &gpu_images[&texture_b.0];\n\n    let texture_b_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: Some(\"binding b\"),\n        layout: &pipeline.texture_b_bind_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&view_a.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&view_b.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(TextureBBindGroup {\n        texture_b_bind_group,\n        init_pipeline,\n        update_pipeline,\n    });\n}\n\npub struct TextureBNode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for TextureBNode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for TextureBNode {\n    fn update(&mut self, world: &mut World) {\n        let bind_group = world.resource::<TextureBBindGroup>();\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<TextureBBindGroup>();\n\n        let texture_b_bind_group = &bind_group.texture_b_bind_group;\n        // let texture_a_bind_group = &bind_group.texture_a_bind_group;\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor::default());\n\n        // pass.set_bind_group(0, texture_a_bind_group, &[]);\n        pass.set_bind_group(0, texture_b_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "bin/texture_c.rs",
    "content": "use bevy::{\n    prelude::*,\n    render::{\n        render_asset::RenderAssets,\n        render_graph::{self},\n        render_resource::{std140::AsStd140, *},\n        renderer::{RenderContext, RenderDevice},\n    },\n};\n\nuse std::borrow::Cow;\n\nuse crate::texture_a::TextureA;\nuse crate::texture_b::TextureB;\nuse crate::{\n    CommonUniform, CommonUniformMeta, ShaderHandles, ShadertoyState, SIZE, WORKGROUP_SIZE,\n};\n\nstruct TextureCBindGroup {\n    texture_c_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n#[derive(Deref)]\npub struct TextureC(pub Handle<Image>);\n\npub struct TextureCPipeline {\n    texture_c_bind_group_layout: BindGroupLayout,\n}\n\nimpl FromWorld for TextureCPipeline {\n    fn from_world(world: &mut World) -> Self {\n        let texture_c_bind_group_layout = world\n            .resource::<RenderDevice>()\n            .create_bind_group_layout(&BindGroupLayoutDescriptor {\n                label: Some(\"layout_c\"),\n                entries: &[\n                    BindGroupLayoutEntry {\n                        binding: 0,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Buffer {\n                            ty: BufferBindingType::Uniform,\n                            has_dynamic_offset: false,\n                            min_binding_size: BufferSize::new(\n                                CommonUniform::std140_size_static() as u64\n                            ),\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 1,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 2,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 3,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba8Unorm,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                ],\n            });\n\n        // let shader = world\n        //     .resource::<AssetServer>()\n        //     .load(\"shaders/texture_b.wgsl\");\n\n        TextureCPipeline {\n            texture_c_bind_group_layout,\n        }\n    }\n}\n\npub fn extract_texture_c(mut commands: Commands, image: Res<TextureC>) {\n    commands.insert_resource(TextureC(image.clone()));\n}\n\npub fn queue_bind_group_c(\n    mut commands: Commands,\n    pipeline: Res<TextureCPipeline>,\n    gpu_images: Res<RenderAssets<Image>>,\n    texture_a_image: Res<TextureA>,\n    texture_b_image: Res<TextureB>,\n    texture_c_image: Res<TextureC>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    all_shader_handles: Res<ShaderHandles>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.texture_c_bind_group_layout.clone()]),\n        shader: all_shader_handles.texture_c_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.texture_c_bind_group_layout.clone()]),\n        shader: all_shader_handles.texture_c_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let texture_a_view = &gpu_images[&texture_a_image.0];\n    let texture_b_view = &gpu_images[&texture_b_image.0];\n    let texture_c_view = &gpu_images[&texture_c_image.0];\n\n    let texture_c_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: Some(\"bind_group_c\"),\n        layout: &pipeline.texture_c_bind_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&texture_a_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&texture_b_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&texture_c_view.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(TextureCBindGroup {\n        texture_c_bind_group,\n        init_pipeline,\n        update_pipeline,\n    });\n}\n\npub struct TextureCNode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for TextureCNode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for TextureCNode {\n    fn update(&mut self, world: &mut World) {\n        let bind_group = world.resource::<TextureCBindGroup>();\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<TextureCBindGroup>();\n\n        let texture_c_bind_group = &bind_group.texture_c_bind_group;\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor::default());\n\n        pass.set_bind_group(0, texture_c_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "bin/texture_d.rs",
    "content": "use bevy::{\n    prelude::*,\n    render::{\n        render_asset::RenderAssets,\n        render_graph::{self},\n        render_resource::{std140::AsStd140, *},\n        renderer::{RenderContext, RenderDevice},\n    },\n};\n\nuse std::borrow::Cow;\n\nuse crate::{\n    CommonUniform, CommonUniformMeta, ShaderHandles, ShadertoyState, SIZE, WORKGROUP_SIZE,\n};\n\nuse crate::texture_a::TextureA;\nuse crate::texture_b::TextureB;\nuse crate::texture_c::TextureC;\n\npub struct TextureDPipeline {\n    texture_d_group_layout: BindGroupLayout,\n}\n\nimpl FromWorld for TextureDPipeline {\n    fn from_world(world: &mut World) -> Self {\n        let texture_d_group_layout =\n            world\n                .resource::<RenderDevice>()\n                .create_bind_group_layout(&BindGroupLayoutDescriptor {\n                    label: None,\n                    entries: &[\n                        BindGroupLayoutEntry {\n                            binding: 0,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::Buffer {\n                                ty: BufferBindingType::Uniform,\n                                has_dynamic_offset: false,\n                                min_binding_size: BufferSize::new(\n                                    CommonUniform::std140_size_static() as u64,\n                                ),\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 1,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 2,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 3,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                        BindGroupLayoutEntry {\n                            binding: 4,\n                            visibility: ShaderStages::COMPUTE,\n                            ty: BindingType::StorageTexture {\n                                access: StorageTextureAccess::ReadWrite,\n                                format: TextureFormat::Rgba8Unorm,\n                                view_dimension: TextureViewDimension::D2,\n                            },\n                            count: None,\n                        },\n                    ],\n                });\n\n        TextureDPipeline {\n            texture_d_group_layout,\n        }\n    }\n}\n\n#[derive(Deref)]\npub struct TextureD(pub Handle<Image>);\n\nstruct TextureDBindGroup {\n    texture_d_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\npub fn extract_texture_d(mut commands: Commands, image: Res<TextureD>) {\n    commands.insert_resource(TextureD(image.clone()));\n}\n\npub fn queue_bind_group_d(\n    mut commands: Commands,\n    pipeline: Res<TextureDPipeline>,\n\n    gpu_images: Res<RenderAssets<Image>>,\n    texture_a_image: Res<TextureA>,\n    texture_b_image: Res<TextureB>,\n    texture_c_image: Res<TextureC>,\n    texture_d_image: Res<TextureD>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n\n    all_shader_handles: Res<ShaderHandles>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.texture_d_group_layout.clone()]),\n        shader: all_shader_handles.texture_d_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.texture_d_group_layout.clone()]),\n        shader: all_shader_handles.texture_d_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let texture_a_view = &gpu_images[&texture_a_image.0];\n    let texture_b_view = &gpu_images[&texture_b_image.0];\n    let texture_c_view = &gpu_images[&texture_c_image.0];\n    let texture_d_view = &gpu_images[&texture_d_image.0];\n\n    let texture_d_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: None,\n        layout: &pipeline.texture_d_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&texture_a_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&texture_b_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&texture_c_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 4,\n                resource: BindingResource::TextureView(&texture_d_view.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(TextureDBindGroup {\n        texture_d_bind_group,\n        init_pipeline: init_pipeline.clone(),\n        update_pipeline: update_pipeline.clone(),\n    });\n}\n\n#[derive(Clone, Hash, PartialEq, Eq)]\npub struct MainUpdatePipelineKey {\n    common_code: String,\n}\n\nimpl Default for MainUpdatePipelineKey {\n    fn default() -> Self {\n        MainUpdatePipelineKey {\n            common_code: Default::default(),\n        }\n    }\n}\n\npub struct TextureDNode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for TextureDNode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for TextureDNode {\n    fn update(&mut self, world: &mut World) {\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let bind_group = world.resource::<TextureDBindGroup>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<TextureDBindGroup>();\n\n        // let texture_a_bind_group = &bind_group.texture_a_bind_group;\n        // let texture_b_bind_group = &bind_group.texture_b_bind_group;\n        // let texture_c_bind_group = &bind_group.texture_c_bind_group;\n        let texture_d_bind_group = &bind_group.texture_d_bind_group;\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor::default());\n\n        pass.set_bind_group(0, texture_d_bind_group, &[]);\n        // pass.set_bind_group(1, texture_b_bind_group, &[]);\n        // pass.set_bind_group(2, texture_c_bind_group, &[]);\n        // pass.set_bind_group(3, texture_d_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch(SIZE.0 / WORKGROUP_SIZE, SIZE.1 / WORKGROUP_SIZE, 1);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "examples/debugger/buffer_a.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "examples/debugger/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/debugger/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/debugger/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/debugger/common.wgsl",
    "content": "// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}"
  },
  {
    "path": "examples/debugger/image.wgsl",
    "content": "// Why are the charaacters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\n// type ivec2 = vec2<i32>;\n// type v2 = vec2<f32>;\n\n// let backColor: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n// var<private> R: vec2<f32>;\n// var<private> uv: vec2<f32> ;\n// var<private> tp: vec2<f32> ;\n// var<private> alignment: vec4<f32>; // north, east, south, west\n// var<private> font_size: f32;\n// var<private> dotColor: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\n// var<private> drawColor: vec3<f32> = vec3<f32>(1., 1., 0.);\n// var<private> vColor: vec3<f32> = backColor;\n// var<private> aspect: f32 = 1.;\n// var<private> pixelPos: vec2<f32> = vec2<f32>(0., 0.);\n// var<private> mousePos: vec2<f32> = vec2<f32>(200., 200.);\n// var<private> lp: vec2<f32> = vec2<f32>(0.5, 0.5);\n// var<private> mp: vec2<f32> = vec2<f32>(0.5, 0.5);\n// var<private> resolution: vec2<f32>;\n\n\n// let FONT_SPACE: f32 = 0.5;\n// let headColor: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\n// let mpColor: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\n// let mxColor: vec3<f32> = vec3<f32>(1., 0., 0.);\n// let myColor: vec3<f32> = vec3<f32>(0., 1., 0.);\n// let font_png_size: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\n\n// fn chara(ch: i32) -> f32 {\n\n//     let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n// \tlet q = clamp(tp, v2(0.), v2(1.)) / 16. + fr ;\n// \tlet inverted_q = v2(q.x, 1. - q.y);\n\n// \t// // There is aliasing on the charaacters\n// \t// let f = textureSampleGrad(font_texture,\n//     //                  font_texture_sampler,\n//     //                  inverted_q,\n//     //                   vec2<f32>(1.0, 0.0),\n//     //                  vec2<f32>(0.0, 1.0));\n\n// \t// using textureLoad without sampler\n//     let q1 = ivec2(font_png_size  * q );\n// \tlet y_inverted_q1 = ivec2(q1.x, i32(font_png_size.y) - q1.y);\n\n// \tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n// \t// smoothing out the aliasing\n// \tlet dx = vec2<i32>(1, 0);\n// \tlet dy = vec2<i32>(0, 1);\n\n// \tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n// \tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n// \tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n// \tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n// \tlet rp = 0.25;\n// \tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n// \treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n// } \n\n// fn SetTextPosition(x: f32, y: f32)  {\n// \ttp =  10. * uv;\n// \ttp.x = tp.x + 17. - x;\n// \ttp.y = tp.y - 9.4 + y;\n// } \n\n// fn SetTextPositionAbs(x: f32, y: f32)  {\n// \ttp.x = 10. * uv.x - x;\n// \ttp.y = 10. * uv.y - y;\n// } \n\n// fn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n// \tvar c: f32 = 0.;\n// \t*value = fract(*value) * 10.;\n\n// \tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n// \t\tc = c + (chara(48 + i32(*value)));\n// \t\ttp.x = tp.x - (0.5);\n// \t\t*digits = *digits - (1);\n// \t\t*value = fract(*value) * 10.;\n\n// \t\tif (*digits <= 0 || *value == 0.) {\t\t\n//             break;\n//         }\n// \t}\n\n// \ttp.x = tp.x - (0.5 * f32(*digits));\n// \treturn c;\n// } \n\n// fn maxInt(a: i32, b: i32) -> i32 {\n//     var ret: i32;\n//     if (a > b) { ret = a; } else { ret = b; };\n// \treturn ret;\n// } \n\n// fn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n// \tvar c: f32 = 0.;\n// \tif (*value < 0) {\n// \t\t*value = -*value;\n// \t\tif (*minDigits < 1) {\t\t\n// \t\t\t*minDigits = 1;\n// \t\t} else { \n// \t\t\t*minDigits = *minDigits - 1;\n// \t\t}\n// \t\tc = c + (chara(45));\n// \t\ttp.x = tp.x - (FONT_SPACE);\n\n// \t}\n// \tvar fn2: i32 = *value;\n// \tvar digits: i32 = 1;\n\n// \tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n// \t\tfn2 = fn2 / (10);\n// \t\tif (fn2 == 0) {\t\tbreak; }\n// \t\tdigits = digits + 1;\n// \t}\n\n// \tdigits = maxInt(*minDigits, digits);\n// \ttp.x = tp.x - (0.5 * f32(digits));\n\n// \tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n// \t\ttp.x = tp.x + (0.5);\n// \t\tc = c + (chara(48 + *value % 10));\n// \t\t*value = *value / (10);\n// \t\tif (ni >= digits) {\t\tbreak; }\n// \t}\n\n// \ttp.x = tp.x - (0.5 * f32(digits));\n// \treturn c;\n// } \n\n// fn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n// \tvar c: f32 = 0.;\n// \tlet original_value: i32 = *value;\n\n// \tif (*value < 0) {\n// \t\t*value = -*value;\n// \t\tif (*minDigits < 1) {\t\t\n// \t\t\t*minDigits = 1;\n// \t\t} else { \n// \t\t\t*minDigits = *minDigits - 1;\n// \t\t}\n// \t\t// tp.x = tp.x + (FONT_SPACE);\n// \t\t// c = c + (chara(45));\n\t\t\n\n// \t}\n// \tvar fn2: i32 = *value;\n// \tvar digits: i32 = 1;\n\n// \tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n// \t\tfn2 = fn2 / (10);\n// \t\tif (fn2 == 0) {\t\tbreak; }\n// \t\tdigits = digits + 1;\n// \t}\n\n// \tdigits = maxInt(*minDigits, digits);\n// \t// tp.x = tp.x - (0.5 * f32(digits));\n\n// \tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n// \t\ttp.x = tp.x + (0.5);\n// \t\tc = c + (chara(48 + *value % 10));\n// \t\t*value = *value / (10);\n// \t\tif (ni == 0) {\t\tbreak; }\n// \t}\n\n// \tif (original_value < 0) {\n// \t\ttp.x = tp.x + (FONT_SPACE);\n// \t\tc = c + (chara(45));\n// \t}\n\n// \t// tp.x = tp.x + (0.5 * f32(digits));\n// \treturn c;\n// } \n\n// // fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n// fn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n// \t// in case of 0.099999..., round up to 0.1000000\n// \tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n// \tlet tpx: f32 = tp.x - 0.5 * f32(maxDigits);\n// \tvar c: f32 = 0.;\n// \tif (value < 0.) {\n// \t\tc = chara(45);\n// \t\tvalue = -value;\n// \t}\n// \ttp.x = tp.x - (0.5);\n//     var ival = i32(value);\n\n//     var one: i32 = 1;\n\n// \tc = c + (drawInt(&ival, &one));\n// \tc = c + (chara(46));\n// \ttp.x = tp.x - (FONT_SPACE);\n\n//     var frac_val = fract(value);\n// \tc = c + (drawFract(&frac_val, prec));\n// \ttp.x = min(tp.x, tpx);\n\n// \treturn c;\n// }\n\n// fn drawFloat_f32(value:  f32) -> f32 {\n//     var two: i32 = 2;\n// \treturn drawFloat(value, &two, 5);\n// } \n\n// fn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n// \treturn drawFloat(value, prec, 2);\n// } \n\n// fn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n//     var one: i32 = 1;\n// \treturn drawIntBackwards(value, &one);\n// } \n\n// fn drawInt_i32(value: ptr<function, i32>) -> f32 {\n//     var one: i32 = 1;\n// \treturn drawInt(value, &one);\n// } \n\n\n\n\n\n// fn SetColor(red: f32, green: f32, blue: f32)  {\n// \tdrawColor = vec3<f32>(red, green, blue);\n// } \n\n// fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n// \t// vColor = mix(vColor, drawColor, drawFloat_f32_prec(fValue, decimalPlaces));\n// \tvColor = mix(vColor, drawColor, drawFloat(fValue, decimalPlaces, maxDigits));\n// \ttp.x = tp.x - (FONT_SPACE);\n// ;\n// } \n\n// fn WriteFloatBox(\n// \tfValue: f32, \n// \tmaxDigits: i32, \n// \tdecimalPlaces: i32, \n// \talpha: f32\n// )  {\n// \tvar decs = decimalPlaces;\n// \tvColor = mix(vColor, drawColor, drawFloat(fValue, &decs, maxDigits) * alpha);\n// \ttp.x = tp.x - (FONT_SPACE);\n// ;\n// } \n\n// fn WriteInteger(iValue: ptr<function, i32>)  {\n// \tvColor = mix(vColor, drawColor, drawInt_i32(iValue));\n// \ttp.x = tp.x - (FONT_SPACE);\n\n// } \n\n// fn WriteIntegerBack(iValue: ptr<function, i32>)  {\n// \tvColor = mix(vColor, drawColor, drawInt_i32_back(iValue));\n// \ttp.x = tp.x + (FONT_SPACE);\n\n// } \n\n\n\n// fn WriteFPS()  {\n// \tvar fps: f32 = f32(uni.iSampleRate);\n// \tSetColor(0.8, 0.6, 0.3);\n// \tvar max_digits_one = 1;\n// \tWriteFloat(fps, 5, &max_digits_one);\n// \tvar c: f32 = 0.;\n// \tc = c + (chara(102));\n// \ttp.x = tp.x - (FONT_SPACE);\n\n// \tc = c + (chara(112));\n// \ttp.x = tp.x - (FONT_SPACE);\n\n// \tc = c + (chara(115));\n// \ttp.x = tp.x - (FONT_SPACE);\n// \t// let c2 = smoothstep(0.0, 1.0, c );\n\n// \tvColor = mix(vColor, drawColor, c);\n// } \n\n// fn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n// \tlet digits: i32 = 3;\n// \tlet radius: f32 = resolution.x / 400.;\n// \tif (uni.iMouse.z > 0.) { dotColor = mpColor; }\n// \tlet r: f32 = length(abs(mPos.xy) - pixelPos) - radius;\n// \t// vColor = vColor + (mix(vec3<f32>(0.), dotColor, 1. - clamp(r, 0., 1.)));\n\n// \tvar max_digits_three: i32 = 3;\n// \tvar mposxi: i32 = i32(mPos.x);\n// \tvar mposyi: i32 = i32(mPos.y);\n\n// \tvar mposx: f32 = (mPos.x);\n// \tvar mposy: f32 = (mPos.y);\n\n\n// \tlet x_pos = alignment.y - 1. * FONT_SPACE;\n\t\t\n// \tSetTextPositionAbs(\n// \t\t x_pos,\n// \t\t y_pos,\n// \t);\n\n// \tdrawColor = myColor;\n// \tWriteIntegerBack(&mposyi);\n\n// \tSetTextPositionAbs(\n// \t\t x_pos - 7. *  FONT_SPACE,\n// \t\t y_pos,\n// \t);\n\n// \tdrawColor = mxColor;\n\n// \tWriteIntegerBack(&mposxi);\n\n// } \n\n\n// fn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n//   var x = r.x;\n//   var y = r.y;\n//   x = select(r.z, r.x, p.x > 0.);\n//   y = select(r.w, r.y, p.x > 0.);\n//   x  = select(y, x, p.y > 0.);\n//   let q = abs(p) - b + x;\n//   return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n// }\n\n\n\n// fn WriteRGBAValues(\n// \tlocation: vec2<i32>, \n// \tvalue: vec4<f32>, \n// \tscreen_poz: vec2<f32>,\n// \talpha: f32,\n//  )  {\n// \tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect, 1.0);\n// \tlet window_ajusted = uni.iResolution / v2(960., 600.);\n\n// \tlet box_pos = vec2<f32>(alignment.w, alignment.x - FONT_SPACE ) / 10.;\n// \t// let box_pos = mp;\n\n// \t// // box location follows mouse position\n// \t// let box_location = v2(\n// \t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect / 1.6 ) , \n// \t// \tuni.iMouse.y - 48. * window_ajusted.y\n// \t// );\n\n\n// \tlet box_location  = v2(\n// \t\t100. * window_ajusted.x /  ( aspect / 1.6 ) , \n// \t\tuni.iResolution.y - 60. * window_ajusted.y,\n// \t);\n\t\n// \tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect, 1.) ;\n\n// \tlet d_box = sdRoundedBox(\n// \t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n// \t\t vec2<f32>(73. /  ( aspect / 1.6 ), 75.) * window_ajusted, \n// \t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n// \t);\n\n// \t// let alpha = 0.225;\n// \tlet decimal_places = 3;\n// \tSetColor(1., 1., 1.);\n// \tvar c: f32 = 0.;\n// \tlet lspace = 0.8;\n\n// \tlet bg_color = vec3<f32>(.8, .7, .9);\n// \tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n// \t// red\n// \tSetTextPosition(\n// \t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n// \t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n// \t) ;\n// \tc = c + (chara(114)); // r\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tc = c + (chara(58)); // colon\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n// \t// green\n// \tSetTextPosition(\n// \t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n// \t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n// \t) ;\n// \tc = c + (chara(103)); // g\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tc = c + (chara(58)); // colon\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n// \t// blue\n// \tSetTextPosition(\n// \t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n// \t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n// \t\t) ;\n// \tc = c + (chara(98)); // b\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tc = c + (chara(58)); // colon\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n// \t// alpha\n// \tSetTextPosition(\n// \t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n// \t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n// \t) ;\n// \tc = c + (chara(97)); // a\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tc = c + (chara(58)); // colon\n// \ttp.x = tp.x - (FONT_SPACE);\n// \tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n// \tvColor = mix(vColor, drawColor, c * alpha);\n// }\n\n// fn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n//     let pa = p - a;\n//     let ba = b - a;\n//     let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n//     return length(pa - ba * h);\n// }\n\n// fn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n// \treturn mix(1., 0., smoothstep(thick, thick + 0.01, abs(length(uv - pos) - radius)));\n// } \n\n// fn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n//     let d = length(p - c);\n//     return d - r;\n// }\n\n// fn draw_ring(location: vec2<i32>) {\n// \tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n// \tlet alpha = 0.75;\n// \tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n// \tlet d = smoothstep(0.5, 1.5, abs(ring_dist - 1.));\n// \tvColor = mix(vColor, headColor,   (1. - d) * alpha );\n// }\n\n// fn draw_crossair(location: vec2<i32>)  {\n\n// \tlet start = 5.0;\n// \tlet end = 20.;\n// \tlet segment1 = sdSegment(\n// \t\tvec2<f32>(location) - uni.iMouse.xy, \n// \t\tvec2<f32>(start, 0.), \n// \t\tvec2<f32>(end, 0.)\n// \t);\n\n// \tlet segment2 = sdSegment(\n// \t\tvec2<f32>(location) - uni.iMouse.xy, \n// \t\tvec2<f32>(-start, 0.), \n// \t\tvec2<f32>(-end, 0.)\n// \t);\n\n// \tlet segment3 = sdSegment(\n// \t\tvec2<f32>(location) - uni.iMouse.xy, \n// \t\tvec2<f32>(0., start), \n// \t\tvec2<f32>(0., end)\n// \t);\n\n// \tlet segment4 = sdSegment(\n// \t\tvec2<f32>(location) - uni.iMouse.xy, \n// \t\tvec2<f32>(0., -start), \n// \t\tvec2<f32>(0., -end)\n// \t);\n\n// \tvar alpha = 0.75;\n// \tif (uni.iMouse.z > 0.) {\n// \t\talpha = 1.0;\n// \t}\n\n// \tlet d = smoothstep(0.5, 1.5, segment1);\n// \tvColor = mix(vColor, headColor, (1.0 -  d) * alpha );\n\n// \tlet d = smoothstep(0.5, 1.5, segment2);\n// \tvColor = mix(vColor, headColor, (1.0 -  d) * alpha );\n\n// \tlet d = smoothstep(0.5, 1.5, segment3);\n// \tvColor = mix(vColor, headColor, (1.0 -  d) * alpha );\n\n// \tlet d = smoothstep(0.5, 1.5, segment4);\n// \tvColor = mix(vColor, headColor, (1.0 -  d) * alpha );\n// }\n\n// fn show_debug_info(location: vec2<i32>) -> vec4<f32> {    \n\n\n// \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// \tresolution = uni.iResolution.xy;\n// \taspect = resolution.x / resolution.y;\n\n// \tlet ratio: vec2<f32> = vec2<f32>(aspect, 1.);\n// \tpixelPos = fragCoord.xy;\n// \tmousePos = uni.iMouse.xy;\n// \tuv = (2. * fragCoord.xy / resolution.xy - 1.) * ratio;\n\n// \talignment = 10. * vec4<f32>(\n// \t\t1.,      // North\n// \t\taspect,  // East\n// \t\t-1.,     // South\n// \t\t-aspect, // West\n// \t);\n\n// \tmp = (2. * abs(uni.iMouse.xy) / resolution.xy - 1.) * ratio; // Mouse position in uv coordinates\n\n// \tWriteMousePos(uni.iMouse.zw, alignment.z + 2.0 * FONT_SPACE); // Click position\n// \tWriteMousePos(uni.iMouse.xy, alignment.z + 0.2 * FONT_SPACE); // Current mouse position\n\n// \tvar c: f32 = 0.;\n\n// \tSetTextPositionAbs(\n// \t\t alignment.y -      FONT_SPACE,\n// \t\t alignment.x - 2. * FONT_SPACE,\n// \t);\n\n// \tSetColor(0.8, 0.8, 0.8);\n// \tvar resx = i32(uni.iResolution.x);\n// \tvar resy = i32(uni.iResolution.y);\n\n\n// \tWriteIntegerBack(&resx);\n// \tc = c + (chara(28));\n// \ttp.x = tp.x + 0. * (FONT_SPACE);\n// \tWriteIntegerBack(&resy);\n\n\n// \tSetTextPositionAbs(\n// \t\t alignment.w - 1. * FONT_SPACE,\n// \t\t alignment.z - 0. * FONT_SPACE,\n// \t);\n\n// \tWriteFPS();\n// \tSetColor(0.9, 0.7, 0.8);\n\n// \tlet fragColor = vec4<f32>(vColor, 1.);\n\n// \tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n// \t// // RGBA probe labels follow mouse\n// \t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n// \tlet inverted_y_mouse_location = vec2<i32>(v2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n// \tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n// \tWriteRGBAValues(location, value, poz, 0.5);\n\n// \tlet inverted_y_mouseclick_location = vec2<i32>(v2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n// \tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n// \tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.25);\n\n// \tdraw_crossair(location);\n\n// \tdraw_ring(location);\n\n// \tlet fragColor = vec4<f32>(vColor, 1.);\n\n// \treturn fragColor;\n// } \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\t\n\tlet y_inverted_location = vec2<i32>((location.x), i32(uni.iResolution.y) - (location.y));\n\n\n\tlet fragColor = show_debug_info(location, vec3<f32>(0.5, 0.2, 0.1));\n\ttextureStore(texture, y_inverted_location, toLinear(fragColor));\n}\n\n"
  },
  {
    "path": "examples/dry_ice/buffer_a.wgsl",
    "content": "fn noise(p_in: vec3<f32>) -> f32 {\n    var p = p_in;\n\tlet ip: vec3<f32> = floor(p);\n\tp = p - (ip);\n\tlet s: vec3<f32> = vec3<f32>(7., 157., 113.);\n\tvar h: vec4<f32> = vec4<f32>(0., s.yz, s.y + s.z) + dot(ip, s);\n\tp = p * p * (3. - 2. * p);\n\th = mix(fract(sin(h) * 43758.5), fract(sin(h + s.x) * 43758.5), p.x);\n\tvar hxy = h.xy;\n\thxy = mix(h.xz, h.yw, p.y);\n\th.x = hxy.x;\n\th.y = hxy.y;\n\treturn mix(h.x, h.y, p.z);\n} \n\nfn fbm(p_in: vec3<f32>, octaveNum: i32) -> vec2<f32> {\n    var p = p_in;\n\tvar octaveNum_var = octaveNum;\n\tvar acc: vec2<f32> = vec2<f32>(0.);\n\tlet freq: f32 = 1.;\n\tvar amp: f32 = 0.5;\n\tlet shift: vec3<f32> = vec3<f32>(100.);\n\n\tfor (var i: i32 = 0; i < octaveNum_var; i = i + 1) {\n\t\tacc = acc + (vec2<f32>(noise(p), noise(p + vec3<f32>(0., 0., 10.))) * amp);\n\t\tp = p * 2. + shift;\n\t\tamp = amp * (0.5);\n\t}\n\n\treturn acc;\n} \n\nfn sampleMinusGradient(coord: vec2<f32>) -> vec3<f32> {\n\tvar veld: vec3<f32> = sample_texture(buffer_a, (coord / uni.iResolution.xy)).xyz;\n\tlet left: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(-1., 0.)) / uni.iResolution.xy)).x;\n\tlet right: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(1., 0.)) / uni.iResolution.xy)).x;\n\tlet bottom: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(0., -1.)) / uni.iResolution.xy)).x;\n\tlet top: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(0., 1.)) / uni.iResolution.xy)).x;\n\tlet grad: vec2<f32> = vec2<f32>(right - left, top - bottom) * 0.5;\n\treturn vec3<f32>(veld.xy - grad, veld.z);\n} \n\nfn vignette(color: vec3<f32>, q: vec2<f32>, v: f32) -> vec3<f32> {\n\tvar color_var = color;\n\tcolor_var = color_var * (mix(1., pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v), 0.02));\n\treturn color_var;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar velocity: vec2<f32> = sampleMinusGradient(fragCoord).xy;\n\tvar veld: vec3<f32> = sampleMinusGradient(fragCoord - dissipation * velocity).xyz;\n\tvar density: f32 = veld.z;\n\tvelocity = veld.xy;\n\tlet uv: vec2<f32> = (2. * fragCoord - uni.iResolution.xy) / uni.iResolution.y;\n\tlet detailNoise: vec2<f32> = fbm(vec3<f32>(uv * 40., uni.iTime * 0.5 + 30.), 7) - 0.5;\n\tvelocity = velocity + (detailNoise * 0.2);\n\tdensity = density + (length(detailNoise) * 0.01);\n\tlet injectionNoise: vec2<f32> = fbm(vec3<f32>(uv * 1.5, uni.iTime * 0.1 + 30.), 7) - 0.5;\n\tvelocity = velocity + (injectionNoise * 0.1);\n\tdensity = density + (max(length(injectionNoise) * 0.04, 0.));\n\tlet influenceRadius: f32 = ballRadius * 2.;\n\n\tfor (var i: i32 = 0; i < nbSphere; i = i + 1) {\n\t\tlet p: vec2<f32> = spherePosition(i, i32(uni.iFrame));\n\t\tlet dist: f32 = distance(uv, p);\n\t\tif (dist < influenceRadius) {\n\t\t\tlet op: vec2<f32> = spherePosition(i, i32(uni.iFrame) + 1);\n\t\t\tlet ballVelocity: vec2<f32> = p - op;\n\t\t\tdensity = density - ((influenceRadius - dist) / influenceRadius * 0.15);\n\t\t\tdensity = max(0., density);\n\t\t\tvelocity = velocity - (ballVelocity * 5.);\n\t\t}\n\t}\n\n\tdensity = min(1., density);\n\tdensity = density * (0.99);\n\tveld = vec3<f32>(vec3<f32>(velocity, density));\n\tveld = vignette(veld, fragCoord / uni.iResolution.xy, 1.);\n\tfragColor = vec4<f32>(veld, 1.);\n\n    textureStore(buffer_a, location, fragColor);\n} \n\n\n\n// fn noise(p_in: vec3<f32>) -> f32 {\n//     var p = p_in;\n// \tlet ip: vec3<f32> = floor(p);\n// \tp = p - (ip);\n// \tlet s: vec3<f32> = vec3<f32>(7., 157., 113.);\n// \tvar h: vec4<f32> = vec4<f32>(0., s.yz, s.y + s.z) + dot(ip, s);\n// \tp = p * p * (3. - 2. * p);\n// \th = mix(fract(sin(h) * 43758.5), fract(sin(h + s.x) * 43758.5), p.x);\n// \tvar hxy = h.xy;\n// \thxy = mix(h.xz, h.yw, p.y);\n// \th.x = hxy.x;\n// \th.y = hxy.y;\n// \treturn mix(h.x, h.y, p.z);\n// } \n\n// fn fbm(p_in: vec3<f32>, octaveNum: i32) -> vec2<f32> {\n//     var p = p_in;\n// \tvar octaveNum_var = octaveNum;\n// \tvar acc: vec2<f32> = vec2<f32>(0.);\n// \tlet freq: f32 = 1.;\n// \tvar amp: f32 = 0.5;\n// \tlet shift: vec3<f32> = vec3<f32>(100.);\n\n// \tfor (var i: i32 = 0; i < octaveNum_var; i = i + 1) {\n// \t\tacc = acc + (vec2<f32>(noise(p), noise(p + vec3<f32>(0., 0., 10.))) * amp);\n// \t\tp = p * 2. + shift;\n// \t\tamp = amp * (0.5);\n// \t}\n\n// \treturn acc;\n// } \n\n// fn sampleMinusGradient(coord: vec2<f32>) -> vec3<f32> {\n// \tvar veld: vec3<f32> = sample_texture(buffer_a,(coord / uni.iResolution.xy)).xyz;\n// \tlet left: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(-1., 0.)) / uni.iResolution.xy)).x;\n// \tlet right: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(1., 0.)) / uni.iResolution.xy)).x;\n// \tlet bottom: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(0., -1.)) / uni.iResolution.xy)).x;\n// \tlet top: f32 = sample_texture(buffer_d, ((coord + vec2<f32>(0., 1.)) / uni.iResolution.xy)).x;\n// \tlet grad: vec2<f32> = vec2<f32>(right - left, top - bottom) * 0.5;\n// \treturn vec3<f32>(veld.xy - grad, veld.z);\n// } \n\n// fn vignette(color: vec3<f32>, q: vec2<f32>, v: f32) -> vec3<f32> {\n// \tvar color_var = color;\n// \tcolor_var = color_var * (mix(1., pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v), 0.02));\n// \treturn color_var;\n// } \n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n//     let R: vec2<f32> = uni.iResolution.xy;\n//     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n// \tvar fragColor: vec4<f32> = vec4<f32>(0.);\n// \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// \tvar velocity: vec2<f32> = sampleMinusGradient(fragCoord).xy;\n// \tvar veld: vec3<f32> = sampleMinusGradient(fragCoord - dissipation * velocity).xyz;\n// \tvar density: f32 = veld.z;\n// \tvelocity = veld.xy;\n// \tlet uv: vec2<f32> = (2. * fragCoord - uni.iResolution.xy) / uni.iResolution.y;\n\n\n// \tlet detailNoise: vec2<f32> = fbm(vec3<f32>(uv * 40., uni.iTime * 0.5 + 30.), 7) - 0.5;\n// \tvelocity = velocity + (detailNoise * 0.2);\n// \tdensity = density + (length(detailNoise) * 0.01);\n\n// \tlet injectionNoise: vec2<f32> = fbm(vec3<f32>(uv * 1.5, uni.iTime * 0.1 + 30.), 7) - 0.5;\n// \tvelocity = velocity + (injectionNoise * 0.1);\n// \tdensity = density + (max(length(injectionNoise) * 0.04, 0.));\n\n// \tlet influenceRadius: f32 = ballRadius * 2.;\n\n// \tfor (var i: i32 = 0; i < nbSphere; i = i + 1) {\n// \t\tlet p: vec2<f32> = spherePosition(i, i32(uni.iFrame));\n// \t\tlet dist: f32 = distance(uv, p);\n// \t\tif (dist < influenceRadius) {\n// \t\t\tlet op: vec2<f32> = spherePosition(i, i32(uni.iFrame) + 1);\n// \t\t\tlet ballVelocity: vec2<f32> = p - op;\n// \t\t\tdensity = density - ((influenceRadius - dist) / influenceRadius * 0.15);\n// \t\t\tdensity = max(0., density);\n// \t\t\tvelocity = velocity - (ballVelocity * 5.);\n// \t\t}\n// \t}\n\n// \tdensity = min(1., density);\n// \tdensity = density * (0.99);\n// \tveld = vec3<f32>(vec3<f32>(velocity, density));\n// \t// veld = vignette(veld, fragCoord / uni.iResolution.xy, 1.);\n// \tfragColor = vec4<f32>(veld, 1.);\n\n//     textureStore(buffer_a, location, fragColor);\n\n// } \n\n"
  },
  {
    "path": "examples/dry_ice/buffer_b.wgsl",
    "content": "\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet icoord: vec2<i32> = vec2<i32>(fragCoord);\n\tlet vel_x_left: f32 = textureLoad(buffer_a, vec2<i32>(icoord + vec2<i32>(-1, 0))).x;\n\tlet vel_x_right: f32 = textureLoad(buffer_a, vec2<i32>(icoord + vec2<i32>(1, 0))).x;\n\tlet vel_y_bottom: f32 = textureLoad(buffer_a, vec2<i32>(icoord + vec2<i32>(0, -1))).y;\n\tlet vel_y_top: f32 = textureLoad(buffer_a, vec2<i32>(icoord + vec2<i32>(0, 1))).y;\n\tlet divergence: f32 = (vel_x_right - vel_x_left + vel_y_top - vel_y_bottom) * 0.5;\n\tfragColor = vec4<f32>(divergence, vec3<f32>(1.));\n    textureStore(buffer_b, location, fragColor);\n} \n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n//     let R: vec2<f32> = uni.iResolution.xy;\n//     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n// \tvar fragColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n// \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// \tlet icoord: vec2<i32> = vec2<i32>(fragCoord);\n// \tlet vel_x_left: f32 = sample_texture(buffer_a, vec2<f32>(icoord + vec2<i32>(-1, 0))).x;\n// \tlet vel_x_right: f32 = sample_texture(buffer_a, vec2<f32>(icoord + vec2<i32>(1, 0))).x;\n// \tlet vel_y_bottom: f32 = sample_texture(buffer_a, vec2<f32>(icoord + vec2<i32>(0, -1))).y;\n// \tlet vel_y_top: f32 = sample_texture(buffer_a, vec2<f32>(icoord + vec2<i32>(0, 1))).y;\n// \tlet divergence: f32 = (vel_x_right - vel_x_left + vel_y_top - vel_y_bottom) * 0.5;\n// \tfragColor = vec4<f32>(divergence, vec3<f32>(1.));\n//     textureStore(buffer_b, location, fragColor);\n\n\n// } \n\n"
  },
  {
    "path": "examples/dry_ice/buffer_c.wgsl",
    "content": "var<private> location: vec2<i32>;\n\nfn div(x: i32, y: i32) -> f32 {\n\treturn textureLoad(buffer_b, vec2<i32>(location + vec2<i32>(x, y))).x;\n} \n\nfn getDiv() -> f32 {\n\tvar p: f32 = 0.;\n\tp = p + (1. * div(-9, 0));\n\tp = p + (9. * div(-8, -1));\n\tp = p + (4. * div(-8, 0));\n\tp = p + (9. * div(-8, 1));\n\tp = p + (36. * div(-7, -2));\n\tp = p + (32. * div(-7, -1));\n\tp = p + (97. * div(-7, 0));\n\tp = p + (32. * div(-7, 1));\n\tp = p + (36. * div(-7, 2));\n\tp = p + (84. * div(-6, -3));\n\tp = p + (112. * div(-6, -2));\n\tp = p + (436. * div(-6, -1));\n\tp = p + (320. * div(-6, 0));\n\tp = p + (436. * div(-6, 1));\n\tp = p + (112. * div(-6, 2));\n\tp = p + (84. * div(-6, 3));\n\tp = p + (126. * div(-5, -4));\n\tp = p + (224. * div(-5, -3));\n\tp = p + (1092. * div(-5, -2));\n\tp = p + (1280. * div(-5, -1));\n\tp = p + (2336. * div(-5, 0));\n\tp = p + (1280. * div(-5, 1));\n\tp = p + (1092. * div(-5, 2));\n\tp = p + (224. * div(-5, 3));\n\tp = p + (126. * div(-5, 4));\n\tp = p + (126. * div(-4, -5));\n\tp = p + (280. * div(-4, -4));\n\tp = p + (1694. * div(-4, -3));\n\tp = p + (2752. * div(-4, -2));\n\tp = p + (6656. * div(-4, -1));\n\tp = p + (6464. * div(-4, 0));\n\tp = p + (6656. * div(-4, 1));\n\tp = p + (2752. * div(-4, 2));\n\tp = p + (1694. * div(-4, 3));\n\tp = p + (280. * div(-4, 4));\n\tp = p + (126. * div(-4, 5));\n\tp = p + (84. * div(-3, -6));\n\tp = p + (224. * div(-3, -5));\n\tp = p + (1694. * div(-3, -4));\n\tp = p + (3520. * div(-3, -3));\n\tp = p + (11016. * div(-3, -2));\n\tp = p + (16128. * div(-3, -1));\n\tp = p + (24608. * div(-3, 0));\n\tp = p + (16128. * div(-3, 1));\n\tp = p + (11016. * div(-3, 2));\n\tp = p + (3520. * div(-3, 3));\n\tp = p + (1694. * div(-3, 4));\n\tp = p + (224. * div(-3, 5));\n\tp = p + (84. * div(-3, 6));\n\tp = p + (36. * div(-2, -7));\n\tp = p + (112. * div(-2, -6));\n\tp = p + (1092. * div(-2, -5));\n\tp = p + (2752. * div(-2, -4));\n\tp = p + (11016. * div(-2, -3));\n\tp = p + (21664. * div(-2, -2));\n\tp = p + (47432. * div(-2, -1));\n\tp = p + (59712. * div(-2, 0));\n\tp = p + (47432. * div(-2, 1));\n\tp = p + (21664. * div(-2, 2));\n\tp = p + (11016. * div(-2, 3));\n\tp = p + (2752. * div(-2, 4));\n\tp = p + (1092. * div(-2, 5));\n\tp = p + (112. * div(-2, 6));\n\tp = p + (36. * div(-2, 7));\n\tp = p + (9. * div(-1, -8));\n\tp = p + (32. * div(-1, -7));\n\tp = p + (436. * div(-1, -6));\n\tp = p + (1280. * div(-1, -5));\n\tp = p + (6656. * div(-1, -4));\n\tp = p + (16128. * div(-1, -3));\n\tp = p + (47432. * div(-1, -2));\n\tp = p + (92224. * div(-1, -1));\n\tp = p + (163476. * div(-1, 0));\n\tp = p + (92224. * div(-1, 1));\n\tp = p + (47432. * div(-1, 2));\n\tp = p + (16128. * div(-1, 3));\n\tp = p + (6656. * div(-1, 4));\n\tp = p + (1280. * div(-1, 5));\n\tp = p + (436. * div(-1, 6));\n\tp = p + (32. * div(-1, 7));\n\tp = p + (9. * div(-1, 8));\n\tp = p + (1. * div(0, -9));\n\tp = p + (4. * div(0, -8));\n\tp = p + (97. * div(0, -7));\n\tp = p + (320. * div(0, -6));\n\tp = p + (2336. * div(0, -5));\n\tp = p + (6464. * div(0, -4));\n\tp = p + (24608. * div(0, -3));\n\tp = p + (59712. * div(0, -2));\n\tp = p + (163476. * div(0, -1));\n\tp = p + (409744. * div(0, 0));\n\tp = p + (163476. * div(0, 1));\n\tp = p + (59712. * div(0, 2));\n\tp = p + (24608. * div(0, 3));\n\tp = p + (6464. * div(0, 4));\n\tp = p + (2336. * div(0, 5));\n\tp = p + (320. * div(0, 6));\n\tp = p + (97. * div(0, 7));\n\tp = p + (4. * div(0, 8));\n\tp = p + (1. * div(0, 9));\n\tp = p + (9. * div(1, -8));\n\tp = p + (32. * div(1, -7));\n\tp = p + (436. * div(1, -6));\n\tp = p + (1280. * div(1, -5));\n\tp = p + (6656. * div(1, -4));\n\tp = p + (16128. * div(1, -3));\n\tp = p + (47432. * div(1, -2));\n\tp = p + (92224. * div(1, -1));\n\tp = p + (163476. * div(1, 0));\n\tp = p + (92224. * div(1, 1));\n\tp = p + (47432. * div(1, 2));\n\tp = p + (16128. * div(1, 3));\n\tp = p + (6656. * div(1, 4));\n\tp = p + (1280. * div(1, 5));\n\tp = p + (436. * div(1, 6));\n\tp = p + (32. * div(1, 7));\n\tp = p + (9. * div(1, 8));\n\tp = p + (36. * div(2, -7));\n\tp = p + (112. * div(2, -6));\n\tp = p + (1092. * div(2, -5));\n\tp = p + (2752. * div(2, -4));\n\tp = p + (11016. * div(2, -3));\n\tp = p + (21664. * div(2, -2));\n\tp = p + (47432. * div(2, -1));\n\tp = p + (59712. * div(2, 0));\n\tp = p + (47432. * div(2, 1));\n\tp = p + (21664. * div(2, 2));\n\tp = p + (11016. * div(2, 3));\n\tp = p + (2752. * div(2, 4));\n\tp = p + (1092. * div(2, 5));\n\tp = p + (112. * div(2, 6));\n\tp = p + (36. * div(2, 7));\n\tp = p + (84. * div(3, -6));\n\tp = p + (224. * div(3, -5));\n\tp = p + (1694. * div(3, -4));\n\tp = p + (3520. * div(3, -3));\n\tp = p + (11016. * div(3, -2));\n\tp = p + (16128. * div(3, -1));\n\tp = p + (24608. * div(3, 0));\n\tp = p + (16128. * div(3, 1));\n\tp = p + (11016. * div(3, 2));\n\tp = p + (3520. * div(3, 3));\n\tp = p + (1694. * div(3, 4));\n\tp = p + (224. * div(3, 5));\n\tp = p + (84. * div(3, 6));\n\tp = p + (126. * div(4, -5));\n\tp = p + (280. * div(4, -4));\n\tp = p + (1694. * div(4, -3));\n\tp = p + (2752. * div(4, -2));\n\tp = p + (6656. * div(4, -1));\n\tp = p + (6464. * div(4, 0));\n\tp = p + (6656. * div(4, 1));\n\tp = p + (2752. * div(4, 2));\n\tp = p + (1694. * div(4, 3));\n\tp = p + (280. * div(4, 4));\n\tp = p + (126. * div(4, 5));\n\tp = p + (126. * div(5, -4));\n\tp = p + (224. * div(5, -3));\n\tp = p + (1092. * div(5, -2));\n\tp = p + (1280. * div(5, -1));\n\tp = p + (2336. * div(5, 0));\n\tp = p + (1280. * div(5, 1));\n\tp = p + (1092. * div(5, 2));\n\tp = p + (224. * div(5, 3));\n\tp = p + (126. * div(5, 4));\n\tp = p + (84. * div(6, -3));\n\tp = p + (112. * div(6, -2));\n\tp = p + (436. * div(6, -1));\n\tp = p + (320. * div(6, 0));\n\tp = p + (436. * div(6, 1));\n\tp = p + (112. * div(6, 2));\n\tp = p + (84. * div(6, 3));\n\tp = p + (36. * div(7, -2));\n\tp = p + (32. * div(7, -1));\n\tp = p + (97. * div(7, 0));\n\tp = p + (32. * div(7, 1));\n\tp = p + (36. * div(7, 2));\n\tp = p + (9. * div(8, -1));\n\tp = p + (4. * div(8, 0));\n\tp = p + (9. * div(8, 1));\n\tp = p + (1. * div(9, 0));\n\treturn p / 1048576.;\n} \n\nfn pre(x: i32, y: i32) -> f32 {\n\treturn textureLoad(buffer_d, vec2<i32>(location + vec2<i32>(x, y))).x;\n} \n\nfn getPre() -> f32 {\n\tvar p: f32 = 0.;\n\tp = p + (1. * pre(-10, 0));\n\tp = p + (10. * pre(-9, -1));\n\tp = p + (10. * pre(-9, 1));\n\tp = p + (45. * pre(-8, -2));\n\tp = p + (100. * pre(-8, 0));\n\tp = p + (45. * pre(-8, 2));\n\tp = p + (120. * pre(-7, -3));\n\tp = p + (450. * pre(-7, -1));\n\tp = p + (450. * pre(-7, 1));\n\tp = p + (120. * pre(-7, 3));\n\tp = p + (210. * pre(-6, -4));\n\tp = p + (1200. * pre(-6, -2));\n\tp = p + (2025. * pre(-6, 0));\n\tp = p + (1200. * pre(-6, 2));\n\tp = p + (210. * pre(-6, 4));\n\tp = p + (252. * pre(-5, -5));\n\tp = p + (2100. * pre(-5, -3));\n\tp = p + (5400. * pre(-5, -1));\n\tp = p + (5400. * pre(-5, 1));\n\tp = p + (2100. * pre(-5, 3));\n\tp = p + (252. * pre(-5, 5));\n\tp = p + (210. * pre(-4, -6));\n\tp = p + (2520. * pre(-4, -4));\n\tp = p + (9450. * pre(-4, -2));\n\tp = p + (14400. * pre(-4, 0));\n\tp = p + (9450. * pre(-4, 2));\n\tp = p + (2520. * pre(-4, 4));\n\tp = p + (210. * pre(-4, 6));\n\tp = p + (120. * pre(-3, -7));\n\tp = p + (2100. * pre(-3, -5));\n\tp = p + (11340. * pre(-3, -3));\n\tp = p + (25200. * pre(-3, -1));\n\tp = p + (25200. * pre(-3, 1));\n\tp = p + (11340. * pre(-3, 3));\n\tp = p + (2100. * pre(-3, 5));\n\tp = p + (120. * pre(-3, 7));\n\tp = p + (45. * pre(-2, -8));\n\tp = p + (1200. * pre(-2, -6));\n\tp = p + (9450. * pre(-2, -4));\n\tp = p + (30240. * pre(-2, -2));\n\tp = p + (44100. * pre(-2, 0));\n\tp = p + (30240. * pre(-2, 2));\n\tp = p + (9450. * pre(-2, 4));\n\tp = p + (1200. * pre(-2, 6));\n\tp = p + (45. * pre(-2, 8));\n\tp = p + (10. * pre(-1, -9));\n\tp = p + (450. * pre(-1, -7));\n\tp = p + (5400. * pre(-1, -5));\n\tp = p + (25200. * pre(-1, -3));\n\tp = p + (52920. * pre(-1, -1));\n\tp = p + (52920. * pre(-1, 1));\n\tp = p + (25200. * pre(-1, 3));\n\tp = p + (5400. * pre(-1, 5));\n\tp = p + (450. * pre(-1, 7));\n\tp = p + (10. * pre(-1, 9));\n\tp = p + (1. * pre(0, -10));\n\tp = p + (100. * pre(0, -8));\n\tp = p + (2025. * pre(0, -6));\n\tp = p + (14400. * pre(0, -4));\n\tp = p + (44100. * pre(0, -2));\n\tp = p + (63504. * pre(0, 0));\n\tp = p + (44100. * pre(0, 2));\n\tp = p + (14400. * pre(0, 4));\n\tp = p + (2025. * pre(0, 6));\n\tp = p + (100. * pre(0, 8));\n\tp = p + (1. * pre(0, 10));\n\tp = p + (10. * pre(1, -9));\n\tp = p + (450. * pre(1, -7));\n\tp = p + (5400. * pre(1, -5));\n\tp = p + (25200. * pre(1, -3));\n\tp = p + (52920. * pre(1, -1));\n\tp = p + (52920. * pre(1, 1));\n\tp = p + (25200. * pre(1, 3));\n\tp = p + (5400. * pre(1, 5));\n\tp = p + (450. * pre(1, 7));\n\tp = p + (10. * pre(1, 9));\n\tp = p + (45. * pre(2, -8));\n\tp = p + (1200. * pre(2, -6));\n\tp = p + (9450. * pre(2, -4));\n\tp = p + (30240. * pre(2, -2));\n\tp = p + (44100. * pre(2, 0));\n\tp = p + (30240. * pre(2, 2));\n\tp = p + (9450. * pre(2, 4));\n\tp = p + (1200. * pre(2, 6));\n\tp = p + (45. * pre(2, 8));\n\tp = p + (120. * pre(3, -7));\n\tp = p + (2100. * pre(3, -5));\n\tp = p + (11340. * pre(3, -3));\n\tp = p + (25200. * pre(3, -1));\n\tp = p + (25200. * pre(3, 1));\n\tp = p + (11340. * pre(3, 3));\n\tp = p + (2100. * pre(3, 5));\n\tp = p + (120. * pre(3, 7));\n\tp = p + (210. * pre(4, -6));\n\tp = p + (2520. * pre(4, -4));\n\tp = p + (9450. * pre(4, -2));\n\tp = p + (14400. * pre(4, 0));\n\tp = p + (9450. * pre(4, 2));\n\tp = p + (2520. * pre(4, 4));\n\tp = p + (210. * pre(4, 6));\n\tp = p + (252. * pre(5, -5));\n\tp = p + (2100. * pre(5, -3));\n\tp = p + (5400. * pre(5, -1));\n\tp = p + (5400. * pre(5, 1));\n\tp = p + (2100. * pre(5, 3));\n\tp = p + (252. * pre(5, 5));\n\tp = p + (210. * pre(6, -4));\n\tp = p + (1200. * pre(6, -2));\n\tp = p + (2025. * pre(6, 0));\n\tp = p + (1200. * pre(6, 2));\n\tp = p + (210. * pre(6, 4));\n\tp = p + (120. * pre(7, -3));\n\tp = p + (450. * pre(7, -1));\n\tp = p + (450. * pre(7, 1));\n\tp = p + (120. * pre(7, 3));\n\tp = p + (45. * pre(8, -2));\n\tp = p + (100. * pre(8, 0));\n\tp = p + (45. * pre(8, 2));\n\tp = p + (10. * pre(9, -1));\n\tp = p + (10. * pre(9, 1));\n\tp = p + (1. * pre(10, 0));\n\treturn p / 1048576.;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\tvar C = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet div: f32 = getDiv();\n\tlet p: f32 = getPre() - div;\n\tfragColor = vec4<f32>(p, div, vec2<f32>(1.));\n\n    textureStore(buffer_c, location, fragColor);\n} \n\n"
  },
  {
    "path": "examples/dry_ice/buffer_d.wgsl",
    "content": "\nvar<private> location: vec2<i32>;\n\nfn div(x: i32, y: i32) -> f32 {\n\treturn textureLoad(buffer_c, vec2<i32>(location + vec2<i32>(x, y))).y;\n} \n\nfn pre(x: i32, y: i32) -> f32 {\n\treturn textureLoad(buffer_c, vec2<i32>(location + vec2<i32>(x, y))).x;\n} \n\nfn getPre() -> f32 {\n\tvar p: f32 = 0.;\n\tp = p + (1. * pre(-10, 0));\n\tp = p + (10. * pre(-9, -1));\n\tp = p + (10. * pre(-9, 1));\n\tp = p + (45. * pre(-8, -2));\n\tp = p + (100. * pre(-8, 0));\n\tp = p + (45. * pre(-8, 2));\n\tp = p + (120. * pre(-7, -3));\n\tp = p + (450. * pre(-7, -1));\n\tp = p + (450. * pre(-7, 1));\n\tp = p + (120. * pre(-7, 3));\n\tp = p + (210. * pre(-6, -4));\n\tp = p + (1200. * pre(-6, -2));\n\tp = p + (2025. * pre(-6, 0));\n\tp = p + (1200. * pre(-6, 2));\n\tp = p + (210. * pre(-6, 4));\n\tp = p + (252. * pre(-5, -5));\n\tp = p + (2100. * pre(-5, -3));\n\tp = p + (5400. * pre(-5, -1));\n\tp = p + (5400. * pre(-5, 1));\n\tp = p + (2100. * pre(-5, 3));\n\tp = p + (252. * pre(-5, 5));\n\tp = p + (210. * pre(-4, -6));\n\tp = p + (2520. * pre(-4, -4));\n\tp = p + (9450. * pre(-4, -2));\n\tp = p + (14400. * pre(-4, 0));\n\tp = p + (9450. * pre(-4, 2));\n\tp = p + (2520. * pre(-4, 4));\n\tp = p + (210. * pre(-4, 6));\n\tp = p + (120. * pre(-3, -7));\n\tp = p + (2100. * pre(-3, -5));\n\tp = p + (11340. * pre(-3, -3));\n\tp = p + (25200. * pre(-3, -1));\n\tp = p + (25200. * pre(-3, 1));\n\tp = p + (11340. * pre(-3, 3));\n\tp = p + (2100. * pre(-3, 5));\n\tp = p + (120. * pre(-3, 7));\n\tp = p + (45. * pre(-2, -8));\n\tp = p + (1200. * pre(-2, -6));\n\tp = p + (9450. * pre(-2, -4));\n\tp = p + (30240. * pre(-2, -2));\n\tp = p + (44100. * pre(-2, 0));\n\tp = p + (30240. * pre(-2, 2));\n\tp = p + (9450. * pre(-2, 4));\n\tp = p + (1200. * pre(-2, 6));\n\tp = p + (45. * pre(-2, 8));\n\tp = p + (10. * pre(-1, -9));\n\tp = p + (450. * pre(-1, -7));\n\tp = p + (5400. * pre(-1, -5));\n\tp = p + (25200. * pre(-1, -3));\n\tp = p + (52920. * pre(-1, -1));\n\tp = p + (52920. * pre(-1, 1));\n\tp = p + (25200. * pre(-1, 3));\n\tp = p + (5400. * pre(-1, 5));\n\tp = p + (450. * pre(-1, 7));\n\tp = p + (10. * pre(-1, 9));\n\tp = p + (1. * pre(0, -10));\n\tp = p + (100. * pre(0, -8));\n\tp = p + (2025. * pre(0, -6));\n\tp = p + (14400. * pre(0, -4));\n\tp = p + (44100. * pre(0, -2));\n\tp = p + (63504. * pre(0, 0));\n\tp = p + (44100. * pre(0, 2));\n\tp = p + (14400. * pre(0, 4));\n\tp = p + (2025. * pre(0, 6));\n\tp = p + (100. * pre(0, 8));\n\tp = p + (1. * pre(0, 10));\n\tp = p + (10. * pre(1, -9));\n\tp = p + (450. * pre(1, -7));\n\tp = p + (5400. * pre(1, -5));\n\tp = p + (25200. * pre(1, -3));\n\tp = p + (52920. * pre(1, -1));\n\tp = p + (52920. * pre(1, 1));\n\tp = p + (25200. * pre(1, 3));\n\tp = p + (5400. * pre(1, 5));\n\tp = p + (450. * pre(1, 7));\n\tp = p + (10. * pre(1, 9));\n\tp = p + (45. * pre(2, -8));\n\tp = p + (1200. * pre(2, -6));\n\tp = p + (9450. * pre(2, -4));\n\tp = p + (30240. * pre(2, -2));\n\tp = p + (44100. * pre(2, 0));\n\tp = p + (30240. * pre(2, 2));\n\tp = p + (9450. * pre(2, 4));\n\tp = p + (1200. * pre(2, 6));\n\tp = p + (45. * pre(2, 8));\n\tp = p + (120. * pre(3, -7));\n\tp = p + (2100. * pre(3, -5));\n\tp = p + (11340. * pre(3, -3));\n\tp = p + (25200. * pre(3, -1));\n\tp = p + (25200. * pre(3, 1));\n\tp = p + (11340. * pre(3, 3));\n\tp = p + (2100. * pre(3, 5));\n\tp = p + (120. * pre(3, 7));\n\tp = p + (210. * pre(4, -6));\n\tp = p + (2520. * pre(4, -4));\n\tp = p + (9450. * pre(4, -2));\n\tp = p + (14400. * pre(4, 0));\n\tp = p + (9450. * pre(4, 2));\n\tp = p + (2520. * pre(4, 4));\n\tp = p + (210. * pre(4, 6));\n\tp = p + (252. * pre(5, -5));\n\tp = p + (2100. * pre(5, -3));\n\tp = p + (5400. * pre(5, -1));\n\tp = p + (5400. * pre(5, 1));\n\tp = p + (2100. * pre(5, 3));\n\tp = p + (252. * pre(5, 5));\n\tp = p + (210. * pre(6, -4));\n\tp = p + (1200. * pre(6, -2));\n\tp = p + (2025. * pre(6, 0));\n\tp = p + (1200. * pre(6, 2));\n\tp = p + (210. * pre(6, 4));\n\tp = p + (120. * pre(7, -3));\n\tp = p + (450. * pre(7, -1));\n\tp = p + (450. * pre(7, 1));\n\tp = p + (120. * pre(7, 3));\n\tp = p + (45. * pre(8, -2));\n\tp = p + (100. * pre(8, 0));\n\tp = p + (45. * pre(8, 2));\n\tp = p + (10. * pre(9, -1));\n\tp = p + (10. * pre(9, 1));\n\tp = p + (1. * pre(10, 0));\n\treturn p / 1048576.;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);\n\tvar C = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet p: f32 = getPre() - div(0, 0);\n\tfragColor = vec4<f32>(p, vec3<f32>(1.));\n    textureStore(buffer_d, location, fragColor);\n} \n\n"
  },
  {
    "path": "examples/dry_ice/common.wgsl",
    "content": "let dissipation: f32 = 0.95;\nlet ballRadius: f32 = 0.06;\nlet fogHeigth: f32 = 0.24;\nlet nbSlice: i32 = 24;\nlet fogSlice: f32 = 0.01;\nlet nbSphere: i32 = 3;\nlet shadowDensity: f32 = 25.;\nlet fogDensity: f32 = 20.;\nlet lightHeight: f32 = 1.;\nlet tau: f32 = 6.28318530718;\n\nfn hash12(p: vec2<f32>) -> f32 {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * 0.1031);\n\tp3 = p3 + (dot(p3, p3.yzx + 33.33));\n\treturn fract((p3.x + p3.y) * p3.z);\n} \n\nfn hash41(p: f32) -> vec4<f32> {\n\tvar p4: vec4<f32> = fract(vec4<f32>(p) * vec4<f32>(0.1031, 0.103, 0.0973, 0.1099));\n\tp4 = p4 + (dot(p4, p4.wzxy + 33.33));\n\treturn fract((p4.xxyz + p4.yzzw) * p4.zywx);\n} \n\nfn rotate(angle: f32, radius: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(angle), -sin(angle)) * radius;\n} \n\nfn floorIntersect(ro: vec3<f32>, rd: vec3<f32>, floorHeight: f32, t: ptr<function, f32>) -> bool {\n\tvar ro_var = ro;\n\tro_var.y = ro_var.y - (floorHeight);\n\tif (rd.y < -0.01) {\n\t\t(*t) = ro_var.y / -rd.y;\n\t\treturn true;\n\t}\n\treturn false;\n} \n\nfn sphIntersect(ro: vec3<f32>, rd: vec3<f32>, ce: vec3<f32>, ra: f32) -> vec2<f32> {\n\tlet oc: vec3<f32> = ro - ce;\n\tlet b: f32 = dot(oc, rd);\n\tlet c: f32 = dot(oc, oc) - ra * ra;\n\tvar h: f32 = b * b - c;\n\tif (h < 0.) {\treturn vec2<f32>(-1.);\n }\n\th = sqrt(h);\n\treturn vec2<f32>(-b - h, -b + h);\n} \n\nfn boxIntersection(ro: vec3<f32>, rd: vec3<f32>, rad: vec3<f32>, center: vec3<f32>, oN: ptr<function, vec3<f32>>) -> vec2<f32> {\n\tvar ro_var = ro;\n\tro_var = ro_var - (center);\n\tlet m: vec3<f32> = 1. / rd;\n\tlet n: vec3<f32> = m * ro_var;\n\tlet k: vec3<f32> = abs(m) * rad;\n\tlet t1: vec3<f32> = -n - k;\n\tlet t2: vec3<f32> = -n + k;\n\tlet tN: f32 = max(max(t1.x, t1.y), t1.z);\n\tlet tF: f32 = min(min(t2.x, t2.y), t2.z);\n\tif (tN > tF || tF < 0.) {\treturn vec2<f32>(-1.);\n }\n\t(*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz);\n\treturn vec2<f32>(tN, tF);\n} \n\nfn spherePosition(id: i32, frame: i32) -> vec2<f32> {\n\tlet offset: vec4<f32> = hash41(f32(id)) * tau;\n\tlet fframe: f32 = f32(frame);\n\treturn vec2<f32>(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2<f32>(1., 0.5) * 0.9;\n} \n\nfn dist2(v: vec3<f32>) -> f32 {\n\treturn dot(v, v);\n} \n\n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n"
  },
  {
    "path": "examples/dry_ice/dry_ice.rs",
    "content": "// https://www.shadertoy.com/view/WlVyRV\n// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0\n// orignal GLSL code by David Gallardo - xjorma/2020\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            // present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: (960.0_f32 * 1.0).floor() as u32,\n            height: (600.0_f32 * 1.0).floor() as u32,\n            borders: 0.,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        // .add_system(update_common_uniform)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"dry_ice\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/dry_ice/image.wgsl",
    "content": "// https://www.shadertoy.com/view/WlVyRV\n// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0\n\nfn sceneIntersection(ro: vec3<f32>, rd: vec3<f32>, inter: ptr<function, vec3<f32>>, normal: ptr<function, vec3<f32>>, color: ptr<function, vec3<f32>>, dist: f32, lightPos: ptr<function, vec3<f32>>) -> f32 {\n\tvar mint: f32 = dist;\n\t(*inter) = vec3<f32>(0.);\n\t(*normal) = vec3<f32>(0.);\n\t(*color) = vec3<f32>(0.);\n\n\tfor (var i: i32 = 0; i < nbSphere; i = i + 1) {\n\t\tlet p2d: vec2<f32> = spherePosition(i, i32(uni.iFrame));\n\t\tlet pos: vec3<f32> = vec3<f32>(p2d.x, ballRadius, p2d.y);\n\t\tvar ballColor: vec3<f32> = vec3<f32>(1., 0., 0.);\n\t\tif (i == 0) {\n\t\t\tballColor = vec3<f32>(1.);\n\t\t\t(*lightPos) = pos + vec3<f32>(0., lightHeight, 0.);\n\t\t}\n\t\tvar t: f32 = sphIntersect(ro, rd, pos, ballRadius).x;\n\t\tif (t > 0. && t < mint) {\n\t\t\tmint = t;\n\t\t\t(*inter) = ro + mint * rd;\n\t\t\t(*normal) = normalize((*inter) - pos);\n\t\t\t(*color) = ballColor;\n\t\t}\n\t}\n\n\n\t\tlet aspecRatio: f32 = uni.iResolution.x / uni.iResolution.y;\n\t\tvar boxNormal: vec3<f32>;\n\t\tlet t: f32 = boxIntersection(ro, rd, vec3<f32>(aspecRatio, 0.1, 1.), vec3<f32>(0., -0.1, 0.), &boxNormal).x;\n\t\tif (t > 0. && t < mint) {\n\t\t\tmint = t;\n\t\t\t(*inter) = ro + mint * rd;\n\t\t\t(*normal) = boxNormal;\n\t\t\tlet tileId: vec2<i32> = vec2<i32>(vec2<f32>((*inter).x, (*inter).z) * 3. + 100.);\n\t\t\t if ((tileId.x & 1 ^ tileId.y & 1) == 0) { (*color) =vec3<f32>(0.3); } else { (*color) =vec3<f32>(0.15); };\n\t\t}\n\treturn mint;\n} \n\nfn sampleFog(pos: vec3<f32>) -> f32 {\n\tvar uv: vec2<f32> = pos.xz;\n\tuv.x = uv.x * (uni.iResolution.y / uni.iResolution.x);\n\tuv = uv * 0.5 + 0.5;\n\tif (max(uv.x, uv.y) > 1. || min(uv.x, uv.y) < 0.) {\n\t\treturn 0.;\n\t}\n\treturn sample_texture(buffer_a, uv).z;\n} \n\nfn Render(ro: vec3<f32>, rd: vec3<f32>, dist: f32, fudge: f32) -> vec3<f32> {\n\tvar inter: vec3<f32>;\n\tvar normal: vec3<f32>;\n\tvar baseColor: vec3<f32>;\n\tvar lightPos: vec3<f32>;\n\tlet mint: f32 = sceneIntersection(ro, rd, &inter, &normal, &baseColor, dist, &lightPos);\n\tvar color: vec3<f32> = vec3<f32>(0.);\n\tif (mint < dist) {\n\t\tvar lightDir: vec3<f32> = normalize(lightPos - inter);\n\t\tvar lightDist2: f32 = dist2(lightPos - inter);\n\t\tvar shadowStep: vec3<f32> = fogHeigth / f32(nbSlice) * lightDir / lightDir.y;\n\t\tvar shadowDist: f32 = 0.;\n\n\t\tfor (var i: i32 = 0; i < nbSlice; i = i + 1) {\n\t\t\tvar shadowPos: vec3<f32> = inter + shadowStep * f32(i);\n\t\t\tlet v: f32 = sampleFog(shadowPos) * fogHeigth;\n\t\t\tshadowDist = shadowDist + (min(max(0., v - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice);\n\t\t}\n\n\t\tvar shadowFactor: f32 = exp(-shadowDist * shadowDensity * 0.25);\n\t\tcolor = baseColor * (max(0., dot(normal, lightDir) * shadowFactor) + 0.2) / lightDist2;\n\t} else { \n\t\tcolor = vec3<f32>(0.);\n\t}\n\tvar t: f32;\n\tif (floorIntersect(ro, rd, fogHeigth, &t)) {\n\t\tvar curPos: vec3<f32> = ro + rd * t;\n\t\tlet fogStep: vec3<f32> = fogHeigth / f32(nbSlice) * rd / abs(rd.y);\n\t\tcurPos = curPos + (fudge * fogStep);\n\t\tlet stepLen: f32 = length(fogStep);\n\t\tvar curDensity: f32 = 0.;\n\t\tvar transmittance: f32 = 1.;\n\t\tvar lightEnergy: f32 = 0.;\n\n\t\tfor (var i: i32 = 0; i < nbSlice; i = i + 1) {\n\t\t\tif (dot(curPos - ro, rd) > mint) {\t\t\tbreak;\n }\n\t\t\tlet curHeigth: f32 = sampleFog(curPos) * fogHeigth;\n\t\t\tlet curSample: f32 = min(max(0., curHeigth - curPos.y), fogSlice) * stepLen / fogSlice;\n\t\t\tif (curSample > 0.001) {\n\t\t\t\tlet lightDir: vec3<f32> = normalize(lightPos - curPos);\n\t\t\t\tlet shadowStep: vec3<f32> = fogHeigth / f32(nbSlice) * lightDir / lightDir.y;\n\t\t\t\tlet lightDist2: f32 = dist2(lightPos - curPos);\n\t\t\t\tvar shadowPos: vec3<f32> = curPos + shadowStep * fudge;\n\t\t\t\tvar shadowDist: f32 = 0.;\n\n\t\t\t\tfor (var j: i32 = 0; j < nbSlice; j = j + 1) {\n\t\t\t\t\tshadowPos = shadowPos + (shadowStep);\n\t\t\t\t\tif (shadowPos.y > fogHeigth) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tlet curHeight: f32 = sampleFog(shadowPos) * fogHeigth;\n\t\t\t\t\tshadowDist = shadowDist + (min(max(0., curHeight - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice);\n\t\t\t\t}\n\n\t\t\t\tlet shadowFactor: f32 = exp(-shadowDist * shadowDensity) / lightDist2;\n\t\t\t\tcurDensity = curSample * fogDensity;\n\t\t\t\tlet absorbedlight: f32 = shadowFactor * (1. * curDensity);\n\t\t\t\tlightEnergy = lightEnergy + (absorbedlight * transmittance);\n\t\t\t\ttransmittance = transmittance * (1. - curDensity);\n\t\t\t}\n\t\t\tcurPos = curPos + (fogStep);\n\t\t}\n\n\t\tcolor = mix(color, vec3<f32>(lightEnergy), 1. - transmittance);\n\t}\n\treturn color;\n} \n\nfn vignette(color: vec3<f32>, q: vec2<f32>, v: f32) -> vec3<f32> {\n\tvar color_var = color;\n\tcolor_var = color_var * (0.3 + 0.8 * pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v));\n\treturn color_var;\n} \n\nfn setCamera(ro: vec3<f32>, ta: vec3<f32>) -> mat3x3<f32> {\n\tlet cw: vec3<f32> = normalize(ta - ro);\n\tlet up: vec3<f32> = vec3<f32>(0., 1., 0.);\n\tlet cu: vec3<f32> = normalize(cross(cw, up));\n\tlet cv: vec3<f32> = normalize(cross(cu, cw));\n\treturn mat3x3<f32>(cu, cv, cw);\n} \n\nfn radians (degrees: f32) -> f32 {\n    return degrees * ( 3.1416 / 180.);\n}\n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar tot: vec3<f32> = vec3<f32>(0.);\n\tlet p: vec2<f32> = (-uni.iResolution.xy + 2. * fragCoord) / uni.iResolution.y;\n\tlet theta: f32 = radians(360.) * (uni.iMouse.x / uni.iResolution.x - 0.5) - radians(90.);\n\tlet phi: f32 = -radians(30.);\n\tlet ro: vec3<f32> = 2. * vec3<f32>(sin(phi) * cos(theta), cos(phi), sin(phi) * sin(theta));\n\tlet ta: vec3<f32> = vec3<f32>(0.);\n\tlet ca: mat3x3<f32> = setCamera(ro, ta);\n\tlet rd: vec3<f32> = ca * normalize(vec3<f32>(p, 1.5));\n\tlet col: vec3<f32> = Render(ro, rd, 6., hash12(fragCoord + uni.iTime));\n\ttot = tot + (col);\n\ttot = vignette(tot, fragCoord / uni.iResolution.xy, 0.6);\n\tfragColor = vec4<f32>(sqrt(tot), 1.);\n\n    textureStore(texture, y_inverted_location, toLinear(fragColor));\n} \n\n\n\n\n// fn sceneIntersection(\n//     ro: vec3<f32>, \n//     rd: vec3<f32>, \n//     inter: ptr<function, vec3<f32>>, \n//     normal: ptr<function, vec3<f32>>, \n//     color: ptr<function, vec3<f32>>, \n//     dist: f32, \n//     lightPos: ptr<function, vec3<f32>>\n// ) -> f32 {\n// \tvar mint: f32 = dist;\n// \t(*inter) = vec3<f32>(0.);\n// \t(*normal) = vec3<f32>(0.);\n// \t(*color) = vec3<f32>(0.);\n\n// \tfor (var i: i32 = 0; i < nbSphere; i = i + 1) {\n// \t\tlet p2d: vec2<f32> = spherePosition(i, i32(uni.iFrame));\n// \t\tlet pos: vec3<f32> = vec3<f32>(p2d.x, ballRadius, p2d.y);\n// \t\tvar ballColor: vec3<f32> = vec3<f32>(1., 0., 0.);\n// \t\tif (i == 0) {\n// \t\t\tballColor = vec3<f32>(1.);\n// \t\t\t(*lightPos) = pos + vec3<f32>(0., lightHeight, 0.);\n// \t\t}\n// \t\tvar t: f32 = sphIntersect(ro, rd, pos, ballRadius).x;\n// \t\tif (t > 0. && t < mint) {\n// \t\t\tmint = t;\n// \t\t\t(*inter) = ro + mint * rd;\n// \t\t\t(*normal) = normalize((*inter) - pos);\n// \t\t\t(*color) = ballColor;\n// \t\t}\n// \t}\n\n\n// \t\tlet aspecRatio: f32 = uni.iResolution.x / uni.iResolution.y;\n// \t\tvar boxNormal: vec3<f32> = vec3<f32>(0. );\n// \t\tlet t: f32 = boxIntersection(ro, rd, vec3<f32>(aspecRatio, 0.1, 1.), vec3<f32>(0., -0.1, 0.), &boxNormal).x;\n\n// \t\tif (t > 0. && t < mint) {\n// \t\t\tmint = t;\n// \t\t\t(*inter) = ro + mint * rd;\n// \t\t\t(*normal) = boxNormal;\n// \t\t\tlet tileId: vec2<i32> = vec2<i32>(vec2<f32>((*inter).x, (*inter).z) * 3. + 100.);\n// \t\t\t if ((tileId.x & 1 ^ tileId.y & 1) == 0) {(*color) = vec3<f32>(0.3); } else { (*color) = vec3<f32>(0.15); };\n// \t\t}\n\n// \treturn mint;\n// } \n\n// fn sampleFog(pos: vec3<f32>) -> f32 {\n// \tvar uv: vec2<f32> = pos.xz;\n// \tuv.x = uv.x * (uni.iResolution.y / uni.iResolution.x);\n// \tuv = uv * 0.5 + 0.5;\n// \tif (max(uv.x, uv.y) > 1. || min(uv.x, uv.y) < 0.) {\n// \t\treturn 0.;\n// \t}\n// \treturn sample_texture(buffer_a, uv).z;\n// } \n\n// fn Render(ro: vec3<f32>, rd: vec3<f32>, dist: f32, fudge: f32) -> vec3<f32> {\n// \tvar inter: vec3<f32> = vec3<f32>(0.);\n// \tvar normal: vec3<f32> = vec3<f32>(0.);\n// \tvar baseColor: vec3<f32> = vec3<f32>(0.);\n// \tvar lightPos: vec3<f32> = vec3<f32>(0.);\n// \tlet mint: f32 = sceneIntersection(ro, rd, &inter, &normal, &baseColor, dist, &lightPos);\n// \tvar color: vec3<f32> = vec3<f32>(0.);\n// \tif (mint < dist) {\n// \t\tvar lightDir: vec3<f32> = normalize(lightPos - inter);\n// \t\tvar lightDist2: f32 = dist2(lightPos - inter);\n// \t\tvar shadowStep: vec3<f32> = fogHeigth / f32(nbSlice) * lightDir / lightDir.y;\n// \t\tvar shadowDist: f32 = 0.;\n\n// \t\tfor (var i: i32 = 0; i < nbSlice; i = i + 1) {\n// \t\t\tvar shadowPos: vec3<f32> = inter + shadowStep * f32(i);\n// \t\t\tlet v: f32 = sampleFog(shadowPos) * fogHeigth;\n// \t\t\tshadowDist = shadowDist + (min(max(0., v - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice);\n// \t\t}\n\n// \t\tvar shadowFactor: f32 = exp(-shadowDist * shadowDensity * 0.25);\n// \t\tcolor = baseColor * (max(0., dot(normal, lightDir) * shadowFactor) + 0.2) / lightDist2;\n// \t} else { \n// \t\tcolor = vec3<f32>(0.);\n// \t}\n// \tvar t: f32 = 0.;\n// \tif (floorIntersect(ro, rd, fogHeigth, &t)) {\n// \t\tvar curPos: vec3<f32> = ro + rd * t;\n// \t\tlet fogStep: vec3<f32> = fogHeigth / f32(nbSlice) * rd / abs(rd.y);\n// \t\tcurPos = curPos + (fudge * fogStep);\n// \t\tlet stepLen: f32 = length(fogStep);\n// \t\tvar curDensity: f32 = 0.;\n// \t\tvar transmittance: f32 = 1.;\n// \t\tvar lightEnergy: f32 = 0.;\n\n// \t\tfor (var i: i32 = 0; i < nbSlice; i = i + 1) {\n// \t\t\tif (dot(curPos - ro, rd) > mint) {\t\t\tbreak;\n//  }\n// \t\t\tlet curHeigth: f32 = sampleFog(curPos) * fogHeigth;\n// \t\t\tlet curSample: f32 = min(max(0., curHeigth - curPos.y), fogSlice) * stepLen / fogSlice;\n// \t\t\tif (curSample > 0.001) {\n// \t\t\t\tlet lightDir: vec3<f32> = normalize(lightPos - curPos);\n// \t\t\t\tlet shadowStep: vec3<f32> = fogHeigth / f32(nbSlice) * lightDir / lightDir.y;\n// \t\t\t\tlet lightDist2: f32 = dist2(lightPos - curPos);\n// \t\t\t\tvar shadowPos: vec3<f32> = curPos + shadowStep * fudge;\n// \t\t\t\tvar shadowDist: f32 = 0.;\n\n// \t\t\t\tfor (var j: i32 = 0; j < nbSlice; j = j + 1) {\n// \t\t\t\t\tshadowPos = shadowPos + (shadowStep);\n// \t\t\t\t\tif (shadowPos.y > fogHeigth) {\n// \t\t\t\t\t\tbreak;\n// \t\t\t\t\t}\n// \t\t\t\t\tlet curHeight: f32 = sampleFog(shadowPos) * fogHeigth;\n// \t\t\t\t\tshadowDist = shadowDist + (min(max(0., curHeight - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice);\n// \t\t\t\t}\n\n// \t\t\t\tlet shadowFactor: f32 = exp(-shadowDist * shadowDensity) / lightDist2;\n// \t\t\t\tcurDensity = curSample * fogDensity;\n// \t\t\t\tlet absorbedlight: f32 = shadowFactor * (1. * curDensity);\n// \t\t\t\tlightEnergy = lightEnergy + (absorbedlight * transmittance);\n// \t\t\t\ttransmittance = transmittance * (1. - curDensity);\n// \t\t\t}\n// \t\t\tcurPos = curPos + (fogStep);\n// \t\t}\n\n// \t\tcolor = mix(color, vec3<f32>(lightEnergy), 1. - transmittance);\n// \t}\n// \treturn color;\n// } \n\n// fn vignette(color: vec3<f32>, q: vec2<f32>, v: f32) -> vec3<f32> {\n// \tvar color_var = color;\n// \tcolor_var = color_var * (0.3 + 0.8 * pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v));\n// \treturn color_var;\n// } \n\n// fn setCamera(ro: vec3<f32>, ta: vec3<f32>) -> mat3x3<f32> {\n// \tlet cw: vec3<f32> = normalize(ta - ro);\n// \tlet up: vec3<f32> = vec3<f32>(0., 1., 0.);\n// \tlet cu: vec3<f32> = normalize(cross(cw, up));\n// \tlet cv: vec3<f32> = normalize(cross(cu, cw));\n// \treturn mat3x3<f32>(cu, cv, cw);\n// } \n\n// fn radians(in: f32) -> f32 {\n//     return in * (3.141592653589793 / 180.);\n// }\n\n// fn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n//     let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n//     let lower = sRGB / vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n//     let R: vec2<f32> = uni.iResolution.xy;\n//     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n// \tvar fragColor: vec4<f32>;\n// \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// \tvar tot: vec3<f32> = vec3<f32>(0.);\n// \tvar rook: array<vec2<f32>,4>;\n// \trook[0] = vec2<f32>(1. / 8., 3. / 8.);\n// \trook[1] = vec2<f32>(3. / 8., -1. / 8.);\n// \trook[2] = vec2<f32>(-1. / 8., -3. / 8.);\n// \trook[3] = vec2<f32>(-3. / 8., 1. / 8.);\n\n// \tfor (var n: i32 = 0; n < 4; n  = n + 1) {\n// \t\tlet o: vec2<f32> = rook[n];\n// \t\tlet p: vec2<f32> = (-uni.iResolution.xy + 2. * (fragCoord + o)) / uni.iResolution.y;\n// \t\tlet theta: f32 = radians(360.) * (uni.iMouse.x / uni.iResolution.x - 0.5) - radians(90.);\n// \t\tlet phi: f32 = -radians(30.);\n// \t\tlet ro: vec3<f32> = 2. * vec3<f32>(sin(phi) * cos(theta), cos(phi), sin(phi) * sin(theta));\n// \t\tlet ta: vec3<f32> = vec3<f32>(0.);\n// \t\tlet ca: mat3x3<f32> = setCamera(ro, ta);\n// \t\tlet rd: vec3<f32> = ca * normalize(vec3<f32>(p, 1.5));\n// \t\tlet col: vec3<f32> = Render(ro, rd, 6., hash12(fragCoord + uni.iTime));\n// \t\ttot = tot + (col);\n// \t}\n\n// \ttot = tot / (4.);\n// \ttot = vignette(tot, fragCoord / uni.iResolution.xy, 0.6);\n// \tfragColor = vec4<f32>(sqrt(tot), 1.);\n\n//     textureStore(texture, y_inverted_location, toLinear(fragColor));\n// } \n\n\n// // fn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n// //     let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n// //     let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n// //     let lower = sRGB / vec4<f32>(12.92);\n\n// //     return mix(higher, lower, cutoff);\n// // }\n\n// // [[stage(compute), workgroup_size(8, 8, 1)]]\n// // fn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n// //     let R: vec2<f32> = uni.iResolution.xy;\n// //     let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n// //     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n// // \tvar fragColor: vec4<f32>;\n// // \tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n// // \tfragColor = vec4<f32>(vec3<f32>(sample_texture(buffer_a, fragCoord / uni.iResolution).z), 1.);\n// //     textureStore(texture, y_inverted_location, toLinear(fragColor));\n// // } \n\n"
  },
  {
    "path": "examples/fire/buffer_a.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "examples/fire/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/fire/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/fire/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/fire/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/fire/image.wgsl",
    "content": "// https://www.shadertoy.com/view/XsXSWS\n// no licence\n\nfn hash(p: vec2<f32>) -> vec2<f32> {\n\tvar p_var = p;\n\tp_var = vec2<f32>(dot(p_var, vec2<f32>(127.1, 311.7)), dot(p_var, vec2<f32>(269.5, 183.3)));\n\treturn -1. + 2. * fract(sin(p_var) * 43758.547);\n} \n\nfn noise(p: vec2<f32>) -> f32 {\n\tlet K1: f32 = 0.36602542;\n\tlet K2: f32 = 0.21132487;\n\tlet i: vec2<f32> = floor(p + (p.x + p.y) * K1);\n\tvar a: vec2<f32> = p - i + (i.x + i.y) * K2;\n\tvar o: vec2<f32>; \n    if (a.x > a.y) { o = vec2<f32>(1., 0.); } else { o = vec2<f32>(0., 1.); };\n\tlet b: vec2<f32> = a - o + K2;\n\tvar c: vec2<f32> = a - 1. + 2. * K2;\n\tlet h: vec3<f32> = max(0.5 - vec3<f32>(dot(a, a), dot(b, b), dot(c, c)), vec3<f32>(0.));\n\tvar n: vec3<f32> = h * h * h * h * vec3<f32>(dot(a, hash(i + 0.)), dot(b, hash(i + o)), dot(c, hash(i + 1.)));\n\treturn dot(n, vec3<f32>(70.));\n} \n\nfn fbm(uv_in: vec2<f32>) -> f32 {\n\tvar f: f32;\n    var uv = uv_in;\n\tlet m: mat2x2<f32> = mat2x2<f32>(1.6, 1.2, -1.2, 1.6);\n\tf = 0.5 * noise(uv);\n\tuv = m * uv;\n\tf = f + (0.25 * noise(uv));\n\tuv = m * uv;\n\tf = f + (0.125 * noise(uv));\n\tuv = m * uv;\n\tf = f + (0.0625 * noise(uv));\n\tuv = m * uv;\n\tf = 0.5 + 0.5 * f;\n\treturn f;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\tlet uv: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\tvar q: vec2<f32> = uv;\n\tq.x = q.x * (5.);\n\tq.y = q.y * (2.);\n\tlet strength: f32 = floor(q.x + 1.);\n\tlet T3: f32 = max(3., 1.25 * strength) * uni.iTime;\n\tq.x = (q.x % 1.) - 0.5;\n\tq.y = q.y - (0.25);\n\tlet n: f32 = fbm(strength * q - vec2<f32>(0., T3));\n\tlet c: f32 = 1. - 16. * pow(max(0., length(q * vec2<f32>(1.8 + q.y * 1.5, 0.75)) - n * max(0., q.y + 0.25)), 1.2);\n\tvar c1: f32 = n * c * (1.5 - pow(2.5 * uv.y, 4.));\n\tc1 = clamp(c1, 0., 1.);\n\tlet col: vec3<f32> = vec3<f32>(1.5 * c1, 1.5 * c1 * c1 * c1, c1 * c1 * c1 * c1 * c1 * c1);\n\tlet a: f32 = c * (1. - pow(uv.y, 3.));\n\tfragColor = vec4<f32>(mix(vec3<f32>(0.), col, a), 1.);\n\n    textureStore(texture, y_inverted_location, fragColor);\n} \n\n\n\n"
  },
  {
    "path": "examples/fire2/buffer_a.wgsl",
    "content": "\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "examples/fire2/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/fire2/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/fire2/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/fire2/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/fire2/fire2.rs",
    "content": "// https://www.shadertoy.com/view/MlKSWm\n// by Ian McEwan, Ashima Arts.\n// MIT License\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            // present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: 960. as u32,\n            height: 600.0 as u32,\n            borders: 0.,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"fire2\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/fire2/image.wgsl",
    "content": "// original code: https://www.shadertoy.com/view/MlKSWm\n// MIT licence\n\nfn mod289(x: vec3<f32>) -> vec3<f32> {\n\treturn x - floor(x * (1. / 289.)) * 289.;\n} \n\nfn mod289_4(x: vec4<f32>) -> vec4<f32> {\n\treturn x - floor(x * (1. / 289.)) * 289.;\n} \n\nfn permute(x: vec4<f32>) -> vec4<f32> {\n\treturn mod289_4((x * 34. + 1.) * x);\n} \n\nfn taylorInvSqrt(r: vec4<f32>) -> vec4<f32> {\n\treturn 1.7928429 - 0.85373473 * r;\n} \n\nfn snoise(v: vec3<f32>) -> f32 {\n\tlet C: vec2<f32> = vec2<f32>(1. / 6., 1. / 3.);\n\tlet D: vec4<f32> = vec4<f32>(0., 0.5, 1., 2.);\n\n\t// First corner\n\tvar i: vec3<f32> = floor(v + dot(v, C.yyy));\n\tlet x0: vec3<f32> = v - i + dot(i, C.xxx);\n\n\t// Other corners\n\tlet g: vec3<f32> = step(x0.yzx, x0.xyz);\n\tlet l: vec3<f32> = 1. - g;\n\tlet i1: vec3<f32> = min(g.xyz, l.zxy);\n\tlet i2: vec3<f32> = max(g.xyz, l.zxy);\n\tlet x1: vec3<f32> = x0 - i1 + C.xxx;\n\tlet x2: vec3<f32> = x0 - i2 + C.yyy;\n\tlet x3: vec3<f32> = x0 - D.yyy;\n\n\t// Permutations\n\ti = mod289(i);\n\tlet p: vec4<f32> = permute(permute(permute(i.z + vec4<f32>(0., i1.z, i2.z, 1.)) + i.y + vec4<f32>(0., i1.y, i2.y, 1.)) + i.x + vec4<f32>(0., i1.x, i2.x, 1.));\n\t\n\t// Gradients: 7x7 points over a square, mapped onto an octahedron.\n\t// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)\n\tlet n_: f32 = 0.14285715;\n\tlet ns: vec3<f32> = n_ * D.wyz - D.xzx;\n\tlet j: vec4<f32> = p - 49. * floor(p * ns.z * ns.z);\n\tlet x_: vec4<f32> = floor(j * ns.z);\n\tlet y_: vec4<f32> = floor(j - 7. * x_);\n\tvar x: vec4<f32> = x_ * ns.x + ns.yyyy;\n\tvar y: vec4<f32> = y_ * ns.x + ns.yyyy;\n\tlet h: vec4<f32> = 1. - abs(x) - abs(y);\n\tlet b0: vec4<f32> = vec4<f32>(x.xy, y.xy);\n\tlet b1: vec4<f32> = vec4<f32>(x.zw, y.zw);\n\tlet s0: vec4<f32> = floor(b0) * 2. + 1.;\n\tlet s1: vec4<f32> = floor(b1) * 2. + 1.;\n\tlet sh: vec4<f32> = -step(h, vec4<f32>(0.));\n\tlet a0: vec4<f32> = b0.xzyw + s0.xzyw * sh.xxyy;\n\tlet a1: vec4<f32> = b1.xzyw + s1.xzyw * sh.zzww;\n\n\t//Normalise gradients\n\tvar p0: vec3<f32> = vec3<f32>(a0.xy, h.x);\n\tvar p1: vec3<f32> = vec3<f32>(a0.zw, h.y);\n\tvar p2: vec3<f32> = vec3<f32>(a1.xy, h.z);\n\tvar p3: vec3<f32> = vec3<f32>(a1.zw, h.w);\n\tlet norm: vec4<f32> = inverseSqrt(vec4<f32>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));\n\tp0 = p0 * (norm.x);\n\tp1 = p1 * (norm.y);\n\tp2 = p2 * (norm.z);\n\tp3 = p3 * (norm.w);\n\n\t// Mix final noise value\n\tvar m: vec4<f32> = max(0.6 - vec4<f32>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec4<f32>(0.));\n\tm = m * m;\n\treturn 42. * dot(m * m, vec4<f32>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));\n} \n\n// PRNG\n// From https://www.shadertoy.com/view/4djSRW\nfn prng(seed: vec2<f32>) -> f32 {\n\tvar seed_var = seed;\n\tseed_var = fract(seed_var * vec2<f32>(5.3983, 5.4427));\n\tseed_var = seed_var + (dot(seed_var.yx, seed_var.xy + vec2<f32>(21.5351, 14.3137)));\n\treturn fract(seed_var.x * seed_var.y * 95.4337);\n} \n\nlet PI: f32 = 3.1415927;\nfn noiseStack(pos_in: vec3<f32>, octaves: i32, falloff: f32) -> f32 {\n\tvar pos = pos_in;\n\tvar noise: f32 = snoise(vec3<f32>(pos));\n\tvar off: f32 = 1.;\n\tif (octaves > 1) {\n\t\tpos = pos * (2.);\n\t\toff = off * (falloff);\n\t\tnoise = (1. - off) * noise + off * snoise(vec3<f32>(pos));\n\t}\n\tif (octaves > 2) {\n\t\tpos = pos * (2.);\n\t\toff = off * (falloff);\n\t\tnoise = (1. - off) * noise + off * snoise(vec3<f32>(pos));\n\t}\n\tif (octaves > 3) {\n\t\tpos = pos * (2.);\n\t\toff = off * (falloff);\n\t\tnoise = (1. - off) * noise + off * snoise(vec3<f32>(pos));\n\t}\n\treturn (1. + noise) / 2.;\n} \n\nfn noiseStackUV(pos: vec3<f32>, octaves: i32, falloff: f32, diff: f32) -> vec2<f32> {\n\tlet displaceA: f32 = noiseStack(pos, octaves, falloff);\n\tlet displaceB: f32 = noiseStack(pos + vec3<f32>(3984.293, 423.21, 5235.19), octaves, falloff);\n\treturn vec2<f32>(displaceA, displaceB);\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\tlet time: f32 = uni.iTime;\n\tlet resolution: vec2<f32> = uni.iResolution.xy;\n\tlet drag: vec2<f32> = uni.iMouse.xy;\n\tlet offset: vec2<f32> = uni.iMouse.xy;\n\n\tlet xpart: f32 = fragCoord.x / resolution.x;\n\tlet ypart: f32 = fragCoord.y / resolution.y;\n\n\tlet clip: f32 = 210.;\n\tlet ypartClip: f32 = fragCoord.y / clip;\n\tlet ypartClippedFalloff: f32 = clamp(2. - ypartClip, 0., 1.);\n\tlet ypartClipped: f32 = min(ypartClip, 1.);\n\tlet ypartClippedn: f32 = 1. - ypartClipped;\n\n\tlet xfuel: f32 = 1. - abs(2. * xpart - 1.);\n\n\tlet timeSpeed: f32 = 0.5;\n\tlet realTime: f32 = timeSpeed * time;\n\n\tlet coordScaled: vec2<f32> = 0.01 * fragCoord - 0.02 * vec2<f32>(offset.x, 0.);\n\tlet position: vec3<f32> = vec3<f32>(coordScaled, 0.) + vec3<f32>(1223., 6434., 8425.);\n\tlet flow: vec3<f32> = vec3<f32>(4.1 * (0.5 - xpart) * pow(ypartClippedn, 4.), -2. * xfuel * pow(ypartClippedn, 64.), 0.);\n\tlet timing: vec3<f32> = realTime * vec3<f32>(0., -1.7, 1.1) + flow;\n\n\tlet displacePos: vec3<f32> = vec3<f32>(1., 0.5, 1.) * 2.4 * position + realTime * vec3<f32>(0.01, -0.7, 1.3);\n\tlet displace3: vec3<f32> = vec3<f32>(noiseStackUV(displacePos, 2, 0.4, 0.1), 0.);\n\n\tlet noiseCoord: vec3<f32> = (vec3<f32>(2., 1., 1.) * position + timing + 0.4 * displace3) / 1.;\n\tlet noise: f32 = noiseStack(noiseCoord, 3, 0.4);\n\n\tlet flames: f32 = pow(ypartClipped, 0.3 * xfuel) * pow(noise, 0.3 * xfuel);\n\n\tlet f: f32 = ypartClippedFalloff * pow(1. - flames * flames * flames, 8.);\n\tlet fff: f32 = f * f * f;\n\tlet fire: vec3<f32> = 1.5 * vec3<f32>(f, fff, fff * fff);\n\n\t// smoke\n\tlet smokeNoise: f32 = 0.5 + snoise(0.4 * position + timing * vec3<f32>(1., 1., 0.2)) / 2.;\n\tlet smoke: vec3<f32> = vec3<f32>(0.3 * pow(xfuel, 3.) * pow(ypart, 2.) * (smokeNoise + 0.4 * (1. - noise)));\n\n\t// sparks\n\tvar sparkGridSize: f32 = 30.;\n\tvar sparkCoord: vec2<f32> = fragCoord - vec2<f32>(2. * offset.x, 190. * realTime);\n\tsparkCoord = sparkCoord - (30. * noiseStackUV(0.01 * vec3<f32>(sparkCoord, 30. * time), 1, 0.4, 0.1));\n\tsparkCoord = sparkCoord + (100. * flow.xy);\n\n\tif (((sparkCoord.y / sparkGridSize) % 2.) < 1.) { sparkCoord.x = sparkCoord.x + (0.5 * sparkGridSize); }\n\tlet sparkGridIndex: vec2<f32> = vec2<f32>(floor(sparkCoord / sparkGridSize));\n\tlet sparkRandom: f32 = prng(sparkGridIndex);\n\tlet sparkLife: f32 = min(10. * (1. - min((sparkGridIndex.y + 190. * realTime / sparkGridSize) / (24. - 20. * sparkRandom), 1.)), 1.);\n\tvar sparks: vec3<f32> = vec3<f32>(0.);\n\tif (sparkLife > 0.) {\n\t\tlet sparkSize: f32 = xfuel * xfuel * sparkRandom * 0.08;\n\t\tlet sparkRadians: f32 = 999. * sparkRandom * 2. * PI + 2. * time;\n\t\tlet sparkCircular: vec2<f32> = vec2<f32>(sin(sparkRadians), cos(sparkRadians));\n\t\tlet sparkOffset: vec2<f32> = (0.5 - sparkSize) * sparkGridSize * sparkCircular;\n\t\tlet sparkModulus: vec2<f32> = ((sparkCoord + sparkOffset) % sparkGridSize) - 0.5 * vec2<f32>(sparkGridSize);\n\t\tlet sparkLength: f32 = length(sparkModulus);\n\t\tlet sparksGray: f32 = max(0., 1. - sparkLength / (sparkSize * sparkGridSize));\n\t\tsparks = sparkLife * sparksGray * vec3<f32>(1., 0.3, 0.);\n\t}\n\n\tfragColor = vec4<f32>(max(fire, sparks) + smoke, 1.);\n\ttextureStore(texture, y_inverted_location, toLinear(fragColor));\n} \n\n\n\n"
  },
  {
    "path": "examples/fluid/buffer_a.wgsl",
    "content": "// var<private> R: vec2<f32>;\n\nfn lnln(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n\treturn length(p - a - (b - a) * clamp(dot(p - a, b - a) / dot(b - a, b - a), 0., 1.));\n} \n\nfn T(U: vec2<f32>) -> vec4<f32> {\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(buffer_a, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(buffer_a, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(buffer_a, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(buffer_a, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar Q: vec4<f32>;\n\tvar U = vec2<f32>(f32(location.x), f32(location.y) );\n\n\t// let R = uni.iResolution.xy;\n\tlet O: vec2<f32> = U;\n\tvar A: vec2<f32> = U + vec2<f32>(1., 0.);\n\tvar B: vec2<f32> = U + vec2<f32>(0., 1.);\n\tvar C: vec2<f32> = U + vec2<f32>(-1., 0.);\n\tvar D: vec2<f32> = U + vec2<f32>(0., -1.);\n\tvar u: vec4<f32> = T(U);\n\tvar a: vec4<f32> = T(A);\n\tvar b: vec4<f32> = T(B);\n\tvar c: vec4<f32> = T(C);\n\tvar d: vec4<f32> = T(D);\n\tvar p: vec4<f32> = vec4<f32>(0.);\n\tvar g: vec2<f32> = vec2<f32>(0.);\n\n\tfor (var i: i32 = 0; i < 2; i = i + 1) {\n\t\tU = U - (u.xy);\n\t\tA = A - (a.xy);\n\t\tB = B - (b.xy);\n\t\tC = C - (c.xy);\n\t\tD = D - (d.xy);\n\n\t\tp = p + (vec4<f32>(length(U - A), length(U - B), length(U - C), length(U - D)) - 1.);\n\n\t\tg = g + (vec2<f32>(a.z - c.z, b.z - d.z));\n\t\tu = T(U);\n\t\ta = T(A);\n\t\tb = T(B);\n\t\tc = T(C);\n\t\td = T(D);\n\t}\n\n\tQ = u;\n\tlet N: vec4<f32> = 0.25 * (a + b + c + d);\n\tQ = mix(Q, N, vec4<f32>(0., 0., 1., 0.));\n\tvar Qxy = Q.xy;\n\tQxy = Q.xy - (g / 10. / f32(2.));\n\tQ.x = Qxy.x;\n\tQ.y = Qxy.y;\n\tQ.z = Q.z + ((p.x + p.y + p.z + p.w) / 10.);\n\tQ.z = Q.z * (0.95);\n\n\tlet mouse: vec4<f32> = textureLoad(buffer_d, vec2<i32>(vec2<f32>(0.5) * R));\n\tlet q: f32 = lnln(U, mouse.xy, mouse.zw);\n\tlet m: vec2<f32> = mouse.xy - mouse.zw;\n\tlet l: f32 = length(m);\n\n\tif (mouse.z > 0. && l > 0.) {\n\t\tvar Qxyw = Q.xyw;\n        Qxyw = mix(Q.xyw, vec3<f32>(-normalize(m) * min(l, 20.) / 25., 1.), max(0., 5. - q) / 25.);\n        Q.x = Qxyw.x;\n        Q.y = Qxyw.y;\n        Q.w = Qxyw.z;\n\t}\n\t// ifuni.iFrame < 1) { \n        \n    #ifdef INIT\n        Q = vec4<f32>(0.); \n    #endif\n        \n        \n\tif (uni.iFrame < 140. && length(U - 0.5 * R) < 20.) {\n        var Qxyw = Q.xyw;\n        Qxyw = vec3<f32>(0., 0.1, 1.);\n        Q.x = Qxyw.x;\n        Q.y = Qxyw.y;\n        Q.w = Qxyw.z; \n    }\n\tif (U.x < 1. || U.y < 1. || R.x - U.x < 1. || R.y - U.y < 1.) { \n        var Qxyw = Q.xyw;\n        Qxyw = Q.xyw * (0.);\n        Q.x = Qxyw.x;\n        Q.y = Qxyw.y;\n        Q.w = Qxyw.z; \n    }\n\n    textureStore(buffer_a, location, Q);\n} \n\n"
  },
  {
    "path": "examples/fluid/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    \n} \n\n"
  },
  {
    "path": "examples/fluid/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n   \n} \n\n"
  },
  {
    "path": "examples/fluid/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar p: vec4<f32> = textureLoad(buffer_d, vec2<i32>(fragCoord));\n\tif (uni.iMouse.z > 0.) {\n\t\tif (p.z > 0.) {\t\t\n            fragColor = vec4<f32>(uni.iMouse.xy, p.xy);\n\t\t} else { \t\t\n            fragColor = vec4<f32>(uni.iMouse.xy, uni.iMouse.xy);\n\t\t}\n\t} else { \t\n        fragColor = vec4<f32>(-uni.iResolution.xy, -uni.iResolution.xy);\n\t}\n\n    textureStore(buffer_d, location, fragColor);\n} \n\n"
  },
  {
    "path": "examples/fluid/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/fluid/fluid.rs",
    "content": "// https://www.shadertoy.com/view/XtGcDK\n// by Wyatt\n// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n    window::PresentMode,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: (960.0_f32 * 1.0).floor() as u32,\n            height: (600.0_f32 * 1.0).floor() as u32,\n            borders: 0.,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        // .add_system(update_common_uniform)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"fluid\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/fluid/image.wgsl",
    "content": "fn t(v: vec2<f32>) -> vec4<f32> {\n\treturn textureLoad(buffer_a, vec2<i32>(v ));\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar C: vec4<f32>;\n\tlet U = vec2<f32>( f32(location.x), f32(location.y) );\n\n\tvar me: vec4<f32> = t(U);\n\tme.z = me.z - (1.);\n\tC = 1. - 3. * me.wwww;\n\n\tlet d: vec3<f32> = vec3<f32>(\n        t(U + vec2<f32>(1., 0.)).w - t(U - vec2<f32>(1., 0.)).w, \n        t(U + vec2<f32>(0., 1.)).w - t(U - vec2<f32>(0., 1.)).w, \n        2.\n    );\n\n\tvar Cxyz = C.xyz;\n\tCxyz = C.xyz - (\n        max(\n            vec3<f32>(0.), \n            sin(vec3<f32>(\n                100. * length(me.xy), \n                -5. * me.z, \n                368. * d.y\n            ) * me.w)\n        ));\n\n\tC.x = Cxyz.x;\n\tC.y = Cxyz.y;\n\tC.z = Cxyz.z;\n    C.a = 1.;\n\n    // let col_debug_info = show_debug_info(location, C.xyz);\n\n    // textureStore(texture, y_inverted_location, toLinear(col_debug_info));\n\n    textureStore(texture, y_inverted_location, (C));\n    // textureStore(texture, y_inverted_location, t(U));\n}"
  },
  {
    "path": "examples/liquid_toy/buffer_a.wgsl",
    "content": "let speed: f32 = 0.01;\nlet scale: f32 = 0.1;\nlet falloff: f32 = 3.;\nlet fade: f32 = 0.4;\nlet strength: f32 = 1.;\nlet range: f32 = 5.;\nfn random3(c: vec3<f32>) -> vec3<f32> {\n\tvar j: f32 = 4096. * sin(dot(c, vec3<f32>(17., 59.4, 15.)));\n\tvar r: vec3<f32>;\n\tr.z = fract(512. * j);\n\tj = j * (0.125);\n\tr.x = fract(512. * j);\n\tj = j * (0.125);\n\tr.y = fract(512. * j);\n\treturn r - 0.5;\n} \n\nlet F3: f32 = 0.3333333;\nlet G3: f32 = 0.1666667;\nfn simplex3d(p: vec3<f32>) -> f32 {\n\tlet s: vec3<f32> = floor(p + dot(p, vec3<f32>(F3)));\n\tvar x: vec3<f32> = p - s + dot(s, vec3<f32>(G3));\n\tlet e: vec3<f32> = step(vec3<f32>(0.), x - x.yzx);\n\tlet i1: vec3<f32> = e * (1. - e.zxy);\n\tlet i2: vec3<f32> = 1. - e.zxy * (1. - e);\n\tlet x1: vec3<f32> = x - i1 + G3;\n\tlet x2: vec3<f32> = x - i2 + 2. * G3;\n\tlet x3: vec3<f32> = x - 1. + 3. * G3;\n\tvar w: vec4<f32>;\n\tvar d: vec4<f32>;\n\tw.x = dot(x, x);\n\tw.y = dot(x1, x1);\n\tw.z = dot(x2, x2);\n\tw.w = dot(x3, x3);\n\tw = max(0.6 - w, vec4<f32>(0.));\n\td.x = dot(random3(s), x);\n\td.y = dot(random3(s + i1), x1);\n\td.z = dot(random3(s + i2), x2);\n\td.w = dot(random3(s + 1.), x3);\n\tw = w * (w);\n\tw = w * (w);\n\td = d * (w);\n\treturn dot(d, vec4<f32>(52.));\n} \n\nlet rot1: mat3x3<f32> = mat3x3<f32>(\n    vec3<f32>(-0.37, 0.36, 0.85), \n    vec3<f32>(-0.14, -0.93, 0.34), \n    vec3<f32>(0.92, 0.01, 0.4));\n\nlet rot2: mat3x3<f32> = mat3x3<f32>(\n     vec3<f32>(-0.55, -0.39, 0.74), \n     vec3<f32>(0.33, -0.91, -0.24), \n     vec3<f32>(0.77, 0.12, 0.63));\n\nlet rot3: mat3x3<f32> = mat3x3<f32>(\n     vec3<f32>(-0.71, 0.52, -0.47), \n     vec3<f32>(-0.08, -0.72, -0.68), \n     vec3<f32>(-0.7, -0.45, 0.56));\n\nfn simplex3d_fractal(m: vec3<f32>) -> f32 {\n\treturn 0.5333333 * simplex3d(m * rot1) + 0.2666667 * simplex3d(2. * m * rot2) + 0.1333333 * simplex3d(4. * m * rot3) + 0.0666667 * simplex3d(8. * m);\n} \n\nfn dummy(p3: vec3<f32>) -> vec3<f32> {\n\tvar value: f32 = simplex3d(p3 * 16.);\n\tvalue = 0.5 + 0.5 * value;\n\treturn vec3<f32>(value);\n} \n\nfn fbm(p: vec3<f32>) -> vec3<f32> {\n\tvar result: vec3<f32> = vec3<f32>(0.);\n\tvar amplitude: f32 = 0.5;\n\n\tfor (var index: f32 = 0.; index < 3.; index  = index + 1.) {\n\t\tlet what: vec3<f32> = dummy(p / amplitude);\n\t\tresult = result + (what * amplitude);\n\t\tamplitude = amplitude / (falloff);\n\t}\n\n\treturn result;\n} \n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar uv: vec2<f32> = (fragCoord.xy - uni.iResolution.xy / 2.) / uni.iResolution.y;\n\tvar spice: vec3<f32> = fbm(vec3<f32>(uv * scale, uni.iTime * speed));\n\tlet t: f32 = uni.iTime * 2.;\n\tlet mouse: vec2<f32> = (uni.iMouse.xy - uni.iResolution.xy / 2.) / uni.iResolution.y;\n\tif (uni.iMouse.z > 0.5) {\tuv = uv - (mouse);\n\t} else { \tuv = uv - (vec2<f32>(cos(t), sin(t)) * 0.3);\n\t}\n\tvar paint: f32 = smoothstep(0.1, 0., length(uv));\n\tvar offset: vec2<f32> = vec2<f32>(0.);\n\tuv = fragCoord.xy / uni.iResolution.xy;\n\n\tlet data: vec4<f32> = sample_texture(buffer_a, uv);\n\tlet unit: vec3<f32> = vec3<f32>(range / uni.iResolution.xy, 0.);\n\n\tlet normal: vec3<f32> = normalize(vec3<f32>(\n        sample_texture(buffer_a, uv - unit.xz).r \n        - sample_texture(buffer_a, uv + unit.xz).r, sample_texture(buffer_a, uv - unit.zy).r \n        - sample_texture(buffer_a, uv + unit.zy).r, data.x * data.x) + 0.001);\n\n\toffset = offset - (normal.xy);\n\tspice.x = spice.x * (6.28 * 2.);\n\tspice.x = spice.x + (uni.iTime);\n\toffset = offset + (vec2<f32>(cos(spice.x), sin(spice.x)));\n\tlet frame: vec4<f32> = sample_texture(buffer_a, uv + strength * offset / uni.iResolution.xy);\n\tpaint = max(paint, frame.x - uni.iTimeDelta * fade);\n\tfragColor = vec4<f32>(clamp(paint, 0., 1.));\n\n    textureStore(buffer_a, location, fragColor);\n} \n\n\n\n"
  },
  {
    "path": "examples/liquid_toy/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/liquid_toy/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/liquid_toy/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/liquid_toy/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/liquid_toy/image.wgsl",
    "content": "// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\nfn sample_texture(ch: texture_storage_2d<rgba32float, read_write>, U01: vec2<f32>) -> vec4<f32> {\n\tlet U = U01 * uni.iResolution;\n\tlet f = vec2<i32>(floor(U));\n\tlet c = vec2<i32>(ceil(U));\n\tlet fr = fract(U);\n\n\tlet upleft =    vec2<i32>( f.x,  c.y );\n\tlet upright =   vec2<i32>( c.x , c.y );\n\tlet downleft =  vec2<i32>( f.x,  f.y );\n\tlet downright = vec2<i32>( c.x , f.y );\n\n\n\tlet interpolated_2d = (\n\t\t (1. - fr.x) * (1. - fr.y) \t* textureLoad(ch, downleft)\n\t\t+ (1. - fr.x) * fr.y \t\t* textureLoad(ch, upleft)\n\t\t+ fr.x * fr.y  \t\t\t\t* textureLoad(ch, upright)\n\t\t+  fr.x * (1. - fr.y) \t\t* textureLoad(ch, downright)\n\t);\n\n\treturn interpolated_2d;\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tvar uv: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\t// let dither: vec3<f32> = textureSample(blue_noise_texture, \n    //     blue_noise_texture_sampler, fragCoord.xy / 1024.).rgb;\n    // let dither: vec3<f32> = textureSample(rgba_noise_256_texture, \n    //     rgba_noise_256_texture_sampler, fragCoord.xy / 256.).rgb;\n\n    let dither: vec3<f32> =  textureSampleGrad(blue_noise_texture,\n                     blue_noise_texture_sampler,\n                      fragCoord.xy / 1024.,\n                      vec2<f32>(0.),\n                      vec2<f32>(0.)).rbg;\n\n\tlet data: vec4<f32> = sample_texture(buffer_a, uv);\n\tlet gray: f32 = data.x;\n\tlet range: f32 = 3.;\n\tlet unit: vec3<f32> = vec3<f32>(range / uni.iResolution.xy, 0.);\n\tlet normal: vec3<f32> = normalize(vec3<f32>(sample_texture(buffer_a, uv + unit.xz).r \n        - sample_texture(buffer_a, uv - unit.xz).r, \n        sample_texture(buffer_a, uv - unit.zy).r \n        - sample_texture(buffer_a, uv + unit.zy).r, gray * gray * gray));\n\n\tvar color: vec3<f32> = vec3<f32>(0.3) * (1. - abs(dot(normal, vec3<f32>(0., 0., 1.))));\n\tlet dir: vec3<f32> = normalize(vec3<f32>(0., 1., 2.));\n\tlet specular: f32 = pow(dot(normal, dir) * 0.5 + 0.5, 20.);\n\tcolor = color + (vec3<f32>(0.5) * smoothstep(0.2, 1., specular));\n\tlet tint: vec3<f32> = 0.5 + 0.5 * cos(vec3<f32>(1., 2., 3.) * 1. + dot(normal, dir) * 4. - uv.y * 3. - 3.);\n\tcolor = color + (tint * smoothstep(0.15, 0., gray));\n\tcolor = color - (dither.x * 0.1);\n\tvar background: vec3<f32> = vec3<f32>(1.);\n\tbackground = background * (smoothstep(1.5, -0.5, length(uv - 0.5)));\n\tcolor = mix(background, clamp(color, vec3<f32>(0.), vec3<f32>(1.)), smoothstep(0.01, 0.1, gray));\n\tif (uni.iMouse.z > 0.5 && uni.iMouse.x / uni.iResolution.x < 0.1) {\n\t\tif (uv.x < 0.33) {\t\tcolor = vec3<f32>(gray);\n\t\t} else { \t\tif (uv.x < 0.66) {\t\tcolor = normal * 0.5 + 0.5;\n\t\t} else { \t\tcolor = vec3<f32>(tint);\n\t\t}\n\t\t}\n\t}\n\tfragColor = vec4<f32>(color, 1.);\n    textureStore(texture, y_inverted_location, toLinear(fragColor));\n} \n\n\n\n\n"
  },
  {
    "path": "examples/liquid_toy/liquid_toy.rs",
    "content": "// Original shader by leon\n// https://www.shadertoy.com/view/fljBWc\n// Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0)\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n    // window::PresentMode,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            // present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: 960. as u32,\n            height: 600.0 as u32,\n            borders: 0.0,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"liquid_toy\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/minimal/buffer_a.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "examples/minimal/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/minimal/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/minimal/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/minimal/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/minimal/image.wgsl",
    "content": "// displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a\n// here\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var O: vec4<f32> =  textureLoad(buffer_a, location);\n    textureStore(texture, location, O);\n}"
  },
  {
    "path": "examples/minimal/minimal.rs",
    "content": "use bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            // present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: 960. as u32,\n            height: 600.0 as u32,\n            borders: 0.0,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"minimal\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/paint/buffer_a.wgsl",
    "content": "fn hue(v: f32) -> vec4<f32> {\n    return (vec4<f32>(.6) + vec4<f32>(.6) * cos(vec4<f32>(6.3 * v) + vec4<f32>(0.0, 23.0, 21.0, 0.0)));\n}\n\nfn smoothit(v: f32) -> f32 {\n    return smoothstep(1.5, 0., v);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn sdRhombus(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let q = abs(p);\n    let qb = dot(q, vec2<f32>(b.x, -b.y));\n    let bb = dot(b, vec2<f32>(b.x, -b.y));\n    let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.);\n    let d = length(q - 0.5 * b * vec2<f32>(1. - h, 1. + h));\n    return d * sign(q.x * b.y + q.y * b.x - b.x * b.y);\n}\n\nfn sdTriangleIsosceles(p: vec2<f32>, c: vec2<f32>) -> f32 {\n    let q = vec2<f32>(abs(p.x), p.y);\n    let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.);\n    let b = q - c * vec2<f32>(clamp(q.x / c.x, 0., 1.), 1.);\n    let s = -sign(c.y);\n    let d = min(vec2<f32>(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2<f32>(dot(b, b), s * (q.y - c.y)));\n    return -sqrt(d.x) * sign(d.y);\n}\n\nfn sdStar(p: vec2<f32>, r: f32, n: u32, m: f32) -> f32 {\n    let an = 3.141593 / f32(n);\n    let en = 3.141593 / m;\n    let acs = vec2<f32>(cos(an), sin(an));\n    let ecs = vec2<f32>(cos(en), sin(en));\n    let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an;\n    var q: vec2<f32> = length(p) * vec2<f32>(cos(bn), abs(sin(bn)));\n    q = q - r * acs;\n    q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y);\n    return length(q) * sign(q.x);\n}\n\nfn sdHeart(p: vec2<f32>) -> f32 {\n    let q = vec2<f32>(abs(p.x), p.y);\n    let w = q - vec2<f32>(0.25, 0.75);\n    if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; }\n    let u = q - vec2<f32>(0., 1.0);\n    let v = q - 0.5 * max(q.x + q.y, 0.);\n    return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y);\n}\n\nfn sdMoon(p: vec2<f32>, d: f32, ra: f32, rb: f32) -> f32 {\n    let q = vec2<f32>(p.x, abs(p.y));\n    let a = (ra * ra - rb * rb + d * d) / (2. * d);\n    let b = sqrt(max(ra * ra - a * a, 0.));\n    if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q - vec2<f32>(a, b)); }\n    return max((length(q) - ra), -(length(q - vec2<f32>(d, 0.)) - rb));\n}\n\nfn sdCross(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    var q: vec2<f32> = abs(p);\n    q = select(q.xy, q.yx, q.y > q.x);\n    let t = q - b;\n    let k = max(t.y, t.x);\n    let w = select(vec2<f32>(b.y - q.x, -k), t, k > 0.);\n    return sign(k) * length(max(w, vec2<f32>(0.)));\n}\n\nfn sdRoundedX(p: vec2<f32>, w: f32, r: f32) -> f32 {\n    let q = abs(p);\n    return length(q - min(q.x + q.y, w) * 0.5) - r;\n}\n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\n// [[stage(compute), workgroup_size(8, 8, 1)]]\n// fn init([[builtin(global_invocation_id)]] invocation_id: vec3<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n//     let location_f32 = vec2<f32>(f32(invocation_id.x), f32(invocation_id.y));\n\n//     # ifdef INIT\n//         if (location.x == 0 && location.y == 0 )  {\n//             textureStore(buffer_a, location, hue(4.0 / 8.0));\n//         } else {\n//             // set brush color to black\n//             let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n//             textureStore(buffer_a, location, black);\n//         }\n//     # endif\n// }\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    // let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    // let location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n\n    // on the very first frame, INIT is defined. Otherwise, it is not.\n    #ifdef INIT\n        if (location.x == 0 && location.y == 0) {\n            textureStore(buffer_a, location, hue(4.0 / 8.0));\n        } else {\n                // set brush color to black\n            let black = vec4<f32>(0.0, 0.0, 0.0, 1.0);\n            textureStore(buffer_a, location, black);\n        }\n    #endif\n    // }\n\n    let U: vec2<f32> = vec2<f32>(location) / R;\n    let M: vec2<f32> = vec2<f32>(uni.iMouse.x, uni.iMouse.y) / R ;\n\n\n     var O: vec4<f32> = textureLoad(buffer_a, location);\n\n    if (location.x == 0 && location.y == 0) {\n        if (M.x < 0.1 && uni.iMouse.w > 0.0) { // just pressed left mouse button\n            let y: f32 = floor(9. * M.y);\n            O = hue(y / 8.);\n\n             textureStore(buffer_a, location, O);\n        }\n        return;\n    }\n\n\n    // display palette on left\n    if (U.x < 0.1) {\n        let y: f32 = floor(9. * U.y);\n        O = hue(y / 8.);\n        O.w = 1.;\n        textureStore(buffer_a, location, O);\n        return;\n    }\n\n    let brush_color = textureLoad(buffer_a, vec2<i32>(0, 0));\n\n    // apply paint\n    if (uni.iMouse.z > 1.0) {\n        let mouse_pix = vec2<f32>(uni.iMouse.x, uni.iMouse.y);\n\n        let brush_sdf = sdCircle(vec2<f32>(location), mouse_pix, 10.0);\n        let brush_d = smoothstep(0.0, 5.0, brush_sdf);\n        let brush_intensity = 0.1;\n        O = mix(O, brush_color, (1.0 - brush_d) * brush_intensity);\n    }\n\n    let inverted_y = vec2<i32>(location.x, location.y);\n\n\n    textureStore(buffer_a, location, O);\n}"
  },
  {
    "path": "examples/paint/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/paint/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/paint/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/paint/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/paint/image.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let location2 = vec2<i32>(i32(R.x) - i32(invocation_id.x), i32(invocation_id.y));\n\n    var alive = true;\n\n\tvar q: f32;\n\tif (true) { \n\t\tq = 1.;\n\t} else { \n\t\tq = 4.;\n\t};\n\n    var O: vec4<f32> =  mix(textureLoad(buffer_a, location),vec4<f32>(0.5), 0.1);\n\n    // var O: vec4<f32> = vec4<f32>(0.5);\n\n    textureStore(texture, y_inverted_location, O);\n}"
  },
  {
    "path": "examples/paint/paint.rs",
    "content": "use bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n    window::PresentMode,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: 960. as u32,\n            height: 600.0 as u32,\n            borders: 0.2,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"paint\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/paint_streams/buffer_a.wgsl",
    "content": "fn Reintegration(ch: texture_storage_2d<rgba32float, read_write>, pos: vec2<f32>) -> particle {\n\n    var P: particle = particle(vec2<f32>(0.0), vec2<f32>(0.0), vec2<f32>(0.0));\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\n            let data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\n            var P0: particle = getParticle(data, tpos);\n\n            P0.X = P0.X + (P0.V * dt); //integrate position\n\n            let difR: f32 = 0.9 + 0.21 * smoothstep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x);\n\n            let D: vec3<f32> = distribution(P0.X, pos, difR);\n            let m: f32 = P0.M.x * D.z;\n            P.X = P.X + (D.xy * m);\n            P.V = P.V + (P0.V * m);\n            P.M.y = P.M.y + (P0.M.y * m);\n            P.M.x = P.M.x + (m);\n        }\n    }\n\n\n    if (P.M.x > 0.0000001) {\n        P.X = P.X / (P.M.x);\n        P.V = P.V / (P.M.x);\n        P.M.y = P.M.y / (P.M.x);\n    }\n\n    return P;\n} \n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var U: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n\t// R = uni.iResolution.xy;\n\t// time = uni.iTime;\n\t// Mouse = uni.iMouse;\n    // let p: vec2<i32> = vec2<i32>(pos);\n\t// let data: vec4<f32> = texel(ch0, pos);\n    // var P: particle;\n    var P: particle = Reintegration(buffer_b, pos);\n\n\t// if (uni.iFrame < 1) {\n    #ifdef INIT\n    let rand: vec3<f32> =  hash32(pos); \n\n    if (rand.z < 0.) {\n        P.X = pos;\n        P.V = 0.5 * (rand.xy - 0.5) + vec2<f32>(0., 0.);\n        P.M = vec2<f32>(mass, 0.);\n    } else {\n\n        P.X = pos;\n        P.V = vec2<f32>(0.);\n        P.M = vec2<f32>(0.000001);\n    }\n    #endif\n\t// }\n\n    U = saveParticle(P, pos);\n    // U = clamp(U, vec4<f32>(0.), vec4<f32>(1.));\n    textureStore(buffer_a, location, U);\n} \n"
  },
  {
    "path": "examples/paint_streams/buffer_b.wgsl",
    "content": "\nfn border(p: vec2<f32>, R2: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\n\n\nfn bN(p: vec2<f32>, R2: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0., h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2);\n    return vec3<f32>(normalize(r.xy), r.z + 1.0e-4);\n} \n\nfn Simulation(\n    ch: texture_storage_2d<rgba32float, read_write>, \n    P: ptr<function, particle>,\n    pos: vec2<f32>)  \n{\n    var F: vec2<f32> = vec2<f32>(0.);\n    var avgV: vec3<f32> = vec3<f32>(0.,);\n\n    // var P = *PIn;\n    for (var i: i32 = -2; i <= 2; i = i + 1) {\n        for (var j: i32 = -2; j <= 2; j = j + 1) {\n            let tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n            // let data: vec4<f32> = texelFetch(ch, Bi(tpos), 0.);\n\n            let data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos)) ;\n\n            var P0: particle = getParticle(data, tpos);\n            let dx: vec2<f32> = P0.X - (*P).X;\n            let avgP: f32 = 0.5 * P0.M.x * (Pf((*P).M) + Pf(P0.M));\n            F = F - (0.5 * G(1. * dx) * avgP * dx);\n            avgV = avgV + (P0.M.x * G(1. * dx) * vec3<f32>(P0.V.x, P0.V.y, 1.));\n        }\n    }\n\n    var avgVxy = avgV.xy;\n    avgVxy = avgV.xy / (avgV.z);\n    avgV.x = avgVxy.x;\n    avgV.y = avgVxy.y;\n\n    F = F + (0. * (*P).M.x * (avgV.xy - (*P).V));\n    F = F + ((*P).M.x * vec2<f32>(0., -0.0004));\n\n    if (Mouse.z > 0.) {\n        let dm: vec2<f32> = (Mouse.xy - Mouse.zw ) / 10.;\n        let d: f32 = distance(Mouse.xy, (*P).X) / 20.;\n        F = F + (0.001 * dm * exp(-d * d));\n\n        // let Part = particle(vec2<f32>(0.), vec2<f32>(0.), vec2<f32>(0.));\n        // return Part;\n    }\n\n    (*P).V = (*P).V + (F * dt / (*P).M.x);\n\n    let N: vec3<f32> = bN((*P).X, R);\n\n    let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, (*P).V);\n    (*P).V = (*P).V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN)));\n    (*P).V = (*P).V + (0. * (*P).M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z));\n\n    if (N.z < 0.) {\n        (*P).V = vec2<f32>(0.);\n    }\n\n    let v: f32 = length((*P).V);\n    var dum: f32;\n    if (v > 1.) { dum = v; } else { dum = 1.; }\n    (*P).V = (*P).V / dum;\n\n    // return P;\n}\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var U: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n        // R = uni.iResolution.xy;\n    time = uni.iTime;\n    Mouse = uni.iMouse;\n    let p: vec2<i32> = vec2<i32>(pos);\n        // let data: vec4<f32> = texel(ch0, pos);\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n\n    if (P.M.x != 0.) {\n         Simulation(buffer_a, &P, pos);\n    }\n\n    let timeMult = 1.0;\n    if (length(P.X - R * vec2<f32>(0.55, 0.9)) < 20.) {\n        P.X = pos;\n        P.V = 0.5 * Dir(-PI * 0.75 + 0.3 * sin(0.4 * 2.0 * timeMult));\n        P.M = mix(P.M, vec2<f32>(fluid_rho, 1.), 0.4);\n    }\n\n    if (length(P.X - R * vec2<f32>(0.45, 0.9)) < 20.) {\n        // P.X = pos;\n        // P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * timeMult));\n        // P.M = mix(P.M, vec2<f32>(fluid_rho, 0.), 0.4);\n\n        P.X = pos;\n        P.V = 0.5 * Dir(PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * 2.0 * timeMult));\n        P.M = mix(P.M, vec2<f32>(fluid_rho, 0.5), 0.4);\n    }\n\n    U = saveParticle(P, pos);\n\n    // U = clamp(U, vec4<f32>(-1000000.), vec4<f32>(100000.));\n    // U.y = clamp(U.y, -1000000., 100000.);\n    textureStore(buffer_b, location, U);\n\n\n    // let b = vec4<f32>(.5, 0.2, 0.1, 1.0) * -10000.0;\n    // textureStore(buffer_b, location, b);\n} \n\n"
  },
  {
    "path": "examples/paint_streams/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var fragColor: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y));\n\n\t// R = uni.iResolution.xy;\n    time = uni.iTime;\n    let p: vec2<i32> = vec2<i32>(pos);\n    // let data: vec4<f32> = texel(ch0, pos);\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n    var rho: vec4<f32> = vec4<f32>(0.);\n\n    for (var i: i32 = -1; i <= 1; i = i + 1) {\n        for (var j: i32 = -1; j <= 1; j = j + 1) {\n            let ij: vec2<i32> = vec2<i32>(i, j);\n            // let data: vec4<f32> = texel(ch0, pos + ij);\n            let data: vec4<f32> = textureLoad(buffer_a, location + ij);\n\n            var P0: particle = getParticle(data, pos + vec2<f32>(ij));\n            let x0: vec2<f32> = P0.X;\n            rho = rho + (1. * vec4<f32>(P.V, P.M) * G((pos - x0) / 0.75));\n        }\n    }\n\n    // fragColor = rho;d\n    // rho = clamp(rho, vec4<f32>(0.), vec4<f32>(1.));\n    textureStore(buffer_c, location, rho);\n} \n\n"
  },
  {
    "path": "examples/paint_streams/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/paint_streams/common.wgsl",
    "content": "\nlet PI = 3.14159265;\n\nlet dt = 2.5;\n\nlet border_h = 5.;\n\nlet h = 1.;\n\nlet mass = 1.;\n\nlet fluid_rho = 0.5;\n\n// let  dif = 1.12;\n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\n\n\n\nfn Pf(rho: vec2<f32>) -> f32 {\n    let GF: f32 = 1.;\n    return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF);\n} \n\nfn Rot(ang: f32) -> mat2x2<f32> {\n    return mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n    return vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n    let d: vec2<f32> = abs(p) - b;\n    // return length(max(d, 0.)) + min(max(d.x, d.y), 0.);\n    return length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\n\n\n// uint pack(vec2 x)\n// {\n//     x = 65534.0*clamp(0.5*x+0.5, 0., 1.);\n//     return uint(round(x.x)) + 65535u*uint(round(x.y));\n// }\n\n\n\n// fn unpack(a: u32) -> vec2<f32> {\n//     var x: vec2<f32> = vec2<f32>(f32(a) % 65535., f32(a) / 65535.);\n//     return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n// } \n\n// vec2 unpack(uint a)\n// {\n//     vec2 x = vec2(a % 65535u, a / 65535u);\n//     return clamp(x/65534.0, 0.,1.)*2.0 - 1.0;\n// }\n\n\n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpack(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = pack(x);\n// \treturn uintBitsToFloat(X);\n// } \n\n// fn decode(&self, place: u8, precis: u8) -> f32 {\n//     let value_u32 = self >> (place - precis);\n\n//     let mut mask = u32::MAX;\n//     if precis < 32 {\n//         mask = (1 << (precis)) - 1;\n//     }\n\n//     // println!(\"mask: {:#0b}\", value_u32);\n//     let masked_value_u32 = value_u32 & mask;\n//     let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32);\n\n//     value_f32\n// }\n\nfn pack(xIn: vec2<f32 >) -> u32 {\n    var x = xIn;\n    let x = 65534. * clamp(0.5 * x + 0.5, vec2<f32 >(0.00), vec2<f32 >(1.0));\n    return u32(round(x.x)) + 65535u * u32(round(x.y));\n} \n\nfn unpack(a: u32) -> vec2<f32> {\n    var x: vec2<f32> = vec2<f32>(f32(a % 65535u), f32(a / 65535u));\n    return clamp(x / 65534., vec2<f32 >(0.), vec2<f32 >(1.)) * 2. - 1.;\n} \n\nfn decode(x: f32) -> vec2<f32> {\n    var X: u32 = u32(x);\n    return unpack(X);\n} \n\nfn encode(x: vec2<f32>) -> f32 {\n    var X: u32 = pack(x);\n    return f32(X);\n} \n\n\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nstruct particle {\n\tX: vec2<f32>,\n\tV: vec2<f32>,\n\tM: vec2<f32>,\n};\n\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n    var P: particle;\n    P.X = decode1uToVec2(data.x) + pos;\n    P.V = decode1uToVec2(data.y);\n    P.M = data.zw;\n    return P;\n} \n\nfn saveParticle(PIn: particle, pos: vec2<f32>) -> vec4<f32> {\n    var P: particle = PIn;\n    P.X = clamp(P.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n    return vec4<f32>(\n        f32(encodeVec2To1u(P.X)),\n        f32(encodeVec2To1u(P.V)),\n        P.M\n    );\n} \n\n\n// fn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n//     var P: particle = particle(\n//         decode(data.x) + pos,\n//         decode(data.y),\n//         data.zw\n//     );\n//     return P;\n// } \n\n// fn saveParticle(P: particle, pos: vec2<f32>) -> vec4<f32> {\n//     var P2: particle = particle(P.X, P.V, P.M);\n//     P2.X = clamp(P2.X - pos, vec2<f32>(-0.5), vec2<f32>(0.5));\n//     return vec4<f32>(encode(P2.X), encode(P2.V), P2.M);\n// } \n\nfn hash32(p: vec2<f32>) -> vec3<f32> {\n    var p3: vec3<f32> = fract(vec3<f32>(p.xyx) * vec3<f32>(0.1031, 0.103, 0.0973));\n    p3 = p3 + (dot(p3, p3.yxz + 33.33));\n    return fract((p3.xxy + p3.yzz) * p3.zyx);\n} \n\nfn G(x: vec2<f32>) -> f32 {\n    return exp(-dot(x, x));\n} \n\nfn G0(x: vec2<f32>) -> f32 {\n    return exp(-length(x));\n} \n\n\n\nfn distribution(x: vec2<f32>, p: vec2<f32>, K: f32) -> vec3<f32> {\n    let omin: vec2<f32> = clamp(x - K * 0.5, p - 0.5, p + 0.5);\n    let omax: vec2<f32> = clamp(x + K * 0.5, p - 0.5, p + 0.5);\n    return vec3<f32>(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K));\n} \n\n// struct particle {\n// \tX: vec2<f32>,\n// \tV: vec2<f32>,\n// \tM: vec2<f32>,\n// };\n\n// fn fromLinear(linearRGB: vec4<f32>) -> vec4<f32> {\n//     let cutoff: vec4<f32> = vec4<f32>(linearRGB < vec4<f32>(0.0031308));\n//     let higher: vec4<f32> = vec4<f32>(1.055) * pow(linearRGB, vec4<f32>(1.0 / 2.4)) - vec4<f32>(0.055);\n//     let lower: vec4<f32> = linearRGB * vec4<f32>(12.92);\n\n//     return mix(higher, lower, cutoff);\n// }\n\n// Converts a color from sRGB gamma to linear light gamma\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}"
  },
  {
    "path": "examples/paint_streams/image.wgsl",
    "content": "// https://www.shadertoy.com/view/WtfyDj\n// no license\n// https://michaelmoroz.github.io/Reintegration-Tracking/\n\nfn mixN(a: vec3<f32>, b: vec3<f32>, k: f32) -> vec3<f32> {\n    return sqrt(mix(a * a, b * b, clamp(k, 0., 1.)));\n} \n\nfn V(p: vec2<f32>) -> vec4<f32> {\n    let data: vec4<f32> = textureLoad(buffer_c, vec2<i32>(p));\n    //  let data: vec4<f32> = textureSampleLevel(buffer_c, buffer_sampler, p / R, 0.0);\n    // let data: vec4<f32> = textureSampleGrad(buffer_c,\n    //                  buffer_sampler,\n    //                  p / R,\n    //                  vec2<f32>(0.0),\n    //                  vec2<f32>(0.0)) ;\n    return data;\n} \n\n\n\nfn border(p: vec2<f32>, R2: vec2<f32>) -> f32 {\n    let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2<f32>(0.5, 0.5));\n    let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2<f32>(0.5, 0.6)), R2 * vec2<f32>(0.05, 0.01));\n    let drain: f32 = -sdBox(p - R2 * vec2<f32>(0.5, 0.7), R2 * vec2<f32>(1.5, 0.5));\n    return max(drain, min(bound, box));\n} \n\n\n\nfn bN(p: vec2<f32>, R2: vec2<f32>) -> vec3<f32> {\n    let dx: vec3<f32> = vec3<f32>(-h, 0., h);\n    let idx: vec4<f32> = vec4<f32>(-1. / h, 0., 1. / h, 0.25);\n    let r: vec3<f32> = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2);\n    return vec3<f32>(normalize(r.xy), r.z + 1.0e-4);\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    var col: vec4<f32>;\n    var pos = vec2<f32>(f32(location.x), f32(location.y)) ;\n\n    // let Mouse = uni.iMouse;\n    time = uni.iTime;\n\n    let p: vec2<i32> = vec2<i32>(pos);\n\n    let data: vec4<f32> = textureLoad(buffer_a, location);\n\n    var P: particle = getParticle(data, pos);\n    let Nb: vec3<f32> = bN(P.X, R);\n    let bord: f32 = smoothstep(2. * border_h, border_h * 0.5, border(pos, R));\n    let rho: vec4<f32> = V(pos);\n    let dx: vec3<f32> = vec3<f32>(-2., 0., 2.);\n    let grad: vec4<f32> = -0.5 * vec4<f32>(V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw);\n    let N: vec2<f32> = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001);\n    let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5);\n\n    let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.);\n\n    let a: f32 = pow(smoothstep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1);\n    let b: f32 = exp(-1.7 * smoothstep(fluid_rho * 1., fluid_rho * 7.5, rho.z));\n    let col0: vec3<f32> = vec3<f32>(1., 0.5, 0.);\n    let col1: vec3<f32> = vec3<f32>(0.1, 0.4, 1.);\n    let fcol: vec3<f32> = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5);\n    col = vec4<f32>(3.);\n    var colxyz = col.xyz;\n\n    colxyz = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    var colxyz = col.xyz;\n    colxyz = mixN(col.xyz, 0. * vec3<f32>(0.5, 0.5, 1.), bord);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    var colxyz = col.xyz;\n    colxyz = tanh(col.xyz);\n    col.x = colxyz.x;\n    col.y = colxyz.y;\n    col.z = colxyz.z;\n\n    // let bufa: vec4<f32> = textureLoad(buffer_a, location);\n\n    // var col2 = vec4<f32>(0.2, 0.6, 0.9, 1.0);\n    // var col2 = vec4<f32>(0.3, 0.5, 0.29, 1.0);\n    // if (y_inverted_location.x > i32(R.x / 2.0)) {\n\n    //     let v = vec2<f32>(0.3, 0.5) * 2.0;\n\n    //     let u = f32(encodeVec2To1u(v));\n\n    //     let back = decode1uToVec2(u) / 2.0;\n\n    //     col2 = vec4<f32>(back.x, back.y, 0.29, 1.0);\n    // }\n\n    // let data2: vec4<f32> = (textureLoad(buffer_a, location)  ) ;\n    // var pb: particle = getParticle(data2, pos);\n    // let v2 = (pb.X - pos + 1.0) / 2.;\n    // let v2 = (pb.M ) / 1.;\n\n    // let debug = vec4<f32>(v2.x, 0.0, 0.0, 1.0);\n\n    // if (Mouse.z > 0.5) {\n    //     col = debug;\n    // }\n\n\n    let col_debug_info = show_debug_info(location, col.xyz);\n    \n    // textureStore(texture, y_inverted_location, toLinear(debug));\n    // textureStore(texture, y_inverted_location, toLinear(col));\n    textureStore(texture, y_inverted_location, toLinear(col_debug_info));\n} \n"
  },
  {
    "path": "examples/paint_streams/paint_streams.rs",
    "content": "// https://www.shadertoy.com/view/WtfyDj\n// by michael0884\n// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\n\nuse bevy::{\n    app::ScheduleRunnerSettings,\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n    utils::Duration,\n    window::PresentMode,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ScheduleRunnerSettings::run_loop(Duration::from_secs_f64(\n        1.0 / 120.0,\n    )))\n    .insert_resource(ClearColor(Color::GRAY))\n    .insert_resource(WindowDescriptor {\n        width: 960.,\n        height: 600.,\n        cursor_visible: true,\n        present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n        ..default()\n    })\n    .insert_resource(ShadertoyCanvas {\n        width: 960. as u32,\n        height: 600.0 as u32,\n        borders: 0.0,\n        position: Vec3::new(0.0, 0.0, 0.0),\n    })\n    .add_plugins(DefaultPlugins)\n    .add_plugin(ShadertoyPlugin)\n    .add_plugin(FrameTimeDiagnosticsPlugin::default())\n    .add_plugin(LogDiagnosticsPlugin::default())\n    .add_startup_system(setup)\n    .add_system(match_window_size)\n    .add_system(limit_fps)\n    .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"paint_streams\";\n    st_res.include_debugger = true;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n\nfn match_window_size(windows: Res<Windows>, mut canvas: ResMut<ShadertoyCanvas>) {\n    let window = windows.get_primary().unwrap();\n    canvas.width = window.width() as u32;\n    canvas.height = window.height() as u32;\n}\n\nuse std::{thread, time};\n\nfn limit_fps() {\n    thread::sleep(time::Duration::from_millis(5));\n}\n"
  },
  {
    "path": "examples/protean_clouds/buffer_a.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n}"
  },
  {
    "path": "examples/protean_clouds/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/protean_clouds/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/protean_clouds/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/protean_clouds/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/protean_clouds/image.wgsl",
    "content": "// https://www.shadertoy.com/view/3l23Rh\n// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\n\n\nfn rot(a: f32) -> mat2x2<f32> {\n\tlet c: f32 = cos(a);\n\tlet s: f32 = sin(a);\n\treturn mat2x2<f32>(vec2<f32>(c, s), vec2<f32>(-s, c));\n} \n\nlet m3: mat3x3<f32> = mat3x3<f32>(\n    vec3<f32>(0.64342, 1.08146, -1.38607), \n    vec3<f32>(-1.696, 0.6302, -0.2957), \n    vec3<f32>(0.2926, 1.3432, 1.1838)\n);\n\nfn mag2(p: vec2<f32>) -> f32 {\n\treturn dot(p, p);\n} \n\nfn linstep(mn: f32, mx: f32, x: f32) -> f32 {\n\treturn clamp((x - mn) / (mx - mn), 0., 1.);\n} \n\nvar<private>  prm1: f32 = 0.;\nvar<private> bsMo: vec2<f32> = vec2<f32>(0., 0.);\nfn disp(t: f32) -> vec2<f32> {\n\treturn vec2<f32>(sin(t * 0.22) * 1., cos(t * 0.175) * 1.) * 2.;\n} \n\nfn map(p_in: vec3<f32>) -> vec2<f32> {\n    var p = p_in;\n\tvar p2: vec3<f32> = p;\n\tvar p2xy = p2.xy;\n\tp2xy = p2.xy - (disp(p.z).xy);\n\tp2.x = p2xy.x;\n\tp2.y = p2xy.y;\n\tvar pxy = p.xy;\n\tpxy = p.xy * (rot(sin(p.z + uni.iTime) * (0.1 + prm1 * 0.05) + uni.iTime * 0.09));\n\tp.x = pxy.x;\n\tp.y = pxy.y;\n\tlet cl: f32 = mag2(p2.xy);\n\tvar d: f32 = 0.;\n\tp = p * (0.61);\n\tvar z: f32 = 1.;\n\tvar trk: f32 = 1.;\n\tvar dspAmp: f32 = 0.1 + prm1 * 0.2;\n\n\tfor (var i: i32 = 0; i < 5; i = i + 1) {\n\t\tp = p + (sin(p.zxy * 0.75 * trk + uni.iTime * trk * 0.8) * dspAmp);\n\t\td = d - (abs(dot(cos(p), sin(p.yzx)) * z));\n\t\tz = z * (0.57);\n\t\ttrk = trk * (1.4);\n\t\tp = p * m3;\n\t}\n\n\td = abs(d + prm1 * 3.) + prm1 * 0.3 - 2.5 + bsMo.y;\n\treturn vec2<f32>(d + cl * 0.2 + 0.25, cl);\n} \n\nfn render(ro: vec3<f32>, rd: vec3<f32>, time: f32) -> vec4<f32> {\n\tvar rez: vec4<f32> = vec4<f32>(0.);\n\tlet ldst: f32 = 8.;\n\tlet lpos: vec3<f32> = vec3<f32>(disp(time + ldst) * 0.5, time + ldst);\n\tvar t: f32 = 1.5;\n\tvar fogT: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < 130; i = i + 1) {\n\t\tif (rez.a > 0.99) {\t\tbreak;\n }\n\t\tlet pos: vec3<f32> = ro + t * rd;\n\t\tlet mpv: vec2<f32> = map(pos);\n\t\tlet den: f32 = clamp(mpv.x - 0.3, 0., 1.) * 1.12;\n\t\tlet dn: f32 = clamp(mpv.x + 2., 0., 3.);\n\t\tvar col: vec4<f32> = vec4<f32>(0.);\n\t\tif (mpv.x > 0.6) {\n\t\t\tcol = vec4<f32>(sin(vec3<f32>(5., 0.4, 0.2) + mpv.y * 0.1 + sin(pos.z * 0.4) * 0.5 + 1.8) * 0.5 + 0.5, 0.08);\n\t\t\tcol = col * (den * den * den);\n\t\t\tvar colrgb = col.rgb;\n\tcolrgb = col.rgb * (linstep(4., -2.5, mpv.x) * 2.3);\n\tcol.r = colrgb.r;\n\tcol.g = colrgb.g;\n\tcol.b = colrgb.b;\n\t\t\tvar dif: f32 = clamp((den - map(pos + 0.8).x) / 9., 0.001, 1.);\n\t\t\tdif = dif + (clamp((den - map(pos + 0.35).x) / 2.5, 0.001, 1.));\n\t\t\tvar colxyz = col.xyz;\n\tcolxyz = col.xyz * (den * (vec3<f32>(0.005, 0.045, 0.075) + 1.5 * vec3<f32>(0.033, 0.07, 0.03) * dif));\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\t\t}\n\t\tlet fogC: f32 = exp(t * 0.2 - 2.2);\n\t\tvar colrgba = col.rgba;\n\tcolrgba = col.rgba + (vec4<f32>(0.06, 0.11, 0.11, 0.1) * clamp(fogC - fogT, 0., 1.));\n\tcol.r = colrgba.r;\n\tcol.g = colrgba.g;\n\tcol.b = colrgba.b;\n\tcol.a = colrgba.a;\n\t\tfogT = fogC;\n\t\trez = rez + col * (1. - rez.a);\n\t\tt = t + (clamp(0.5 - dn * dn * 0.05, 0.09, 0.3));\n\t}\n\n\treturn clamp(rez, vec4<f32>(0.), vec4<f32>(1.));\n} \n\nfn getsat(c: vec3<f32>) -> f32 {\n\tlet mi: f32 = min(min(c.x, c.y), c.z);\n\tlet ma: f32 = max(max(c.x, c.y), c.z);\n\treturn (ma - mi) / (ma + 0.0000001);\n} \n\nfn iLerp(a: vec3<f32>, b: vec3<f32>, x: f32) -> vec3<f32> {\n\tvar ic: vec3<f32> = mix(a, b, x) + vec3<f32>(0.000001, 0., 0.);\n\tlet sd: f32 = abs(getsat(ic) - mix(getsat(a), getsat(b), x));\n\tlet dir: vec3<f32> = normalize(vec3<f32>(2. * ic.x - ic.y - ic.z, 2. * ic.y - ic.x - ic.z, 2. * ic.z - ic.y - ic.x));\n\tlet lgt: f32 = dot(vec3<f32>(1.), ic);\n\tlet ff: f32 = dot(dir, normalize(ic));\n\tic = ic + (1.5 * dir * sd * ff * lgt);\n\treturn clamp(ic, vec3<f32>(0.), vec3<f32>(1.));\n} \n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet q: vec2<f32> = fragCoord.xy / uni.iResolution.xy;\n\tlet p: vec2<f32> = (fragCoord - 0.5 * uni.iResolution.xy) / uni.iResolution.y;\n\tbsMo = (uni.iMouse.xy - 0.5 * uni.iResolution.xy) / uni.iResolution.y;\n\tlet time: f32 = uni.iTime * 3.;\n\tvar ro: vec3<f32> = vec3<f32>(0., 0., time);\n\tro = ro + (vec3<f32>(sin(uni.iTime) * 0.5, sin(uni.iTime * 1.) * 0., 0.));\n\tlet dspAmp: f32 = 0.85;\n\tvar roxy = ro.xy;\n\troxy = ro.xy + (disp(ro.z) * dspAmp);\n\tro.x = roxy.x;\n\tro.y = roxy.y;\n\tlet tgtDst: f32 = 3.5;\n\tlet targt: vec3<f32> = normalize(ro - vec3<f32>(disp(time + tgtDst) * dspAmp, time + tgtDst));\n\tro.x = ro.x - (bsMo.x * 2.);\n\tvar rightdir: vec3<f32> = normalize(cross(targt, vec3<f32>(0., 1., 0.)));\n\tlet updir: vec3<f32> = normalize(cross(rightdir, targt));\n\trightdir = normalize(cross(updir, targt));\n\tvar rd: vec3<f32> = normalize((p.x * rightdir + p.y * updir) * 1. - targt);\n\tvar rdxy = rd.xy;\n\trdxy = rd.xy * (rot(-disp(time + 3.5).x * 0.2 + bsMo.x));\n\trd.x = rdxy.x;\n\trd.y = rdxy.y;\n\tprm1 = smoothstep(-0.4, 0.4, sin(uni.iTime * 0.3));\n\tlet scn: vec4<f32> = render(ro, rd, time);\n\tvar col: vec3<f32> = scn.rgb;\n\tcol = iLerp(col.bgr, col.rgb, clamp(1. - prm1, 0.05, 1.));\n\tcol = pow(col, vec3<f32>(0.55, 0.65, 0.6)) * vec3<f32>(1., 0.97, 0.9);\n\tcol = col * (pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), 0.12) * 0.7 + 0.3);\n\tfragColor = vec4<f32>(col, 1.);\n    textureStore(texture, location, fragColor);\n} \n\n"
  },
  {
    "path": "examples/protean_clouds/protean_clouds.rs",
    "content": "// https://www.shadertoy.com/view/3l23Rh\n// by nimitz\n// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            // present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: 960. as u32,\n            height: 600.0 as u32,\n            borders: 0.2,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"protean_clouds\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/seascape/buffer_a.wgsl",
    "content": "\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "examples/seascape/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/seascape/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/seascape/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/seascape/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/seascape/image.wgsl",
    "content": "// https://www.shadertoy.com/view/Ms2SD1\n// Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n\nlet NUM_STEPS: i32 = 8;\nlet PI: f32 = 3.141592;\nlet EPSILON: f32 = 0.001;\nlet ITER_GEOMETRY: i32 = 3;\nlet ITER_FRAGMENT: i32 = 5;\nlet SEA_HEIGHT: f32 = 0.6;\nlet SEA_CHOPPY: f32 = 4.;\nlet SEA_SPEED: f32 = 0.8;\nlet SEA_FREQ: f32 = 0.16;\nlet SEA_BASE: vec3<f32> = vec3<f32>(0., 0.09, 0.18);\nlet SEA_WATER_COLOR: vec3<f32> = vec3<f32>(0.48, 0.54, 0.36);\nlet octave_m: mat2x2<f32> = mat2x2<f32>(vec2<f32>(1.6, 1.2), vec2<f32>(-1.2, 1.6));\n\nfn fromEuler(ang: vec3<f32>) -> mat3x3<f32> {\n\tlet a1: vec2<f32> = vec2<f32>(sin(ang.x), cos(ang.x));\n\tlet a2: vec2<f32> = vec2<f32>(sin(ang.y), cos(ang.y));\n\tlet a3: vec2<f32> = vec2<f32>(sin(ang.z), cos(ang.z));\n\tvar m: mat3x3<f32>;\n    m[0] = vec3<f32>(a1.y * a3.y + a1.x * a2.x * a3.x, a1.y * a2.x * a3.x + a3.y * a1.x, -a2.y * a3.x);\n    m[1] =  vec3<f32>(-a2.y * a1.x, a1.y * a2.y, a2.x);\n    m[2] =  vec3<f32>(a3.y * a1.x * a2.x + a1.y * a3.x, a1.x * a3.x - a1.y * a3.y * a2.x, a2.y * a3.y);\n\treturn m;\n} \n\nfn hash(p: vec2<f32>) -> f32 {\n\tlet h: f32 = dot(p, vec2<f32>(127.1, 311.7));\n\treturn fract(sin(h) * 43758.547);\n} \n\nfn noise(p: vec2<f32>) -> f32 {\n\tlet i: vec2<f32> = floor(p);\n\tlet f: vec2<f32> = fract(p);\n\tlet u: vec2<f32> = f * f * (3. - 2. * f);\n\treturn -1. + 2. * mix(mix(hash(i + vec2<f32>(0., 0.)), hash(i + vec2<f32>(1., 0.)), u.x), mix(hash(i + vec2<f32>(0., 1.)), hash(i + vec2<f32>(1., 1.)), u.x), u.y);\n} \n\nfn diffuse(n: vec3<f32>, l: vec3<f32>, p: f32) -> f32 {\n\treturn pow(dot(n, l) * 0.4 + 0.6, p);\n} \n\nfn specular(n: vec3<f32>, l: vec3<f32>, e: vec3<f32>, s: f32) -> f32 {\n\tlet nrm: f32 = (s + 8.) / (PI * 8.);\n\treturn pow(max(dot(reflect(e, n), l), 0.), s) * nrm;\n} \n\nfn getSkyColor(e: vec3<f32>) -> vec3<f32> {\n\tvar e_var = e;\n\te_var.y = (max(e_var.y, 0.) * 0.8 + 0.2) * 0.8;\n\treturn vec3<f32>(pow(1. - e_var.y, 2.), 1. - e_var.y, 0.6 + (1. - e_var.y) * 0.4) * 1.1;\n} \n\nfn sea_octave(uv: vec2<f32>, choppy: f32) -> f32 {\n\tvar uv_var = uv;\n\tuv_var = uv_var + (noise(uv_var));\n\tvar wv: vec2<f32> = 1. - abs(sin(uv_var));\n\tlet swv: vec2<f32> = abs(cos(uv_var));\n\twv = mix(wv, swv, wv);\n\treturn pow(1. - pow(wv.x * wv.y, 0.65), choppy);\n} \n\nfn map(p: vec3<f32>) -> f32 {\n\tvar freq: f32 = SEA_FREQ;\n\tvar amp: f32 = SEA_HEIGHT;\n\tvar choppy: f32 = SEA_CHOPPY;\n\tvar uv: vec2<f32> = p.xz;\n\tuv.x = uv.x * (0.75);\n\tvar d: f32;\n\tvar h: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < ITER_GEOMETRY; i = i + 1) {\n\t\td = sea_octave((uv + (1. + uni.iTime * SEA_SPEED)) * freq, choppy);\n\t\td = d + (sea_octave((uv - (1. + uni.iTime * SEA_SPEED)) * freq, choppy));\n\t\th = h + (d * amp);\n\t\tuv = uv * (octave_m);\n\t\tfreq = freq * (1.9);\n\t\tamp = amp * (0.22);\n\t\tchoppy = mix(choppy, 1., 0.2);\n\t}\n\n\treturn p.y - h;\n} \n\nfn map_detailed(p: vec3<f32>) -> f32 {\n\tvar freq: f32 = SEA_FREQ;\n\tvar amp: f32 = SEA_HEIGHT;\n\tvar choppy: f32 = SEA_CHOPPY;\n\tvar uv: vec2<f32> = p.xz;\n\tuv.x = uv.x * (0.75);\n\tvar d: f32;\n\tvar h: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < ITER_FRAGMENT; i = i + 1) {\n\t\td = sea_octave((uv + (1. + uni.iTime * SEA_SPEED)) * freq, choppy);\n\t\td = d + (sea_octave((uv - (1. + uni.iTime * SEA_SPEED)) * freq, choppy));\n\t\th = h + (d * amp);\n\t\tuv = uv * (octave_m);\n\t\tfreq = freq * (1.9);\n\t\tamp = amp * (0.22);\n\t\tchoppy = mix(choppy, 1., 0.2);\n\t}\n\n\treturn p.y - h;\n} \n\nfn getSeaColor(p: vec3<f32>, n: vec3<f32>, l: vec3<f32>, eye: vec3<f32>, dist: vec3<f32>) -> vec3<f32> {\n\tvar fresnel: f32 = clamp(1. - dot(n, -eye), 0., 1.);\n\tfresnel = pow(fresnel, 3.) * 0.5;\n\tlet reflected: vec3<f32> = getSkyColor(reflect(eye, n));\n\tlet refracted: vec3<f32> = SEA_BASE + diffuse(n, l, 80.) * SEA_WATER_COLOR * 0.12;\n\tvar color: vec3<f32> = mix(refracted, reflected, fresnel);\n\tlet atten: f32 = max(1. - dot(dist, dist) * 0.001, 0.);\n\tcolor = color + (SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten);\n\tcolor = color + (vec3<f32>(specular(n, l, eye, 60.)));\n\treturn color;\n} \n\nfn getNormal(p: vec3<f32>, eps: f32) -> vec3<f32> {\n\tvar n: vec3<f32>;\n\tn.y = map_detailed(p);\n\tn.x = map_detailed(vec3<f32>(p.x + eps, p.y, p.z)) - n.y;\n\tn.z = map_detailed(vec3<f32>(p.x, p.y, p.z + eps)) - n.y;\n\tn.y = eps;\n\treturn normalize(n);\n} \n\nfn heightMapTracing(ori: vec3<f32>, dir: vec3<f32>,  p: ptr<function, vec3<f32>>) -> f32 {\n\tvar p_var: vec3<f32>;\n\tvar tm: f32 = 0.;\n\tvar tx: f32 = 1000.;\n\tvar hx: f32 = map(ori + dir * tx);\n\tif (hx > 0.) {\n\t\tp_var = ori + dir * tx;\n\t\treturn tx;\n\t}\n\tvar hm: f32 = map(ori + dir * tm);\n\tvar tmid: f32 = 0.;\n\n\tfor (var i: i32 = 0; i < NUM_STEPS; i = i + 1) {\n\t\ttmid = mix(tm, tx, hm / (hm - hx));\n\t\tp_var = ori + dir * tmid;\n\t\tlet hmid: f32 = map(p_var);\n\t\tif (hmid < 0.) {\n\t\t\ttx = tmid;\n\t\t\thx = hmid;\n\t\t} else { \n\n\t\t\ttm = tmid;\n\t\t\thm = hmid;\n\t\t}\n\t}\n    *p = p_var;\n\n\treturn tmid;\n} \n\nfn getPixel(coord: vec2<f32>, time: f32) -> vec3<f32> {\n\tvar uv: vec2<f32> = coord / uni.iResolution.xy;\n\tuv = uv * 2. - 1.;\n\tuv.x = uv.x * (uni.iResolution.x / uni.iResolution.y);\n\tlet ang: vec3<f32> = vec3<f32>(sin(time * 3.) * 0.1, sin(time) * 0.2 + 0.3, time);\n\tlet ori: vec3<f32> = vec3<f32>(0., 3.5, time * 5.);\n\tvar dir: vec3<f32> = normalize(vec3<f32>(uv.xy, -2.));\n\tdir.z = dir.z + (length(uv) * 0.14);\n\tdir = normalize(dir) * fromEuler(ang);\n\tvar p: vec3<f32>;\n\theightMapTracing(ori, dir, &p);\n\tlet dist: vec3<f32> = p - ori;\n\tlet n: vec3<f32> = getNormal(p, dot(dist, dist) * (0.1 / uni.iResolution.x));\n\tlet light: vec3<f32> = normalize(vec3<f32>(0., 1., 0.8));\n\treturn mix(getSkyColor(dir), getSeaColor(p, n, light, dir, dist), pow(smoothstep(0., -0.02, dir.y), 0.2));\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tlet time: f32 = uni.iTime * 0.3 + uni.iMouse.x * 0.01;\n\n\t// var color: vec3<f32> = vec3<f32>(0.);\n\n\t// for (var i: i32 = -1; i <= 1; i = i + 1) {\n\n\t// \tfor (var j: i32 = -1; j <= 1; j = j + 1) {\n\t// \t\tlet uv2: vec2<f32> = fragCoord + vec2<f32>(f32(i), f32(j)) / 3.;\n\t// \t\tcolor = color + (getPixel(uv2, time));\n\t// \t}\n\n\t// }\n    // color = color / (9.);\n\n    var color: vec3<f32> = getPixel(fragCoord, time);\n\n\t\n\tfragColor = vec4<f32>(pow(color, vec3<f32>(0.65)), 1.);\n    // fragColor = vec4<f32>(1.);\n    // fragColor = getSkyColor(location);\n\n    // let col_debug_info = show_debug_info(location, fragColor.xyz);\n\n    textureStore(texture, y_inverted_location, toLinear(fragColor));\n} \n\n"
  },
  {
    "path": "examples/seascape/seascape.rs",
    "content": "// https://www.shadertoy.com/view/Ms2SD1\n// by TDM\n// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            // present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: 960. as u32,\n            height: 600.0 as u32,\n            borders: 0.2,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"seascape\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/simpler_particles/buffer_a.wgsl",
    "content": "// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\nfn Integrate(\n\tch: texture_storage_2d<rgba32float, read_write>, \n\tP: ptr<function, particle>, \n\tpos: vec2<f32>\n)  {\n\tvar I: i32 = 3;\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\t\tlet tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\t\tlet data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\n\t\tif (tpos.x < 0. || tpos.y < 0.) {\t\tcontinue; }\n\n\t\tvar P0: particle = getParticle(data, tpos);\n\n\t\tif (\n\t\t\t(P0.NX.x >= pos.x - 0.5 && P0.NX.x < pos.x + 0.5) \n\t\t\t&& (P0.NX.y >= pos.y - 0.5) \n\t\t\t&& (P0.NX.y < pos.y + 0.5) \n\t\t\t&& (P0.M > 0.5)\n\t\t) {\n\t\t\tvar P0V: vec2<f32> = (P0.NX - P0.X) / 2.;\n\n\t\t\tif (uni.iMouse.z > 0.) {\n\t\t\t\tlet dm: vec2<f32> = P0.NX - uni.iMouse.xy;\n\t\t\t\tlet d: f32 = length(dm / 50.);\n\t\t\t\tP0V = P0V + (normalize(dm) * exp(-d * d) * 0.3);\n\t\t\t}\n\n\t\t\tP0V = P0V + (vec2<f32>(0., -0.005));\n\t\t\tlet v: f32 = length(P0V);\n\t\t\tvar denom = 1.; \n\t\t\tif (v > 1.) { denom = v; }\n\t\t\tP0V = P0V / denom;\n\t\t\tP0.X = P0.NX;\n\t\t\tP0.NX = P0.NX + P0V * 2.;\n\t\t\t(*P) = P0;\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t}\n\n} \n\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    // let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\t// var U: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\trng_initialize(pos, i32(uni.iFrame));\n\tvar P: particle;\n\n\tIntegrate(buffer_d, &P, pos);\n\n\t// if (uni.iFrame == 0) {\n\t#ifdef INIT\n\t\tif (rand() > 0.992) {\n\t\t\tP.X = pos;\n\t\t\tP.NX = pos + (rand2() - 0.5) * 0.;\n\t\t\tlet r: f32 = pow(rand(), 2.);\n\t\t\tP.M = mix(1., 4., r);\n\t\t\tP.R = mix(1., particle_size * 0.5, r);\n\t\t} else { \n\t\t\tP.X = pos;\n\t\t\tP.NX = pos;\n\t\t\tP.M = 0.;\n\t\t\tP.R = particle_size * 0.5;\n\t\t}\n\t// }\n\t#endif\n\n\tlet U = saveParticle(P, pos);\n\ttextureStore(buffer_a, location, U);\n    \n} \n\n\n"
  },
  {
    "path": "examples/simpler_particles/buffer_b.wgsl",
    "content": "\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    // let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\t// var U: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet data: vec4<f32> = textureLoad(buffer_a, vec2<i32>(pos));\n\tvar P: particle = getParticle(data, pos);\n\n\tif (P.M > 0.) { Simulation(buffer_a, &P, pos); }\n\n\tlet U = saveParticle(P, pos);\n\ttextureStore(buffer_b, location, U);\n} \n\n"
  },
  {
    "path": "examples/simpler_particles/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    // let R: vec2<f32> = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\t// var U: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet data: vec4<f32> = textureLoad(buffer_b, vec2<i32>(pos));\n\tvar P: particle = getParticle(data, pos);\n\tif (P.M > 0.) { Simulation(buffer_b, &P, pos); }\n\n\tlet U = saveParticle(P, pos);\n\ttextureStore(buffer_c, location, U);\n} \n\n"
  },
  {
    "path": "examples/simpler_particles/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    // let R: vec2<f32> = uni.iResolution.xy;\n    // let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\t// var U: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tMouse = uni.iMouse;\n\tlet data: vec4<f32> = textureLoad(buffer_c, vec2<i32>(pos));\n\tvar P: particle = getParticle(data, pos);\n\n\tif (P.M > 0.) { Simulation(buffer_c, &P, pos); }\n\n\tlet U = saveParticle(P, pos);\n\ttextureStore(buffer_d, location, U);\n} \n\n"
  },
  {
    "path": "examples/simpler_particles/common.wgsl",
    "content": "// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  \n\nvar<private> R: vec2<f32>;\nvar<private> Mouse: vec4<f32>;\nvar<private> time: f32;\nvar<private> s0: vec4<u32>;\n// let particle_size: f32 = 10.5;\nlet particle_size: f32 = 2.5;\nlet relax_value: f32 = 0.3;\n\nfn Rot(ang: f32) -> mat2x2<f32> {\n\treturn mat2x2<f32>(cos(ang), -sin(ang), sin(ang), cos(ang));\n} \n\nfn Dir(ang: f32) -> vec2<f32> {\n\treturn vec2<f32>(cos(ang), sin(ang));\n} \n\nfn sdBox(p: vec2<f32>, b: vec2<f32>) -> f32 {\n\tvar d: vec2<f32> = abs(p) - b;\n\treturn length(max(d, vec2<f32>(0.))) + min(max(d.x, d.y), 0.);\n} \n\nfn border(p: vec2<f32>) -> f32 {\n\tlet bound: f32 = -sdBox(p - R * 0.5, R * vec2<f32>(0.5, 0.5));\n\tlet box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2<f32>(0.5, 0.6)), R * vec2<f32>(0.05, 0.01));\n\tlet drain: f32 = -sdBox(p - R * vec2<f32>(0.5, 0.7), R * vec2<f32>(1.5, 0.5));\n\t// return bound - 15.;\n\t// return min(bound, box);\n\treturn max(drain, min(bound, box));\n} \n\nfn bN(p: vec2<f32>) -> vec3<f32> {\n\tvar dx: vec3<f32> = vec3<f32>(-1., 0., 1.);\n\tlet idx: vec4<f32> = vec4<f32>(-1. / 1., 0., 1. / 1., 0.25);\n\tvar r: vec3<f32> = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx);\n\treturn vec3<f32>(normalize(r.xy), r.z + 0.0001);\n} \n\n// fn decode(x: f32) -> vec2<f32> {\n// \tvar X: u32 = floatBitsToUint(x);\n// \treturn unpackHalf2x16(X);\n// } \n\n// fn encode(x: vec2<f32>) -> f32 {\n// \tvar X: u32 = packHalf2x16(x);\n// \treturn uintBitsToFloat(X);\n// } \n\nfn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 {\n    var input = input2;\n    // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ;\n    let value_f32_normalized = value * f32((1u << (precis - 1u)));\n    let delta_bits = u32(place - precis);\n    let value_u32 = u32(value_f32_normalized) << delta_bits;\n\n    var mask: u32 = 0u;\n\n    if (precis < 32u) {\n        mask = 4294967295u - (((1u << precis) - 1u) << (place - precis));\n    }\n\n    let input = (input2 & mask) | value_u32;\n    return input;\n}\n\nfn encodeVec2To1u(value: vec2<f32>) -> u32 {\n    var input: u32 = 0u;\n    let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0));\n    let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0));\n    input = encode2(x, input, 32u, 16u);\n    input = encode2(y, input, 16u, 16u);\n\n    return input;\n}\n\nfn decode2(input: u32, place: u32, precis: u32) -> f32 {\n    let value_u32 = input >> (place - precis);\n\n    var mask: u32 = 4294967295u;\n    if (precis < 32u) {\n        mask = (1u << precis) - 1u;\n    }\n\n    let masked_value_u32 = value_u32 & mask;\n    let max_val = 1u << (precis - 1u);\n    let value_f32 = f32(masked_value_u32) / f32(max_val) ;\n\n    return value_f32;\n}\n\nfn decode1uToVec2(q: f32) -> vec2<f32> {\n    let uq = u32(q);\n    let x = decode2(uq, 32u, 16u);\n    let y = decode2(uq, 16u, 16u);\n    return vec2<f32>(x, y) * 2. - 1.;\n}\n\n\nstruct particle {\n\tX: vec2<f32>,\n\tNX: vec2<f32>,\n\tR: f32,\n\tM: f32,\n};\nfn getParticle(data: vec4<f32>, pos: vec2<f32>) -> particle {\n\tvar P: particle;\n\tP.X = decode1uToVec2(data.x) + pos;\n\tP.NX = decode1uToVec2(data.y) + pos;\n\tP.R = data.z;\n\tP.M = data.w;\n\treturn P;\n} \n\nfn saveParticle(P_in: particle, pos: vec2<f32>) -> vec4<f32> {\n\tvar P = P_in;\n\tP.X = P.X - pos;\n\tP.NX = P.NX - pos;\n\treturn vec4<f32>(\n\t\tf32(encodeVec2To1u(P.X)), \n\t\tf32(encodeVec2To1u(P.NX)), \n\t\tP.R, \n\t\tP.M\n\t);\n} \n\n\nfn rng_initialize(p: vec2<f32>, frame: i32)  {\n\ts0 = vec4<u32>(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y));\n} \n\n// // https://www.pcg-random.org/\n// void pcg4d(inout uvec4 v)\n// {\n// \tv = v * 1664525u + 1013904223u;\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n//     v = v ^ (v>>16u);\n//     v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;\n// }\n\n\nfn pcg4d(v: ptr<private, vec4<u32>>)  {\n\n\t(*v) = (*v) * 1664525u + 1013904223u;\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n\n\n\tlet v2 = vec4<u32>((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u);\n\n\t(*v) = (*v) ^ v2;\n\t// (*v) = (*v) ^ ((*v) >> 16u);\n\t(*v).x = (*v).x + ((*v).y * (*v).w);\n\t(*v).y = (*v).y + ((*v).z * (*v).x);\n\t(*v).z = (*v).z + ((*v).x * (*v).y);\n\t(*v).w = (*v).w + ((*v).y * (*v).z);\n} \n\nfn rand() -> f32 {\n\tpcg4d(&s0);\n\treturn f32(s0.x) / f32(4294967300.);\n} \n\nfn rand2() -> vec2<f32> {\n\tpcg4d(&s0);\n\treturn vec2<f32>(s0.xy) / f32(4294967300.);\n} \n\nfn rand3() -> vec3<f32> {\n\tpcg4d(&s0);\n\treturn vec3<f32>(s0.xyz) / f32(4294967300.);\n} \n\nfn rand4() -> vec4<f32> {\n\tpcg4d(&s0);\n\treturn vec4<f32>(s0) / f32(4294967300.);\n} \n\nfn Simulation(\n\tch: texture_storage_2d<rgba32float, read_write>,  \n\tP: ptr<function, particle>, \n\tpos: vec2<f32>\n)  {\n\tvar F: vec2<f32> = vec2<f32>(0.);\n\tvar I: i32 = i32(ceil(particle_size));\n\t// var I: i32 = 4;\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\tif (i == 0 && j == 0) {\t\tcontinue;   }\n\n\n\t\tlet tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\n\t\tlet data: vec4<f32> = textureLoad(ch, vec2<i32>(tpos));\n\t\tlet P0: particle = getParticle(data, tpos);\n\n\t\tif (P0.M == 0.) {\tcontinue;   }\n\n\t\tlet dx: vec2<f32> = P0.NX - (*P).NX;\n\t\tvar d: f32 = length(dx);\n\t\tvar r: f32 = (*P).R + P0.R;\n\n\t\tvar m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.;\n\t\tm = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M);\n\t\tm = P0.M / ((*P).M + P0.M);\n\n\t\tif (d < r) { F = F - (normalize(dx) * (r - d) * m); }\n\t}\n\t}\n\n\tlet dp: vec2<f32> = (*P).NX;\n\tvar d: f32 = border(dp);\n\tif (d < 0.) { F = F - (bN(dp).xy * d); }\n\t(*P).NX = (*P).NX + (F * 0.9 / 3.);\n} \n\n// RUST_LOG=\"wgpu=error,naga=warn,info\" cargo run --release --example simpler_particles  "
  },
  {
    "path": "examples/simpler_particles/fps.rs",
    "content": "use bevy::{\n    diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin},\n    prelude::*,\n    time::FixedTimestep,\n};\n\nconst TIMESTEP_4_PER_SECOND: f64 = 20.0 / 60.0;\n\npub struct FPSPlugin;\n\nimpl Plugin for FPSPlugin {\n    fn build(&self, app: &mut App) {\n        // app.add_plugin(FrameTimeDiagnosticsPlugin::default())\n        //     .add_startup_system(spawn_text)\n        //     .add_system(update)\n        app.add_plugin(FrameTimeDiagnosticsPlugin::default())\n            .add_startup_system(setup)\n            .add_system_set(\n                SystemSet::new()\n                    .with_run_criteria(FixedTimestep::step(TIMESTEP_4_PER_SECOND))\n                    .with_system(text_update_system),\n            )\n            .add_system(text_color_system);\n    }\n}\n\n// fn main() {\n//     App::new()\n//         .add_plugins(DefaultPlugins)\n//         .add_plugin(FrameTimeDiagnosticsPlugin::default())\n//         .add_startup_system(setup)\n//         .add_system(text_update_system)\n//         .add_system(text_color_system)\n//         .run();\n// }\n\n// A unit struct to help identify the FPS UI component, since there may be many Text components\n#[derive(Component)]\nstruct FpsText;\n\n// A unit struct to help identify the color-changing Text component\n#[derive(Component)]\nstruct ColorText;\n\nfn setup(mut commands: Commands, asset_server: Res<AssetServer>) {\n    // // UI camera\n    // commands.spawn_bundle(Camera2dBundle::default());\n    // Text with one section\n\n    // Text with multiple sections\n    commands\n        .spawn_bundle(\n            // Create a TextBundle that has a Text with a list of sections.\n            TextBundle::from_sections([\n                TextSection::new(\n                    \"FPS: \",\n                    TextStyle {\n                        font: asset_server.load(\"fonts/poly.ttf\"),\n                        font_size: 60.0,\n                        color: Color::BLACK,\n                    },\n                ),\n                TextSection::from_style(TextStyle {\n                    font: asset_server.load(\"fonts/poly.ttf\"),\n                    font_size: 60.0,\n                    color: Color::BLACK,\n                }),\n            ])\n            .with_style(Style {\n                align_self: AlignSelf::FlexEnd,\n                ..default()\n            }),\n        )\n        .insert(FpsText);\n}\n\nfn text_color_system(time: Res<Time>, mut query: Query<&mut Text, With<ColorText>>) {\n    for mut text in &mut query {\n        let seconds = time.seconds_since_startup() as f32;\n\n        // Update the color of the first and only section.\n        text.sections[0].style.color = Color::Rgba {\n            red: (1.25 * seconds).sin() / 2.0 + 0.5,\n            green: (0.75 * seconds).sin() / 2.0 + 0.5,\n            blue: (0.50 * seconds).sin() / 2.0 + 0.5,\n            alpha: 1.0,\n        };\n    }\n}\n\nfn text_update_system(diagnostics: Res<Diagnostics>, mut query: Query<&mut Text, With<FpsText>>) {\n    for mut text in &mut query {\n        if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) {\n            if let Some(average) = fps.average() {\n                // Update the value of the second section\n                text.sections[1].value = format!(\"{average:.2}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "examples/simpler_particles/image.wgsl",
    "content": "\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    R = uni.iResolution.xy;\n\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar col: vec4<f32>;\n\tvar pos = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tR = uni.iResolution.xy;\n\ttime = uni.iTime;\n\tvar colxyz = col.xyz;\n\tcolxyz = vec3<f32>(1.);\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\n\tvar d: f32 = 100.;\n\tvar c: vec3<f32> = vec3<f32>(1.);\n\tvar m: f32 = 1.;\n\tvar I: i32 = i32(ceil(particle_size * 0.5)) + 2;\n\t\n\n\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\tvar tpos: vec2<f32> = pos + vec2<f32>(f32(i), f32(j));\n\t\tvar data: vec4<f32> = textureLoad(buffer_d, vec2<i32>(tpos));\n\t\tvar P0: particle = getParticle(data, tpos);\n\n\t\tif (P0.M == 0.) {\t\tcontinue; }\n\n\t\tvar nd: f32 = distance(pos, P0.NX) - P0.R;\n\n\t\tif (nd < d) {\n\t\t\tlet V: vec2<f32> = (P0.NX - P0.X) * 1. / 2.;\n\t\t\tc = vec3<f32>(V * 0.5 + 0.5, (P0.M - 1.) / 3.);\n\t\t\tc = mix(vec3<f32>(1.), c, length(V));\n\t\t\tm = P0.M;\n\t\t}\n\n\t\td = min(d, nd);\n\n\t\tif (d < 0.) {\t\tbreak;  }\n\t}\n\n\t}\n\n\tvar s: f32 = 100.;\n\tlet off: vec2<f32> = vec2<f32>(5., 5.);\n\tif (d > 0. && i32(pos.x) % 2 == 0 && i32(pos.y) % 2 == 0) {\n\n\t\tfor (var i: i32 = -I; i <= I; i = i + 1) {\n\t\tfor (var j: i32 = -I; j <= I; j = j + 1) {\n\n\t\t\tlet tpos: vec2<f32> = pos - off + vec2<f32>(f32(i), f32(j));\n\t\t\tlet data: vec4<f32> = textureLoad(buffer_d, vec2<i32>(tpos));\n\t\t\tlet P0: particle = getParticle(data, tpos);\n\t\t\tif (tpos.x < 0. || tpos.x > R.x || tpos.y < 0. || tpos.y > R.x) {\n\t\t\t\ts = 0.;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (P0.M == 0.) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet nd: f32 = distance(pos - off, P0.NX) - P0.R;\n\t\t\ts = min(s, nd);\n\t\t}\n\n\t\t}\n\n\t}\n\n\tif (d < 0.) { d = sin(d); }\n\n\tvar colxyz = col.xyz;\n\tcolxyz = vec3<f32>(abs(d));\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\n\tif (d < 0.) {\n\t\tvar colxyz = col.xyz;\n\t\tcolxyz = col.xyz * (c);\n\t\tcol.x = colxyz.x;\n\t\tcol.y = colxyz.y;\n\t\tcol.z = colxyz.z;\n\n\t\tvar colxyz = col.xyz;\n\t\tcolxyz = col.xyz / (0.4 + m * 0.25);\n\t\tcol.x = colxyz.x;\n\t\tcol.y = colxyz.y;\n\t\tcol.z = colxyz.z;\n\t}\n\n\tvar colxyz = col.xyz;\n\tcolxyz = clamp(col.xyz, vec3<f32>(0.), vec3<f32>(1.));\n\tcol.x = colxyz.x;\n\tcol.y = colxyz.y;\n\tcol.z = colxyz.z;\n\n\tif (d > 0.) {\n\t\t var colxyz = col.xyz;\n\t\tcolxyz = col.xyz * (mix(vec3<f32>(0.5), vec3<f32>(1.), clamp(s, 0., 1.)));\n\t\tcol.x = colxyz.x;\n\t\tcol.y = colxyz.y;\n\t\tcol.z = colxyz.z; \n\t}\n\n\tif (pos.x < 3.) || (pos.x > R.x - 3.) || (pos.y < 3.) || (pos.y > R.y - 3.) { \n\t\tvar colxyz = col.xyz;\n\t\tcolxyz = vec3<f32>(0.5);\n\t\tcol.x = colxyz.x;\n\t\tcol.y = colxyz.y;\n\t\tcol.z = colxyz.z; \n\t}\n\n\t// col = vec4<f32>(1.0, 0.0, 0.0, 1.0);\n\tcol.w = 1.0;\n\n\ttextureStore(texture, y_inverted_location, col);\n} \n\n"
  },
  {
    "path": "examples/simpler_particles/simpler_particles.rs",
    "content": "// https://www.shadertoy.com/view/Ms2SD1\n// by TDM\n// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nmod fps;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            // width: 960.,\n            // height: 600.,\n            width: 1200.,\n            height: 800.,\n            cursor_visible: true,\n            present_mode: bevy::window::PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            // width: 960. as u32,\n            // height: 600.0 as u32,\n            width: 1200,\n            height: 800,\n            borders: 0.02,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugin(fps::FPSPlugin)\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"simpler_particles\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/soul/buffer_a.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "examples/soul/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/soul/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/soul/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/soul/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/soul/image.wgsl",
    "content": "// https://www.shadertoy.com/view/3ltyRB\n// by leon\n// License Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0)\n\nstruct Volume {\n\tdist: f32,\n\tmate: i32,\n\tdensity: f32,\n\tspace: f32,\n};\n\nfn select2(a: Volume, b: Volume) -> Volume {\n\tif (a.dist < b.dist) {\treturn a;\n }\n\treturn b;\n} \n\nlet mat_eye_globe: i32 = 1;\nlet mat_pupils: i32 = 2;\nlet mat_eyebrows: i32 = 3;\nlet mat_iris: i32 = 4;\nlet mat_glass: i32 = 5;\nfn rot(a: f32) -> mat2x2<f32> {\n\tlet c: f32 = cos(a);\n\tvar s: f32 = sin(a);\n\treturn mat2x2<f32>(c, -s, s, c);\n} \n\nfn hash12(p: vec2<f32>) -> f32 {\n\tvar p3: vec3<f32> = fract(vec3<f32>(p.xyx) * 0.1031);\n\tp3 = p3 + (dot(p3, p3.yzx + 33.33));\n\treturn fract((p3.x + p3.y) * p3.z);\n} \n\nfn sdBox(p: vec3<f32>, b: vec3<f32>) -> f32 {\n\tvar q: vec3<f32> = abs(p) - b;\n\treturn length(max(q, vec3<f32>(0.))) + min(max(q.x, max(q.y, q.z)), 0.);\n} \n\nfn opSmoothUnion(d1: f32, d2: f32, k: f32) -> f32 {\n\tvar h: f32 = clamp(0.5 + 0.5 * (d2 - d1) / k, 0., 1.);\n\treturn mix(d2, d1, h) - k * h * (1. - h);\n} \n\nfn opSmoothSubtraction(d1: f32, d2: f32, k: f32) -> f32 {\n\tvar h: f32 = clamp(0.5 - 0.5 * (d2 + d1) / k, 0., 1.);\n\treturn mix(d2, -d1, h) + k * h * (1. - h);\n} \n\nfn opSmoothIntersection(d1: f32, d2: f32, k: f32) -> f32 {\n\tlet h: f32 = clamp(0.5 - 0.5 * (d2 - d1) / k, 0., 1.);\n\treturn mix(d2, d1, h) + k * h * (1. - h);\n} \n\nfn sdCappedTorus(p2: vec3<f32>, sc: vec2<f32>, ra: f32, rb: f32) -> f32 {\n    var p = p2;\n\tp.x = abs(p.x);\n\tvar k: f32 = 0.; \n    if (sc.y * p.x > sc.x * p.y) { \n        k = dot(p.xy, sc); }\n    else { \n        k = length(p.xy); \n    };\n\treturn sqrt(dot(p, p) + ra * ra - 2. * ra * k) - rb;\n} \n\nfn sdVerticalCapsule(p2: vec3<f32>, h: f32, r: f32) -> f32 {\n    var p = p2;\n\tp.y = p.y - (clamp(p.y, 0., h));\n\treturn length(p) - r;\n} \n\nfn sdCappedCone(p: vec3<f32>, a: vec3<f32>, b: vec3<f32>, ra: f32, rb: f32) -> f32 {\n\tlet rba: f32 = rb - ra;\n\tlet baba: f32 = dot(b - a, b - a);\n\tlet papa: f32 = dot(p - a, p - a);\n\tlet paba: f32 = dot(p - a, b - a) / baba;\n\tlet x: f32 = sqrt(papa - paba * paba * baba);\n    var rab: f32;\n    if (paba < 0.5) { rab = ra; } else { rab = rb; }\n\tlet cax: f32 = max(0., x - rab);\n\tvar cay: f32 = abs(paba - 0.5) - 0.5;\n\tlet k: f32 = rba * rba + baba;\n\tlet f: f32 = clamp((rba * (x - ra) + paba * baba) / k, 0., 1.);\n\tvar cbx: f32 = x - ra - f * rba;\n\tlet cby: f32 = paba - f;\n\tvar s: f32; \n    if (cbx < 0. && cay < 0.) { s = -1.; } else { s = 1.; };\n\treturn s * sqrt(min(cax * cax + cay * cay * baba, cbx * cbx + cby * cby * baba));\n} \n\nfn sdRoundedCylinder(p: vec3<f32>, ra: f32, rb: f32, h: f32) -> f32 {\n\tlet d: vec2<f32> = vec2<f32>(length(p.xz) - 2. * ra + rb, abs(p.y) - h);\n\treturn min(max(d.x, d.y), 0.) + length(max(d, vec2<f32>(0.))) - rb;\n} \n\nfn sdRoundBox(p: vec3<f32>, b: vec3<f32>, r: f32) -> f32 {\n\tlet q: vec3<f32> = abs(p) - b;\n\treturn length(max(q, vec3<f32>(0.))) + min(max(q.x, max(q.y, q.z)), 0.) - r;\n} \n\nvar<private> ao_pass: bool = false;\nfn map2(pos_in: vec3<f32>) -> Volume {\n    var pos = pos_in;\n\tvar shape: f32 = 100.;\n\tvar poszy = pos.zy;\n\tposzy = pos.zy * (rot(sin(pos.y * 0.2 + uni.iTime) * 0.1 + 0.2));\n\tpos.z = poszy.x;\n\tpos.y = poszy.y;\n\tvar posyx = pos.yx;\n\tposyx = pos.yx * (rot(0.1 * sin(pos.y * 0.3 + uni.iTime)));\n\tpos.y = posyx.x;\n\tpos.x = posyx.y;\n\tvar p: vec3<f32> = pos;\n\n\tvar ghost: Volume;\n\tghost.mate = 0;\n\tghost.density = 0.05;\n\tghost.space = 0.12;\n    \n\tvar opaque: Volume;\n\topaque.mate = 0;\n\topaque.density = 1.;\n\topaque.space = 0.;\n\n\tvar hair: Volume;\n\thair.mate = mat_eyebrows;\n\thair.density = 0.2;\n\thair.space = 0.1;\n\n\tvar glass: Volume;\n\tglass.mate = mat_glass;\n\tglass.density = 0.15;\n\tglass.space = 0.1;\n    glass.dist = 0.;\n\n\tghost.dist = length(p * vec3<f32>(1., 0.9, 1.)) - 1.;\n\tghost.dist = opSmoothUnion(ghost.dist, length(p - vec3<f32>(0., 1.2, 0.)) - 0.55, 0.35);\n\n\tp.z = p.z + (1.3);\n\tvar pyz = p.yz;\n\tpyz = p.yz * (rot(p.z * 0.5 + 0.1 * sin(uni.iTime + p.z * 4.)));\n\tp.y = pyz.x;\n\tp.z = pyz.y;\n\tshape = sdBox(p, vec3<f32>(1., 0.01, 1.));\n\tshape = max(shape, -length(pos.xz) + 0.99);\n\tghost.dist = opSmoothSubtraction(shape, ghost.dist, 0.1);\n\tp = pos - vec3<f32>(0., 1.6, 0.);\n\tshape = sdRoundedCylinder(p + sin(p.z * 4.) * 0.03, 0.4, 0.01, 0.01);\n\tshape = min(shape, sdCappedCone(p + 0.05 * sin(p.z * 8.), vec3<f32>(0., 0.5, 0.), vec3<f32>(0.), 0.3, 0.445));\n\tghost.dist = min(ghost.dist, shape);\n\tp = pos - vec3<f32>(0., 1., -0.55);\n\tlet s: f32 = sign(p.x);\n\n\tvar pxz = p.xz;\n\tpxz = p.xz * (rot(-pos.x * 1.));\n\tp.x = pxz.x;\n\tp.z = pxz.y;\n\n\tp.x = abs(p.x) - 0.15;\n\n\topaque.dist = max(length(p * vec3<f32>(1., 1., 1.3)) - 0.18, -ghost.dist);\n\topaque.mate = mat_eye_globe;\n\n\tp = p - (vec3<f32>(0.05, 0.3, -0.03));\n\tp.y = p.y - (0.01 * sin(uni.iTime * 3.));\n\n\tvar pxy = p.xy;\n\tpxy = p.xy * (rot(0.2 + sin(pos.x * 2. + uni.iTime) * 0.5));\n\tp.x = pxy.x;\n\tp.y = pxy.y;\n\n\tshape = sdBox(p, vec3<f32>(0.15, 0.02 - p.x * 0.1, 0.03));\n\thair.dist = shape;\n\tp = pos;\n\tghost.dist = opSmoothUnion(ghost.dist, length(p + vec3<f32>(0., 1.8, 0.)) - 0.5, 0.6);\n\tp.x = abs(p.x) - 0.2;\n\tp.z = p.z + (0.1 * sin(p.x * 4. + uni.iTime));\n\tghost.dist = opSmoothUnion(ghost.dist, sdVerticalCapsule(p + vec3<f32>(0., 2.8, 0.), 0.6, 0.01 + max(0., p.y + 3.) * 0.3), 0.2);\n\tp = pos;\n\tp.x = abs(p.x) - 0.4;\n\n\tvar pxy = p.xy;\n\tpxy = p.xy * (rot(3.14 / 2.));\n\tp.x = pxy.x;\n\tp.y = pxy.y;\n\n\tp.x = p.x + (pos.x * 0.2 * sin(pos.x + uni.iTime));\n\tghost.dist = opSmoothUnion(ghost.dist, sdVerticalCapsule(p + vec3<f32>(-1.5, 0., 0.), 0.6, 0.2), 0.2);\n\t\n    let vvv = select2(ghost, opaque);\n    var volume: Volume = select2(vvv, hair);\n\tif (!ao_pass) {\n\t\tp = pos - vec3<f32>(0., 1., -0.65);\n\t\tp.x = abs(p.x) - 0.18;\n\t\tglass.dist = sdRoundBox(p + vec3<f32>(-0.1, 0., 0.1), vec3<f32>(0.2 + p.y * 0.1, 0.15 + p.x * 0.05, 0.001), 0.05);\n\t\tglass.dist = max(glass.dist, -sdRoundBox(p + vec3<f32>(-0.1, 0., 0.1), vec3<f32>(0.18 + p.y * 0.1, 0.14 + p.x * 0.05, 0.1), 0.05));\n\t\tglass.dist = max(glass.dist, abs(p.z) - 0.1);\n\t\tvolume = select2(volume, glass);\n\t}\n\treturn volume;\n} \n\nfn getNormal(p: vec3<f32>) -> vec3<f32> {\n\tlet off: vec2<f32> = vec2<f32>(0.001, 0.);\n\treturn normalize(map2(p).dist - vec3<f32>(map2(p - off.xyy).dist, map2(p - off.yxy).dist, map2(p - off.yyx).dist));\n} \n\nfn getAO(pos: vec3<f32>, nor: vec3<f32>) -> f32 {\n\tvar occ: f32 = 0.;\n\tvar sca: f32 = 1.;\n\n\tfor (var i: i32 = 0; i < 5; i = i + 1) {\n\t\tlet h: f32 = 0.01 + 0.12 * f32(i) / 4.;\n\t\tvar volume: Volume = map2(pos + h * nor);\n\t\tlet d: f32 = volume.dist;\n\t\tocc = occ + ((h - d) * sca);\n\t\tsca = sca * (0.95);\n\t\tif (occ > 0.35) { break; }\n\t}\n\n\treturn clamp(1. - 3. * occ, 0., 1.) * (0.5 + 0.5 * nor.y);\n} \n\n\n// @compute @workgroup_size(8, 8, 1)\n// fn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n//     let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n//     var O: vec4<f32> =  textureLoad(buffer_a, location);\n//     textureStore(texture, location, O);\n// }\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar color: vec4<f32>;\n\tvar coordinate = vec2<f32>(f32(location.x), f32(location.y) );\n\n\tcolor = vec4<f32>(0., 0., 0., 0.);\n\tlet uv: vec2<f32> = coordinate / uni.iResolution.xy;\n\tlet p: vec2<f32> = 2. * (coordinate - 0.5 * uni.iResolution.xy) / uni.iResolution.y;\n\tvar pos: vec3<f32> = vec3<f32>(-5., 0., -8.);\n\tvar z: vec3<f32> = normalize(vec3<f32>(0., -0.3, 0.) - pos);\n\tvar x: vec3<f32> = normalize(cross(z, vec3<f32>(0., 1., 0.)));\n\tvar y: vec3<f32> = normalize(cross(x, z));\n\tlet ray: vec3<f32> = normalize(z * 3. + x * p.x + y * p.y);\n\tvar colorrgb = color.rgb;\n\tcolorrgb = color.rgb + (vec3<f32>(0.2235, 0.3804, 0.5882) * uv.y);\n\tcolor.r = colorrgb.x;\n\tcolor.g = colorrgb.y;\n\tcolor.b = colorrgb.z;\n    color.a = 1.;\n\tvar shade: f32 = 0.;\n\tvar normal: vec3<f32> = vec3<f32>(0., 1., 0.);\n\tvar ao: f32 = 1.;\n\tlet rng: f32 = hash12(coordinate + uni.iTime);\n\tvar count: i32 = 30;\n\n\tfor (var index: i32 = 0; index < count; index += 1) {\n\t\tvar volume: Volume = map2(pos);\n\t\tif (volume.dist < 0.01) {\n        \n\t\t\tif (shade < 0.001) {\n\t\t\t\tao_pass = true;\n\t\t\t\tao = getAO(pos, normal);\n\t\t\t\tao_pass = false;\n\t\t\t}\n\t\t\tshade = shade + (volume.density);\n\t\t\tnormal = getNormal(pos);\n\t\t\tlet fresnel: f32 = pow(dot(ray, normal) * 0.5 + 0.5, 1.2);\n\t\t\tvolume.dist = volume.space * fresnel;\n\t\t\tvar col: vec3<f32> = vec3<f32>(0.);\n\t\t\tif (volume.mate == mat_eye_globe) {\n\n                let globe: f32 = dot(normal, vec3<f32>(0., 1., 0.)) * 0.5 + 0.5;\n                var look: vec3<f32> = vec3<f32>(0., 0., -1.);\n                var lookxz = look.xz;\n                lookxz = look.xz * (rot(sin(uni.iTime) * 0.2 - 0.2));\n                look.x = lookxz.x;\n                look.z = lookxz.y;\n                var lookyz = look.yz;\n                lookyz = look.yz * (rot(sin(uni.iTime * 2.) * 0.1 + 0.5));\n                look.y = lookyz.x;\n                look.z = lookyz.y;\n                let pupils: f32 = smoothstep(0.01, 0., dot(normal, look) - 0.95);\n                col = col + (vec3<f32>(1.) * globe * pupils);\n                // break;\n            }\n            else if (volume.mate == mat_eyebrows) {\n                col = col + (vec3<f32>(0.3451, 0.2314, 0.5255));\n                // break;\n            }\n            else if (volume.mate == mat_glass) {\n                col = col + (vec3<f32>(0.2));\n                // break;\n            }\n            else {\n                let leftlight: vec3<f32> = normalize(vec3<f32>(6., -5., 1.));\n                let rightlight: vec3<f32> = normalize(vec3<f32>(-3., 1., 1.));\n                let frontlight: vec3<f32> = normalize(vec3<f32>(-1., 1., -2.));\n                let blue: vec3<f32> = vec3<f32>(0., 0., 1.) * pow(dot(normal, leftlight) * 0.5 + 0.5, 0.2);\n                let green: vec3<f32> = vec3<f32>(0., 1., 0.) * pow(dot(normal, frontlight) * 0.5 + 0.5, 2.);\n                let red: vec3<f32> = vec3<f32>(0.8941, 0.2039, 0.0824) * pow(dot(normal, rightlight) * 0.5 + 0.5, 0.5);\n                col = col + (blue + green + red);\n                col = col * (ao * 0.5 + 0.3);\n                // break;\n            }\n        \n            var colorrgb = color.rgb;\n            colorrgb = color.rgb + (col * volume.density);\n            color.r = colorrgb.x;\n            color.g = colorrgb.y;\n            color.b = colorrgb.z;\n\n            // color = vec4<f32>(1.0, 0.0, 0.0, 1.0);\n            \n        }\n\t\tif (shade >= 1.) {\n\t\t\tbreak;\n\t\t}\n        \n\t\tvolume.dist = volume.dist * (0.9 + 0.1 * rng);\n\t\tpos = pos + (ray * volume.dist);\n\t}\n\n\n    // color = vec4<f32>(1.0, 0.0, 0.0, 1.0);\n    // color.a = 1.0;\n    textureStore(texture, y_inverted_location, color);\n\n} \n\n\n"
  },
  {
    "path": "examples/soul/soul.rs",
    "content": "// Original shader by leon\n// https://www.shadertoy.com/view/3ltyRB\n// Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0)\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n    window::PresentMode,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: 960. as u32,\n            height: 600.0 as u32,\n            borders: 0.0,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"soul\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n"
  },
  {
    "path": "examples/sunset/buffer_a.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    let color = vec4<f32>(0.5);\n    textureStore(buffer_a, location, color);\n}"
  },
  {
    "path": "examples/sunset/buffer_b.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/sunset/buffer_c.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/sunset/buffer_d.wgsl",
    "content": "@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n\n}"
  },
  {
    "path": "examples/sunset/common.wgsl",
    "content": ""
  },
  {
    "path": "examples/sunset/image.wgsl",
    "content": "// https://www.shadertoy.com/view/wlBXWK\n\nfn calculate_scattering(start: vec3<f32>, dir: vec3<f32>, max_dist: f32, scene_color: vec3<f32>, light_dir: vec3<f32>, light_intensity: vec3<f32>, planet_position: vec3<f32>, planet_radius: f32, atmo_radius: f32, beta_ray: vec3<f32>, beta_mie: vec3<f32>, beta_absorption: vec3<f32>, beta_ambient: vec3<f32>, g: f32, height_ray: f32, height_mie: f32, height_absorption: f32, absorption_falloff: f32, steps_i: i32, steps_l: i32) -> vec3<f32> {\n\tvar start_var = start;\n\tstart_var = start_var - (planet_position);\n\tvar a: f32 = dot(dir, dir);\n\tvar b: f32 = 2. * dot(dir, start_var);\n\tvar c: f32 = dot(start_var, start_var) - atmo_radius * atmo_radius;\n\tvar d: f32 = b * b - 4. * a * c;\n\tif (d < 0.) {\treturn scene_color;\n }\n\tvar ray_length: vec2<f32> = vec2<f32>(max((-b - sqrt(d)) / (2. * a), 0.), min((-b + sqrt(d)) / (2. * a), max_dist));\n\tif (ray_length.x > ray_length.y) {\treturn scene_color;\n }\n\tvar allow_mie: bool = max_dist > ray_length.y;\n\tray_length.y = min(ray_length.y, max_dist);\n\tray_length.x = max(ray_length.x, 0.);\n\tlet step_size_i: f32 = (ray_length.y - ray_length.x) / f32(steps_i);\n\tvar ray_pos_i: f32 = ray_length.x + step_size_i * 0.5;\n\tvar total_ray: vec3<f32> = vec3<f32>(0.);\n\tvar total_mie: vec3<f32> = vec3<f32>(0.);\n\tvar opt_i: vec3<f32> = vec3<f32>(0.);\n\tlet scale_height: vec2<f32> = vec2<f32>(height_ray, height_mie);\n\tvar mu: f32 = dot(dir, light_dir);\n\tvar mumu: f32 = mu * mu;\n\tvar gg: f32 = g * g;\n\tlet phase_ray: f32 = 3. / 50.265484 * (1. + mumu);\n\tvar phase_mie: f32; \n    if (allow_mie) { \n        phase_mie = 3. / 25.132742 * ((1. - gg) * (mumu + 1.)) / (pow(1. + gg - 2. * mu * g, 1.5) * (2. + gg)); \n    } else { \n        phase_mie = 0.; \n        };\n\n\tfor (var i: i32 = 0; i < steps_i; i = i + 1) {\n\t\tlet pos_i: vec3<f32> = start_var + dir * ray_pos_i;\n\t\tlet height_i: f32 = length(pos_i) - planet_radius;\n\t\tvar density: vec3<f32> = vec3<f32>(exp(-height_i / scale_height), 0.);\n\t\tvar denom: f32 = (height_absorption - height_i) / absorption_falloff;\n\t\tdensity.z = 1. / (denom * denom + 1.) * density.x;\n\t\tdensity = density * (step_size_i);\n\t\topt_i = opt_i + (density);\n\t\ta = dot(light_dir, light_dir);\n\t\tb = 2. * dot(light_dir, pos_i);\n\t\tc = dot(pos_i, pos_i) - atmo_radius * atmo_radius;\n\t\td = b * b - 4. * a * c;\n\t\tlet step_size_l: f32 = (-b + sqrt(d)) / (2. * a * f32(steps_l));\n\t\tvar ray_pos_l: f32 = step_size_l * 0.5;\n\t\tvar opt_l: vec3<f32> = vec3<f32>(0.);\n\n\t\tfor (var l: i32 = 0; l < steps_l; l = l + 1) {\n\t\t\tlet pos_l: vec3<f32> = pos_i + light_dir * ray_pos_l;\n\t\t\tlet height_l: f32 = length(pos_l) - planet_radius;\n\t\t\tvar density_l: vec3<f32> = vec3<f32>(exp(-height_l / scale_height), 0.);\n\t\t\tlet denom: f32 = (height_absorption - height_l) / absorption_falloff;\n\t\t\tdensity_l.z = 1. / (denom * denom + 1.) * density_l.x;\n\t\t\tdensity_l = density_l * (step_size_l);\n\t\t\topt_l = opt_l + (density_l);\n\t\t\tray_pos_l = ray_pos_l + (step_size_l);\n\t\t}\n\n\t\tlet attn: vec3<f32> = exp(-beta_ray * (opt_i.x + opt_l.x) - beta_mie * (opt_i.y + opt_l.y) - beta_absorption * (opt_i.z + opt_l.z));\n\t\ttotal_ray = total_ray + (density.x * attn);\n\t\ttotal_mie = total_mie + (density.y * attn);\n\t\tray_pos_i = ray_pos_i + (step_size_i);\n\t}\n\n\tlet opacity: vec3<f32> = exp(-(beta_mie * opt_i.y + beta_ray * opt_i.x + beta_absorption * opt_i.z));\n\treturn (phase_ray * beta_ray * total_ray + phase_mie * beta_mie * total_mie + opt_i.x * beta_ambient) * light_intensity + scene_color * opacity;\n} \n\nfn ray_sphere_intersect(start: vec3<f32>, dir: vec3<f32>, radius: f32) -> vec2<f32> {\n\tlet a: f32 = dot(dir, dir);\n\tlet b: f32 = 2. * dot(dir, start);\n\tlet c: f32 = dot(start, start) - radius * radius;\n\tlet d: f32 = b * b - 4. * a * c;\n\tif (d < 0.) {\treturn vec2<f32>(100000., -100000.);\n }\n\treturn vec2<f32>((-b - sqrt(d)) / (2. * a), (-b + sqrt(d)) / (2. * a));\n} \n\nfn skylight(sample_pos: vec3<f32>, surface_normal: vec3<f32>, light_dir: vec3<f32>, background_col: vec3<f32>) -> vec3<f32> {\n\tvar surface_normal_var = surface_normal;\n\tsurface_normal_var = normalize(mix(surface_normal_var, light_dir, 0.6));\n\treturn calculate_scattering(sample_pos, surface_normal_var, 3. * 6471000., background_col, light_dir, vec3<f32>(40.), vec3<f32>(0.), 6371000., 6471000., vec3<f32>(0.0000055, 0.000013, 0.0000224), vec3<f32>(0.000021), vec3<f32>(0.0000204, 0.0000497, 0.00000195), vec3<f32>(0.), 0.7, 8000., 1200., 30000., 4000., 4, 4);\n} \n\nfn render_scene(pos: vec3<f32>, dir: vec3<f32>, light_dir: vec3<f32>) -> vec4<f32> {\n\tvar color: vec4<f32> = vec4<f32>(0., 0., 0., 1000000000000.);\n\tvar colorxyz = color.xyz;\n\t// colorxyz = vec3<f32>;\n    if (dot(dir, light_dir) > 0.9998) { \n        colorxyz = vec3<f32>(3.); \n    } else { \n        colorxyz =vec3<f32>( 0.); \n        };\n\tcolor.x = colorxyz.x;\n\tcolor.y = colorxyz.y;\n\tcolor.z = colorxyz.z;\n\tlet planet_intersect: vec2<f32> = ray_sphere_intersect(pos - vec3<f32>(0.), dir, 6371000.);\n\tif (0. < planet_intersect.y) {\n\t\tcolor.w = max(planet_intersect.x, 0.);\n\t\tlet sample_pos: vec3<f32> = pos + dir * planet_intersect.x - vec3<f32>(0.);\n\t\tlet surface_normal: vec3<f32> = normalize(sample_pos);\n\t\tvar colorxyz = color.xyz;\n\tcolorxyz = vec3<f32>(0., 0.25, 0.05);\n\tcolor.x = colorxyz.x;\n\tcolor.y = colorxyz.y;\n\tcolor.z = colorxyz.z;\n\t\tlet N: vec3<f32> = surface_normal;\n\t\tlet V: vec3<f32> = -dir;\n\t\tlet L: vec3<f32> = light_dir;\n\t\tlet dotNV: f32 = max(0.000001, dot(N, V));\n\t\tlet dotNL: f32 = max(0.000001, dot(N, L));\n\t\tlet shadow: f32 = dotNL / (dotNL + dotNV);\n\t\tvar colorxyz = color.xyz;\n\tcolorxyz = color.xyz * (shadow);\n\tcolor.x = colorxyz.x;\n\tcolor.y = colorxyz.y;\n\tcolor.z = colorxyz.z;\n\t\tvar colorxyz = color.xyz;\n\tcolorxyz = color.xyz + (clamp(skylight(sample_pos, surface_normal, light_dir, vec3<f32>(0.)) * vec3<f32>(0., 0.25, 0.05), vec3<f32>(0.), vec3<f32>(1.)));\n\tcolor.x = colorxyz.x;\n\tcolor.y = colorxyz.y;\n\tcolor.z = colorxyz.z;\n\t}\n\treturn color;\n} \n\nfn get_camera_vector(resolution: vec2<f32>, coord: vec2<f32>) -> vec3<f32> {\n\tvar uv: vec2<f32> = coord.xy / resolution.xy - vec2<f32>(0.5);\n\tuv.x = uv.x * (resolution.x / resolution.y);\n\treturn normalize(vec3<f32>(uv.x, uv.y, -1.));\n} \n\nfn toLinear(sRGB: vec4<f32>) -> vec4<f32> {\n    let cutoff = vec4<f32>(sRGB < vec4<f32>(0.04045));\n    let higher = pow((sRGB + vec4<f32>(0.055)) / vec4<f32>(1.055), vec4<f32>(2.4));\n    let lower = sRGB / vec4<f32>(12.92);\n\n    return mix(higher, lower, cutoff);\n}\n\n\n@compute @workgroup_size(8, 8, 1)\nfn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {\n    let R: vec2<f32> = uni.iResolution.xy;\n    let y_inverted_location = vec2<i32>(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y));\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n    \n\tvar fragColor: vec4<f32>;\n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    let time = uni.iTime / 3.0;\n\n\tlet camera_vector: vec3<f32> = get_camera_vector(uni.iResolution, fragCoord);\n\tlet offset: f32 = (1. - cos(time / 2.)) * 6471000.;\n\tlet camera_position: vec3<f32> = vec3<f32>(0., 6371000. + 1., offset);\n\tvar light_dir: vec3<f32>; \n    if (uni.iMouse.y == 0.) { \n        light_dir = normalize(vec3<f32>(0., cos(-time / 8.), sin(-time / 8.))); \n    } else { \n        light_dir = normalize(vec3<f32>(0., cos(uni.iMouse.y * -5. / uni.iResolution.y), sin(uni.iMouse.y * -5. / uni.iResolution.y))); \n    };\n\tlet scene: vec4<f32> = render_scene(camera_position, camera_vector, light_dir);\n\tvar col: vec3<f32> = vec3<f32>(0.);\n\tcol = col + (calculate_scattering(camera_position, camera_vector, scene.w, scene.xyz, light_dir, vec3<f32>(40.), vec3<f32>(0.), 6371000., 6471000., vec3<f32>(0.0000055, 0.000013, 0.0000224), vec3<f32>(0.000021), vec3<f32>(0.0000204, 0.0000497, 0.00000195), vec3<f32>(0.), 0.7, 8000., 1200., 30000., 4000., 12, 4));\n\tcol = 1. - exp(-col);\n\t// fragColor = vec4<f32>(col, 1.);\n\n    textureStore(texture, y_inverted_location,  toLinear(vec4<f32>((col), 1.)));\n} \n\n"
  },
  {
    "path": "examples/sunset/sunset.rs",
    "content": "// MIT License\n// Copyright (c) 2019 Dimas Leenman\n\nuse bevy::{\n    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},\n    prelude::*,\n};\n\nuse bevy_shadertoy_wgsl::*;\n\nfn main() {\n    let mut app = App::new();\n\n    app.insert_resource(ClearColor(Color::GRAY))\n        .insert_resource(WindowDescriptor {\n            width: 960.,\n            height: 600.,\n            cursor_visible: true,\n            // present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS\n            ..default()\n        })\n        .insert_resource(ShadertoyCanvas {\n            width: 960. as u32,\n            height: 600.0 as u32,\n            borders: 0.0,\n            position: Vec3::new(0.0, 0.0, 0.0),\n        })\n        .add_plugins(DefaultPlugins)\n        .add_plugin(ShadertoyPlugin)\n        .add_plugin(FrameTimeDiagnosticsPlugin::default())\n        .add_plugin(LogDiagnosticsPlugin::default())\n        .add_startup_system(setup)\n        // .add_system(update_common_uniform)\n        .run();\n}\n\nfn setup(\n    mut commands: Commands,\n    asset_server: Res<AssetServer>,\n    mut st_res: ResMut<ShadertoyResources>,\n) {\n    let example = \"sunset\";\n    st_res.include_debugger = false;\n\n    let all_shader_handles: ShaderHandles =\n        make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    commands.insert_resource(all_shader_handles);\n}\n\n//  ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4\n//  ffmpeg -ss 2 -t 27 -i output.mp4 -vf \"fps=20,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse\" -loop 0 showcase.gif\n"
  },
  {
    "path": "src/lib.rs",
    "content": "//! Notes:\n//! wglsl error messages do not display the correct line numbers when comparing to the\n//! buffer and image scripts because the shader that is read by the GPU includes\n//! the uniform and the bindings, which add about 50 lines of code\n\nuse bevy::{\n    // core::{Pod, Zeroable},\n\n    // core_pipeline::node::MAIN_PASS_DEPENDENCIES,\n    prelude::*,\n    render::{\n        extract_resource::{ExtractResource, ExtractResourcePlugin},\n        render_asset::RenderAssets,\n        render_graph::{self, NodeLabel, RenderGraph},\n        // render_resource::ShaderSize,\n        // render_resource::*,\n        render_resource::{\n            encase::private::WriteInto, BindGroup, BindGroupDescriptor, BindGroupEntry,\n            BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource,\n            BindingType, Buffer, BufferBindingType, BufferDescriptor, BufferSize, BufferUsages,\n            CachedComputePipelineId, CachedPipelineState, ComputePassDescriptor,\n            ComputePipelineDescriptor, Extent3d, PipelineCache, SamplerBindingType, ShaderStages,\n            ShaderType, StorageTextureAccess, TextureDimension, TextureFormat, TextureSampleType,\n            TextureUsages, TextureViewDimension,\n        },\n        renderer::{RenderContext, RenderDevice, RenderQueue},\n        MainWorld,\n        RenderApp,\n        RenderStage,\n    },\n    window::WindowResized,\n};\n// run the following to avoid the \"nage skip function\" warning at every frame\n// RUST_LOG=wgpu=error,naga=warn,info  cargo run --release --features bevy/dynamic --example simpler_particles\n\nuse crevice::std140::AsStd140;\n\nuse bevy::{app::ScheduleRunnerSettings, utils::Duration};\n\nuse std::borrow::Cow;\nuse std::fs; // not compatible with WASM -->\n\nmod texture_a;\nuse texture_a::*;\n\nmod texture_b;\nuse texture_b::*;\n\nmod texture_c;\nuse texture_c::*;\n\nmod texture_d;\nuse texture_d::*;\n\npub const WORKGROUP_SIZE: u32 = 8;\npub const NUM_PARTICLES: u32 = 256;\n// pub const BORDERS: f32 = 1.0;\n\n#[derive(Clone, ExtractResource, Debug)]\npub struct ShadertoyCanvas {\n    pub width: u32,\n    pub height: u32,\n    pub borders: f32,\n    pub position: Vec3,\n}\n\n#[derive(Clone, ExtractResource)]\npub struct ShadertoyTextures {\n    font_texture_handle: Handle<Image>,\n    rgba_noise_256_handle: Handle<Image>,\n    blue_noise_handle: Handle<Image>,\n}\n\n#[derive(Clone, ExtractResource)]\npub struct ShadertoyResources {\n    number_of_frames: u32,\n    time_since_reset: f32,\n    pub include_debugger: bool,\n}\n\nfn setup(\n    mut commands: Commands,\n    mut images: ResMut<Assets<Image>>,\n    canvas: Res<ShadertoyCanvas>,\n\n    asset_server: Res<AssetServer>,\n    windows: Res<Windows>,\n) {\n    commands.spawn_bundle(Camera2dBundle::default());\n    // let window = windows.primary();\n\n    let mut image = Image::new_fill(\n        Extent3d {\n            width: canvas.width,\n            height: canvas.height,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba32Float,\n    );\n    image.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let image = images.add(image);\n\n    commands.insert_resource(ChangedWindowSize(false));\n\n    commands.insert_resource(MainImage(image.clone()));\n\n    commands.spawn_bundle(SpriteBundle {\n        sprite: Sprite {\n            custom_size: Some(Vec2::new(canvas.width as f32, canvas.height as f32)),\n            ..default()\n        },\n        texture: image.clone(),\n        // // the y axis of a bevy window is flipped compared to shadertoy. We fix it\n        // // by rotating the sprite 180 degrees, but this comes at the cost of a mirrored\n        // // image in the x axis.\n        // transform: Transform::from_rotation(bevy::math::Quat::from_rotation_z(\n        //     core::f32::consts::PI,\n        // )),\n        transform: Transform::from_translation(canvas.position),\n        ..default()\n    });\n\n    let font_texture_handle: Handle<Image> = asset_server.load(\"textures/font.png\");\n    let rgba_noise_256_handle: Handle<Image> = asset_server.load(\"textures/rgba_noise_256.png\");\n    let blue_noise_handle: Handle<Image> = asset_server.load(\"textures/blue_noise.png\");\n\n    commands.insert_resource(ShadertoyTextures {\n        font_texture_handle,\n        rgba_noise_256_handle,\n        blue_noise_handle,\n    });\n\n    let window = windows.primary();\n    let mut common_uniform = CommonUniform::new();\n\n    common_uniform.i_resolution.x = window.width();\n    common_uniform.i_resolution.y = window.height();\n    commands.insert_resource(common_uniform);\n\n    //\n    //\n    //\n    // Texture A: equivalent of Buffer A in Shadertoy\n    let mut texture_a = Image::new_fill(\n        Extent3d {\n            width: canvas.width,\n            height: canvas.height,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        // &[255, 255, 255, 255],\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba32Float,\n    );\n    texture_a.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let texture_a = images.add(texture_a);\n\n    commands.insert_resource(TextureA(texture_a));\n\n    //\n    //\n    //\n    // Texture B: equivalent of Buffer B in Shadertoy\n    let mut texture_b = Image::new_fill(\n        Extent3d {\n            width: canvas.width,\n            height: canvas.height,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        // &[255, 255, 255, 255],\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba32Float,\n    );\n    texture_b.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let texture_b = images.add(texture_b);\n\n    commands.insert_resource(TextureB(texture_b));\n\n    //\n    //\n    //\n    // Texture C: equivalent of Buffer C in Shadertoy\n    let mut texture_c = Image::new_fill(\n        Extent3d {\n            width: canvas.width,\n            height: canvas.height,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        // &[255, 255, 255, 255],\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba32Float,\n    );\n    texture_c.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let texture_c = images.add(texture_c);\n\n    commands.insert_resource(TextureC(texture_c));\n\n    //\n    //\n    //\n    // Texture D: equivalent of Buffer D in Shadertoy\n    let mut texture_d = Image::new_fill(\n        Extent3d {\n            width: canvas.width,\n            height: canvas.height,\n            depth_or_array_layers: 1,\n        },\n        TextureDimension::D2,\n        // &[255, 255, 255, 255],\n        &[0, 0, 0, 0],\n        TextureFormat::Rgba32Float,\n    );\n    texture_d.texture_descriptor.usage =\n        TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;\n\n    let texture_d = images.add(texture_d);\n\n    commands.insert_resource(TextureD(texture_d));\n\n    // TODO\n    // rain: https://www.shadertoy.com/view/wdGSzw\n    // fix clouds\n\n    // // let example = \"clouds\";\n    // // let example = \"minimal\";\n    // // let example = \"paint\";\n    // // let example = \"paint_streams2\";\n    // // let example = \"seascape\";\n    // // let example = \"sunset\";\n    // let example = \"fluid\";\n    // // let example = \"dry_ice\";\n    // // let example = \"protean_clouds\";\n\n    // // let example = \"fire2\";\n    // // let example = \"fire\";\n    // // let example = \"debugger\";\n    // // let example = \"molecular_dynamics\";\n    // // let example = \"love_and_domination\";\n    // // let example = \"dancing_tree\";\n\n    // let all_shader_handles: ShaderHandles =\n    //     make_and_load_shaders2(example, &asset_server, st_res.include_debugger);\n\n    // commands.insert_resource(all_shader_handles);\n}\n\npub fn make_and_load_shaders(example: &str, asset_server: &Res<AssetServer>) -> ShaderHandles {\n    let image_shader_handle = asset_server.load(&format!(\"./shaders/{}/image.wgsl\", example));\n    let texture_a_shader = asset_server.load(&format!(\"./shaders/{}/buffer_a.wgsl\", example));\n    let texture_b_shader = asset_server.load(&format!(\"./shaders/{}/buffer_b.wgsl\", example));\n    let texture_c_shader = asset_server.load(&format!(\"./shaders/{}/buffer_c.wgsl\", example));\n    let texture_d_shader = asset_server.load(&format!(\"./shaders/{}/buffer_d.wgsl\", example));\n\n    ShaderHandles {\n        image_shader: image_shader_handle,\n        texture_a_shader,\n        texture_b_shader,\n        texture_c_shader,\n        texture_d_shader,\n    }\n}\n\npub fn make_and_load_shaders2(\n    example: &str,\n    asset_server: &Res<AssetServer>,\n    include_debugger: bool,\n) -> ShaderHandles {\n    // let image_shader_handle = asset_server.load(&format!(\"shaders/{}/image.wgsl\", example));\n    // let example_string = example.to_string();\n    //\n\n    format_and_save_shader(example, \"image\", include_debugger);\n    format_and_save_shader(example, \"buffer_a\", false);\n    format_and_save_shader(example, \"buffer_b\", false);\n    format_and_save_shader(example, \"buffer_c\", false);\n    format_and_save_shader(example, \"buffer_d\", false);\n\n    let image_shader_handle = asset_server.load(&format!(\"./shaders/{}/image.wgsl\", example));\n    let texture_a_shader = asset_server.load(&format!(\"./shaders/{}/buffer_a.wgsl\", example));\n    let texture_b_shader = asset_server.load(&format!(\"./shaders/{}/buffer_b.wgsl\", example));\n    let texture_c_shader = asset_server.load(&format!(\"./shaders/{}/buffer_c.wgsl\", example));\n    let texture_d_shader = asset_server.load(&format!(\"./shaders/{}/buffer_d.wgsl\", example));\n\n    ShaderHandles {\n        image_shader: image_shader_handle,\n        texture_a_shader,\n        texture_b_shader,\n        texture_c_shader,\n        texture_d_shader,\n    }\n}\n\n// This function uses the std library and isn't compatible with wasm\nfn format_and_save_shader(example: &str, buffer_type: &str, include_debugger: bool) {\n    let common_prelude = include_str!(\"./templates/common_prelude.wgsl\");\n\n    let template = match buffer_type {\n        \"image\" => include_str!(\"./templates/image_template.wgsl\"),\n        \"buffer_a\" => include_str!(\"./templates/buffer_a_template.wgsl\"),\n        \"buffer_b\" => include_str!(\"./templates/buffer_b_template.wgsl\"),\n        \"buffer_c\" => include_str!(\"./templates/buffer_c_template.wgsl\"),\n        \"buffer_d\" => include_str!(\"./templates/buffer_d_template.wgsl\"),\n        _ => include_str!(\"./templates/buffer_d_template.wgsl\"),\n    };\n\n    let mut shader_content = template.replace(\"{{COMMON_PRELUDE}}\", common_prelude);\n\n    if include_debugger {\n        let debbuger_str = include_str!(\"./templates/debugger.wgsl\");\n        shader_content = shader_content.replace(\"{{DEBUGGER}}\", debbuger_str);\n    } else {\n        shader_content = shader_content.replace(\"{{DEBUGGER}}\", \"\");\n    }\n\n    let path_to_code_block = format!(\"./examples/{}/{}.wgsl\", example, buffer_type);\n    let path_to_common = format!(\"./examples/{}/common.wgsl\", example);\n    println!(\"common: {}\", path_to_common);\n\n    let common = fs::read_to_string(path_to_common).expect(\"could not read file.\");\n    let image_main = fs::read_to_string(path_to_code_block).expect(\"could not read file.\");\n\n    let mut shader_content = shader_content.replace(\"{{COMMON}}\", &common);\n    shader_content = shader_content.replace(\"{{CODE_BLOCK}}\", &image_main);\n    let folder = format!(\"./assets/shaders/{}\", example);\n    let path = format!(\"{}/{}.wgsl\", folder, buffer_type);\n    println!(\"{}\", path);\n    let _ = fs::create_dir(folder);\n    fs::write(path, shader_content).expect(\"Unable to write file\");\n}\n\n// fn import_shader(\n//     shader_skeleton: &str,\n//     shader_handle_untyped: HandleUntyped,\n//     shaders: &mut Assets<Shader>,\n//     shader_core_script: &str,\n//     signature: &str,\n// ) -> Handle<Shader> {\n//     //\n//     // insert common code in every shader\n//     let shader_prelude =\n//     let mut image_source = shader_skeleton.replace(\"{{COMMON}}\", &COMMON);\n//     image_source = image_source.replace(signature, shader_core_script);\n\n//     let image_shader = Shader::from_wgsl(Cow::from(image_source));\n//     shaders.set_untracked(shader_handle_untyped.clone(), image_shader.clone());\n//     shader_handle_untyped.typed()\n// }\n\n// Copied from Shadertoy.com :\n// uniform vec3      iResolution;           // viewport resolution (in pixels)\n// uniform float     iTime;                 // shader playback time (in seconds)\n// uniform float     iTimeDelta;            // render time (in seconds)\n// uniform int       iFrame;                // shader playback frame\n// uniform float     iChannelTime[4];       // channel playback time (in seconds)\n// uniform vec3      iChannelResolution[4]; // channel resolution (in pixels)\n// uniform vec4      iMouse;                // mouse pixel coords. xy: current (if MLB down), zw: click\n// uniform samplerXX iChannel0..3;          // input channel. XX = 2D/Cube\n// uniform vec4      iDate;                 // (year, month, day, time in seconds)\n// uniform float     iSampleRate;           // sound sample rate (i.e., 44100)\n\n// use bytemuck::{Pod, Zeroable};\n// #[derive(Clone, Copy, bevy::render::render_resource::ShaderType)]\n#[derive(Clone, Copy)]\npub struct CommonUniform {\n    pub i_resolution: Vec2,\n    pub changed_window_size: f32,\n    pub padding0: f32,\n\n    pub i_time: f32,\n    pub i_time_delta: f32,\n    pub i_frame: f32,\n    pub i_sample_rate: f32, // sound sample rate\n\n    pub i_mouse: Vec4,\n\n    pub i_channel_time: Vec4,\n    pub i_channel_resolution: Vec4,\n    pub i_date: Vec4,\n}\n\nimpl CommonUniform {\n    pub fn new() -> Self {\n        Self {\n            i_resolution: Vec2::ZERO,\n            changed_window_size: 0.0,\n            padding0: 0.0,\n\n            i_time: 0.,\n            i_time_delta: 0.,\n            i_frame: 0.,\n            i_sample_rate: 0.,\n\n            i_mouse: Vec4::ZERO,\n\n            i_channel_time: Vec4::ZERO,\n            i_channel_resolution: Vec4::ZERO,\n            i_date: Vec4::ZERO,\n        }\n    }\n\n    pub fn into_crevice(&self) -> CommonUniformCrevice {\n        CommonUniformCrevice {\n            i_resolution: crevice::std140::Vec2 {\n                x: self.i_resolution.x,\n                y: self.i_resolution.y,\n            },\n\n            changed_window_size: self.changed_window_size,\n            padding0: self.padding0,\n\n            i_time: self.i_time,\n            i_time_delta: self.i_time_delta,\n            i_frame: self.i_frame,\n            i_sample_rate: self.i_sample_rate,\n\n            i_mouse: crevice::std140::Vec4 {\n                x: self.i_mouse.x,\n                y: self.i_mouse.y,\n                z: self.i_mouse.z,\n                w: self.i_mouse.w,\n            },\n\n            i_channel_time: crevice::std140::Vec4 {\n                x: self.i_channel_time.x,\n                y: self.i_channel_time.y,\n                z: self.i_channel_time.z,\n                w: self.i_channel_time.w,\n            },\n            i_channel_resolution: crevice::std140::Vec4 {\n                x: self.i_channel_resolution.x,\n                y: self.i_channel_resolution.y,\n                z: self.i_channel_resolution.z,\n                w: self.i_channel_resolution.w,\n            },\n            i_date: crevice::std140::Vec4 {\n                x: self.i_date.x,\n                y: self.i_date.y,\n                z: self.i_date.z,\n                w: self.i_date.w,\n            },\n        }\n    }\n}\n\n#[derive(Clone, Copy, AsStd140)]\npub struct CommonUniformCrevice {\n    pub i_resolution: crevice::std140::Vec2,\n    pub changed_window_size: f32,\n    pub padding0: f32,\n\n    pub i_time: f32,\n    pub i_time_delta: f32,\n    pub i_frame: f32,\n    pub i_sample_rate: f32, // sound sample rate\n\n    pub i_mouse: crevice::std140::Vec4,\n\n    pub i_channel_time: crevice::std140::Vec4,\n    pub i_channel_resolution: crevice::std140::Vec4,\n    pub i_date: crevice::std140::Vec4,\n}\n\n#[derive(Deref)]\npub struct ExtractedUniform(pub CommonUniformCrevice);\n\nimpl ExtractResource for ExtractedUniform {\n    type Source = CommonUniform;\n\n    fn extract_resource(common_uniform: &Self::Source) -> Self {\n        ExtractedUniform(common_uniform.into_crevice().clone())\n    }\n}\n\n// pub struct ExtractedTextures {\n//     pub a: TextureA,\n//     pub b: TextureB,\n//     pub c: TextureC,\n//     pub d: TextureD,\n// }\n\n// impl ExtractResource for ExtractedTextures {\n//     type Source = (TextureA, TextureB, TextureC, TextureD);\n\n//     fn extract_resource(textures: &Self::Source) -> Self {\n//         ExtractedTextures {\n//             a: TextureA(textures.0.clone()),\n//             b: TextureB(textures.1.clone()),\n//             c: TextureC(textures.2.clone()),\n//             d: TextureD(textures.3.clone()),\n//         }\n//     }\n// }\n\n// #[derive(Deref)]\n// pub struct ExtractedTextureA(TextureA);\n\n// impl ExtractResource for ExtractedTextureA {\n//     type Source = TextureA;\n\n//     fn extract_resource(texture: &Self::Source) -> Self {\n//         ExtractedTextureA(TextureA(texture.0.clone()))\n//     }\n// }\n\npub struct CommonUniformMeta {\n    buffer: Buffer,\n}\n\nfn make_new_texture(\n    // old_buffer_length: i32,\n    canvas_size: &Vec2,\n    image_handle: &Handle<Image>,\n    images: &mut ResMut<Assets<Image>>,\n) {\n    if let Some(image) = images.get_mut(image_handle) {\n        // There is no easy way to get the data from the gpu to the cpu, so when we\n        // resize the image, we lose all the data. There might be a way to get the\n        // data soon though.\n\n        image.resize(Extent3d {\n            width: canvas_size.x as u32,\n            height: canvas_size.y as u32,\n            depth_or_array_layers: 1,\n        });\n    }\n}\n\n// also updates the size of the buffers and main texture accordign to the window size\n// TODO: update date, channel time, channe l_resolution, sample_rate\nfn update_common_uniform(\n    mut common_uniform: ResMut<CommonUniform>,\n    mut window_resize_event: EventReader<WindowResized>,\n    mut query: Query<(&mut Sprite, &Transform, &Handle<Image>)>,\n    mut images: ResMut<Assets<Image>>,\n    windows: Res<Windows>,\n    time: Res<Time>,\n    mouse_button_input: Res<Input<MouseButton>>,\n    canvas: ResMut<ShadertoyCanvas>,\n    texture_a: Res<TextureA>,\n    texture_b: Res<TextureB>,\n    texture_c: Res<TextureC>,\n    texture_d: Res<TextureD>,\n    mut frames_accum: ResMut<ShadertoyResources>,\n    mut changed_window_size: ResMut<ChangedWindowSize>,\n) {\n    // update resolution\n    changed_window_size.0 = false;\n    for _window_resize in window_resize_event.iter() {\n        // canvas_size.width = common_uniform.i_resolution.x as u32;\n        // canvas_size.height = common_uniform.i_resolution.y as u32;\n\n        // common_uniform.i_resolution.x = (window_resize.width * (1. - canvas.borders)).floor();\n        // common_uniform.i_resolution.y = (window_resize.height * (1. - canvas.borders)).floor();\n\n        common_uniform.i_resolution.x = (canvas.width as f32 * (1. - canvas.borders)).floor();\n        common_uniform.i_resolution.y = (canvas.height as f32 * (1. - canvas.borders)).floor();\n        changed_window_size.0 = true;\n\n        for (mut sprite, _, image_handle) in query.iter_mut() {\n            sprite.custom_size = Some(common_uniform.i_resolution);\n\n            make_new_texture(&common_uniform.i_resolution, image_handle, &mut images);\n            make_new_texture(&common_uniform.i_resolution, &texture_a.0, &mut images);\n            make_new_texture(&common_uniform.i_resolution, &texture_b.0, &mut images);\n            make_new_texture(&common_uniform.i_resolution, &texture_c.0, &mut images);\n            make_new_texture(&common_uniform.i_resolution, &texture_d.0, &mut images);\n        }\n    }\n\n    // update mouse position\n    let window = windows.primary();\n    if let Some(mouse_pos) = window.cursor_position() {\n        let mp = mouse_pos;\n        // println!(\"{:?}\", mp);\n\n        for (_, transform, _) in query.iter() {\n            let pos = transform.translation.truncate();\n            let window_size = Vec2::new(window.width(), window.height());\n            let top_left = pos + (window_size - common_uniform.i_resolution) / 2.0;\n\n            common_uniform.i_mouse.x = mp.x - top_left.x;\n\n            common_uniform.i_mouse.y = mp.y - top_left.y;\n\n            if mouse_button_input.just_pressed(MouseButton::Left) {\n                common_uniform.i_mouse.z = common_uniform.i_mouse.x;\n                common_uniform.i_mouse.w = common_uniform.i_mouse.y;\n            }\n\n            if mouse_button_input.pressed(MouseButton::Left) {\n                common_uniform.i_mouse.z = common_uniform.i_mouse.z.abs();\n                common_uniform.i_mouse.w = common_uniform.i_mouse.w.abs();\n            } else {\n                common_uniform.i_mouse.z = -common_uniform.i_mouse.z.abs();\n                common_uniform.i_mouse.w = -common_uniform.i_mouse.w.abs();\n            }\n        }\n    }\n\n    // update time\n    common_uniform.i_time = time.seconds_since_startup() as f32;\n    common_uniform.i_time_delta = time.delta_seconds() as f32;\n    frames_accum.time_since_reset += time.delta_seconds();\n    frames_accum.number_of_frames += 1;\n    let fps_refresh_time = 0.5; // seconds\n\n    if frames_accum.time_since_reset > fps_refresh_time {\n        common_uniform.i_sample_rate =\n            frames_accum.number_of_frames as f32 / frames_accum.time_since_reset;\n        frames_accum.time_since_reset = 0.0;\n        frames_accum.number_of_frames = 0;\n    }\n\n    common_uniform.i_frame += 1.0;\n}\n\npub struct ShadertoyPlugin;\n\n#[derive(Clone, ExtractResource)]\npub struct ShaderHandles {\n    pub image_shader: Handle<Shader>,\n    pub texture_a_shader: Handle<Shader>,\n    pub texture_b_shader: Handle<Shader>,\n    pub texture_c_shader: Handle<Shader>,\n    pub texture_d_shader: Handle<Shader>,\n}\n\nimpl Plugin for ShadertoyPlugin {\n    fn build(&self, app: &mut App) {\n        app.add_plugin(ExtractResourcePlugin::<ExtractedUniform>::default())\n            .add_plugin(ExtractResourcePlugin::<TextureA>::default())\n            .add_plugin(ExtractResourcePlugin::<TextureB>::default())\n            .add_plugin(ExtractResourcePlugin::<TextureC>::default())\n            .add_plugin(ExtractResourcePlugin::<TextureD>::default())\n            .add_plugin(ExtractResourcePlugin::<MainImage>::default())\n            .add_plugin(ExtractResourcePlugin::<ChangedWindowSize>::default())\n            .add_plugin(ExtractResourcePlugin::<ShadertoyResources>::default())\n            .add_plugin(ExtractResourcePlugin::<ShadertoyTextures>::default())\n            .add_plugin(ExtractResourcePlugin::<ShaderHandles>::default())\n            .add_plugin(ExtractResourcePlugin::<ShadertoyCanvas>::default())\n            .add_startup_system(setup)\n            .add_system(update_common_uniform)\n            .insert_resource(ShadertoyResources {\n                number_of_frames: 0,\n                time_since_reset: 0.0,\n                include_debugger: false,\n            });\n\n        let render_app = app.sub_app_mut(RenderApp);\n\n        let render_device = render_app.world.resource::<RenderDevice>();\n\n        let buffer = render_device.create_buffer(&BufferDescriptor {\n            label: Some(\"common uniform buffer\"),\n            size: std::mem::size_of::<f32>() as u64 * 25,\n            usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,\n            mapped_at_creation: false,\n        });\n\n        render_app\n            .insert_resource(ScheduleRunnerSettings::run_loop(Duration::from_secs_f64(\n                1.0 / 120.0,\n            )))\n            .insert_resource(CommonUniformMeta {\n                buffer: buffer.clone(),\n            })\n            .add_system_to_stage(RenderStage::Prepare, prepare_common_uniform)\n            .init_resource::<ShadertoyPipelines>()\n            // .add_system_to_stage(RenderStage::Extract, extract_stuff_here)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group)\n            // .init_resource::<TextureAPipeline>()\n            // .add_system_to_stage(RenderStage::Extract, extract_texture_a)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group_a)\n            // .init_resource::<TextureBPipeline>()\n            // .add_system_to_stage(RenderStage::Extract, extract_texture_b)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group_b)\n            // .init_resource::<TextureCPipeline>()\n            // .add_system_to_stage(RenderStage::Extract, extract_texture_c)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group_c)\n            // .init_resource::<TextureDPipeline>()\n            // .add_system_to_stage(RenderStage::Extract, extract_texture_d)\n            .add_system_to_stage(RenderStage::Queue, queue_bind_group_d);\n\n        let mut render_graph = render_app.world.resource_mut::<RenderGraph>();\n\n        render_graph.add_node(\"main_image\", MainNode::default());\n        render_graph.add_node(\"texture_a\", TextureANode::default());\n        render_graph.add_node(\"texture_b\", TextureBNode::default());\n        render_graph.add_node(\"texture_c\", TextureCNode::default());\n        render_graph.add_node(\"texture_d\", TextureDNode::default());\n\n        render_graph\n            .add_node_edge(\"texture_a\", \"texture_b\")\n            .unwrap();\n\n        render_graph\n            .add_node_edge(\"texture_b\", \"texture_c\")\n            .unwrap();\n\n        render_graph\n            .add_node_edge(\"texture_c\", \"texture_d\")\n            .unwrap();\n\n        render_graph\n            .add_node_edge(\"texture_d\", \"main_image\")\n            .unwrap();\n\n        render_graph\n            .add_node_edge(\"main_image\", bevy::render::main_graph::node::CAMERA_DRIVER)\n            .unwrap();\n    }\n}\n\n// pub struct ShadertoyPipelines {\n//     main_image_group_layout: BindGroupLayout,\n// }\n\npub struct ShadertoyPipelines {\n    pub main_image_group_layout: BindGroupLayout,\n    pub abcd_group_layout: BindGroupLayout,\n}\n\nimpl ShadertoyPipelines {\n    pub fn make_texture_layout(binding: u32) -> BindGroupLayoutEntry {\n        BindGroupLayoutEntry {\n            binding,\n            visibility: ShaderStages::COMPUTE,\n            ty: BindingType::StorageTexture {\n                access: StorageTextureAccess::ReadWrite,\n                format: TextureFormat::Rgba32Float,\n                view_dimension: TextureViewDimension::D2,\n            },\n            count: None,\n        }\n    }\n\n    pub fn new(render_device: &RenderDevice) -> Self {\n        let uniform_descriptor = BindGroupLayoutEntry {\n            binding: 0,\n            visibility: ShaderStages::COMPUTE,\n            ty: BindingType::Buffer {\n                ty: BufferBindingType::Uniform,\n                has_dynamic_offset: false,\n                min_binding_size: BufferSize::new(std::mem::size_of::<f32>() as u64 * 25),\n            },\n            count: None,\n        };\n\n        let abcd_group_layout =\n            render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {\n                label: Some(\"abcd_layout\"),\n                entries: &[\n                    uniform_descriptor,\n                    ShadertoyPipelines::make_texture_layout(1),\n                    ShadertoyPipelines::make_texture_layout(2),\n                    ShadertoyPipelines::make_texture_layout(3),\n                    ShadertoyPipelines::make_texture_layout(4),\n                ],\n            });\n\n        let main_image_group_layout =\n            render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {\n                label: Some(\"main_layout\"),\n                entries: &[\n                    uniform_descriptor,\n                    ShadertoyPipelines::make_texture_layout(1),\n                    ShadertoyPipelines::make_texture_layout(2),\n                    ShadertoyPipelines::make_texture_layout(3),\n                    ShadertoyPipelines::make_texture_layout(4),\n                    BindGroupLayoutEntry {\n                        binding: 5,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::StorageTexture {\n                            access: StorageTextureAccess::ReadWrite,\n                            format: TextureFormat::Rgba32Float,\n                            view_dimension: TextureViewDimension::D2,\n                        },\n                        count: None,\n                    },\n                    // font texture\n                    BindGroupLayoutEntry {\n                        binding: 6,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Texture {\n                            sample_type: TextureSampleType::Float { filterable: true },\n                            view_dimension: TextureViewDimension::D2,\n                            multisampled: false,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 7,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Sampler(SamplerBindingType::Filtering),\n                        count: None,\n                    },\n                    // noise texture\n                    BindGroupLayoutEntry {\n                        binding: 8,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Texture {\n                            sample_type: TextureSampleType::Float { filterable: true },\n                            view_dimension: TextureViewDimension::D2,\n                            multisampled: false,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 9,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Sampler(SamplerBindingType::Filtering),\n                        count: None,\n                    },\n                    // blue noise texture\n                    BindGroupLayoutEntry {\n                        binding: 10,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Texture {\n                            sample_type: TextureSampleType::Float { filterable: true },\n                            view_dimension: TextureViewDimension::D2,\n                            multisampled: false,\n                        },\n                        count: None,\n                    },\n                    BindGroupLayoutEntry {\n                        binding: 11,\n                        visibility: ShaderStages::COMPUTE,\n                        ty: BindingType::Sampler(SamplerBindingType::Filtering),\n                        count: None,\n                    },\n                ],\n            });\n\n        ShadertoyPipelines {\n            main_image_group_layout,\n            abcd_group_layout,\n        }\n    }\n}\n\nimpl FromWorld for ShadertoyPipelines {\n    fn from_world(world: &mut World) -> Self {\n        let render_device = world.resource::<RenderDevice>();\n        ShadertoyPipelines::new(render_device)\n    }\n}\n\n// impl FromWorld for ShadertoyPipelines {\n//     fn from_world(world: &mut World) -> Self {\n//         let main_image_group_layout =\n//             world\n//                 .resource::<RenderDevice>()\n//                 .create_bind_group_layout(&BindGroupLayoutDescriptor {\n//                     label: Some(\"main_layout\"),\n//                     entries: &[\n//                         BindGroupLayoutEntry {\n//                             binding: 0,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::Buffer {\n//                                 ty: BufferBindingType::Uniform,\n//                                 has_dynamic_offset: false,\n//                                 min_binding_size: BufferSize::new(\n//                                     CommonUniform::std140_size_static() as u64,\n//                                 ),\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 1,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 2,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 3,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 4,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 5,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                         // BindGroupLayoutEntry {\n//                         //     binding: 6,\n//                         //     visibility: ShaderStages::COMPUTE,\n//                         //     ty: BindingType::StorageTexture {\n//                         //         access: StorageTextureAccess::ReadWrite,\n//                         //         format: TextureFormat::Rgba32Float,\n//                         //         view_dimension: TextureViewDimension::D2,\n//                         //     },\n//                         //     count: None,\n//                         // },\n//                         BindGroupLayoutEntry {\n//                             binding: 6,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::Texture {\n//                                 sample_type: TextureSampleType::Float { filterable: true },\n//                                 view_dimension: TextureViewDimension::D2,\n//                                 multisampled: false,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 7,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::Sampler(SamplerBindingType::Filtering),\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 8,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::Texture {\n//                                 sample_type: TextureSampleType::Float { filterable: true },\n//                                 view_dimension: TextureViewDimension::D2,\n//                                 multisampled: false,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 9,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::Sampler(SamplerBindingType::Filtering),\n//                             count: None,\n//                         },\n//                     ],\n//                 });\n\n//         ShadertoyPipelines {\n//             main_image_group_layout,\n//         }\n//     }\n// }\n\n#[derive(Deref, Clone, ExtractResource)]\nstruct MainImage(Handle<Image>);\n\n// use bevy::core::cast_slice;\n\nstruct MainImageBindGroup {\n    main_image_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n// write the extracted common uniform into the corresponding uniform buffer\npub fn prepare_common_uniform(\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n    render_queue: Res<RenderQueue>,\n    mut extrated_common_uniform_crevice: ResMut<ExtractedUniform>,\n    // mut extracted_uniform: ResMut<ExtractedUniform>,\n    render_device: Res<RenderDevice>,\n    mut pipelines: ResMut<ShadertoyPipelines>,\n) {\n    // // use bevy::render::render_resource::std140::Std140;\n    let std140_common_uniform = extrated_common_uniform_crevice.0.as_std140();\n    let bytes = std140_common_uniform.as_bytes();\n\n    // let mut uni = extracted_uniform.0;\n    // let blah = uni.write_into::<Buffer>(*common_uniform_meta.buffer);\n    // let as_bytes = bevy::core::cast_slice([uni.clone()]);\n\n    // let as_bytes = &uni.0.to_owned().\n\n    // TODO: HOW TO ACTUALLY SERIALIZE THE UNIFORM\n    render_queue.write_buffer(\n        &common_uniform_meta.buffer,\n        0,\n        bytes,\n        // as_bytes,\n        // bytemuck::cast_slice(as_bytes),\n        // bevy::core::cast_slice(&bytes),\n    );\n\n    // TODO: DO THIS IN THE EXTRACT PHASE?\n    // modify the pipelines according to the new window size if applicable\n    if extrated_common_uniform_crevice.changed_window_size > 0.5 {\n        *pipelines = ShadertoyPipelines::new(&render_device);\n    }\n}\n\n#[derive(Deref, Clone, ExtractResource)]\npub struct ChangedWindowSize(pub bool);\n\nfn extract_stuff_here(\n    // mut world: &mut MainWorld,\n    mut commands: Commands,\n    image: Res<MainImage>,\n    font_image: ResMut<ShadertoyTextures>,\n    // common_uniform: Res<CommonUniform>,\n    all_shader_handles: Res<ShaderHandles>,\n    canvas_size: Res<ShadertoyCanvas>,\n    mut window_resize_event: EventReader<WindowResized>,\n    // texture_a_image: Res<TextureA>,\n    // texture_b_image: Res<TextureB>,\n    // texture_c_image: Res<TextureC>,\n    // texture_d_image: Res<TextureD>,\n) {\n    // // insert common uniform only once\n    // // commands.insert_resource(common_uniform.clone());\n\n    // // commands.insert_resource(MainImage(image.clone()));\n\n    //     // commands.insert_resource(texture_a_image.clone());\n    // // commands.insert_resource(texture_b_image.clone());\n    // // commands.insert_resource(texture_c_image.clone());\n    // // commands.insert_resource(texture_d_image.clone());\n\n    commands.insert_resource(font_image.clone());\n\n    commands.insert_resource(all_shader_handles.clone());\n\n    let mut changed_window_size = false;\n    commands.insert_resource(canvas_size.clone());\n\n    for _ in window_resize_event.iter() {\n        changed_window_size = true;\n    }\n\n    commands.insert_resource(ChangedWindowSize(changed_window_size));\n\n    // world.insert_resource(font_image.clone());\n\n    // world.insert_resource(all_shader_handles.clone());\n\n    // let mut changed_window_size = false;\n    // world.insert_resource(canvas_size.clone());\n\n    // for _ in window_resize_event.iter() {\n    //     changed_window_size = true;\n    // }\n\n    // world.insert_resource(ChangedWindowSize(changed_window_size));\n}\n\nfn queue_bind_group(\n    mut commands: Commands,\n    pipeline: Res<ShadertoyPipelines>,\n\n    gpu_images: Res<RenderAssets<Image>>,\n    shadertoy_textures: Res<ShadertoyTextures>,\n    main_image: Res<MainImage>,\n    texture_a_image: Res<TextureA>,\n    texture_b_image: Res<TextureB>,\n    texture_c_image: Res<TextureC>,\n    texture_d_image: Res<TextureD>,\n    // textures: Res<ExtractedTextures>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    all_shader_handles: Res<ShaderHandles>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n    mut changed_size_res: ResMut<ChangedWindowSize>,\n    mut render_graph: ResMut<RenderGraph>,\n) {\n    if changed_size_res.0 {\n        let main_node: &mut MainNode = render_graph\n            .get_node_mut(NodeLabel::Name(Cow::from(\"main_image\")))\n            .unwrap();\n        main_node.state = ShadertoyState::Loading;\n\n        let texture_a_node: &mut TextureANode = render_graph\n            .get_node_mut(NodeLabel::Name(Cow::from(\"texture_a\")))\n            .unwrap();\n        texture_a_node.state = ShadertoyState::Loading;\n\n        let texture_b_node: &mut TextureBNode = render_graph\n            .get_node_mut(NodeLabel::Name(Cow::from(\"texture_b\")))\n            .unwrap();\n        texture_b_node.state = ShadertoyState::Loading;\n\n        let texture_c_node: &mut TextureCNode = render_graph\n            .get_node_mut(NodeLabel::Name(Cow::from(\"texture_c\")))\n            .unwrap();\n        texture_c_node.state = ShadertoyState::Loading;\n\n        let texture_d_node: &mut TextureDNode = render_graph\n            .get_node_mut(NodeLabel::Name(Cow::from(\"texture_d\")))\n            .unwrap();\n        texture_d_node.state = ShadertoyState::Loading;\n    }\n\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.main_image_group_layout.clone()]),\n        shader: all_shader_handles.image_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.main_image_group_layout.clone()]),\n        shader: all_shader_handles.image_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let main_view = &gpu_images[&main_image.0];\n    let font_view = &gpu_images[&shadertoy_textures.font_texture_handle];\n    let rgba_noise_256_view = &gpu_images[&shadertoy_textures.rgba_noise_256_handle];\n    let blue_noise_view = &gpu_images[&shadertoy_textures.blue_noise_handle];\n\n    let texture_a_view = &gpu_images[&texture_a_image.0];\n    let texture_b_view = &gpu_images[&texture_b_image.0];\n    let texture_c_view = &gpu_images[&texture_c_image.0];\n    let texture_d_view = &gpu_images[&texture_d_image.0];\n\n    // let texture_a_view = &gpu_images[&textures.a.0];\n    // let texture_b_view = &gpu_images[&textures.b.0];\n    // let texture_c_view = &gpu_images[&textures.c.0];\n    // let texture_d_view = &gpu_images[&textures.d.0];\n\n    let main_image_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: Some(\"main_bind_group\"),\n        layout: &pipeline.main_image_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&texture_a_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&texture_b_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&texture_c_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 4,\n                resource: BindingResource::TextureView(&texture_d_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 5,\n                resource: BindingResource::TextureView(&main_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 6,\n                resource: BindingResource::TextureView(&font_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 7,\n                resource: BindingResource::Sampler(&font_view.sampler),\n            },\n            BindGroupEntry {\n                binding: 8,\n                resource: BindingResource::TextureView(&rgba_noise_256_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 9,\n                resource: BindingResource::Sampler(&rgba_noise_256_view.sampler),\n            },\n            BindGroupEntry {\n                binding: 10,\n                resource: BindingResource::TextureView(&blue_noise_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 11,\n                resource: BindingResource::Sampler(&blue_noise_view.sampler),\n            },\n        ],\n    });\n\n    commands.insert_resource(MainImageBindGroup {\n        main_image_bind_group,\n        init_pipeline: init_pipeline.clone(),\n        update_pipeline: update_pipeline.clone(),\n    });\n}\n\npub enum ShadertoyState {\n    Loading,\n    Init,\n    Update,\n}\n\npub struct MainNode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for MainNode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for MainNode {\n    fn update(&mut self, world: &mut World) {\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let bind_group = world.resource::<MainImageBindGroup>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<MainImageBindGroup>();\n        let canvas_size = world.resource::<ShadertoyCanvas>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor {\n                label: Some(\"main_compute_pass\"),\n            });\n\n        pass.set_bind_group(0, &bind_group.main_image_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/templates/buffer_a_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n{{COMMON}}\n\n{{CODE_BLOCK}}"
  },
  {
    "path": "src/templates/buffer_b_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n{{COMMON}}\n\n{{CODE_BLOCK}}"
  },
  {
    "path": "src/templates/buffer_c_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n{{COMMON}}\n\n{{CODE_BLOCK}}"
  },
  {
    "path": "src/templates/buffer_d_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n{{COMMON}}\n\n{{CODE_BLOCK}}\n"
  },
  {
    "path": "src/templates/common.wgsl",
    "content": ""
  },
  {
    "path": "src/templates/common_prelude.wgsl",
    "content": "struct CommonUniform {\n    iResolution: vec2<f32>,\n    changed_window_size: f32,\n    padding0: f32,\n    \n    iTime: f32,\n    iTimeDelta: f32,\n    iFrame: f32,\n    iSampleRate: f32,\n    \n    iMouse: vec4<f32>,\n    \n\n    iChannelTime: vec4<f32>,\n    iChannelResolution: vec4<f32>,\n    iDate: vec4<f32>,\n};\n\n\n@group(0) @binding(0)\nvar<uniform> uni: CommonUniform;\n\n@group(0) @binding(1)\nvar buffer_a: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(2)\nvar buffer_b: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(3)\nvar buffer_c: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(4)\nvar buffer_d: texture_storage_2d<rgba32float, read_write>;\n\n"
  },
  {
    "path": "src/templates/debugger.wgsl",
    "content": "// Why are the charaacters so pixelated? \n// One possible reason is that we are in a compute shader and the textures are not\n// filtered.\n\nlet backColorDebug: vec3<f32> = vec3<f32>(0.2, 0.2, 0.2);\n\n\nvar<private> uv_debug: vec2<f32> ;\nvar<private> tp_debug: vec2<f32> ;\nvar<private> align_debug: vec4<f32>; // north, east, south, west\nvar<private> font_size_debug: f32;\nvar<private> dotColor_debug: vec3<f32> = vec3<f32>(0.5, 0.5, 0.);\nvar<private> drawColorDebug: vec3<f32> = vec3<f32>(1., 1., 0.);\nvar<private> vColor: vec3<f32> = backColorDebug;\nvar<private> aspect_debug: f32 = 1.;\nvar<private> pixelPosDebug: vec2<f32> = vec2<f32>(0., 0.);\n\nlet FONT_SPACE_DEBUG: f32 = 0.5;\nlet headColorDebug: vec3<f32> = vec3<f32>(0.9, 0.6, 0.2);\nlet mpColorDebug: vec3<f32> = vec3<f32>(0.99, 0.99, 0.);\nlet mxColorDebug: vec3<f32> = vec3<f32>(1., 0., 0.);\nlet myColorDebug: vec3<f32> = vec3<f32>(0., 1., 0.);\nlet font_png_size_debug: vec2<f32> = vec2<f32>(1023.0, 1023.0);\n\nfn chara(ch: i32) -> f32 {\n\n    let fr = fract(floor(vec2<f32>(f32(ch), 15.999 - f32(ch) / 16.)) / 16.);\n\tlet q = clamp(tp_debug, vec2<f32>(0.), vec2<f32>(1.)) / 16. + fr ;\n\tlet inverted_q = vec2<f32>(q.x, 1. - q.y);\n\n\t// // There is aliasing on the charaacters\n\t// let f = textureSampleGrad(font_texture,\n    //                  font_texture_sampler,\n    //                  inverted_q,\n    //                   vec2<f32>(1.0, 0.0),\n    //                  vec2<f32>(0.0, 1.0));\n\n\t// using textureLoad without sampler\n    let q1 = vec2<i32>(font_png_size_debug  * q );\n\tlet y_inverted_q1 = vec2<i32>(q1.x, i32(font_png_size_debug.y) - q1.y);\n\n\tvar f: vec4<f32> = textureLoad(font_texture, y_inverted_q1 , 0);\n\n\t// smoothing out the aliasing\n\tlet dx = vec2<i32>(1, 0);\n\tlet dy = vec2<i32>(0, 1);\n\n\tlet fx1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dx, 0);\n\tlet fx2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dx, 0);\n\tlet fy1: vec4<f32> = textureLoad(font_texture, y_inverted_q1 + dy, 0);\n\tlet fy2: vec4<f32> = textureLoad(font_texture, y_inverted_q1 - dy, 0);\n\n\tlet rp = 0.25;\n\tf = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ;\n\n\treturn f.x * (f.y + 0.3) * (f.z + 0.3) * 2.;\n} \n\nfn SetTextPosition(x: f32, y: f32)  {\n\ttp_debug =  10. * uv_debug;\n\ttp_debug.x = tp_debug.x + 17. - x;\n\ttp_debug.y = tp_debug.y - 9.4 + y;\n} \n\nfn SetTextPositionAbs(x: f32, y: f32)  {\n\ttp_debug.x = 10. * uv_debug.x - x;\n\ttp_debug.y = 10. * uv_debug.y - y;\n} \n\nfn drawFract(value: ptr<function, f32>, digits:  ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\t*value = fract(*value) * 10.;\n\n\tfor (var ni: i32 = 1; ni < 60; ni = ni + 1) {\n\t\tc = c + (chara(48 + i32(*value)));\n\t\ttp_debug.x = tp_debug.x - (0.5);\n\t\t*digits = *digits - (1);\n\t\t*value = fract(*value) * 10.;\n\n\t\tif (*digits <= 0 || *value == 0.) {\t\t\n            break;\n        }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(*digits));\n\treturn c;\n} \n\nfn maxInt(a: i32, b: i32) -> i32 {\n    var ret: i32;\n    if (a > b) { ret = a; } else { ret = b; };\n\treturn ret;\n} \n\nfn drawInt(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\tc = c + (chara(45));\n\t\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = 1; ni < 11; ni = ni + 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (chara(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni >= digits) {\t\tbreak; }\n\t}\n\n\ttp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\treturn c;\n} \n\nfn drawIntBackwards(value: ptr<function, i32>,  minDigits: ptr<function, i32>) -> f32 {\n\tvar c: f32 = 0.;\n\tlet original_value: i32 = *value;\n\n\tif (*value < 0) {\n\t\t*value = -*value;\n\t\tif (*minDigits < 1) {\t\t\n\t\t\t*minDigits = 1;\n\t\t} else { \n\t\t\t*minDigits = *minDigits - 1;\n\t\t}\n\t\t// tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\t// c = c + (chara(45));\n\t\t\n\n\t}\n\tvar fn2: i32 = *value;\n\tvar digits: i32 = 1;\n\n\tfor (var ni: i32 = 0; ni < 10; ni = ni + 1) {\n\t\tfn2 = fn2 / (10);\n\t\tif (fn2 == 0) {\t\tbreak; }\n\t\tdigits = digits + 1;\n\t}\n\n\tdigits = maxInt(*minDigits, digits);\n\t// tp_debug.x = tp_debug.x - (0.5 * f32(digits));\n\n\tfor (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) {\n\t\ttp_debug.x = tp_debug.x + (0.5);\n\t\tc = c + (chara(48 + *value % 10));\n\t\t*value = *value / (10);\n\t\tif (ni == 0) {\t\tbreak; }\n\t}\n\n\tif (original_value < 0) {\n\t\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\t\tc = c + (chara(45));\n\t}\n\n\t// tp_debug.x = tp_debug.x + (0.5 * f32(digits));\n\treturn c;\n} \n\n// fn drawFloat(value: ptr<function, f32>, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\nfn drawFloat(val: f32, prec: ptr<function, i32>, maxDigits: i32) -> f32 {\n\t// in case of 0.099999..., round up to 0.1000000\n\tvar value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits));\n\n\tlet tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits);\n\tvar c: f32 = 0.;\n\tif (value < 0.) {\n\t\tc = chara(45);\n\t\tvalue = -value;\n\t}\n\ttp_debug.x = tp_debug.x - (0.5);\n    var ival = i32(value);\n\n    var one: i32 = 1;\n\n\tc = c + (drawInt(&ival, &one));\n\tc = c + (chara(46));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n    var frac_val = fract(value);\n\tc = c + (drawFract(&frac_val, prec));\n\ttp_debug.x = min(tp_debug.x, tp_debugx);\n\n\treturn c;\n}\n\nfn drawFloat_f32(value:  f32) -> f32 {\n    var two: i32 = 2;\n\treturn drawFloat(value, &two, 5);\n} \n\nfn drawFloat_f32_prec(value: f32, prec: ptr<function, i32>) -> f32 {\n\treturn drawFloat(value, prec, 2);\n} \n\nfn drawInt_i32_back(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawIntBackwards(value, &one);\n} \n\nfn drawInt_i32(value: ptr<function, i32>) -> f32 {\n    var one: i32 = 1;\n\treturn drawInt(value, &one);\n} \n\n\n\n\n\nfn SetColor(red: f32, green: f32, blue: f32)  {\n\tdrawColorDebug = vec3<f32>(red, green, blue);\n} \n\nfn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr<function, i32>)  {\n\n\t// vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces));\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteFloatBox(\n\tfValue: f32, \n\tmaxDigits: i32, \n\tdecimalPlaces: i32, \n\talpha: f32\n)  {\n\tvar decs = decimalPlaces;\n\tvColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha);\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n;\n} \n\nfn WriteInteger(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32(iValue));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n} \n\nfn WriteIntegerBack(iValue: ptr<function, i32>)  {\n\tvColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue));\n\ttp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG);\n\n} \n\n\n\nfn WriteFPS()  {\n\tvar fps: f32 = f32(uni.iSampleRate);\n\tSetColor(0.8, 0.6, 0.3);\n\tvar max_digits_one = 1;\n\tWriteFloat(fps, 5, &max_digits_one);\n\tvar c: f32 = 0.;\n\tc = c + (chara(102));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (chara(112));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\n\tc = c + (chara(115));\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\t// let c2 = smoothstep(0.0, 1.0, c );\n\n\tvColor = mix(vColor, drawColorDebug, c);\n} \n\nfn WriteMousePos(mPos: vec2<f32>, y_pos: f32)  {\n\tlet digits: i32 = 3;\n\tlet radius: f32 =  uni.iResolution.x / 400.;\n\tif (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; }\n\tlet r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius;\n\t// vColor = vColor + (mix(vec3<f32>(0.), dotColor_debug, 1. - clamp(r, 0., 1.)));\n\n\tvar max_digits_three: i32 = 3;\n\tvar mposxi: i32 = i32(mPos.x);\n\tvar mposyi: i32 = i32(mPos.y);\n\n\tvar mposx: f32 = (mPos.x);\n\tvar mposy: f32 = (mPos.y);\n\n\n\tlet x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG;\n\t\t\n\tSetTextPositionAbs(\n\t\t x_pos,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = myColorDebug;\n\tWriteIntegerBack(&mposyi);\n\n\tSetTextPositionAbs(\n\t\t x_pos - 7. *  FONT_SPACE_DEBUG,\n\t\t y_pos,\n\t);\n\n\tdrawColorDebug = mxColorDebug;\n\n\tWriteIntegerBack(&mposxi);\n\n} \n\n\nfn sdRoundedBox(p: vec2<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {\n  var x = r.x;\n  var y = r.y;\n  x = select(r.z, r.x, p.x > 0.);\n  y = select(r.w, r.y, p.x > 0.);\n  x  = select(y, x, p.y > 0.);\n  let q = abs(p) - b + x;\n  return min(max(q.x, q.y), 0.) + length(max(q, vec2<f32>(0.))) - x;\n}\n\n\n\nfn WriteRGBAValues(\n\tlocation: vec2<i32>, \n\tvalue: vec4<f32>, \n\tscreen_poz: vec2<f32>,\n\talpha: f32,\n )  {\n\tlet poz = screen_poz / uni.iResolution * 20. * vec2<f32>(aspect_debug, 1.0);\n\tlet window_ajusted = uni.iResolution / vec2<f32>(960., 600.);\n\n\tlet box_pos = vec2<f32>(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.;\n\t// let box_pos = mp;\n\n\t// // box location follows mouse position\n\t// let box_location = vec2<f32>(\n\t// \tuni.iMouse.x + 100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t// \tuni.iMouse.y - 48. * window_ajusted.y\n\t// );\n\n\n\tlet box_location  = vec2<f32>(\n\t\t100. * window_ajusted.x /  ( aspect_debug / 1.6 ) , \n\t\tuni.iResolution.y - 60. * window_ajusted.y,\n\t);\n\t\n\tlet inverted_screen_poz = vec2<f32>(screen_poz.x,  -screen_poz.y) ; // / vec2<f32>(aspect_debug, 1.) ;\n\n\tlet d_box = sdRoundedBox(\n\t\t vec2<f32>(location) - box_location - inverted_screen_poz, \n\t\t vec2<f32>(73. /  ( aspect_debug / 1.6 ), 75.) * window_ajusted, \n\t\tvec4<f32>(5.,5.,5.,5.)  * 5.0 \n\t);\n\n\t// let alpha = 0.225;\n\tlet decimal_places = 3;\n\tSetColor(1., 1., 1.);\n\tvar c: f32 = 0.;\n\tlet lspace = 0.8;\n\n\tlet bg_color = vec3<f32>(.8, .7, .9);\n\tvColor = mix( vColor, bg_color,  (1.0 -  step(0.0, d_box)) * alpha ); \n\n\t// red\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1.) - 0.0 + poz.y\n\t) ;\n\tc = c + (chara(114)); // r\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (chara(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.r, 3, decimal_places, alpha );\n\n\t// green\n\tSetTextPosition(\n\t\t10. *  ((box_pos.x +1. + lspace)) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 1.0 + poz.y,\n\t) ;\n\tc = c + (chara(103)); // g\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (chara(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.g, 3, decimal_places, alpha );\n\n\t// blue\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 2.0 + poz.y,\n\t\t) ;\n\tc = c + (chara(98)); // b\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (chara(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.b, 4, decimal_places, alpha );\n\n\t// alpha\n\tSetTextPosition(\n\t\t10. *  (box_pos.x +1. + lspace) + poz.x, \n\t\t10. * (-box_pos.y +1. ) + 3.0 + poz.y,\n\t) ;\n\tc = c + (chara(97)); // a\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tc = c + (chara(58)); // colon\n\ttp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG);\n\tWriteFloatBox(value.a, 4, decimal_places, alpha );\n\n\tvColor = mix(vColor, drawColorDebug, c * alpha);\n}\n\nfn sdSegment(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>) -> f32 {\n    let pa = p - a;\n    let ba = b - a;\n    let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.);\n    return length(pa - ba * h);\n}\n\nfn ring(pos: vec2<f32>, radius: f32, thick: f32) -> f32 {\n\treturn mix(1., 0., smoothstep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius)));\n} \n\nfn sdCircle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {\n    let d = length(p - c);\n    return d - r;\n}\n\nfn draw_ring(location: vec2<i32>) {\n\tlet mouse_click_poz = vec2<f32>(abs(uni.iMouse.z) , abs(uni.iMouse.w));\n\n\tlet alpha = 0.75;\n\tlet ring_dist = sdCircle(vec2<f32>(location) , mouse_click_poz, 2.3);\n\tlet d = smoothstep(0.5, 1.5, abs(ring_dist - 1.));\n\tvColor = mix(vColor, headColorDebug,   (1. - d) * alpha );\n}\n\nfn draw_crossair(location: vec2<i32>)  {\n\n\tlet start = 5.0;\n\tlet end = 20.;\n\tlet segment1 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(start, 0.), \n\t\tvec2<f32>(end, 0.)\n\t);\n\n\tlet segment2 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(-start, 0.), \n\t\tvec2<f32>(-end, 0.)\n\t);\n\n\tlet segment3 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., start), \n\t\tvec2<f32>(0., end)\n\t);\n\n\tlet segment4 = sdSegment(\n\t\tvec2<f32>(location) - uni.iMouse.xy, \n\t\tvec2<f32>(0., -start), \n\t\tvec2<f32>(0., -end)\n\t);\n\n\tvar alpha = 0.75;\n\tif (uni.iMouse.z > 0.) {\n\t\talpha = 1.0;\n\t}\n\n\tlet d = smoothstep(0.5, 1.5, segment1);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothstep(0.5, 1.5, segment2);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothstep(0.5, 1.5, segment3);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n\n\tlet d = smoothstep(0.5, 1.5, segment4);\n\tvColor = mix(vColor, headColorDebug, (1.0 -  d) * alpha );\n}\n\nfn show_debug_info(location: vec2<i32>, color: vec3<f32>) -> vec4<f32> {    \n\tvar fragCoord = vec2<f32>(f32(location.x), f32(location.y) );\n    vColor = color;\n\n\n\taspect_debug =  uni.iResolution.x /  uni.iResolution.y;\n\n\tlet ratio: vec2<f32> = vec2<f32>(aspect_debug, 1.);\n\tpixelPosDebug = fragCoord.xy;\n\t// mousePosDebug = uni.iMouse.xy;\n\tuv_debug = (2. * fragCoord.xy /  uni.iResolution.xy - 1.) * ratio;\n\n\talign_debug = 10. * vec4<f32>(\n\t\t1.,      // North\n\t\taspect_debug,  // East\n\t\t-1.,     // South\n\t\t-aspect_debug, // West\n\t);\n\n\n\tWriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position\n\tWriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position\n\n\tvar c: f32 = 0.;\n\n\tSetTextPositionAbs(\n\t\t align_debug.y -      FONT_SPACE_DEBUG,\n\t\t align_debug.x - 2. * FONT_SPACE_DEBUG,\n\t);\n\n\tSetColor(0.8, 0.8, 0.8);\n\tvar resx = i32(uni.iResolution.x);\n\tvar resy = i32(uni.iResolution.y);\n\n\n\tWriteIntegerBack(&resx);\n\tc = c + (chara(28));\n\ttp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG);\n\tWriteIntegerBack(&resy);\n\n\n\tSetTextPositionAbs(\n\t\t align_debug.w - 1. * FONT_SPACE_DEBUG,\n\t\t align_debug.z - 0. * FONT_SPACE_DEBUG,\n\t);\n\n\tWriteFPS();\n\tSetColor(0.9, 0.7, 0.8);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\tlet poz = vec2<f32>(0., uni.iResolution.y / 2.);\n\t\n\t// // RGBA probe labels follow mouse\n\t// let poz = vec2<f32>(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y);\n\t\n\tlet inverted_y_mouse_location = vec2<i32>(vec2<f32>(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y));\n\tlet value: vec4<f32> = textureLoad(texture, inverted_y_mouse_location);\n\tWriteRGBAValues(location, value, poz, 0.85);\n\n\tlet inverted_y_mouseclick_location = vec2<i32>(vec2<f32>(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w)));\n\tlet value2: vec4<f32> = textureLoad(texture, inverted_y_mouseclick_location);\n\tWriteRGBAValues(location, value2, vec2<f32>(0.), 0.65);\n\n\tdraw_crossair(location);\n\n\tdraw_ring(location);\n\n\tlet fragColor = vec4<f32>(vColor, 1.);\n\n\t\n\n\treturn fragColor;\n} \n"
  },
  {
    "path": "src/templates/image.wgsl",
    "content": "fn hash(value: u32) -> u32 {\n    var state = value;\n    state = state ^ 2747636419u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    state = state ^ state >> 16u;\n    state = state * 2654435769u;\n    return state;\n}\nfn randomFloat(value: u32) -> f32 {\n    return f32(hash(value)) / 4294967295.0;\n}\n\n\n\n// fn get(location: vec2<i32>, offset_x: i32, offset_y: i32) -> i32 {\n//     let value: vec4<f32> = textureLoad(texture, location + vec2<i32>(offset_x, offset_y));\n//     return i32(value.x);\n// }\n\n// fn count_alive(location: vec2<i32>) -> i32 {\n//     return get(location, -1, -1) +\n//            get(location, -1,  0) +\n//            get(location, -1,  1) +\n//            get(location,  0, -1) +\n//            get(location,  0,  1) +\n//            get(location,  1, -1) +\n//            get(location,  1,  0) +\n//            get(location,  1,  1);\n// }\n\n[[stage(compute), workgroup_size(8, 8, 1)]]\nfn update([[builtin(global_invocation_id)]] invocation_id: vec3<u32>) {\n    let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));\n\n    // let n_alive = count_alive(location);\n    // let color = vec4<f32>(f32(n_alive) / 8.0);\n\n    // var alive: bool;\n    // if (n_alive == 3) {\n    //     alive = true;\n    // } else if (n_alive == 2) {\n    //     let currently_alive = get(location, 0, 0);\n    //     alive = bool(currently_alive);\n    // } else {\n    //     alive = false;\n    // }\n\n    var alive = true;\n\n    // let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    // if (value.x > 0.51) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_b, vec2<i32>(0,1));\n    // if (value.x > 0.74) {\n    //     alive = false;\n    // }\n\n    // let value: vec4<f32> = textureLoad(buffer_c, vec2<i32>(0,1));\n    // if (value.x > 0.61) {\n    //     alive = false;\n    // }\n\n    let value: vec4<f32> = textureLoad(buffer_a, vec2<i32>(0,1));\n    if (value.x > 0.79) {\n        alive = false;\n    }\n\n    // if (ga > 2) {\n    //     alive = true;\n    // }\n\n    // if (uni.iTime > 1.0) {\n    //     alive = false;\n    // }\n\n    // alive = false;\n\n    storageBarrier();\n\n    textureStore(texture, location, vec4<f32>(f32(alive)));\n}"
  },
  {
    "path": "src/templates/image_template.wgsl",
    "content": "{{COMMON_PRELUDE}}\n\n@group(0) @binding(5)\nvar texture: texture_storage_2d<rgba32float, read_write>;\n\n// [[group(0), binding(6)]]\n// var font_texture: texture_storage_2d<rgba32float, read_write>;\n\n@group(0) @binding(6)\nvar font_texture: texture_2d<f32>;\n\n@group(0) @binding(7)\nvar font_texture_sampler: sampler;\n\n@group(0) @binding(8)\nvar rgba_noise_256_texture: texture_2d<f32>;\n\n@group(0) @binding(9)\nvar rgba_noise_256_texture_sampler: sampler;\n\n@group(0) @binding(10)\nvar blue_noise_texture: texture_2d<f32>;\n\n@group(0) @binding(11)\nvar blue_noise_texture_sampler: sampler;\n\n\n{{DEBUGGER}}\n\n{{COMMON}}\n\n{{CODE_BLOCK}}"
  },
  {
    "path": "src/texture_a.rs",
    "content": "use bevy::{\n    prelude::*,\n    render::{\n        extract_resource::ExtractResource,\n        render_asset::RenderAssets,\n        render_graph::{self},\n        render_resource::*,\n        renderer::{RenderContext, RenderDevice},\n    },\n};\n\nuse std::borrow::Cow;\n\nuse crate::texture_b::TextureB;\nuse crate::texture_c::TextureC;\nuse crate::texture_d::TextureD;\nuse crate::{\n    CommonUniform, CommonUniformMeta, ShaderHandles, ShadertoyCanvas, ShadertoyPipelines,\n    ShadertoyState, WORKGROUP_SIZE,\n};\n\nstruct TextureABindGroup {\n    // texture_b_bind_group: BindGroup,\n    texture_a_bind_group: BindGroup,\n    // common_uniform_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n// pub struct CommonUniformMetaA {\n//     // buffer: UniformVec<CommonUniform>,\n//     pub buffer: Buffer,\n//     // bind_group: Option<BindGroup>,\n// }\n\n#[derive(Clone, Deref, ExtractResource)]\npub struct TextureA(pub Handle<Image>);\n\n// pub struct TextureAPipeline {\n//     texture_a_bind_group_layout: BindGroupLayout,\n// }\n\n// impl FromWorld for TextureAPipeline {\n//     fn from_world(world: &mut World) -> Self {\n//         let texture_a_bind_group_layout = world\n//             .resource::<RenderDevice>()\n//             .create_bind_group_layout(&BindGroupLayoutDescriptor {\n//                 label: Some(\"layout_a\"),\n//                 entries: &[\n//                     BindGroupLayoutEntry {\n//                         binding: 0,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::Buffer {\n//                             ty: BufferBindingType::Uniform,\n//                             has_dynamic_offset: false,\n//                             min_binding_size: BufferSize::new(\n//                                 CommonUniform::std140_size_static() as u64\n//                             ),\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 1,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 2,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 3,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 4,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                 ],\n//             });\n\n//         TextureAPipeline {\n//             texture_a_bind_group_layout,\n//         }\n//     }\n// }\n\n// pub fn extract_texture_a(mut commands: Commands, image: Res<TextureA>) {\n//     commands.insert_resource(TextureA(image.clone()));\n// }\n\npub fn queue_bind_group_a(\n    mut commands: Commands,\n    // pipeline: Res<TextureAPipeline>,\n    pipeline: Res<ShadertoyPipelines>,\n    gpu_images: Res<RenderAssets<Image>>,\n\n    texture_a: Res<TextureA>,\n    texture_b: Res<TextureB>,\n    texture_c: Res<TextureC>,\n    texture_d: Res<TextureD>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    all_shader_handles: Res<ShaderHandles>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.abcd_group_layout.clone()]),\n        shader: all_shader_handles.texture_a_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.abcd_group_layout.clone()]),\n        shader: all_shader_handles.texture_a_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    // let texture_a_view = &gpu_images[&texture_a.0];\n    let view_a = &gpu_images[&texture_a.0];\n    let view_b = &gpu_images[&texture_b.0];\n    let view_c = &gpu_images[&texture_c.0];\n    let view_d = &gpu_images[&texture_d.0];\n\n    let texture_a_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: Some(\"texture_a_bind_group\"),\n        layout: &pipeline.abcd_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&view_a.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&view_b.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&view_c.texture_view),\n            },\n            BindGroupEntry {\n                binding: 4,\n                resource: BindingResource::TextureView(&view_d.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(TextureABindGroup {\n        texture_a_bind_group,\n        init_pipeline,\n        update_pipeline,\n    });\n}\n\npub struct TextureANode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for TextureANode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for TextureANode {\n    fn update(&mut self, world: &mut World) {\n        let bind_group = world.resource::<TextureABindGroup>();\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<TextureABindGroup>();\n        let canvas_size = world.resource::<ShadertoyCanvas>();\n\n        let texture_a_bind_group = &bind_group.texture_a_bind_group;\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor::default());\n\n        pass.set_bind_group(0, texture_a_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/texture_b.rs",
    "content": "use bevy::{\n    prelude::*,\n    render::{\n        extract_resource::ExtractResource,\n        render_asset::RenderAssets,\n        render_graph::{self},\n        // render_resource::*,\n        render_resource::*,\n        renderer::{RenderContext, RenderDevice},\n    },\n};\n\nuse crate::texture_a::*;\nuse crate::texture_c::*;\nuse crate::texture_d::*;\n\nuse std::borrow::Cow;\n\nuse crate::{\n    CommonUniform, CommonUniformMeta, ShaderHandles, ShadertoyCanvas, ShadertoyPipelines,\n    ShadertoyState, WORKGROUP_SIZE,\n};\n\nstruct TextureBBindGroup {\n    texture_b_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n#[derive(Clone, Deref, ExtractResource)]\npub struct TextureB(pub Handle<Image>);\n\n// pub struct TextureBPipeline {\n//     texture_b_bind_group_layout: BindGroupLayout,\n// }\n\n// impl FromWorld for TextureBPipeline {\n//     fn from_world(world: &mut World) -> Self {\n//         let texture_b_bind_group_layout = world\n//             .resource::<RenderDevice>()\n//             .create_bind_group_layout(&BindGroupLayoutDescriptor {\n//                 label: Some(\"layout_b\"),\n//                 entries: &[\n//                     BindGroupLayoutEntry {\n//                         binding: 0,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::Buffer {\n//                             ty: BufferBindingType::Uniform,\n//                             has_dynamic_offset: false,\n//                             min_binding_size: BufferSize::new(\n//                                 CommonUniform::std140_size_static() as u64\n//                             ),\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 1,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 2,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 3,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 4,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                 ],\n//             });\n\n//         TextureBPipeline {\n//             texture_b_bind_group_layout,\n//         }\n//     }\n// }\n\n// pub fn extract_texture_b(mut commands: Commands, image: Res<TextureB>) {\n//     commands.insert_resource(TextureB(image.clone()));\n// }\n\npub fn queue_bind_group_b(\n    mut commands: Commands,\n    pipeline: Res<ShadertoyPipelines>,\n    gpu_images: Res<RenderAssets<Image>>,\n    texture_a_image: Res<TextureA>,\n    texture_b_image: Res<TextureB>,\n    texture_c_image: Res<TextureC>,\n    texture_d_image: Res<TextureD>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    all_shader_handles: Res<ShaderHandles>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.abcd_group_layout.clone()]),\n        shader: all_shader_handles.texture_b_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.abcd_group_layout.clone()]),\n        shader: all_shader_handles.texture_b_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let texture_a_view = &gpu_images[&texture_a_image.0];\n    let texture_b_view = &gpu_images[&texture_b_image.0];\n    let texture_c_view = &gpu_images[&texture_c_image.0];\n    let texture_d_view = &gpu_images[&texture_d_image.0];\n\n    let texture_b_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: Some(\"binding b\"),\n        layout: &pipeline.abcd_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&texture_a_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&texture_b_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&texture_c_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 4,\n                resource: BindingResource::TextureView(&texture_d_view.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(TextureBBindGroup {\n        texture_b_bind_group,\n        init_pipeline,\n        update_pipeline,\n    });\n}\n\npub struct TextureBNode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for TextureBNode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for TextureBNode {\n    fn update(&mut self, world: &mut World) {\n        let bind_group = world.resource::<TextureBBindGroup>();\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<TextureBBindGroup>();\n        let canvas_size = world.resource::<ShadertoyCanvas>();\n        let texture_b_bind_group = &bind_group.texture_b_bind_group;\n        // let texture_a_bind_group = &bind_group.texture_a_bind_group;\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor::default());\n\n        // pass.set_bind_group(0, texture_a_bind_group, &[]);\n        pass.set_bind_group(0, texture_b_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/texture_c.rs",
    "content": "use bevy::{\n    prelude::*,\n    render::{\n        extract_resource::ExtractResource,\n        render_asset::RenderAssets,\n        render_graph::{self},\n        render_resource::*,\n        renderer::{RenderContext, RenderDevice},\n    },\n};\n\nuse std::borrow::Cow;\n\nuse crate::texture_a::TextureA;\nuse crate::texture_b::TextureB;\nuse crate::texture_d::TextureD;\nuse crate::{\n    CommonUniform, CommonUniformMeta, ShaderHandles, ShadertoyCanvas, ShadertoyPipelines,\n    ShadertoyState, WORKGROUP_SIZE,\n};\n\nstruct TextureCBindGroup {\n    texture_c_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n#[derive(Clone, Deref, ExtractResource)]\npub struct TextureC(pub Handle<Image>);\n\n// pub struct TextureCPipeline {\n//     texture_c_bind_group_layout: BindGroupLayout,\n// }\n\n// impl FromWorld for TextureCPipeline {\n//     fn from_world(world: &mut World) -> Self {\n//         let texture_c_bind_group_layout = world\n//             .resource::<RenderDevice>()\n//             .create_bind_group_layout(&BindGroupLayoutDescriptor {\n//                 label: Some(\"layout_c\"),\n//                 entries: &[\n//                     BindGroupLayoutEntry {\n//                         binding: 0,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::Buffer {\n//                             ty: BufferBindingType::Uniform,\n//                             has_dynamic_offset: false,\n//                             min_binding_size: BufferSize::new(\n//                                 CommonUniform::std140_size_static() as u64\n//                             ),\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 1,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 2,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 3,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                     BindGroupLayoutEntry {\n//                         binding: 4,\n//                         visibility: ShaderStages::COMPUTE,\n//                         ty: BindingType::StorageTexture {\n//                             access: StorageTextureAccess::ReadWrite,\n//                             format: TextureFormat::Rgba32Float,\n//                             view_dimension: TextureViewDimension::D2,\n//                         },\n//                         count: None,\n//                     },\n//                 ],\n//             });\n\n//         // let shader = world\n//         //     .resource::<AssetServer>()\n//         //     .load(\"shaders/texture_b.wgsl\");\n\n//         TextureCPipeline {\n//             texture_c_bind_group_layout,\n//         }\n//     }\n// }\n\n// pub fn extract_texture_c(mut commands: Commands, image: Res<TextureC>) {\n//     commands.insert_resource(TextureC(image.clone()));\n// }\n\npub fn queue_bind_group_c(\n    mut commands: Commands,\n    pipeline: Res<ShadertoyPipelines>,\n    gpu_images: Res<RenderAssets<Image>>,\n    texture_a_image: Res<TextureA>,\n    texture_b_image: Res<TextureB>,\n    texture_c_image: Res<TextureC>,\n    texture_d_image: Res<TextureD>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    all_shader_handles: Res<ShaderHandles>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.abcd_group_layout.clone()]),\n        shader: all_shader_handles.texture_c_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.abcd_group_layout.clone()]),\n        shader: all_shader_handles.texture_c_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let texture_a_view = &gpu_images[&texture_a_image.0];\n    let texture_b_view = &gpu_images[&texture_b_image.0];\n    let texture_c_view = &gpu_images[&texture_c_image.0];\n    let texture_d_view = &gpu_images[&texture_d_image.0];\n\n    let texture_c_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: Some(\"bind_group_c\"),\n        layout: &pipeline.abcd_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&texture_a_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&texture_b_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&texture_c_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 4,\n                resource: BindingResource::TextureView(&texture_d_view.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(TextureCBindGroup {\n        texture_c_bind_group,\n        init_pipeline,\n        update_pipeline,\n    });\n}\n\npub struct TextureCNode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for TextureCNode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for TextureCNode {\n    fn update(&mut self, world: &mut World) {\n        let bind_group = world.resource::<TextureCBindGroup>();\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<TextureCBindGroup>();\n        let canvas_size = world.resource::<ShadertoyCanvas>();\n\n        let texture_c_bind_group = &bind_group.texture_c_bind_group;\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor::default());\n\n        pass.set_bind_group(0, texture_c_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/texture_d.rs",
    "content": "use bevy::{\n    prelude::*,\n    render::{\n        extract_resource::ExtractResource,\n        render_asset::RenderAssets,\n        render_graph::{self},\n        render_resource::*,\n        renderer::{RenderContext, RenderDevice},\n    },\n};\n\nuse std::borrow::Cow;\n\nuse crate::{\n    CommonUniform, CommonUniformMeta, ShaderHandles, ShadertoyCanvas, ShadertoyPipelines,\n    ShadertoyState, WORKGROUP_SIZE,\n};\n\nuse crate::texture_a::TextureA;\nuse crate::texture_b::TextureB;\nuse crate::texture_c::TextureC;\n\n// pub struct TextureDPipeline {\n//     texture_d_group_layout: BindGroupLayout,\n// }\n\n// impl FromWorld for TextureDPipeline {\n//     fn from_world(world: &mut World) -> Self {\n//         let texture_d_group_layout =\n//             world\n//                 .resource::<RenderDevice>()\n//                 .create_bind_group_layout(&BindGroupLayoutDescriptor {\n//                     label: None,\n//                     entries: &[\n//                         BindGroupLayoutEntry {\n//                             binding: 0,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::Buffer {\n//                                 ty: BufferBindingType::Uniform,\n//                                 has_dynamic_offset: false,\n//                                 min_binding_size: BufferSize::new(\n//                                     CommonUniform::std140_size_static() as u64,\n//                                 ),\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 1,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 2,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 3,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                         BindGroupLayoutEntry {\n//                             binding: 4,\n//                             visibility: ShaderStages::COMPUTE,\n//                             ty: BindingType::StorageTexture {\n//                                 access: StorageTextureAccess::ReadWrite,\n//                                 format: TextureFormat::Rgba32Float,\n//                                 view_dimension: TextureViewDimension::D2,\n//                             },\n//                             count: None,\n//                         },\n//                     ],\n//                 });\n\n//         TextureDPipeline {\n//             texture_d_group_layout,\n//         }\n//     }\n// }\n\n#[derive(Clone, Deref, ExtractResource)]\npub struct TextureD(pub Handle<Image>);\n\nstruct TextureDBindGroup {\n    texture_d_bind_group: BindGroup,\n    init_pipeline: CachedComputePipelineId,\n    update_pipeline: CachedComputePipelineId,\n}\n\n// pub fn extract_texture_d(mut commands: Commands, image: Res<TextureD>) {\n//     commands.insert_resource(TextureD(image.clone()));\n// }\n\npub fn queue_bind_group_d(\n    mut commands: Commands,\n    pipeline: Res<ShadertoyPipelines>,\n\n    gpu_images: Res<RenderAssets<Image>>,\n    texture_a_image: Res<TextureA>,\n    texture_b_image: Res<TextureB>,\n    texture_c_image: Res<TextureC>,\n    texture_d_image: Res<TextureD>,\n    render_device: Res<RenderDevice>,\n    mut pipeline_cache: ResMut<PipelineCache>,\n    common_uniform_meta: ResMut<CommonUniformMeta>,\n\n    all_shader_handles: Res<ShaderHandles>,\n) {\n    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.abcd_group_layout.clone()]),\n        shader: all_shader_handles.texture_d_shader.clone(),\n        shader_defs: vec![\"INIT\".to_string()],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {\n        label: None,\n        layout: Some(vec![pipeline.abcd_group_layout.clone()]),\n        shader: all_shader_handles.texture_d_shader.clone(),\n        shader_defs: vec![],\n        entry_point: Cow::from(\"update\"),\n    });\n\n    let texture_a_view = &gpu_images[&texture_a_image.0];\n    let texture_b_view = &gpu_images[&texture_b_image.0];\n    let texture_c_view = &gpu_images[&texture_c_image.0];\n    let texture_d_view = &gpu_images[&texture_d_image.0];\n\n    let texture_d_bind_group = render_device.create_bind_group(&BindGroupDescriptor {\n        label: None,\n        layout: &pipeline.abcd_group_layout,\n        entries: &[\n            BindGroupEntry {\n                binding: 0,\n                resource: common_uniform_meta.buffer.as_entire_binding(),\n            },\n            BindGroupEntry {\n                binding: 1,\n                resource: BindingResource::TextureView(&texture_a_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 2,\n                resource: BindingResource::TextureView(&texture_b_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 3,\n                resource: BindingResource::TextureView(&texture_c_view.texture_view),\n            },\n            BindGroupEntry {\n                binding: 4,\n                resource: BindingResource::TextureView(&texture_d_view.texture_view),\n            },\n        ],\n    });\n\n    commands.insert_resource(TextureDBindGroup {\n        texture_d_bind_group,\n        init_pipeline: init_pipeline.clone(),\n        update_pipeline: update_pipeline.clone(),\n    });\n}\n\n#[derive(Clone, Hash, PartialEq, Eq)]\npub struct MainUpdatePipelineKey {\n    common_code: String,\n}\n\nimpl Default for MainUpdatePipelineKey {\n    fn default() -> Self {\n        MainUpdatePipelineKey {\n            common_code: Default::default(),\n        }\n    }\n}\n\npub struct TextureDNode {\n    pub state: ShadertoyState,\n}\n\nimpl Default for TextureDNode {\n    fn default() -> Self {\n        Self {\n            state: ShadertoyState::Loading,\n        }\n    }\n}\n\nimpl render_graph::Node for TextureDNode {\n    fn update(&mut self, world: &mut World) {\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let bind_group = world.resource::<TextureDBindGroup>();\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        match self.state {\n            ShadertoyState::Loading => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(init_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Init\n                }\n            }\n            ShadertoyState::Init => {\n                if let CachedPipelineState::Ok(_) =\n                    pipeline_cache.get_compute_pipeline_state(update_pipeline_cache)\n                {\n                    self.state = ShadertoyState::Update\n                }\n            }\n            ShadertoyState::Update => {}\n        }\n    }\n\n    fn run(\n        &self,\n        _graph: &mut render_graph::RenderGraphContext,\n        render_context: &mut RenderContext,\n        world: &World,\n    ) -> Result<(), render_graph::NodeRunError> {\n        let bind_group = world.resource::<TextureDBindGroup>();\n        let canvas_size = world.resource::<ShadertoyCanvas>();\n\n        let texture_d_bind_group = &bind_group.texture_d_bind_group;\n\n        let init_pipeline_cache = bind_group.init_pipeline;\n        let update_pipeline_cache = bind_group.update_pipeline;\n\n        let pipeline_cache = world.resource::<PipelineCache>();\n\n        let mut pass = render_context\n            .command_encoder\n            .begin_compute_pass(&ComputePassDescriptor::default());\n\n        pass.set_bind_group(0, texture_d_bind_group, &[]);\n\n        // select the pipeline based on the current state\n        match self.state {\n            ShadertoyState::Loading => {}\n\n            ShadertoyState::Init => {\n                let init_pipeline = pipeline_cache\n                    .get_compute_pipeline(init_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(init_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n\n            ShadertoyState::Update => {\n                let update_pipeline = pipeline_cache\n                    .get_compute_pipeline(update_pipeline_cache)\n                    .unwrap();\n                pass.set_pipeline(update_pipeline);\n                pass.dispatch_workgroups(\n                    canvas_size.width / WORKGROUP_SIZE,\n                    canvas_size.height / WORKGROUP_SIZE,\n                    1,\n                );\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  }
]