#ifdef WIN32 #include #include #endif #include #include #include "glut.h" #include "linmath.h" #include "texture.h" #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif struct Texture *floorTexture=NULL; int mWinWidth; int mWinHeight; void setCamera(); int trigSpecialEvent=0; static void setupTexture(struct Texture *tx) { glGenTextures(1,&tx->mTextureNum); glBindTexture(GL_TEXTURE_2D,tx->mTextureNum); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // this is nicest available mipmap interpolation gluBuild2DMipmaps(GL_TEXTURE_2D, 3, tx->mWidth, tx->mHeight, GL_RGB, GL_UNSIGNED_BYTE, tx->mRGB); } static void drawStuff() { GLfloat light[4]={0.9,0.9,0.9,0.5}; GLfloat dark[4]={0.2,0.2,0.2,1}; glPushAttrib(GL_ENABLE_BIT); glMatrixMode(GL_MODELVIEW); // Tell OpenGL that we want to push the modelview matrix (not projection or texture matrix) glPushMatrix(); glMaterialfv(GL_FRONT, GL_SPECULAR, light); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20); glBegin(GL_TRIANGLES); glEnd(); glPopMatrix(); glPopAttrib(); } static void setupLight(void) { GLfloat white[3]={1,1,1}; GLfloat pos[4]={0,2,5,1}; /* set colors to white for light 0, and set its position */ glLightfv(GL_LIGHT0, GL_AMBIENT, white); glLightfv(GL_LIGHT0, GL_DIFFUSE, white); glLightfv(GL_LIGHT0, GL_SPECULAR, white); glLightfv(GL_LIGHT0, GL_POSITION, pos); glEnable(GL_LIGHT0); /* enable light 0 */ glEnable(GL_LIGHTING); /* enable lighting */ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); glEnable(GL_NORMALIZE); } static void drawFloor(void) { GLfloat black[4]={0,0,0,1}; GLfloat grey[4]={0.6,0.6,0.6,1}; GLfloat darkgrey[4]={0.2,0.2,0.2,1.0}; /* enable texturing and set floorTexture to active */ //glEnable(GL_TEXTURE_2D); //glBindTexture(GL_TEXTURE_2D, floorTexture->mTextureNum); glColor3fv(grey); // Used when lighting is disabled // Material is used when lighting is enabled glMaterialfv(GL_FRONT, GL_AMBIENT, darkgrey); glMaterialfv(GL_FRONT, GL_DIFFUSE, grey); glMaterialfv(GL_FRONT, GL_SPECULAR, black); glMaterialfv(GL_FRONT, GL_EMISSION, black); glMateriali(GL_FRONT, GL_SHININESS, 0); // No shininess glBegin(GL_POLYGON); glNormal3f(0,1,0); glTexCoord2f(1,1); glVertex3f( 4.0,-1.74, 4.0); glNormal3f(0,1,0); glTexCoord2f(1,0); glVertex3f( 4.0,-1.74,-4.0); glNormal3f(0,1,0); glTexCoord2f(0,0); glVertex3f(-4.0,-1.74,-4.0); glNormal3f(0,1,0); glTexCoord2f(0,1); glVertex3f(-4.0,-1.74, 4.0); glEnd(); //glDisable(GL_TEXTURE_2D); } void display(void) { /* clear screen (Z-buffer and color buffer) */ glClearColor(0.2,0.2,0.8,1.0); // Set clear color glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clears the color buffer and the z-buffer setCamera(); drawFloor(); drawStuff(); glutSwapBuffers(); // swap front and back buffer // This frame has now been displayed. } void handleKeys(unsigned char key, int x, int y) { switch(key) { case 27: /* ESC */ exit(0); /* dirty exit */ break; /* unnecessary, I know */ case 32: /* space */ break; } } void handleSpecialKeys(int key, int x, int y) { switch(key) { case GLUT_KEY_LEFT: printf("Left arrow\n"); break; case GLUT_KEY_RIGHT: printf("Right arrow\n"); break; case GLUT_KEY_UP: case GLUT_KEY_DOWN: break; } } /* global variables for navigation */ static int lbut_state = 1; static int mbut_state = 1; static int rbut_state = 1; static int prev_x = 0; static int prev_y = 0; void mouse(int button, int state, int x, int y) { /* button=GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, or GLUT_RIGHT_BUTTON, */ printf("button: %d, state=%d, (x,y)=(%d,%d)\n",button,state,x,y); prev_x = x; prev_y = y; switch(button) { case 0: if(lbut_state != state) trigSpecialEvent = !trigSpecialEvent; lbut_state = state; /* up/down/left/right */ break; case 1: mbut_state = state; /* zoom in/out */ break; case 2: rbut_state = state; /* rotate around the rotation center */ default: break; } } static float radius = 8; static float y_angle= M_PI/4; // angle around y-axis static float theta_angle=M_PI/4; // angle to y-plane (plane with the y-axis as normal and containing origo) void setCamera() { const Vec3f viewat = {0,0,0}; const Vec3f viewup = {0,1,0}; const Vec3f yaxis = {0,1,0}; Vec3f viewpos = {0,0,1}; Vec3f tmpvec; Mat33f rotmat; // Rotate around y-axis V3SET3(viewpos, 0,0,radius); M33RotationAxis(yaxis, y_angle,rotmat); // create the rotation matrix M33MULTVEC(tmpvec, rotmat, viewpos); V3SET(viewpos, tmpvec); // update viewvec // Rotate around y-plane V3CROSS(tmpvec, viewpos, yaxis); V3NORMALIZEF(tmpvec); // axis in y-plane to rotate around M33RotationAxis(tmpvec, theta_angle, rotmat); // create the rotation matrix M33MULTVEC(tmpvec, rotmat, viewpos); V3SET(viewpos, tmpvec); // update viewvec /* set projection matrix */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* reset */ gluPerspective(45.0,(float)mWinWidth/(float)mWinHeight, 0.2,30.0); /* FOV, aspect ratio, near, far */ /* set modelview matrix */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(viewpos[X],viewpos[Y],viewpos[Z], viewat[X],viewat[Y],viewat[Z], viewup[X],viewup[Y],viewup[Z]); } void motion(int x, int y) { int delta_x = x - prev_x; int delta_y = y - prev_y; printf("Motion: %d %d\n",x,y); // ZOOM if(mbut_state == 0) { radius -= delta_y * 0.3; radius = max(0.1, radius); } // ROTATE AROUND ORIGIN if(lbut_state == 0) { y_angle += delta_x * 0.3 * M_PI/180.0; theta_angle += delta_y * 0.3 * M_PI/180.0; theta_angle = min((M_PI/2.0)-0.05, theta_angle); theta_angle = max(-(M_PI/2.0)+0.05, theta_angle); if(y_angle > M_PI*2) y_angle -= M_PI*2; if(y_angle < -M_PI*2) y_angle += M_PI*2; } // If we did not call glutPostRedisplay() in idle(), we would have to explicitly call // it from here. It marks the current window as needing to be redisplayed. The next // iteration through glutMainLoop, the window’s display callback will be called to redisplay // the window. Multiple calls to glutPostRedisplay generates only a single redisplay callback. prev_x = x; prev_y = y; } void reshape(int width, int height) { mWinWidth=width; mWinHeight=height; glViewport(0, 0, mWinWidth, mWinHeight); } void idle( void ) { glutPostRedisplay(); // Tell glut that the window // needs to be redisplayed again. This forces the display to be redrawn // over and over again. } int main(int argc, char *argv[]) { /* init GLUT */ glutInit(&argc, argv); /* open window of size 800x600 with double buffering, RGB colors, and Z-buffering */ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); mWinWidth = 800; mWinHeight = 600; glutInitWindowSize(800,600); glutCreateWindow("RTR: Hemuppgift 2"); glutKeyboardFunc(handleKeys); glutSpecialFunc(handleSpecialKeys); /* the display function is called once when the gluMainLoop is called, * but also each time the window has to be redrawn due to window * changes (overlap, resize, etc). It can also be forced to be called * by making a glutPostRedisplay() call */ glutDisplayFunc(display); // This is the main redraw function glutMouseFunc(mouse); // callback function on mouse buttons glutMotionFunc(motion); // callback function on mouse movements glutReshapeFunc(reshape); // Called on resizing of the screen glutIdleFunc( idle ); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); /* enable Z-buffering */ glDisable(GL_CULL_FACE); /* show back faces of triangle */ /* make sure we use the entire window */ glViewport(0, 0, mWinWidth, mWinHeight); /* read texture */ floorTexture=readPPM("balls4.ppm"); if(!floorTexture) { printf("Could not read texture. Exiting\n"); exit(1); } setupTexture(floorTexture); glutMainLoop(); /* start the program main loop */ return 0; }