forked from chi-feng/colorful-fluid-dynamics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
FluidDisplay.js
executable file
·114 lines (108 loc) · 3.93 KB
/
FluidDisplay.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
function FluidDisplay(field) {
this.additive = true;
this.canvas = document.getElementById("canvas-fluid");
this.context = this.canvas.getContext("2d");
this.image = null; // created in renderParticles
// buffer is for displaying density
this.buffer = document.createElement("canvas");
this.buffer.width = field.width;
this.buffer.height = field.height;
this.buffercontext = this.buffer.getContext("2d");
this.bufferimage = this.buffercontext.createImageData(field.width, field.height);
// set alpha to 255
for (var i = 3; i < field.width * field.height * 4; i += 4) {
this.bufferimage.data[i] = 255;
}
}
FluidDisplay.prototype.clear = function() {
this.context.fillStyle = 'black';
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
}
FluidDisplay.prototype.renderDensityField = function(field) {
for (var x = 0; x < field.width; x++) {
for (var y = 0; y < field.height; y++) {
var d = field.getDensity(x, y) / 5;
if (d > 1) d = 1;
var base = 4 * (y * field.width + x);
d = d * 2 - 1;
this.bufferimage.data[base + 0] = jet.r(d);
this.bufferimage.data[base + 1] = jet.g(d);
this.bufferimage.data[base + 2] = jet.b(d);
}
}
this.buffercontext.putImageData(this.bufferimage, 0, 0);
var hscale = this.canvas.width / this.buffer.width;
var vscale = this.canvas.height / this.buffer.height;
this.context.scale(hscale, vscale);
this.context.drawImage(this.buffer, 0, 0);
this.context.scale(1 / hscale, 1 / vscale);
}
FluidDisplay.prototype.renderVelocityField = function(field) {
this.context.save();
this.context.lineWidth = 1;
var wscale = this.canvas.width / field.width;
var hscale = this.canvas.height / field.height;
this.context.strokeStyle = 'white';
var scale = 20;
this.context.beginPath();
for (var x = 0; x < field.width; x++) {
for (var y = 0; y < field.height; y++) {
var vx = field.getXVelocity(x, y);
var vy = field.getYVelocity(x, y);
this.context.moveTo(x * wscale + 0.5 * wscale, y * hscale + 0.5 * hscale);
this.context.lineTo((x + 0.5 + scale * vx) * wscale,
(y + 0.5 + scale * vy) * hscale);
}
}
this.context.stroke();
this.context.restore();
}
FluidDisplay.prototype.renderParticles = function(field, px, py, pc, pl) {
this.image = this.context.createImageData(this.canvas.width, this.canvas.height);
var wscale = this.canvas.width / field.width;
var hscale = this.canvas.height / field.height;
var n = px.length;
var h, s, v, r, g, b, j, f, p, q, t;
for (var i = 0; i < n; i++) {
var cx = Math.floor(px[i] * wscale);
var cy = Math.floor(py[i] * hscale);
var base = 4 * (cy * this.canvas.width + cx);
h = pc[i];
s = pl[i] / life;
v = s * s;
{ // hsv -> rgb, inlined for performance
j = Math.floor(h * 6);
f = h * 6 - j;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (j % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
}
// alpha
this.image.data[base + 3] = 255;
// blending modes
if (this.additive) {
this.image.data[base ] += Math.floor(r * 255);
this.image.data[base + 1] += Math.floor(g * 255);
this.image.data[base + 2] += Math.floor(b * 255);
} else {
this.image.data[base ] = Math.floor(r * 255);
this.image.data[base + 1] = Math.floor(g * 255);
this.image.data[base + 2] = Math.floor(b * 255);
}
}
this.context.putImageData(this.image, 0, 0);
}
FluidDisplay.prototype.circle = function(radius, color) {
this.context.beginPath();
this.context.arc(this.canvas.width / 2, this.canvas.height / 2, 40, 0, 2 * Math.PI, false);
this.context.fillStyle = color;
this.context.fill();
}