|
|
// shim layer with setTimeout fallback (Paul Irish)
|
|
|
window.requestAnimFrame = (function(){
|
|
|
return window.requestAnimationFrame ||
|
|
|
window.webkitRequestAnimationFrame ||
|
|
|
window.mozRequestAnimationFrame ||
|
|
|
window.oRequestAnimationFrame ||
|
|
|
window.msRequestAnimationFrame ||
|
|
|
function( callback ){
|
|
|
window.setTimeout(callback, 1000 / 60);
|
|
|
};
|
|
|
})();
|
|
|
|
|
|
|
|
|
// Based on http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/GDC03.pdf
|
|
|
var NavierStokes = function(settings){
|
|
|
this.init(settings);
|
|
|
};
|
|
|
|
|
|
NavierStokes.prototype = {
|
|
|
|
|
|
init : function(settings){
|
|
|
var defaultSettings = {
|
|
|
resolution : 64,
|
|
|
iterations : 10,
|
|
|
fract : 1/4,
|
|
|
diffusion : 1,
|
|
|
gridmodify : 0,
|
|
|
dt : 0.1,
|
|
|
callbackUser : function(D, U, V, size){},
|
|
|
callbackDisplay : function(D, U, V, size){}
|
|
|
};
|
|
|
|
|
|
if (this.settings === undefined){
|
|
|
this.settings = defaultSettings;
|
|
|
}
|
|
|
|
|
|
this._mergeRecursive(this.settings, settings);
|
|
|
|
|
|
this.rows = this.settings.resolution + 2;
|
|
|
this.arraySize = (this.settings.resolution+2)*(this.settings.resolution+2);
|
|
|
|
|
|
|
|
|
this.U = new Float32Array(this.arraySize);
|
|
|
this.V = new Float32Array(this.arraySize);
|
|
|
this.D = new Float32Array(this.arraySize);
|
|
|
|
|
|
this.U_prev = new Float32Array(this.arraySize);
|
|
|
this.V_prev = new Float32Array(this.arraySize);
|
|
|
this.D_prev = new Float32Array(this.arraySize);
|
|
|
|
|
|
this.NullArray = new Float32Array(this.arraySize);
|
|
|
|
|
|
|
|
|
// Precalculate lookup table for 2D > 1D array.
|
|
|
this.IX = new Array(this.rows);
|
|
|
for (var i = 0; i < this.rows; i++){
|
|
|
this.IX[i] = new Array(this.rows);
|
|
|
for (var b = 0; b < this.rows; b++){
|
|
|
this.IX[i][b] = i+b*this.rows;
|
|
|
}
|
|
|
}
|
|
|
// Init all Arrays.
|
|
|
for (i = 0; i < this.arraySize; i++){
|
|
|
this.D_prev[i] = this.U_prev[i] = this.V_prev[i] = this.D[i] = this.U[i] = this.V[i] = this.NullArray[i] = 0.0;
|
|
|
}
|
|
|
|
|
|
//Init some vars based on the Resolution settings:
|
|
|
this.calculateSettings();
|
|
|
},
|
|
|
clear : function(){
|
|
|
this.D.set(this.NullArray);
|
|
|
this.U.set(this.NullArray);
|
|
|
this.V.set(this.NullArray);
|
|
|
},
|
|
|
// Getter Setter
|
|
|
getResolution : function(){
|
|
|
return this.settings.resolution;
|
|
|
},
|
|
|
|
|
|
getSettings : function(){
|
|
|
return this.settings;
|
|
|
},
|
|
|
|
|
|
update : function(){
|
|
|
// Add user Action
|
|
|
this.userAction();
|
|
|
|
|
|
// Cals velosity & density
|
|
|
this.vel_step (this.U, this.V, this.U_prev, this.V_prev, this.settings.dt );
|
|
|
this.dens_step (this.D, this.D_prev, this.U, this.V, this.settings.dt );
|
|
|
|
|
|
this.settings.callbackDisplay(this.D, this.U, this.V, this.settings.resolution);
|
|
|
},
|
|
|
|
|
|
calculateSettings : function(){
|
|
|
this.centerPos = (-0.5/this.settings.resolution) * (1 + this.settings.gridmodify);
|
|
|
this.scale = this.settings.resolution * 0.5;
|
|
|
this.dt0 = this.settings.dt * this.settings.resolution;
|
|
|
this.p5 = this.settings.resolution + 0.5;
|
|
|
},
|
|
|
|
|
|
userAction : function (){
|
|
|
this.D_prev.set(this.NullArray);
|
|
|
this.U_prev.set(this.NullArray);
|
|
|
this.V_prev.set(this.NullArray);
|
|
|
|
|
|
this.settings.callbackUser(this.D_prev, this.U_prev, this.V_prev, this.settings.resolution);
|
|
|
},
|
|
|
vel_step : function (u, v, u0, v0, dt ){
|
|
|
var tmp;
|
|
|
|
|
|
this.add_source(u, u0, dt );
|
|
|
this.add_source(v, v0, dt );
|
|
|
|
|
|
tmp = u0;
|
|
|
u0 = u;
|
|
|
u = tmp;
|
|
|
this.diffuse ( 1, u, u0, dt );
|
|
|
|
|
|
|
|
|
tmp = v0;
|
|
|
v0 = v;
|
|
|
v = tmp;
|
|
|
this.diffuse ( 2, v, v0, dt );
|
|
|
|
|
|
this.project(u, v, u0, v0);
|
|
|
|
|
|
tmp = u0;
|
|
|
u0 = u;
|
|
|
u = tmp;
|
|
|
|
|
|
tmp = v0;
|
|
|
v0 = v;
|
|
|
v = tmp;
|
|
|
this.advect(1, u, u0, u0, v0, dt);
|
|
|
this.advect(2, v, v0, u0, v0, dt);
|
|
|
|
|
|
this.project(u, v, u0, v0 );
|
|
|
},
|
|
|
|
|
|
dens_step : function (x, x0, u, v, dt){
|
|
|
var tmp;
|
|
|
this.add_source (x, x0, dt);
|
|
|
//SWAP ( x0, x );
|
|
|
this.diffuse (0, x0, x, dt );
|
|
|
//SWAP ( x0, x );
|
|
|
this.advect ( 0, x, x0, u, v, dt );
|
|
|
},
|
|
|
|
|
|
add_source : function (x, s, dt){
|
|
|
for (var i=0; i<this.arraySize ; i++ ){
|
|
|
x[i] += dt * s[i];
|
|
|
}
|
|
|
},
|
|
|
|
|
|
|
|
|
diffuse : function (b, x, x0, dt){
|
|
|
for (var i=1; i < this.arraySize;i++){
|
|
|
x[i] = x0[i]*this.settings.diffusion;
|
|
|
}
|
|
|
this.set_bnd(b, x);
|
|
|
},
|
|
|
|
|
|
project : function ( u, v, p, div ) {
|
|
|
var i, k,prevRow, thisRow, nextValue, nextRow, to, lastRow;
|
|
|
for (i = 1 ; i <= this.settings.resolution; i++ ){
|
|
|
prevRow = this.IX[0][i-1];
|
|
|
thisRow = this.IX[0][i];
|
|
|
nextRow = this.IX[0][i+1];
|
|
|
|
|
|
valueBefore = thisRow - 1;
|
|
|
valueNext = thisRow + 1;
|
|
|
|
|
|
to = this.settings.resolution + valueNext;
|
|
|
for (k = valueNext; k < to; k++ ) {
|
|
|
p[k] = 0;
|
|
|
div[k] = (u[++valueNext] - u[++valueBefore] + v[++nextRow] - v[++prevRow]) * this.centerPos;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
this.set_bnd(0, div);
|
|
|
this.set_bnd(0, p);
|
|
|
|
|
|
for (k=0 ; k<this.settings.iterations; k++) {
|
|
|
for (j=1 ; j<=this.settings.resolution; j++) {
|
|
|
lastRow = this.IX[0][j-1];
|
|
|
thisRow = this.IX[0][j];
|
|
|
nextRow = this.IX[0][j+1];
|
|
|
prevX = p[thisRow];
|
|
|
thisRow++;
|
|
|
for (i=1; i<=this.settings.resolution; i++){
|
|
|
p[thisRow] = prevX = (div[thisRow] + p[++lastRow] + p[++thisRow] + p[++nextRow] + prevX ) * this.settings.fract;
|
|
|
}
|
|
|
}
|
|
|
this.set_bnd(0, p);
|
|
|
}
|
|
|
|
|
|
for (j = 1; j <= this.settings.resolution; j++ ) {
|
|
|
lastRow = this.IX[0][j-1];
|
|
|
thisRow = this.IX[0][j];
|
|
|
nextRow = this.IX[0][j+1];
|
|
|
|
|
|
valueBefore = thisRow - 1;
|
|
|
valueNext = thisRow + 1;
|
|
|
|
|
|
for (i = 1; i <= this.settings.resolution; i++) {
|
|
|
u[++thisRow] -= this.scale * (p[++valueNext] - p[++valueBefore]);
|
|
|
v[thisRow] -= this.scale * (p[++nextRow] - p[++lastRow]);
|
|
|
}
|
|
|
}
|
|
|
this.set_bnd(1, u);
|
|
|
this.set_bnd(2, v);
|
|
|
},
|
|
|
|
|
|
advect : function (b, d, d0, u, v, dt ){
|
|
|
var to;
|
|
|
for (var j = 1; j<= this.settings.resolution; j++) {
|
|
|
var pos = j * this.rows;
|
|
|
for (var k = 1; k <= this.settings.resolution; k++) {
|
|
|
var x = k - this.dt0 * u[++pos];
|
|
|
var y = j - this.dt0 * v[pos];
|
|
|
|
|
|
if (x < 0.5) x = 0.5
|
|
|
if (x > this.p5) x = this.p5;
|
|
|
|
|
|
var i0 = x | 0;
|
|
|
var i1 = i0 + 1;
|
|
|
|
|
|
if (y < 0.5) y = 0.5
|
|
|
if (y > this.p5) y = this.p5;
|
|
|
|
|
|
var j0 = y | 0;
|
|
|
var j1 = j0 + 1;
|
|
|
var s1 = x - i0;
|
|
|
var s0 = 1 - s1;
|
|
|
var t1 = y - j0;
|
|
|
var t0 = 1 - t1;
|
|
|
var toR1 = this.IX[0][j0];
|
|
|
var toR2 = this.IX[0][j1];
|
|
|
d[pos] = s0 * (t0 * d0[i0 + toR1] + t1 * d0[i0 + toR2]) + s1 * (t0 * d0[i1 + toR1] + t1 * d0[i1 + toR2]);
|
|
|
}
|
|
|
}
|
|
|
this.set_bnd(b, d);
|
|
|
},
|
|
|
// Calculate Boundary's
|
|
|
set_bnd : function (b, x ){
|
|
|
var i, j;
|
|
|
switch (b){
|
|
|
case 1 :
|
|
|
for (i = 1; i <= this.settings.resolution; i++) {
|
|
|
x[i] = x[i + this.rows];
|
|
|
x[this.IX[i][(this.settings.resolution+1)]] = x[this.IX[i][(this.settings.resolution)]];
|
|
|
x[this.IX[0][i]] = -x[this.IX[1][i]];
|
|
|
x[this.IX[(this.settings.resolution+1)][i]] = -x[this.IX[(this.settings.resolution)][i]];
|
|
|
}
|
|
|
break;
|
|
|
case 2 :
|
|
|
for ( i = 1; i <= this.settings.resolution; i++) {
|
|
|
x[i] = -x[i + this.rows];
|
|
|
x[this.IX[i][(this.settings.resolution+1)]] = -x[this.IX[i][(this.settings.resolution)]];
|
|
|
x[this.IX[0][i]] = x[this.IX[1][i]];
|
|
|
x[this.IX[(this.settings.resolution+1)][i]] = x[this.IX[(this.settings.resolution)][i]];
|
|
|
}
|
|
|
break;
|
|
|
default :
|
|
|
for ( i = 1; i <= this.settings.resolution; i++) {
|
|
|
x[i] = x[i + this.rows];
|
|
|
x[this.IX[i][(this.settings.resolution+1)]] = x[this.IX[i][(this.settings.resolution)]];
|
|
|
x[this.IX[0][i]] = x[this.IX[1][i]];
|
|
|
x[this.IX[(this.settings.resolution+1)][i]] = x[this.IX[(this.settings.resolution)][i]];
|
|
|
}
|
|
|
}
|
|
|
// Boundes of the Canvas
|
|
|
var topPos = this.IX[0][this.settings.resolution+1];
|
|
|
x[0] = (x[1] + x[this.rows]) / 2;
|
|
|
x[topPos] = (x[1 + topPos] + x[this.IX[this.settings.resolution][0]]) / 2;
|
|
|
x[(this.settings.resolution+1)] = (x[this.settings.resolution] + x[(this.settings.resolution + 1) + this.rows]) / 2;
|
|
|
x[(this.settings.resolution+1)+topPos] = (x[this.settings.resolution + topPos] + x[this.IX[this.settings.resolution+1][this.settings.resolution]]);
|
|
|
|
|
|
},
|
|
|
// Merge Settings.
|
|
|
_mergeRecursive : function(obj1, obj2) {
|
|
|
for (var p in obj2) {
|
|
|
if ( obj2[p].constructor==Object ) {
|
|
|
obj1[p] = this._mergeRecursive(obj1[p], obj2[p]);
|
|
|
} else {
|
|
|
obj1[p] = obj2[p];
|
|
|
}
|
|
|
}
|
|
|
return obj1;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var Display = function(canvas){
|
|
|
this.colorFunctions = {
|
|
|
"BW" : this.calcColorBW ,
|
|
|
"Color": this.calcColor,
|
|
|
"User" : this.calcUserColor
|
|
|
};
|
|
|
this.currColorFunc = "BW";
|
|
|
this.canvas = canvas;
|
|
|
this.context = canvas.getContext("2d", {alpha : false});
|
|
|
this.supportImageData = !!this.context.getImageData;
|
|
|
|
|
|
this.colorUser = {
|
|
|
R : 0,
|
|
|
G : 255,
|
|
|
B : 0
|
|
|
}
|
|
|
};
|
|
|
|
|
|
Display.prototype = {
|
|
|
|
|
|
init : function (res){
|
|
|
this.calcResolution = res;
|
|
|
this.imageData = null;
|
|
|
this.showColors = false;
|
|
|
this.line = null;
|
|
|
},
|
|
|
|
|
|
density : function(D, U, V){
|
|
|
var r,g,b, x, y, d;
|
|
|
|
|
|
if (this.supportImageData){
|
|
|
// Get Image Data
|
|
|
if (this.imageData === null){
|
|
|
this.imageData = this.context.getImageData(0, 0, this.calcResolution, this.calcResolution);
|
|
|
}
|
|
|
|
|
|
|
|
|
for (x = 0; x < this.calcResolution; x++) {
|
|
|
for (y = 0; y < this.calcResolution; y++){
|
|
|
var posC = (x + y * this.calcResolution) * 4;
|
|
|
var pos = fluid.IX[x][y];
|
|
|
|
|
|
var cArray = this.colorFunctions[this.currColorFunc].call(this, D, U, V, pos);
|
|
|
|
|
|
this.imageData.data[posC] = cArray[0]; // R
|
|
|
this.imageData.data[posC + 1] = cArray[1]; // G
|
|
|
this.imageData.data[posC + 2] = cArray[2]; // B
|
|
|
this.imageData.data[posC + 3] = 255; //A
|
|
|
}
|
|
|
}
|
|
|
this.context.putImageData(this.imageData, 0, 0);
|
|
|
}else{
|
|
|
// Slow fallback for oldie
|
|
|
for (x = 0; x < this.calcResolution; x++) {
|
|
|
for (y = 0; y < this.calcResolution; y++) {
|
|
|
var pos = fluid.IX[x][y];
|
|
|
var c =(D[pos] / 2);
|
|
|
this.context.setFillColor(c , c, c , 1);
|
|
|
this.context.fillRect(x, y, 1, 1);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// Draw the line for creating an Emitter
|
|
|
if (this.line != null){
|
|
|
this.context.beginPath();
|
|
|
this.context.lineWidth = 1;
|
|
|
this.context.strokeStyle = "rgb(255,255,255)";
|
|
|
this.context.moveTo(this.line[0][0],this.line[0][1]);
|
|
|
this.context.lineTo(this.line[1][0],this.line[1][1]);
|
|
|
this.context.stroke();
|
|
|
}
|
|
|
},
|
|
|
|
|
|
setColorFunction: function(colorFuncName){
|
|
|
this.currColorFunc = "BW";
|
|
|
},
|
|
|
|
|
|
calcColorBW : function(D, U, V, pos){
|
|
|
var bw = (D[pos] * 255 / 6) | 0;
|
|
|
return [bw, bw, bw];
|
|
|
},
|
|
|
|
|
|
calcColor : function(D, U, V, pos){
|
|
|
var r = Math.abs((U[pos] * 1300 ) | 0);
|
|
|
var b = Math.abs((V[pos] * 1300 ) | 0);
|
|
|
var g = (D[pos] * 255 / 6) | 0;
|
|
|
|
|
|
return [r, g, b];
|
|
|
},
|
|
|
|
|
|
calcUserColor : function(D, U, V, pos){
|
|
|
var r = Math.abs((U[pos] *500* this.colorUser.R) | 0);
|
|
|
var g = (D[pos] * this.colorUser.G) | 0;
|
|
|
var b = Math.abs((V[pos] *500* this.colorUser.B ) | 0);
|
|
|
|
|
|
return [r, g, b];
|
|
|
},
|
|
|
|
|
|
drawLine : function (a0, a1, scale){
|
|
|
var l0 = [a0[0]*scale, a0[1]*scale];
|
|
|
var l1 = [a1[0]*scale, a1[1]*scale];
|
|
|
|
|
|
this.line = [l0, l1];
|
|
|
},
|
|
|
|
|
|
removeLine : function(){this.line = null},
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var user = {
|
|
|
displaySize : 500,
|
|
|
canvas : null,
|
|
|
canvasOffset : null,
|
|
|
scale : 0,
|
|
|
|
|
|
mouseStart: [],
|
|
|
mouseEnd : [],
|
|
|
mouseLeftDown : false,
|
|
|
mousePath : [],
|
|
|
|
|
|
mouseRightDown : false,
|
|
|
mouseRightStart : [],
|
|
|
|
|
|
forceEmitters : [],
|
|
|
|
|
|
insertedDensity : 50,
|
|
|
|
|
|
init : function(canvas){
|
|
|
this.canvas = $(canvas);
|
|
|
|
|
|
this.canvasOffset = this.canvas.offset();
|
|
|
|
|
|
var that = this;
|
|
|
window.ontouchend = window.onmouseup = function(e){that.handleInputEnd(e);};
|
|
|
canvas.ontouchstart = canvas.onmousedown = function(e){that.handleInput(e);};
|
|
|
canvas.ontouchmove = canvas.onmousemove = function(e){that.handleInputMove(e);};
|
|
|
canvas.oncontextmenu = function(e){e.preventDefault();};
|
|
|
},
|
|
|
|
|
|
interact : function(D, U, V, size){
|
|
|
var x, y, pos, i ;
|
|
|
|
|
|
if (this.mouseLeftDown){
|
|
|
var dx = this.mouseStart[0] - this.mouseEnd[0];
|
|
|
var dy = this.mouseStart[1] - this.mouseEnd[1];
|
|
|
|
|
|
var mousePathLength = Math.sqrt(dx * dx + dy * dy) | 0;
|
|
|
mousePathLength = (mousePathLength < 1) ? 1 : mousePathLength;
|
|
|
for ( i = 0; i < mousePathLength; i++) {
|
|
|
x = (((this.mouseStart[0] - (i / mousePathLength) * dx)) * this.scale) | 0;
|
|
|
y = (((this.mouseStart[1] - (i / mousePathLength) * dy)) * this.scale) | 0;
|
|
|
|
|
|
pos = fluid.IX[x][y];
|
|
|
|
|
|
U[pos] = -dx / 6;
|
|
|
V[pos] = -dy / 6;
|
|
|
D[pos] = this.insertedDensity;
|
|
|
}
|
|
|
this.mouseStart[0] = this.mouseEnd[0];
|
|
|
this.mouseStart[1] = this.mouseEnd[1];
|
|
|
}
|
|
|
|
|
|
for (i = 0;i<this.forceEmitters.length;i++){
|
|
|
var posDir = this.forceEmitters[i];
|
|
|
var pos = fluid.IX[posDir[0]*this.scale | 0][posDir[1]*this.scale | 0];
|
|
|
U[pos] = posDir[2];
|
|
|
V[pos] = posDir[3];
|
|
|
}
|
|
|
|
|
|
},
|
|
|
initFluidWithResolution : function(){
|
|
|
fluid.init();
|
|
|
this.setCanvasSize(fluid.settings.resolution);
|
|
|
display.init(fluid.settings.resolution);
|
|
|
},
|
|
|
clearDisplay : function(){
|
|
|
fluid.clear();
|
|
|
this.forceEmitters = [];
|
|
|
},
|
|
|
|
|
|
setDisplay : function(e){
|
|
|
var displaySize = parseInt(e);
|
|
|
if (displaySize === 0){ // 1:1
|
|
|
this.setDisplaySize(fluid.getSettings().resolution);
|
|
|
}else{
|
|
|
this.setDisplaySize(displaySize);
|
|
|
}
|
|
|
},
|
|
|
setCanvasSize : function(size){
|
|
|
this.canvas.attr("width", size);
|
|
|
this.canvas.attr("height", size);
|
|
|
this.calculateScale();
|
|
|
},
|
|
|
|
|
|
setDisplaySize : function(size){
|
|
|
$('#wrapper').width(size);
|
|
|
this.canvas.width(size);
|
|
|
this.canvas.height(size);
|
|
|
this.calculateScale();
|
|
|
},
|
|
|
|
|
|
calculateScale : function(){
|
|
|
this.scale = fluid.getResolution() / this.canvas.width();
|
|
|
this.canvasOffset = this.canvas.offset();
|
|
|
},
|
|
|
|
|
|
handleInput : function(e){
|
|
|
if (e.type === "touchstart"){
|
|
|
this.mouseLeftDown = true;
|
|
|
this.mouseEnd = this.mouseStart = [e.pageX - this.canvasOffset.left, e.pageY - this.canvasOffset.top];
|
|
|
}else if (e.button !== undefined){
|
|
|
var mPos = this.getMousePositon(e);
|
|
|
if (e.button == 0){
|
|
|
this.mouseLeftDown = true;
|
|
|
this.mouseEnd = this.mouseStart = mPos;
|
|
|
}else if (e.button == 2){
|
|
|
this.mouseRightDown = true;
|
|
|
this.mouseRightStart = mPos;
|
|
|
}
|
|
|
}
|
|
|
e.preventDefault();
|
|
|
},
|
|
|
|
|
|
handleInputMove : function(e){
|
|
|
var mPos = this.getMousePositon(e);
|
|
|
if (this.mouseLeftDown){
|
|
|
if (e.type === "touchmove"){
|
|
|
this.mouseEnd = [e.pageX - this.canvasOffset.left, e.pageY - this.canvasOffset.top];
|
|
|
}else{
|
|
|
this.mouseEnd = mPos;
|
|
|
}
|
|
|
}
|
|
|
if (this.mouseRightDown){
|
|
|
display.drawLine(this.mouseRightStart, mPos, this.scale);
|
|
|
}
|
|
|
},
|
|
|
handleInputEnd : function(e){
|
|
|
this.mouseLeftDown = false;
|
|
|
if (this.mouseRightDown){
|
|
|
this.mouseRightDown = false;
|
|
|
var endPos = this.getMousePositon(e);
|
|
|
var x = this.mouseRightStart[0];
|
|
|
var y = this.mouseRightStart[1];
|
|
|
|
|
|
var dx = -(x - endPos[0]) / 10;
|
|
|
var dy = -(y - endPos[1]) / 10;
|
|
|
this.forceEmitters.push([x, y, dx, dy]);
|
|
|
display.removeLine();
|
|
|
}
|
|
|
},
|
|
|
getMousePositon : function (e){
|
|
|
var mouseX, mouseY;
|
|
|
|
|
|
if(e.offsetX) {
|
|
|
mouseX = e.offsetX;
|
|
|
mouseY = e.offsetY;
|
|
|
}
|
|
|
else if(e.layerX) {
|
|
|
mouseX = e.layerX;
|
|
|
mouseY = e.layerY;
|
|
|
}
|
|
|
return [mouseX, mouseY];
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var canvas = document.getElementById("d");
|
|
|
var display = new Display(canvas);
|
|
|
var fluid = new NavierStokes({
|
|
|
callbackDisplay : function(D, U, V, size){
|
|
|
display.density(D, U, V, size);
|
|
|
},
|
|
|
callbackUser : function(D, U, V, size){
|
|
|
user.interact(D, U, V, size);
|
|
|
}});
|
|
|
|
|
|
user.init(canvas, fluid, display);
|
|
|
user.initFluidWithResolution();
|
|
|
|
|
|
//Start Simulation
|
|
|
function simulation(){
|
|
|
window.requestAnimFrame(simulation);
|
|
|
//var thisFrameTime = (thisLoop=new Date) - lastLoop;
|
|
|
//frameTime+= (thisFrameTime - frameTime) / filterStrength;
|
|
|
//lastLoop = thisLoop;
|
|
|
fluid.update();
|
|
|
};
|
|
|
|
|
|
// Run Simulation
|
|
|
simulation();
|
|
|
|