/**************************************** Program to draw a Shaded Cube Programmed by Olac Fuentes Last modified November 10, 2009 CS3370 *****************************************/ #include "stdafx.h" #include #include #include "glut.h" #include using namespace std; // Define a constant for the value of PI, from [2] #define GL_PI 3.1415926535f // Rotation amounts, from [2] static GLfloat xRot =25.0; static GLfloat yRot =-25.0; GLfloat nRange = 100.0f; // display window size int winWidth=600; int winHeight=600; float water_level =0; int randSeed; float h=10; float colorLimit[] = {1.,.7,.4,0}; float ls[] = {1000,700,10}; float frx=winWidth/(2*nRange); float fry=winHeight/(2*nRange); float max_height = 150; float height = 0; float h_inc = .1; float t=0; float r = 50; // converts from degrees to radians struct wcPt3D { // adapted from [1] GLfloat x, y, z; }; void setwcPt3D(wcPt3D& p, float x, float y, float z){ p.x=x;p.y=y;p.z=z; } wcPt3D p[1000]; // vertices counter int vx_c=0; // Modes int op_mode=1; // 0: Points, 1: Polygons int fill_poly=1; // 0: wire, 1: filled float axis_size=70.0; int axis_on=0; int smooth_color_on=0; float fx,fy,fz,fx_old,fy_old,fz_old; /**************************************/ void draw_axis() { glBegin (GL_LINES); glColor3f (1.0, 0.0, 0.0); // X: Red glVertex3f (-axis_size*0.2, 0.0, 0.0); glVertex3f (axis_size, 0.0, 0.0); glColor3f (0.0, 1.0, 0.0); // Y: Green glVertex3f (0.0, -axis_size*0.2, 0.0); glVertex3f (0.0, axis_size, 0.0); glColor3f (0.0, 0.0, 1.0); // Z: Blue glVertex3f (0.0, 0.0, -axis_size*0.2); glVertex3f (0.0, 0.0, axis_size); glEnd ( ); } // Keyboard Functions void operations(GLubyte sizeFactor, GLint xMouse, GLint yMouse){ switch (sizeFactor){ case ('q' | 'Q') : exit(0); break; case ('X') : ls[0] += 47; break; case ('x') : ls[0] -= 47; break; case ('Y') : ls[1] += 47; break; case ('y') : ls[1] -= 47; break; case ('Z') : ls[2] += 47; break; case ('z') : ls[2] -= 47; break; default: break; } glutPostRedisplay(); } void computeNormal(wcPt3D p0,wcPt3D p1,wcPt3D p2,float v[]){ v[0] = (p0.y-p1.y)*(p2.z-p1.z)-(p0.z-p1.z)*(p2.y-p1.y); v[1] = (p0.z-p1.z)*(p2.x-p1.x)-(p0.x-p1.x)*(p2.z-p1.z); v[2] = (p0.x-p1.x)*(p2.y-p1.y)-(p0.y-p1.y)*(p2.x-p1.x); GLfloat mag = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); v[0]/=mag; v[1]/=mag; v[2]/=mag; } float dotProduct(float v1[],float v2[]){ return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]; } float mag(float v1[]){ return sqrt(v1[0]*v1[0]+v1[1]*v1[1]+v1[2]*v1[2]); } void vertex3Dp(wcPt3D p){ glVertex3f(p.x,p.y,p.z); } void drawFloor(){ glBegin(GL_POLYGON); glColor3f (.1,.2,.4 ); glVertex3f(-2000, 0, -2000); glVertex3f(-2000, 0, 2000); glVertex3f(2000, 0, 2000); glVertex3f(2000, 0, -2000); glEnd(); } void shadedCube(float side){ static float cubeColor[] ={.8,.1,.1}; float ambient = 0.6; float residual = (1.-ambient)/2; float intensity; float normal[3]; static wcPt3D cubeVertex[8]; static wcPt3D shadowVertex[8]; int i,j,k; int c=0; //Generate Cube vertices for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++){ setwcPt3D(cubeVertex[c],i*side,j*side,k*side); c++; } // Compute coordinates of shadows for(c=0;c<8;c++){ t = cubeVertex[c].y/(cubeVertex[c].y -ls[1]); if (t>0) setwcPt3D(shadowVertex[c],0,0,0); else setwcPt3D(shadowVertex[c],cubeVertex[c].x + t*(ls[0]-cubeVertex[c].x),0,cubeVertex[c].z + t*(ls[2]-cubeVertex[c].z)); } // Draw ground plane drawFloor(); // Cube vertices for each of the six faces, in counerclockwise order int cubeFace[6][4]={{1,5,7,3},{5,4,6,7},{2,3,7,6},{0,2,6,4},{0,1,3,2},{0,4,5,1}}; // Draw shadows for(i=0;i<6;i++){ glColor3f (.05,.1,.2); glPolygonMode(GL_BACK,GL_FILL); // Backfaces cast shadows, too glBegin(GL_POLYGON); for(j=0;j<4;j++) vertex3Dp(shadowVertex[cubeFace[i][j]]); glEnd(); } // Draw cube glPolygonMode(GL_BACK,GL_POINT); //Don't draw back faces for(i=0;i<6;i++){ glBegin(GL_POLYGON); computeNormal(cubeVertex[cubeFace[i][1]],cubeVertex[cubeFace[i][0]],cubeVertex[cubeFace[i][2]],normal); intensity = ambient+ residual*dotProduct(ls,normal)/mag(ls)/mag(normal); glColor3f (intensity*cubeColor[0],intensity*cubeColor[1],intensity*cubeColor[2]); for(j=0;j<4;j++) vertex3Dp(cubeVertex[cubeFace[i][j]]); glEnd(); } } void initParticles(){ for (int i=0;i<1000;i++){ p[i].x = h*(1.0*rand()/RAND_MAX-.5); p[i].y = -height+0*h*(1.0*rand()/RAND_MAX-.5); p[i].z = r+h*(1.0*rand()/RAND_MAX-.5); } fx=0; fy=-height; fz = r; glColor3f (.8,0,0); glPointSize(1); } void particles(){ draw_axis(); height +=h_inc; if ((height>max_height)|(height <- 0)) h_inc= -h_inc; t+=.01; fx_old = fx; fy_old = fy; fz_old = fz; fx = r*sin(t); fz = r*cos(t); fy = height; glColor3f (.8,0,0); //cout << p[0].x <<" "<< p[0].y <<" "<< p[0].z <<"\n"; //cout << fx <<" "<< fy <<" "<< fz <<"\n"; glBegin(GL_POINTS); for (int i=0;i<200;i++){ glVertex3f(p[i].x,p[i].y,p[i].z); p[i].x += (fx-fx_old) * (.8 + .25*(1.*rand()/RAND_MAX-.5)) + .05*h*(1.0*rand()/RAND_MAX-.5); p[i].y += (fy-fy_old) * (.8 + .25*(1.*rand()/RAND_MAX-.5)) + .025*h*(1.0*rand()/RAND_MAX-.5); p[i].z += (fz-fz_old) * (.8 + .25*(1.*rand()/RAND_MAX-.5)) + .05*h*(1.0*rand()/RAND_MAX-.5); } glEnd( ); } /**********************************************************************/ // Called to draw scene, adapted from [2] void RenderScene(void) { // Storeage for coordinates and angles // Clear the window with current clearing color //glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT); // Save matrix state and do the rotation glPushMatrix(); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); if (axis_on) draw_axis(); glPolygonMode(GL_BACK,GL_POINT); glPolygonMode(GL_FRONT,GL_FILL); GLfloat step = GL_PI/20.; GLfloat r=50.0; //particles(); shadedCube(50); // Restore transformations glPopMatrix(); // Flush drawing commands glutSwapBuffers(); } // This function does any needed initialization on the rendering // context. from [2] void SetupRC() { // Black background glClearColor(0.0f, 0.0f, 0.0f, 1.0f ); // Set drawing color to green glColor3f(0.0f, 1.0f, 0.0f); // glEnable(GL_DEPTH_TEST); } // adapted from [2] void SpecialKeys(int key, int x, int y) { if(key == GLUT_KEY_UP) xRot-= 5.0f; if(key == GLUT_KEY_DOWN) xRot += 5.0f; if(key == GLUT_KEY_LEFT) yRot -= 5.0f; if(key == GLUT_KEY_RIGHT) yRot += 5.0f; glutPostRedisplay(); } // adapted from [2] void ChangeSize(int w, int h) { // Prevent a divide by zero if(h == 0) h = 1; // Set Viewport to window dimensions glViewport(0, 0, w, h); // Reset projection matrix stack glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Establish clipping volume (left, right, bottom, top, near, far) if (w <= h) glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -2*nRange, 2*nRange); else glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -2*nRange, 2*nRange); // Reset Model view matrix stack glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void display_commands(){ cout << "Use the direction keys to rotate the sphere\n"; cout << "Keyboard Function:\n"; cout << " X: Increase X light\n"; cout << " x: Decrease X light\n"; cout << " Y: Increase Y light\n"; cout << " y: Decrease Y light\n"; cout << " Z: Increase Y light\n"; cout << " z: Decrease Y light\n"; cout << " Q: quit the program\n"; cout << "\n"; } // adapted from [2] int main(int argc, char* argv[]) { glutInit(&argc, argv); // glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //No depth buffer for cube glutInitWindowPosition (800, 200); glutInitWindowSize(winWidth, winHeight); display_commands(); glutCreateWindow("Shaded cube with cast shadows"); glutReshapeFunc(ChangeSize); glutKeyboardFunc (operations); glutSpecialFunc(SpecialKeys); glutDisplayFunc(RenderScene); SetupRC(); srand(time(NULL)); randSeed = rand(); initParticles(); glutMainLoop(); return 0; }