/*********************************************************** CSCD18, SPRING 2005 dog.cpp author: Eron Steger based on code by: J. Radulovich Simple demo program using OpenGL and the glut/glui libraries Instructions: Please read the assignment page to determine exactly what needs to be implemented. Then read over this file and become acquainted with its design. Add source code where it appears appropriate. In particular, see lines marked 'TODO'. You should not need to change the overall structure of the program. However it should be clear what your changes do, and you should use sufficient comments to explain your code. While the point of the assignment is to draw and animate the character, you will also be marked based on your design. ***********************************************************/ /* * Aly Merchant * 991579083 * CSC418h1s Assignment #1 */ #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #include #ifndef _WIN32 #include #else void usleep(unsigned int nanosec) { Sleep(nanosec / 1000); } #endif // *************** GLOBAL VARIABLES ************************* const float PI = 3.14159; // --------------- USER INTERFACE VARIABLES ----------------- // Window settings int windowID; // Glut window ID (for display) GLUI *glui; // Glui window (for controls) int Win[2]; // window (x,y) size // ---------------- ANIMATION VARIABLES --------------------- // Animation settings int animate_mode = 0; // 0 = no anim, 1 = animate int animation_frame = 0; // Specify current frame of animation // Joint parameters const float JOINT_MIN = -45.0f; const float JOINT_MAX = 45.0f; float joint_rot = 0.0f; ////////////////////////////////////////////////////// // Add additional joint parameters here ////////////////////////////////////////////////////// // *********** FUNCTION HEADER DECLARATIONS **************** // Initialization functions void initGlut(char* winName); void initGlui(); void initGl(); // Callbacks for handling events in glut void myReshape(int w, int h); void animate(); void display(void); // Callback for handling events in glui void GLUI_Control(int id); // Functions to help draw the object // - functions labelled draw* perform the actual drawing // - functions labelled make* create an object void drawSquare(float); void drawTorso(float,float); void drawCircle(float); void drawNeck(float); void drawHead(float); void makeArm(float,float); void makeJaw(float,float); void makeTail(float,float); void makeNeck(float,float); void makeHead(float,float); void makeForeArm(float,float); void makeJoint(float); // Return the current system clock (in seconds) double getTime(); // ******************** FUNCTIONS ************************ // main() function // Initializes the user interface (and any user variables) // then hands over control to the event handler, which calls // display() whenever the GL window needs to be redrawn. int main(int argc, char** argv) { // Process program arguments if(argc != 3) { printf("Usage: demo [width] [height]\n"); printf("Using 300x200 window by default...\n"); Win[0] = 300; Win[1] = 200; } else { Win[0] = atoi(argv[1]); Win[1] = atoi(argv[2]); } // Initialize glut, glui, and opengl initGlut(argv[0]); initGlui(); initGl(); // Invoke the standard GLUT main event loop glutMainLoop(); return 0; // never reached } // Initialize glut and create a window with the specified caption void initGlut(char* winName) { // Set video mode: double-buffered, color, depth-buffered glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // Create window glutInitWindowPosition (0, 0); glutInitWindowSize(Win[0],Win[1]); windowID = glutCreateWindow(winName); // Setup callback functions to handle events glutReshapeFunc(myReshape); // Call myReshape whenever window resized glutDisplayFunc(display); // Call display whenever new frame needed } // Quit button handler. Called when the "quit" button is pressed. void quitButton(int) { exit(0); } // Animate button handler. Called when the "animate" checkbox is pressed. void animateButton(int) { // synchronize variables that GLUT uses glui->sync_live(); animation_frame = 0; if(animate_mode == 1) { // start animation GLUI_Master.set_glutIdleFunc(animate); } else { // stop animation GLUI_Master.set_glutIdleFunc(NULL); } } // Initialize GLUI and the user interface void initGlui() { GLUI_Master.set_glutIdleFunc(NULL); // Create GLUI window glui = GLUI_Master.create_glui("Glui Window", 0, Win[0]+10, 0); // Create a control to specify the rotation of the joint GLUI_Spinner *joint_spinner = glui->add_spinner("Joint", GLUI_SPINNER_FLOAT, &joint_rot); joint_spinner->set_speed(0.1); joint_spinner->set_float_limits(JOINT_MIN, JOINT_MAX, GLUI_LIMIT_CLAMP); /////////////////////////////////////////////////////////// // // Add controls for additional joints here /////////////////////////// //////////////////////////////// /* * all joints are controlled by the same variable, no additional controls * are required */ // Add button to specify animation mode glui->add_separator(); glui->add_checkbox("Animate", &animate_mode, 0, animateButton); // Add "Quit" button glui->add_separator(); glui->add_button("Quit", 0, quitButton); // Set the main window to be the "active" window glui->set_main_gfx_window(windowID); } // Performs most of the OpenGL intialization void initGl(void) { // glClearColor (red, green, blue, alpha) // Ignore the meaning of the 'alpha' value for now glClearColor(0.7f,0.7f,0.9f,1.0f); } // Callback idle function for animating the scene void animate() { // Update geometry const double joint_rot_speed = 0.1; double joint_rot_t = (sin(animation_frame*joint_rot_speed) + 1.0) / 2.0; joint_rot = joint_rot_t * JOINT_MIN + (1 - joint_rot_t) * JOINT_MAX; /////////////////////////////////////////////////////////// // // Modify this function animate the character's joints // Note: Nothing should be drawn in this function! OpenGL drawing // should only happen in the display() callback. // /////////////////////////////////////////////////////////// /* * joint_rot is used as a global animation parameter, it is scaled and * negated as necessary to vary the joint movements * no updating is necessary here */ // Update user interface glui->sync_live(); // Tell glut window to update itself. This will cause the display() // callback to be called, which renders the object (once you've written // the callback). glutSetWindow(windowID); glutPostRedisplay(); // increment the frame number. animation_frame++; // Wait 50 ms between frames (20 frames per second) usleep(50000); } // Handles the window being resized by updating the viewport // and projection matrices void myReshape(int w, int h) { // Setup projection matrix for new window glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-w/2, w/2, -h/2, h/2); // Update OpenGL viewport and internal variables glViewport(0,0, w,h); Win[0] = w; Win[1] = h; } // display callback // // This gets called by the event handler to draw // the scene, so this is where you need to build // your scene -- make your changes and additions here. // All rendering happens in this function. For Assignment 1, // updates to geometry should happen in the "animate" function. void display(void) { // glClearColor (red, green, blue, alpha) // Ignore the meaning of the 'alpha' value for now glClearColor(0.7f,0.7f,0.9f,1.0f); // OK, now clear the screen with the background colour glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Setup the model-view transformation matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /////////////////////////////////////////////////////////// // // Modify this function draw the scene // This should include function calls to pieces that // apply the appropriate transformation matrice and // render the individual body parts. /////////////////////////////////////////////////////////// // Draw our hinged object const float BODY_WIDTH = 100.0f; const float BODY_LENGTH = 60.0f; // Push the current transformation matrix on the stack glPushMatrix(); // Draw the 'body' glPushMatrix(); // Scale square to size of body glScalef(BODY_WIDTH, BODY_LENGTH, 1.0); // Set the colour to green glColor3f(0.0, 1.0, 0.0); // Draw the square for the body //drawSquare(1.0); drawTorso(1.0,1.0); glPopMatrix(); /* * Draw all children * - push a translation to the joint * - rotate the joint (alignment and animation) * - call a function to draw the child * - pop the transformation stack * * children include: 4 legs, tail, neck */ glPushMatrix(); glTranslatef(-2.0 * BODY_WIDTH/6.0, -BODY_LENGTH/2.0f + BODY_LENGTH/10, 0.0); glRotatef(joint_rot, 0.0, 0.0, 1.0); makeArm(BODY_WIDTH/20.0f,BODY_LENGTH/2.0f); glPopMatrix(); glPushMatrix(); glTranslatef(-1.0 * BODY_WIDTH/6.0, -BODY_LENGTH/2.0f + BODY_LENGTH/10, 0.0); glRotatef(-joint_rot, 0.0, 0.0, 1.0); makeArm(BODY_WIDTH/20.0f,BODY_LENGTH/2.0f); glPopMatrix(); glPushMatrix(); glTranslatef(1.0 * BODY_WIDTH/6.0, -BODY_LENGTH/2.0f + BODY_LENGTH/10, 0.0); glRotatef(joint_rot, 0.0, 0.0, 1.0); makeArm(BODY_WIDTH/20.0f,BODY_LENGTH/2.0f); glPopMatrix(); glPushMatrix(); glTranslatef(2.0 * BODY_WIDTH/6.0, -BODY_LENGTH/2.0f + BODY_LENGTH/10, 0.0); glRotatef(-joint_rot, 0.0, 0.0, 1.0); makeArm(BODY_WIDTH/20.0f,BODY_LENGTH/2.0f); glPopMatrix(); glPushMatrix(); glTranslatef(2.5 * BODY_WIDTH/6.0, 0, 0.0); glRotatef(joint_rot/2.0f+100.0f, 0.0, 0.0, 1.0); makeTail(BODY_WIDTH/22.5f,BODY_LENGTH/1.8f); glPopMatrix(); glPushMatrix(); glTranslatef(-2.0f * BODY_WIDTH/6.0f, BODY_LENGTH/5.0f, 0.0); glRotatef(joint_rot/6.0f-135.0f, 0.0, 0.0, 1.0); makeNeck(BODY_WIDTH/4.0f,BODY_LENGTH/3.0f); glPopMatrix(); // Retrieve the previous state of the transformation stack glPopMatrix(); // Execute any GL functions that are in the queue just to be safe glFlush(); // Now, show the frame buffer that we just drew into. // (this prevents flickering). glutSwapBuffers(); } /* * makeJoint draws a scaled black circle at the current location */ void makeJoint(float scl) { glPushMatrix(); glScalef( scl, scl, 1.0); glColor3f(0.2,0.2,0.1); drawCircle(1.0); glPopMatrix(); } /* * generic notes for make* functions: * - creates a joint to attach to the parent object * - scales to the parameters specified * - translates to the center of the object * - calls the appropriate draw* function * - clears the stack * - translates and rotates to position the child object * - calls the appropriate make* function */ /* * makeForeArm draws the second limb segment using two squares */ void makeForeArm(float sw, float sl) { makeJoint(sw); glColor3f(0.2,0.6,0.2); glPushMatrix(); glScalef(sw,sl,1); glTranslatef(0, -0.5, 0); drawSquare(1.0); glPopMatrix(); glTranslatef(-sw/2.0f,-sl,0); glScalef(2*sw,sl/10.0f,1); drawSquare(1.0); } /* * makeArm draws the first limb segment using a square and calls makeForeArm */ void makeArm(float sw, float sl) { makeJoint(sw); glColor3f(0.1,0.8,0.1); glPushMatrix(); glScalef(sw, sl, 1.0); glTranslatef(0, -0.5, 0); drawSquare(1.0); glPopMatrix(); glPushMatrix(); glTranslatef(0,-sl/1.1f,1); glRotatef(joint_rot/3.0f, 0,0,1); makeForeArm(sw, sl/2.0f); glPopMatrix(); } /* * makeTail draws the tail using an unfilled circle */ void makeTail(float sw, float sl) { makeJoint(sw); glPushMatrix(); glScalef(sw, sl, 1.0); glTranslatef(0, -0.5, 0); drawCircle(1.0); glPopMatrix(); } /* * makeJaw draws the jaw and sets up a sliding joint using glTranslate and * joint_rot */ void makeJaw(float sw, float sl) { glColor3f(0.4,0.6,0.4); glPushMatrix(); glScalef(sw,sl,1.0); glTranslatef( 0.75 + joint_rot/180,-0.5,0); drawSquare(1.0); glPopMatrix(); } /* * makeHead draws the head and calls makeJaw */ void makeHead(float sw, float sl) { makeJoint(sw/4.0f); glColor3f(0.2,0.6,0.2); glPushMatrix(); glScalef(sw,sl,1.0); glTranslatef(0,-0.5,0); drawHead(1.0); glPopMatrix(); glPushMatrix(); glTranslatef(sw/6.0f,-sl/2.0f,0); makeJaw(sw*5.0f/24.0f,sl/2.0f); glPopMatrix(); } /* * makeNeck draws the neck and calls makeHead */ void makeNeck(float sw, float sl) { makeJoint(sw/3.0f); glColor3f(0.1,0.8,0.1); glPushMatrix(); glScalef(sw, sl, 1.0); glTranslatef(0, -0.5, 0); drawNeck(1.0); glPopMatrix(); glPushMatrix(); glTranslatef(0, -sl/1.2f, 0); glRotatef(-joint_rot/9.0f+40.0f, 0,0,1); makeHead(sw,sl*2.5f); glPopMatrix(); } // Draw a square of the specified size, centered at the current location void drawSquare(float width) { // Draw the square glBegin(GL_POLYGON); glVertex2d(-width/2, -width/2); glVertex2d(width/2, -width/2); glVertex2d(width/2, width/2); glVertex2d(-width/2, width/2); glEnd(); } /* * drawNeck renders a trapezoid bounded within the square specified by width */ void drawNeck(float width) { glBegin(GL_POLYGON); glVertex2d(-width/3.3, -width/2); glVertex2d(width/3.3, -width/2); glVertex2d(width/2, width/2); glVertex2d(-width/2, width/2); glEnd(); } /* * drawHead renders the head as a custom polygon, by ordering the verticies in * this way it is possible to use only one polygon */ void drawHead(float width) { glBegin(GL_POLYGON); glVertex2d(-width/4, width/4); glVertex2d(-width/2, width/2); glVertex2d(width/2, width/2); glVertex2d(width/2, 0); glVertex2d(width/6, 0); glVertex2d(width/6, -width/2); glVertex2d(-width/4, -width/2); glEnd(); } /* * drawTorso renders the torso as a custom polygon rendered within the * rectangle specified by width and height */ void drawTorso(float width, float height) { glBegin(GL_POLYGON); glVertex2d(-width/2, height/10); glVertex2d(-width/2, -height/2); glVertex2d(width/2, -height/2); glVertex2d(width/2, height/10); glVertex2d(width/10, height/10); glVertex2d(-width/3, height/2); glEnd(); } /* * drawCircle uses a 100 sided polygon to approximate a circle * the circle is unfilled, useful for drawing joints * not as nice for drawing tails but it is used anyways */ void drawCircle(float radius) { glBegin(GL_LINE_LOOP); for (int i=0; i<100; i++) glVertex2d(radius*cos(0.062831853*i),radius*sin(0.062831853*i)); glEnd(); }