/*********************** * Johnny Jetpack * by Paul Adam and Jamie Bradley * * glutjohnny.c * * this file contains all the glut callbacks and the main loop structure. *************************/ #include #include #include #include #include #include #include #include #include "johnny.h" #include "animation.h" #define DEVELOPING 0 int Stop = 0; void myMouse(int button, int state, int x, int y) { /* glOrtho moved (0,0) to center of window--now must */ /* convert physical coordinates to logical coordinates */ x = x - W/2; y = H/2 - y; if(button==GLUT_LEFT_BUTTON) switch(state) { case GLUT_DOWN : if(!GameOver && !Dead && Fuel) { Thrust = 27; thrustX = x; thrustY = y; if(initialclick) { Landed = 0; Velocity[Xv] = 0; Velocity[Zv] = 0; Frame = 0; AnimationMode = 1; } initialclick = 0; } else { GameOver = 0; } break; case GLUT_UP : if(!Dead) { Thrust = 0; thrustX = 0; thrustY = 0; Frame = 0; initialclick = 1; } break; } } void myDrag(int x, int y) { int dragV[3], nextdragV[2]; x = x - W/2; y = H/2 - y; if(Thrust && !Dead) { dragV[Xv] = (x - thrustX)/3; dragV[Zv] = (y - thrustY)/3; if (dragV[Xv] > 5) AnimationMode = 3; else if (dragV[Xv] < -5) AnimationMode = 4; else AnimationMode = 1; RotateVector(JohnnyTheta,dragV,0,0); Velocity[Xv] += dragV[Xv]; Velocity[Zv] -= dragV[Zv]; nextVelocity[Xv] = 2 * Velocity[Xv] - OldDragX; nextVelocity[Zv] = 2 * Velocity[Zv] - OldDragY; if(Velocity[Xv] > MAX_VELOCITY_X) Velocity[Xv] = MAX_VELOCITY_X; if(Velocity[Xv] < -MAX_VELOCITY_X) Velocity[Xv] = -MAX_VELOCITY_X; if(Velocity[Zv] > MAX_VELOCITY_Z) Velocity[Zv] = MAX_VELOCITY_Z; if(Velocity[Zv] < -MAX_VELOCITY_Z) Velocity[Zv] = -MAX_VELOCITY_Z; if(nextVelocity[Xv] > MAX_VELOCITY_X) nextVelocity[Xv] = MAX_VELOCITY_X; if(nextVelocity[Xv] < -MAX_VELOCITY_X) nextVelocity[Xv] = -MAX_VELOCITY_X; if(nextVelocity[Zv] > MAX_VELOCITY_Z) nextVelocity[Zv] = MAX_VELOCITY_Z; if(nextVelocity[Zv] < -MAX_VELOCITY_Z) nextVelocity[Zv] = -MAX_VELOCITY_Z; OldDragX = Velocity[Xv]; OldDragY = Velocity[Zv]; } } /********************************************************** This function is a callback function, in that when the keyboard is hit, this function is called, and the key hit is in the variable key. **********************************************************/ void keyboard (unsigned char key, int x, int y) { switch(key) { /*Quit -> ESC, q, or Q*/ case 27: exit (0); break; /* legs*/ case '1': if(DEVELOPING) RightHipRotateX[AnimationMode][Frame] = (RightHipRotateX[AnimationMode][Frame] + 1) % 360; break; case '!': if(DEVELOPING) RightHipRotateX[AnimationMode][Frame] = (RightHipRotateX[AnimationMode][Frame] - 1) % 360; break; case '2': if(DEVELOPING) RightKneeRotate[AnimationMode][Frame] = (RightKneeRotate[AnimationMode][Frame] + 1) % 360; break; case '@': if(DEVELOPING) RightKneeRotate[AnimationMode][Frame] = (RightKneeRotate[AnimationMode][Frame] - 1) % 360; break; case '3': if(DEVELOPING) RightAnkleRotate[AnimationMode][Frame] = (RightAnkleRotate[AnimationMode][Frame] + 1) % 360; break; case '#': if(DEVELOPING) RightAnkleRotate[AnimationMode][Frame] = (RightAnkleRotate[AnimationMode][Frame] - 1) % 360; break; case '4': if(DEVELOPING) LeftHipRotateX[AnimationMode][Frame] = (LeftHipRotateX[AnimationMode][Frame] + 1) % 360; break; case '$': if(DEVELOPING) LeftHipRotateX[AnimationMode][Frame] = (LeftHipRotateX[AnimationMode][Frame] - 1) % 360; break; case '5': if(DEVELOPING) LeftKneeRotate[AnimationMode][Frame] = (LeftKneeRotate[AnimationMode][Frame] + 1) % 360; break; case '%': if(DEVELOPING) LeftKneeRotate[AnimationMode][Frame] = (LeftKneeRotate[AnimationMode][Frame] - 1) % 360; break; case '6': if(DEVELOPING) LeftAnkleRotate[AnimationMode][Frame] = (LeftAnkleRotate[AnimationMode][Frame] + 1) % 360; break; case '^': if(DEVELOPING) LeftAnkleRotate[AnimationMode][Frame] = (LeftAnkleRotate[AnimationMode][Frame] - 1) % 360; break; /* arms */ case '7': if(DEVELOPING) RightShoulderRotateX[AnimationMode][Frame] = (RightShoulderRotateX[AnimationMode][Frame] + 1) % 360; break; case '&': if(DEVELOPING) RightShoulderRotateX[AnimationMode][Frame] = (RightShoulderRotateX[AnimationMode][Frame] - 1) % 360; break; case '8': if(DEVELOPING) RightShoulderRotateY[AnimationMode][Frame] = (RightShoulderRotateY[AnimationMode][Frame] + 1) % 360; break; case '*': if(DEVELOPING) RightShoulderRotateY[AnimationMode][Frame] = (RightShoulderRotateY[AnimationMode][Frame] - 1) % 360; break; case '9': if(DEVELOPING) RightShoulderRotateZ[AnimationMode][Frame] = (RightShoulderRotateZ[AnimationMode][Frame] + 1) % 360; break; case '(': if(DEVELOPING) RightShoulderRotateZ[AnimationMode][Frame] = (RightShoulderRotateZ[AnimationMode][Frame] - 1) % 360; break; case '0': if(DEVELOPING) LeftShoulderRotateX[AnimationMode][Frame] = (LeftShoulderRotateX[AnimationMode][Frame] + 1) % 360; break; case ')': if(DEVELOPING) LeftShoulderRotateX[AnimationMode][Frame] = (LeftShoulderRotateX[AnimationMode][Frame] - 1) % 360; break; case '-': if(DEVELOPING) LeftShoulderRotateY[AnimationMode][Frame] = (LeftShoulderRotateY[AnimationMode][Frame] + 1) % 360; break; case '_': if(DEVELOPING) LeftShoulderRotateY[AnimationMode][Frame] = (LeftShoulderRotateY[AnimationMode][Frame] - 1) % 360; break; case '=': if(DEVELOPING) LeftShoulderRotateZ[AnimationMode][Frame] = (LeftShoulderRotateZ[AnimationMode][Frame] + 1) % 360; break; case '+': if(DEVELOPING) LeftShoulderRotateZ[AnimationMode][Frame] = (LeftShoulderRotateZ[AnimationMode][Frame] - 1) % 360; break; case 'q': if(DEVELOPING) RightElbowRotate[AnimationMode][Frame] = (RightElbowRotate[AnimationMode][Frame] + 1) % 360; break; case 'Q': if(DEVELOPING) RightElbowRotate[AnimationMode][Frame] = (RightElbowRotate[AnimationMode][Frame] - 1) % 360; break; case 'w': if(DEVELOPING) LeftElbowRotate[AnimationMode][Frame] = (LeftElbowRotate[AnimationMode][Frame] + 1) % 360; break; case 'W': if(DEVELOPING) LeftElbowRotate[AnimationMode][Frame] = (LeftElbowRotate[AnimationMode][Frame] - 1) % 360; break; case 'e': if(DEVELOPING) RightWristRotate[AnimationMode][Frame] = (RightWristRotate[AnimationMode][Frame] + 1) % 360; break; case 'E': if(DEVELOPING) RightWristRotate[AnimationMode][Frame] = (RightWristRotate[AnimationMode][Frame] - 1) % 360; break; case 'r': if(DEVELOPING) LeftWristRotate[AnimationMode][Frame] = (LeftWristRotate[AnimationMode][Frame] + 1) % 360; break; case 'R': if(DEVELOPING) LeftWristRotate[AnimationMode][Frame] = (LeftWristRotate[AnimationMode][Frame] - 1) % 360; break; /* trunk */ case 't': if(DEVELOPING) ChestRotateX[AnimationMode][Frame] = (ChestRotateX[AnimationMode][Frame] + 1) % 360; break; case 'T': if(DEVELOPING) ChestRotateX[AnimationMode][Frame] = (ChestRotateX[AnimationMode][Frame] - 1) % 360; break; case 'y': if(DEVELOPING) ChestRotateY[AnimationMode][Frame] = (ChestRotateY[AnimationMode][Frame] + 1) % 360; break; case 'Y': if(DEVELOPING) ChestRotateY[AnimationMode][Frame] = (ChestRotateY[AnimationMode][Frame] - 1) % 360; break; case 'u': if(DEVELOPING) ChestRotateZ[AnimationMode][Frame] = (ChestRotateZ[AnimationMode][Frame] + 1) % 360; break; case 'U': if(DEVELOPING) ChestRotateZ[AnimationMode][Frame] = (ChestRotateZ[AnimationMode][Frame] - 1) % 360; break; case 'i': if(DEVELOPING) NeckRotate[AnimationMode][Frame] = (NeckRotate[AnimationMode][Frame] + 1) % 360; break; case 'I': if(DEVELOPING) NeckRotate[AnimationMode][Frame] = (NeckRotate[AnimationMode][Frame] -1) % 360; break; case 'o': if(DEVELOPING) TummyRotate[AnimationMode][Frame] = (TummyRotate[AnimationMode][Frame] + 1) % 360; break; case 'O': if(DEVELOPING) TummyRotate[AnimationMode][Frame] = (TummyRotate[AnimationMode][Frame] - 1) % 360; break; case 'p': if(DEVELOPING) BodyRotateX[AnimationMode][Frame] = (BodyRotateX[AnimationMode][Frame] + 1) % 360; break; case 'P': if(DEVELOPING) BodyRotateX[AnimationMode][Frame] = (BodyRotateX[AnimationMode][Frame] - 1) % 360; break; case 'a': if(DEVELOPING) BodyRotateY[AnimationMode][Frame] = (BodyRotateY[AnimationMode][Frame] + 1) % 360; break; case 'A': if(DEVELOPING) BodyRotateY[AnimationMode][Frame] = (BodyRotateY[AnimationMode][Frame] - 1) % 360; break; case 's': if(DEVELOPING) BodyRotateZ[AnimationMode][Frame] = (BodyRotateZ[AnimationMode][Frame] + 1) % 360; break; case 'S': if(DEVELOPING) BodyRotateZ[AnimationMode][Frame] = (BodyRotateZ[AnimationMode][Frame] - 1) % 360; break; case 'd': if(DEVELOPING) BodyMoveY[AnimationMode][Frame] = (BodyMoveY[AnimationMode][Frame] + 1) % 360; break; case 'D': if(DEVELOPING) BodyMoveY[AnimationMode][Frame] = (BodyMoveY[AnimationMode][Frame] - 1) % 360; break; case 'g': if(DEVELOPING) PrintPose(AnimationMode,Frame); break; } return; } static void speckeyboard(int key, int x, int y) { switch (key) { case GLUT_KEY_RIGHT: JohnnyTheta = (JohnnyTheta - 5) % 360; break; case GLUT_KEY_LEFT: JohnnyTheta = (JohnnyTheta + 5) % 360; break; } } /********************************************************* When a choice is made from the menu, this function is called and it consists of toggles, or to quit *********************************************************/ void selectMainMenu(int sel) { switch(sel) { case 7: /*toggle fill*/ FILL = !FILL; break; case 10: /*quit*/ exit(0); break; } glutPostRedisplay(); /*redraw the object*/ return; } /****************************************************** This is a callback function, that is called when the object needs to be redisplayed (due to a rotation, translation, or menu resize, etc.). ******************************************************/ void display (void) { float yavg, xavg, zavg, avg; /*set window parameters*/ glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable (GL_DEPTH_TEST); glViewport(0, 0, W, H); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective (FOVY, (GLfloat)W/H, 1, 10000); glDepthFunc(GL_LESS); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); yavg = (y_min+y_max)/2; if ((yavg<.1) && (yavg>-0.1)) yavg = y_max; xavg = (x_min+x_max)/2; if ((xavg<.1) && (xavg>-0.1)) xavg = x_max; avg = sqrt (xavg*xavg + yavg*yavg); gluLookAt(0, 0, avg/sin(FOVY*RADIANS), 0, 0, 0, 0, 1, 0); if (!GameOver) { UpdateVelocity(); UpdateJohnny(); /* camera zooming */ glPushMatrix(); glTranslatef(0,0,Z); /*move the world around Johnny*/ glPushMatrix(); glTranslatef(-JohnnyX, -JohnnyY, -JohnnyZ); glTranslatef(JohnnyX, JohnnyY, JohnnyZ); glRotatef(-JohnnyTheta, 0, 1, 0); glTranslatef(-JohnnyX, -JohnnyY, -JohnnyZ); glRotatef(rotatey, 0, 1, 0); glRotatef(rotatex, 1, 0, 0); glRotatef(rotatez, 0, 0, 1); /*lighting*/ if (LIGHTS) lighting(); else disable(); /*fill, or just wireframe?*/ if (!FILL) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); else { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glShadeModel(GL_FLAT); } /*****************************************************************************/ /*****now draw the stuff to the screen***************/ /*Set material*/ glColor3f(0.0, 0.0, 0.0); Set_Mat(gray); UpdateFuel(); if(Fuel) DrawAllPlatforms(); DrawCoins(Coins,NumCoins); DrawFuelCans(FuelCans,NumFuelCans); DrawAllLava(); /* DrawJohnnyBound(); DrawNextJohnnyBound(); */ /* end move world around johnny */ glPopMatrix(); /*draw the johnny model*/ DrawJohnny(); /*if there's no fuel, let johnny fall into lava or he'll get stuck*/ if(Fuel) detectCollisions(); detectCoinCollision(); detectFuelCanCollision(); detectLavaCollision(); /* emd camera movements */ glPopMatrix(); ShowMessage(); DrawFuelGauge(); /*after death animation, start over*/ if(Dead && (Frame == 29)) { ResetLevel(Level); Lives--; } /* did johnny find all the coins?*/ if(!NumCoins) { if(Level + 1 < 0) Level++; else Level = 0; ResetLevel(Level); } /* out of lives? */ if(!Lives) { GameOver = 1; Lives = 5; } } if(GameOver<60 && GameOver) { ShowGameOver(); Level = 0; ResetLevel(); GameOver++; } if(GameOver==60) { SplashScreen(); } /*swap display buffers*/ glutSwapBuffers(); /*force new display to screen*/ glFlush(); glutPostRedisplay(); return; } /****************************************************** If the window is resized, this function resizes it by setting the width to W and height to H, and then redisplaying the model. ******************************************************/ void myReshape(GLsizei w, GLsizei h) { W = w; H = h; glutPostRedisplay(); return; } /***************************************************** This function sets up the display list, but first it must call display, as it needs the vertices and faces (which are determined the first time display is called) so that the display list works properly. ******************************************************/ void init (void) { glEnable(GL_DEPTH_TEST); Level = 0; /* GameOver needs to be >= 60 so that the splash screen shows initially*/ GameOver = 60; ResetLevel(); /* set camera zoom */ Z = 900; fflush(stdout); display(); return; } /********************************************************** This function just indicates options that are displayed when the Right mouse button is hit, and any function callbacks. It also lists what keys to hit to translate or rotate the model. *************************************************************/ void glutMenu(void) { glutCreateMenu(selectMainMenu); glutAddMenuEntry("Move Left/Right: drag mouse left/right while left clicked", 1); glutAddMenuEntry("Move Forward/Backward: drag mouse up/down while left clicked", 2); glutAddMenuEntry("JetPack Thrust: left mouse button", 3); glutAddMenuEntry("Rotate Clockwise: right arrow", 4); glutAddMenuEntry("Rotate CClockwise: left arrow", 5); glutAddMenuEntry("", 6); glutAddMenuEntry("Toggle Fill", 7); glutAddMenuEntry("", 8); glutAddMenuEntry("", 9); glutAddMenuEntry("Quit", 10); glutAttachMenu(GLUT_RIGHT_BUTTON); return; } /******************************************************* Starting point of the program *******************************************************/ int main (int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(320, 240); glutInitWindowPosition(100, 100); glutCreateWindow("Johnny Jetpack v.0000000000001"); init(); glutDisplayFunc (display); glutReshapeFunc(myReshape); glutMouseFunc(myMouse); glutMotionFunc(myDrag); glutKeyboardFunc (keyboard); glutSpecialFunc(speckeyboard); glutMenu(); glutMainLoop(); return (0); }