<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
    <title>Cindy JS</title>
    <script type="text/javascript" src="../../build/js/Cindy.js"></script>
    <script type="text/javascript" src="../../build/js/CindyGL.js"></script>
    <link rel="stylesheet" href="../../css/cindy.css">
  </head>
    
	<body style="font-family:Arial;">
    <!-- http://jamie-wong.com/2016/08/05/webgl-fluid-simulation/-->
    <h1>CindyJS: Simulation of a fluid</h1>
		Adapted from <a href="http://jamie-wong.com/2016/08/05/webgl-fluid-simulation/">http://jamie-wong.com/2016/08/05/webgl-fluid-simulation/</a>
    <script id="csinit" type="text/x-cindyscript">
				
				
				init(res) := (
					N = res;
					L = [0, 0]; //bottom left corner
					R = [N, 0]; //bottom right corner

					img = "img";
					u = "u";
					d = "d";
					p = "p";
					ua = "ua";
					dragging = false;

					forall(["ua", "d", "p", "u", "img"], img,
							createimage(img, N, N); colorplot(L, R, img, [0, 0, 0, 0]);
					);
					
					alpha = random()*2*pi;
					dir = (cos(alpha), sin(alpha));
					colorplot(L, R, u,
							val = initu(dir, pixel2coord(#));
							(val_1, val_2, 0, 1);
					);

					colorplot(img, mod(round(#.x * 5) + round(#.y * 5), 2));
				);

				pixel2coord(x) := x / N * 4 + (-2, -2);
				initu(dir, x) := ( //vector field
						.03 * (cos(3 * x_2), sin(3 * x_1))
						+ if ( | x - dir | < .2, 3*dir, (0,0))
						//max(0, 1-3*| x - dir |)*3*dir
				);

				dt = 1;
				rho = .1;
				eps = 1;

				advect(img, u, res) := (
						colorplot(L, R, res,
								v = imagergba(L, R, u, #, repeat -> true); imagergba(L, R, img, #+dt * (v_1, v_2), repeat -> true, interpolate -> true);
						);
				);

				divergence(ua, res) := (
						colorplot(L, R, res,
								(-2 * eps * rho / dt) * (
										imagergba(L, R, ua, #+(1, 0), repeat -> true) _1 -
										imagergba(L, R, ua, #+(-1, 0), repeat -> true) _1 +
										imagergba(L, R, ua, #+(0, 1), repeat -> true) _2 -
										imagergba(L, R, ua, #+(0, -1), repeat -> true) _2
								)
						); res
				);

				pressure(d, res) := (
						p = res;
						if(dragging,
							colorplot(L, R, p, 0); //init value
						);
						//else: use old value of p for starting point for Jacobi iteration
						repeat(niterations,
								colorplot(L, R, p,
										(
												imagergba(L, R, d, #, repeat -> true, interpolate -> false) _1 +
												imagergba(L, R, p, #+(2, 0), repeat -> true, interpolate -> false) _1 +
												imagergba(L, R, p, #+(-2, 0), repeat -> true, interpolate -> false) _1 +
												imagergba(L, R, p, #+(0, 2), repeat -> true, interpolate -> false) _1 +
												imagergba(L, R, p, #+(0, -2), repeat -> true, interpolate -> false) _1
										) / 4
								);
						); p
				);


				substgradient(ua, d, res) := (
						colorplot(L, R, res,
								imagergba(L, R, ua, #, repeat -> true) -
								(dt / (2 * rho * eps)) * (
										imagergba(L, R, p, #+(1, 0), repeat -> true, interpolate -> false) _1 -
										imagergba(L, R, p, #+(-1, 0), repeat -> true, interpolate -> false) _1,
										imagergba(L, R, p, #+(0, 1), repeat -> true, interpolate -> false) _1 -
										imagergba(L, R, p, #+(0, -1), repeat -> true, interpolate -> false) _1,
										0,
										0
								)
						); res
				);

				init(512);
				last = (random(), random());
				niterations = 16;
    </script>

		<script id="csmousedown" type="text/x-cindyscript">	
				dragging = true;
				last = mouse();
		</script>

		<script id="csmouseup" type="text/x-cindyscript">	
				dragging = false;
		</script>
		
		<script id="cskeydown" type="text/x-cindyscript">
			  print("pressed key" + keycode());
			  if(keycode()==32,
						colorplot(img, mod(round(#.x * 5) + round(#.y * 5), 2));
				);
		</script>

    <script id="csdraw" type="text/x-cindyscript">
				clamp(c) := (min(1, max(c_1, 0)), min(1, max(c_2, 0)), min(1 ,max(c_3, 0)));
				colorplot(L, R, img,
			    //if (false & dragging & |mouse() - pixel2coord(#)| < .025, hue(seconds()),
					clamp(
			        imagergb(L, R, img, #)
							+ .003*imagergb(L, R, u, #) //just add some color based on u to make it less greyish
					)
			    //)
				);

				delta = 20 * (last - mouse());
				//errc(delta);
				colorplot(L, R, u,
				    if (dragging & | mouse() - pixel2coord(#) | < .15, (delta_1, delta_2, 0, 0), (0, 0, 0, 0)) +
				        imagergba(L, R, u, #)
				);

				last = mouse();

				/*
						u_a := advect field u through itself
						d := calculate divergence of u_a
						p := calculate pressure based on d, using jacobi iteration
						u := u_a - gradient of p
						c := advect field c through velocity field u
						draw c
				*/

				advect(u, u, ua);
				divergence(ua, d);
				pressure(d, p);
				substgradient(ua, p, u);
				advect(img, u, img);



				drawimage([-2, -2], [2, -2], img);
    </script>

		<div id="container" style="width:512px; height: 512px">
	    <div id="CSCanvas" style="width:100%; height:100%"></div>
	  </div>
		<div>
			Press <b>space</b> to reset advected image to checkerboard.
		</div>
    <script type="text/javascript">
        cdy = CindyJS({canvasname:"CSCanvas",
                    scripts: "cs*",
                    geometry:[
                      //{name:"A", kind:"P", type:"Free", pos:[1  ,-1],size:3},
                      //{name:"B", kind:"P", type:"Free", pos:[-1 ,1],size:3}
                    ],
                    animation: {autoplay: true},
										images: {image: "image.png"},
										use: ["CindyGL"],
                    ports: [{
                      id: "CSCanvas",
                      transform: [ { visibleRect: [-2, -2, 2, 2] } ]
                    }]
                  });
									
				var container = document.getElementById("container");
				function setsize(N) {
					cdy.evokeCS(`init(${N})`);
			    container.style.width = container.style.height = Math.max(N,512) + "px";
				}
    </script>
		<div>
			Resolution:
			<select onchange="setsize(this.value);">  
				<option>256</option>
				<option selected>512</option>
				<option>768</option>
				<option>1024</option>
			</select> px.
		</div>
		<div>
			Number of iterations in Jacobi method for solving pressure
			<select onchange="cdy.evokeCS('niterations = ' + this.value);">  
				<option>2</option>
				<option>4</option>
				<option>8</option>
				<option selected>16</option>
				<option>24</option>
				<option>32</option>
				<option>48</option>
				<option>64</option>
				<option>128</option>
			</select>
		</div>
	</body>
</html>
