diff --git a/water.c b/water.c new file mode 100644 index 0000000..fa9d7e6 --- /dev/null +++ b/water.c @@ -0,0 +1,174 @@ + +#include +#include +#include + + +#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; +}