// Peter Bui // CSE 40166 Computer Graphics (Fall 2010) // Example 13: wagon #include "color.h" #include #include #include #ifdef __APPLE__ #include #else #include #endif using namespace std; // Constants ------------------------------------------------------------------- #define WHEEL_UP 3 #define WHEEL_DOWN 4 #define CAMERA_DISTANCE_MIN 1.0 #define CAMERA_DISTANCE_MAX 100.0 enum { DL_WAGON = 1, DL_GRID, DL_JENNY_CUB, DL_BOX }; enum { CAMERA_FIRST_PERSON, CAMERA_BIRDS_EYE, CAMERA_THIRD_PERSON, CAMERA_ORBIT }; // Global variables ------------------------------------------------------------ static size_t WindowWidth = 640; static size_t WindowHeight = 480; static GLint MouseX = 0; static GLint MouseY = 0; static double CameraLatitude = 45.0; static double CameraLongitude = 25.0; static double CameraDistance = 50.0; static double EyeX = -100.0; static double EyeY = 50.0; static double EyeZ = 100.0; static double DirX = 0.0; static double DirY = 0.0; static double DirZ = 0.0; static double WagonOrientation = 0.0; static double WagonSpeed = 0.0; static double WagonX = 0.0; static double WagonZ = 0.0; static double WagonLength = 10.0; static double WagonWidth = 4.0; static double WagonSideWidth = 0.5; static double JennyCubOrientation = 0.0; static double JennyCubOrientationDelta = 2.0; static GLUquadric *Quadric = NULL; static int CameraMode = CAMERA_ORBIT; static bool WireFrameMode = false; // Update camera --------------------------------------------------------------- void update_camera_location() { double L = CameraDistance * cos(M_PI*CameraLongitude/180.0); switch (CameraMode) { case CAMERA_ORBIT: EyeX = WagonX + L * -sin(M_PI*CameraLatitude/180.0); EyeY = CameraDistance * sin(M_PI*CameraLongitude/180.0); EyeZ = WagonZ + L * cos(M_PI*CameraLatitude/180.0); DirX = WagonX; DirY = 0.0; DirZ = WagonZ; break; case CAMERA_BIRDS_EYE: EyeX = WagonX; EyeY = CameraDistance; EyeZ = WagonZ; DirX = WagonX; DirY = 0.0; DirZ = WagonZ - 0.01; break; case CAMERA_FIRST_PERSON: EyeX = WagonX; EyeY = 6.0; EyeZ = WagonZ; DirX = WagonX + CameraDistance*cos(WagonOrientation*M_PI/180.0); DirY = 6.0; DirZ = WagonZ - CameraDistance*sin(WagonOrientation*M_PI/180.0); break; case CAMERA_THIRD_PERSON: EyeX = WagonX - CameraDistance*cos(WagonOrientation*M_PI/180.0); EyeY = 10.0; EyeZ = WagonZ + CameraDistance*sin(WagonOrientation*M_PI/180.0); DirX = WagonX + CameraDistance/2.0*cos(WagonOrientation*M_PI/180.0); DirY = 10.0; DirZ = WagonZ - CameraDistance/2.0*sin(WagonOrientation*M_PI/180.0); } glutPostRedisplay(); } // Initialize scene ------------------------------------------------------------ void init_scene() { glEnable(GL_DEPTH_TEST); GLfloat diffuse0[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat ambient0[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat specular0[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat position0[] = { 100.0, 100.0, 100.0, 1.0 }; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0); glLightfv(GL_LIGHT0, GL_SPECULAR, specular0); glLightfv(GL_LIGHT0, GL_POSITION, position0); glEnable(GL_COLOR_MATERIAL) ; glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glEnable(GL_NORMALIZE); glEnable(GL_SMOOTH); if (Quadric == NULL) Quadric = gluNewQuadric(); update_camera_location(); } // Draw wagon ------------------------------------------------------------------ void draw_wagon_base() { glPushMatrix(); { glScalef(WagonLength, 1.0, WagonWidth); glutSolidCube(1.0); } glPopMatrix(); } void draw_wagon_side(double tx, double ty, double tz, double sx, double sy, double sz) { glPushMatrix(); { glTranslatef(tx, ty, tz); glScalef(sx, sy, sz); glutSolidCube(1.0); } glPopMatrix(); } void draw_wagon_logo(double tx, double ty, double tz, bool reflect) { glPushMatrix(); { glPushAttrib(GL_LINE_BIT); glColor3f(1.0, 1.0, 1.0); glLineWidth(4.0); glTranslatef(tx, ty, tz); glScalef(reflect ? -0.01 : 0.01, 0.01, 0.01); for (const char *c = "Radio Flyer"; *c; c++) glutStrokeCharacter(GLUT_STROKE_ROMAN, *c); glPopAttrib(); } glPopMatrix(); } void draw_wagon_body() { glColor3f(1.0, 0.0, 0.0); draw_wagon_base(); draw_wagon_side(0.0, 1.0, -(WagonWidth/2.0 - WagonSideWidth/2.0), WagonLength, 1.0, WagonSideWidth); draw_wagon_side(0.0, 1.0, (WagonWidth/2.0 - WagonSideWidth/2.0), WagonLength, 1.0, WagonSideWidth); draw_wagon_side( (WagonLength/2.0 - WagonSideWidth/2.0), 1.0, 0.0, WagonSideWidth, 1.0, WagonWidth); draw_wagon_side(-(WagonLength/2.0 - WagonSideWidth/2.0), 1.0, 0.0, WagonSideWidth, 1.0, WagonWidth); draw_wagon_logo(-WagonLength/2.0*0.75, 0.0, WagonWidth/2.0, false); draw_wagon_logo( WagonLength/2.0*0.75, 0.0, -WagonWidth/2.0, true); } void draw_wagon_wheel(double tx, double ty, double tz) { glPushMatrix(); { glTranslatef(tx, ty, tz); glColor3f(1.0, 1.0, 1.0); gluDisk(Quadric, 0.0, 1.0, 24, 24); glColor3f(0.0, 0.0, 1.0); glutSolidTorus(0.5, 0.9, 24, 24); } glPopMatrix(); } void draw_wagon_spoke(double tx, double ty, double tz, double length) { glPushMatrix(); { glTranslatef(tx, ty, tz); glColor3f(0.0, 1.0, 0.0); gluCylinder(Quadric, 0.5, 0.5, length, 24, 24); glTranslatef(0.0, 0.30, -tz); glRotatef(-90.0, 1.0, 0.0, 0.0); glutSolidCone(0.25, 1.0, 24, 24); } glPopMatrix(); } void draw_wagon_wheels() { draw_wagon_wheel(-WagonLength/2.0*0.75, -1.75, -WagonWidth/2.0 - 0.5); draw_wagon_wheel(-WagonLength/2.0*0.75, -1.75, WagonWidth/2.0 + 0.5); draw_wagon_wheel( WagonLength/2.0*0.75, -1.75, WagonWidth/2.0 + 0.5); draw_wagon_wheel( WagonLength/2.0*0.75, -1.75, -WagonWidth/2.0 - 0.5); draw_wagon_spoke(-WagonLength/2.0*0.75, -1.75, -WagonWidth/2.0 - 0.5, WagonWidth + 1.0); draw_wagon_spoke( WagonLength/2.0*0.75, -1.75, -WagonWidth/2.0 - 0.5, WagonWidth + 1.0); } void draw_wagon() { draw_wagon_body(); draw_wagon_wheels(); } // Draw jenny cub -------------------------------------------------------------- void draw_jenny_cub_body() { glPushMatrix(); { glColor3f(0.75, 0.5, 0.0); glRotatef(-90.0, 1.0, 0.0, 0.0); glutSolidCone(1.5, 2.0, 24, 24); } glPopMatrix(); } void draw_jenny_cub_ears() { glPushMatrix(); { glRotatef(90.0, 0.0, 1.0, 0.0); glPushMatrix(); { glTranslatef( cos(M_PI/5), sin(M_PI/5), 0.0); glutSolidTorus(0.15, 0.25, 24, 24); gluDisk(Quadric, 0.0, 0.25, 24, 24); } glPopMatrix(); glPushMatrix(); { glTranslatef(-cos(M_PI/5), sin(M_PI/5), 0.0); glutSolidTorus(0.15, 0.25, 24, 24); gluDisk(Quadric, 0.0, 0.25, 24, 24); } glPopMatrix(); } glPopMatrix(); } void draw_jenny_cub_eyes() { glPushAttrib(GL_ALL_ATTRIB_BITS); glColor3f(0.0, 0.0, 0.0); glPushMatrix(); { glTranslatef(0.9*cos(M_PI*0.1), 0.3, 0.9*sin(M_PI*0.1)); glutSolidSphere(0.1, 24, 24); } glPopMatrix(); glPushMatrix(); { glTranslatef(0.9*cos(M_PI*0.1), 0.3, -0.9*sin(M_PI*0.1)); glutSolidSphere(0.1, 24, 24); } glPopMatrix(); glPopAttrib(); } void draw_jenny_cub_nose() { glPushAttrib(GL_ALL_ATTRIB_BITS); glColor3f(0.0, 0.0, 0.0); glPushMatrix(); { glTranslatef(0.5*0.9*cos(M_PI*0.1), 0.5*0.9*sin(M_PI*0.1), 0.0); glutSolidSphere(0.15, 24, 24); } glPopMatrix(); glPopAttrib(); } void draw_jenny_cub_head() { glPushMatrix(); { glColor3f(0.75, 0.5, 0.0); glTranslatef(0.0, 2.5, 0.0); glutSolidSphere(1.0, 24, 24); draw_jenny_cub_ears(); draw_jenny_cub_eyes(); glTranslatef(0.75, -0.25, 0.0); glutSolidSphere(0.5, 24, 24); draw_jenny_cub_nose(); } glPopMatrix(); } void draw_jenny_cub() { draw_jenny_cub_body(); draw_jenny_cub_head(); } // Draw grid ------------------------------------------------------------------- void draw_grid() { glPushMatrix(); glPushAttrib(GL_LIGHTING_BIT); { glDisable(GL_LIGHTING); glScalef(5.0, 5.0, 5.0); for(int k = 0; k < 2; k++) { for(int i = -50; i < 51; i++) { glBegin(GL_LINE_STRIP); { for(int j = -50; j < 51; j++) { glColor3fv(color_rotate()); glVertex3f(k == 0 ? i : j, 0, k == 0 ? j : i); } } glEnd(); } } } glPopAttrib(); glPopMatrix(); } // Make display lists ---------------------------------------------------------- void make_display_lists() { glNewList(DL_WAGON, GL_COMPILE); { draw_wagon(); }; glEndList(); glNewList(DL_JENNY_CUB, GL_COMPILE); { draw_jenny_cub(); }; glEndList(); glNewList(DL_GRID, GL_COMPILE); { draw_grid(); }; glEndList(); glNewList(DL_BOX, GL_COMPILE); { glBegin(GL_POLYGON); { glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f( 0.5, 0.5); glVertex2f( 0.5, -0.5); } glEnd(); }; glEndList(); } // Draw scene ------------------------------------------------------------------ void draw_scene() { glViewport(0, 0, WindowWidth, WindowHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (GLdouble)WindowWidth/(GLdouble)WindowHeight, 1.0, 750.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(EyeX, EyeY, EyeZ, DirX, DirY, DirZ, 0.0, 1.0, 0.0); glPolygonMode(GL_FRONT_AND_BACK, WireFrameMode ? GL_LINE : GL_FILL); glEnable(GL_LIGHTING); glShadeModel(GL_SMOOTH); glPushMatrix(); { glTranslatef(WagonX, 3.0, WagonZ); glRotatef(WagonOrientation, 0.0, 1.0, 0.0); glCallList(DL_WAGON); glTranslatef(-WagonLength/4.0, 0.0, 0.0); glRotatef(JennyCubOrientation, 0.0, 1.0, 0.0); glCallList(DL_JENNY_CUB); } glPopMatrix(); glCallList(DL_GRID); } // Draw minimap ---------------------------------------------------------------- void draw_minimap() { glViewport(0, 0, WindowWidth/3, WindowHeight/3); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-250.0, 250.0, -250.0, 250.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_LIGHTING); glShadeModel(GL_FLAT); glPushMatrix(); { glTranslatef(0.0, 0.0, -0.1); glRotatef(90.0, 1.0, 0.0, 0.0); glCallList(DL_GRID); } glPopMatrix(); glPushMatrix(); { glTranslatef(WagonX, -WagonZ, 0.0); glColor3f(1.0, 0.0, 0.0); glScalef(25.0, 25.0, 1.0); glCallList(DL_BOX); } glPopMatrix(); } // Draw text ------------------------------------------------------------------- void draw_text() { char buffer[1024]; glViewport(0, 0, WindowWidth, WindowHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, WindowWidth, 0.0, WindowHeight); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_LIGHTING); glShadeModel(GL_SMOOTH); glTranslatef(WindowWidth*0.4, 10.0, 0.0); glScalef(0.1, 0.1, 1.0); glColor3f(1.0, 1.0, 0.0); snprintf(buffer, 1024, "x: %0.2lf, z: %0.2lf, ort: %0.2lf, speed: %0.2lf", WagonX, WagonZ, WagonOrientation, WagonSpeed); for (char *c = buffer; *c; c++) glutStrokeCharacter(GLUT_STROKE_ROMAN, *c); } // Display callback ------------------------------------------------------------ void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_scene(); draw_minimap(); draw_text(); glutSwapBuffers(); } // Reshape callback ------------------------------------------------------------ void reshape(GLsizei nw, GLsizei nh) { WindowWidth = nw; WindowHeight = nh; init_scene(); } // Keyboard callback ----------------------------------------------------------- void keyboard(unsigned char key, int x, int y) { switch (key) { case 'q': case 'Q': exit(EXIT_SUCCESS); break; case 'w': WireFrameMode = !WireFrameMode; break; case ' ': WagonSpeed = 0.0; break; case '0': CameraMode = CAMERA_ORBIT; WagonSpeed = 0; WagonOrientation = 0.0; WagonX = 0.0; WagonZ = 0.0; JennyCubOrientation = 0.0; break; case '1': CameraMode = CAMERA_FIRST_PERSON; break; case '2': CameraMode = CAMERA_BIRDS_EYE; break; case '3': CameraMode = CAMERA_THIRD_PERSON; break; case '4': CameraMode = CAMERA_ORBIT; break; } update_camera_location(); } // Special callback ----------------------------------------------------------- void special(int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT: WagonOrientation += 10.0; break; case GLUT_KEY_RIGHT: WagonOrientation -= 10.0; break; case GLUT_KEY_UP: WagonSpeed += 0.1; break; case GLUT_KEY_DOWN: WagonSpeed -= 0.1; break; } update_camera_location(); } // Mouse callback -------------------------------------------------------------- void mouse(int button, int state, int x, int y) { MouseX = x; MouseY = y; switch (button) { case WHEEL_UP: CameraDistance = (CameraDistance > CAMERA_DISTANCE_MIN ? CameraDistance - 1.0 : CAMERA_DISTANCE_MIN); break; case WHEEL_DOWN: CameraDistance = (CameraDistance < CAMERA_DISTANCE_MAX ? CameraDistance + 1.0 : CAMERA_DISTANCE_MAX); break; } update_camera_location(); } // Motion callback ------------------------------------------------------------- void motion(int x, int y) { CameraLatitude += 180.0*(double)(x - MouseX)/WindowWidth; CameraLongitude += 180.0*(double)(y - MouseY)/WindowHeight; if (CameraLongitude < -90.0) CameraLongitude = -90.0; if (CameraLongitude > 90.0) CameraLongitude = 90.0; MouseX = x; MouseY = y; update_camera_location(); } // Timer callback -------------------------------------------------------------- void timer(int value) { WagonX += WagonSpeed * cos(WagonOrientation*M_PI/180.0); WagonZ -= WagonSpeed * sin(WagonOrientation*M_PI/180.0); if (fabs(WagonSpeed) > 0.01) { if (JennyCubOrientation > 90.0) JennyCubOrientationDelta = -fabs(WagonSpeed)*10.0; if (JennyCubOrientation < -90.0) JennyCubOrientationDelta = fabs(WagonSpeed)*10.0; JennyCubOrientation += JennyCubOrientationDelta; } update_camera_location(); glutTimerFunc(100, timer, 0); } // Main execution -------------------------------------------------------------- int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(WindowWidth, WindowHeight); glutCreateWindow("wagon"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutSpecialFunc(special); glutMouseFunc(mouse); glutTimerFunc(100, timer, 0); glutMotionFunc(motion); init_scene(); make_display_lists(); glutMainLoop(); return (EXIT_SUCCESS); } // vim: sts=4 sw=4 ts=8 ft=cpp