/* * The running man * * Copyright (C) 2001-2003 Robert Ancell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* compile with `make' */ #include #include #include #include #include void init(void); void reshape(int x, int y); void keyboard(unsigned char, int, int); void mouse(int, int, int, int); void mouse_motion(int, int); void draw_ground(void); void animate(void); void display(void); int main(int argc, char **argv); /* The glass model */ GlassModel *glass_man; int nvariables; int mbutton, oldx, oldy; float view_theta = 0.0f, view_phi = 0.0f, view_radius = 2500.0f; int screen_width, screen_height; float frequency = 1.0f; /* The variables for the model */ int jump, waist_pitch, l_shoulder_rot, r_shoulder_rot, l_elbow_rot, r_elbow_rot; int head_pitch, head_heading, l_hip_rot, r_hip_rot, l_knee_rot, r_knee_rot; int l_ankle_rot, r_ankle_rot; void init(void) { /* Set up glut */ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL); glutInitWindowSize(400, 400); glutCreateWindow("The Running Man"); /* Attach the functions */ glutMouseFunc(mouse); glutMotionFunc(mouse_motion); glutKeyboardFunc(keyboard); glutReshapeFunc(reshape); glutIdleFunc(animate); glutDisplayFunc(display); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 0.5, 1000000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); screen_width = w; screen_height = h; } void keyboard(unsigned char key, int x, int y) { switch(key) { case '+': frequency += 0.5f; break; case '-': frequency -= 0.5f; break; case 27: /* esc */ exit(0); break; } glutPostRedisplay(); } void mouse(int button, int state, int x, int y) { mbutton = button; oldx = x; oldy = y; } void mouse_motion(int x, int y) { int dx = x - oldx, dy = y - oldy; switch(mbutton) { case GLUT_LEFT_BUTTON: view_theta += 1.0f * (float) dx; view_phi += 1.0f * (float) dy; break; case GLUT_RIGHT_BUTTON: view_radius += 15.0f * (float) dy; break; } oldx = x; oldy = y; glutPostRedisplay(); } void draw_ground(void) { glColor4f(0.1f, 0.8f, 0.2f, 0.5f); glBegin(GL_QUADS); glVertex3f(-2500.0f, 0.0f, 2500.0f); glVertex3f(2500.0f, 0.0f, 2500.0f); glVertex3f(2500.0f, 0.0f, -2500.0f); glVertex3f(-2500.0f, 0.0f, -2500.0f); glEnd(); } void animate(void) { int ticks = glutGet(GLUT_ELAPSED_TIME); static int old_ticks = 0; float dt = (ticks - old_ticks) / 1000.0f; static float theta = 0; float sin_theta, cos_theta, nsin_theta, ncos_theta, j_theta; theta += frequency * dt; sin_theta = sin(theta); cos_theta = cos(theta); nsin_theta = 0.5f * (sin_theta + 1.0f); ncos_theta = 0.5f * (cos_theta + 1.0f); /* Jump */ j_theta = 0.5 * fmod(2.0 * theta, 2.0 * M_PI) / M_PI - 0.5; glassSetVariable(glass_man, jump, 155.0 + 745.0f + 500.0*(0.25 - j_theta*j_theta)); /* Waist */ glassSetVariable(glass_man, waist_pitch, 45.0f + exp(-0.05f * frequency) * -45.0f); /* Arms */ glassSetVariable(glass_man, l_shoulder_rot, (sin_theta * 45.0f)); glassSetVariable(glass_man, r_shoulder_rot, (-sin_theta * 45.0f)); glassSetVariable(glass_man, l_elbow_rot, (-45.0f - (1 - nsin_theta) * 90.0f)); glassSetVariable(glass_man, r_elbow_rot, (-45.0f - nsin_theta * 90.0f)); /* Head */ glassSetVariable(glass_man, head_heading, (sin_theta * 45.0f)); /* Legs */ glassSetVariable(glass_man, l_hip_rot, (-70.0f + (1.0f - nsin_theta) * 115.0f)); glassSetVariable(glass_man, r_hip_rot, (-70.0f + nsin_theta * 115.0f)); if(cos_theta < 0.0f) { glassSetVariable(glass_man, r_knee_rot, (70.0f + nsin_theta * 20.0f)); if(sin_theta < 0.0f) glassSetVariable(glass_man, l_knee_rot, (-90.0f + (1.0f - nsin_theta) * 180.0f)); else glassSetVariable(glass_man, l_knee_rot, (70.0f + -(1.0f - nsin_theta) * 180.0f)); } else { glassSetVariable(glass_man, l_knee_rot, (70.0f + (1.0f - nsin_theta) * 20.0f)); if(sin_theta < 0.0f) glassSetVariable(glass_man, r_knee_rot, (70.0f + -nsin_theta * 180.0f)); else glassSetVariable(glass_man, r_knee_rot, (-90.0f + nsin_theta * 180.0f)); } glassSetVariable(glass_man, l_ankle_rot, (-sin_theta * 30.0f)); glassSetVariable(glass_man, r_ankle_rot, (sin_theta * 30.0f)); old_ticks = ticks; glutPostRedisplay(); } /* Draw the scene */ void display(void) { int i; GLfloat value, min, max; float percent; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT| GL_STENCIL_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -view_radius); glRotatef(view_phi, 1.0f, 0.0f, 0.0f); glRotatef(view_theta, 0.0f, 1.0f, 0.0f); /* move camera up off ground */ glTranslatef(0.0f, -845.0f, 0.0f); /* Draws the running man */ glassDrawModel(glass_man); /* Make a stencil of the ground */ glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_STENCIL_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDepthMask(GL_FALSE); glStencilFunc(GL_ALWAYS, 1, 0xffffffff); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); draw_ground(); glPopAttrib(); /* Draws the reflection of the running man */ glPushMatrix(); glPushAttrib(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 1, 0xffffffff); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glDepthMask(GL_FALSE); glCullFace(GL_FRONT); glScalef(1.0f, -1.0f, 1.0f); glassDrawModel(glass_man); glPopAttrib(); glPopMatrix(); /* Actually draws the gound */ glPushAttrib(GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); draw_ground(); glPopAttrib(); /* Draw the overlay */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0f, screen_width, 0.0f, screen_height, -1.0f, 0.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glBegin(GL_QUADS); for(i = 0; i < nvariables; i++) { glColor3f(0.0, 0.0f, 1.0f); glVertex3f(i * 20.0f + 10.0f, 50.0f, 0.5f); glVertex3f(i * 20.0f + 10.0f, 10.0f, 0.5f); glVertex3f(i * 20.0f + 20.0f, 10.0f, 0.5f); glVertex3f(i * 20.0f + 20.0f, 50.0f, 0.5f); } glColor3f(1.0, 1.0f, 1.0f); for(i = 0; i < nvariables; i++) { value = glassGetVariableValue(glass_man, i); min = glassGetVariableMin(glass_man, i); max = glassGetVariableMax(glass_man, i); percent = (value - min) / (max - min); glVertex3f(i * 20.0f + 12.0f, 12.0f + 36.0f * percent, 0.6f); glVertex3f(i * 20.0f + 12.0f, 12.0f, 0.6f); glVertex3f(i * 20.0f + 17.0f, 12.0f, 0.6f); glVertex3f(i * 20.0f + 17.0f, 12.0f + 36.0f * percent, 0.6f); } glEnd(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat) screen_width/(GLfloat) screen_height, 0.5, 10000.0); glutSwapBuffers(); } int main(int argc, char **argv) { glutInit(&argc, argv); init(); /* Load the glass model */ if((glass_man = glassLoadModel("models/person.glm")) == NULL) { fprintf(stderr, "models/person.glm not found, exiting\n"); exit(0); } nvariables = glassGetNumVariables(glass_man); /* Extract the variables */ jump = glassFindVariable(glass_man, "jump"); waist_pitch = glassFindVariable(glass_man, "waist pitch"); l_shoulder_rot = glassFindVariable(glass_man, "left shoulder rotate"); r_shoulder_rot = glassFindVariable(glass_man, "right shoulder rotate"); l_elbow_rot = glassFindVariable(glass_man, "left elbow rotate"); r_elbow_rot = glassFindVariable(glass_man, "right elbow rotate"); head_pitch = glassFindVariable(glass_man, "head pitch"); head_heading = glassFindVariable(glass_man, "head heading"); l_hip_rot = glassFindVariable(glass_man, "left hip rotate"); r_hip_rot = glassFindVariable(glass_man, "right hip rotate"); l_knee_rot = glassFindVariable(glass_man, "left knee rotate"); r_knee_rot = glassFindVariable(glass_man, "right knee rotate"); l_ankle_rot = glassFindVariable(glass_man, "left ankle rotate"); r_ankle_rot = glassFindVariable(glass_man, "right ankle rotate"); glutMainLoop(); return 0; }