/* * Simulating water (with lightning) * * Andrey Mirtchovski (aam396@mail.usask.ca) */ #include #include #include #include #include #define BOUNDS 1 #define WATERSIZE 150 #define DAMP 20 static GLuint texname; float water[2][WATERSIZE][WATERSIZE]; int spin_x, spin_y, spin_z; /* x-y rotation and zoom */ int h, w; /* height, width of window */ int old_x, old_y, move_z; int depth = 3; int i = 0; unsigned *teximage; int t = 0, f = 1; void calcwater() { int x, y; float n; for(y = 1; y < WATERSIZE-1; y++) { for(x = 1; x < WATERSIZE-1; x++) { n = ( water[t][x-1][y] + water[t][x+1][y] + water[t][x][y-1] + water[t][x][y+1] ) /2; n -= water[f][x][y]; n = n - (n / DAMP); water[f][x][y] = n; } } y = 0; for(x = 1; x < WATERSIZE-1; x++) { n = ( water[t][x-1][y] + water[t][x+1][y] + water[t][x][y+1] ) /2; n -= water[f][x][y]; n = n - (n / DAMP); water[f][x][y] = n; } x = 0; for(y = 1; y < WATERSIZE-1; y++) { n = ( water[t][x+1][y] + water[t][x][y-1] + water[t][x][y+1] ) /2; n -= water[f][x][y]; n = n - (n / DAMP); water[f][x][y] = n; } x = WATERSIZE-1; for(y = 1; y < WATERSIZE-1; y++) { n = ( water[t][x-1][y] + water[t][x][y-1] + water[t][x][y+1] ) /2; n -= water[f][x][y]; n = n - (n / DAMP); water[f][x][y] = n; } y = WATERSIZE-1; for(x = 1; x < WATERSIZE-1; x++) { n = ( water[t][x-1][y] + water[t][x+1][y] + water[t][x][y-1] ) /2; n -= water[f][x][y]; n = n - (n / DAMP); water[f][x][y] = n; } } void init(); void reshape(int width, int height) { w = width; h = height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 2000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity (); } GLfloat position[] = { 0.0, 0.0, 1.5, 1.0 }; GLfloat norm[3]; void normals(float x1, float y1,float z1, float x2,float y2,float z2, float x3,float y3,float z3) { /* calculate [1 - 2]x[2 - 3] -- the surface normals for a triangle */ float v1[3], v2[3]; float dist; /* vector1 - vector2 */ v1[0] = x1 - x2; v1[1] = y1 - y2; v1[2] = z1 - z2; /* vector2 - vector3 */ v2[0] = x2 - x3; v2[1] = y2 - y3; v2[2] = z2 - z3; /* now the cross product */ norm[0] = v1[1]*v2[2] - v1[2]*v2[1]; norm[1] = v1[2]*v2[0] - v1[0]*v2[2]; norm[2] = v1[0]*v2[1] - v1[1]*v2[0]; dist = sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]); norm[0] /= dist; norm[1] /= dist; norm[2] /= dist; } void display(void) { int i, j, tmp; float tx, ty; float texd = (float)1/WATERSIZE; /* for texture mapping */ float w = WATERSIZE/2; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv (GL_LIGHT0, GL_POSITION, position); glPushMatrix(); glTranslatef (-1.0, 1.0, -10); glDisable (GL_LIGHTING); glColor3f (0.0, 1.0, 1.0); glutWireCube (0.1); glEnable (GL_LIGHTING); glPopMatrix(); glPushMatrix(); glTranslatef(0, 0, spin_z-200); glRotatef(spin_x, 0, 1, 0); glRotatef(spin_y-60, 1, 0, 0); calcwater(); // glColor3f(0.0, 1, 1); glBegin(GL_TRIANGLES); for(i = 0; i < WATERSIZE-1; i++) { for(j = 0; j < WATERSIZE-1; j++) { tx = (float)j/WATERSIZE; ty = (float)i/WATERSIZE; normals(j-w, i-w, water[t][j][i], j+1-w, i-w, water[t][j+1][i], j+1-w, i+1-w, water[t][j+1][i+1]); glNormal3fv(norm); glVertex3f(j-WATERSIZE/2, i-WATERSIZE/2, water[t][j][i]); glVertex3f(j+1-WATERSIZE/2, i-WATERSIZE/2, water[t][j+1][i]); glVertex3f(j+1-WATERSIZE/2, i+1-WATERSIZE/2, water[t][j+1][i+1]); normals(j-w, i+1-w, water[t][j][i+1], j-w, i-w, water[t][j][i], j+1-w, i+1-w, water[t][j+1][i+1]); glNormal3fv(norm); glVertex3f(j-WATERSIZE/2, i+1-WATERSIZE/2, water[t][j][i+1]); glVertex3f(j-WATERSIZE/2, i-WATERSIZE/2, water[t][j][i]); glVertex3f(j+1-WATERSIZE/2, i+1-WATERSIZE/2, water[t][j+1][i+1]); } } glEnd(); tmp = t; t = f; f = tmp; glPopMatrix(); glutSwapBuffers(); } int num = 0; int delay = 50; void idle(void) { if(!(++num %delay)) { water[f][rand()%WATERSIZE][rand()%WATERSIZE] = -rand()%50+10; delay = rand()%100 + 100; } glutPostRedisplay(); } void bail(int code) { exit(code); } void mouse(int button, int state, int x, int y) { switch(button) { case 0: old_x = x - spin_x; old_y = y - spin_y; break; case 2: old_y = y - spin_z; move_z = (move_z ? 0 : 1); } glutPostRedisplay(); } void motion(x, y) { if(!move_z) { spin_x = x - old_x; spin_y = y - old_y; } else { spin_z = y - old_y; } glutPostRedisplay(); } void keyboard(unsigned char key, int x, int y) { static int old_x = 50; static int old_y = 50; static int old_width = 512; static int old_height = 512; switch (key) { case 27: bail(0); break; case 'w': glutPositionWindow(old_x, old_y); glutReshapeWindow(old_width, old_height); break; case 'f': if (glutGet(GLUT_WINDOW_WIDTH) < glutGet(GLUT_SCREEN_WIDTH)) { old_x = glutGet(GLUT_WINDOW_X); old_y = glutGet(GLUT_WINDOW_Y); old_width = glutGet(GLUT_WINDOW_WIDTH); old_height = glutGet(GLUT_WINDOW_HEIGHT); glutFullScreen(); } break; case ' ': water[f][WATERSIZE/2][WATERSIZE/2] = -1000; break; } } void init(void) { int i, j; GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 100.0 }; w = glutGet(GLUT_WINDOW_WIDTH); h = glutGet(GLUT_WINDOW_HEIGHT); glClearColor (0.0, 0.0, 0.0, 1.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); glShadeModel (GL_SMOOTH); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); for( i = 0; i < WATERSIZE; i++) for( j = 0; j < WATERSIZE; j++) { water[0][j][i] = 0; water[1][j][i] = 0; } } int main(int argc, char** argv) { int i; srand(time(NULL)); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowPosition(50, 50); glutInitWindowSize(512, 512); glutInit(&argc, argv); glutCreateWindow("Simulating Water"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); glEnable (GL_DEPTH_TEST); if(argc == 2) { if (strcmp(argv[1], "-h") == 0) { fprintf(stderr, "%s [depth]\n", argv[0]); exit(0); } sscanf(argv[1], "%d", &depth); } init(); glutIdleFunc(idle); glutMainLoop(); return 0; }