#include <math.h>
#include <stdlib.h>
#include <helianthus.h>
#define SIZE 100
double matrix[3][2] = {
{ 5, 2 },
{ 5, -2 },
{ 0, -5 } };
double invMatrix[2][2] = {
{ 0.1 , 0.1 },
{ 0.25, -0.25 } };
double grid[2][SIZE][SIZE];
int gridId = 0;
double simTm;
double calcX(double x, double y, double z)
{ return matrix[0][0]*x + matrix[1][0]*y + matrix[2][0]*z; }
double calcY(double x, double y, double z)
{ return matrix[0][1]*x + matrix[1][1]*y + matrix[2][1]*z; }
double calcBackX(double sx, double sy)
{ return invMatrix[0][0]*sx + invMatrix[1][0]*sy; }
double calcBackY(double sx, double sy)
{ return invMatrix[0][1]*sx + invMatrix[1][1]*sy; }
void drawBox(double x, double y, double z, double dx, double dy, double dz, unsigned int color) {
saveState();
double ch = colorGetHue(color);
double cs = colorGetSaturation(color);
double cv = colorGetValue(color);
noStroke();
fill(colorByHSV(ch, cs, cv*0.6));
moveTo( calcX(x, y, z),
calcY(x, y, z) );
lineTo( calcX(x+dx, y, z),
calcY(x+dx, y, z) );
lineTo( calcX(x+dx, y, z+dz),
calcY(x+dx, y, z+dz) );
lineTo( calcX(x, y, z+dz),
calcY(x, y, z+dz) );
closePath();
fill(colorByHSV(ch, cs, cv*0.8));
moveTo( calcX(x+dx, y, z),
calcY(x+dx, y, z) );
lineTo( calcX(x+dx, y+dy, z),
calcY(x+dx, y+dy, z) );
lineTo( calcX(x+dx, y+dy, z+dz),
calcY(x+dx, y+dy, z+dz) );
lineTo( calcX(x+dx, y, z+dz),
calcY(x+dx, y, z+dz) );
closePath();
fill(color);
moveTo( calcX(x, y, z+dz),
calcY(x, y, z+dz) );
lineTo( calcX(x+dx, y, z+dz),
calcY(x+dx, y, z+dz) );
lineTo( calcX(x+dx, y+dy, z+dz),
calcY(x+dx, y+dy, z+dz) );
lineTo( calcX(x, y+dy, z+dz),
calcY(x, y+dy, z+dz) );
closePath();
restoreState();
}
void setPoint(int i, int j, int size, double z) {
for(int ii = -size; ii <= size; ++ii)
for(int jj = -size; jj <= size; ++jj)
if ( i + ii >= 0 && i + ii < SIZE
&& j + jj >= 0 && j + jj < SIZE
&& ii*ii + jj*jj <= size*(size + 1) )
grid[0][i+ii][j+jj] = grid[1][i+ii][j+jj] = z;
}
void init() { }
void draw() {
double w = windowGetWidth();
double h = windowGetHeight();
double tm = windowGetSeconds();
saveState();
translate(w/2, h/2);
double smx = mouseTransformedX();
double smy = mouseTransformedY();
double mx = calcBackX(smx, smy);
double my = calcBackY(smx, smy);
if (keyWentDown("space"))
setPoint(randomNumber(0, SIZE-1), randomNumber(0, SIZE-1), 2, (randomFloat() - 0.5)*10);
double k = 1/sqrt(2);
double dt = 0.01;
if (fabs(simTm - tm) > 5) simTm = tm - dt/2;
while(simTm < tm) {
if (mouseDown("left") || mouseDown("right") || mouseDown("middle")) {
int i = (int)floor(mx + SIZE*0.5);
int j = (int)floor(my + SIZE*0.5);
setPoint(i, j, 4, mouseDown("left") ? 20 : mouseDown("right") ? -20 : 0);
}
int prevId = gridId;
gridId = 1 - gridId;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
double z = grid[prevId][i][j];
double v = z - grid[gridId][i][j];
double f = 0;
double sum = 0;
if (i > 0 ) { f += grid[prevId][i-1][j] - z; sum += 1; }
if (i < SIZE-1) { f += grid[prevId][i+1][j] - z; sum += 1; }
if (j > 0 ) { f += grid[prevId][i][j-1] - z; sum += 1; }
if (j < SIZE-1) { f += grid[prevId][i][j+1] - z; sum += 1; }
if (i > 0 && j > 0 ) { f += k*(grid[prevId][i-1][j-1] - z); sum += k; }
if (i < SIZE-1 && j > 0 ) { f += k*(grid[prevId][i+1][j-1] - z); sum += k; }
if (i > 0 && j < SIZE-1) { f += k*(grid[prevId][i-1][j+1] - z); sum += k; }
if (i < SIZE-1 && j < SIZE-1) { f += k*(grid[prevId][i+1][j+1] - z); sum += k; }
if (sum > 0) f /= sum;
grid[gridId][i][j] = z + (v + 0.1*f)*0.99;
}
}
simTm += dt;
}
for(int i = 0; i < SIZE; ++i)
for(int j = SIZE-1; j >= 0; --j)
drawBox( i - SIZE*0.5 - 0.5,
j - SIZE*0.5 - 0.5,
-50,
1, 1, 50 + grid[gridId][i][j],
COLOR_AQUA );
restoreState();
saveState();
noFill();
text(10, 10, "try left and right mouse buttons");
restoreState();
}
int main() {
windowSetTitle("Water");
windowSetVariableFrameRate();
windowSetResizable(TRUE);
windowSetInit(&init);
windowSetDraw(&draw);
windowRun();
return 0;
}