// Includes #include <stdio. h> #include <stdarg. h> #include <math. h> #define GL_GLEXT_PROTOTYPES #ifdef APPLE #include <GLUT/glut. h> #else #include <GL/glut. h> #endif

// Function Prototypes void display(); void specialKeys(); // Global Variables double rotate_y=0; double rotate_x=0;

int main(int argc, char* argv[]){ // Initialize GLUT and process user parameters glutInit(&argc,argv); // Request double buffered true color window with Z-buffer glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); This statement sets up your environment. A big thing to remember when writing OpenGL programs is that you must ask for everything. This requires you to have a greater understanding of how your program works and what you need to include to get the functionality that you want. In this line, you will set up the display with double buffering, RGB color, and a Z-buffer. Double buffering is a technique used in graphics programs to eliminate a problem that arises due to how images are drawn to the screen. Each time you redraw the scene, the display must first be erased then the new information will be drawn. Without double buffering you will observe a flickering effect as the screen is erased and redrawn repeatedly. This problem is fixed by adding a second buffer to draw to. With this method, an image is drawn to the first buffer and that buffer is shown to you. The next frame will be drawn to the second buffer and when that’s done, the two buffers will switch places. You will immediately see the second buffer, but, hidden from us, the first buffer is being erased and redrawn with the third frame which will be swapped in when finished. You also want to enable the RGB color system in your window. Z-buffering is how you get the 3D effects that you want. OpenGL uses a three dimensional coordinate system with x, y and z axes. To give the effect that an object is closer to you its position on the z axis is increased, however, to make it appear further away its position on the z axis is decreased.

// Create window glutCreateWindow(“Awesome Cube”);

// Create window glutCreateWindow(“Awesome Cube”);

// Enable Z-buffer depth test glEnable(GL_DEPTH_TEST);

// Enable Z-buffer depth test glEnable(GL_DEPTH_TEST);

// Callback functions glutDisplayFunc(display); glutSpecialFunc(specialKeys);

// Pass control to GLUT for events glutMainLoop(); // Return to OS return 0; }

Conceptually, each side is going to be drawn by defining the four corners and letting OpenGL connect the lines and fill it in with a color that you define. Below are the steps to doing this.

void display(){ // Clear screen and Z-buffer glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

void display(){ // Clear screen and Z-buffer glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

Here you will be starting with the front of your cube. Later you will add color to all 6 sides. // Multi-colored side - FRONT glBegin(GL_POLYGON); // Vertices will be added in the next step glEnd();

Here you will be starting with the front of your cube. Later you will add color to all 6 sides. // Multi-colored side - FRONT glBegin(GL_POLYGON); // Vertices will be added in the next step glEnd();

Here you will be starting with the front of your cube. Later you will add color to all 6 sides. // Multi-colored side - FRONT glBegin(GL_POLYGON); // Vertices will be added in the next step glEnd();

The first is how many dimensions you are working in. The 3 above in glVertex3f says you are drawing in 3 dimensions. It is also possible to work in 2 or 4 dimensions. The f above in glVertex3f says you are working with floating point numbers. You can also use shorts, integers or doubles. Notice that these points are defined in a counter-clockwise manner. This is not very important at the moment but when you begin to work with lighting, textures, and cull-facing, this will become incredibly important so get in the habit of defining your points counter-clockwise now. Add add the vertices between the glBegin() and glEnd() lines. // Multi-colored side - FRONT glBegin(GL_POLYGON); glVertex3f( -0. 5, -0. 5, -0. 5); // P1 glVertex3f( -0. 5, 0. 5, -0. 5); // P2 glVertex3f( 0. 5, 0. 5, -0. 5); // P3 glVertex3f( 0. 5, -0. 5, -0. 5); // P4 glEnd();

The first is how many dimensions you are working in. The 3 above in glVertex3f says you are drawing in 3 dimensions. It is also possible to work in 2 or 4 dimensions. The f above in glVertex3f says you are working with floating point numbers. You can also use shorts, integers or doubles. Notice that these points are defined in a counter-clockwise manner. This is not very important at the moment but when you begin to work with lighting, textures, and cull-facing, this will become incredibly important so get in the habit of defining your points counter-clockwise now. Add add the vertices between the glBegin() and glEnd() lines. // Multi-colored side - FRONT glBegin(GL_POLYGON); glVertex3f( -0. 5, -0. 5, -0. 5); // P1 glVertex3f( -0. 5, 0. 5, -0. 5); // P2 glVertex3f( 0. 5, 0. 5, -0. 5); // P3 glVertex3f( 0. 5, -0. 5, -0. 5); // P4 glEnd();

When you call glColor3f() every vertex drawn from that point on will be of that color. Therefore, if you want all four vertices to be red, just set the color once anytime before the glVertex3f() commands and all vertices will be red. The Front side defined below shows how to define a new color for each vertex. When you do this, you can see an interesting property of the OpenGL colors. Since each vertex of the polygon has its own color, OpenGL will automatically blend the colors! The next step will show how to assign four vertices with the same color. //Multi-colored side - FRONT glBegin(GL_POLYGON); glColor3f( 1. 0, 0. 0, 0. 0 ); glVertex3f( 0. 5, -0. 5, -0. 5 ); // P1 is red glColor3f( 0. 0, 1. 0, 0. 0 ); glVertex3f( 0. 5, 0. 5, -0. 5 ); // P2 is green glColor3f( 0. 0, 0. 0, 1. 0 ); glVertex3f( -0. 5, 0. 5, -0. 5 ); // P3 is blue glColor3f( 1. 0, 0. 0, 1. 0 ); glVertex3f( -0. 5, -0. 5, -0. 5 ); // P4 is purple glEnd();

// White side - BACK glBegin(GL_POLYGON); glColor3f( 1. 0, 1. 0, 1. 0 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glEnd(); // Purple side - RIGHT glBegin(GL_POLYGON); glColor3f( 1. 0, 0. 0, 1. 0 ); glVertex3f( 0. 5, -0. 5, -0. 5 ); glVertex3f( 0. 5, 0. 5, -0. 5 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glEnd(); // Green side - LEFT glBegin(GL_POLYGON); glColor3f( 0. 0, 1. 0, 0. 0 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, -0. 5, -0. 5 ); glEnd(); // Blue side - TOP glBegin(GL_POLYGON); glColor3f( 0. 0, 0. 0, 1. 0 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( 0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glEnd(); // Red side - BOTTOM glBegin(GL_POLYGON); glColor3f( 1. 0, 0. 0, 0. 0 ); glVertex3f( 0. 5, -0. 5, -0. 5 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, -0. 5 ); glEnd(); glFlush(); glutSwapBuffers(); } We also want to add in two last lines of code for this function. These are glFlush(); and glutSwapBuffers(); which give us the double-buffering effect you learned about earlier.

// White side - BACK glBegin(GL_POLYGON); glColor3f( 1. 0, 1. 0, 1. 0 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glEnd(); // Purple side - RIGHT glBegin(GL_POLYGON); glColor3f( 1. 0, 0. 0, 1. 0 ); glVertex3f( 0. 5, -0. 5, -0. 5 ); glVertex3f( 0. 5, 0. 5, -0. 5 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glEnd(); // Green side - LEFT glBegin(GL_POLYGON); glColor3f( 0. 0, 1. 0, 0. 0 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, -0. 5, -0. 5 ); glEnd(); // Blue side - TOP glBegin(GL_POLYGON); glColor3f( 0. 0, 0. 0, 1. 0 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( 0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glEnd(); // Red side - BOTTOM glBegin(GL_POLYGON); glColor3f( 1. 0, 0. 0, 0. 0 ); glVertex3f( 0. 5, -0. 5, -0. 5 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, -0. 5 ); glEnd(); glFlush(); glutSwapBuffers(); } We also want to add in two last lines of code for this function. These are glFlush(); and glutSwapBuffers(); which give us the double-buffering effect you learned about earlier.

This function is why you declared the global variables rotate_x and rotate_y. When you press the right and left arrow keys, rotate_y will be incremented or decremented by 5 degrees. Similarly, when you press the up and down arrow keys, rotate_x will change accordingly. void specialKeys( int key, int x, int y ) { // Right arrow - increase rotation by 5 degree if (key == GLUT_KEY_RIGHT) rotate_y += 5; // Left arrow - decrease rotation by 5 degree else if (key == GLUT_KEY_LEFT) rotate_y -= 5; else if (key == GLUT_KEY_UP) rotate_x += 5; else if (key == GLUT_KEY_DOWN) rotate_x -= 5; // Request display update glutPostRedisplay(); }

This function is why you declared the global variables rotate_x and rotate_y. When you press the right and left arrow keys, rotate_y will be incremented or decremented by 5 degrees. Similarly, when you press the up and down arrow keys, rotate_x will change accordingly. void specialKeys( int key, int x, int y ) { // Right arrow - increase rotation by 5 degree if (key == GLUT_KEY_RIGHT) rotate_y += 5; // Left arrow - decrease rotation by 5 degree else if (key == GLUT_KEY_LEFT) rotate_y -= 5; else if (key == GLUT_KEY_UP) rotate_x += 5; else if (key == GLUT_KEY_DOWN) rotate_x -= 5; // Request display update glutPostRedisplay(); }

// Reset transformations glLoadIdentity(); // Rotate when user changes rotate_x and rotate_y glRotatef( rotate_x, 1. 0, 0. 0, 0. 0 ); glRotatef( rotate_y, 0. 0, 1. 0, 0. 0 ); // Multi-colored side - FRONT . . . . First notice that the syntax of glRotatef() is similar to that of glColor3f() and glVertex3f() but always requires 4 parameters. The first parameter is the degree of rotation to be applied. The next three parameters define which axis to rotate about with the first being the x axis, second being the y axis, and third being the z axis. Right now you only need to rotate about the x and y-axis. All transformations that you write in your program need lines similar to this. Conceptually, you can think of this as rotating your object about the x axis by the amount defined by rotate_x and then rotating around the y axis by rotate_y. However, OpenGL combines all these statements into one matrix transformation. Each time you call the display function, you build a transformation matrix and glLoadIdentity() assures that you will start out with a new matrix in each pass. The other transformation functions you could apply are glTranslatef() and glScalef(). These functions are similar to glRotatef() with the exception the they only take 3 parameters, the x, y, and z amounts to translate or scale the object. In order to get the correct effect when applying all three transformations to one object, you need to apply them in the correct order. Always write them in the order glTranslate, glRotate, then glScale. OpenGL essentially applies the transformations in a bottom up manner. To understand this try to imagine what a simple 1x1x1 cube would look like with the transformations if OpenGL applied them from top to bottom and if OpenGL applied them from bottom to top.

// Other transformations glTranslatef( 0. 1, 0. 0, 0. 0 ); glRotatef( 180, 0. 0, 1. 0, 0. 0 ); glScalef( 2. 0, 2. 0, 0. 0 );

On Linux: gcc cube. c -o cube -lglut -lGL . / mycube On Mac: gcc -o foo foo. c -framework GLUT -framework OpenGL . / mycube On Windows: gcc -Wall -ofoo foo. c -lglut32cu -lglu32 -lopengl32 . / mycube

// // File: mycube. c // Author: Matt Daisley // Created: 4/25/2012 // Project: Source code for Make a Cube in OpenGL // Description: Creates an OpenGL window and draws a 3D cube // That the user can rotate using the arrow keys // // Controls: Left Arrow - Rotate Left // Right Arrow - Rotate Right // Up Arrow - Rotate Up // Down Arrow - Rotate Down // ———————————————————- // Includes // ———————————————————- #include <stdio. h> #include <stdarg. h> #include <math. h> #define GL_GLEXT_PROTOTYPES #ifdef APPLE #include <GLUT/glut. h> #else #include <GL/glut. h> #endif // ———————————————————- // Function Prototypes // ———————————————————- void display(); void specialKeys(); // ———————————————————- // Global Variables // ———————————————————- double rotate_y=0; double rotate_x=0; // ———————————————————- // display() Callback function // ———————————————————- void display(){ // Clear screen and Z-buffer glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Reset transformations glLoadIdentity(); // Other Transformations // glTranslatef( 0. 1, 0. 0, 0. 0 ); // Not included // glRotatef( 180, 0. 0, 1. 0, 0. 0 ); // Not included // Rotate when user changes rotate_x and rotate_y glRotatef( rotate_x, 1. 0, 0. 0, 0. 0 ); glRotatef( rotate_y, 0. 0, 1. 0, 0. 0 ); // Other Transformations // glScalef( 2. 0, 2. 0, 0. 0 ); // Not included //Multi-colored side - FRONT glBegin(GL_POLYGON); glColor3f( 1. 0, 0. 0, 0. 0 ); glVertex3f( 0. 5, -0. 5, -0. 5 ); // P1 is red glColor3f( 0. 0, 1. 0, 0. 0 ); glVertex3f( 0. 5, 0. 5, -0. 5 ); // P2 is green glColor3f( 0. 0, 0. 0, 1. 0 ); glVertex3f( -0. 5, 0. 5, -0. 5 ); // P3 is blue glColor3f( 1. 0, 0. 0, 1. 0 ); glVertex3f( -0. 5, -0. 5, -0. 5 ); // P4 is purple glEnd(); // White side - BACK glBegin(GL_POLYGON); glColor3f( 1. 0, 1. 0, 1. 0 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glEnd(); // Purple side - RIGHT glBegin(GL_POLYGON); glColor3f( 1. 0, 0. 0, 1. 0 ); glVertex3f( 0. 5, -0. 5, -0. 5 ); glVertex3f( 0. 5, 0. 5, -0. 5 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glEnd(); // Green side - LEFT glBegin(GL_POLYGON); glColor3f( 0. 0, 1. 0, 0. 0 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glVertex3f( -0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, -0. 5, -0. 5 ); glEnd(); // Blue side - TOP glBegin(GL_POLYGON); glColor3f( 0. 0, 0. 0, 1. 0 ); glVertex3f( 0. 5, 0. 5, 0. 5 ); glVertex3f( 0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, 0. 5, -0. 5 ); glVertex3f( -0. 5, 0. 5, 0. 5 ); glEnd(); // Red side - BOTTOM glBegin(GL_POLYGON); glColor3f( 1. 0, 0. 0, 0. 0 ); glVertex3f( 0. 5, -0. 5, -0. 5 ); glVertex3f( 0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, 0. 5 ); glVertex3f( -0. 5, -0. 5, -0. 5 ); glEnd(); glFlush(); glutSwapBuffers(); } // ———————————————————- // specialKeys() Callback Function // ———————————————————- void specialKeys( int key, int x, int y ) { // Right arrow - increase rotation by 5 degree if (key == GLUT_KEY_RIGHT) rotate_y += 5; // Left arrow - decrease rotation by 5 degree else if (key == GLUT_KEY_LEFT) rotate_y -= 5; else if (key == GLUT_KEY_UP) rotate_x += 5; else if (key == GLUT_KEY_DOWN) rotate_x -= 5; // Request display update glutPostRedisplay(); } // ———————————————————- // main() function // ———————————————————- int main(int argc, char* argv[]){ // Initialize GLUT and process user parameters glutInit(&argc,argv); // Request double buffered true color window with Z-buffer glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // Create window glutCreateWindow(“Awesome Cube”); // Enable Z-buffer depth test glEnable(GL_DEPTH_TEST); // Callback functions glutDisplayFunc(display); glutSpecialFunc(specialKeys); // Pass control to GLUT for events glutMainLoop(); // Return to OS return 0; }