Blob Blame Raw

#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;
}