#include <iostream>
#include <GL/glut.h>

int width  = 800;
int height = 600;

#define WATER_LEN 256
#define WATER_SCALE 2
double** water1;
double** water;
int active = 0;

void display_func ();

void mouse_func (int button, int button_state, int x, int y)
{
  std::cout << "MouseButton: " << button << " " << button_state << " " 
         << x << " " << y << std::endl;
  active = !button_state;

  int i = x*WATER_LEN/800;
  int j = WATER_LEN - (y*WATER_LEN/600);

  if (button == 0)
    {
      std::cout << "Splash1" << std::endl;
      int size = 50;
      for(int y = -size; y <  size; ++y)
        for(int x = -size; x < size; ++x)
          {
            double r = sqrt(x*x + y*y);
            double q = size*size - r*r;
            if (q > 0 
                && (i+x < WATER_LEN) && (i+x > 0)
                && (i+y < WATER_LEN) && (i+y > 0))
              {
                water [i+x][j+y] += sqrt(q)*0.01;
                water1[i+x][j+y] = water [i+x][j+y];
              }
          }
    }
  else
    {
      water[i][j]  = -5.91f;
      water1[i][j] = -5.9f;
    }
}

void idle_func ()
{
  static double t = 0.0f;

  t += .1f;

  double c = 1.0f;
  double h = 1.0f;
  double dt = 0.1f;

  double A = c*dt/h * c*dt/h;
  double B = 2 - 4*A;   // use 2*A for 2d

  for(int j = 1; j < WATER_LEN - 1; ++j)
    for(int i = 1; i < WATER_LEN - 1; ++i)
      {
        water1[i][j] = A*(water[i-1][j-1] + water[i+1][j-1] + water[i-1][j+1] + water[i+1][j+1])
                        + B*water[i][j] - water1[i][j];
        water1[i][j] *= .999f;
      }

  std::swap(water, water1);
  
  display_func();
}

void keyboard_func (unsigned char key, int x, int y)
{
  switch (key)
    {
    case 27: // Escape
      exit(0);
      break;
    }
}

void special_func (int key, int x, int y)
{
}

void mouse_motion_func (int x, int y)
{
  /*
  if (active)
    {
  x -= 144;
  x /= 1;
  if (x > 0 && x < WATER_LEN)
     for(int i = x - 5; i < x + 5; ++i)
       water[x] += .3f;

  //std::cout << "x: " << x << std::endl;
  }*/
}

void display_func ()
{
  glClear(GL_COLOR_BUFFER_BIT);

  //glLineWidth (2);

  glPushMatrix();
  glTranslatef(-256, 0, -256);
  glScaled(1.5, 1.5, 1.5);
  glRotatef(45, 1.0, 1.0, 0.0);
  glBegin (GL_LINES);
  int step = 2;
  for(int j = step; j < WATER_LEN; j+=step)
    {
    for(int i = step; i < WATER_LEN; i+=step)
      {
        //std::cout << water[i] << std::endl;
        /*glVertex2f (144 + (i-1)*WATER_SCALE + WATER_SCALE*j,
                    water[i-1][j]*50 + 400 + WATER_SCALE*j);
        glVertex2f (144 + i*WATER_SCALE + WATER_SCALE*j, 
                    water[i][j]*50 + 400 + WATER_SCALE*j);*/

        glVertex3f ((i-step)*WATER_SCALE,
                    water[i-step][j]*50 + 400,
                    j*WATER_SCALE);
        glVertex3f (i*WATER_SCALE,
                    water[i][j]*50 + 400,
                    j*WATER_SCALE);

      }
    }
  glEnd ();
  glPopMatrix();
  glutSwapBuffers();
}

void reshape_func(int w, int h)
{
  glViewport (0,0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, w, h, 0, -100000, 100000);
  glMatrixMode(GL_MODELVIEW);
  width  = w;
  height = h;
}

int main(int argc, char** argv)
{
  water  = new double*[WATER_LEN];
  water1 = new double*[WATER_LEN];
  
  for(int i = 0; i < WATER_LEN; ++i)
    {
      water[i]  = new double[WATER_LEN];
      water1[i] = new double[WATER_LEN];

      for(int j = 0; j < WATER_LEN; ++j)
        {
          water[i][j] = 0;
          water1[i][j] = 0;
        }
    }

  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
  glutInitWindowSize(width, height);
  //glutInitWindowPosition(100, 100); don't care
  glutSetWindow(glutCreateWindow("Water Simulation"));

  glutDisplayFunc(::display_func);
  glutReshapeFunc(::reshape_func);
  glutMouseFunc(::mouse_func);

  glutMotionFunc (::mouse_motion_func);
  glutPassiveMotionFunc (::mouse_motion_func);

  glutIdleFunc (::idle_func);
  glutKeyboardFunc(::keyboard_func);
  glutSpecialFunc(::special_func);

  glClearColor (0.0, 0.0, 0.0, 0.1);

  glutMainLoop(); 
}

/* EOF */


